From 9ff778fa4bd64b802106bd94c91fdc2a0cdc3600 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 10 Nov 2022 14:10:55 +0200 Subject: [PATCH] Check for own address (SPA) match when finding PMKSA entries This prevents attempts of trying to use PMKSA caching when the existing entry was created using a different MAC address than the one that is currently being used. This avoids exposing the longer term PMKID value when using random MAC addresses for connections. In practice, similar restriction was already done by flushing the PMKSA cache entries whenever wpas_update_random_addr() changed the local address or when the interface was marked down (e.g., for an external operation to change the MAC address). Signed-off-by: Jouni Malinen --- src/pasn/pasn_initiator.c | 3 ++- src/rsn_supp/pmksa_cache.c | 14 ++++++++------ src/rsn_supp/pmksa_cache.h | 3 ++- src/rsn_supp/preauth.c | 5 +++-- src/rsn_supp/wpa.c | 15 +++++++++------ src/rsn_supp/wpa.h | 2 +- wpa_supplicant/dpp_supplicant.c | 2 +- wpa_supplicant/events.c | 3 ++- 8 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c index 280575405..c96e6eb43 100644 --- a/src/pasn/pasn_initiator.c +++ b/src/pasn/pasn_initiator.c @@ -553,7 +553,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn, struct rsn_pmksa_cache_entry *pmksa; pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, - NULL, NULL, pasn->akmp); + pasn->own_addr, NULL, NULL, pasn->akmp); if (pmksa && pasn->custom_pmkid_valid) pmkid = pasn->custom_pmkid; else if (pmksa) @@ -795,6 +795,7 @@ static int wpas_pasn_set_pmk(struct pasn_data *pasn, } pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, + pasn->own_addr, pmkid, NULL, pasn->akmp); if (pmksa) { wpa_printf(MSG_DEBUG, "PASN: Using PMKSA"); diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index 07f64a18d..257d3444f 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -148,7 +148,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) return; entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : - pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0); + pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, NULL, 0); if (entry && !wpa_key_mgmt_sae(entry->akmp)) { sec = pmksa->pmksa->reauth_time - now.sec; if (sec < 0) @@ -419,13 +419,15 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) * Returns: Pointer to PMKSA cache entry or %NULL if no match was found */ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, + const u8 *aa, const u8 *spa, + const u8 *pmkid, const void *network_ctx, int akmp) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; while (entry) { if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && + (!spa || os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && (pmkid == NULL || os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && (!akmp || akmp == entry->akmp) && @@ -601,11 +603,11 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, sm->cur_pmksa = NULL; if (pmkid) - sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, - network_ctx, akmp); + sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, sm->own_addr, + pmkid, network_ctx, akmp); if (sm->cur_pmksa == NULL && bssid) - sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, - network_ctx, akmp); + sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, sm->own_addr, + NULL, network_ctx, akmp); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, network_ctx, diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index 55b0d7122..b34532c0a 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -65,7 +65,8 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, struct wpa_sm *sm); void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, + const u8 *aa, const u8 *spa, + const u8 *pmkid, const void *network_ctx, int akmp); int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c index a96655f77..8f86820a7 100644 --- a/src/rsn_supp/preauth.c +++ b/src/rsn_supp/preauth.c @@ -330,7 +330,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm) dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates, struct rsn_pmksa_candidate, list) { struct rsn_pmksa_cache_entry *p = NULL; - p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL, 0); + p = pmksa_cache_get(sm->pmksa, candidate->bssid, sm->own_addr, + NULL, NULL, 0); if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 && (p == NULL || p->opportunistic)) { wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA " @@ -491,7 +492,7 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) return; - pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL, 0); + pmksa = pmksa_cache_get(sm->pmksa, bssid, sm->own_addr, NULL, NULL, 0); if (pmksa && (!pmksa->opportunistic || !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) return; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 74ea66088..666a63a1a 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -318,7 +318,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, * not have enough time to get the association information * event before receiving this 1/4 message, so try to find a * matching PMKSA cache entry here. */ - sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid, + sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, + sm->own_addr, pmkid, NULL, 0); if (sm->cur_pmksa) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, @@ -434,8 +435,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, fils_cache_id); } if (!sm->cur_pmksa && pmkid && - pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL, - 0)) { + pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, + pmkid, NULL, 0)) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: the new PMK matches with the " "PMKID"); @@ -4731,10 +4732,11 @@ void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, } -int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, +int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, const u8 *own_addr, const void *network_ctx) { - return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx, 0) != NULL; + return pmksa_cache_get(sm->pmksa, bssid, own_addr, NULL, network_ctx, + 0) != NULL; } @@ -4744,7 +4746,8 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const void *network_ctx, int akmp) { - return pmksa_cache_get(sm->pmksa, aa, pmkid, network_ctx, akmp); + return pmksa_cache_get(sm->pmksa, aa, sm->own_addr, pmkid, network_ctx, + akmp); } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index f8854078a..c84564699 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -221,7 +221,7 @@ wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm, void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, const u8 *pmkid, const u8 *bssid, const u8 *fils_cache_id); -int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, +int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, const u8 *own_addr, const void *network_ctx); void wpa_sm_drop_sa(struct wpa_sm *sm); struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index e5be5ba13..6d0cd27cb 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -4358,7 +4358,7 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && !(ied.key_mgmt & WPA_KEY_MGMT_DPP)) return 0; /* AP does not support DPP AKM - continue */ - if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid)) + if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, wpa_s->own_addr, ssid)) return 0; /* PMKSA exists for DPP AKM - continue */ if (!ssid->dpp_connector || !ssid->dpp_netaccesskey || diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 0356c809a..5af3b6177 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1515,7 +1515,8 @@ skip_assoc_disallow: #ifdef CONFIG_DPP if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) && - !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) && + !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, wpa_s->own_addr, + ssid) && (!ssid->dpp_connector || !ssid->dpp_netaccesskey || !ssid->dpp_csign)) { if (debug_print)