]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FILS: Fix FILS connect failures after ERP key invalidation
authorAnkita Bajaj <bankita@codeaurora.org>
Fri, 27 Jul 2018 08:25:27 +0000 (13:55 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 24 Aug 2018 13:27:34 +0000 (16:27 +0300)
If the RADIUS authentication server dropped the cached ERP keys for any
reason, FILS authentication attempts with ERP fails and the previous
wpa_supplicant implementation ended up trying to use the same keys for
all consecutive attempts as well. This did not allow recovery from state
mismatch between the ERP server and peer using full EAP authentication.

Address this by trying to use full (non-FILS) authentication when trying
to connect to an AP using the same ERP realm with FILS-enabled network
profile if the previous authentication attempt had failed. This allows
new ERP keys to be established and FILS authentication to be used again
for the consecutive connections.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index fb77f1dbd23e988435c79d35875ef5ce1d9b2106..4cdca349118cd64bd0e6a5fe7f930c45dbc3f894 100644 (file)
@@ -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);
index d57195f1531739a29f839b3abf8fcf498646bae0..b685064746d8b7c80ec5df5c7756f6e590ca1794 100644 (file)
@@ -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 ||
index 0c090a93c23879005df5b117ac4376aa08baad53..8bd27274f3ff6070970df92661f86ae2906667aa 100644 (file)
@@ -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 ||
index 2b0dca0ef2feb9d6edf3db94b182bd070c45b82d..c6d6d84d84d60e8c5dde73e8580c4668a490a575 100644 (file)
@@ -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);