From: Jouni Malinen Date: Mon, 27 Oct 2025 11:44:27 +0000 (+0200) Subject: SAE: Process password identifier as an octet string X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2c1a47980536888fe419243a619b7f9f5a9f3dce;p=thirdparty%2Fhostap.git SAE: Process password identifier as an octet string Replace the nul terminated character string design with a pointer to the beginning of an octet string and an explicit length indication for the SAE password identifier. This is needed to be able to add support for changing SAE password identifiers that might not use character strings. Signed-off-by: Jouni Malinen --- diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index d1d988b5f..bc20aa0b4 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -522,7 +522,7 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf) ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, (const u8 *) ssid->wpa_passphrase, os_strlen(ssid->wpa_passphrase), - NULL); + NULL, 0); if (!ssid->pt) return -1; } @@ -532,7 +532,9 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf) pw->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, (const u8 *) pw->password, os_strlen(pw->password), - pw->identifier); + (const u8 *) pw->identifier, + pw->identifier ? + os_strlen(pw->identifier) : 0); if (!pw->pt) return -1; } diff --git a/src/ap/beacon.c b/src/ap/beacon.c index ad2af6e7a..5a9961119 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -2543,8 +2543,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, return -1; } - params->sae_password = sae_get_password(hapd, NULL, NULL, NULL, - NULL, NULL); + params->sae_password = sae_get_password(hapd, NULL, NULL, 0, + NULL, NULL, NULL); if (!params->sae_password) { wpa_printf(MSG_ERROR, "SAE password not configured for offload"); return -1; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 45106617d..ccb66db6c 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -654,7 +654,7 @@ int sae_password_bind(struct hostapd_data *hapd, const u8 *addr, const char * sae_get_password(struct hostapd_data *hapd, struct sta_info *sta, - const char *rx_id, + const u8 *rx_id, size_t rx_id_len, struct sae_password_entry **pw_entry, struct sae_pt **s_pt, const struct sae_pk **s_pk) @@ -712,7 +712,8 @@ const char * sae_get_password(struct hostapd_data *hapd, if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier)) continue; if (rx_id && pw->identifier && - os_strcmp(rx_id, pw->identifier) != 0) + (rx_id_len != os_strlen(pw->identifier) || + os_memcmp(rx_id, pw->identifier, rx_id_len) != 0)) continue; password = pw->password; pt = pw->pt; @@ -753,7 +754,8 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, struct wpabuf *buf; const char *password = NULL; struct sae_password_entry *pw; - const char *rx_id = NULL; + const u8 *rx_id = NULL; + size_t rx_id_len = 0; int use_pt = 0; struct sae_pt *pt = NULL; const struct sae_pk *pk = NULL; @@ -767,6 +769,9 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, if (sta->sae->tmp) { rx_id = sta->sae->tmp->parsed_pw_id ? sta->sae->tmp->parsed_pw_id : sta->sae->tmp->pw_id; + rx_id_len = sta->sae->tmp->parsed_pw_id ? + sta->sae->tmp->parsed_pw_id_len : + sta->sae->tmp->pw_id_len; use_pt = sta->sae->h2e; #ifdef CONFIG_SAE_PK os_memcpy(sta->sae->tmp->own_addr, own_addr, ETH_ALEN); @@ -782,7 +787,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, status_code == WLAN_STATUS_SAE_PK) use_pt = 1; - password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk); + password = sae_get_password(hapd, sta, rx_id, rx_id_len, &pw, &pt, &pk); if (!password || (use_pt && !pt)) { wpa_printf(MSG_DEBUG, "SAE: No password available"); return NULL; @@ -814,11 +819,11 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, } buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN + - (rx_id ? 3 + os_strlen(rx_id) : 0)); + (rx_id ? 3 + rx_id_len : 0)); if (buf && sae_write_commit(sta->sae, buf, sta->sae->tmp ? sta->sae->tmp->anti_clogging_token : NULL, - rx_id) < 0) { + rx_id, rx_id_len) < 0) { wpabuf_free(buf); buf = NULL; } @@ -1185,10 +1190,12 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, if (tmp && tmp->parsed_pw_id && !tmp->pw_id) { tmp->pw_id = tmp->parsed_pw_id; + tmp->pw_id_len = tmp->parsed_pw_id_len; tmp->parsed_pw_id = NULL; - wpa_printf(MSG_DEBUG, - "SAE: Known Password Identifier bound to this STA: '%s'", - tmp->pw_id); + tmp->parsed_pw_id_len = 0; + wpa_hexdump_ascii(MSG_DEBUG, + "SAE: Known Password Identifier bound to this STA", + tmp->pw_id, tmp->pw_id_len); } sae_set_state(sta, SAE_COMMITTED, "Sent Commit"); @@ -2885,7 +2892,7 @@ static void hapd_initialize_pasn(struct hostapd_data *hapd, pasn_enable_kdk_derivation(pasn); #endif /* CONFIG_TESTING_OPTIONS */ pasn->use_anti_clogging = use_anti_clogging(hapd); - pasn_set_password(pasn, sae_get_password(hapd, sta, NULL, NULL, + pasn_set_password(pasn, sae_get_password(hapd, sta, NULL, 0, NULL, &pasn->pt, NULL)); pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len); pasn_set_rsnxe_ie(pasn, hostapd_wpa_ie(hapd, WLAN_EID_RSNX)); diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index a2bd583be..77704faae 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -293,7 +293,8 @@ bool hostapd_is_multiple_link_mld(struct hostapd_data *hapd); int sae_password_bind(struct hostapd_data *hapd, const u8 *addr, const char *password); const char * sae_get_password(struct hostapd_data *hapd, - struct sta_info *sta, const char *rx_id, + struct sta_info *sta, const u8 *rx_id, + size_t rx_id_len, struct sae_password_entry **pw_entry, struct sae_pt **s_pt, const struct sae_pk **s_pk); struct sta_info * hostapd_ml_get_assoc_sta(struct hostapd_data *hapd, diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c index 4339fc772..edbdbfa1a 100644 --- a/src/common/common_module_tests.c +++ b/src/common/common_module_tests.c @@ -416,7 +416,7 @@ static int sae_tests(void) goto fail; /* Check that output matches the test vector */ - if (sae_write_commit(&sae, buf, NULL, NULL) < 0) + if (sae_write_commit(&sae, buf, NULL, NULL, 0) < 0) goto fail; wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf); @@ -449,7 +449,9 @@ static int sae_tests(void) pt_info = sae_derive_pt(pt_groups, (const u8 *) ssid, os_strlen(ssid), - (const u8 *) pw, os_strlen(pw), pwid); + (const u8 *) pw, os_strlen(pw), + (const u8 *) pwid, + os_strlen(pwid)); if (!pt_info) goto fail; diff --git a/src/common/proximity_ranging.c b/src/common/proximity_ranging.c index a0175828c..1cb337713 100644 --- a/src/common/proximity_ranging.c +++ b/src/common/proximity_ranging.c @@ -1666,7 +1666,7 @@ static void pr_pasn_set_password(struct pasn_data *pasn, u8 pasn_type, } pasn->pt = sae_derive_pt(pasn_groups, (const u8 *) PR_PASN_SSID, os_strlen(PR_PASN_SSID), - (const u8 *) passphrase, len, NULL); + (const u8 *) passphrase, len, NULL, 0); /* Set passphrase for PASN responder to validate Auth 1 frame */ pasn->password = passphrase; } diff --git a/src/common/sae.c b/src/common/sae.c index 8005095fc..14af5ffd1 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -831,7 +831,8 @@ fail: static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len, const u8 *password, size_t password_len, - const char *identifier, u8 *pwd_seed) + const u8 *identifier, size_t identifier_len, + u8 *pwd_seed) { const u8 *addr[2]; size_t len[2]; @@ -845,10 +846,10 @@ static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len, wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", password, password_len); if (identifier) { - wpa_printf(MSG_DEBUG, "SAE: password identifier: %s", - identifier); + wpa_hexdump_ascii(MSG_DEBUG, "SAE: password identifier", + identifier, identifier_len); addr[num_elem] = (const u8 *) identifier; - len[num_elem] = os_strlen(identifier); + len[num_elem] = identifier_len; num_elem++; } if (hkdf_extract(hash_len, ssid, ssid_len, num_elem, addr, len, @@ -873,7 +874,7 @@ static struct crypto_ec_point * sae_derive_pt_ecc(struct crypto_ec *ec, int group, const u8 *ssid, size_t ssid_len, const u8 *password, size_t password_len, - const char *identifier) + const u8 *identifier, size_t identifier_len) { u8 pwd_seed[64]; u8 pwd_value[SAE_MAX_ECC_PRIME_LEN * 2]; @@ -892,7 +893,7 @@ sae_derive_pt_ecc(struct crypto_ec *ec, int group, pwd_value_len = prime_len + (prime_len + 1) / 2; if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len, - identifier, pwd_seed) < 0) + identifier, identifier_len, pwd_seed) < 0) goto fail; /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len) @@ -973,7 +974,7 @@ static struct crypto_bignum * sae_derive_pt_ffc(const struct dh_group *dh, int group, const u8 *ssid, size_t ssid_len, const u8 *password, size_t password_len, - const char *identifier) + const u8 *identifier, size_t identifier_len) { size_t hash_len, prime_len, pwd_value_len; struct crypto_bignum *prime, *order; @@ -997,7 +998,7 @@ sae_derive_pt_ffc(const struct dh_group *dh, int group, goto fail; if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len, - identifier, pwd_seed) < 0) + identifier, identifier_len, pwd_seed) < 0) goto fail; /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element", len) */ @@ -1050,7 +1051,7 @@ fail: static struct sae_pt * sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len, const u8 *password, size_t password_len, - const char *identifier) + const u8 *identifier, size_t identifier_len) { struct sae_pt *pt; @@ -1072,7 +1073,7 @@ sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len, if (pt->ec) { pt->ecc_pt = sae_derive_pt_ecc(pt->ec, group, ssid, ssid_len, password, password_len, - identifier); + identifier, identifier_len); if (!pt->ecc_pt) { wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT"); goto fail; @@ -1088,7 +1089,8 @@ sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len, } pt->ffc_pt = sae_derive_pt_ffc(pt->dh, group, ssid, ssid_len, - password, password_len, identifier); + password, password_len, identifier, + identifier_len); if (!pt->ffc_pt) { wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT"); goto fail; @@ -1104,7 +1106,7 @@ fail: struct sae_pt * sae_derive_pt(const int *groups, const u8 *ssid, size_t ssid_len, const u8 *password, size_t password_len, - const char *identifier) + const u8 *identifier, size_t identifier_len) { struct sae_pt *pt = NULL, *last = NULL, *tmp; const int default_groups[] = { 19, 0 }; @@ -1114,7 +1116,8 @@ struct sae_pt * sae_derive_pt(const int *groups, groups = default_groups; for (i = 0; groups[i] > 0; i++) { tmp = sae_derive_pt_group(groups[i], ssid, ssid_len, password, - password_len, identifier); + password_len, identifier, + identifier_len); if (!tmp) continue; @@ -1685,7 +1688,8 @@ int sae_process_commit(struct sae_data *sae) int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token, const char *identifier) + const struct wpabuf *token, const u8 *identifier, + size_t identifier_len) { u8 *pos; @@ -1727,11 +1731,11 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, if (identifier) { /* Password Identifier element */ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); - wpabuf_put_u8(buf, 1 + os_strlen(identifier)); + wpabuf_put_u8(buf, 1 + identifier_len); wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER); - wpabuf_put_str(buf, identifier); - wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s", - identifier); + wpabuf_put_data(buf, identifier, identifier_len); + wpa_hexdump_ascii(MSG_DEBUG, "SAE: own Password Identifier", + identifier, identifier_len); } if (sae->h2e && sae->tmp->own_rejected_groups) { @@ -2072,6 +2076,7 @@ static int sae_parse_password_identifier(struct sae_data *sae, bool h2e, } os_free(sae->tmp->parsed_pw_id); sae->tmp->parsed_pw_id = NULL; + sae->tmp->parsed_pw_id_len = 0; return WLAN_STATUS_SUCCESS; /* No Password Identifier */ } @@ -2096,7 +2101,7 @@ static int sae_parse_password_identifier(struct sae_data *sae, bool h2e, } if (sae->tmp->pw_id && - (len != os_strlen(sae->tmp->pw_id) || + (len != sae->tmp->pw_id_len || os_memcmp(sae->tmp->pw_id, epos, len) != 0)) { wpa_printf(MSG_DEBUG, "SAE: The included Password Identifier does not match the expected one (%s)", @@ -2106,9 +2111,12 @@ static int sae_parse_password_identifier(struct sae_data *sae, bool h2e, os_free(sae->tmp->parsed_pw_id); sae->tmp->parsed_pw_id = os_malloc(len + 1); - if (!sae->tmp->parsed_pw_id) + if (!sae->tmp->parsed_pw_id) { + sae->tmp->parsed_pw_id_len = 0; return WLAN_STATUS_UNSPECIFIED_FAILURE; + } os_memcpy(sae->tmp->parsed_pw_id, epos, len); + sae->tmp->parsed_pw_id_len = len; sae->tmp->parsed_pw_id[len] = '\0'; wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier", sae->tmp->parsed_pw_id, len); diff --git a/src/common/sae.h b/src/common/sae.h index 0d94e1f21..e9bd0f748 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -58,8 +58,10 @@ struct sae_temporary_data { struct crypto_bignum *prime_buf; struct crypto_bignum *order_buf; struct wpabuf *anti_clogging_token; - char *pw_id; - char *parsed_pw_id; + u8 *pw_id; + size_t pw_id_len; + u8 *parsed_pw_id; + size_t parsed_pw_id_len; int vlan_id; u8 bssid[ETH_ALEN]; struct wpabuf *own_rejected_groups; @@ -140,7 +142,8 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt, int *rejected_groups, const struct sae_pk *pk); int sae_process_commit(struct sae_data *sae); int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token, const char *identifier); + const struct wpabuf *token, const u8 *identifier, + size_t identifier_len); u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups, int h2e, int *ie_offset); @@ -154,7 +157,7 @@ size_t sae_ffc_prime_len_2_hash_len(size_t prime_len); struct sae_pt * sae_derive_pt(const int *groups, const u8 *ssid, size_t ssid_len, const u8 *password, size_t password_len, - const char *identifier); + const u8 *identifier, size_t identifier_len); struct crypto_ec_point * sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt, const u8 *addr1, const u8 *addr2); diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index a2d78db5f..8a97091b4 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -6361,7 +6361,7 @@ static void p2p_pairing_set_password(struct pasn_data *pasn, u8 pasn_type, } pasn->pt = sae_derive_pt(pasn_groups, (const u8 *) P2P_PAIRING_SSID, os_strlen(P2P_PAIRING_SSID), - (const u8 *) passphrase, len, NULL); + (const u8 *) passphrase, len, NULL, 0); /* Set passphrase for pairing responder to validate PASN auth 1 frame */ pasn->password = passphrase; } diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c index 8669839d5..9a46e0a4a 100644 --- a/src/pasn/pasn_initiator.c +++ b/src/pasn/pasn_initiator.c @@ -126,7 +126,7 @@ static struct wpabuf * wpas_pasn_wd_sae_commit(struct pasn_data *pasn) wpabuf_put_le16(buf, 1); wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); - sae_write_commit(&pasn->sae, buf, NULL, NULL); + sae_write_commit(&pasn->sae, buf, NULL, NULL, 0); pasn->sae.state = SAE_COMMITTED; return buf; diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c index 45dd22649..cd5fc5e41 100644 --- a/src/pasn/pasn_responder.c +++ b/src/pasn/pasn_responder.c @@ -252,7 +252,7 @@ static struct wpabuf * pasn_get_sae_wd(struct pasn_data *pasn) 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, NULL); + sae_write_commit(&pasn->sae, buf, NULL, NULL, 0); len = wpabuf_len(buf); WPA_PUT_LE16(len_ptr, len - 2); diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index ada53c796..463137353 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -356,9 +356,10 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s, } if (sta->sae->tmp && !sta->sae->tmp->pw_id && ssid->sae_password_id) { - sta->sae->tmp->pw_id = os_strdup(ssid->sae_password_id); + sta->sae->tmp->pw_id = (u8 *) os_strdup(ssid->sae_password_id); if (!sta->sae->tmp->pw_id) return -1; + sta->sae->tmp->pw_id_len = os_strlen(ssid->sae_password_id); } return sae_prepare_commit(wpa_s->own_addr, sta->addr, (u8 *) password, os_strlen(password), diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index 6a0abe76b..4fd4b7416 100644 --- a/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant/pasn_supplicant.c @@ -127,8 +127,10 @@ wpas_pasn_sae_derive_pt(struct wpa_ssid *ssid, int group) } return sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, - (const u8 *) password, os_strlen(password), - ssid->sae_password_id); + (const u8 *) password, os_strlen(password), + (const u8 *) ssid->sae_password_id, + ssid->sae_password_id ? + os_strlen(ssid->sae_password_id) : 0); } diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 55dcf41ef..b6e86f9c5 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -106,6 +106,9 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, wpa_s->key_mgmt; const u8 *addr = mld_addr ? mld_addr : bssid; enum sae_pwe sae_pwe; + const u8 *password_id = (const u8 *) ssid->sae_password_id; + size_t password_id_len = ssid->sae_password_id ? + os_strlen(ssid->sae_password_id) : 0; if (ret_use_pt) *ret_use_pt = 0; @@ -286,7 +289,7 @@ reuse_data: 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) { + password_id, password_id_len) < 0) { wpabuf_free(buf); goto fail; } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 317ca3d57..33814273b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2674,6 +2674,9 @@ void wpa_s_setup_sae_pt(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int default_groups[] = { 19, 20, 21, 0 }; const char *password; enum sae_pwe sae_pwe; + const u8 *password_id = (const u8 *) ssid->sae_password_id; + size_t password_id_len = ssid->sae_password_id ? + os_strlen(ssid->sae_password_id) : 0; if (!groups || groups[0] <= 0) groups = default_groups; @@ -2701,7 +2704,7 @@ void wpa_s_setup_sae_pt(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, return; /* PT already derived */ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, (const u8 *) password, os_strlen(password), - ssid->sae_password_id); + password_id, password_id_len); #endif /* CONFIG_SAE */ }