SAE: Add support for PMKSA caching on the station side

This makes wpa_supplicant SME create PMKSA cache entries from SAE
authentication and try to use PMKSA caching if an entry is found for the
AP. If the AP rejects the attempt, fall back to SAE authentication is
used.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-10-18 13:02:02 +03:00
parent f299117093
commit bc26ac50dd
6 changed files with 49 additions and 8 deletions

View file

@ -2181,10 +2181,12 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
* @sm: Pointer to WPA state machine data from wpa_sm_init() * @sm: Pointer to WPA state machine data from wpa_sm_init()
* @pmk: The new PMK * @pmk: The new PMK
* @pmk_len: The length of the new PMK in bytes * @pmk_len: The length of the new PMK in bytes
* @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
* *
* Configure the PMK for WPA state machine. * Configure the PMK for WPA state machine.
*/ */
void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len) void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
const u8 *bssid)
{ {
if (sm == NULL) if (sm == NULL)
return; return;
@ -2197,6 +2199,11 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
sm->xxkey_len = pmk_len; sm->xxkey_len = pmk_len;
os_memcpy(sm->xxkey, pmk, pmk_len); os_memcpy(sm->xxkey, pmk, pmk_len);
#endif /* CONFIG_IEEE80211R */ #endif /* CONFIG_IEEE80211R */
if (bssid) {
pmksa_cache_add(sm->pmksa, pmk, pmk_len, bssid, sm->own_addr,
sm->network_ctx, sm->key_mgmt);
}
} }

View file

@ -105,7 +105,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
void wpa_sm_deinit(struct wpa_sm *sm); void wpa_sm_deinit(struct wpa_sm *sm);
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid); void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
void wpa_sm_notify_disassoc(struct wpa_sm *sm); void wpa_sm_notify_disassoc(struct wpa_sm *sm);
void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len); void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
const u8 *bssid);
void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm); void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth); void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx); void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);

View file

@ -230,7 +230,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
wpa_sm_set_pmk(peer->supp, psk, PMK_LEN); wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL);
peer->supp_ie_len = sizeof(peer->supp_ie); peer->supp_ie_len = sizeof(peer->supp_ie);
if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,

View file

@ -199,6 +199,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
"0x%x", params.auth_alg); "0x%x", params.auth_alg);
} }
#ifdef CONFIG_SAE #ifdef CONFIG_SAE
wpa_s->sme.sae_pmksa_caching = 0;
if (wpa_key_mgmt_sae(ssid->key_mgmt)) { if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
const u8 *rsn; const u8 *rsn;
struct wpa_ie_data ied; struct wpa_ie_data ied;
@ -391,6 +392,15 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
} }
#ifdef CONFIG_SAE #ifdef CONFIG_SAE
if (params.auth_alg == WPA_AUTH_ALG_SAE &&
pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0)
{
wpa_dbg(wpa_s, MSG_DEBUG,
"PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
params.auth_alg = WPA_AUTH_ALG_OPEN;
wpa_s->sme.sae_pmksa_caching = 1;
}
if (params.auth_alg == WPA_AUTH_ALG_SAE) { if (params.auth_alg == WPA_AUTH_ALG_SAE) {
if (start) if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid, resp = sme_auth_build_sae_commit(wpa_s, ssid,
@ -667,7 +677,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for " wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
"4-way handshake"); "4-way handshake");
wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
wpa_s->pending_bssid);
} }
#endif /* CONFIG_SAE */ #endif /* CONFIG_SAE */
@ -881,6 +892,27 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL); eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
#ifdef CONFIG_SAE
if (wpa_s->sme.sae_pmksa_caching && wpa_s->current_ssid &&
wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"PMKSA caching attempt rejected - drop PMKSA cache entry and fall back to SAE authentication");
wpa_sm_aborted_cached(wpa_s->wpa);
wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
if (wpa_s->current_bss) {
struct wpa_bss *bss = wpa_s->current_bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
WLAN_REASON_DEAUTH_LEAVING);
wpas_connect_work_done(wpa_s);
wpa_supplicant_mark_disassoc(wpa_s);
wpa_supplicant_connect(wpa_s, bss, ssid);
return;
}
}
#endif /* CONFIG_SAE */
/* /*
* For now, unconditionally terminate the previous authentication. In * For now, unconditionally terminate the previous authentication. In
* theory, this should not be needed, but mac80211 gets quite confused * theory, this should not be needed, but mac80211 gets quite confused

View file

@ -1177,7 +1177,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
} }
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) { if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
#ifndef CONFIG_NO_PBKDF2 #ifndef CONFIG_NO_PBKDF2
if (bss && ssid->bssid_set && ssid->ssid_len == 0 && if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
ssid->passphrase) { ssid->passphrase) {
@ -1186,7 +1186,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
4096, psk, PMK_LEN); 4096, psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN); psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
} }
#endif /* CONFIG_NO_PBKDF2 */ #endif /* CONFIG_NO_PBKDF2 */
#ifdef CONFIG_EXT_PASSWORD #ifdef CONFIG_EXT_PASSWORD
@ -1222,7 +1222,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from " wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
"external passphrase)", "external passphrase)",
psk, PMK_LEN); psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
} else } else
#endif /* CONFIG_NO_PBKDF2 */ #endif /* CONFIG_NO_PBKDF2 */
if (wpabuf_len(pw) == 2 * PMK_LEN) { if (wpabuf_len(pw) == 2 * PMK_LEN) {
@ -1233,7 +1233,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ext_password_free(pw); ext_password_free(pw);
return -1; return -1;
} }
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
} else { } else {
wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable " wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
"PSK available"); "PSK available");

View file

@ -651,6 +651,7 @@ struct wpa_supplicant {
struct sae_data sae; struct sae_data sae;
struct wpabuf *sae_token; struct wpabuf *sae_token;
int sae_group_index; int sae_group_index;
unsigned int sae_pmksa_caching:1;
#endif /* CONFIG_SAE */ #endif /* CONFIG_SAE */
} sme; } sme;
#endif /* CONFIG_SME */ #endif /* CONFIG_SME */