diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index fb77f1dbd..4cdca3491 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3971,10 +3971,12 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, #ifdef CONFIG_FILS /* Update ERP next sequence number */ - if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) + if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) { eapol_sm_update_erp_next_seq_num( wpa_s->eapol, data->assoc_reject.fils_erp_next_seq_num); + fils_connection_failure(wpa_s); + } #endif /* CONFIG_FILS */ wpas_connection_failed(wpa_s, bssid); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index d57195f15..b68506474 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -591,6 +591,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_key_mgmt_fils(ssid->key_mgmt)) { const u8 *indic; u16 fils_info; + const u8 *realm, *username, *rrk; + size_t realm_len, username_len, rrk_len; + u16 next_seq_num; /* * Check FILS Indication element (FILS Information field) bits @@ -620,6 +623,19 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, goto no_fils; } + if (wpa_s->last_con_fail_realm && + eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, + &username, &username_len, + &realm, &realm_len, &next_seq_num, + &rrk, &rrk_len) == 0 && + realm && realm_len == wpa_s->last_con_fail_realm_len && + os_memcmp(realm, wpa_s->last_con_fail_realm, + realm_len) == 0) { + wpa_printf(MSG_DEBUG, + "SME: FILS authentication for this realm failed last time - try to regenerate ERP key hierarchy"); + goto no_fils; + } + if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0, wpa_bss_get_fils_cache_id(bss), @@ -1195,6 +1211,12 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) ie_txt ? ie_txt : ""); os_free(ie_txt); +#ifdef CONFIG_FILS + if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS || + wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS) + fils_connection_failure(wpa_s); +#endif /* CONFIG_FILS */ + if (data->auth.status_code != WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG || wpa_s->sme.auth_alg == data->auth.auth_type || diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 0c090a93c..8bd27274f 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -280,6 +280,9 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout"); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); wpa_blacklist_del(wpa_s, wpa_s->bssid); + os_free(wpa_s->last_con_fail_realm); + wpa_s->last_con_fail_realm = NULL; + wpa_s->last_con_fail_realm_len = 0; } @@ -504,6 +507,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->confanother); wpa_s->confanother = NULL; + os_free(wpa_s->last_con_fail_realm); + wpa_s->last_con_fail_realm = NULL; + wpa_s->last_con_fail_realm_len = 0; + wpa_sm_set_eapol(wpa_s->wpa, NULL); eapol_sm_deinit(wpa_s->eapol); wpa_s->eapol = NULL; @@ -2545,7 +2552,10 @@ static u8 * wpas_populate_assoc_ies( ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) && eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username, &username_len, &realm, &realm_len, - &next_seq_num, &rrk, &rrk_len) == 0) { + &next_seq_num, &rrk, &rrk_len) == 0 && + (!wpa_s->last_con_fail_realm || + wpa_s->last_con_fail_realm_len != realm_len || + os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) { algs = WPA_AUTH_ALG_FILS; params->fils_erp_username = username; params->fils_erp_username_len = username_len; @@ -6504,6 +6514,35 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) } +#ifdef CONFIG_FILS +void fils_connection_failure(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + const u8 *realm, *username, *rrk; + size_t realm_len, username_len, rrk_len; + u16 next_seq_num; + + if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) || + eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, + &username, &username_len, + &realm, &realm_len, &next_seq_num, + &rrk, &rrk_len) != 0 || + !realm) + return; + + wpa_hexdump_ascii(MSG_DEBUG, + "FILS: Store last connection failure realm", + realm, realm_len); + os_free(wpa_s->last_con_fail_realm); + wpa_s->last_con_fail_realm = os_malloc(realm_len); + if (wpa_s->last_con_fail_realm) { + wpa_s->last_con_fail_realm_len = realm_len; + os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len); + } +} +#endif /* CONFIG_FILS */ + + int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s) { return wpa_s->conf->ap_scan == 2 || diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 2b0dca0ef..c6d6d84d8 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -532,6 +532,8 @@ struct wpa_supplicant { struct wpa_bss *current_bss; int ap_ies_from_associnfo; unsigned int assoc_freq; + u8 *last_con_fail_realm; + size_t last_con_fail_realm_len; /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ int pairwise_cipher; @@ -1316,6 +1318,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s); void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid); +void fils_connection_failure(struct wpa_supplicant *wpa_s); int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s); int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s); void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason);