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 <ilan.peer@xxxxxxxxx> --- 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 25dc1fade7..521f30a38e 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4528,6 +4528,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 23416c6ebf..c7b186b0d5 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -832,6 +832,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 891cdd22aa..b71caac9c3 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2238,7 +2238,8 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion", sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce, - ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len); + ptk, sm->wpa_key_mgmt, 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 933a4b8ed7..0576bbfba2 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -233,6 +233,12 @@ struct wpa_auth_config { u8 fils_cache_id[FILS_CACHE_ID_LEN]; #endif /* CONFIG_FILS */ int sae_pwe; + + /* + * 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 7fb0923e48..97de7d9b0a 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -139,6 +139,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, FILS_CACHE_ID_LEN); #endif /* CONFIG_FILS */ wconf->sae_pwe = conf->sae_pwe; +#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 ea9f7a21ce..7c289b5423 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) @@ -458,6 +468,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 beb1ecd5e4..9a3bacceed 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -196,6 +196,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 @@ -209,11 +210,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 */ }; @@ -340,7 +343,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 504feaf2a5..693cc3ba14 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -578,7 +578,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, sm->key_mgmt, - sm->pairwise_cipher, z, z_len); + sm->pairwise_cipher, z, z_len, + sm->hltk ? WPA_HLTK_MAX_LEN : 0); } @@ -2929,6 +2930,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->wpa_ptk_rekey = config->wpa_ptk_rekey; sm->p2p = config->p2p; sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation; + sm->hltk = config->hltk; #ifdef CONFIG_FILS if (config->fils_cache_id) { sm->fils_cache_id_set = 1; @@ -2948,6 +2950,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->wpa_ptk_rekey = 0; sm->p2p = 0; sm->wpa_rsc_relaxation = 0; + sm->hltk = 0; } } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index f1fbb1bb56..9c9e3825a1 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -114,6 +114,7 @@ struct rsn_supp_config { int p2p; int wpa_rsc_relaxation; const u8 *fils_cache_id; + int hltk; }; #ifndef CONFIG_NO_WPA diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 2a433425c7..27fed89573 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -64,6 +64,12 @@ struct wpa_sm { int p2p; int wpa_rsc_relaxation; + /* + * 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 e184495423..05c145ab63 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 33b35056b0..50652e7196 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -5047,6 +5047,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 326ac61202..85bac591d8 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1560,6 +1560,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 d80b8f28dd..43c0153c62 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -1298,5 +1298,10 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, wpa_bss_get_fils_cache_id(wpa_s->current_bss); #endif /* CONFIG_FILS */ } +#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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap