diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index f723bb0a3..d7d5bf7dc 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -117,6 +117,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) * @spa: Supplicant address * @network_ctx: Network configuration context for this PMK * @akmp: WPA_KEY_MGMT_* used in key derivation + * @cache_id: Pointer to FILS Cache Identifier or %NULL if not advertised * Returns: Pointer to the added PMKSA cache entry or %NULL on error * * This function create a PMKSA entry for a new PMK and adds it to the PMKSA @@ -127,7 +128,8 @@ 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 *pmkid, const u8 *kck, size_t kck_len, - const u8 *aa, const u8 *spa, void *network_ctx, int akmp) + const u8 *aa, const u8 *spa, void *network_ctx, int akmp, + const u8 *cache_id) { struct rsn_pmksa_cache_entry *entry; struct os_reltime now; @@ -157,6 +159,10 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; entry->akmp = akmp; + if (cache_id) { + entry->fils_cache_id_set = 1; + os_memcpy(entry->fils_cache_id, cache_id, FILS_CACHE_ID_LEN); + } os_memcpy(entry->aa, aa, ETH_ALEN); entry->network_ctx = network_ctx; @@ -362,7 +368,9 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, NULL, NULL, 0, aa, pmksa->sm->own_addr, - old_entry->network_ctx, old_entry->akmp); + old_entry->network_ctx, old_entry->akmp, + old_entry->fils_cache_id_set ? + old_entry->fils_cache_id : NULL); if (new_entry == NULL) return NULL; @@ -410,6 +418,24 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, } +static struct rsn_pmksa_cache_entry * +pmksa_cache_get_fils_cache_id(struct rsn_pmksa_cache *pmksa, + const void *network_ctx, const u8 *cache_id) +{ + struct rsn_pmksa_cache_entry *entry; + + for (entry = pmksa->pmksa; entry; entry = entry->next) { + if (network_ctx == entry->network_ctx && + entry->fils_cache_id_set && + os_memcmp(cache_id, entry->fils_cache_id, + FILS_CACHE_ID_LEN) == 0) + return entry; + } + + return NULL; +} + + /** * pmksa_cache_get_current - Get the current used PMKSA entry * @sm: Pointer to WPA state machine data from wpa_sm_init() @@ -442,11 +468,12 @@ void pmksa_cache_clear_current(struct wpa_sm *sm) * @bssid: BSSID for PMKSA or %NULL if not used * @network_ctx: Network configuration context * @try_opportunistic: Whether to allow opportunistic PMKSA caching + * @fils_cache_id: Pointer to FILS Cache Identifier or %NULL if not used * Returns: 0 if PMKSA was found or -1 if no matching entry was found */ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, - int try_opportunistic) + int try_opportunistic, const u8 *fils_cache_id) { struct rsn_pmksa_cache *pmksa = sm->pmksa; wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " @@ -457,6 +484,10 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, if (bssid) wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR, MAC2STR(bssid)); + if (fils_cache_id) + wpa_printf(MSG_DEBUG, + "RSN: Search for FILS Cache Identifier %02x%02x", + fils_cache_id[0], fils_cache_id[1]); sm->cur_pmksa = NULL; if (pmkid) @@ -469,6 +500,10 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, network_ctx, bssid); + if (sm->cur_pmksa == NULL && fils_cache_id) + sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa, + network_ctx, + fils_cache_id); if (sm->cur_pmksa) { wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", sm->cur_pmksa->pmkid, PMKID_LEN); @@ -495,11 +530,20 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) char *pos = buf; struct rsn_pmksa_cache_entry *entry; struct os_reltime now; + int cache_id_used = 0; + + for (entry = pmksa->pmksa; entry; entry = entry->next) { + if (entry->fils_cache_id_set) { + cache_id_used = 1; + break; + } + } os_get_reltime(&now); ret = os_snprintf(pos, buf + len - pos, "Index / AA / PMKID / expiration (in seconds) / " - "opportunistic\n"); + "opportunistic%s\n", + cache_id_used ? " / FILS Cache Identifier" : ""); if (os_snprintf_error(buf + len - pos, ret)) return pos - buf; pos += ret; @@ -514,12 +558,24 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) pos += ret; pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, PMKID_LEN); - ret = os_snprintf(pos, buf + len - pos, " %d %d\n", + ret = os_snprintf(pos, buf + len - pos, " %d %d", (int) (entry->expiration - now.sec), entry->opportunistic); if (os_snprintf_error(buf + len - pos, ret)) return pos - buf; pos += ret; + if (entry->fils_cache_id_set) { + ret = os_snprintf(pos, buf + len - pos, " %02x%02x", + entry->fils_cache_id[0], + entry->fils_cache_id[1]); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; + } + ret = os_snprintf(pos, buf + len - pos, "\n"); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; entry = entry->next; } return pos - buf; diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index adc251a08..f9a72a6f6 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -21,6 +21,14 @@ struct rsn_pmksa_cache_entry { int akmp; /* WPA_KEY_MGMT_* */ u8 aa[ETH_ALEN]; + /* + * If FILS Cache Identifier is included (fils_cache_id_set), this PMKSA + * cache entry is applicable to all BSSs (any BSSID/aa[]) that + * advertise the same FILS Cache Identifier within the same ESS. + */ + u8 fils_cache_id[2]; + unsigned int fils_cache_id_set:1; + os_time_t reauth_time; /** @@ -59,7 +67,8 @@ struct rsn_pmksa_cache_entry * pmksa_cache_head(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 *pmkid, const u8 *kck, size_t kck_len, - const u8 *aa, const u8 *spa, void *network_ctx, int akmp); + const u8 *aa, const u8 *spa, void *network_ctx, int akmp, + const u8 *cache_id); struct rsn_pmksa_cache_entry * pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *entry); @@ -67,7 +76,7 @@ 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); + int try_opportunistic, const u8 *fils_cache_id); struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *aa); @@ -123,7 +132,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, static inline struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, const u8 *pmkid, const u8 *kck, size_t kck_len, - const u8 *aa, const u8 *spa, void *network_ctx, int akmp) + const u8 *aa, const u8 *spa, void *network_ctx, int akmp, + const u8 *cache_id) { return NULL; } @@ -135,7 +145,8 @@ static inline void pmksa_cache_clear_current(struct wpa_sm *sm) static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, - int try_opportunistic) + int try_opportunistic, + const u8 *fils_cache_id) { return -1; } diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c index e83d07357..5f11a5309 100644 --- a/src/rsn_supp/preauth.c +++ b/src/rsn_supp/preauth.c @@ -97,7 +97,7 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, NULL, 0, sm->preauth_bssid, sm->own_addr, sm->network_ctx, - WPA_KEY_MGMT_IEEE8021X); + WPA_KEY_MGMT_IEEE8021X, NULL); } else { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: failed to get master session key from " diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 4210ea7eb..00b7ae207 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -315,6 +315,13 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, } if (res == 0) { struct rsn_pmksa_cache_entry *sa = NULL; + const u8 *fils_cache_id = NULL; + +#ifdef CONFIG_FILS + if (sm->fils_cache_id_set) + fils_cache_id = sm->fils_cache_id; +#endif /* CONFIG_FILS */ + wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " "machines", sm->pmk, pmk_len); sm->pmk_len = pmk_len; @@ -327,7 +334,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, NULL, 0, src_addr, sm->own_addr, sm->network_ctx, - sm->key_mgmt); + sm->key_mgmt, + fils_cache_id); } if (!sm->cur_pmksa && pmkid && pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL)) @@ -1371,7 +1379,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL, sm->ptk.kck, sm->ptk.kck_len, sm->bssid, sm->own_addr, - sm->network_ctx, sm->key_mgmt); + sm->network_ctx, sm->key_mgmt, NULL); if (!sm->cur_pmksa) sm->cur_pmksa = sa; } @@ -2573,7 +2581,7 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, if (bssid) { pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0, bssid, sm->own_addr, - sm->network_ctx, sm->key_mgmt); + sm->network_ctx, sm->key_mgmt, NULL); } } @@ -2656,6 +2664,15 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->wpa_ptk_rekey = config->wpa_ptk_rekey; sm->p2p = config->p2p; sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation; +#ifdef CONFIG_FILS + if (config->fils_cache_id) { + sm->fils_cache_id_set = 1; + os_memcpy(sm->fils_cache_id, config->fils_cache_id, + FILS_CACHE_ID_LEN); + } else { + sm->fils_cache_id_set = 0; + } +#endif /* CONFIG_FILS */ } else { sm->network_ctx = NULL; sm->peerkey_enabled = 0; @@ -3456,7 +3473,8 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, sm->fils_erp_pmkid, NULL, 0, sm->bssid, sm->own_addr, - sm->network_ctx, sm->key_mgmt); + sm->network_ctx, sm->key_mgmt, + NULL); } if (!sm->cur_pmksa) { diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 98162c1bf..fe0f84a10 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -109,6 +109,7 @@ struct rsn_supp_config { int wpa_ptk_rekey; int p2p; int wpa_rsc_relaxation; + const u8 *fils_cache_id; }; #ifndef CONFIG_NO_WPA diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index ab54a18f5..7073bfeda 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -148,7 +148,9 @@ struct wpa_sm { size_t fils_key_auth_len; unsigned int fils_completed:1; unsigned int fils_erp_pmkid_set:1; + unsigned int fils_cache_id_set:1; u8 fils_erp_pmkid[PMKID_LEN]; + u8 fils_cache_id[FILS_CACHE_ID_LEN]; #endif /* CONFIG_FILS */ }; diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 914bd5d9b..708b58abf 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -1317,3 +1317,19 @@ int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates) *rates = r; return len; } + + +#ifdef CONFIG_FILS +const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss) +{ + const u8 *ie; + + if (bss) { + ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); + if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7)) + return ie + 4; + } + + return NULL; +} +#endif /* CONFIG_FILS */ diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 84505fa7c..37d9fb650 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -145,6 +145,7 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss); int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates); struct wpa_bss_anqp * wpa_bss_anqp_alloc(void); int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss); +const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss); static inline int bss_is_dmg(const struct wpa_bss *bss) { diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 448615e40..500c28506 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -327,7 +327,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, 0, NULL); if (pmksa_set == 0) { eapol_sm_notify_pmkid_attempt(wpa_s->eapol); break; diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c index 6ae239f79..9cb2d92e8 100644 --- a/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant/preauth_test.c @@ -344,8 +344,8 @@ int main(int argc, char *argv[]) if (preauth_test.auth_timed_out) ret = -2; else { - ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0) - ? 0 : -3; + ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0, + NULL) ? 0 : -3; } test_eapol_clean(&wpa_s); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index b57f167b1..c2fc5f9ec 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -301,13 +301,19 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_bss_get_ie(bss, WLAN_EID_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt)) { int try_opportunistic; + const u8 *cache_id = NULL; + try_opportunistic = (ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : ssid->proactive_key_caching) && (ssid->proto & WPA_PROTO_RSN); +#ifdef CONFIG_FILS + if (wpa_key_mgmt_fils(ssid->key_mgmt)) + cache_id = wpa_bss_get_fils_cache_id(bss); +#endif /* CONFIG_FILS */ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, wpa_s->current_ssid, - try_opportunistic) == 0) + try_opportunistic, cache_id) == 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, @@ -516,8 +522,8 @@ 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) == 0) - { + pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0, + NULL) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication"); params.auth_alg = WPA_AUTH_ALG_OPEN; @@ -552,7 +558,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (params.auth_alg == WPA_AUTH_ALG_OPEN && wpa_key_mgmt_fils(ssid->key_mgmt)) { if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, - ssid, 0) == 0) + ssid, 0, + wpa_bss_get_fils_cache_id(bss)) == + 0) wpa_printf(MSG_DEBUG, "SME: Try to use FILS with PMKSA caching"); resp = fils_build_auth(wpa_s->wpa); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 10c17929e..7757a03f5 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2290,7 +2290,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) ssid->proactive_key_caching) && (ssid->proto & WPA_PROTO_RSN); if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, - ssid, try_opportunistic) == 0) + ssid, try_opportunistic, NULL) == 0) eapol_sm_notify_pmkid_attempt(wpa_s->eapol); wpa_ie_len = sizeof(wpa_ie); if (wpa_supplicant_set_suites(wpa_s, bss, ssid, diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 0d753a9c0..768911fee 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -1232,6 +1232,11 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation; +#ifdef CONFIG_FILS + if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) + conf.fils_cache_id = + wpa_bss_get_fils_cache_id(wpa_s->current_bss); +#endif /* CONFIG_FILS */ } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); }