[PATCH 12/20] wpa_supplicant: Include Security profile element in auth/assoc

Andrei Otcheretianski andrei.otcheretianski at intel.com
Wed Jun 10 06:12:05 PDT 2026


From: Ilan Peer <ilan.peer at intel.com>

When connecting to an AP that advertises a security profile element,
and the WPA SM was configured with a matching security profile ID,
build a local Security Profile element advertising the chosen profile
ID and include it in:

- The first Authentication frame, when that frame carries an RSNE
  (i.e., EPPKE Authentication frame 1);
- The (Re)Association Request frame.

For PASN, since the Security Profile Element is expected only in the
1st authentication frame, extend pasn_set_extra_ies() to also clear
the content of the PASN extra elements.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/pasn/pasn_common.c          |  6 ++-
 src/rsn_supp/wpa.c              | 66 +++++++++++++++++++++++++++++++++
 src/rsn_supp/wpa.h              |  7 ++++
 wpa_supplicant/sme.c            | 41 ++++++++++++++++++++
 wpa_supplicant/wpa_supplicant.c | 11 ++++++
 5 files changed, 130 insertions(+), 1 deletion(-)

diff --git a/src/pasn/pasn_common.c b/src/pasn/pasn_common.c
index ab9e551bb8..d7359e66f0 100644
--- a/src/pasn/pasn_common.c
+++ b/src/pasn/pasn_common.c
@@ -214,14 +214,18 @@ void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid)
 int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies,
 		       size_t extra_ies_len)
 {
-	if (!pasn || !extra_ies_len || !extra_ies)
+	if (!pasn)
 		return -1;
 
 	if (pasn->extra_ies) {
 		os_free((u8 *) pasn->extra_ies);
+		pasn->extra_ies = NULL;
 		pasn->extra_ies_len = 0;
 	}
 
+	if (!extra_ies_len || !extra_ies)
+		return 0;
+
 	pasn->extra_ies = os_memdup(extra_ies, extra_ies_len);
 	if (!pasn->extra_ies) {
 		wpa_printf(MSG_ERROR,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 929c064038..0d8531f823 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -5850,6 +5850,72 @@ void wpa_sm_set_matched_security_profile(struct wpa_sm *sm, int profile)
 }
 
 
+/*
+ * wpa_sm_build_security_profile - Build Security Profile element
+ *
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @buf: Buffer for building the Security Profile element
+ * @len: Length of the buf buffer
+ * Returns: Number of bytes written to buf, or 0 if no Security Profile
+ * element should be sent
+ *
+ * Build a Security Profile element advertising the single profile from
+ * the current WPA SM configuration and is also advertised by the AP.
+ */
+int wpa_sm_build_security_profile(struct wpa_sm *sm, u8 *buf, size_t len)
+{
+	int match, out_octets;
+	size_t elen;
+	u8 reduced_rsn_capab = 0;
+	u8 *pos;
+
+	if (!sm || !buf)
+		return 0;
+
+	if (!sm->ap_security_profile || sm->ap_security_profile_len < 2)
+		return 0;
+
+	match = sm->matched_sec_profile;
+	if (match < 0)
+		return 0;
+
+	if (sm->ext_key_id)
+		reduced_rsn_capab |=
+			SECURITY_PROFILE_REDUCED_RSN_CAPAB_EXT_KEY_ID;
+#ifdef CONFIG_OCV
+	if (sm->ocv)
+		reduced_rsn_capab |= SECURITY_PROFILE_REDUCED_RSN_CAPAB_OCVC;
+#endif /* CONFIG_OCV */
+
+	out_octets = (match / 8) + 1;
+
+	/*
+	 * Element ID + Length + Element ID Extension +
+	 * Reduced RSN Capabilities + Security Profile Indication +
+	 * Security Profile Bitmap.
+	 */
+	elen = 1 + 1 + 1 + 1 + 1 + out_octets;
+	if (len < elen)
+		return 0;
+
+	pos = buf;
+	*pos++ = WLAN_EID_EXTENSION;
+	*pos++ = elen - 2;
+	*pos++ = WLAN_EID_EXT_SECURITY_PROFILE;
+	*pos++ = reduced_rsn_capab;
+	*pos++ = (out_octets << SECURITY_PROFILE_IND_OCTETS_BITMAP_SHIFT) &
+		SECURITY_PROFILE_IND_OCTETS_BITMAP_MASK;
+
+	os_memset(pos, 0, out_octets);
+	pos[match / 8] |= BIT(match % 8);
+	pos += out_octets;
+
+	wpa_hexdump(MSG_DEBUG,
+		    "RSN: Built local Security Profile element", buf, elen);
+	return elen;
+}
+
+
 /**
  * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index ce657b5d58..3adfb2b79d 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -226,6 +226,7 @@ int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie, size_t len);
 int wpa_sm_set_ap_rsne_override_2(struct wpa_sm *sm, const u8 *ie, size_t len);
 int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie, size_t len);
 int wpa_sm_set_ap_security_profile(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_build_security_profile(struct wpa_sm *sm, u8 *buf, size_t len);
 void wpa_sm_set_matched_security_profile(struct wpa_sm *sm, int profile);
 int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
 
@@ -411,6 +412,12 @@ static inline int wpa_sm_set_ap_security_profile(struct wpa_sm *sm,
 	return -1;
 }
 
+static inline int wpa_sm_build_security_profile(struct wpa_sm *sm, u8 *buf,
+						size_t len)
+{
+	return 0;
+}
+
 static inline void wpa_sm_set_matched_security_profile(struct wpa_sm *sm,
 						       int profile)
 {
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 0ab66e760c..e3be8c3c15 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -972,6 +972,8 @@ static int wpas_eppke_initialize(struct wpa_supplicant *wpa_s,
 	u8 rsne[80];
 	size_t rsne_len = sizeof(rsne);
 	int len;
+	u8 secp[20];
+	size_t secp_len;
 
 	pasn = &wpa_s->pasn;
 
@@ -1166,6 +1168,24 @@ static int wpas_eppke_initialize(struct wpa_supplicant *wpa_s,
 	pasn_set_rsne(pasn, rsne);
 	wpa_hexdump(MSG_DEBUG, "EPPKE: Set own RSNE default",
 		    pasn->rsn_ie, pasn->rsn_ie_len);
+
+	/*
+	 * Include the matching Security Profile element in the first EPPKE
+	 * Authentication frame. Pass it via PASN extra_ies so that it is part
+	 * of the stored auth1 frame used for the auth-3 MIC computation.
+	 * The extra_ies are cleared after building auth1 to avoid including
+	 * this element in auth frame 3.
+	 */
+	secp_len = wpa_sm_build_security_profile(wpa_s->wpa, secp,
+						 sizeof(secp));
+	if (secp_len) {
+		if (pasn_set_extra_ies(pasn, secp, secp_len) < 0) {
+			wpa_printf(MSG_INFO,
+				   "EPPKE: Failed to set Security Profile element");
+			goto fail;
+		}
+	}
+
 	pasn->akmp = wpa_s->key_mgmt;
 	pasn->cipher = wpa_s->pairwise_cipher;
 	pasn->group = group;
@@ -1221,6 +1241,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_MBO */
 	int omit_rsnxe = 0;
 	unsigned int keys_to_clear = 0;
+	u8 secp[20];
+	size_t secp_len;
 
 	if (bss == NULL) {
 		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -1640,6 +1662,18 @@ skip_setup:
 		wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
 	}
 
+	secp_len = wpa_sm_build_security_profile(wpa_s->wpa, secp,
+						 sizeof(secp));
+	if (secp_len &&
+	    secp_len <= sizeof(wpa_s->sme.assoc_req_ie) -
+	    wpa_s->sme.assoc_req_ie_len) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"RSN: Add Security Profile element to (Re)Association Request frame");
+		os_memcpy(wpa_s->sme.assoc_req_ie +
+			  wpa_s->sme.assoc_req_ie_len, secp, secp_len);
+		wpa_s->sme.assoc_req_ie_len += secp_len;
+	}
+
 	if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION &&
 	    wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_KNOWN_STA_IDENTIFICATION)) {
 		struct wpabuf *e;
@@ -1723,6 +1757,13 @@ skip_setup:
 
 			resp = wpas_pasn_build_auth_1(&wpa_s->pasn, NULL,
 						      false, 0);
+
+			/*
+			 * Clear extra_ies after auth1 is built so that
+			 * the Security Profile element is not included
+			 * in auth frame 3.
+			 */
+			pasn_set_extra_ies(&wpa_s->pasn, NULL, 0);
 		} else {
 			resp = wpas_pasn_build_auth_3(&wpa_s->pasn, 0);
 		}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 2181015453..043411707c 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3815,6 +3815,8 @@ static u8 * wpas_populate_assoc_ies(
 	size_t max_wpa_ie_len = 500;
 	size_t wpa_ie_len;
 	int algs = WPA_AUTH_ALG_OPEN;
+	u8 secp[20];
+	size_t secp_len;
 #ifdef CONFIG_MBO
 	const u8 *mbo_ie;
 #endif
@@ -4269,6 +4271,15 @@ pfs_fail:
 		wpa_ie_len += wpa_s->rsnxe_len;
 	}
 
+	secp_len = wpa_sm_build_security_profile(wpa_s->wpa, secp,
+						 sizeof(secp));
+	if (secp_len && secp_len <= max_wpa_ie_len - wpa_ie_len) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"RSN: Add Security Profile element to (Re)Association Request frame");
+		os_memcpy(wpa_ie + wpa_ie_len, secp, secp_len);
+		wpa_ie_len += secp_len;
+	}
+
 #ifndef CONFIG_NO_ROBUST_AV
 #ifdef CONFIG_TESTING_OPTIONS
 	if (wpa_s->disable_mscs_support)
-- 
2.53.0




More information about the Hostap mailing list