[PATCH 25/29] EPPKE: Update RSNE construction and validation per IEEE P802.11bi/D2.0
Sai Pratyusha Magam
smagam at qti.qualcomm.com
Thu Dec 11 05:14:39 PST 2025
From: Ainy Kumari <ainy.kumari at oss.qualcomm.com>
Update existing PASN APIs for RSNE generation and validation logic to
align with IEEE 802.11bi/D2.0, section 12.16.9.3.2 to support EPPKE
authentication.
Below are the key changes:
- Add wpa_pick_group_mgmt_cipher() to select group management cipher.
- Extend wpa_pasn_add_rsne() and wpa_pasn_validate_rsne() to support
Group Data and Group Management Cipher Suites inclusion for EPPKE.
- Pass group cipher parameters in PASN initiator/responder mode.
- Skip MFPR bit setting in RSN Capabilities for EPPKE.
- Ensure RSNE reflects correct capabilities and cipher suites based
on auth type
Signed-off-by: Sai Pratyusha Magam <smagam at qti.qualcomm.com>
Signed-off-by: Ainy Kumari <ainy.kumari at oss.qualcomm.com>
---
src/ap/ieee802_11.c | 2 +-
src/common/wpa_common.c | 70 +++++++++++++++++++++++++++++----------
src/common/wpa_common.h | 7 ++--
src/pasn/pasn_common.h | 2 ++
src/pasn/pasn_initiator.c | 14 +++++---
src/pasn/pasn_responder.c | 22 ++++++++----
wpa_supplicant/sme.c | 7 ++++
7 files changed, 93 insertions(+), 31 deletions(-)
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index df7ec8270..545a6b7bf 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2920,7 +2920,7 @@ static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
return -1;
}
- ret = wpa_pasn_validate_rsne(&rsne_data);
+ ret = wpa_pasn_validate_rsne(&rsne_data, false);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
return -1;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 29cd21515..9a8064d6b 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -3348,6 +3348,20 @@ int wpa_pick_group_cipher(int ciphers)
}
+int wpa_pick_group_mgmt_cipher(int ciphers)
+{
+ if (ciphers & WPA_CIPHER_AES_128_CMAC)
+ return WPA_CIPHER_AES_128_CMAC;
+ if (ciphers & WPA_CIPHER_BIP_GMAC_128)
+ return WPA_CIPHER_BIP_GMAC_128;
+ if (ciphers & WPA_CIPHER_BIP_GMAC_256)
+ return WPA_CIPHER_BIP_GMAC_256;
+ if (ciphers & WPA_CIPHER_BIP_CMAC_256)
+ return WPA_CIPHER_BIP_CMAC_256;
+ return -1;
+}
+
+
int wpa_parse_cipher(const char *value)
{
int val = 0, last;
@@ -4023,13 +4037,15 @@ void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
/*
- * wpa_pasn_add_rsne - Add an RSNE for PASN authentication
+ * wpa_pasn_add_rsne - Add an RSNE for PASN/EPPKE authentication
* @buf: Buffer in which the IE will be added
* @pmkid: Optional PMKID. Can be NULL.
* @akmp: Authentication and key management protocol
* @cipher: The cipher suite
+ * @is_eppke: EPPKE Authentication
*/
-int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher,
+ bool is_eppke, int group_cipher, int group_mgmt_cipher)
{
struct rsn_ie_hdr *hdr;
u32 suite;
@@ -4051,8 +4067,13 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
- /* Group addressed data is not allowed */
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ if (is_eppke) {
+ /* EPPKE: Group addressed data is allowed */
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher));
+ } else {
+ /* PASN: Group addressed data is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ }
pos += RSN_SELECTOR_LEN;
/* Add the pairwise cipher */
@@ -4103,8 +4124,13 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
}
pos += RSN_SELECTOR_LEN;
- /* RSN Capabilities: PASN mandates both MFP capable and required */
- capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+ if (is_eppke) {
+ /* RSN Capabilities: EPPKE does not mandate setting MFPR to 1 */
+ capab = WPA_CAPABILITY_MFPC;
+ } else {
+ /* RSN Capabilities: PASN mandates both MFP capable and required */
+ capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+ }
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -4120,9 +4146,13 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
pos += 2;
}
- /* Group addressed management is not allowed */
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
-
+ if (is_eppke) {
+ /* EPPKE: Group addressed management is allowed */
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, group_mgmt_cipher));
+ } else {
+ /* PASN: Group addressed management is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ }
return 0;
}
@@ -4260,23 +4290,29 @@ int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
/*
- * wpa_pasn_validate_rsne - Validate PSAN specific data of RSNE
+ * wpa_pasn_validate_rsne - Validate PASN/EPPKE specific data of RSNE
* @data: Parsed representation of an RSNE
+ * @is_eppke: EPPKE Authentication
* Returns -1 for invalid data; otherwise 0
*/
-int wpa_pasn_validate_rsne(const struct wpa_ie_data *data)
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data, bool is_eppke)
{
- u16 capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+ u16 capab = WPA_CAPABILITY_MFPC;
+
+ if (!is_eppke)
+ capab |= WPA_CAPABILITY_MFPR;
if (data->proto != WPA_PROTO_RSN)
return -1;
if ((data->capabilities & capab) != capab) {
- wpa_printf(MSG_DEBUG, "PASN: Invalid RSNE capabilities");
+ wpa_printf(MSG_DEBUG, "%s: Invalid RSNE capabilities",
+ is_eppke ? "EPPKE" : "PASN");
return -1;
}
- if (!data->has_group || data->group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ if (!data->has_group ||
+ (!is_eppke && data->group_cipher != WPA_CIPHER_GTK_NOT_USED)) {
wpa_printf(MSG_DEBUG, "PASN: Invalid group data cipher");
return -1;
}
@@ -4307,12 +4343,12 @@ int wpa_pasn_validate_rsne(const struct wpa_ie_data *data)
case WPA_KEY_MGMT_PASN:
break;
default:
- wpa_printf(MSG_ERROR, "PASN: invalid key_mgmt: 0x%0x",
- data->key_mgmt);
+ wpa_printf(MSG_ERROR, "%s: invalid key_mgmt: 0x%0x",
+ is_eppke ? "EPPKE" : "PASN", data->key_mgmt);
return -1;
}
- if (data->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ if (!is_eppke && (data->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED)) {
wpa_printf(MSG_DEBUG, "PASN: Invalid group mgmt cipher");
return -1;
}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index ad3c017ec..3739f94f8 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -761,6 +761,7 @@ int rsn_cipher_put_suites(u8 *pos, int ciphers);
int wpa_cipher_put_suites(u8 *pos, int ciphers);
int wpa_pick_pairwise_cipher(int ciphers, int none_allowed);
int wpa_pick_group_cipher(int ciphers);
+int wpa_pick_group_mgmt_cipher(int ciphers);
int wpa_parse_cipher(const char *value);
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
@@ -793,8 +794,8 @@ void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
const u8 *src, const u8 *dst,
u8 trans_seq, u16 status, bool is_eppke);
-int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid,
- int akmp, int cipher);
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher,
+ bool is_eppke, int group_cipher, int group_mgmt_cipher);
void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
u8 wrapped_data_format,
@@ -804,7 +805,7 @@ void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
struct wpabuf *wrapped_data_buf);
-int wpa_pasn_validate_rsne(const struct wpa_ie_data *data);
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data, bool is_eppke);
int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
struct wpa_pasn_params_data *pasn_params);
diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h
index 4d35bffd0..d75255709 100644
--- a/src/pasn/pasn_common.h
+++ b/src/pasn/pasn_common.h
@@ -55,6 +55,8 @@ struct pasn_data {
u8 mld_addr[ETH_ALEN];
bool is_ml_sta;
u32 hash_alg;
+ int group_cipher;
+ int group_mgmt_cipher;
#ifdef CONFIG_SAE
struct sae_pt *pt;
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index 32daf9c05..4ce5f6549 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -296,7 +296,9 @@ static struct wpabuf * wpas_pasn_fils_build_auth(struct pasn_data *pasn)
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
/* Own RSNE */
- wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher,
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn->group_cipher, pasn->group_mgmt_cipher);
/* FILS Nonce */
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
@@ -422,7 +424,8 @@ static int wpas_pasn_wd_fils_rx(struct pasn_data *pasn, struct wpabuf *wd)
return -1;
}
- ret = wpa_pasn_validate_rsne(&rsne_data);
+ ret = wpa_pasn_validate_rsne(&rsne_data,
+ pasn->auth_alg == WLAN_AUTH_EPPKE);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
return -1;
@@ -645,7 +648,9 @@ struct wpabuf *wpas_pasn_build_auth_1(struct pasn_data *pasn,
wrapped_data_buf = wpas_pasn_get_wrapped_data(pasn);
}
- if (wpa_pasn_add_rsne(buf, pmkid, pasn->akmp, pasn->cipher) < 0)
+ if (wpa_pasn_add_rsne(buf, pmkid, pasn->akmp, pasn->cipher,
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn->group_cipher, pasn->group_mgmt_cipher) < 0)
goto fail;
if (!wrapped_data_buf)
@@ -1261,7 +1266,8 @@ int wpas_parse_pasn_frame(struct pasn_data *pasn, u16 auth_type,
goto fail;
}
- ret = wpa_pasn_validate_rsne(&rsn_data);
+ ret = wpa_pasn_validate_rsne(&rsn_data,
+ pasn->auth_alg == WLAN_AUTH_EPPKE);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
goto fail;
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index b4dea5ee5..0b7426c7e 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -303,7 +303,9 @@ static struct wpabuf * pasn_get_fils_wd(struct pasn_data *pasn)
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
/* Own RSNE */
- wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher,
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn->group_cipher, pasn->group_mgmt_cipher);
/* FILS Nonce */
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
@@ -558,8 +560,9 @@ int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr,
#endif /* CONFIG_FILS */
}
- if (wpa_pasn_add_rsne(buf, pmkid,
- pasn->akmp, pasn->cipher) < 0)
+ if (wpa_pasn_add_rsne(buf, pmkid, pasn->akmp, pasn->cipher,
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn->group_cipher, pasn->group_mgmt_cipher) < 0)
goto fail;
/* No need to derive PMK if PMKSA is given */
@@ -636,8 +639,10 @@ int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr,
if (!rsn_buf)
goto fail;
- if (wpa_pasn_add_rsne(rsn_buf, pmkid,
- pasn->akmp, pasn->cipher) < 0)
+ if (wpa_pasn_add_rsne(rsn_buf, pmkid, pasn->akmp, pasn->cipher,
+ pasn->auth_alg == WLAN_AUTH_EPPKE,
+ pasn->group_cipher,
+ pasn->group_mgmt_cipher) < 0)
goto fail;
rsn_ie = wpabuf_head_u8(rsn_buf);
@@ -762,7 +767,8 @@ int handle_auth_pasn_1(struct pasn_data *pasn,
goto send_resp;
}
- ret = wpa_pasn_validate_rsne(&rsn_data);
+ ret = wpa_pasn_validate_rsne(&rsn_data,
+ pasn->auth_alg == WLAN_AUTH_EPPKE);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
status = WLAN_STATUS_INVALID_RSNIE;
@@ -790,6 +796,10 @@ int handle_auth_pasn_1(struct pasn_data *pasn,
pasn->akmp = rsn_data.key_mgmt;
pasn->cipher = rsn_data.pairwise_cipher;
+#ifdef CONFIG_ENC_ASSOC
+ pasn->group_cipher = rsn_data.group_cipher;
+ pasn->group_mgmt_cipher = rsn_data.mgmt_group_cipher;
+#endif /* CONFIG_ENC_ASSOC */
if (pasn->derive_kdk &&
ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index fa81d6f96..1187484ef 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -631,6 +631,7 @@ static void wpas_eppke_initialize(struct wpa_supplicant *wpa_s, struct wpa_bss *
u8 beacon_rsne_len, beacon_rsnxe_len;
u32 capab = 0;
int group;
+ int group_mgmt_cipher;
pasn = &wpa_s->pasn;
@@ -710,6 +711,12 @@ static void wpas_eppke_initialize(struct wpa_supplicant *wpa_s, struct wpa_bss *
}
pasn->akmp = wpa_s->key_mgmt;
pasn->cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 1);
+ pasn->group_cipher = wpa_pick_group_cipher(ssid->group_cipher);
+ if (ssid->group_mgmt_cipher != 0)
+ group_mgmt_cipher = ssid->group_mgmt_cipher;
+ else
+ group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
+ pasn->group_mgmt_cipher = wpa_pick_group_mgmt_cipher(group_mgmt_cipher);
pasn->group = group;
pasn->freq = bss->freq;
pasn->auth_alg = WLAN_AUTH_EPPKE;
--
2.34.1
More information about the Hostap
mailing list