diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_common.c b/components/wpa_supplicant/esp_supplicant/src/esp_common.c index 0488f378ba..91ef416e72 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_common.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_common.c @@ -23,8 +23,8 @@ #include "rsn_supp/wpa_i.h" #include "rsn_supp/wpa.h" -#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) struct wpa_supplicant g_wpa_supp; +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) #ifdef CONFIG_SUPPLICANT_TASK static void *s_supplicant_task_hdl = NULL; @@ -276,6 +276,7 @@ static int handle_assoc_frame(u8 *frame, size_t len, return 0; } #endif /* CONFIG_IEEE80211R */ +#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf) @@ -283,19 +284,24 @@ static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, int ret = 0; switch (type) { +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_WPA_11KV_SUPPORT) case WLAN_FC_STYPE_BEACON: case WLAN_FC_STYPE_PROBE_RESP: ret = esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf); break; +#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ #ifdef CONFIG_IEEE80211R case WLAN_FC_STYPE_AUTH: ret = handle_auth_frame(frame, len, sender, rssi, channel); break; +#endif /* CONFIG_IEEE80211R */ case WLAN_FC_STYPE_ASSOC_RESP: case WLAN_FC_STYPE_REASSOC_RESP: + wpa_sm_notify_assoc(&gWpaSm, sender); +#ifdef CONFIG_IEEE80211R ret = handle_assoc_frame(frame, len, sender, rssi, channel); - break; #endif /* CONFIG_IEEE80211R */ + break; #if defined(CONFIG_WPA_11KV_SUPPORT) case WLAN_FC_STYPE_ACTION: #ifdef CONFIG_SUPPLICANT_TASK @@ -313,6 +319,7 @@ static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, return ret; } +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) #ifdef CONFIG_MBO bool mbo_bss_profile_match(u8 *bssid) { @@ -338,11 +345,14 @@ bool mbo_bss_profile_match(u8 *bssid) } #endif /* CONFIG_MBO */ +#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ + int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) { struct wpa_supplicant *wpa_s = &g_wpa_supp; int ret = 0; +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) #ifdef CONFIG_SUPPLICANT_TASK s_supplicant_api_lock = os_recursive_mutex_create(); if (!s_supplicant_api_lock) { @@ -376,19 +386,21 @@ int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &supplicant_sta_disconn_handler, NULL); +#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ wpa_s->type = 0; wpa_s->subtype = 0; -#ifdef CONFIG_IEEE80211R wpa_s->type |= (1 << WLAN_FC_STYPE_ASSOC_RESP) | (1 << WLAN_FC_STYPE_REASSOC_RESP) | (1 << WLAN_FC_STYPE_AUTH); -#endif /* CONFIG_IEEE80211R */ if (esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype) != ESP_OK) { ret = -1; goto err; } wpa_cb->wpa_sta_rx_mgmt = ieee80211_handle_rx_frm; + +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) #ifdef CONFIG_MBO dl_list_init(&wpa_s->bss_tmp_disallowed); #endif /* CONFIG_MBO */ +#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ return 0; err: esp_supplicant_common_deinit(); @@ -399,6 +411,7 @@ void esp_supplicant_common_deinit(void) { struct wpa_supplicant *wpa_s = &g_wpa_supp; +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) esp_scan_deinit(wpa_s); #ifdef CONFIG_WPA_11KV_SUPPORT wpas_rrm_reset(wpa_s); @@ -408,10 +421,12 @@ void esp_supplicant_common_deinit(void) &supplicant_sta_conn_handler); esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &supplicant_sta_disconn_handler); +#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ if (wpa_s->type) { wpa_s->type = 0; esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype); } +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) #ifdef CONFIG_SUPPLICANT_TASK if (!s_supplicant_task_hdl && esp_supplicant_post_evt(SIG_SUPPLICANT_DEL_TASK, 0) != 0) { if (s_supplicant_evt_queue) { @@ -424,8 +439,10 @@ void esp_supplicant_common_deinit(void) } } #endif /* CONFIG_SUPPLICANT_TASK */ +#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ } +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) #ifdef CONFIG_WPA_11KV_SUPPORT bool esp_rrm_is_rrm_supported_connection(void) { @@ -817,12 +834,6 @@ int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan) return -1; } void esp_set_scan_ie(void) { } -int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) -{ - wpa_cb->wpa_sta_rx_mgmt = NULL; - return 0; -} -void esp_supplicant_common_deinit(void) { } #endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */ #if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WPA3_SAE) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 9bb5f5e923..04e75e3524 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -240,7 +240,7 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) case WIFI_REASON_CONNECTION_FAIL: case WIFI_REASON_HANDSHAKE_TIMEOUT: esp_wpa3_free_sae_data(); - wpa_sta_clear_curr_pmksa(); + wpa_sm_notify_disassoc(&gWpaSm); break; default: break; diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index f13cc15a2a..5e279b6658 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -1358,6 +1358,21 @@ SM_STATE(WPA_PTK, AUTHENTICATION2) } +static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm) +{ + if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { + wpa_printf(MSG_ERROR, + "WPA: Failed to get random data for ANonce"); + sm->Disconnect = TRUE; + return -1; + } + wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce, + WPA_NONCE_LEN); + sm->TimeoutCtr = 0; + return 0; +} + + SM_STATE(WPA_PTK, INITPMK) { u8 msk[2 * PMK_LEN]; @@ -1837,9 +1852,12 @@ SM_STEP(WPA_PTK) SM_ENTER(WPA_PTK, AUTHENTICATION); else if (sm->ReAuthenticationRequest) SM_ENTER(WPA_PTK, AUTHENTICATION2); - else if (sm->PTKRequest) - SM_ENTER(WPA_PTK, PTKSTART); - else switch (sm->wpa_ptk_state) { + else if (sm->PTKRequest) { + if (wpa_auth_sm_ptk_update(sm) < 0) + SM_ENTER(WPA_PTK, DISCONNECTED); + else + SM_ENTER(WPA_PTK, PTKSTART); + } else switch (sm->wpa_ptk_state) { case WPA_PTK_INITIALIZE: break; case WPA_PTK_DISCONNECT: diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index b827c36fe0..043f4bdc04 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -202,8 +202,21 @@ struct wpa_ptk { size_t kck_len; size_t kek_len; size_t tk_len; + int installed; /* 1 if key has already been installed to driver */ }; +struct wpa_gtk { + u8 gtk[WPA_GTK_MAX_LEN]; + size_t gtk_len; +}; + +#ifdef CONFIG_IEEE80211W +struct wpa_igtk { + u8 igtk[WPA_IGTK_MAX_LEN]; + size_t igtk_len; +}; +#endif /* CONFIG_IEEE80211W */ + struct wpa_gtk_data { enum wpa_alg alg; int tx, key_rsc_len, keyidx; diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index acfecb5c8e..d971e7df19 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -750,8 +750,22 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, enum key_flag key_flag) int keylen; enum wpa_alg alg; + if (sm->ptk.installed) { + wpa_printf(MSG_DEBUG, "WPA: Do not re-install same PTK to the driver"); + return 0; + } wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.\n"); + if (sm->pairwise_cipher == WPA_CIPHER_NONE) { + wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: NONE - do not use pairwise keys"); + return 0; + } + + if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { + wpa_printf(MSG_DEBUG, "WPA: Unsupported pairwise cipher %d", sm->pairwise_cipher); + return -1; + } + alg = wpa_cipher_to_alg(sm->pairwise_cipher); keylen = wpa_cipher_key_len(sm->pairwise_cipher); @@ -770,6 +784,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, enum key_flag key_flag) return -1; } + sm->ptk.installed = 1; + if (sm->wpa_ptk_rekey) { eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, @@ -856,7 +872,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); /* Detect possible key reinstallation */ - if (wpa_supplicant_gtk_in_use(sm, &(sm->gd))) { + if ((sm->gtk.gtk_len == (size_t) gd->gtk_len && + os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) || + wpa_supplicant_gtk_in_use(sm, &(sm->gd))) { wpa_printf(MSG_DEBUG, "WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)", gd->keyidx, gd->tx, gd->gtk_len); @@ -892,6 +910,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, gd->alg, gd->gtk_len, gd->keyidx); return -1; } + sm->gtk.gtk_len = gd->gtk_len; + os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len); return 0; } @@ -988,6 +1008,44 @@ int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, return 0; } +#ifdef CONFIG_IEEE80211W +static int wpa_supplicant_install_igtk(struct wpa_sm *sm, + const wifi_wpa_igtk_t *igtk) +{ + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher); + u16 keyidx = WPA_GET_LE16(igtk->keyid); + + /* Detect possible key reinstallation */ + if (sm->igtk.igtk_len == len && + os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) { + wpa_printf(MSG_DEBUG, + "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)", + keyidx); + return 0; + } + + wpa_printf(MSG_DEBUG, + "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x", + keyidx, MAC2STR(igtk->pn)); + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len); + if (keyidx > 4095) { + wpa_printf(MSG_WARNING, + "WPA: Invalid IGTK KeyID %d", keyidx); + return -1; + } + if (esp_wifi_set_igtk_internal(WIFI_IF_STA, igtk) < 0) { + wpa_printf(MSG_WARNING, + "WPA: Failed to configure IGTK to the driver"); + return -1; + } + + sm->igtk.igtk_len = len; + os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len); + + return 0; +} +#endif /* CONFIG_IEEE80211W */ + #ifdef DEBUG_PRINT void wpa_report_ie_mismatch(struct wpa_sm *sm, const char *reason, const u8 *src_addr, @@ -1047,7 +1105,6 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, if (ie->igtk) { const wifi_wpa_igtk_t *igtk; - uint16_t keyidx; #define WPA_IGTK_KDE_PREFIX_LEN (2 + 6) len = wpa_cipher_key_len(sm->mgmt_group_cipher); if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len) { @@ -1055,12 +1112,9 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, } igtk = (const wifi_wpa_igtk_t*)ie->igtk; - keyidx = WPA_GET_LE16(igtk->keyid); - if (keyidx > 4095) { + if (wpa_supplicant_install_igtk(sm, igtk) < 0) { return -1; } - wpa_printf(MSG_DEBUG, "WPA: Installing IGTK to the driver.\n"); - return esp_wifi_set_igtk_internal(WIFI_IF_STA, igtk); } #endif return 0; @@ -2249,9 +2303,87 @@ void wpa_sm_deinit(void) os_free(sm->ap_rsnxe); sm->ap_rsnxe = NULL; os_free(sm->assoc_rsnxe); + wpa_sm_drop_sa(sm); sm->assoc_rsnxe = NULL; } +/** + * wpa_sm_notify_assoc - Notify WPA state machine about association + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @bssid: The BSSID of the new association + * + * This function is called to let WPA state machine know that the connection + * was established. + */ +void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) +{ + int clear_keys = 1; + + if (sm == NULL) + return; + + wpa_printf(MSG_DEBUG, + "WPA: Association event - clear replay counter"); + os_memcpy(sm->bssid, bssid, ETH_ALEN); + os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN); + sm->rx_replay_counter_set = 0; + sm->renew_snonce = 1; + +#ifdef CONFIG_IEEE80211R + if (wpa_ft_is_completed(sm)) { + /* + * Clear portValid to kick EAPOL state machine to re-enter + * AUTHENTICATED state to get the EAPOL port Authorized. + */ + wpa_supplicant_key_neg_complete(sm, sm->bssid, 1); + + /* Prepare for the next transition */ + wpa_ft_prepare_auth_request(sm, NULL); + + clear_keys = 0; + sm->ft_protocol = 1; + } else { + sm->ft_protocol = 0; + } +#endif /* CONFIG_IEEE80211R */ + if (clear_keys) { + /* + * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if + * this is not part of a Fast BSS Transition. + */ + wpa_printf(MSG_DEBUG, "WPA: Clear old PTK"); + sm->ptk_set = 0; + os_memset(&sm->ptk, 0, sizeof(sm->ptk)); + sm->tptk_set = 0; + os_memset(&sm->tptk, 0, sizeof(sm->tptk)); + os_memset(&sm->gtk, 0, sizeof(sm->gtk)); + os_memset(&sm->igtk, 0, sizeof(sm->igtk)); + } +} + + +/** + * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * + * This function is called to let WPA state machine know that the connection + * was lost. This will abort any existing pre-authentication session. + */ +void wpa_sm_notify_disassoc(struct wpa_sm *sm) +{ + eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); + pmksa_cache_clear_current(sm); +#ifdef CONFIG_IEEE80211R + sm->ft_reassoc_completed = 0; + sm->ft_protocol = 0; +#endif /* CONFIG_IEEE80211R */ + + /* Keys are not needed in the WPA state machine anymore */ + wpa_sm_drop_sa(sm); + + os_memset(sm->bssid, 0, ETH_ALEN); +} + void wpa_set_profile(u32 wpa_proto, u8 auth_mode) { @@ -2707,6 +2839,18 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len) return 0; } +void wpa_sm_drop_sa(struct wpa_sm *sm) +{ + wpa_printf(MSG_DEBUG, "WPA: Clear old PMK and PTK"); + sm->ptk_set = 0; + sm->tptk_set = 0; + sm->pmk_len = 0; + os_memset(&sm->ptk, 0, sizeof(sm->ptk)); + os_memset(&sm->tptk, 0, sizeof(sm->tptk)); + os_memset(&sm->gtk, 0, sizeof(sm->gtk)); + os_memset(&sm->igtk, 0, sizeof(sm->igtk)); +} + #ifdef CONFIG_OWE_STA struct wpabuf *owe_build_assoc_req(struct wpa_sm *sm, u16 group) { diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index 908d3b9263..4f7a768fc6 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -58,6 +58,8 @@ int wpa_sm_set_ap_rsnxe(const u8 *ie, size_t len); int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len); +void wpa_sm_drop_sa(struct wpa_sm *sm); + #ifdef CONFIG_IEEE80211R int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len); @@ -123,6 +125,10 @@ struct wpa_sm * get_wpa_sm(void); void wpa_sm_set_pmk_from_pmksa(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); + int owe_process_assoc_resp(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_ie, size_t dh_len); struct wpabuf *owe_build_assoc_req(struct wpa_sm *sm, u16 group); diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index f150ca2702..79d8535701 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -36,6 +36,11 @@ struct wpa_sm { u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; int rx_replay_counter_set; u8 request_counter[WPA_REPLAY_COUNTER_LEN]; + struct wpa_gtk gtk; +#ifdef CONFIG_IEEE80211W + struct wpa_igtk igtk; +#endif /* CONFIG_IEEE80211W */ + struct rsn_pmksa_cache *pmksa; /* PMKSA cache */ struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */ u8 ssid[32];