]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
STA: Known STA Identification to skip association comeback mechanism
authorJouni Malinen <quic_jouni@quicinc.com>
Sat, 25 Jan 2025 17:36:11 +0000 (19:36 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 25 Jan 2025 17:46:39 +0000 (19:46 +0200)
Add a Known STA Identification element into (Re)Association Request
frame when using PMF with an AP with which we were last associated and
for which have stored the last used KCK in case that AP advertises
support for this capability to skip association comeback mechanism and
SA Query procedure.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/common/ieee802_11_defs.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/sme.c

index 37601fcb4726de6183f82b93a60d92b21095da2a..602954bb21ee0e1e6cd1d3b398f47c36813ef980 100644 (file)
 #define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
 #define WLAN_EXT_CAPAB_MSCS 85
 #define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88
+#define WLAN_EXT_CAPAB_KNOWN_STA_IDENTIFICATION 102
 
 /* Extended RSN Capabilities */
 /* bits 0-3: Field length (n-1) */
index 9e4b0b219eda74f36d370ba1afc1ba4d05be9005..100c523a612752508caa04280cf98c1720de1bcf 100644 (file)
@@ -3427,6 +3427,28 @@ failed:
 }
 
 
+static void wpa_sm_tptk_to_ptk(struct wpa_sm *sm)
+{
+       sm->tptk_set = 0;
+       sm->ptk_set = 1;
+       os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+       os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+
+       if (wpa_sm_pmf_enabled(sm)) {
+               os_memcpy(sm->last_kck, sm->ptk.kck, sm->ptk.kck_len);
+               sm->last_kck_len = sm->ptk.kck_len;
+               sm->last_kck_pmk_len = sm->pmk_len;
+               sm->last_kck_key_mgmt = sm->key_mgmt;
+               sm->last_kck_eapol_key_ver = sm->last_eapol_key_ver;
+               os_memcpy(sm->last_kck_aa, wpa_sm_get_auth_addr(sm), ETH_ALEN);
+       } else {
+               os_memset(sm->last_kck, 0, sizeof(sm->last_kck));
+               sm->last_kck_len = 0;
+               os_memset(sm->last_kck_aa, 0, ETH_ALEN);
+       }
+}
+
+
 static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
                                               struct wpa_eapol_key *key,
                                               u16 ver,
@@ -3456,10 +3478,7 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
                continue_fuzz:
 #endif /* TEST_FUZZ */
                        ok = 1;
-                       sm->tptk_set = 0;
-                       sm->ptk_set = 1;
-                       os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
-                       os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+                       wpa_sm_tptk_to_ptk(sm);
                        /*
                         * This assures the same TPTK in sm->tptk can never be
                         * copied twice to sm->ptk as the new PTK. In
@@ -3712,12 +3731,8 @@ static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len,
        WPA_PUT_BE16(pos, *key_data_len);
        bin_clear_free(tmp, *key_data_len);
 
-       if (sm->tptk_set) {
-               sm->tptk_set = 0;
-               sm->ptk_set = 1;
-               os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
-               os_memset(&sm->tptk, 0, sizeof(sm->tptk));
-       }
+       if (sm->tptk_set)
+               wpa_sm_tptk_to_ptk(sm);
 
        os_memcpy(sm->rx_replay_counter, key->replay_counter,
                  WPA_REPLAY_COUNTER_LEN);
@@ -4042,6 +4057,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                goto out;
        }
 
+       sm->last_eapol_key_ver = ver;
+
        if ((key_info & WPA_KEY_INFO_MIC) &&
            wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
                goto out;
@@ -4392,6 +4409,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
 #ifdef CONFIG_DPP2
        wpabuf_clear_free(sm->dpp_z);
 #endif /* CONFIG_DPP2 */
+       os_memset(sm->last_kck, 0, sizeof(sm->last_kck));
        os_free(sm);
 }
 
@@ -7204,3 +7222,41 @@ void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
        if (sm)
                sm->driver_bss_selection = driver_bss_selection;
 }
+
+
+struct wpabuf * wpa_sm_known_sta_identification(struct wpa_sm *sm, const u8 *aa,
+                                               u64 timestamp)
+{
+       struct wpabuf *ie;
+       unsigned int mic_len;
+       const u8 *start;
+       u8 *mic;
+
+       if (!sm || sm->last_kck_len == 0)
+               return NULL;
+
+       if (!ether_addr_equal(aa, sm->last_kck_aa))
+               return NULL;
+
+       mic_len = wpa_mic_len(sm->last_kck_key_mgmt, sm->last_kck_pmk_len);
+
+       ie = wpabuf_alloc(3 + 8 + 1 + mic_len);
+       if (!ie)
+               return NULL;
+
+       wpabuf_put_u8(ie, WLAN_EID_EXTENSION);
+       wpabuf_put_u8(ie, 1 + 8 + 1 + mic_len);
+       wpabuf_put_u8(ie, WLAN_EID_EXT_KNOWN_STA_IDENTIFICATION);
+       start = wpabuf_put(ie, 0);
+       wpabuf_put_le64(ie, timestamp);
+       wpabuf_put_u8(ie, mic_len);
+       mic = wpabuf_put(ie, mic_len);
+       if (wpa_eapol_key_mic(sm->last_kck, sm->last_kck_len,
+                             sm->last_kck_key_mgmt, sm->last_kck_eapol_key_ver,
+                             start, 8, mic) < 0) {
+               wpabuf_free(ie);
+               return NULL;
+       }
+
+       return ie;
+}
index 9783feef2b651da43833730b956dd19ef22ea992..25657d6057876fac9e6d05d5c061ea95205d1e7e 100644 (file)
@@ -667,5 +667,7 @@ struct rsn_pmksa_cache * wpa_sm_get_pmksa_cache(struct wpa_sm *sm);
 void wpa_sm_set_cur_pmksa(struct wpa_sm *sm,
                          struct rsn_pmksa_cache_entry *entry);
 const u8 * wpa_sm_get_auth_addr(struct wpa_sm *sm);
+struct wpabuf * wpa_sm_known_sta_identification(struct wpa_sm *sm, const u8 *aa,
+                                               u64 timestamp);
 
 #endif /* WPA_H */
index 2fd08b0f231cd910888e52efac5dc9bc558a1ea4..44c172ccbc08fb63472069a939be235affe56db7 100644 (file)
@@ -238,6 +238,14 @@ struct wpa_sm {
 
        bool rsn_override_support;
        enum wpa_rsn_override rsn_override;
+
+       u8 last_kck[WPA_KCK_MAX_LEN];
+       size_t last_kck_len;
+       size_t last_kck_pmk_len;
+       unsigned int last_kck_key_mgmt;
+       int last_kck_eapol_key_ver;
+       u8 last_kck_aa[ETH_ALEN];
+       int last_eapol_key_ver;
 };
 
 
index 2b758939d32c65637edc937f6db4156bacbb0733..32474a21aa32a6050d297e9256ae01cc5edf3c43 100644 (file)
@@ -944,6 +944,31 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
                wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
        }
 
+       if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION &&
+           wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_KNOWN_STA_IDENTIFICATION)) {
+               struct wpabuf *e;
+
+               e = wpa_sm_known_sta_identification(
+                       wpa_s->wpa,
+                       params.mld ? params.ap_mld_addr : bss->bssid,
+                       bss->tsf);
+               if (e) {
+                       size_t len;
+
+                       len = sizeof(wpa_s->sme.assoc_req_ie) -
+                               wpa_s->sme.assoc_req_ie_len;
+                       if (wpabuf_len(e) <= len) {
+                               wpa_printf(MSG_DEBUG,
+                                          "SME: Add Known STA Identification element");
+                               os_memcpy(wpa_s->sme.assoc_req_ie +
+                                         wpa_s->sme.assoc_req_ie_len,
+                                         wpabuf_head(e), wpabuf_len(e));
+                               wpa_s->sme.assoc_req_ie_len += wpabuf_len(e);
+                       }
+                       wpabuf_free(e);
+               }
+       }
+
 #ifdef CONFIG_HS20
        if (is_hs20_network(wpa_s, ssid, bss)) {
                struct wpabuf *hs20;