mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
fix(esp_wifi): Add alt snonce verification in softAP
This commit is contained in:
@@ -44,6 +44,10 @@
|
|||||||
|
|
||||||
|
|
||||||
static int wpa_sm_step(struct wpa_state_machine *sm);
|
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,
|
static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
|
||||||
size_t data_len);
|
size_t data_len);
|
||||||
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
|
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
|
||||||
@@ -776,6 +780,14 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *s
|
|||||||
!wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
|
!wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
|
||||||
int i;
|
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 &&
|
if (msg == PAIRWISE_2 &&
|
||||||
wpa_replay_counter_valid(sm->prev_key_replay,
|
wpa_replay_counter_valid(sm->prev_key_replay,
|
||||||
key->replay_counter) &&
|
key->replay_counter) &&
|
||||||
@@ -789,9 +801,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *s
|
|||||||
* pending requests, so allow the SNonce to be updated
|
* pending requests, so allow the SNonce to be updated
|
||||||
* even if we have already sent out EAPOL-Key 3/4.
|
* 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;
|
sm->update_snonce = 1;
|
||||||
wpa_replay_counter_mark_invalid(sm->prev_key_replay,
|
os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
|
||||||
key->replay_counter);
|
sm->alt_snonce_valid = TRUE;
|
||||||
|
os_memcpy(sm->alt_replay_counter, sm->key_replay[0].counter,
|
||||||
|
WPA_REPLAY_COUNTER_LEN);
|
||||||
goto continue_processing;
|
goto continue_processing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,7 +920,9 @@ continue_processing:
|
|||||||
sm->MICVerified = FALSE;
|
sm->MICVerified = FALSE;
|
||||||
if (sm->PTK_valid && !sm->update_snonce) {
|
if (sm->PTK_valid && !sm->update_snonce) {
|
||||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
|
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,
|
wpa_printf(MSG_INFO,
|
||||||
"received EAPOL-Key with invalid MIC");
|
"received EAPOL-Key with invalid MIC");
|
||||||
return;
|
return;
|
||||||
@@ -1254,6 +1271,56 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
|||||||
eloop_register_timeout(1, 0, resend_eapol_handle, (void*)(sm->index), NULL);
|
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,
|
static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
|
||||||
size_t data_len)
|
size_t data_len)
|
||||||
{
|
{
|
||||||
@@ -1290,6 +1357,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
|
|||||||
memset(&sm->PTK, 0, sizeof(sm->PTK));
|
memset(&sm->PTK, 0, sizeof(sm->PTK));
|
||||||
wpa_auth_set_key(sm->wpa_auth, 0, WIFI_WPA_ALG_NONE, sm->addr, 0, NULL, 0);
|
wpa_auth_set_key(sm->wpa_auth, 0, WIFI_WPA_ALG_NONE, sm->addr, 0, NULL, 0);
|
||||||
sm->pairwise_set = FALSE;
|
sm->pairwise_set = FALSE;
|
||||||
|
sm->alt_snonce_valid = FALSE;
|
||||||
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
|
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ struct wpa_state_machine {
|
|||||||
unsigned int mgmt_frame_prot:1;
|
unsigned int mgmt_frame_prot:1;
|
||||||
unsigned int rx_eapol_key_secure:1;
|
unsigned int rx_eapol_key_secure:1;
|
||||||
unsigned int update_snonce:1;
|
unsigned int update_snonce:1;
|
||||||
|
unsigned int alt_snonce_valid:1;
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
unsigned int ft_completed:1;
|
unsigned int ft_completed:1;
|
||||||
unsigned int pmk_r1_name_valid:1;
|
unsigned int pmk_r1_name_valid:1;
|
||||||
@@ -96,6 +97,9 @@ struct wpa_state_machine {
|
|||||||
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||||
int req_replay_counter_used;
|
int req_replay_counter_used;
|
||||||
|
|
||||||
|
u8 alt_SNonce[WPA_NONCE_LEN];
|
||||||
|
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||||
|
|
||||||
u8 *wpa_ie;
|
u8 *wpa_ie;
|
||||||
size_t wpa_ie_len;
|
size_t wpa_ie_len;
|
||||||
u8 *rsnxe;
|
u8 *rsnxe;
|
||||||
|
|||||||
Reference in New Issue
Block a user