From e7aeb6d8ac416ddd96d736e9cd3127430339ec0a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 30 May 2020 23:30:42 +0300 Subject: [PATCH] SAE-PK: STA functionality This adds STA side functionality for SAE-PK. This version enables SAE-PK automatically based on the configured SAE password value if the selected AP advertises support for SAE-PK. Signed-off-by: Jouni Malinen --- wpa_supplicant/sme.c | 88 +++++++++++++++++++++++++-------- wpa_supplicant/wpa_supplicant.c | 4 +- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index d03b0ce8a..3ad006528 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -85,16 +85,21 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s) static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const u8 *bssid, int external, - int reuse, int *ret_use_pt) + int reuse, int *ret_use_pt, + bool *ret_use_pk) { struct wpabuf *buf; size_t len; const char *password; struct wpa_bss *bss; int use_pt = 0; + bool use_pk = false; + u8 rsnxe_capa = 0; if (ret_use_pt) *ret_use_pt = 0; + if (ret_use_pk) + *ret_use_pk = false; #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->sae_commit_override) { @@ -124,6 +129,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "SAE: Reuse previously generated PWE on a retry with the same AP"); use_pt = wpa_s->sme.sae.tmp->h2e; + use_pk = wpa_s->sme.sae.tmp->pk; goto reuse_data; } if (sme_set_sae_group(wpa_s) < 0) { @@ -131,19 +137,27 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, return NULL; } + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + if (bss) { + const u8 *rsnxe; + + rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX); + if (rsnxe && rsnxe[1] >= 1) + rsnxe_capa = rsnxe[2]; + } + if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3) use_pt = 1; +#ifdef CONFIG_SAE_PK + if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) && + ssid->sae_password && sae_pk_valid_password(ssid->sae_password)) { + use_pt = 1; + use_pk = true; + } +#endif /* CONFIG_SAE_PK */ if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) { - bss = wpa_bss_get_bssid_latest(wpa_s, bssid); - if (bss) { - const u8 *rsnxe; - - rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX); - if (rsnxe && rsnxe[1] >= 1) - use_pt = !!(rsnxe[2] & - BIT(WLAN_RSNX_CAPAB_SAE_H2E)); - } + use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E)); if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) && wpa_s->conf->sae_pwe != 3 && @@ -167,8 +181,17 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); return NULL; } - if (wpa_s->sme.sae.tmp) + if (wpa_s->sme.sae.tmp) { os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN); + if (use_pt && use_pk) + wpa_s->sme.sae.tmp->pk = 1; +#ifdef CONFIG_SAE_PK + os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr, + ETH_ALEN); + os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN); + sae_pk_set_password(&wpa_s->sme.sae, password); +#endif /* CONFIG_SAE_PK */ + } reuse_data: len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0; @@ -179,8 +202,12 @@ reuse_data: return NULL; if (!external) { wpabuf_put_le16(buf, 1); /* Transaction seq# */ - wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT : - WLAN_STATUS_SUCCESS); + if (use_pk) + wpabuf_put_le16(buf, WLAN_STATUS_SAE_PK); + else if (use_pt) + wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); + else + wpabuf_put_le16(buf,WLAN_STATUS_SUCCESS); } if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token, ssid->sae_password_id) < 0) { @@ -189,6 +216,8 @@ reuse_data: } if (ret_use_pt) *ret_use_pt = use_pt; + if (ret_use_pk) + *ret_use_pk = use_pk; return buf; } @@ -716,7 +745,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (start) resp = sme_auth_build_sae_commit(wpa_s, ssid, bss->bssid, 0, - start == 2, NULL); + start == 2, NULL, + NULL); else resp = sme_auth_build_sae_confirm(wpa_s, 0); if (resp == NULL) { @@ -1008,8 +1038,11 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, { struct wpabuf *resp, *buf; int use_pt; + bool use_pk; + u16 status; - resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt); + resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt, + &use_pk); if (!resp) { wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit"); return -1; @@ -1023,10 +1056,14 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, } wpa_s->sme.seq_num++; + if (use_pk) + status = WLAN_STATUS_SAE_PK; + else if (use_pt) + status = WLAN_STATUS_SAE_HASH_TO_ELEMENT; + else + status = WLAN_STATUS_SUCCESS; sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, - bssid, 1, wpa_s->sme.seq_num, - use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT : - WLAN_STATUS_SUCCESS); + bssid, 1, wpa_s->sme.seq_num, status); wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); @@ -1287,7 +1324,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, } if (status_code != WLAN_STATUS_SUCCESS && - status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT) + status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT && + status_code != WLAN_STATUS_SAE_PK) return -1; if (auth_transaction == 1) { @@ -1310,18 +1348,26 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected"); return -1; } - if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->h2e && + if (wpa_s->sme.sae.tmp && + (!wpa_s->sme.sae.tmp->h2e || wpa_s->sme.sae.tmp->pk) && status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) { wpa_printf(MSG_DEBUG, "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected"); return -1; } + if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->pk && + status_code == WLAN_STATUS_SAE_PK) { + wpa_printf(MSG_DEBUG, + "SAE: Unexpected use of status code for PK in SAE commit when PK was not expected"); + return -1; + } if (groups && groups[0] <= 0) groups = NULL; res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, groups, status_code == - WLAN_STATUS_SAE_HASH_TO_ELEMENT); + WLAN_STATUS_SAE_HASH_TO_ELEMENT || + status_code == WLAN_STATUS_SAE_PK); if (res == SAE_SILENTLY_DISCARD) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message due to reflection attack"); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index acd0091bc..f5a4c360b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2061,7 +2061,9 @@ static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid) if (!password) password = ssid->passphrase; - if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password || + if (!password || + (conf->sae_pwe == 0 && !ssid->sae_password_id && + !sae_pk_valid_password(password)) || conf->sae_pwe == 3) { /* PT derivation not needed */ sae_deinit_pt(ssid->pt);