diff options
Diffstat (limited to 'src/rsn_supp/pmksa_cache.c')
-rw-r--r-- | src/rsn_supp/pmksa_cache.c | 79 |
1 files changed, 52 insertions, 27 deletions
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index df675834c6f48..ef7b683864765 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - RSN PMKSA cache - * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -15,7 +15,7 @@ #include "wpa_i.h" #include "pmksa_cache.h" -#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) +#ifdef IEEE8021X_EAPOL static const int pmksa_cache_max_entries = 32; @@ -35,7 +35,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) { - os_free(entry); + bin_clear_free(entry, sizeof(*entry)); } @@ -53,9 +53,9 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) { struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; pmksa->pmksa = entry->next; @@ -80,13 +80,13 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) { int sec; struct rsn_pmksa_cache_entry *entry; - struct os_time now; + struct os_reltime now; eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); if (pmksa->pmksa == NULL) return; - os_get_time(&now); + os_get_reltime(&now); sec = pmksa->pmksa->expiration - now.sec; if (sec < 0) sec = 0; @@ -109,6 +109,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @pmk: The new pairwise master key * @pmk_len: PMK length in bytes, usually PMK_LEN (32) + * @kck: Key confirmation key or %NULL if not yet derived + * @kck_len: KCK length in bytes * @aa: Authenticator address * @spa: Supplicant address * @network_ctx: Network configuration context for this PMK @@ -122,22 +124,31 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) */ struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, + const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { struct rsn_pmksa_cache_entry *entry, *pos, *prev; - struct os_time now; + struct os_reltime now; if (pmk_len > PMK_LEN) return NULL; + if (wpa_key_mgmt_suite_b(akmp) && !kck) + return NULL; + entry = os_zalloc(sizeof(*entry)); if (entry == NULL) return NULL; os_memcpy(entry->pmk, pmk, pmk_len); entry->pmk_len = pmk_len; - rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, - wpa_key_mgmt_sha256(akmp)); - os_get_time(&now); + if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid); + else if (wpa_key_mgmt_suite_b(akmp)) + rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid); + else + rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, + wpa_key_mgmt_sha256(akmp)); + os_get_reltime(&now); entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; @@ -152,9 +163,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, while (pos) { if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { if (pos->pmk_len == pmk_len && - os_memcmp(pos->pmk, pmk, pmk_len) == 0 && - os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == - 0) { + os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 && + os_memcmp_const(pos->pmkid, entry->pmkid, + PMKID_LEN) == 0) { wpa_printf(MSG_DEBUG, "WPA: reusing previous " "PMKSA entry"); os_free(entry); @@ -164,17 +175,23 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, pmksa->pmksa = pos->next; else prev->next = pos->next; - wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " - "the current AP"); - pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); /* * If OKC is used, there may be other PMKSA cache * entries based on the same PMK. These needs to be * flushed so that a new entry can be created based on - * the new PMK. + * the new PMK. Only clear other entries if they have a + * matching PMK and this PMK has been used successfully + * with the current AP, i.e., if opportunistic flag has + * been cleared in wpa_supplicant_key_neg_complete(). */ - pmksa_cache_flush(pmksa, network_ctx); + wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " + "the current AP and any PMKSA cache entry " + "that was based on the old PMK"); + if (!pos->opportunistic) + pmksa_cache_flush(pmksa, network_ctx, pos->pmk, + pos->pmk_len); + pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); break; } prev = pos; @@ -235,15 +252,22 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, * pmksa_cache_flush - Flush PMKSA cache entries for a specific network * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @network_ctx: Network configuration context or %NULL to flush all entries + * @pmk: PMK to match for or %NYLL to match all PMKs + * @pmk_len: PMK length */ -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) { struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; int removed = 0; entry = pmksa->pmksa; while (entry) { - if (entry->network_ctx == network_ctx || network_ctx == NULL) { + if ((entry->network_ctx == network_ctx || + network_ctx == NULL) && + (pmk == NULL || + (pmk_len == entry->pmk_len && + os_memcmp(pmk, entry->pmk, pmk_len) == 0))) { wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " "for " MACSTR, MAC2STR(entry->aa)); if (prev) @@ -320,6 +344,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *new_entry; new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, + NULL, 0, aa, pmksa->sm->own_addr, old_entry->network_ctx, old_entry->akmp); if (new_entry == NULL) @@ -453,13 +478,13 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) int i, ret; char *pos = buf; struct rsn_pmksa_cache_entry *entry; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); ret = os_snprintf(pos, buf + len - pos, "Index / AA / PMKID / expiration (in seconds) / " "opportunistic\n"); - if (ret < 0 || ret >= buf + len - pos) + if (os_snprintf_error(buf + len - pos, ret)) return pos - buf; pos += ret; i = 0; @@ -468,7 +493,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) i++; ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", i, MAC2STR(entry->aa)); - if (ret < 0 || ret >= buf + len - pos) + if (os_snprintf_error(buf + len - pos, ret)) return pos - buf; pos += ret; pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, @@ -476,7 +501,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) ret = os_snprintf(pos, buf + len - pos, " %d %d\n", (int) (entry->expiration - now.sec), entry->opportunistic); - if (ret < 0 || ret >= buf + len - pos) + if (os_snprintf_error(buf + len - pos, ret)) return pos - buf; pos += ret; entry = entry->next; @@ -509,4 +534,4 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, return pmksa; } -#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ +#endif /* IEEE8021X_EAPOL */ |