[RFC 20/30] PASN: Extend PTK derivation to support SMD
Ilan Peer
ilan.peer at intel.com
Wed Oct 21 06:43:38 PDT 2026
Extend the PASN PMK to PTK derivation to also support
SMD:
- Include SMD Identifier in the PTK derivation.
- Derive SMD_KDK when needed (for per-AP MLD SMD mode).
The changes include changes in the PASN library and also
in station SME and AP SME.
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
src/ap/ieee802_11.c | 4 +++-
src/common/common_module_tests.c | 3 ++-
src/common/wpa_common.c | 24 ++++++++++++++++++++----
src/common/wpa_common.h | 2 +-
src/pasn/pasn_common.h | 13 +++++++++++++
src/pasn/pasn_initiator.c | 4 +++-
src/pasn/pasn_responder.c | 4 +++-
src/rsn_supp/wpa.c | 7 +++++--
src/rsn_supp/wpa.h | 1 +
wpa_supplicant/sme.c | 4 ++++
10 files changed, 55 insertions(+), 11 deletions(-)
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 4dce610ee6f1..608eee822271 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -4779,7 +4779,9 @@ static void pasn_fils_auth_resp(struct hostapd_data *hapd,
pasn_get_ptk(sta->pasn), pasn_get_akmp(sta->pasn),
pasn_get_cipher(sta->pasn), sta->pasn->kdk_len,
sta->pasn->kek_len, &sta->pasn->hash_alg,
- pasn->auth_alg == WLAN_AUTH_EPPKE);
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn_get_smd_id(sta->pasn),
+ pasn_derive_smd_kdk(sta->pasn) ? pmk_len : 0);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
goto fail;
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 49beaecdbe0d..f24be70163ad 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -655,7 +655,8 @@ static int pasn_test_pasn_auth(void)
spa_addr, bssid,
dhss, sizeof(dhss),
&ptk, WPA_KEY_MGMT_PASN, WPA_CIPHER_CCMP,
- WPA_KDK_MAX_LEN, 0, &hash_alg, false);
+ WPA_KDK_MAX_LEN, 0, &hash_alg, false,
+ NULL, 0);
if (ret)
return ret;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 617278faf931..6ccc781d8e66 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1755,6 +1755,9 @@ static enum rsn_hash_alg pasn_select_hash_alg(int akmp, int cipher,
* @kek_len: The length in octets that should be derived for KEK. Can be zero.
* @alg: Output variable for indicating the selected hash algorithm
* @is_eppke: EPPKE authentication
+ * @smd_id: The SMD ID for EPPKE authentication. Can be NULL
+ * @smd_kdk_len: The length in octets that should be derived for SMD KDK.
+ * Can be zero
* Returns: 0 on success, -1 on failure
*/
int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
@@ -1762,10 +1765,10 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
const u8 *dhss, size_t dhss_len,
struct wpa_ptk *ptk, int akmp, int cipher,
size_t kdk_len, size_t kek_len, enum rsn_hash_alg *alg,
- bool is_eppke)
+ bool is_eppke, const u8 *smd_id, size_t smd_kdk_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];
const u8 *pos;
u8 *data;
size_t data_len, ptk_len;
@@ -1796,7 +1799,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
* TK = L(PASN-PTK, 256, TK_bits)
* KDK = L(PASN-PTK, 256 + TK_bits, kdk_len * 8)
*/
- data_len = 2 * ETH_ALEN + dhss_len;
+ data_len = 2 * ETH_ALEN + dhss_len + (smd_id ? ETH_ALEN : 0);
data = os_zalloc(data_len);
if (!data)
return -1;
@@ -1804,10 +1807,13 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
os_memcpy(data, spa, ETH_ALEN);
os_memcpy(data + ETH_ALEN, bssid, ETH_ALEN);
os_memcpy(data + 2 * ETH_ALEN, dhss, dhss_len);
+ if (smd_id)
+ os_memcpy(data + 2 * ETH_ALEN + dhss_len, smd_id, ETH_ALEN);
ptk->kck_len = WPA_PASN_KCK_LEN;
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk->kdk_len = kdk_len;
+ ptk->smd_kdk_len = smd_kdk_len;
ptk->kek_len = kek_len;
ptk->kek2_len = 0;
ptk->kck2_len = 0;
@@ -1819,7 +1825,8 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
goto err;
}
- ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len + ptk->kek_len;
+ ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len +
+ ptk->smd_kdk_len + ptk->kek_len;
if (ptk_len > sizeof(tmp))
goto err;
@@ -1862,6 +1869,8 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
MAC2STR(spa), MAC2STR(bssid));
wpa_hexdump_key(MSG_DEBUG, "PASN: DHss", dhss, dhss_len);
+ if (smd_id)
+ wpa_hexdump_key(MSG_DEBUG, "PASN: SMD ID", smd_id, ETH_ALEN);
wpa_hexdump_key(MSG_DEBUG, "PASN: PMK", pmk, pmk_len);
wpa_hexdump_key(MSG_DEBUG, "PASN: PASN-PTK", tmp, ptk_len);
@@ -1884,6 +1893,13 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
os_memcpy(ptk->kdk, pos, ptk->kdk_len);
wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:",
ptk->kdk, ptk->kdk_len);
+ pos += ptk->kdk_len;
+ }
+
+ if (smd_kdk_len) {
+ os_memcpy(ptk->smd_kdk, pos, ptk->smd_kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: SMD KDK:",
+ ptk->smd_kdk, ptk->smd_kdk_len);
}
ptk->ptk_len = ptk_len;
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 6ade8f047058..c3a3c6b06c3b 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -853,7 +853,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
const u8 *dhss, size_t dhss_len,
struct wpa_ptk *ptk, int akmp, int cipher,
size_t kdk_len, size_t kek_len, enum rsn_hash_alg *alg,
- bool is_eppke);
+ bool is_eppke, const u8 *smd_id, size_t smd_kdk_len);
size_t pasn_mic_len(enum rsn_hash_alg alg);
diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h
index bdeef7c7b9a0..59f07bf3e7f7 100644
--- a/src/pasn/pasn_common.h
+++ b/src/pasn/pasn_common.h
@@ -181,6 +181,8 @@ struct pasn_data {
bool authorized;
bool tk_configured;
#endif /* CONFIG_ENC_ASSOC */
+ const u8 *smd_id;
+ bool derive_smd_kdk;
#ifdef CONFIG_PMKSA_PRIVACY
bool pmksa_caching_privacy;
u8 epp_pmkid_cur[PMKID_LEN];
@@ -369,6 +371,17 @@ int pasn_get_cipher(struct pasn_data *pasn);
size_t pasn_get_pmk_len(struct pasn_data *pasn);
u8 * pasn_get_pmk(struct pasn_data *pasn);
struct wpa_ptk * pasn_get_ptk(struct pasn_data *pasn);
+
+static inline const u8 * pasn_get_smd_id(struct pasn_data *pasn)
+{
+ return pasn->smd_id;
+}
+
+static inline bool pasn_derive_smd_kdk(struct pasn_data *pasn)
+{
+ return pasn->derive_smd_kdk;
+}
+
int pasn_add_encrypted_data(struct pasn_data *pasn, struct wpabuf *buf,
const u8 *data, size_t data_len);
int pasn_parse_encrypted_data(struct pasn_data *pasn, const u8 *data,
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index 18a109b51280..5e4f4b9470a1 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -1563,7 +1563,9 @@ int wpas_parse_pasn_frame(struct pasn_data *pasn, u16 auth_type,
wpabuf_head(secret), wpabuf_len(secret),
&pasn->ptk, pasn->akmp, pasn->cipher,
pasn->kdk_len, pasn->kek_len, &pasn->hash_alg,
- pasn->auth_alg == WLAN_AUTH_EPPKE);
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn_get_smd_id(pasn),
+ pasn_derive_smd_kdk(pasn) ? pasn->pmk_len : 0);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
goto fail;
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index 1ef066953ef3..e8e1a67ad528 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -501,7 +501,9 @@ pasn_derive_keys(struct pasn_data *pasn,
&pasn->ptk, pasn->akmp,
pasn->cipher, pasn->kdk_len, pasn->kek_len,
&pasn->hash_alg,
- pasn->auth_alg == WLAN_AUTH_EPPKE);
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn_get_smd_id(pasn),
+ pasn_derive_smd_kdk(pasn) ? pmk_len : 0);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
return -1;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 5c032e0c5819..b104869a404b 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -749,10 +749,13 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
}
-static bool wpa_sm_is_smd_per_ap_mld_ptk(struct wpa_sm *sm)
+bool wpa_sm_is_smd_per_ap_mld_ptk(struct wpa_sm *sm)
{
const struct ieee80211_smd_info *smd;
+ if (!sm)
+ return false;
+
if (!sm->smd || !sm->ap_smd_info)
return false;
@@ -6142,7 +6145,7 @@ const u8 * wpa_sm_get_smd_id(struct wpa_sm *sm)
size_t wpa_sm_get_smd_kdk_len(struct wpa_sm *sm, size_t pmk_len)
{
- if (!sm || !wpa_sm_is_smd_per_ap_mld_ptk(sm))
+ if (!wpa_sm_is_smd_per_ap_mld_ptk(sm))
return 0;
return pmk_len;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index c476af9a6e17..80d6b1814360 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -236,6 +236,7 @@ int wpa_sm_set_ap_security_profile(struct wpa_sm *sm, const u8 *elem,
int wpa_sm_set_ap_smd_info(struct wpa_sm *sm, const u8 *ie);
const u8 * wpa_sm_get_smd_id(struct wpa_sm *sm);
size_t wpa_sm_get_smd_kdk_len(struct wpa_sm *sm, size_t pmk_len);
+bool wpa_sm_is_smd_per_ap_mld_ptk(struct wpa_sm *sm);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 26f76cc82a5a..dbb291b6583a 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1773,6 +1773,10 @@ static int wpas_eppke_initialize(struct wpa_supplicant *wpa_s,
pasn->group = group;
pasn->freq = bss->freq;
pasn->auth_alg = WLAN_AUTH_EPPKE;
+#ifdef CONFIG_SMD
+ pasn->smd_id = wpa_sm_get_smd_id(wpa_s->wpa);
+ pasn->derive_smd_kdk = wpa_sm_is_smd_per_ap_mld_ptk(wpa_s->wpa);
+#endif /* CONFIG_SMD */
os_memcpy(pasn->own_addr, wpa_s->own_addr, ETH_ALEN);
if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
--
2.55.0
More information about the Hostap
mailing list