X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fap%2Fwpa_auth.c;h=ab20705f0f3b0bb71723d25844944c5f9844043d;hb=4d64fd37b742cc1da84b2d0488c4ac3270be4b4c;hp=922bfe72584d45861a331f97b67b2556ce5d61de;hpb=2f1357fb62dad045099fbca633c62ff0a6a57653;p=thirdparty%2Fhostap.git diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 922bfe725..ab20705f0 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -1,6 +1,6 @@ /* * IEEE 802.11 RSN / WPA Authenticator - * Copyright (c) 2004-2015, Jouni Malinen + * Copyright (c) 2004-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -13,14 +13,17 @@ #include "utils/state_machine.h" #include "utils/bitfield.h" #include "common/ieee802_11_defs.h" +#include "common/ocv.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" #include "crypto/aes_siv.h" #include "crypto/crypto.h" #include "crypto/sha1.h" #include "crypto/sha256.h" +#include "crypto/sha384.h" #include "crypto/random.h" #include "eapol_auth/eapol_auth_sm.h" +#include "drivers/driver.h" #include "ap_config.h" #include "ieee802_11.h" #include "wpa_auth.h" @@ -53,18 +56,20 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, unsigned int pmk_len, - struct wpa_ptk *ptk); + struct wpa_ptk *ptk, int force_sha256); static void wpa_group_free(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_group_get(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_group_put(struct wpa_authenticator *wpa_auth, struct wpa_group *group); +static int ieee80211w_kde_len(struct wpa_state_machine *sm); static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos); static const u32 eapol_key_timeout_first = 100; /* ms */ static const u32 eapol_key_timeout_subseq = 1000; /* ms */ static const u32 eapol_key_timeout_first_group = 500; /* ms */ +static const u32 eapol_key_timeout_no_retrans = 4000; /* ms */ /* TODO: make these configurable */ static const int dot11RSNAConfigPMKLifetime = 43200; @@ -110,12 +115,13 @@ static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk, size_t *psk_len) + const u8 *prev_psk, size_t *psk_len, + int *vlan_id) { if (wpa_auth->cb->get_psk == NULL) return NULL; return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr, - prev_psk, psk_len); + prev_psk, psk_len, vlan_id); } @@ -131,21 +137,46 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, - u8 *key, size_t key_len) + u8 *key, size_t key_len, + enum key_flag key_flag) { if (wpa_auth->cb->set_key == NULL) return -1; return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx, - key, key_len); + key, key_len, key_flag); } static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, const u8 *addr, int idx, u8 *seq) { + int res; + if (wpa_auth->cb->get_seqnum == NULL) return -1; - return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq); + res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq); +#ifdef CONFIG_TESTING_OPTIONS + if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) { + wpa_printf(MSG_DEBUG, + "TESTING: Override GTK RSC %016llx --> %016llx", + (long long unsigned) WPA_GET_LE64(seq), + (long long unsigned) + WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override)); + os_memcpy(seq, wpa_auth->conf.gtk_rsc_override, + WPA_KEY_RSC_LEN); + } + if (!addr && idx >= 4 && idx <= 5 && + wpa_auth->conf.igtk_rsc_override_set) { + wpa_printf(MSG_DEBUG, + "TESTING: Override IGTK RSC %016llx --> %016llx", + (long long unsigned) WPA_GET_LE64(seq), + (long long unsigned) + WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override)); + os_memcpy(seq, wpa_auth->conf.igtk_rsc_override, + WPA_KEY_RSC_LEN); + } +#endif /* CONFIG_TESTING_OPTIONS */ + return res; } @@ -236,20 +267,23 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, } -static int wpa_use_aes_cmac(struct wpa_state_machine *sm) +#ifdef CONFIG_OCV +static int wpa_channel_info(struct wpa_authenticator *wpa_auth, + struct wpa_channel_info *ci) { - int ret = 0; -#ifdef CONFIG_IEEE80211R_AP - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) - ret = 1; -#endif /* CONFIG_IEEE80211R_AP */ -#ifdef CONFIG_IEEE80211W - if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt)) - ret = 1; -#endif /* CONFIG_IEEE80211W */ - if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) - ret = 1; - return ret; + if (!wpa_auth->cb->channel_info) + return -1; + return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci); +} +#endif /* CONFIG_OCV */ + + +static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth, + const u8 *addr, int vlan_id) +{ + if (!wpa_auth->cb->update_vlan) + return -1; + return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id); } @@ -312,6 +346,19 @@ static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx) } +void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm) +{ + if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) { + wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for " + MACSTR " (%d seconds)", MAC2STR(sm->addr), + sm->wpa_auth->conf.wpa_ptk_rekey); + eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); + eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0, + wpa_rekey_ptk, sm->wpa_auth, sm); + } +} + + static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx) { if (sm->pmksa == ctx) @@ -347,6 +394,10 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth, wpa_get_ntp_timestamp(buf + ETH_ALEN); ptr = (unsigned long) group; os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr)); +#ifdef TEST_FUZZ + os_memset(buf + ETH_ALEN, 0xab, 8); + os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr)); +#endif /* TEST_FUZZ */ if (random_get_bytes(rkey, sizeof(rkey)) < 0) return -1; @@ -683,8 +734,12 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) #endif /* CONFIG_IEEE80211R_AP */ os_free(sm->last_rx_eapol_key); os_free(sm->wpa_ie); + os_free(sm->rsnxe); wpa_group_put(sm->wpa_auth, sm->group); - os_free(sm); +#ifdef CONFIG_DPP2 + wpabuf_clear_free(sm->dpp_z); +#endif /* CONFIG_DPP2 */ + bin_clear_free(sm, sizeof(*sm)); } @@ -697,9 +752,10 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "strict rekeying - force GTK rekey since STA " "is leaving"); - eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL); - eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth, - NULL); + if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk, + sm->wpa_auth, NULL) == -1) + eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth, + NULL); } eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); @@ -725,8 +781,18 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm) if (sm == NULL) return; - sm->PTKRequest = TRUE; - sm->PTK_valid = 0; + if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { + wpa_printf(MSG_INFO, + "WPA: PTK0 rekey not allowed, disconnect " MACSTR, + MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + /* Try to encourage the STA to reconnect */ + sm->disconnect_reason = + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; + } else { + sm->PTKRequest = TRUE; + sm->PTK_valid = 0; + } } @@ -849,30 +915,44 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, int ok = 0; const u8 *pmk = NULL; size_t pmk_len; + int vlan_id = 0; os_memset(&PTK, 0, sizeof(PTK)); for (;;) { if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, - sm->p2p_dev_addr, pmk, &pmk_len); + sm->p2p_dev_addr, pmk, &pmk_len, + &vlan_id); if (pmk == NULL) break; +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) { + os_memcpy(sm->xxkey, pmk, pmk_len); + sm->xxkey_len = pmk_len; + } +#endif /* CONFIG_IEEE80211R_AP */ } else { pmk = sm->PMK; pmk_len = sm->pmk_len; } - if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0) + if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) < + 0) break; if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK, data, data_len) == 0) { + if (sm->PMK != pmk) { + os_memcpy(sm->PMK, pmk, pmk_len); + sm->pmk_len = pmk_len; + } ok = 1; break; } - if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) + if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) || + wpa_key_mgmt_sae(sm->wpa_key_mgmt)) break; } @@ -885,8 +965,14 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, wpa_printf(MSG_DEBUG, "WPA: Earlier SNonce resulted in matching MIC"); sm->alt_snonce_valid = 0; + + if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && + wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0) + return -1; + os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN); os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); + forced_memzero(&PTK, sizeof(PTK)); sm->PTK_valid = TRUE; return 0; @@ -900,8 +986,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; u16 key_info, key_data_length; - enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST, - SMK_M1, SMK_M3, SMK_ERROR } msg; + enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST } msg; char *msgtxt; struct wpa_eapol_ie_parse kde; const u8 *key_data; @@ -975,19 +1060,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys * are set */ - if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) == - (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) { - if (key_info & WPA_KEY_INFO_ERROR) { - msg = SMK_ERROR; - msgtxt = "SMK Error"; - } else { - msg = SMK_M1; - msgtxt = "SMK M1"; - } - } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { - msg = SMK_M3; - msgtxt = "SMK M3"; - } else if (key_info & WPA_KEY_INFO_REQUEST) { + if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { + wpa_printf(MSG_DEBUG, "WPA: Ignore SMK message"); + return; + } + + if (key_info & WPA_KEY_INFO_REQUEST) { msg = REQUEST; msgtxt = "Request"; } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) { @@ -1003,16 +1081,13 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, msgtxt = "2/4 Pairwise"; } - /* TODO: key_info type validation for PeerKey */ if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 || msg == GROUP_2) { u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK; if (sm->pairwise == WPA_CIPHER_CCMP || sm->pairwise == WPA_CIPHER_GCMP) { - if (wpa_use_aes_cmac(sm) && - sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN && - !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) && - !wpa_key_mgmt_fils(sm->wpa_key_mgmt) && + if (wpa_use_cmac(sm->wpa_key_mgmt) && + !wpa_use_akm_defined(sm->wpa_key_mgmt) && ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, @@ -1022,11 +1097,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, return; } - if (!wpa_use_aes_cmac(sm) && - !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) && - !wpa_key_mgmt_fils(sm->wpa_key_mgmt) && - sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && - sm->wpa_key_mgmt != WPA_KEY_MGMT_DPP && + if (!wpa_use_cmac(sm->wpa_key_mgmt) && + !wpa_use_akm_defined(sm->wpa_key_mgmt) && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, @@ -1036,10 +1108,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, } } - if ((wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) || - wpa_key_mgmt_fils(sm->wpa_key_mgmt) || - sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) && + if (wpa_use_akm_defined(sm->wpa_key_mgmt) && ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, "did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases"); @@ -1188,28 +1257,6 @@ continue_processing: return; } break; -#ifdef CONFIG_PEERKEY - case SMK_M1: - case SMK_M3: - case SMK_ERROR: - if (!wpa_auth->conf.peerkey) { - wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but " - "PeerKey use disabled - ignoring message"); - return; - } - if (!sm->PTK_valid) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg SMK in " - "invalid state - dropped"); - return; - } - break; -#else /* CONFIG_PEERKEY */ - case SMK_M1: - case SMK_M3: - case SMK_ERROR: - return; /* STSL disabled - ignore SMK messages */ -#endif /* CONFIG_PEERKEY */ case REQUEST: break; } @@ -1248,6 +1295,11 @@ continue_processing: wpa_try_alt_snonce(sm, data, data_len))) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key with invalid MIC"); +#ifdef TEST_FUZZ + wpa_printf(MSG_INFO, + "TEST: Ignore Key MIC failure for fuzz testing"); + goto continue_fuzz; +#endif /* TEST_FUZZ */ return; } #ifdef CONFIG_FILS @@ -1256,9 +1308,17 @@ continue_processing: &key_data_length) < 0) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key with invalid MIC"); +#ifdef TEST_FUZZ + wpa_printf(MSG_INFO, + "TEST: Ignore Key MIC failure for fuzz testing"); + goto continue_fuzz; +#endif /* TEST_FUZZ */ return; } #endif /* CONFIG_FILS */ +#ifdef TEST_FUZZ + continue_fuzz: +#endif /* TEST_FUZZ */ sm->MICVerified = TRUE; eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); sm->pending_1_of_4_timeout = 0; @@ -1281,12 +1341,7 @@ continue_processing: * even though MAC address KDE is not normally encrypted, * supplicant is allowed to encrypt it. */ - if (msg == SMK_ERROR) { -#ifdef CONFIG_PEERKEY - wpa_smk_error(wpa_auth, sm, key_data, key_data_length); -#endif /* CONFIG_PEERKEY */ - return; - } else if (key_info & WPA_KEY_INFO_ERROR) { + if (key_info & WPA_KEY_INFO_ERROR) { if (wpa_receive_error_report( wpa_auth, sm, !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0) @@ -1296,11 +1351,6 @@ continue_processing: "received EAPOL-Key Request for new " "4-Way Handshake"); wpa_request_new_ptk(sm); -#ifdef CONFIG_PEERKEY - } else if (msg == SMK_M1) { - wpa_smk_m1(wpa_auth, sm, key, key_data, - key_data_length); -#endif /* CONFIG_PEERKEY */ } else if (key_data_length > 0 && wpa_parse_kde_ies(key_data, key_data_length, &kde) == 0 && @@ -1339,13 +1389,6 @@ continue_processing: wpa_replay_counter_mark_invalid(sm->key_replay, NULL); } -#ifdef CONFIG_PEERKEY - if (msg == SMK_M3) { - wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length); - return; - } -#endif /* CONFIG_PEERKEY */ - os_free(sm->last_rx_eapol_key); sm->last_rx_eapol_key = os_memdup(data, data_len); if (sm->last_rx_eapol_key == NULL) @@ -1364,7 +1407,7 @@ continue_processing: static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr, const u8 *gnonce, u8 *gtk, size_t gtk_len) { - u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16]; + u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + WPA_GTK_MAX_LEN]; u8 *pos; int ret = 0; @@ -1375,21 +1418,35 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr, * is done only at the Authenticator and as such, does not need to be * exactly same. */ + os_memset(data, 0, sizeof(data)); os_memcpy(data, addr, ETH_ALEN); os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN); pos = data + ETH_ALEN + WPA_NONCE_LEN; wpa_get_ntp_timestamp(pos); +#ifdef TEST_FUZZ + os_memset(pos, 0xef, 8); +#endif /* TEST_FUZZ */ pos += 8; - if (random_get_bytes(pos, 16) < 0) + if (random_get_bytes(pos, gtk_len) < 0) ret = -1; -#ifdef CONFIG_IEEE80211W - sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len); -#else /* CONFIG_IEEE80211W */ - if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len) - < 0) +#ifdef CONFIG_SHA384 + if (sha384_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), + gtk, gtk_len) < 0) ret = -1; -#endif /* CONFIG_IEEE80211W */ +#else /* CONFIG_SHA384 */ +#ifdef CONFIG_SHA256 + if (sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), + gtk, gtk_len) < 0) + ret = -1; +#else /* CONFIG_SHA256 */ + if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), + gtk, gtk_len) < 0) + ret = -1; +#endif /* CONFIG_SHA256 */ +#endif /* CONFIG_SHA384 */ + + forced_memzero(data, sizeof(data)); return ret; } @@ -1430,13 +1487,9 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (force_version) version = force_version; - else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE || - sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP || - wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) || - wpa_key_mgmt_fils(sm->wpa_key_mgmt)) + else if (wpa_use_akm_defined(sm->wpa_key_mgmt)) version = WPA_KEY_INFO_TYPE_AKM_DEFINED; - else if (wpa_use_aes_cmac(sm)) + else if (wpa_use_cmac(sm->wpa_key_mgmt)) version = WPA_KEY_INFO_TYPE_AES_128_CMAC; else if (sm->pairwise != WPA_CIPHER_TKIP) version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; @@ -1458,10 +1511,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, key_data_len = kde_len; if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE || - sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN || - wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) || + wpa_use_aes_key_wrap(sm->wpa_key_mgmt) || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) { pad_len = key_data_len % 8; if (pad_len) @@ -1493,13 +1543,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, WPA_PUT_BE16(key->key_info, key_info); alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group; - if ((key_info & WPA_KEY_INFO_SMK_MESSAGE) || - (sm->wpa == WPA_VERSION_WPA2 && !pairwise)) + if (sm->wpa == WPA_VERSION_WPA2 && !pairwise) WPA_PUT_BE16(key->key_length, 0); else WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg)); - /* FIX: STSL: what to use as key_replay_counter? */ for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) { sm->key_replay[i].valid = sm->key_replay[i - 1].valid; os_memcpy(sm->key_replay[i].counter, @@ -1523,7 +1571,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, os_memcpy(key_data, kde, kde_len); WPA_PUT_BE16(key_mic + mic_len, kde_len); #ifdef CONFIG_FILS - } else if (!mic_len) { + } else if (!mic_len && kde) { const u8 *aad[1]; size_t aad_len[1]; @@ -1562,10 +1610,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data", buf, key_data_len); if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE || - sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN || - wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) || + wpa_use_aes_key_wrap(sm->wpa_key_mgmt) || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)", @@ -1609,9 +1654,12 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, return; } - wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len, - sm->wpa_key_mgmt, version, - (u8 *) hdr, len, key_mic); + if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len, + sm->wpa_key_mgmt, version, + (u8 *) hdr, len, key_mic) < 0) { + os_free(hdr); + return; + } #ifdef CONFIG_TESTING_OPTIONS if (!pairwise && wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 && @@ -1654,8 +1702,14 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, eapol_key_timeout_first_group; else timeout_ms = eapol_key_timeout_subseq; + if (wpa_auth->conf.wpa_disable_eapol_key_retries && + (!pairwise || (key_info & WPA_KEY_INFO_MIC))) + timeout_ms = eapol_key_timeout_no_retrans; if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC)) sm->pending_1_of_4_timeout = 1; +#ifdef TEST_FUZZ + timeout_ms = 1; +#endif /* TEST_FUZZ */ wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry " "counter %u)", timeout_ms, ctr); eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000, @@ -1697,7 +1751,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm) sm->PTK_valid = FALSE; os_memset(&sm->PTK, 0, sizeof(sm->PTK)); if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, - 0)) + 0, KEY_FLAG_PAIRWISE)) wpa_printf(MSG_DEBUG, "RSN: PTK removal from the driver failed"); sm->pairwise_set = FALSE; @@ -1730,6 +1784,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) case WPA_DEAUTH: case WPA_DISASSOC: sm->DeauthenticationRequest = TRUE; +#ifdef CONFIG_IEEE80211R_AP + os_memset(sm->PMK, 0, sizeof(sm->PMK)); + sm->pmk_len = 0; + os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); + sm->xxkey_len = 0; + os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1)); + sm->pmk_r1_len = 0; +#endif /* CONFIG_IEEE80211R_AP */ break; case WPA_REAUTH: case WPA_REAUTH_EAPOL: @@ -1750,6 +1812,15 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) sm->Init = FALSE; sm->AuthenticationRequest = TRUE; break; + } else if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { + wpa_printf(MSG_INFO, + "WPA: PTK0 rekey not allowed, disconnect " + MACSTR, MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + /* Try to encourage the STA reconnect */ + sm->disconnect_reason = + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; + break; } if (sm->GUpdateStationKeys) { /* @@ -1770,6 +1841,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) /* Using FT protocol, not WPA auth state machine */ sm->ft_completed = 1; + wpa_auth_set_ptk_rekey_timer(sm); return 0; #else /* CONFIG_IEEE80211R_AP */ break; @@ -1793,10 +1865,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) sm->ft_completed = 0; #endif /* CONFIG_IEEE80211R_AP */ -#ifdef CONFIG_IEEE80211W if (sm->mgmt_frame_prot && event == WPA_AUTH) remove_ptk = 0; -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_FILS if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) && (event == WPA_AUTH || event == WPA_ASSOC)) @@ -2009,8 +2079,13 @@ SM_STATE(WPA_PTK, INITPMK) sm->pmk_len = pmk_len; #ifdef CONFIG_IEEE80211R_AP if (len >= 2 * PMK_LEN) { - os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN); - sm->xxkey_len = PMK_LEN; + if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) { + os_memcpy(sm->xxkey, msk, SHA384_MAC_LEN); + sm->xxkey_len = SHA384_MAC_LEN; + } else { + os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN); + sm->xxkey_len = PMK_LEN; + } } #endif /* CONFIG_IEEE80211R_AP */ } else { @@ -2019,7 +2094,7 @@ SM_STATE(WPA_PTK, INITPMK) sm->Disconnect = TRUE; return; } - os_memset(msk, 0, sizeof(msk)); + forced_memzero(msk, sizeof(msk)); sm->req_replay_counter_used = 0; /* IEEE 802.11i does not set keyRun to FALSE, but not doing this @@ -2041,7 +2116,7 @@ SM_STATE(WPA_PTK, INITPSK) SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk); psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL, - &psk_len); + &psk_len, NULL); if (psk) { os_memcpy(sm->PMK, psk, psk_len); sm->pmk_len = psk_len; @@ -2055,6 +2130,10 @@ SM_STATE(WPA_PTK, INITPSK) wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache"); os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len); sm->pmk_len = sm->pmksa->pmk_len; +#ifdef CONFIG_IEEE80211R_AP + os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len); + sm->xxkey_len = sm->pmksa->pmk_len; +#endif /* CONFIG_IEEE80211R_AP */ } #endif /* CONFIG_SAE */ sm->req_replay_counter_used = 0; @@ -2081,8 +2160,18 @@ SM_STATE(WPA_PTK, PTKSTART) wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "sending 1/4 msg of 4-Way Handshake"); /* - * TODO: Could add PMKID even with WPA2-PSK, but only if there is only - * one possible PSK for this STA. + * For infrastructure BSS cases, it is better for the AP not to include + * the PMKID KDE in EAPOL-Key msg 1/4 since it could be used to initiate + * offline search for the passphrase/PSK without having to be able to + * capture a 4-way handshake from a STA that has access to the network. + * + * For IBSS cases, addition of PMKID KDE could be considered even with + * WPA2-PSK cases that use multiple PSKs, but only if there is a single + * possible PSK for this STA. However, this should not be done unless + * there is support for using that information on the supplicant side. + * The concern about exposing PMKID unnecessarily in infrastructure BSS + * cases would also apply here, but at least in the IBSS case, this + * would cover a potential real use case. */ if (sm->wpa == WPA_VERSION_WPA2 && (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) || @@ -2095,11 +2184,53 @@ SM_STATE(WPA_PTK, PTKSTART) pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN; RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID); if (sm->pmksa) { + wpa_hexdump(MSG_DEBUG, + "RSN: Message 1/4 PMKID from PMKSA entry", + sm->pmksa->pmkid, PMKID_LEN); os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN], sm->pmksa->pmkid, PMKID_LEN); } else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) { /* No KCK available to derive PMKID */ + wpa_printf(MSG_DEBUG, + "RSN: No KCK available to derive PMKID for message 1/4"); + pmkid = NULL; +#ifdef CONFIG_FILS + } else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) { + if (sm->pmkid_set) { + wpa_hexdump(MSG_DEBUG, + "RSN: Message 1/4 PMKID from FILS/ERP", + sm->pmkid, PMKID_LEN); + os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN], + sm->pmkid, PMKID_LEN); + } else { + /* No PMKID available */ + wpa_printf(MSG_DEBUG, + "RSN: No FILS/ERP PMKID available for message 1/4"); + pmkid = NULL; + } +#endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211R_AP + } else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && + sm->ft_completed) { + wpa_printf(MSG_DEBUG, + "FT: No PMKID in message 1/4 when using FT protocol"); pmkid = NULL; +#endif /* CONFIG_IEEE80211R_AP */ +#ifdef CONFIG_SAE + } else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { + if (sm->pmkid_set) { + wpa_hexdump(MSG_DEBUG, + "RSN: Message 1/4 PMKID from SAE", + sm->pmkid, PMKID_LEN); + os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN], + sm->pmkid, PMKID_LEN); + } else { + /* No PMKID available */ + wpa_printf(MSG_DEBUG, + "RSN: No SAE PMKID available for message 1/4"); + pmkid = NULL; + } +#endif /* CONFIG_SAE */ } else { /* * Calculate PMKID since no PMKSA cache entry was @@ -2108,8 +2239,13 @@ SM_STATE(WPA_PTK, PTKSTART) rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr, sm->addr, &pmkid[2 + RSN_SELECTOR_LEN], sm->wpa_key_mgmt); + wpa_hexdump(MSG_DEBUG, + "RSN: Message 1/4 PMKID derived from PMK", + &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN); } } + if (!pmkid) + pmkid_len = 0; wpa_send_eapol(sm->wpa_auth, sm, WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL, sm->ANonce, pmkid, pmkid_len, 0, 0); @@ -2118,16 +2254,42 @@ SM_STATE(WPA_PTK, PTKSTART) static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, unsigned int pmk_len, - struct wpa_ptk *ptk) + struct wpa_ptk *ptk, int force_sha256) { + const u8 *z = NULL; + size_t z_len = 0; + int akmp; + #ifdef CONFIG_IEEE80211R_AP - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) - return wpa_auth_derive_ptk_ft(sm, pmk, ptk); + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + if (sm->ft_completed) { + u8 ptk_name[WPA_PMK_NAME_LEN]; + + return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, + sm->SNonce, sm->ANonce, + sm->addr, sm->wpa_auth->addr, + sm->pmk_r1_name, + ptk, ptk_name, + sm->wpa_key_mgmt, + sm->pairwise); + } + return wpa_auth_derive_ptk_ft(sm, ptk); + } #endif /* CONFIG_IEEE80211R_AP */ +#ifdef CONFIG_DPP2 + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) { + z = wpabuf_head(sm->dpp_z); + z_len = wpabuf_len(sm->dpp_z); + } +#endif /* CONFIG_DPP2 */ + + akmp = sm->wpa_key_mgmt; + if (force_sha256) + akmp |= WPA_KEY_MGMT_PSK_SHA256; return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion", sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce, - ptk, sm->wpa_key_mgmt, sm->pairwise); + ptk, akmp, sm->pairwise, z, z_len); } @@ -2158,22 +2320,35 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, if (fils_ft_len) { struct wpa_authenticator *wpa_auth = sm->wpa_auth; struct wpa_auth_config *conf = &wpa_auth->conf; - u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; + int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); + size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; if (wpa_derive_pmk_r0(fils_ft, fils_ft_len, conf->ssid, conf->ssid_len, conf->mobility_domain, conf->r0_key_holder, conf->r0_key_holder_len, - sm->addr, pmk_r0, pmk_r0_name) < 0) + sm->addr, pmk_r0, pmk_r0_name, + use_sha384) < 0) return -1; - wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0", pmk_r0, PMK_LEN); + wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0", + pmk_r0, pmk_r0_len); wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN); - wpa_ft_store_pmk_r0(wpa_auth, sm->addr, pmk_r0, pmk_r0_name, - sm->pairwise); - os_memset(fils_ft, 0, sizeof(fils_ft)); + wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name); + forced_memzero(fils_ft, sizeof(fils_ft)); + + res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder, + sm->addr, sm->pmk_r1_name, + use_sha384); + forced_memzero(pmk_r0, PMK_LEN_MAX); + if (res < 0) + return -1; + wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name, + WPA_PMK_NAME_LEN); + sm->pmk_r1_name_valid = 1; } #endif /* CONFIG_IEEE80211R_AP */ @@ -2186,7 +2361,7 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, sm->wpa_key_mgmt, sm->fils_key_auth_sta, sm->fils_key_auth_ap, &sm->fils_key_auth_len); - os_memset(ick, 0, sizeof(ick)); + forced_memzero(ick, sizeof(ick)); /* Store nonces for (Re)Association Request/Response frame processing */ os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN); @@ -2488,7 +2663,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf, if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) { wpa_printf(MSG_DEBUG, "FILS: Not enough room for FILS elements"); - wpabuf_free(plain); + wpabuf_clear_free(plain); return -1; } @@ -2498,7 +2673,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf, if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len, wpabuf_head(plain), wpabuf_len(plain), 5, aad, aad_len, pos) < 0) { - wpabuf_free(plain); + wpabuf_clear_free(plain); return -1; } @@ -2506,7 +2681,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf, "FILS: Encrypted Association Response elements", pos, AES_BLOCK_SIZE + wpabuf_len(plain)); current_len += wpabuf_len(plain) + AES_BLOCK_SIZE; - wpabuf_free(plain); + wpabuf_clear_free(plain); sm->fils_completed = 1; @@ -2524,7 +2699,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, size_t gtk_len; struct wpa_group *gsm; - plain = wpabuf_alloc(1000); + plain = wpabuf_alloc(1000 + ieee80211w_kde_len(sm)); if (!plain) return NULL; @@ -2553,13 +2728,14 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, /* GTK KDE */ gtk = gsm->GTK[gsm->GN - 1]; gtk_len = gsm->GTK_len; - if (sm->wpa_auth->conf.disable_gtk) { + if (sm->wpa_auth->conf.disable_gtk || + sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random GTK to each STA to prevent use * of GTK in the BSS. */ if (random_get_bytes(dummy_gtk, gtk_len) < 0) { - wpabuf_free(plain); + wpabuf_clear_free(plain); return NULL; } gtk = dummy_gtk; @@ -2571,12 +2747,33 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, gtk, gtk_len); wpabuf_put(plain, tmp2 - tmp); - /* IGTK KDE */ + /* IGTK KDE and BIGTK KDE */ tmp = wpabuf_put(plain, 0); tmp2 = ieee80211w_kde_add(sm, tmp); wpabuf_put(plain, tmp2 - tmp); *len = (u8 *) wpabuf_put(plain, 0) - len - 1; + +#ifdef CONFIG_OCV + if (wpa_auth_uses_ocv(sm)) { + struct wpa_channel_info ci; + u8 *pos; + + if (wpa_channel_info(sm->wpa_auth, &ci) != 0) { + wpa_printf(MSG_WARNING, + "FILS: Failed to get channel info for OCI element"); + wpabuf_clear_free(plain); + return NULL; + } + + pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN); + if (ocv_insert_extended_oci(&ci, pos) < 0) { + wpabuf_clear_free(plain); + return NULL; + } + } +#endif /* CONFIG_OCV */ + return plain; } @@ -2600,7 +2797,7 @@ int fils_set_tk(struct wpa_state_machine *sm) wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver"); if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk, klen)) { + sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) { wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver"); return -1; } @@ -2634,7 +2831,7 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf, wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__, (unsigned int) wpabuf_len(plain)); - wpabuf_free(plain); + wpabuf_clear_free(plain); sm->fils_completed = 1; return pos; } @@ -2642,6 +2839,21 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf, #endif /* CONFIG_FILS */ +#ifdef CONFIG_OCV +int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth, + int ap_seg1_idx, int *bandwidth, int *seg1_idx) +{ + struct wpa_authenticator *wpa_auth = sm->wpa_auth; + + if (!wpa_auth->cb->get_sta_tx_params) + return -1; + return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr, + ap_max_chanwidth, ap_seg1_idx, + bandwidth, seg1_idx); +} +#endif /* CONFIG_OCV */ + + SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) { struct wpa_authenticator *wpa_auth = sm->wpa_auth; @@ -2656,6 +2868,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; struct wpa_eapol_ie_parse kde; + int vlan_id = 0; + int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround; SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); sm->EAPOLKeyReceived = FALSE; @@ -2671,22 +2885,40 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, - sm->p2p_dev_addr, pmk, &pmk_len); + sm->p2p_dev_addr, pmk, &pmk_len, + &vlan_id); if (pmk == NULL) break; psk_found = 1; +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) { + os_memcpy(sm->xxkey, pmk, pmk_len); + sm->xxkey_len = pmk_len; + } +#endif /* CONFIG_IEEE80211R_AP */ } else { pmk = sm->PMK; pmk_len = sm->pmk_len; } - if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0) + if ((!pmk || !pmk_len) && sm->pmksa) { + wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache"); + pmk = sm->pmksa->pmk; + pmk_len = sm->pmksa->pmk_len; + } + + if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK, + owe_ptk_workaround == 2) < 0) break; if (mic_len && wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK, sm->last_rx_eapol_key, sm->last_rx_eapol_key_len) == 0) { + if (sm->PMK != pmk) { + os_memcpy(sm->PMK, pmk, pmk_len); + sm->pmk_len = pmk_len; + } ok = 1; break; } @@ -2700,7 +2932,18 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) } #endif /* CONFIG_FILS */ - if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) +#ifdef CONFIG_OWE + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 && + owe_ptk_workaround == 1) { + wpa_printf(MSG_DEBUG, + "OWE: Try PTK derivation workaround with SHA256"); + owe_ptk_workaround = 2; + continue; + } +#endif /* CONFIG_OWE */ + + if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) || + wpa_key_mgmt_sae(sm->wpa_key_mgmt)) break; } @@ -2757,6 +3000,48 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) WLAN_REASON_PREV_AUTH_NOT_VALID); return; } + if ((!sm->rsnxe && kde.rsnxe) || + (sm->rsnxe && !kde.rsnxe) || + (sm->rsnxe && kde.rsnxe && + (sm->rsnxe_len != kde.rsnxe_len || + os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4"); + wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq", + sm->rsnxe, sm->rsnxe_len); + wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4", + kde.rsnxe, kde.rsnxe_len); + /* MLME-DEAUTHENTICATE.request */ + wpa_sta_disconnect(wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } +#ifdef CONFIG_OCV + if (wpa_auth_uses_ocv(sm)) { + struct wpa_channel_info ci; + int tx_chanwidth; + int tx_seg1_idx; + + if (wpa_channel_info(wpa_auth, &ci) != 0) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + "Failed to get channel info to validate received OCI in EAPOL-Key 2/4"); + return; + } + + if (get_sta_tx_parameters(sm, + channel_width_to_int(ci.chanwidth), + ci.seg1_idx, &tx_chanwidth, + &tx_seg1_idx) < 0) + return; + + if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci, + tx_chanwidth, tx_seg1_idx) != 0) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + ocv_errorstr); + return; + } + } +#endif /* CONFIG_OCV */ #ifdef CONFIG_IEEE80211R_AP if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { wpa_sta_disconnect(wpa_auth, sm->addr, @@ -2805,6 +3090,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) } #endif /* CONFIG_IEEE80211R_AP */ + if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && + wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) { + wpa_sta_disconnect(wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } + sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); @@ -2819,6 +3111,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) sm->MICVerified = TRUE; os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); + forced_memzero(&PTK, sizeof(PTK)); sm->PTK_valid = TRUE; } @@ -2830,23 +3123,27 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2) } -#ifdef CONFIG_IEEE80211W - static int ieee80211w_kde_len(struct wpa_state_machine *sm) { + size_t len = 0; + if (sm->mgmt_frame_prot) { - size_t len; - len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); - return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len; + len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN; + len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + } + if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) { + len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN; + len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); } - return 0; + return len; } static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) { struct wpa_igtk_kde igtk; + struct wpa_bigtk_kde bigtk; struct wpa_group *gsm = sm->group; u8 rsc[WPA_KEY_RSC_LEN]; size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); @@ -2862,7 +3159,8 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) else os_memcpy(igtk.pn, rsc, sizeof(igtk.pn)); os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len); - if (sm->wpa_auth->conf.disable_gtk) { + if (sm->wpa_auth->conf.disable_gtk || + sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random IGTK to each STA to prevent use of * IGTK in the BSS. @@ -2874,37 +3172,105 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len, NULL, 0); + if (!sm->wpa_auth->conf.beacon_prot) + return pos; + + bigtk.keyid[0] = gsm->GN_bigtk; + bigtk.keyid[1] = 0; + if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0) + os_memset(bigtk.pn, 0, sizeof(bigtk.pn)); + else + os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn)); + os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len); + pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK, + (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len, + NULL, 0); + return pos; } -#else /* CONFIG_IEEE80211W */ -static int ieee80211w_kde_len(struct wpa_state_machine *sm) +static int ocv_oci_len(struct wpa_state_machine *sm) { +#ifdef CONFIG_OCV + if (wpa_auth_uses_ocv(sm)) + return OCV_OCI_KDE_LEN; +#endif /* CONFIG_OCV */ return 0; } - -static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) +static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos) { - return pos; +#ifdef CONFIG_OCV + struct wpa_channel_info ci; + + if (!wpa_auth_uses_ocv(sm)) + return 0; + + if (wpa_channel_info(sm->wpa_auth, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Failed to get channel info for OCI element"); + return -1; + } + + return ocv_insert_oci_kde(&ci, argpos); +#else /* CONFIG_OCV */ + return 0; +#endif /* CONFIG_OCV */ } -#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_TESTING_OPTIONS +static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid, + const u8 *ie, size_t ie_len) +{ + const u8 *elem; + u8 *buf; + + wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name); + wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override", + old_buf, *len); + buf = os_malloc(*len + ie_len); + if (!buf) + return NULL; + os_memcpy(buf, old_buf, *len); + elem = get_ie(buf, *len, eid); + if (elem) { + u8 elem_len = 2 + elem[1]; + + os_memmove((void *) elem, elem + elem_len, + *len - (elem - buf) - elem_len); + *len -= elem_len; + } + os_memcpy(buf + *len, ie, ie_len); + *len += ie_len; + wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override", + buf, *len); + + return buf; +} +#endif /* CONFIG_TESTING_OPTIONS */ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) { - u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32]; - size_t gtk_len, kde_len; + u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32]; + size_t gtk_len, kde_len, wpa_ie_len; struct wpa_group *gsm = sm->group; u8 *wpa_ie; - int wpa_ie_len, secure, keyidx, encr = 0; + int secure, gtkidx, encr = 0; + u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL; SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = FALSE; sm->TimeoutCtr++; + if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries && + sm->TimeoutCtr > 1) { + /* Do not allow retransmission of EAPOL-Key msg 3/4 */ + return; + } if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ @@ -2912,7 +3278,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], - GTK[GN], IGTK, [FTIE], [TIE * 2]) + GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2]) */ os_memset(rsc, 0, WPA_KEY_RSC_LEN); wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); @@ -2921,13 +3287,33 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) wpa_ie_len = sm->wpa_auth->wpa_ie_len; if (sm->wpa == WPA_VERSION_WPA && (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) && - wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) { + wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) { /* WPA-only STA, remove RSN IE and possible MDIE */ wpa_ie = wpa_ie + wpa_ie[1] + 2; if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN) wpa_ie = wpa_ie + wpa_ie[1] + 2; wpa_ie_len = wpa_ie[1] + 2; } +#ifdef CONFIG_TESTING_OPTIONS + if (sm->wpa_auth->conf.rsne_override_eapol_set) { + wpa_ie_buf2 = replace_ie( + "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN, + sm->wpa_auth->conf.rsne_override_eapol, + sm->wpa_auth->conf.rsne_override_eapol_len); + if (!wpa_ie_buf2) + goto done; + wpa_ie = wpa_ie_buf2; + } + if (sm->wpa_auth->conf.rsnxe_override_eapol_set) { + wpa_ie_buf = replace_ie( + "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX, + sm->wpa_auth->conf.rsnxe_override_eapol, + sm->wpa_auth->conf.rsnxe_override_eapol_len); + if (!wpa_ie_buf) + goto done; + wpa_ie = wpa_ie_buf; + } +#endif /* CONFIG_TESTING_OPTIONS */ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "sending 3/4 msg of 4-Way Handshake"); if (sm->wpa == WPA_VERSION_WPA2) { @@ -2935,16 +3321,17 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) secure = 1; gtk = gsm->GTK[gsm->GN - 1]; gtk_len = gsm->GTK_len; - if (sm->wpa_auth->conf.disable_gtk) { + if (sm->wpa_auth->conf.disable_gtk || + sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random GTK to each STA to prevent use * of GTK in the BSS. */ if (random_get_bytes(dummy_gtk, gtk_len) < 0) - return; + goto done; gtk = dummy_gtk; } - keyidx = gsm->GN; + gtkidx = gsm->GN; _rsc = rsc; encr = 1; } else { @@ -2952,7 +3339,6 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) secure = 0; gtk = NULL; gtk_len = 0; - keyidx = 0; _rsc = NULL; if (sm->rx_eapol_key_secure) { /* @@ -2970,7 +3356,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } } - kde_len = wpa_ie_len + ieee80211w_kde_len(sm); + kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); if (gtk) kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; #ifdef CONFIG_IEEE80211R_AP @@ -2985,7 +3371,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) #endif /* CONFIG_P2P */ kde = os_malloc(kde_len); if (kde == NULL) - return; + goto done; pos = kde; os_memcpy(pos, wpa_ie, wpa_ie_len); @@ -3000,8 +3386,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) if (res < 0) { wpa_printf(MSG_ERROR, "FT: Failed to insert " "PMKR1Name into RSN IE in EAPOL-Key data"); - os_free(kde); - return; + goto done; } pos -= wpa_ie_len; pos += elen; @@ -3009,12 +3394,14 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) #endif /* CONFIG_IEEE80211R_AP */ if (gtk) { u8 hdr[2]; - hdr[0] = keyidx & 0x03; + hdr[0] = gtkidx & 0x03; hdr[1] = 0; pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); } pos = ieee80211w_kde_add(sm, pos); + if (ocv_oci_add(sm, &pos) < 0) + goto done; #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { @@ -3028,7 +3415,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) 2 + sm->assoc_resp_ftie[1]); res = 2 + sm->assoc_resp_ftie[1]; } else { - res = wpa_write_ftie(conf, conf->r0_key_holder, + int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); + + res = wpa_write_ftie(conf, use_sha384, + conf->r0_key_holder, conf->r0_key_holder_len, NULL, NULL, pos, kde + kde_len - pos, @@ -3037,8 +3427,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) if (res < 0) { wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " "into EAPOL-Key Key Data"); - os_free(kde); - return; + goto done; } pos += res; @@ -3053,7 +3442,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) *pos++ = WLAN_EID_TIMEOUT_INTERVAL; *pos++ = 5; *pos++ = WLAN_TIMEOUT_KEY_LIFETIME; - WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60); + WPA_PUT_LE32(pos, conf->r0_key_lifetime); pos += 4; } #endif /* CONFIG_IEEE80211R_AP */ @@ -3074,8 +3463,11 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) WPA_KEY_INFO_MIC : 0) | WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_KEY_TYPE, - _rsc, sm->ANonce, kde, pos - kde, keyidx, encr); + _rsc, sm->ANonce, kde, pos - kde, 0, encr); +done: os_free(kde); + os_free(wpa_ie_buf); + os_free(wpa_ie_buf2); } @@ -3087,7 +3479,8 @@ SM_STATE(WPA_PTK, PTKINITDONE) enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise); int klen = wpa_cipher_key_len(sm->pairwise); if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk, klen)) { + sm->PTK.tk, klen, + KEY_FLAG_PAIRWISE_RX_TX)) { wpa_sta_disconnect(sm->wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); return; @@ -3095,12 +3488,7 @@ SM_STATE(WPA_PTK, PTKINITDONE) /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ sm->pairwise_set = TRUE; - if (sm->wpa_auth->conf.wpa_ptk_rekey) { - eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); - eloop_register_timeout(sm->wpa_auth->conf. - wpa_ptk_rekey, 0, wpa_rekey_ptk, - sm->wpa_auth, sm); - } + wpa_auth_set_ptk_rekey_timer(sm); if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) || sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP || @@ -3200,7 +3588,7 @@ SM_STEP(WPA_PTK) break; case WPA_PTK_INITPSK: if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, - NULL, NULL)) { + NULL, NULL, NULL)) { SM_ENTER(WPA_PTK, PTKSTART); #ifdef CONFIG_SAE } else if (wpa_auth_uses_sae(sm) && sm->pmksa) { @@ -3247,7 +3635,9 @@ SM_STEP(WPA_PTK) sm->EAPOLKeyPairwise && sm->MICVerified) SM_ENTER(WPA_PTK, PTKINITDONE); else if (sm->TimeoutCtr > - sm->wpa_auth->conf.wpa_pairwise_update_count) { + sm->wpa_auth->conf.wpa_pairwise_update_count || + (sm->wpa_auth->conf.wpa_disable_eapol_key_retries && + sm->TimeoutCtr > 1)) { wpa_auth->dot11RSNA4WayHandshakeFailures++; wpa_auth_vlogger( sm->wpa_auth, sm->addr, LOGGER_DEBUG, @@ -3287,6 +3677,11 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group); sm->GTimeoutCtr++; + if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries && + sm->GTimeoutCtr > 1) { + /* Do not allow retransmission of EAPOL-Key group msg 1/2 */ + return; + } if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ @@ -3304,7 +3699,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) "sending 1/2 msg of Group Key Handshake"); gtk = gsm->GTK[gsm->GN - 1]; - if (sm->wpa_auth->conf.disable_gtk) { + if (sm->wpa_auth->conf.disable_gtk || + sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random GTK to each STA to prevent use * of GTK in the BSS. @@ -3315,7 +3711,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) } if (sm->wpa == WPA_VERSION_WPA2) { kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + - ieee80211w_kde_len(sm); + ieee80211w_kde_len(sm) + ocv_oci_len(sm); kde_buf = os_malloc(kde_len); if (kde_buf == NULL) return; @@ -3326,6 +3722,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gsm->GTK_len); pos = ieee80211w_kde_add(sm, pos); + if (ocv_oci_add(sm, &pos) < 0) { + os_free(kde_buf); + return; + } kde_len = pos - kde; } else { kde = gtk; @@ -3346,8 +3746,67 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) { +#ifdef CONFIG_OCV + struct wpa_authenticator *wpa_auth = sm->wpa_auth; + const u8 *key_data, *mic; + struct ieee802_1x_hdr *hdr; + struct wpa_eapol_key *key; + struct wpa_eapol_ie_parse kde; + size_t mic_len; + u16 key_data_length; +#endif /* CONFIG_OCV */ + SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group); sm->EAPOLKeyReceived = FALSE; + +#ifdef CONFIG_OCV + mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len); + + /* + * Note: last_rx_eapol_key length fields have already been validated in + * wpa_receive(). + */ + hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key; + key = (struct wpa_eapol_key *) (hdr + 1); + mic = (u8 *) (key + 1); + key_data = mic + mic_len + 2; + key_data_length = WPA_GET_BE16(mic + mic_len); + if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) - + sizeof(*key) - mic_len - 2) + return; + + if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) { + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + "received EAPOL-Key group msg 2/2 with invalid Key Data contents"); + return; + } + + if (wpa_auth_uses_ocv(sm)) { + struct wpa_channel_info ci; + int tx_chanwidth; + int tx_seg1_idx; + + if (wpa_channel_info(wpa_auth, &ci) != 0) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2"); + return; + } + + if (get_sta_tx_parameters(sm, + channel_width_to_int(ci.chanwidth), + ci.seg1_idx, &tx_chanwidth, + &tx_seg1_idx) < 0) + return; + + if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci, + tx_chanwidth, tx_seg1_idx) != 0) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + ocv_errorstr); + return; + } + } +#endif /* CONFIG_OCV */ + if (sm->GUpdateStationKeys) sm->group->GKeyDoneStations--; sm->GUpdateStationKeys = FALSE; @@ -3390,7 +3849,9 @@ SM_STEP(WPA_PTK_GROUP) !sm->EAPOLKeyPairwise && sm->MICVerified) SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED); else if (sm->GTimeoutCtr > - sm->wpa_auth->conf.wpa_group_update_count) + sm->wpa_auth->conf.wpa_group_update_count || + (sm->wpa_auth->conf.wpa_disable_eapol_key_retries && + sm->GTimeoutCtr > 1)) SM_ENTER(WPA_PTK_GROUP, KEYERROR); else if (sm->TimeoutEvt) SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING); @@ -3409,6 +3870,7 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { int ret = 0; + size_t len; os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); inc_byte_array(group->Counter, WPA_NONCE_LEN); @@ -3419,9 +3881,7 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, wpa_hexdump_key(MSG_DEBUG, "GTK", group->GTK[group->GN - 1], group->GTK_len); -#ifdef CONFIG_IEEE80211W if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { - size_t len; len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); inc_byte_array(group->Counter, WPA_NONCE_LEN); @@ -3432,7 +3892,19 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, wpa_hexdump_key(MSG_DEBUG, "IGTK", group->IGTK[group->GN_igtk - 4], len); } -#endif /* CONFIG_IEEE80211W */ + + if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION && + wpa_auth->conf.beacon_prot) { + len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); + os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); + inc_byte_array(group->Counter, WPA_NONCE_LEN); + if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion", + wpa_auth->addr, group->GNonce, + group->BIGTK[group->GN_bigtk - 6], len) < 0) + ret = -1; + wpa_hexdump_key(MSG_DEBUG, "BIGTK", + group->BIGTK[group->GN_bigtk - 6], len); + } return ret; } @@ -3450,10 +3922,10 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth, os_memset(group->GTK, 0, sizeof(group->GTK)); group->GN = 1; group->GM = 2; -#ifdef CONFIG_IEEE80211W group->GN_igtk = 4; group->GM_igtk = 5; -#endif /* CONFIG_IEEE80211W */ + group->GN_bigtk = 6; + group->GM_bigtk = 7; /* GTK[GN] = CalcGTK() */ wpa_gtk_update(wpa_auth, group); } @@ -3542,7 +4014,6 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos) } -#ifdef CONFIG_IEEE80211W int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) { struct wpa_group *gsm = sm->group; @@ -3571,7 +4042,37 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) return pos - start; } -#endif /* CONFIG_IEEE80211W */ + + +int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos) +{ + struct wpa_group *gsm = sm->group; + u8 *start = pos; + size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + + /* + * BIGTK subelement: + * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16] + */ + *pos++ = WNM_SLEEP_SUBELEM_BIGTK; + *pos++ = 2 + 6 + len; + WPA_PUT_LE16(pos, gsm->GN_bigtk); + pos += 2; + if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0) + return 0; + pos += 6; + + os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len); + pos += len; + + wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit", + gsm->GN_bigtk); + wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit", + gsm->IGTK[gsm->GN_bigtk - 6], len); + + return pos - start; +} + #endif /* CONFIG_WNM_AP */ @@ -3588,11 +4089,12 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, tmp = group->GM; group->GM = group->GN; group->GN = tmp; -#ifdef CONFIG_IEEE80211W tmp = group->GM_igtk; group->GM_igtk = group->GN_igtk; group->GN_igtk = tmp; -#endif /* CONFIG_IEEE80211W */ + tmp = group->GM_bigtk; + group->GM_bigtk = group->GN_bigtk; + group->GN_bigtk = tmp; /* "GKeyDoneStations = GNoStations" is done in more robust way by * counting the STAs that are marked with GUpdateStationKeys instead of * including all STAs that could be in not-yet-completed state. */ @@ -3618,10 +4120,10 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, if (wpa_auth_set_key(wpa_auth, group->vlan_id, wpa_cipher_to_alg(wpa_auth->conf.wpa_group), broadcast_ether_addr, group->GN, - group->GTK[group->GN - 1], group->GTK_len) < 0) + group->GTK[group->GN - 1], group->GTK_len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) ret = -1; -#ifdef CONFIG_IEEE80211W if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { enum wpa_alg alg; size_t len; @@ -3632,10 +4134,17 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, if (ret == 0 && wpa_auth_set_key(wpa_auth, group->vlan_id, alg, broadcast_ether_addr, group->GN_igtk, - group->IGTK[group->GN_igtk - 4], len) < 0) + group->IGTK[group->GN_igtk - 4], len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) + ret = -1; + + if (ret == 0 && wpa_auth->conf.beacon_prot && + wpa_auth_set_key(wpa_auth, group->vlan_id, alg, + broadcast_ether_addr, group->GN_bigtk, + group->BIGTK[group->GN_bigtk - 6], len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) ret = -1; } -#endif /* CONFIG_IEEE80211W */ return ret; } @@ -3773,11 +4282,12 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) tmp = group->GM; group->GM = group->GN; group->GN = tmp; -#ifdef CONFIG_IEEE80211W tmp = group->GM_igtk; group->GM_igtk = group->GN_igtk; group->GN_igtk = tmp; -#endif /* CONFIG_IEEE80211W */ + tmp = group->GM_bigtk; + group->GM_bigtk = group->GN_bigtk; + group->GN_bigtk = tmp; wpa_gtk_update(wpa_auth, group); wpa_group_config_group_keys(wpa_auth, group); } @@ -3923,8 +4433,12 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen) /* Private MIB */ ret = os_snprintf(buf + len, buflen - len, + "wpa=%d\n" + "AKMSuiteSelector=" RSN_SUITE "\n" "hostapdWPAPTKState=%d\n" "hostapdWPAPTKGroupState=%d\n", + sm->wpa, + RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)), sm->wpa_ptk_state, sm->wpa_ptk_group_state); if (os_snprintf_error(buflen - len, ret)) @@ -3954,6 +4468,15 @@ int wpa_auth_get_pairwise(struct wpa_state_machine *sm) } +const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len) +{ + if (!sm) + return NULL; + *len = sm->pmk_len; + return sm->PMK; +} + + int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm) { if (sm == NULL) @@ -4027,6 +4550,15 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, sm->wpa_auth->conf.disable_pmksa_caching) return -1; +#ifdef CONFIG_IEEE80211R_AP + if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) && + wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) && + !wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) { + /* Cache MPMK/XXKey instead of initial part from MSK */ + pmk = pmk + PMK_LEN; + pmk_len = PMK_LEN; + } else +#endif /* CONFIG_IEEE80211R_AP */ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) { if (pmk_len > PMK_LEN_SUITE_B_192) pmk_len = PMK_LEN_SUITE_B_192; @@ -4034,6 +4566,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, pmk_len = PMK_LEN; } + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len); if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL, sm->PTK.kck, sm->PTK.kck_len, sm->wpa_auth->addr, sm->addr, session_timeout, @@ -4052,6 +4585,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, if (wpa_auth == NULL) return -1; + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len); if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL, NULL, 0, wpa_auth->addr, @@ -4069,6 +4603,7 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, if (wpa_auth->conf.disable_pmksa_caching) return -1; + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN); if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid, NULL, 0, wpa_auth->addr, addr, 0, NULL, @@ -4079,6 +4614,13 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, } +void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid) +{ + os_memcpy(sm->pmkid, pmkid, PMKID_LEN); + sm->pmkid_set = 1; +} + + int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *pmk, size_t pmk_len, const u8 *pmkid, int session_timeout, int akmp) @@ -4086,6 +4628,7 @@ int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr, if (wpa_auth->conf.disable_pmksa_caching) return -1; + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN); if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid, NULL, 0, wpa_auth->addr, addr, session_timeout, NULL, akmp)) @@ -4438,6 +4981,14 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, (timeout_ms % 1000) * 1000, wpa_send_eapol_timeout, wpa_auth, sm); } + +#ifdef CONFIG_TESTING_OPTIONS + if (sm->eapol_status_cb) { + sm->eapol_status_cb(sm->eapol_status_cb_ctx1, + sm->eapol_status_cb_ctx2); + sm->eapol_status_cb = NULL; + } +#endif /* CONFIG_TESTING_OPTIONS */ } @@ -4529,11 +5080,12 @@ wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_IEEE80211R_AP -int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, u8 *buf, size_t len) +int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384, + u8 *buf, size_t len) { struct wpa_auth_config *conf = &wpa_auth->conf; - return wpa_write_ftie(conf, conf->r0_key_holder, + return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder, conf->r0_key_holder_len, NULL, NULL, buf, len, NULL, 0); } @@ -4550,4 +5102,303 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm, *fils_kek_len = sm->PTK.kek_len; } + +void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk, + size_t pmk_len, const u8 *pmkid) +{ + os_memcpy(sm->PMK, pmk, pmk_len); + sm->pmk_len = pmk_len; + os_memcpy(sm->pmkid, pmkid, PMKID_LEN); + sm->pmkid_set = 1; +} + #endif /* CONFIG_FILS */ + + +void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg) +{ + if (sm) + sm->auth_alg = auth_alg; +} + + +#ifdef CONFIG_DPP2 +void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z) +{ + if (sm) { + wpabuf_clear_free(sm->dpp_z); + sm->dpp_z = z ? wpabuf_dup(z) : NULL; + } +} +#endif /* CONFIG_DPP2 */ + + +#ifdef CONFIG_TESTING_OPTIONS + +int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2) +{ + const u8 *anonce = sm->ANonce; + u8 anonce_buf[WPA_NONCE_LEN]; + + if (change_anonce) { + if (random_get_bytes(anonce_buf, WPA_NONCE_LEN)) + return -1; + anonce = anonce_buf; + } + + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "sending 1/4 msg of 4-Way Handshake (TESTING)"); + wpa_send_eapol(sm->wpa_auth, sm, + WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL, + anonce, NULL, 0, 0, 0); + return 0; +} + + +int wpa_auth_resend_m3(struct wpa_state_machine *sm, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2) +{ + u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos; + u8 *opos; + size_t gtk_len, kde_len; + struct wpa_group *gsm = sm->group; + u8 *wpa_ie; + int wpa_ie_len, secure, gtkidx, encr = 0; + + /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], + GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2]) + */ + + /* Use 0 RSC */ + os_memset(rsc, 0, WPA_KEY_RSC_LEN); + /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */ + wpa_ie = sm->wpa_auth->wpa_ie; + wpa_ie_len = sm->wpa_auth->wpa_ie_len; + if (sm->wpa == WPA_VERSION_WPA && + (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) && + wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) { + /* WPA-only STA, remove RSN IE and possible MDIE */ + wpa_ie = wpa_ie + wpa_ie[1] + 2; + if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN) + wpa_ie = wpa_ie + wpa_ie[1] + 2; + wpa_ie_len = wpa_ie[1] + 2; + } + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "sending 3/4 msg of 4-Way Handshake (TESTING)"); + if (sm->wpa == WPA_VERSION_WPA2) { + /* WPA2 send GTK in the 4-way handshake */ + secure = 1; + gtk = gsm->GTK[gsm->GN - 1]; + gtk_len = gsm->GTK_len; + gtkidx = gsm->GN; + _rsc = rsc; + encr = 1; + } else { + /* WPA does not include GTK in msg 3/4 */ + secure = 0; + gtk = NULL; + gtk_len = 0; + _rsc = NULL; + if (sm->rx_eapol_key_secure) { + /* + * It looks like Windows 7 supplicant tries to use + * Secure bit in msg 2/4 after having reported Michael + * MIC failure and it then rejects the 4-way handshake + * if msg 3/4 does not set Secure bit. Work around this + * by setting the Secure bit here even in the case of + * WPA if the supplicant used it first. + */ + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "STA used Secure bit in WPA msg 2/4 - " + "set Secure for 3/4 as workaround"); + secure = 1; + } + } + + kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); + if (gtk) + kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */ + kde_len += 300; /* FTIE + 2 * TIE */ + } +#endif /* CONFIG_IEEE80211R_AP */ + kde = os_malloc(kde_len); + if (kde == NULL) + return -1; + + pos = kde; + os_memcpy(pos, wpa_ie, wpa_ie_len); + pos += wpa_ie_len; +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + int res; + size_t elen; + + elen = pos - kde; + res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name); + if (res < 0) { + wpa_printf(MSG_ERROR, "FT: Failed to insert " + "PMKR1Name into RSN IE in EAPOL-Key data"); + os_free(kde); + return -1; + } + pos -= wpa_ie_len; + pos += elen; + } +#endif /* CONFIG_IEEE80211R_AP */ + if (gtk) { + u8 hdr[2]; + hdr[0] = gtkidx & 0x03; + hdr[1] = 0; + pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, + gtk, gtk_len); + } + opos = pos; + pos = ieee80211w_kde_add(sm, pos); + if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) { + /* skip KDE header and keyid */ + opos += 2 + RSN_SELECTOR_LEN + 2; + os_memset(opos, 0, 6); /* clear PN */ + } + if (ocv_oci_add(sm, &pos) < 0) { + os_free(kde); + return -1; + } + +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + int res; + struct wpa_auth_config *conf; + + conf = &sm->wpa_auth->conf; + if (sm->assoc_resp_ftie && + kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) { + os_memcpy(pos, sm->assoc_resp_ftie, + 2 + sm->assoc_resp_ftie[1]); + res = 2 + sm->assoc_resp_ftie[1]; + } else { + int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); + + res = wpa_write_ftie(conf, use_sha384, + conf->r0_key_holder, + conf->r0_key_holder_len, + NULL, NULL, pos, + kde + kde_len - pos, + NULL, 0); + } + if (res < 0) { + wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " + "into EAPOL-Key Key Data"); + os_free(kde); + return -1; + } + pos += res; + + /* TIE[ReassociationDeadline] (TU) */ + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE; + WPA_PUT_LE32(pos, conf->reassociation_deadline); + pos += 4; + + /* TIE[KeyLifetime] (seconds) */ + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_KEY_LIFETIME; + WPA_PUT_LE32(pos, conf->r0_key_lifetime); + pos += 4; + } +#endif /* CONFIG_IEEE80211R_AP */ + + wpa_send_eapol(sm->wpa_auth, sm, + (secure ? WPA_KEY_INFO_SECURE : 0) | + (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? + WPA_KEY_INFO_MIC : 0) | + WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | + WPA_KEY_INFO_KEY_TYPE, + _rsc, sm->ANonce, kde, pos - kde, 0, encr); + os_free(kde); + return 0; +} + + +int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2) +{ + u8 rsc[WPA_KEY_RSC_LEN]; + struct wpa_group *gsm = sm->group; + const u8 *kde; + u8 *kde_buf = NULL, *pos, hdr[2]; + u8 *opos; + size_t kde_len; + u8 *gtk; + + /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ + os_memset(rsc, 0, WPA_KEY_RSC_LEN); + /* Use 0 RSC */ + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "sending 1/2 msg of Group Key Handshake (TESTING)"); + + gtk = gsm->GTK[gsm->GN - 1]; + if (sm->wpa == WPA_VERSION_WPA2) { + kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + + ieee80211w_kde_len(sm) + ocv_oci_len(sm); + kde_buf = os_malloc(kde_len); + if (kde_buf == NULL) + return -1; + + kde = pos = kde_buf; + hdr[0] = gsm->GN & 0x03; + hdr[1] = 0; + pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, + gtk, gsm->GTK_len); + opos = pos; + pos = ieee80211w_kde_add(sm, pos); + if (pos - opos >= + 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) { + /* skip KDE header and keyid */ + opos += 2 + RSN_SELECTOR_LEN + 2; + os_memset(opos, 0, 6); /* clear PN */ + } + if (ocv_oci_add(sm, &pos) < 0) { + os_free(kde_buf); + return -1; + } + kde_len = pos - kde; + } else { + kde = gtk; + kde_len = gsm->GTK_len; + } + + sm->eapol_status_cb = cb; + sm->eapol_status_cb_ctx1 = ctx1; + sm->eapol_status_cb_ctx2 = ctx2; + + wpa_send_eapol(sm->wpa_auth, sm, + WPA_KEY_INFO_SECURE | + (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? + WPA_KEY_INFO_MIC : 0) | + WPA_KEY_INFO_ACK | + (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), + rsc, NULL, kde, kde_len, gsm->GN, 1); + + os_free(kde_buf); + return 0; +} + + +int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth) +{ + if (!wpa_auth) + return -1; + eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); + return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL); +} + +#endif /* CONFIG_TESTING_OPTIONS */