[PATCH 10/12] WPA: Extend the wpa_pmk_to_ptk() function to also derive HLTK

Ilan Peer <[email protected]>
Newsgroups gmane.linux.drivers.hostap
Message-ID <[email protected]>
Extend the wpa_pmk_to_ptk() to also derive High Level
Transient Key (HLTK), which can later be used for
for secure LTF measurements.

Update the wpa_supplicant and hostapd configuration and the
corresponding WPA and WPA Auth state machine, to allow
enabling of HLTK derivation.

Signed-off-by: Ilan Peer <[email protected]>
---
 hostapd/config_file.c      |  6 ++++++
 src/ap/ap_config.h         | 10 ++++++++++
 src/ap/wpa_auth.c          |  3 ++-
 src/ap/wpa_auth.h          |  6 ++++++
 src/ap/wpa_auth_glue.c     |  5 +++++
 src/common/wpa_common.c    | 23 ++++++++++++++++++++---
 src/common/wpa_common.h    |  5 ++++-
 src/rsn_supp/wpa.c         |  5 ++++-
 src/rsn_supp/wpa.h         |  1 +
 src/rsn_supp/wpa_i.h       |  6 ++++++
 wlantest/rx_eapol.c        |  2 +-
 wpa_supplicant/config.c    |  5 +++++
 wpa_supplicant/config.h    | 10 ++++++++++
 wpa_supplicant/wpas_glue.c |  5 +++++
 14 files changed, 85 insertions(+), 7 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 6dde59a5a7..83fdacf42b 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4550,6 +4550,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 		}
 		bss->mka_psk_set |= MKA_PSK_SET_CKN;
 #endif /* CONFIG_MACSEC */
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	} else if (os_strcmp(buf, "force_hltk_derivation") == 0) {
+		bss->force_hltk_derivation = atoi(pos);
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
 	} else {
 		wpa_printf(MSG_ERROR,
 			   "Line %d: unknown configuration item '%s'",
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b6e11f25f5..5a60785c20 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -840,6 +840,16 @@ struct hostapd_bss_config {
 	 */
 	u8 mka_psk_set;
 #endif /* CONFIG_MACSEC */
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	/*
+	 * Normally, HLTK should be derived iff both sides support secure LTF.
+	 * Allow forcing HLTK derivation for testing purposes
+	 */
+	int force_hltk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
 };
 
 /**
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index e67c344988..88c3c5aede 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -2289,7 +2289,8 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
 		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, akmp, sm->pairwise, z, z_len);
+			      ptk, akmp, sm->pairwise, z, z_len,
+			      sm->wpa_auth->conf.hltk ? WPA_HLTK_MAX_LEN : 0);
 }
 
 
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 1f7ba4899d..9c5de83e30 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -240,6 +240,12 @@ struct wpa_auth_config {
 #endif /* CONFIG_FILS */
 	int sae_pwe;
 	int owe_ptk_workaround;
+
+	/*
+	 * If set Higher Layer Transient Key should be derived as part of PMK to
+	 * PTK derivation.
+	 */
+	int hltk;
 };
 
 typedef enum {
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 82e82a7d2c..2d0299be00 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -166,6 +166,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
 #ifdef CONFIG_OWE
 	wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
 #endif /* CONFIG_OWE */
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	wconf->hltk = conf->force_hltk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
 }
 
 
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index bd79575d0f..844bb343eb 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -333,6 +333,7 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
  * @ptk: Buffer for pairwise transient key
  * @akmp: Negotiated AKM
  * @cipher: Negotiated pairwise cipher
+ * @hltk_len: the length in octets that should be derived for HTLK
  * Returns: 0 on success, -1 on failure
  *
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
@@ -348,12 +349,13 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 		   const u8 *addr1, const u8 *addr2,
 		   const u8 *nonce1, const u8 *nonce2,
 		   struct wpa_ptk *ptk, int akmp, int cipher,
-		   const u8 *z, size_t z_len)
+		   const u8 *z, size_t z_len, size_t hltk_len)
 {
 #define MAX_Z_LEN 66 /* with NIST P-521 */
 	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
 	size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
-	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+		WPA_HLTK_MAX_LEN];
 	size_t ptk_len;
 
 	if (pmk_len == 0) {
@@ -387,16 +389,24 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 		data_len += z_len;
 	}
 
+	if (hltk_len > WPA_HLTK_MAX_LEN) {
+		wpa_printf(MSG_ERROR,
+			   "WPA: HLTK len=%zu exceeds max supported len",
+			   hltk_len);
+		return -1;
+	}
+
 	ptk->kck_len = wpa_kck_len(akmp, pmk_len);
 	ptk->kek_len = wpa_kek_len(akmp, pmk_len);
 	ptk->tk_len = wpa_cipher_key_len(cipher);
+	ptk->hltk_len = hltk_len;
 	if (ptk->tk_len == 0) {
 		wpa_printf(MSG_ERROR,
 			   "WPA: Unsupported cipher (0x%x) used in PTK derivation",
 			   cipher);
 		return -1;
 	}
-	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->hltk_len;
 
 	if (wpa_key_mgmt_sha384(akmp)) {
 #if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
@@ -479,6 +489,13 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
 	wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
 
+	if (hltk_len) {
+		os_memcpy(ptk->hltk, tmp + ptk->kck_len + ptk->kek_len +
+			  ptk->tk_len, ptk->hltk_len);
+		wpa_hexdump_key(MSG_DEBUG, "WPA: HLTK",
+				ptk->hltk, ptk->hltk_len);
+	}
+
 	ptk->kek2_len = 0;
 	ptk->kck2_len = 0;
 
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 7850c878ef..99ec57bb38 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -199,6 +199,7 @@ struct wpa_eapol_key {
 #define WPA_KCK_MAX_LEN 32
 #define WPA_KEK_MAX_LEN 64
 #define WPA_TK_MAX_LEN 32
+#define WPA_HLTK_MAX_LEN 32
 #define FILS_ICK_MAX_LEN 48
 #define FILS_FT_MAX_LEN 48
 
@@ -212,11 +213,13 @@ struct wpa_ptk {
 	u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
 	u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
 	u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
+	u8 hltk[WPA_HLTK_MAX_LEN]; /* HL Temporal Key */
 	size_t kck_len;
 	size_t kek_len;
 	size_t tk_len;
 	size_t kck2_len;
 	size_t kek2_len;
+	size_t hltk_len;
 	int installed; /* 1 if key has already been installed to driver */
 };
 
@@ -356,7 +359,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 		   const u8 *addr1, const u8 *addr2,
 		   const u8 *nonce1, const u8 *nonce2,
 		   struct wpa_ptk *ptk, int akmp, int cipher,
-		   const u8 *z, size_t z_len);
+		   const u8 *z, size_t z_len, size_t hltk_len);
 int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
 		     const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
 		     size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 2887bdf34e..6841bcf0a7 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -604,7 +604,8 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
 	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->pairwise_cipher, z, z_len,
+			      sm->hltk ? WPA_HLTK_MAX_LEN : 0);
 }
 
 
@@ -3030,6 +3031,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->hltk = config->hltk;
 #ifdef CONFIG_FILS
 		if (config->fils_cache_id) {
 			sm->fils_cache_id_set = 1;
@@ -3052,6 +3054,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->hltk = 0;
 	}
 }
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 0bd14495ae..b9c3cb53f7 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -119,6 +119,7 @@ struct rsn_supp_config {
 	int owe_ptk_workaround;
 	const u8 *fils_cache_id;
 	int beacon_prot;
+	int hltk;
 };
 
 #ifndef CONFIG_NO_WPA
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 7af678dcd9..f06dbd6ba4 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -69,6 +69,12 @@ struct wpa_sm {
 	int owe_ptk_workaround;
 	int beacon_prot;
 
+	/*
+	 * If set Higher Layer Transient Key should be derived as part of PMK to
+	 * PTK derivation.
+	 */
+	int hltk;
+
 	u8 own_addr[ETH_ALEN];
 	const char *ifname;
 	const char *bridge_ifname;
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
index e4fe7e23eb..0a75a89dbc 100644
--- a/wlantest/rx_eapol.c
+++ b/wlantest/rx_eapol.c
@@ -132,7 +132,7 @@ static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss,
 				  "Pairwise key expansion",
 				  bss->bssid, sta->addr, sta->anonce,
 				  sta->snonce, &ptk, sta->key_mgmt,
-				  sta->pairwise_cipher, NULL, 0) < 0 ||
+				  sta->pairwise_cipher, NULL, 0, 0) < 0 ||
 		   check_mic(ptk.kck, ptk.kck_len, sta->key_mgmt, ver, data,
 			     len) < 0) {
 		return -1;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 938165465d..0234c4fce2 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -5052,6 +5052,11 @@ static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_WNM
 	{ INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	{ INT_RANGE(force_hltk_derivation, 0, 1), 0 },
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index b3c779233f..c067f6ca35 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1570,6 +1570,16 @@ struct wpa_config {
 	 * By default BSS transition management is enabled
 	 */
 	int disable_btm;
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	/*
+	 * Normally, HLTK should be derived iff both sides support secure LTF.
+	 * Allow forcing HLTK derivation for testing purposes
+	 */
+	int force_hltk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN*/
 };
 
 
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 5ddefce082..29257b9873 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1334,5 +1334,10 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_FILS */
 		conf.beacon_prot = ssid->beacon_prot;
 	}
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	conf.hltk = wpa_s->conf->force_hltk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN*/
 	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
 }
-- 
2.17.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.