DPP: Drop PMKSA entry if AP reject association due to invalid PMKID

This is needed to avoid trying the subsequent connections with the old
PMKID that the AP claims not to hold and continues connection failures.
This was already handled for the SME-in-the-driver case in commit commit
50b77f50e8 ("DPP: Flush PMKSA if an assoc reject without timeout is
received"), but the wpa_supplicant SME case did not have matching
processing.

Add the needed check to avoid recover from cases where the AP has
dropped its PMKSA cache entry. Do this only based on the specific status
code value (53 = invalid PMKID) and only for the PMKSA entry that
triggered this failure to minimize actions taken based on an unprotected
(Re)Association Response frame.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2022-11-20 08:00:36 +02:00
parent 1e602adabb
commit 5ea7a2f545
5 changed files with 73 additions and 0 deletions

View file

@ -57,6 +57,34 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
}
void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *e;
e = pmksa->pmksa;
while (e) {
if (e == entry) {
pmksa->pmksa = entry->next;
break;
}
if (e->next == entry) {
e->next = entry->next;
break;
}
}
if (!e) {
wpa_printf(MSG_DEBUG,
"RSN: Could not remove PMKSA cache entry %p since it is not in the list",
entry);
return;
}
pmksa_cache_free_entry(pmksa, entry, PMKSA_FREE);
}
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;

View file

@ -90,6 +90,8 @@ 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, bool external_only);
void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry);
void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa);
#else /* IEEE8021X_EAPOL */
@ -170,6 +172,11 @@ static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
{
}
static inline void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
}
static inline void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa)
{
}

View file

@ -4751,6 +4751,14 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
}
void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm,
struct rsn_pmksa_cache_entry *entry)
{
if (sm && sm->pmksa)
pmksa_cache_remove(sm->pmksa, entry);
}
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");

View file

@ -229,6 +229,8 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
const u8 *pmkid,
const void *network_ctx,
int akmp);
void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm,
struct rsn_pmksa_cache_entry *entry);
bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md);
int wpa_sm_has_ptk_installed(struct wpa_sm *sm);

View file

@ -2300,6 +2300,34 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SAE */
#ifdef CONFIG_DPP
if (wpa_s->current_ssid &&
wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
!data->assoc_reject.timed_out &&
data->assoc_reject.status_code == WLAN_STATUS_INVALID_PMKID) {
struct rsn_pmksa_cache_entry *pmksa;
pmksa = pmksa_cache_get_current(wpa_s->wpa);
if (pmksa) {
wpa_dbg(wpa_s, MSG_DEBUG,
"DPP: Drop PMKSA cache entry for the BSS due to invalid PMKID report");
wpa_sm_pmksa_cache_remove(wpa_s->wpa, pmksa);
}
wpa_sm_aborted_cached(wpa_s->wpa);
if (wpa_s->current_bss) {
struct wpa_bss *bss = wpa_s->current_bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_dbg(wpa_s, MSG_DEBUG,
"DPP: Try network introduction again");
wpas_connect_work_done(wpa_s);
wpa_supplicant_mark_disassoc(wpa_s);
wpa_supplicant_connect(wpa_s, bss, ssid);
return;
}
}
#endif /* CONFIG_DPP */
/*
* For now, unconditionally terminate the previous authentication. In
* theory, this should not be needed, but mac80211 gets quite confused