From dccb6cde037f4693c835697d632c6c16beb9a4e8 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 16 Dec 2020 13:01:39 +0200 Subject: [PATCH] WPA: Support deriving KDK based on capabilities Derive the KDK as part of PMK to PTK derivation if forced by configuration or in case both the local station and the AP declare support for secure LTF. Signed-off-by: Ilan Peer --- src/rsn_supp/wpa.c | 27 +++++++++++++++++++++------ src/rsn_supp/wpa.h | 2 +- src/rsn_supp/wpa_ft.c | 22 ++++++++++++++++++---- src/rsn_supp/wpa_i.h | 4 ++-- wpa_supplicant/wpas_glue.c | 2 +- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 9ef073114..e1aba36de 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -579,7 +579,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, struct wpa_ptk *ptk) { const u8 *z = NULL; - size_t z_len = 0; + size_t z_len = 0, kdk_len; int akmp; #ifdef CONFIG_IEEE80211R @@ -603,11 +603,19 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, akmp |= WPA_KEY_MGMT_PSK_SHA256; } #endif /* CONFIG_OWE */ + + if (sm->force_kdk_derivation || + (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && + sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + kdk_len = WPA_KDK_MAX_LEN; + else + kdk_len = 0; + return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, ptk, akmp, sm->pairwise_cipher, z, z_len, - sm->kdk ? WPA_KDK_MAX_LEN : 0); + kdk_len); } @@ -3188,7 +3196,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->p2p = config->p2p; sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation; sm->owe_ptk_workaround = config->owe_ptk_workaround; - sm->kdk = config->kdk; + sm->force_kdk_derivation = config->force_kdk_derivation; #ifdef CONFIG_FILS if (config->fils_cache_id) { sm->fils_cache_id_set = 1; @@ -3211,7 +3219,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->wpa_rsc_relaxation = 0; sm->owe_ptk_workaround = 0; sm->beacon_prot = 0; - sm->kdk = false; + sm->force_kdk_derivation = false; } } @@ -4134,7 +4142,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, const u8 *g_sta = NULL; size_t g_sta_len = 0; const u8 *g_ap = NULL; - size_t g_ap_len = 0; + size_t g_ap_len = 0, kdk_len; struct wpabuf *pub = NULL; os_memcpy(sm->bssid, bssid, ETH_ALEN); @@ -4362,6 +4370,13 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, goto fail; } + if (sm->force_kdk_derivation || + (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && + sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + kdk_len = WPA_KDK_MAX_LEN; + else + kdk_len = 0; + if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid, sm->fils_nonce, sm->fils_anonce, dh_ss ? wpabuf_head(dh_ss) : NULL, @@ -4369,7 +4384,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, &sm->ptk, ick, &ick_len, sm->key_mgmt, sm->pairwise_cipher, sm->fils_ft, &sm->fils_ft_len, - sm->kdk ? WPA_KDK_MAX_LEN : 0) < 0) { + kdk_len) < 0) { wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK"); goto fail; } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 9f0861cd2..8e4533e45 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -132,7 +132,7 @@ struct rsn_supp_config { int owe_ptk_workaround; const u8 *fils_cache_id; int beacon_prot; - bool kdk; + bool force_kdk_derivation; }; #ifndef CONFIG_NO_WPA diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 28985f238..c26f1a5cd 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -40,7 +40,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, const u8 *anonce = key->key_nonce; int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); const u8 *mpmk; - size_t mpmk_len; + size_t mpmk_len, kdk_len; if (sm->xxkey_len > 0) { mpmk = sm->xxkey; @@ -68,10 +68,17 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, wpa_ft_pasn_store_r1kh(sm, src_addr); + if (sm->force_kdk_derivation || + (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && + sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + kdk_len = WPA_KDK_MAX_LEN; + else + kdk_len = 0; + return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce, sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk, ptk_name, sm->key_mgmt, sm->pairwise_cipher, - sm->kdk ? WPA_KDK_MAX_LEN : 0); + kdk_len); } @@ -539,7 +546,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, int ret; const u8 *bssid; const u8 *kck; - size_t kck_len; + size_t kck_len, kdk_len; int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); const u8 *anonce, *snonce; @@ -664,11 +671,18 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, wpa_ft_pasn_store_r1kh(sm, bssid); + if (sm->force_kdk_derivation || + (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && + sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + kdk_len = WPA_KDK_MAX_LEN; + else + kdk_len = 0; + if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce, sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt, sm->pairwise_cipher, - sm->kdk ? WPA_KDK_MAX_LEN : 0) < 0) + kdk_len) < 0) return -1; if (wpa_key_mgmt_fils(sm->key_mgmt)) { diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 16f089c48..1dc963963 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -80,9 +80,9 @@ struct wpa_sm { /* * If set Key Derivation Key should be derived as part of PMK to - * PTK derivation. + * PTK derivation regardless of advertised capabilities. */ - bool kdk; + bool force_kdk_derivation; u8 own_addr[ETH_ALEN]; const char *ifname; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index b914d2974..798b5b461 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -1477,7 +1477,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, } #ifdef CONFIG_PASN #ifdef CONFIG_TESTING_OPTIONS - conf.kdk = wpa_s->conf->force_kdk_derivation; + conf.force_kdk_derivation = wpa_s->conf->force_kdk_derivation; #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN*/ wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);