]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FILS: Flush PMKSA entries on FILS connection failure
authorVeerendranath Jakkam <vjakkam@codeaurora.org>
Thu, 1 Jul 2021 16:40:23 +0000 (22:10 +0530)
committerJouni Malinen <j@w1.fi>
Wed, 14 Jul 2021 18:20:17 +0000 (21:20 +0300)
wpa_supplicant generates both a PMKSA cache entry and ERP keys upon
successful FILS connection and uses FILS authentication algorithm for
subsequent connections when either ERP keys or a PMKSA cache entry is
available.

In some cases, like AP/RADIUS server restart, both ERP keys and PMKSA
becomes invalid. But currently when an AP rejects an association,
wpa_supplicant marks only ERP keys as failed but not clearing PMKSA.

Since PMKSA is not cleared, consecutive connection attempts are still
happening with FILS authentication algorithm and connection attempts are
failing with the same association rejection again instead of trying to
recover from the state mismatch by deriving a new ERP key hierarchy.

Clear PMKSA entries as well on association rejection from an AP to allow
the following connection attempt to go with open authentication to
re-establish a valid ERP key hierarchy. Also, since clearing PMKSA
entries on unprotected (Re)Association Response frames could allow DoS
attack (reduce usability of PMKSA caching), clear PMKSA entries only
when ERP keys exists.

Signed-off-by: Veerendranath Jakkam <vjakkam@codeaurora.org>
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index b511d1cc14575edce08dadf1c4f600adfef6b8bd..a565e658f33db31f393a0ae15aa404dbb6b1ed39 100644 (file)
@@ -4621,6 +4621,7 @@ 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) {
+               fils_pmksa_cache_flush(wpa_s);
                eapol_sm_update_erp_next_seq_num(
                        wpa_s->eapol,
                        data->assoc_reject.fils_erp_next_seq_num);
index 0d9b9caa59067bb6a59f535f0962d5293d3ee414..9b8dca5bcac0afa5e620e02fe6685445c35425d4 100644 (file)
@@ -7537,6 +7537,35 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
 
 
 #ifdef CONFIG_FILS
+
+void fils_pmksa_cache_flush(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;
+
+       /* Clear the PMKSA cache entry if FILS authentication was rejected.
+        * Check for ERP keys existing to limit when this can be done since
+        * the rejection response is not protected and such triggers should
+        * really not allow internal state to be modified unless required to
+        * avoid significant issues in functionality. In this case, this is
+        * needed to allow recovery from cases where the AP or authentication
+        * server has dropped PMKSAs and ERP keys. */
+       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_dbg(wpa_s, MSG_DEBUG, "FILS: Drop PMKSA cache entry");
+       wpa_sm_aborted_cached(wpa_s->wpa);
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+}
+
+
 void fils_connection_failure(struct wpa_supplicant *wpa_s)
 {
        struct wpa_ssid *ssid = wpa_s->current_ssid;
index 6877f5a9960d777a405b6b6aedec1eeccef694d5..60acb53c5c387e83623e0f0af10ca4223e8c42b1 100644 (file)
@@ -1501,6 +1501,7 @@ 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);
+void fils_pmksa_cache_flush(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);