[PATCH 06/20] AP: Reject first Authentication frame with mismatched security profile
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Wed Jun 10 06:11:59 PDT 2026
From: Ilan Peer <ilan.peer at intel.com>
In case security profile support is enabled and the first authentication
frame includes a security profile verify that:
- It contains a single security profile that is supported by the AP.
- The values in the RSN element and the extended RSN element match
the security profile
If the verification fails, reject the authentication with status code
REJECTED_INVALID_SECURITY_PROFILE.
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
src/ap/ieee802_11.c | 43 ++++++++++++-
src/ap/wpa_auth.h | 5 ++
src/ap/wpa_auth_ie.c | 148 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+), 2 deletions(-)
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index feebcbcd2a..e100dfa2f1 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -4087,9 +4087,8 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 trans_seq, u16 status)
{
- int ret;
-#ifdef CONFIG_P2P
struct ieee802_11_elems elems;
+ int ret;
if (len < 24) {
wpa_printf(MSG_DEBUG, "PASN: Too short Management frame");
@@ -4105,6 +4104,7 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
return;
}
+#ifdef CONFIG_P2P
if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) ==
(P2P_ENABLED | P2P_GROUP_OWNER) &&
hapd->p2p && elems.p2p2_ie && elems.p2p2_ie_len) {
@@ -4145,6 +4145,45 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
hapd_initialize_pasn(hapd, sta);
hapd_pasn_update_params(hapd, sta, mgmt, len);
+
+ /*
+ * When support for security profiles is enabled, need to
+ * verify that if the first authentication frame carries the
+ * necessary IEs, they are consistent and match exactly one of
+ * the supported security profiles.
+ */
+ if (hapd->conf->sec_profile_enabled) {
+ u16 secp_resp =
+ WLAN_STATUS_REJECTED_INVALID_SECURITY_PROFILE;
+
+ if (elems.security_profile) {
+ if (!elems.rsn_ie ||
+ !wpa_auth_validate_security_profile(
+ hapd->wpa_auth,
+ elems.rsn_ie - 2,
+ elems.rsn_ie_len + 2,
+ elems.rsnxe ?
+ elems.rsnxe - 2 : NULL,
+ elems.rsnxe ?
+ elems.rsnxe_len + 2 : 0,
+ elems.security_profile,
+ elems.security_profile_len)) {
+ wpa_printf(MSG_INFO,
+ "RSN: First Authentication frame from "
+ MACSTR
+ " does not match any advertised security profile",
+ MAC2STR(sta->addr));
+
+ send_auth_reply(hapd, sta, sta->addr,
+ mgmt->u.auth.auth_alg,
+ 2, secp_resp, NULL, 0,
+ "sec-profile-mismatch");
+ ap_free_sta(hapd, sta);
+ return;
+ }
+ }
+ }
+
ret = handle_auth_pasn_1(sta->pasn, hapd->own_addr, sta->addr,
mgmt, len, false);
wpabuf_free(sta->pasn->frame);
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 7efaff88f6..249e410caa 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -493,6 +493,11 @@ int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
int wpa_auth_uses_spp_amsdu(struct wpa_state_machine *sm);
void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv);
int wpa_auth_uses_ocv(struct wpa_state_machine *sm);
+bool wpa_auth_validate_security_profile(struct wpa_authenticator *wpa_auth,
+ const u8 *rsne, size_t rsne_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *secp_body,
+ size_t secp_body_len);
struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *p2p_dev_addr);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 50327b6d62..0a3e2cafc1 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -713,6 +713,154 @@ static u16 wpa_match_security_profiles(struct wpa_auth_config *conf)
return bitmap;
}
+
+/*
+ * wpa_auth_validate_security_profile - Validate Security Profile Element
+ *
+ * @wpa_auth: WPA authenticator context
+ * @rsne: Pointer to the RSN element
+ * @rsne_len: Length of the RSN element
+ * @rsnxe: Pointer to the RSNXE element
+ * @rsnxe_len: Length of the RSNXE element
+ * @secp_body: Pointer to the Security Profile element
+ * @secp_body_len: Length of the Security Profile element
+ * Returns: true on match, false on mismatch or error
+ */
+bool wpa_auth_validate_security_profile(struct wpa_authenticator *wpa_auth,
+ const u8 *rsne, size_t rsne_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *secp_body,
+ size_t secp_body_len)
+{
+ u16 profile_bitmap;
+ struct wpa_ie_data data;
+ const struct ieee80211_security_profile *p;
+ const u8 *bitmap;
+ size_t bitmap_octets, bit, bits = 0;
+ u8 match = 0xff;
+ bool mfp;
+
+ /* Sanity check */
+ if (!wpa_auth || !wpa_auth->conf.sec_profile_enabled)
+ return true;
+
+ if (!rsne || !secp_body)
+ return true;
+
+ if (wpa_parse_wpa_ie_rsn(rsne, rsne_len, &data) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Failed to parse RSNE in for security profile validation");
+ return false;
+ }
+
+ if (secp_body_len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Truncated Security Profile element");
+ return false;
+ }
+
+ bitmap_octets = (secp_body[1] &
+ SECURITY_PROFILE_IND_OCTETS_BITMAP_MASK) >>
+ SECURITY_PROFILE_IND_OCTETS_BITMAP_SHIFT;
+ if (!bitmap_octets || secp_body_len < 2 + bitmap_octets) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Invalid Security Profile bitmap length");
+ return false;
+ }
+
+ bitmap = &secp_body[2];
+ for (bit = 0; bit < bitmap_octets * 8; bit++) {
+ if (bitmap[bit / 8] & BIT(bit % 8)) {
+ match = bit;
+ bits++;
+ }
+ }
+ if (bits != 1 || match > SECURITY_PROFILE_MAX) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Security Profile element does not indicate exactly one profile (bits=%zu)",
+ bits);
+ return false;
+ }
+
+ profile_bitmap = wpa_match_security_profiles(&wpa_auth->conf);
+ if (!(profile_bitmap & BIT(match))) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Indicated security profile %u not advertised by AP",
+ match);
+ return false;
+ }
+ p = &g_security_profiles[match];
+
+ if ((data.key_mgmt & (p->akm & ~WPA_KEY_MGMT_EPPKE)) !=
+ (p->akm & ~WPA_KEY_MGMT_EPPKE) ||
+ (p->akm2 && (data.key_mgmt & p->akm2) != p->akm2)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSNE AKM 0x%x does not match security profile %u (akm=0x%x akm2=0x%x)",
+ data.key_mgmt, match, p->akm, p->akm2);
+ return false;
+ }
+
+ if ((data.pairwise_cipher & p->pairwise_cipher) !=
+ p->pairwise_cipher) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSNE pairwise cipher 0x%x does not match security profile %u (cipher=0x%x)",
+ data.pairwise_cipher, match, p->pairwise_cipher);
+ return false;
+ }
+
+ mfp = (data.capabilities & WPA_CAPABILITY_MFPC) != 0;
+ if (mfp != p->mfp) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSNE MFPC=%d does not match security profile %u (mfp=%d)",
+ mfp, match, p->mfp);
+ return false;
+ }
+
+ /* Validate RSNXE capabilities against the security profile */
+ if (p->assoc_frame_enc_and_pmksa_privacy !=
+ ieee802_11_rsnx_capab(rsnxe,
+ WLAN_RSNX_CAPAB_ASSOC_FRAME_ENCRYPTION)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSNXE assoc frame encryption=%d does not match security profile %u (%d)",
+ !p->assoc_frame_enc_and_pmksa_privacy,
+ match, p->assoc_frame_enc_and_pmksa_privacy);
+ return false;
+ }
+
+ if (p->assoc_frame_enc_and_pmksa_privacy !=
+ ieee802_11_rsnx_capab(rsnxe,
+ WLAN_RSNX_CAPAB_PMKSA_CACHING_PRIVACY)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSNXE PMKSA caching privacy=%d does not match security profile %u (%d)",
+ !p->assoc_frame_enc_and_pmksa_privacy,
+ match, p->assoc_frame_enc_and_pmksa_privacy);
+ return false;
+ }
+
+ if (p->kek_in_pasn !=
+ ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_KEK_IN_PASN)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSNXE KEK in PASN=%d does not match security profile %u (%d)",
+ !p->kek_in_pasn, match, p->kek_in_pasn);
+ return false;
+ }
+
+ if (p->dot1x_in_auth_frame !=
+ ieee802_11_rsnx_capab(rsnxe,
+ WLAN_RSNX_CAPAB_802_1X_IN_AUTH_FRAMES)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSNXE 802.1X in auth frames=%d does not match security profile %u (%d)",
+ !p->dot1x_in_auth_frame,
+ match, p->dot1x_in_auth_frame);
+ return false;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: Security profile %u validation successful",
+ match);
+ return true;
+}
+
+
/*
* wpa_write_security_profile - Write Security Profile element
*
--
2.53.0
More information about the Hostap
mailing list