[PATCH 1/1] hostapd: Add support for SAE offload for AP interface

Vinayak Yadawad vinayak.yadawad at broadcom.com
Fri Nov 10 06:23:06 PST 2023


Driver/Firmware advertising SAE AP offload support would take
care of SAE authentication and PMK generation at driver/firmware.
This feature requires the driver to be supporting 4way handshake
offload to process the generated PMK at the driver level for 4way
handshake.

Signed-off-by: Vinayak Yadawad <vinayak.yadawad at broadcom.com>
---
 src/ap/beacon.c                   | 27 +++++++++++++++++++++++++++
 src/ap/ieee802_11.c               |  6 +++---
 src/ap/ieee802_11.h               | 10 +++++++++-
 src/ap/wpa_auth.h                 |  1 +
 src/ap/wpa_auth_glue.c            | 15 +++++++++++++++
 src/ap/wpa_auth_ie.c              | 29 ++++++++++++++++++++++++-----
 src/drivers/driver.h              |  6 ++++++
 src/drivers/driver_nl80211.c      |  6 ++++++
 src/drivers/driver_nl80211_capa.c |  4 ++++
 9 files changed, 95 insertions(+), 9 deletions(-)

diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index b88aeb03c..6d775f597 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2026,6 +2026,33 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
 #endif /* NEED_AP_MLME */
 
+#ifdef CONFIG_SAE
+	/* If SAE offload is enabled, provide passphrase to lower layer for
+	 * PMK generation
+	 */
+	if ((wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) &&
+	    (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
+		if (hostapd_sae_pk_in_use(hapd->conf)) {
+			wpa_printf(MSG_ERROR,
+				"sae_pk not supported with SAE offload");
+			return -1;
+		}
+
+		if (hostapd_sae_pw_id_in_use(hapd->conf)) {
+			wpa_printf(MSG_ERROR,
+				"sae pw_id not supported with SAE offlaod");
+			return -1;
+		}
+
+		params->sae_password = sae_get_password(hapd, NULL, NULL, NULL,
+			NULL, NULL);
+		if (!params->sae_password) {
+			wpa_printf(MSG_ERROR, "sae password not configured");
+			return -1;
+		}
+	}
+#endif /* CONFIG_SAE */
+
 	params->head = (u8 *) head;
 	params->head_len = head_len;
 	params->tail = tail;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index d48185a17..73c4a1106 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -540,7 +540,7 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
 }
 
 
-static const char * sae_get_password(struct hostapd_data *hapd,
+const char * sae_get_password(struct hostapd_data *hapd,
 				     struct sta_info *sta,
 				     const char *rx_id,
 				     struct sae_password_entry **pw_entry,
@@ -554,7 +554,7 @@ static const char * sae_get_password(struct hostapd_data *hapd,
 	struct hostapd_sta_wpa_psk_short *psk = NULL;
 
 	for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
-		if (!is_broadcast_ether_addr(pw->peer_addr) &&
+		if (!is_broadcast_ether_addr(pw->peer_addr) && sta &&
 		    os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
 			continue;
 		if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
@@ -573,7 +573,7 @@ static const char * sae_get_password(struct hostapd_data *hapd,
 		pt = hapd->conf->ssid.pt;
 	}
 
-	if (!password) {
+	if (!password && sta) {
 		for (psk = sta->psk; psk; psk = psk->next) {
 			if (psk->is_passphrase) {
 				password = psk->passphrase;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 8ffce0bf5..8f81c6e7d 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -20,6 +20,9 @@ struct radius_sta;
 enum ieee80211_op_mode;
 enum oper_chan_width;
 struct ieee802_11_elems;
+struct sae_pk;
+struct sae_pt;
+struct sae_password_entry;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 		    struct hostapd_frame_info *fi);
@@ -238,5 +241,10 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
 void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
 			    enum oper_chan_width *width, u8 *seg0, u8 *seg1);
 bool hostapd_is_mld_ap(struct hostapd_data *hapd);
-
+#ifdef CONFIG_SAE
+const char * sae_get_password(struct hostapd_data *hapd,
+			struct sta_info *sta, const char *rx_id,
+            struct sae_password_entry **pw_entry,
+            struct sae_pt **s_pt, const struct sae_pk **s_pk);
+#endif /* CONFIG_SAE */
 #endif /* IEEE802_11_H */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 28eea83d8..d6ed6772b 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -395,6 +395,7 @@ struct wpa_auth_callbacks {
 	int (*get_ml_rsn_info)(void *ctx, struct wpa_auth_ml_rsn_info *info);
 	int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info);
 #endif /* CONFIG_IEEE80211BE */
+	int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
 };
 
 struct wpa_authenticator * wpa_init(const u8 *addr,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 30a72b126..14da825d9 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1600,6 +1600,20 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
 
 #endif /* CONFIG_IEEE80211BE */
 
+static int hostapd_wpa_auth_get_drv_flags(void *ctx,
+					    u64 *drv_flags, u64 *drv_flags2)
+{
+	struct hostapd_data *hapd = ctx;
+
+	if (!drv_flags || !drv_flags2)
+		return -1;
+
+	*drv_flags = hapd->iface->drv_flags;
+	*drv_flags2 = hapd->iface->drv_flags2;
+
+	return 0;
+}
+
 
 int hostapd_setup_wpa(struct hostapd_data *hapd)
 {
@@ -1655,6 +1669,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 		.get_ml_rsn_info = hostapd_wpa_auth_get_ml_rsn_info,
 		.get_ml_key_info = hostapd_wpa_auth_get_ml_key_info,
 #endif /* CONFIG_IEEE80211BE */
+		.get_drv_flags = hostapd_wpa_auth_get_drv_flags,
 	};
 	const u8 *wpa_ie;
 	size_t wpa_ie_len;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 9b90e0749..15fb6baaf 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -17,7 +17,7 @@
 #include "pmksa_cache_auth.h"
 #include "wpa_auth_ie.h"
 #include "wpa_auth_i.h"
-
+#include "drivers/driver.h"
 
 #ifdef CONFIG_RSN_TESTING
 int rsn_testing = 0;
@@ -600,6 +600,14 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
 	return 0;
 }
 
+static int wpa_auth_get_drv_flags(struct wpa_authenticator *wpa_auth,
+		    u64 *drv_flags, u64 *drv_flags2)
+{
+	if(!wpa_auth->cb->get_drv_flags)
+		return -1;
+	return wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx,
+		drv_flags, drv_flags2);
+}
 
 enum wpa_validate_result
 wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
@@ -1013,11 +1021,22 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 	}
 
 #ifdef CONFIG_SAE
-	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
-	    !sm->pmksa) {
-		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE) {
+		u64 drv_flags = 0;
+		u64 drv_flags2 = 0;
+		bool ap_sae_offload = false;
+
+		if (!wpa_auth_get_drv_flags(wpa_auth, &drv_flags,
+		    &drv_flags2)) {
+			ap_sae_offload =
+				!!(drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP);
+		}
+
+		if (!ap_sae_offload && data.num_pmkid && !sm->pmksa) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
 				 "No PMKSA cache entry found for SAE");
-		return WPA_INVALID_PMKID;
+			return WPA_INVALID_PMKID;
+		}
 	}
 #endif /* CONFIG_SAE */
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 24016b344..292266c29 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1809,6 +1809,10 @@ struct wpa_driver_ap_params {
 	 * mld_link_id - Link id for MLD BSS's
 	 */
 	u8 mld_link_id;
+	/**
+	 * sae_password - sae password for SAE offload
+	 */
+	const char *sae_password;
 };
 
 struct wpa_driver_mesh_bss_params {
@@ -2281,6 +2285,8 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ         0x0000000000008000ULL
 /** Driver supports SAE authentication offload in STA mode */
 #define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA	0x0000000000010000ULL
+/** Driver support AP SAE authentication offload */
+#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP	0x0000000000020000ULL
 	u64 flags2;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 8b72d74c5..0a4f33d25 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5110,6 +5110,12 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 			 suites))
 		goto fail;
 
+	if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
+	    (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP) &&
+	    params->sae_password && (nla_put(msg, NL80211_ATTR_SAE_PASSWORD,
+	    os_strlen(params->sae_password), params->sae_password)))
+		goto fail;
+
 	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 	    (!params->pairwise_ciphers ||
 	     params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index b7d914140..2be1f5cd8 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -705,6 +705,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
 	if (ext_feature_isset(ext_features, len,
 			      NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT))
 		capa->flags2 |= WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_SAE_OFFLOAD_AP))
+		capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP;
 }
 
 
-- 
2.32.0

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4218 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20231110/b6e801d4/attachment.p7s>


More information about the Hostap mailing list