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 <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2022-11-10 14:10:55 +02:00 committed by Jouni Malinen
parent 9f04a9c8dd
commit 9ff778fa4b
8 changed files with 28 additions and 19 deletions

View file

@ -553,7 +553,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn,
struct rsn_pmksa_cache_entry *pmksa; struct rsn_pmksa_cache_entry *pmksa;
pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, 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) if (pmksa && pasn->custom_pmkid_valid)
pmkid = pasn->custom_pmkid; pmkid = pasn->custom_pmkid;
else if (pmksa) 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, pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr,
pasn->own_addr,
pmkid, NULL, pasn->akmp); pmkid, NULL, pasn->akmp);
if (pmksa) { if (pmksa) {
wpa_printf(MSG_DEBUG, "PASN: Using PMKSA"); wpa_printf(MSG_DEBUG, "PASN: Using PMKSA");

View file

@ -148,7 +148,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
return; return;
entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : 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)) { if (entry && !wpa_key_mgmt_sae(entry->akmp)) {
sec = pmksa->pmksa->reauth_time - now.sec; sec = pmksa->pmksa->reauth_time - now.sec;
if (sec < 0) 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 * 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, 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, const void *network_ctx,
int akmp) int akmp)
{ {
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
while (entry) { while (entry) {
if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
(!spa || os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
(pmkid == NULL || (pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
(!akmp || akmp == entry->akmp) && (!akmp || akmp == entry->akmp) &&
@ -601,11 +603,11 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
sm->cur_pmksa = NULL; sm->cur_pmksa = NULL;
if (pmkid) if (pmkid)
sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, sm->own_addr,
network_ctx, akmp); pmkid, network_ctx, akmp);
if (sm->cur_pmksa == NULL && bssid) if (sm->cur_pmksa == NULL && bssid)
sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, sm->own_addr,
network_ctx, akmp); NULL, network_ctx, akmp);
if (sm->cur_pmksa == NULL && try_opportunistic && bssid) if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
network_ctx, network_ctx,

View file

@ -65,7 +65,8 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, struct wpa_sm *sm); void *ctx, struct wpa_sm *sm);
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(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, const void *network_ctx,
int akmp); int akmp);
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);

View file

@ -330,7 +330,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates, dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
struct rsn_pmksa_candidate, list) { struct rsn_pmksa_candidate, list) {
struct rsn_pmksa_cache_entry *p = NULL; 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 && if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
(p == NULL || p->opportunistic)) { (p == NULL || p->opportunistic)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA " 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)) if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
return; 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 || if (pmksa && (!pmksa->opportunistic ||
!(ie.capabilities & WPA_CAPABILITY_PREAUTH))) !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
return; return;

View file

@ -318,7 +318,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
* not have enough time to get the association information * not have enough time to get the association information
* event before receiving this 1/4 message, so try to find a * event before receiving this 1/4 message, so try to find a
* matching PMKSA cache entry here. */ * 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); NULL, 0);
if (sm->cur_pmksa) { if (sm->cur_pmksa) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, 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); fils_cache_id);
} }
if (!sm->cur_pmksa && pmkid && if (!sm->cur_pmksa && pmkid &&
pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL, pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr,
0)) { pmkid, NULL, 0)) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: the new PMK matches with the " "RSN: the new PMK matches with the "
"PMKID"); "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) 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, const void *network_ctx,
int akmp) 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);
} }

View file

@ -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, 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 *pmkid, const u8 *bssid,
const u8 *fils_cache_id); 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); const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm); void wpa_sm_drop_sa(struct wpa_sm *sm);
struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,

View file

@ -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 && if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
!(ied.key_mgmt & WPA_KEY_MGMT_DPP)) !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
return 0; /* AP does not support DPP AKM - continue */ 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 */ return 0; /* PMKSA exists for DPP AKM - continue */
if (!ssid->dpp_connector || !ssid->dpp_netaccesskey || if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||

View file

@ -1515,7 +1515,8 @@ skip_assoc_disallow:
#ifdef CONFIG_DPP #ifdef CONFIG_DPP
if ((ssid->key_mgmt & WPA_KEY_MGMT_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_connector || !ssid->dpp_netaccesskey ||
!ssid->dpp_csign)) { !ssid->dpp_csign)) {
if (debug_print) if (debug_print)