From 852b2f2738178f90b95c886176faf75ef301a296 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 8 Apr 2018 20:06:40 +0300 Subject: [PATCH] SAE: Only allow SAE AKMP for PMKSA caching attempts Explicitly check the PMKSA cache entry to have matching SAE AKMP for the case where determining whether to use PMKSA caching instead of new SAE authentication. Previously, only the network context was checked, but a single network configuration profile could be used with both WPA2-PSK and SAE, so should check the AKMP as well. Signed-off-by: Jouni Malinen --- src/rsn_supp/pmksa_cache.c | 25 ++++++++++++++++--------- src/rsn_supp/pmksa_cache.h | 8 +++++--- src/rsn_supp/preauth.c | 6 +++--- src/rsn_supp/wpa.c | 8 ++++---- wpa_supplicant/events.c | 4 ++-- wpa_supplicant/preauth_test.c | 2 +- wpa_supplicant/sme.c | 9 +++++---- wpa_supplicant/wpa_supplicant.c | 2 +- 8 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index f5024f20f..fdd522087 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -96,7 +96,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : - pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL); + pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0); if (entry) { sec = pmksa->pmksa->reauth_time - now.sec; if (sec < 0) @@ -341,17 +341,20 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) * @aa: Authenticator address or %NULL to match any * @pmkid: PMKID or %NULL to match any * @network_ctx: Network context or %NULL to match any + * @akmp: Specific AKMP to search for or 0 for any * 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 void *network_ctx) + 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) && (pmkid == NULL || os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && + (!akmp || akmp == entry->akmp) && (network_ctx == NULL || network_ctx == entry->network_ctx)) return entry; entry = entry->next; @@ -390,6 +393,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @network_ctx: Network configuration context * @aa: Authenticator address for the new AP + * @akmp: Specific AKMP to search for or 0 for any * Returns: Pointer to a new PMKSA cache entry or %NULL if not available * * Try to create a new PMKSA cache entry opportunistically by guessing that the @@ -398,7 +402,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, */ struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *aa) + const u8 *aa, int akmp) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; @@ -406,7 +410,8 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, if (network_ctx == NULL) return NULL; while (entry) { - if (entry->network_ctx == network_ctx) { + if (entry->network_ctx == network_ctx && + (!akmp || entry->akmp == akmp)) { entry = pmksa_cache_clone_entry(pmksa, entry, aa); if (entry) { wpa_printf(MSG_DEBUG, "RSN: added " @@ -476,11 +481,13 @@ void pmksa_cache_clear_current(struct wpa_sm *sm) */ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, - int try_opportunistic, const u8 *fils_cache_id) + int try_opportunistic, const u8 *fils_cache_id, + int akmp) { struct rsn_pmksa_cache *pmksa = sm->pmksa; wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " - "try_opportunistic=%d", network_ctx, try_opportunistic); + "try_opportunistic=%d akmp=0x%x", + network_ctx, try_opportunistic, akmp); if (pmkid) wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", pmkid, PMKID_LEN); @@ -495,14 +502,14 @@ 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); + network_ctx, akmp); if (sm->cur_pmksa == NULL && bssid) sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, - network_ctx); + network_ctx, akmp); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, network_ctx, - bssid); + bssid, akmp); if (sm->cur_pmksa == NULL && fils_cache_id) sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa, network_ctx, diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index f9a72a6f6..626761dea 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -61,7 +61,8 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, 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 void *network_ctx); + const void *network_ctx, + int akmp); int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * @@ -76,10 +77,11 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); void pmksa_cache_clear_current(struct wpa_sm *sm); int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, - int try_opportunistic, const u8 *fils_cache_id); + int try_opportunistic, const u8 *fils_cache_id, + int akmp); struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, - void *network_ctx, const u8 *aa); + 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); diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c index d4276b953..d0c43f464 100644 --- a/src/rsn_supp/preauth.c +++ b/src/rsn_supp/preauth.c @@ -323,7 +323,7 @@ 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); + p = pmksa_cache_get(sm->pmksa, candidate->bssid, 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 " @@ -372,7 +372,7 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, if (sm->network_ctx && sm->proactive_key_caching) pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx, - bssid); + bssid, 0); if (!preauth) { wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without " @@ -483,7 +483,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); + pmksa = pmksa_cache_get(sm->pmksa, bssid, 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 f84d7d01c..da01494a3 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -268,7 +268,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, * 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, - NULL); + NULL, 0); if (sm->cur_pmksa) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: found matching PMKID from PMKSA cache"); @@ -354,8 +354,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)) - { + pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL, + 0)) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: the new PMK matches with the " "PMKID"); @@ -3130,7 +3130,7 @@ 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, const void *network_ctx) { - return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx) != NULL; + return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx, 0) != NULL; } diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 19c8475b6..7c5452802 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -335,7 +335,7 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s) for (i = 0; i < ie.num_pmkid; i++) { pmksa_set = pmksa_cache_set_current(wpa_s->wpa, ie.pmkid + i * PMKID_LEN, - NULL, NULL, 0, NULL); + NULL, NULL, 0, NULL, 0); if (pmksa_set == 0) { eapol_sm_notify_pmkid_attempt(wpa_s->eapol); break; @@ -3805,7 +3805,7 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, /* Update the current PMKSA used for this connection */ pmksa_cache_set_current(wpa_s->wpa, data->assoc_info.fils_pmkid, - NULL, NULL, 0, NULL); + NULL, NULL, 0, NULL, 0); } } #endif /* CONFIG_FILS */ diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c index a213a30f1..f2fff550a 100644 --- a/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant/preauth_test.c @@ -348,7 +348,7 @@ int main(int argc, char *argv[]) ret = -2; else { ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0, - NULL) ? 0 : -3; + NULL, 0) ? 0 : -3; } test_eapol_clean(&wpa_s); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 460e4e6a7..8481b9aab 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -333,7 +333,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #endif /* CONFIG_FILS */ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, wpa_s->current_ssid, - try_opportunistic, cache_id) == 0) + try_opportunistic, cache_id, + 0) == 0) eapol_sm_notify_pmkid_attempt(wpa_s->eapol); wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); if (wpa_supplicant_set_suites(wpa_s, bss, ssid, @@ -548,7 +549,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #ifdef CONFIG_SAE if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE && pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0, - NULL) == 0) { + NULL, WPA_KEY_MGMT_SAE) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication"); wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); @@ -616,8 +617,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0, - wpa_bss_get_fils_cache_id(bss)) == - 0) + wpa_bss_get_fils_cache_id(bss), + 0) == 0) wpa_printf(MSG_DEBUG, "SME: Try to use FILS with PMKSA caching"); resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 9808640ea..9ee099613 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2427,7 +2427,7 @@ static u8 * wpas_populate_assoc_ies( #endif /* CONFIG_FILS */ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, try_opportunistic, - cache_id) == 0) + cache_id, 0) == 0) eapol_sm_notify_pmkid_attempt(wpa_s->eapol); wpa_ie_len = max_wpa_ie_len; if (wpa_supplicant_set_suites(wpa_s, bss, ssid,