diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 5fde990ea..c49cdaa67 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -59,7 +59,9 @@ 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, int force_sha256); + struct wpa_ptk *ptk, int force_sha256, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len); static void wpa_group_free(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_group_get(struct wpa_authenticator *wpa_auth, @@ -950,6 +952,10 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, const u8 *pmk = NULL; size_t pmk_len; int vlan_id = 0; + u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_LEN_MAX]; + size_t key_len; + int ret = -1; os_memset(&PTK, 0, sizeof(PTK)); for (;;) { @@ -971,8 +977,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, pmk_len = sm->pmk_len; } - if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) < - 0) + if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0, + pmk_r0, pmk_r1, pmk_r0_name, &key_len) < 0) break; if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK, @@ -993,7 +999,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, if (!ok) { wpa_printf(MSG_DEBUG, "WPA: Earlier SNonce did not result in matching MIC"); - return -1; + goto fail; } wpa_printf(MSG_DEBUG, @@ -1002,14 +1008,26 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, 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; + goto fail; + +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) { + wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1"); + wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name, + key_len); + } +#endif /* CONFIG_IEEE80211R_AP */ 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; + ret = 0; +fail: + forced_memzero(pmk_r0, sizeof(pmk_r0)); + forced_memzero(pmk_r1, sizeof(pmk_r1)); + return ret; } @@ -2347,7 +2365,9 @@ 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, int force_sha256) + struct wpa_ptk *ptk, int force_sha256, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len) { const u8 *z = NULL; size_t z_len = 0, kdk_len; @@ -2373,7 +2393,8 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, ptk_name, sm->wpa_key_mgmt, sm->pairwise, kdk_len); } else { - ret = wpa_auth_derive_ptk_ft(sm, ptk); + ret = wpa_auth_derive_ptk_ft(sm, ptk, pmk_r0, pmk_r1, + pmk_r0_name, key_len); } if (ret) { wpa_printf(MSG_ERROR, "FT: PTK derivation failed"); @@ -3058,6 +3079,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) struct wpa_eapol_ie_parse kde; int vlan_id = 0; int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround; + u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_LEN_MAX]; + size_t key_len; SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); sm->EAPOLKeyReceived = false; @@ -3096,7 +3120,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) } if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK, - owe_ptk_workaround == 2) < 0) + owe_ptk_workaround == 2, pmk_r0, pmk_r1, + pmk_r0_name, &key_len) < 0) break; if (mic_len && @@ -3145,7 +3170,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) sm->last_rx_eapol_key, sm->last_rx_eapol_key_len); sm->waiting_radius_psk = 1; - return; + goto out; } if (!ok) { @@ -3153,7 +3178,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) "invalid MIC in msg 2/4 of 4-Way Handshake"); if (psk_found) wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr); - return; + goto out; } /* @@ -3167,12 +3192,12 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) 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; + goto out; if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg 2/4 with invalid Key Data contents"); - return; + goto out; } if (kde.rsn_ie) { eapol_key_ie = kde.rsn_ie; @@ -3199,7 +3224,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) /* MLME-DEAUTHENTICATE.request */ wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } if ((!sm->rsnxe && kde.rsnxe) || (sm->rsnxe && !kde.rsnxe) || @@ -3215,7 +3240,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) /* MLME-DEAUTHENTICATE.request */ wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } #ifdef CONFIG_OCV if (wpa_auth_uses_ocv(sm)) { @@ -3227,14 +3252,14 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) 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; + goto out; } if (get_sta_tx_parameters(sm, channel_width_to_int(ci.chanwidth), ci.seg1_idx, &tx_chanwidth, &tx_seg1_idx) < 0) - return; + goto out; res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci, tx_chanwidth, tx_seg1_idx); @@ -3251,7 +3276,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) OCV_FAILURE "addr=" MACSTR " frame=eapol-key-m2 error=%s", MAC2STR(sm->addr), ocv_errorstr); - return; + goto out; } } #endif /* CONFIG_OCV */ @@ -3259,7 +3284,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_P2P @@ -3297,7 +3322,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association"); wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } } #endif /* CONFIG_DPP2 */ @@ -3317,7 +3342,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", sm->pmk_r1_name, WPA_PMK_NAME_LEN); - return; + goto out; } } #endif /* CONFIG_IEEE80211R_AP */ @@ -3326,7 +3351,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) 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; + goto out; } sm->pending_1_of_4_timeout = 0; @@ -3342,9 +3367,20 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) sm->MICVerified = true; +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) { + wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1"); + wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name, + key_len); + } +#endif /* CONFIG_IEEE80211R_AP */ + os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); forced_memzero(&PTK, sizeof(PTK)); sm->PTK_valid = true; +out: + forced_memzero(pmk_r0, sizeof(pmk_r0)); + forced_memzero(pmk_r1, sizeof(pmk_r1)); } diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 88d63bb77..7a5e58401 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2109,11 +2109,11 @@ int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, } -int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) +int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len) { - u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; size_t pmk_r0_len, pmk_r1_len; - u8 pmk_r1[PMK_LEN_MAX]; u8 ptk_name[WPA_PMK_NAME_LEN]; const u8 *mdid = sm->wpa_auth->conf.mobility_domain; const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder; @@ -2121,12 +2121,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder; const u8 *ssid = sm->wpa_auth->conf.ssid; size_t ssid_len = sm->wpa_auth->conf.ssid_len; - int psk_local = sm->wpa_auth->conf.ft_psk_generate_local; - int expires_in = sm->wpa_auth->conf.r0_key_lifetime; - struct vlan_description vlan; - const u8 *identity, *radius_cui; - size_t identity_len, radius_cui_len; - int session_timeout; const u8 *mpmk; size_t mpmk_len; @@ -2139,7 +2133,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) pmk_r0_len = SHA384_MAC_LEN; else pmk_r0_len = PMK_LEN; - pmk_r1_len = pmk_r0_len; + *key_len = pmk_r1_len = pmk_r0_len; if (sm->xxkey_len > 0) { mpmk = sm->xxkey; @@ -2153,10 +2147,39 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) return -1; } + if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid, + r0kh, r0kh_len, sm->addr, + pmk_r0, pmk_r0_name, + sm->wpa_key_mgmt) < 0 || + wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr, + pmk_r1, sm->pmk_r1_name) < 0) + return -1; + + return wpa_pmk_r1_to_ptk(pmk_r1, 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, + 0); +} + + +void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0, + const u8 *pmk_r1, const u8 *pmk_r0_name, + size_t key_len) +{ + int psk_local = sm->wpa_auth->conf.ft_psk_generate_local; + int expires_in = sm->wpa_auth->conf.r0_key_lifetime; + struct vlan_description vlan; + const u8 *identity, *radius_cui; + size_t identity_len, radius_cui_len; + int session_timeout; + + if (psk_local && wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) + return; + if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) { wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR, MAC2STR(sm->addr)); - return -1; + return; } identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity); @@ -2164,31 +2187,16 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) &radius_cui); session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr); - if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid, - r0kh, r0kh_len, sm->addr, - pmk_r0, pmk_r0_name, - sm->wpa_key_mgmt) < 0) - return -1; - if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) - wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len, - pmk_r0_name, - sm->pairwise, &vlan, expires_in, - session_timeout, identity, identity_len, - radius_cui, radius_cui_len); - if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr, - pmk_r1, sm->pmk_r1_name) < 0) - return -1; - if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) - wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len, - sm->pmk_r1_name, sm->pairwise, &vlan, - expires_in, session_timeout, identity, - identity_len, radius_cui, radius_cui_len); - - return wpa_pmk_r1_to_ptk(pmk_r1, 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, - 0); + wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, key_len, + pmk_r0_name, + sm->pairwise, &vlan, expires_in, + session_timeout, identity, identity_len, + radius_cui, radius_cui_len); + wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, key_len, + sm->pmk_r1_name, sm->pairwise, &vlan, + expires_in, session_timeout, identity, + identity_len, radius_cui, radius_cui_len); } diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 7ed3f2b6b..f3cb9be31 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -304,7 +304,12 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len, const u8 *anonce, const u8 *snonce, u8 *buf, size_t len, const u8 *subelem, size_t subelem_len, int rsnxe_used); -int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk); +int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len); +void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0, + const u8 *pmk_r1, const u8 *pmk_r0_name, + size_t key_len); struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);