From 79f87f4734123a78f8b9d2a84d885a831c94a5a6 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Apr 2021 12:06:24 +0300 Subject: [PATCH] PASN: Change PASN flows to use SAE H2E only Do so for both wpa_supplicant and hostapd. While this was not explicitly required in IEEE P802.11az/D3.0, likely direction for the draft is to start requiring use of H2E for all cases where SAE is used with PASN. Signed-off-by: Ilan Peer --- src/ap/ieee802_11.c | 20 +++++----- wpa_supplicant/pasn_supplicant.c | 68 ++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 1b0384dfc..f7f07b494 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2383,11 +2383,12 @@ static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd, struct wpabuf *wd) { struct pasn_data *pasn = sta->pasn; - const char *password = NULL; + const char *password; const u8 *data; size_t buf_len; u16 res, alg, seq, status; int groups[] = { pasn->group, 0 }; + struct sae_pt *pt = NULL; int ret; if (!wd) @@ -2409,8 +2410,8 @@ static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u", alg, seq, status); - /* TODO: SAE H2E */ - if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) { + if (alg != WLAN_AUTH_SAE || seq != 1 || + status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit"); return -1; } @@ -2424,15 +2425,14 @@ static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd, return -1; } - password = sae_get_password(hapd, sta, NULL, NULL, NULL, NULL); - if (!password) { - wpa_printf(MSG_DEBUG, "PASN: No SAE password found"); + password = sae_get_password(hapd, sta, NULL, NULL, &pt, NULL); + if (!password || !pt) { + wpa_printf(MSG_DEBUG, "PASN: No SAE PT found"); return -1; } - ret = sae_prepare_commit(hapd->own_addr, sta->addr, - (const u8 *) password, os_strlen(password), 0, - &pasn->sae); + ret = sae_prepare_commit_pt(&pasn->sae, pt, hapd->own_addr, sta->addr, + NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit"); return -1; @@ -2529,7 +2529,7 @@ static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd, len_ptr = wpabuf_put(buf, 2); wpabuf_put_le16(buf, WLAN_AUTH_SAE); wpabuf_put_le16(buf, 1); - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); /* Write the actual commit and update the length accordingly */ sae_write_commit(&pasn->sae, buf, NULL, 0); diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index d483175b7..edb550800 100644 --- a/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant/pasn_supplicant.c @@ -102,30 +102,17 @@ static struct wpabuf * wpas_pasn_wd_sae_commit(struct wpa_supplicant *wpa_s) { struct wpas_pasn *pasn = &wpa_s->pasn; struct wpabuf *buf = NULL; - const char *password = NULL; int ret; - if (pasn->ssid) { - password = pasn->ssid->sae_password; - if (!password) - password = pasn->ssid->passphrase; - } - - if (!password) { - wpa_printf(MSG_DEBUG, "PASN: SAE without a password"); - return NULL; - } - ret = sae_set_group(&pasn->sae, pasn->group); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group"); return NULL; } - /* TODO: SAE H2E */ - ret = sae_prepare_commit(wpa_s->own_addr, pasn->bssid, - (const u8 *) password, os_strlen(password), 0, - &pasn->sae); + ret = sae_prepare_commit_pt(&pasn->sae, pasn->ssid->pt, + wpa_s->own_addr, pasn->bssid, + NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit"); return NULL; @@ -140,7 +127,7 @@ static struct wpabuf * wpas_pasn_wd_sae_commit(struct wpa_supplicant *wpa_s) wpabuf_put_le16(buf, WLAN_AUTH_SAE); wpabuf_put_le16(buf, 1); - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); sae_write_commit(&pasn->sae, buf, NULL, 0); pasn->sae.state = SAE_COMMITTED; @@ -186,14 +173,14 @@ static int wpas_pasn_wd_sae_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd) wpa_printf(MSG_DEBUG, "PASN: SAE: commit: alg=%u, seq=%u, status=%u", alg, seq, status); - /* TODO: SAE H2E */ - if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) { + if (alg != WLAN_AUTH_SAE || seq != 1 || + status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { wpa_printf(MSG_DEBUG, "PASN: SAE: dropping peer commit"); return -1; } res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups, - 0); + 1); if (res != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "PASN: SAE failed parsing commit"); return -1; @@ -271,6 +258,31 @@ static struct wpabuf * wpas_pasn_wd_sae_confirm(struct wpa_supplicant *wpa_s) return buf; } + +static int wpas_pasn_sae_setup_pt(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, int group) +{ + const char *password = ssid->sae_password; + int groups[2] = { group, 0 }; + + if (!password) + password = ssid->passphrase; + + if (!password) { + wpa_printf(MSG_DEBUG, "PASN: SAE without a password"); + return -1; + } + + if (ssid->pt) + return 0; /* PT already derived */ + + ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, + (const u8 *) password, os_strlen(password), + ssid->sae_password_id); + + return ssid->pt ? 0 : -1; +} + #endif /* CONFIG_SAE */ @@ -718,8 +730,8 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s, goto fail; /* Add own RNSXE */ - /* TODO: How to handle protected TWT and SAE H2E? */ capab = 0; + capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF); if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT) @@ -1008,6 +1020,20 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, "PASN: No network profile found for SAE"); return -1; } + + if (beacon_rsnxe_len < 3 || + !(beacon_rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) { + wpa_printf(MSG_DEBUG, + "PASN: AP does not support SAE H2E"); + return -1; + } + + if (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) < 0) { + wpa_printf(MSG_DEBUG, + "PASN: Failed to derive PT"); + return -1; + } + pasn->sae.state = SAE_NOTHING; pasn->sae.send_confirm = 0; pasn->ssid = ssid;