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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2018-04-08 20:06:40 +03:00
parent 06b1a10434
commit 852b2f2738
8 changed files with 37 additions and 27 deletions

View file

@ -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); eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
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); pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0);
if (entry) { if (entry) {
sec = pmksa->pmksa->reauth_time - now.sec; sec = pmksa->pmksa->reauth_time - now.sec;
if (sec < 0) if (sec < 0)
@ -341,17 +341,20 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
* @aa: Authenticator address or %NULL to match any * @aa: Authenticator address or %NULL to match any
* @pmkid: PMKID or %NULL to match any * @pmkid: PMKID or %NULL to match any
* @network_ctx: Network context 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 * 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 *pmkid,
const void *network_ctx) const void *network_ctx,
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) &&
(pmkid == NULL || (pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
(!akmp || akmp == entry->akmp) &&
(network_ctx == NULL || network_ctx == entry->network_ctx)) (network_ctx == NULL || network_ctx == entry->network_ctx))
return entry; return entry;
entry = entry->next; 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() * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context * @network_ctx: Network configuration context
* @aa: Authenticator address for the new AP * @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 * 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 * 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 * struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, 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; 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) if (network_ctx == NULL)
return NULL; return NULL;
while (entry) { 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); entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) { if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added " 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, int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx, 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; struct rsn_pmksa_cache *pmksa = sm->pmksa;
wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " 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) if (pmkid)
wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
pmkid, PMKID_LEN); pmkid, PMKID_LEN);
@ -495,14 +502,14 @@ 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, pmkid,
network_ctx); 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, NULL,
network_ctx); 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,
bssid); bssid, akmp);
if (sm->cur_pmksa == NULL && fils_cache_id) if (sm->cur_pmksa == NULL && fils_cache_id)
sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa, sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa,
network_ctx, network_ctx,

View file

@ -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); 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 *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); 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 * pmksa_cache_head(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * 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); void pmksa_cache_clear_current(struct wpa_sm *sm);
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx, 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 * struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, 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, 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);

View file

@ -323,7 +323,7 @@ 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); p = pmksa_cache_get(sm->pmksa, candidate->bssid, 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 "
@ -372,7 +372,7 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
if (sm->network_ctx && sm->proactive_key_caching) if (sm->network_ctx && sm->proactive_key_caching)
pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx, pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
bssid); bssid, 0);
if (!preauth) { if (!preauth) {
wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without " 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)) if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
return; return;
pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL); pmksa = pmksa_cache_get(sm->pmksa, bssid, 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

@ -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 * 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, pmkid,
NULL); 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,
"RSN: found matching PMKID from PMKSA cache"); "RSN: found matching PMKID from PMKSA cache");
@ -354,8 +354,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, 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");
@ -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, int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx) 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;
} }

View file

@ -335,7 +335,7 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
for (i = 0; i < ie.num_pmkid; i++) { for (i = 0; i < ie.num_pmkid; i++) {
pmksa_set = pmksa_cache_set_current(wpa_s->wpa, pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
ie.pmkid + i * PMKID_LEN, ie.pmkid + i * PMKID_LEN,
NULL, NULL, 0, NULL); NULL, NULL, 0, NULL, 0);
if (pmksa_set == 0) { if (pmksa_set == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol); eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
break; 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 */ /* Update the current PMKSA used for this connection */
pmksa_cache_set_current(wpa_s->wpa, pmksa_cache_set_current(wpa_s->wpa,
data->assoc_info.fils_pmkid, data->assoc_info.fils_pmkid,
NULL, NULL, 0, NULL); NULL, NULL, 0, NULL, 0);
} }
} }
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */

View file

@ -348,7 +348,7 @@ int main(int argc, char *argv[])
ret = -2; ret = -2;
else { else {
ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0, ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0,
NULL) ? 0 : -3; NULL, 0) ? 0 : -3;
} }
test_eapol_clean(&wpa_s); test_eapol_clean(&wpa_s);

View file

@ -333,7 +333,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
wpa_s->current_ssid, wpa_s->current_ssid,
try_opportunistic, cache_id) == 0) try_opportunistic, cache_id,
0) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol); eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid, 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 #ifdef CONFIG_SAE
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE && if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0, 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, wpa_dbg(wpa_s, MSG_DEBUG,
"PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication"); "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); 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, if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
ssid, 0, ssid, 0,
wpa_bss_get_fils_cache_id(bss)) == wpa_bss_get_fils_cache_id(bss),
0) 0) == 0)
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"SME: Try to use FILS with PMKSA caching"); "SME: Try to use FILS with PMKSA caching");
resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md); resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md);

View file

@ -2427,7 +2427,7 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
ssid, try_opportunistic, ssid, try_opportunistic,
cache_id) == 0) cache_id, 0) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol); eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
wpa_ie_len = max_wpa_ie_len; wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid, if (wpa_supplicant_set_suites(wpa_s, bss, ssid,