]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FILS: Flush external-PMKSA when connection fails without ERP keys
authorVeerendranath Jakkam <vjakkam@codeaurora.org>
Thu, 1 Jul 2021 18:09:06 +0000 (23:39 +0530)
committerJouni Malinen <j@w1.fi>
Wed, 14 Jul 2021 18:35:24 +0000 (21:35 +0300)
External applications can store PMKSA entries persistently and
reconfigure them to wpa_supplicant after restart. This can result in
wpa_supplicant having a PMKSA for FILS authentication without having
matching ERP keys for it which would prevent the previously added
mechanism for dropping FILS PMKSA entries to recover from rejected
association attempts.

Fix this by clearing PMKSA entries configured by external applications
upon FILS connection failure even when ERP keys are not available.

Signed-off-by: Veerendranath Jakkam <vjakkam@codeaurora.org>
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_supplicant.c

index cb2a8674a81b09e5213f3a340897701bc129efa8..97a01a2f81e8dccfa040178006a01ab0e4771d85 100644 (file)
@@ -212,7 +212,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
                                   "that was based on the old PMK");
                        if (!pos->opportunistic)
                                pmksa_cache_flush(pmksa, entry->network_ctx,
-                                                 pos->pmk, pos->pmk_len);
+                                                 pos->pmk, pos->pmk_len,
+                                                 false);
                        pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
                        break;
                }
@@ -282,9 +283,11 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
  * @network_ctx: Network configuration context or %NULL to flush all entries
  * @pmk: PMK to match for or %NULL to match all PMKs
  * @pmk_len: PMK length
+ * @external_only: Flush only PMKSA cache entries configured by external
+ * applications
  */
 void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
-                      const u8 *pmk, size_t pmk_len)
+                      const u8 *pmk, size_t pmk_len, bool external_only)
 {
        struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
        int removed = 0;
@@ -295,7 +298,8 @@ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
                     network_ctx == NULL) &&
                    (pmk == NULL ||
                     (pmk_len == entry->pmk_len &&
-                     os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
+                     os_memcmp(pmk, entry->pmk, pmk_len) == 0)) &&
+                   (!external_only || entry->external)) {
                        wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
                                   "for " MACSTR, MAC2STR(entry->aa));
                        if (prev)
index 83faa05844d62c4fe1ccb2cf974c032ab4e443b6..ae7bc13fa11869975a0c2415780f2d2544692521 100644 (file)
@@ -43,6 +43,7 @@ struct rsn_pmksa_cache_entry {
         */
        void *network_ctx;
        int opportunistic;
+       bool external;
 };
 
 struct rsn_pmksa_cache;
@@ -84,7 +85,7 @@ struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
                              void *network_ctx, const u8 *aa, int akmp);
 void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
-                      const u8 *pmk, size_t pmk_len);
+                      const u8 *pmk, size_t pmk_len, bool external_only);
 
 #else /* IEEE8021X_EAPOL */
 
@@ -157,7 +158,8 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 
 static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
                                     void *network_ctx,
-                                    const u8 *pmk, size_t pmk_len)
+                                    const u8 *pmk, size_t pmk_len,
+                                    bool external_only)
 {
 }
 
index 78e2380b15e8d6a1b039301ccb199cdd7eb394ec..e01cd52177d283e705244e534fbd99a1921409df 100644 (file)
@@ -2345,6 +2345,16 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm)
 }
 
 
+void wpa_sm_aborted_external_cached(struct wpa_sm *sm)
+{
+       if (sm && sm->cur_pmksa && sm->cur_pmksa->external) {
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "RSN: Cancelling external PMKSA caching attempt");
+               sm->cur_pmksa = NULL;
+       }
+}
+
+
 static void wpa_eapol_key_dump(struct wpa_sm *sm,
                               const struct wpa_eapol_key *key,
                               unsigned int key_data_len,
@@ -3865,7 +3875,13 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
 
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
 {
-       pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
+       pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0, false);
+}
+
+
+void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+       pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0, true);
 }
 
 
index f377acba2f2384e4c6db1e652b41a08055e54636..ff8a85b6e29ba93196a94f1a4436f549efb24981 100644 (file)
@@ -180,6 +180,7 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
                     struct wpa_ie_data *data);
 
 void wpa_sm_aborted_cached(struct wpa_sm *sm);
+void wpa_sm_aborted_external_cached(struct wpa_sm *sm);
 int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                    const u8 *buf, size_t len);
 int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
@@ -205,6 +206,7 @@ int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
 void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
 
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
 
 int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
 
@@ -353,6 +355,10 @@ static inline void wpa_sm_aborted_cached(struct wpa_sm *sm)
 {
 }
 
+static inline void wpa_sm_aborted_external_cached(struct wpa_sm *sm)
+{
+}
+
 static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                                  const u8 *buf, size_t len)
 {
@@ -392,6 +398,11 @@ static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
 {
 }
 
+static inline void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm,
+                                                    void *network_ctx)
+{
+}
+
 static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
                                            void *network_ctx)
 {
index 4e8b30aba2f332bb852c7bf4d3135ba27b75319f..8a6a829b66659b45484bb0922d49847a449e5631 100644 (file)
@@ -10623,6 +10623,8 @@ static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
 
        entry->network_ctx = ssid;
 
+       entry->external = true;
+
        wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
        entry = NULL;
        ret = 0;
index 9b8dca5bcac0afa5e620e02fe6685445c35425d4..cc184dba5febf8b439b7e5989c4ea73d5325188b 100644 (file)
@@ -7549,16 +7549,27 @@ void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
         * 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,
+        * avoid significant issues in functionality. In addition, drop
+        * externally configure PMKSA entries even without ERP keys since it
+        * is possible for an external component to add PMKSA entries for FILS
+        * authentication without restoring previously generated ERP keys.
+        *
+        * 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))
+               return;
+
+       if (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) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "FILS: Drop external PMKSA cache entry");
+               wpa_sm_aborted_external_cached(wpa_s->wpa);
+               wpa_sm_external_pmksa_cache_flush(wpa_s->wpa, ssid);
                return;
+       }
 
        wpa_dbg(wpa_s, MSG_DEBUG, "FILS: Drop PMKSA cache entry");
        wpa_sm_aborted_cached(wpa_s->wpa);