From 3653663933319aeaffb56322b1d47dd1abdb3150 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 13 Mar 2019 17:24:29 +0200 Subject: [PATCH] FILS+FT: AP mode processing of PMKR1Name in initial MD association Derive PMKR1Name during the FILS authentication step, verify that the station uses matching PMKR1Name in (Re)Association Request frame, and add RSNE[PMKR1Name] into (Re)Association Response frame when going through FT initial mobility domain association using FILS. These steps were missed from the initial implementation, but are needed to match the IEEE 802.11ai requirements for explicit confirmation of the FT key hierarchy (similarly to what is done in FT 4-way handshake when FILS is not used). Signed-off-by: Jouni Malinen --- src/ap/ieee802_11.c | 1 + src/ap/wpa_auth.c | 17 +++++++++++++++++ src/ap/wpa_auth.h | 1 + src/ap/wpa_auth_ft.c | 18 ++++++++++++++++-- src/ap/wpa_auth_i.h | 1 + src/ap/wpa_auth_ie.c | 15 +++++++++++++++ 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index eee468396..78f01dfa5 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2865,6 +2865,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, "state machine"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } + wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg); res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, hapd->iface->freq, wpa_ie, wpa_ie_len, diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index cc77acb1b..1cb8113d0 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2210,6 +2210,16 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, pmk_r0_name, WPA_PMK_NAME_LEN); wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name); os_memset(fils_ft, 0, sizeof(fils_ft)); + + res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder, + sm->addr, sm->pmk_r1_name, + use_sha384); + os_memset(pmk_r0, 0, 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 */ @@ -4812,6 +4822,13 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm, #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_TESTING_OPTIONS int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce, diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 1d57dcae7..50a8d1743 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -473,6 +473,7 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm, u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm, u8 *pos, size_t max_len, const u8 *req_ies, size_t req_ies_len); +void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg); int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce, void (*cb)(void *ctx1, void *ctx2), diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 31ca4e5d0..1fb6a0d86 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2386,10 +2386,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, end = pos + max_len; - if (auth_alg == WLAN_AUTH_FT) { + if (auth_alg == WLAN_AUTH_FT || + ((auth_alg == WLAN_AUTH_FILS_SK || + auth_alg == WLAN_AUTH_FILS_SK_PFS || + auth_alg == WLAN_AUTH_FILS_PK) && + (sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 | + WPA_KEY_MGMT_FT_FILS_SHA384)))) { + if (!sm->pmk_r1_name_valid) { + wpa_printf(MSG_ERROR, + "FT: PMKR1Name is not valid for Assoc Resp RSNE"); + return NULL; + } + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name for Assoc Resp RSNE", + sm->pmk_r1_name, WPA_PMK_NAME_LEN); /* * RSN (only present if this is a Reassociation Response and - * part of a fast BSS transition) + * part of a fast BSS transition; or if this is a + * (Re)Association Response frame during an FT initial mobility + * domain association using FILS) */ res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name); if (res < 0) diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index a349304d5..a3164d265 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -22,6 +22,7 @@ struct wpa_state_machine { u8 addr[ETH_ALEN]; u8 p2p_dev_addr[ETH_ALEN]; + u16 auth_alg; enum { WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED, diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 4a96008c1..791c5a01b 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -852,6 +852,21 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, else sm->wpa = WPA_VERSION_WPA; +#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS) + if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 || + sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) && + (sm->auth_alg == WLAN_AUTH_FILS_SK || + sm->auth_alg == WLAN_AUTH_FILS_SK_PFS || + sm->auth_alg == WLAN_AUTH_FILS_PK) && + (data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid || + os_memcmp_const(data.pmkid, sm->pmk_r1_name, + WPA_PMK_NAME_LEN) != 0)) { + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, + "No PMKR1Name match for FILS+FT"); + return WPA_INVALID_PMKID; + } +#endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */ + sm->pmksa = NULL; for (i = 0; i < data.num_pmkid; i++) { wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",