[PATCH 1/3] mesh: add support for SAE Hash-to-Element in mesh mode.
Nicolas Cavallari
nicolas.cavallari at green-communications.fr
Thu Sep 18 08:31:38 PDT 2025
It currently comes with the limitation that the PT is derived twice:
one for the supplicant and one for the authenticator.
Signed-off-by: Nicolas Cavallari <nicolas.cavallari at green-communications.fr>
---
src/ap/ap_config.h | 1 +
src/ap/ieee802_11.c | 14 +++++++++++++-
wpa_supplicant/mesh.c | 9 +++++++++
wpa_supplicant/mesh_rsn.c | 26 +++++++++++++++++++++++---
wpa_supplicant/mesh_rsn.h | 1 +
5 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f38676ad8..3feab92d2 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -53,6 +53,7 @@ struct mesh_conf {
unsigned int pairwise_cipher;
unsigned int group_cipher;
unsigned int mgmt_group_cipher;
+ unsigned int sae_pwe;
int dot11MeshMaxRetries;
int dot11MeshRetryTimeout; /* msec */
int dot11MeshConfirmTimeout; /* msec */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index ca5ca9687..6f43d373e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1594,7 +1594,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
sta->sae->tmp) {
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
- if (pos + sizeof(le16) > end) {
+ if (pos + sizeof(le16) +
+ (sta->sae->h2e ? 3 : 0) > end) {
wpa_printf(MSG_ERROR,
"SAE: Too short anti-clogging token request");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1608,6 +1609,17 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
goto reply;
}
pos += sizeof(le16);
+ if (sta->sae->h2e &&
+ !(pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] == end - pos - 2 &&
+ pos[2] == WLAN_EID_EXT_ANTI_CLOGGING_TOKEN)) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Invalid anti-clogging token container");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
+ if (sta->sae->h2e)
+ pos += 3;
wpabuf_free(sta->sae->tmp->anti_clogging_token);
sta->sae->tmp->anti_clogging_token =
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 297d644e5..fdf5e68e3 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -97,6 +97,7 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
+ conf->sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
conf->ieee80211w = ssid->ieee80211w;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
@@ -200,6 +201,13 @@ static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s)
len = os_strlen(password);
bss->conf->ssid.wpa_passphrase = dup_binstr(password, len);
+ if (ssid->pt) {
+ sae_deinit_pt(bss->conf->ssid.pt);
+ bss->conf->ssid.pt = sae_derive_pt(bss->conf->sae_groups,
+ ssid->ssid, ssid->ssid_len,
+ (const u8 *) password,
+ len, ssid->sae_password_id);
+ }
wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, ifmsh->mconf);
return !wpa_s->mesh_rsn ? -1 : 0;
@@ -480,6 +488,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
bss->conf->mesh = MESH_ENABLED;
bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
bss->conf->mesh_fwding = wpa_s->conf->mesh_fwding;
+ bss->conf->sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
ieee80211_freq_to_chan(freq->center_freq1, &chan);
if (wpa_s->mesh_vht_enabled) {
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index ada53c796..b8854163d 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -24,6 +24,7 @@
#include "wpas_glue.h"
#include "mesh_mpm.h"
#include "mesh_rsn.h"
+#include "config.h"
#define MESH_AUTH_TIMEOUT 10
#define MESH_AUTH_RETRY 3
@@ -187,6 +188,9 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
conf.ieee80211w = ieee80211w;
if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
+#ifdef CONFIG_SAE
+ conf.sae_pwe = rsn->sae_pwe;
+#endif
#ifdef CONFIG_OCV
conf.ocv = ocv;
#endif /* CONFIG_OCV */
@@ -261,6 +265,7 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
mesh_rsn->pairwise_cipher = conf->pairwise_cipher;
mesh_rsn->group_cipher = conf->group_cipher;
mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
+ mesh_rsn->sae_pwe = conf->sae_pwe;
if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
conf->ieee80211w, conf->ocv) < 0) {
@@ -341,6 +346,7 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
struct sta_info *sta)
{
const char *password;
+ bool use_pt = false;
password = ssid->sae_password;
if (!password)
@@ -355,14 +361,28 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
return -1;
}
+ if (ssid->sae_password_id &&
+ wpa_s->mesh_rsn->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+ use_pt = true;
+ if (wpa_s->mesh_rsn->sae_pwe == SAE_PWE_HASH_TO_ELEMENT)
+ use_pt = true;
+
+ if (!use_pt)
+ return sae_prepare_commit(wpa_s->own_addr, sta->addr,
+ (u8 *) password, os_strlen(password),
+ sta->sae);
+
if (sta->sae->tmp && !sta->sae->tmp->pw_id && ssid->sae_password_id) {
sta->sae->tmp->pw_id = os_strdup(ssid->sae_password_id);
if (!sta->sae->tmp->pw_id)
return -1;
}
- return sae_prepare_commit(wpa_s->own_addr, sta->addr,
- (u8 *) password, os_strlen(password),
- sta->sae);
+
+ if (!ssid->pt)
+ wpa_s_setup_sae_pt(wpa_s, ssid, true);
+
+ return sae_prepare_commit_pt(sta->sae, ssid->pt,
+ wpa_s->own_addr, sta->addr, NULL, NULL);
}
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
index 8775cedc3..e0c88b70d 100644
--- a/wpa_supplicant/mesh_rsn.h
+++ b/wpa_supplicant/mesh_rsn.h
@@ -24,6 +24,7 @@ struct mesh_rsn {
#ifdef CONFIG_SAE
struct wpabuf *sae_token;
int sae_group_index;
+ int sae_pwe;
#endif /* CONFIG_SAE */
};
--
2.51.0
More information about the Hostap
mailing list