[RFC 05/30] WPA: Extend PMK to PTK derivation to also derive a SMD_KDK
Ilan Peer
ilan.peer at intel.com
Wed Oct 21 06:43:23 PDT 2026
Extend the PMK to PTK derivation to also derive a SMD_KDK. In
addition, extend the function to also allow including the
SMD Identifier as part of the 'z'.
Similarly, also extend wpa_auth_802_1x_pmk_to_ptk().
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
src/ap/ieee802_11.c | 2 +-
src/ap/wpa_auth.c | 2 +-
src/common/common_module_tests.c | 2 +-
src/common/wpa_common.c | 38 ++++++++++++++++++++++++--------
src/common/wpa_common.h | 11 +++++++--
src/rsn_supp/wpa.c | 2 +-
wlantest/rx_eapol.c | 2 +-
wpa_supplicant/sme.c | 2 +-
8 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index ecaf97713221..10b127760c4f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -3575,7 +3575,7 @@ static int ieee80211_802_1x_derive_ptk(struct hostapd_data *hapd,
sta->eap_auth_data.cipher,
wpabuf_head_u8(sta->eap_auth_data.dhss),
wpabuf_len(sta->eap_auth_data.dhss),
- &sta->eap_auth_data.ptk, kdk_len)) {
+ &sta->eap_auth_data.ptk, kdk_len, 0)) {
wpa_printf(MSG_INFO, "Failed to derive the PTK");
return -1;
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 699a3d2b0a9b..5140d378b78e 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -3162,7 +3162,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
wpa_auth_get_aa(sm), wpa_auth_get_spa(sm),
sm->ANonce, snonce, ptk, akmp,
sm->pairwise, z, z_len, kdk_len,
- sm->pasn_group);
+ sm->pasn_group, 0);
if (ret) {
wpa_printf(MSG_DEBUG,
"WPA: PTK derivation failed");
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 74a0ea368202..49beaecdbe0d 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -735,7 +735,7 @@ static int pasn_test_no_pasn_auth(void)
"Pairwise key expansion",
spa, aa, snonce, anonce,
&ptk, WPA_KEY_MGMT_SAE, WPA_CIPHER_CCMP,
- NULL, 0, WPA_KDK_MAX_LEN, 19);
+ NULL, 0, WPA_KDK_MAX_LEN, 19, 0);
if (ret)
return ret;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 55e690ded236..d3edb0eeb588 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -596,6 +596,7 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp,
* @z: Additional context data
* @z_len: Length of additional context data
* @kdk_len: The length in octets that should be derived for KDK
+ * @smd_kdk_len: The length in octets that should be derived for SMD KDK
* Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
@@ -607,19 +608,20 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp,
* The optional Z.x component is used only with DPP and that part is not defined
* in IEEE 802.11. The additional context data is also used to carry the DHss
* (Diffie-Hellman shared secret) when IEEE 802.1X authentication in
- * Authentication frames is used.
+ * Authentication frames is used and SMD Indentifier when the association is
+ * an SMD association
*/
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, size_t kdk_len, u16 pasn_group)
+ const u8 *z, size_t z_len, size_t kdk_len, u16 pasn_group,
+ size_t smd_kdk_len)
{
-#define MAX_Z_LEN 66 /* with NIST P-521 */
- u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
+ u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + WPA_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 +
- WPA_KDK_MAX_LEN];
+ WPA_KDK_MAX_LEN + WPA_SMD_KDK_MAX_LEN];
size_t ptk_len;
#ifdef CONFIG_OWE
int owe_ptk_workaround = 0;
@@ -635,7 +637,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
return -1;
}
- if (z_len > MAX_Z_LEN)
+ if (z_len > WPA_MAX_Z_LEN)
return -1;
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
@@ -668,17 +670,28 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
return -1;
}
+ if (smd_kdk_len > WPA_SMD_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR,
+ "WPA: SMD KDK len=%zu exceeds max supported len",
+ smd_kdk_len);
+ return -1;
+ }
+
+ /* Only some of the AKMs below derive an explicit hash algorithm */
+ ptk->hash_alg = RSN_HASH_NOT_SPECIFIED;
ptk->kck_len = wpa_kck_len(akmp, pmk_len);
ptk->kek_len = wpa_kek_len(akmp, pmk_len, pasn_group);
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk->kdk_len = kdk_len;
+ ptk->smd_kdk_len = smd_kdk_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->kdk_len;
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len +
+ ptk->smd_kdk_len;
if (wpa_key_mgmt_sha384(akmp)) {
#ifdef CONFIG_SHA384
@@ -815,6 +828,13 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
wpa_hexdump_key(MSG_DEBUG, "WPA: KDK", ptk->kdk, ptk->kdk_len);
}
+ if (smd_kdk_len) {
+ os_memcpy(ptk->smd_kdk, tmp + ptk->kck_len + ptk->kek_len +
+ ptk->tk_len + ptk->kdk_len, ptk->smd_kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: SMD KDK",
+ ptk->smd_kdk, ptk->smd_kdk_len);
+ }
+
ptk->kek2_len = 0;
ptk->kck2_len = 0;
@@ -2140,12 +2160,12 @@ int wpa_auth_802_1x_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa,
const u8 *aa, const u8 *snonce, const u8 *anonce,
int akmp, int cipher, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
- size_t kdk_len)
+ size_t kdk_len, size_t smd_kdk_len)
{
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
spa, aa, snonce, anonce, ptk, akmp,
cipher, dhss, dhss_len, kdk_len,
- PASN_GROUP_NOT_SPECIFIED);
+ PASN_GROUP_NOT_SPECIFIED, smd_kdk_len);
}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 158f79afd167..2c301601174d 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -267,6 +267,10 @@ struct wpa_eapol_key {
#define FILS_FT_MAX_LEN 48
#define WPA_PASN_KCK_LEN 32
#define WPA_LTF_KEYSEED_MAX_LEN 48
+#define WPA_SMD_KDK_MAX_LEN PMK_LEN_MAX
+
+ /* Maximal DHss for NIST P-521 + optional SMD Identifier */
+#define WPA_MAX_Z_LEN (66 + ETH_ALEN)
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -279,6 +283,7 @@ struct wpa_ptk {
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 kdk[WPA_KDK_MAX_LEN]; /* Key Derivation Key */
+ u8 smd_kdk[WPA_SMD_KDK_MAX_LEN]; /* SMD Key Derivation Key */
u8 ltf_keyseed[WPA_LTF_KEYSEED_MAX_LEN]; /* LTF Key seed */
size_t kck_len;
size_t kek_len;
@@ -288,6 +293,7 @@ struct wpa_ptk {
size_t kdk_len;
size_t ptk_len;
size_t ltf_keyseed_len;
+ size_t smd_kdk_len;
enum rsn_hash_alg hash_alg;
int installed; /* 1 if key has already been installed to driver */
bool installed_rx; /* whether TK has been installed as the next TK
@@ -495,7 +501,8 @@ 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, size_t kdk_len, u16 pasn_group);
+ const u8 *z, size_t z_len, size_t kdk_len, u16 pasn_group,
+ size_t smd_kdk_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);
@@ -874,7 +881,7 @@ int wpa_auth_802_1x_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa,
const u8 *aa, const u8 *snonce, const u8 *anonce,
int akmp, int cipher, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
- size_t kdk_len);
+ size_t kdk_len, size_t smd_kdk_len);
void wpa_add_supported_groups(struct wpabuf *buf, const int *groups);
/* Security Profile entry (IEEE P802.11bn/D2.0) */
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 5a05a991b9f9..c8f5d359af8b 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -792,7 +792,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
sm->own_addr, wpa_sm_get_auth_addr(sm), sm->snonce,
key->key_nonce, ptk, akmp,
sm->pairwise_cipher, z, z_len,
- kdk_len, sm->pasn_group);
+ kdk_len, sm->pasn_group, 0);
if (ret) {
wpa_printf(MSG_ERROR, "WPA: PTK derivation failed");
return ret;
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
index d0fbd8ad6163..57c5480a3db1 100644
--- a/wlantest/rx_eapol.c
+++ b/wlantest/rx_eapol.c
@@ -250,7 +250,7 @@ static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss,
aa, sa, sta->anonce,
sta->snonce, &ptk, sta->key_mgmt,
sta->pairwise_cipher, NULL, 0, kdk_len,
- PASN_GROUP_NOT_SPECIFIED) < 0 ||
+ PASN_GROUP_NOT_SPECIFIED, 0) < 0 ||
check_mic(sta, ptk.kck, ptk.kck_len, ver, data, len) < 0) {
return -1;
}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 1e4dc15dec1b..c107947033ee 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -4627,7 +4627,7 @@ static int sme_802_1x_derive_ptk_and_install(struct wpa_supplicant *wpa_s,
key_mgmt, pairwise_cipher,
wpabuf_head(auth_1x->dhss),
wpabuf_len(auth_1x->dhss),
- &ptk, kdk_len) < 0) {
+ &ptk, kdk_len, 0) < 0) {
wpa_msg(wpa_s, MSG_INFO, "SME: PTK derivation failed");
forced_memzero(pmk, PMK_LEN_MAX);
return -1;
--
2.55.0
More information about the Hostap
mailing list