SAE: Add support for PMKSA caching on the station side
authorJouni Malinen <j@w1.fi>
Sat, 18 Oct 2014 10:02:02 +0000 (13:02 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 18 Oct 2014 10:02:02 +0000 (13:02 +0300)
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>
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
wpa_supplicant/ibss_rsn.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index b17fc88..4df9e25 100644 (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()
  * @pmk: The new PMK
  * @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.
  */
-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)
                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;
        os_memcpy(sm->xxkey, pmk, pmk_len);
 #endif /* CONFIG_IEEE80211R */
+
+       if (bssid) {
+               pmksa_cache_add(sm->pmksa, pmk, pmk_len, bssid, sm->own_addr,
+                               sm->network_ctx, sm->key_mgmt);
+       }
 }
 
 
index 63032b0..595fdf2 100644 (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_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
 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_fast_reauth(struct wpa_sm *sm, int fast_reauth);
 void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
index 3083dd8..0e487d2 100644 (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_GROUP, WPA_CIPHER_CCMP);
        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);
        if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
index 36b4f87..9841c10 100644 (file)
@@ -199,6 +199,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
                        "0x%x", params.auth_alg);
        }
 #ifdef CONFIG_SAE
+       wpa_s->sme.sae_pmksa_caching = 0;
        if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
                const u8 *rsn;
                struct wpa_ie_data ied;
@@ -391,6 +392,15 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
        }
 
 #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 (start)
                        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 "
                           "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 */
 
@@ -881,6 +892,27 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
 
        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
         * theory, this should not be needed, but mac80211 gets quite confused
index e7aeeac..028e034 100644 (file)
@@ -1177,7 +1177,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 
        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
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
                    ssid->passphrase) {
@@ -1186,7 +1186,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                    4096, psk, PMK_LEN);
                        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
                                        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 */
 #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 "
                                                "external passphrase)",
                                                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
 #endif /* CONFIG_NO_PBKDF2 */
                        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);
                                        return -1;
                                }
-                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
                        } else {
                                wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
                                        "PSK available");
index ba9df62..f968c96 100644 (file)
@@ -651,6 +651,7 @@ struct wpa_supplicant {
                struct sae_data sae;
                struct wpabuf *sae_token;
                int sae_group_index;
+               unsigned int sae_pmksa_caching:1;
 #endif /* CONFIG_SAE */
        } sme;
 #endif /* CONFIG_SME */