From a76a314c1535292206d92fff733cd8b36cadeaa0 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 16 Oct 2022 16:38:27 +0300 Subject: [PATCH] FT: Extend PMK-R0 derivation for FT-SAE-EXT-KEY Provide AKM to the helper function to cover the SHA512-based derivation case. Signed-off-by: Jouni Malinen --- src/ap/wpa_auth.c | 3 +- src/ap/wpa_auth_ft.c | 20 ++++++++--- src/common/wpa_common.c | 76 +++++++++++++++++++++++++++++------------ src/common/wpa_common.h | 2 +- src/rsn_supp/wpa.c | 7 ++-- src/rsn_supp/wpa_ft.c | 7 ++-- wlantest/rx_eapol.c | 8 +++-- 7 files changed, 88 insertions(+), 35 deletions(-) diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 0806ff0fb..736c2feb6 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2459,7 +2459,6 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, struct wpa_authenticator *wpa_auth = sm->wpa_auth; struct wpa_auth_config *conf = &wpa_auth->conf; u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; - int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); if (wpa_derive_pmk_r0(fils_ft, fils_ft_len, conf->ssid, conf->ssid_len, @@ -2467,7 +2466,7 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, conf->r0_key_holder, conf->r0_key_holder_len, sm->addr, pmk_r0, pmk_r0_name, - use_sha384) < 0) + sm->wpa_key_mgmt) < 0) return -1; wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 27a2ba3cf..9ad7bbc19 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2108,9 +2108,7 @@ 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) { u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; - size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ? - SHA384_MAC_LEN : PMK_LEN; - size_t pmk_r1_len = pmk_r0_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; @@ -2128,6 +2126,17 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) const u8 *mpmk; size_t mpmk_len; + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + (sm->xxkey_len == SHA256_MAC_LEN || + sm->xxkey_len == SHA384_MAC_LEN || + sm->xxkey_len == SHA512_MAC_LEN)) + pmk_r0_len = sm->xxkey_len; + else if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) + pmk_r0_len = SHA384_MAC_LEN; + else + pmk_r0_len = PMK_LEN; + pmk_r1_len = pmk_r0_len; + if (sm->xxkey_len > 0) { mpmk = sm->xxkey; mpmk_len = sm->xxkey_len; @@ -2154,7 +2163,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid, r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name, - wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0) + 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, @@ -2955,7 +2964,8 @@ static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm, if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh, r0kh_len, sm->addr, - pmk_r0, pmk_r0_name, 0) < 0 || + pmk_r0, pmk_r0_name, + WPA_KEY_MGMT_FT_PSK) < 0 || wpa_derive_pmk_r1(pmk_r0, PMK_LEN, pmk_r0_name, r1kh, sm->addr, pmk_r1, pmk_r1_name) < 0 || os_memcmp_const(pmk_r1_name, req_pmk_r1_name, diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 11620ccfc..38bca41a0 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -2059,30 +2059,40 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, const u8 *ssid, size_t ssid_len, const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name, - int use_sha384) + int key_mgmt) { u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + FT_R0KH_ID_MAX_LEN + ETH_ALEN]; - u8 *pos, r0_key_data[64], hash[48]; + u8 *pos, r0_key_data[64], hash[64]; const u8 *addr[2]; size_t len[2]; - size_t q = use_sha384 ? 48 : 32; - size_t r0_key_data_len = q + 16; + size_t q, r0_key_data_len; + int res; + + if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + (xxkey_len == SHA256_MAC_LEN || xxkey_len == SHA384_MAC_LEN || + xxkey_len == SHA512_MAC_LEN)) + q = xxkey_len; + else if (wpa_key_mgmt_sha384(key_mgmt)) + q = SHA384_MAC_LEN; + else + q = SHA256_MAC_LEN; + r0_key_data_len = q + 16; /* - * R0-Key-Data = KDF-384(XXKey, "FT-R0", + * R0-Key-Data = KDF-Hash-Length(XXKey, "FT-R0", * SSIDlength || SSID || MDID || R0KHlength || * R0KH-ID || S0KH-ID) * XXKey is either the second 256 bits of MSK or PSK; or the first - * 384 bits of MSK for FT-EAP-SHA384. + * 384 bits of MSK for FT-EAP-SHA384; or PMK from SAE. * PMK-R0 = L(R0-Key-Data, 0, Q) * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128) - * Q = 384 for FT-EAP-SHA384; otherwise, 256 + * Q = 384 for FT-EAP-SHA384; the length of the digest generated by H() + * for FT-SAE-EXT-KEY; or otherwise, 256 */ if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) return -1; - wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s", - use_sha384 ? "SHA384" : "SHA256"); + wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-SHA%zu", q * 8); wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len); wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len); wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN); @@ -2100,30 +2110,43 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, os_memcpy(pos, s0kh_id, ETH_ALEN); pos += ETH_ALEN; + res = -1; +#ifdef CONFIG_SHA512 + if (q == SHA512_MAC_LEN) { + if (xxkey_len != SHA512_MAC_LEN) { + wpa_printf(MSG_ERROR, + "FT: Unexpected XXKey length %d (expected %d)", + (int) xxkey_len, SHA512_MAC_LEN); + return -1; + } + res = sha512_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, + r0_key_data, r0_key_data_len); + } +#endif /* CONFIG_SHA512 */ #ifdef CONFIG_SHA384 - if (use_sha384) { + if (q == SHA384_MAC_LEN) { if (xxkey_len != SHA384_MAC_LEN) { wpa_printf(MSG_ERROR, "FT: Unexpected XXKey length %d (expected %d)", (int) xxkey_len, SHA384_MAC_LEN); return -1; } - if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, - r0_key_data, r0_key_data_len) < 0) - return -1; + res = sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, + r0_key_data, r0_key_data_len); } #endif /* CONFIG_SHA384 */ - if (!use_sha384) { + if (q == SHA256_MAC_LEN) { if (xxkey_len != PMK_LEN) { wpa_printf(MSG_ERROR, "FT: Unexpected XXKey length %d (expected %d)", (int) xxkey_len, PMK_LEN); return -1; } - if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, - r0_key_data, r0_key_data_len) < 0) - return -1; + res = sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, + r0_key_data, r0_key_data_len); } + if (res < 0) + return res; os_memcpy(pmk_r0, r0_key_data, q); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16); @@ -2136,12 +2159,23 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, addr[1] = &r0_key_data[q]; len[1] = 16; + res = -1; +#ifdef CONFIG_SHA512 + if (q == SHA512_MAC_LEN) + res = sha512_vector(2, addr, len, hash); +#endif /* CONFIG_SHA512 */ #ifdef CONFIG_SHA384 - if (use_sha384 && sha384_vector(2, addr, len, hash) < 0) - return -1; + if (q == SHA384_MAC_LEN) + res = sha384_vector(2, addr, len, hash); #endif /* CONFIG_SHA384 */ - if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0) - return -1; + if (q == SHA256_MAC_LEN) + res = sha256_vector(2, addr, len, hash); + if (res < 0) { + wpa_printf(MSG_DEBUG, + "FT: Failed to derive PMKR0Name (PMK-R0 len %zu)", + q); + return res; + } os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN); forced_memzero(r0_key_data, sizeof(r0_key_data)); diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 561f926ae..7374d8b7b 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -475,7 +475,7 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, const u8 *ssid, size_t ssid_len, const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name, - int use_sha384); + int key_mgmt); int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, const u8 *s1kh_id, u8 *pmk_r1_name, size_t pmk_r1_len); diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 10bef1a4a..5f305b897 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -4610,11 +4610,14 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf) if (wpa_derive_pmk_r0(sm->fils_ft, sm->fils_ft_len, sm->ssid, sm->ssid_len, sm->mobility_domain, sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, - sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) { + sm->pmk_r0, sm->pmk_r0_name, sm->key_mgmt) < 0) { wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMK-R0"); return -1; } - sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; + if (wpa_key_mgmt_sae_ext_key(sm->key_mgmt)) + sm->pmk_r0_len = sm->fils_ft_len; + else + sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR, MAC2STR(sm->r1kh_id)); pos = wpabuf_put(buf, WPA_PMK_NAME_LEN); diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 372d6872b..beae5f106 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -55,11 +55,14 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, return -1; } - sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; + if (wpa_key_mgmt_sae_ext_key(sm->key_mgmt)) + sm->pmk_r0_len = mpmk_len; + else + sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; if (wpa_derive_pmk_r0(mpmk, mpmk_len, sm->ssid, sm->ssid_len, sm->mobility_domain, sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, - sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) + sm->pmk_r0, sm->pmk_r0_name, sm->key_mgmt) < 0) return -1; sm->pmk_r1_len = sm->pmk_r0_len; if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name, diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c index e96c487fe..6607aeec4 100644 --- a/wlantest/rx_eapol.c +++ b/wlantest/rx_eapol.c @@ -192,9 +192,13 @@ static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss, bss->ssid, bss->ssid_len, bss->mdid, bss->r0kh_id, bss->r0kh_id_len, sa, sta->pmk_r0, sta->pmk_r0_name, - use_sha384) < 0) + sta->key_mgmt) < 0) return -1; - sta->pmk_r0_len = use_sha384 ? PMK_LEN_SUITE_B_192 : PMK_LEN; + if (wpa_key_mgmt_sae_ext_key(sta->key_mgmt)) + sta->pmk_r0_len = pmk->pmk_len; + else + sta->pmk_r0_len = use_sha384 ? PMK_LEN_SUITE_B_192 : + PMK_LEN; if (wpa_derive_pmk_r1(sta->pmk_r0, sta->pmk_r0_len, sta->pmk_r0_name, bss->r1kh_id, sa,