fix(esp_wifi): Add alt snonce verification in softAP

This commit is contained in:
Kapil Gupta
2026-02-24 10:45:16 +05:30
parent dedef930a5
commit d588a95acb
2 changed files with 75 additions and 3 deletions

View File

@@ -43,6 +43,10 @@
static int wpa_sm_step(struct wpa_state_machine *sm);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len, struct wpa_ptk *ptk);
static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
size_t data_len);
static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
size_t data_len);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
@@ -733,6 +737,14 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *s
!wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
int i;
if (msg == PAIRWISE_4 && sm->alt_snonce_valid &&
sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
os_memcmp(key->replay_counter, sm->alt_replay_counter,
WPA_REPLAY_COUNTER_LEN) == 0) {
wpa_printf(MSG_DEBUG, "WPA: Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
goto continue_processing;
}
if (msg == PAIRWISE_2 &&
wpa_replay_counter_valid(sm->prev_key_replay,
key->replay_counter) &&
@@ -746,9 +758,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *s
* pending requests, so allow the SNonce to be updated
* even if we have already sent out EAPOL-Key 3/4.
*/
wpa_printf(MSG_DEBUG, "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
sm->update_snonce = 1;
wpa_replay_counter_mark_invalid(sm->prev_key_replay,
key->replay_counter);
os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
sm->alt_snonce_valid = TRUE;
os_memcpy(sm->alt_replay_counter, sm->key_replay[0].counter,
WPA_REPLAY_COUNTER_LEN);
goto continue_processing;
}
@@ -862,7 +877,9 @@ continue_processing:
sm->MICVerified = FALSE;
if (sm->PTK_valid && !sm->update_snonce) {
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
data_len)) {
data_len) &&
(msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
wpa_try_alt_snonce(sm, data, data_len))) {
wpa_printf(MSG_INFO,
"received EAPOL-Key with invalid MIC");
return;
@@ -1210,6 +1227,56 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
eloop_register_timeout(1, 0, resend_eapol_handle, (void*)(sm->index), NULL);
}
static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
size_t data_len)
{
struct wpa_ptk PTK;
int ok = 0;
const u8 *pmk = NULL;
unsigned int pmk_len;
os_memset(&PTK, 0, sizeof(PTK));
for (;;) {
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
if (pmk == NULL)
break;
pmk_len = PMK_LEN;
} else {
pmk = sm->PMK;
pmk_len = sm->pmk_len;
}
if (!pmk && sm->pmksa) {
pmk = sm->pmksa->pmk;
pmk_len = sm->pmksa->pmk_len;
}
wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK);
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len) == 0) {
ok = 1;
break;
}
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
}
if (ok) {
wpa_printf(MSG_DEBUG, "WPA: Verified Key MIC using alt_SNonce");
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
sm->alt_snonce_valid = FALSE;
return 0;
}
return -1;
}
static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
size_t data_len)
{
@@ -1246,6 +1313,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
memset(&sm->PTK, 0, sizeof(sm->PTK));
wpa_auth_set_key(sm->wpa_auth, 0, WIFI_WPA_ALG_NONE, sm->addr, 0, NULL, 0);
sm->pairwise_set = FALSE;
sm->alt_snonce_valid = FALSE;
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
}

View File

@@ -86,6 +86,7 @@ struct wpa_state_machine {
unsigned int mgmt_frame_prot:1;
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
unsigned int alt_snonce_valid:1;
#ifdef CONFIG_IEEE80211R_AP
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
@@ -96,6 +97,9 @@ struct wpa_state_machine {
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
u8 alt_SNonce[WPA_NONCE_LEN];
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
u8 *wpa_ie;
size_t wpa_ie_len;
u8 *rsnxe;