diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index cb2a8674a..97a01a2f8 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -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) diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index 83faa0584..ae7bc13fa 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -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) { } diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 78e2380b1..e01cd5217 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -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); } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index f377acba2..ff8a85b6e 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -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) { diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 4e8b30aba..8a6a829b6 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 9b8dca5bc..cc184dba5 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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);