From ba9387b511e697821b4ca9ed256ece5bab1e6c00 Mon Sep 17 00:00:00 2001 From: Chien Wong Date: Sat, 22 Mar 2025 17:58:47 +0800 Subject: [PATCH 1/2] change(esp_wifi): Improve handling group parameter A in H2E Signed-off-by: Chien Wong --- .../src/crypto/crypto_mbedtls-ec.c | 38 ++++++++++++++++++- components/wpa_supplicant/src/common/sae.c | 6 +-- components/wpa_supplicant/src/crypto/crypto.h | 10 ++++- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c b/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c index 52cec2e4d2..d9a4801271 100644 --- a/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c +++ b/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -149,6 +149,42 @@ const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e) return (const struct crypto_bignum *) & ((mbedtls_ecp_group *)e)->N; } +struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e) +{ + int ret = -1; + struct crypto_bignum *a; + mbedtls_mpi *m_a; + mbedtls_ecp_group *grp = (mbedtls_ecp_group *)e; + if (mbedtls_ecp_get_type(grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + return NULL; + } + a = crypto_bignum_init(); + if (!a) { + return NULL; + } + m_a = (mbedtls_mpi *)a; + /* Handle Mbed TLS quirk. + * + * Mbed TLS default ECP implementation is using grp->A = NULL to represent A = -3 for + * Short Weierstrass curves(e.g. P-256) thus accessing A needs some tweaking. + * + * See mbedtls/ecp.h for details. */ +#ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED + if (mbedtls_ecp_group_a_is_minus_3(grp)) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(m_a, &grp->P, 3)); + } else { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(m_a, &grp->A)); + } +#else + goto cleanup; +#endif + return a; + +cleanup: + crypto_bignum_deinit(a, 0); + return NULL; +} + const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e) { return (const struct crypto_bignum *) & ((mbedtls_ecp_group *)e)->B; diff --git a/components/wpa_supplicant/src/common/sae.c b/components/wpa_supplicant/src/common/sae.c index f5b61bad62..1d11ecfd65 100644 --- a/components/wpa_supplicant/src/common/sae.c +++ b/components/wpa_supplicant/src/common/sae.c @@ -594,9 +594,7 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group, prime = crypto_ec_get_prime(ec); prime_len = crypto_ec_prime_len(ec); - /* Value of 'a' defined for curve secp256r1 in 'y^2 = x^3 + ax + b' */ - uint8_t buf[32] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc}; - a = crypto_bignum_init_set(buf, 32); + a = crypto_ec_get_a(ec); b = crypto_ec_get_b(ec); u2 = crypto_bignum_init(); @@ -615,7 +613,7 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group, gx2 = crypto_bignum_init(); tmp = crypto_bignum_init(); if (!u2 || !t1 || !t2 || !z || !t || !zero || !one || !two || !three || - !x1a || !x1b || !x2 || !gx1 || !gx2 || !tmp) + !x1a || !x1b || !x2 || !gx1 || !gx2 || !a || !tmp) goto fail; if (z_int < 0 && crypto_bignum_sub(prime, z, z) < 0) diff --git a/components/wpa_supplicant/src/crypto/crypto.h b/components/wpa_supplicant/src/crypto/crypto.h index 183cbf590f..7946e6be16 100644 --- a/components/wpa_supplicant/src/crypto/crypto.h +++ b/components/wpa_supplicant/src/crypto/crypto.h @@ -796,6 +796,14 @@ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e); * Internal data structure for EC implementation to represent a point. The * contents is specific to the used crypto library. */ +struct crypto_ec_point; + +/** + * crypto_ec_get_a - Get 'a' coefficient of an EC group's curve + * @e: EC context from crypto_ec_init() + * Returns: 'a' coefficient (bignum) of the group + */ +struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e); /** * crypto_ec_get_b - Get 'b' coefficient of an EC group's curve @@ -804,8 +812,6 @@ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e); */ const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e); -struct crypto_ec_point; - /** * crypto_ec_point_init - Initialize data for an EC point * @e: EC context from crypto_ec_init() From f025008d4ec27e9156d2c97f95936ee37fc022e9 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Thu, 3 Apr 2025 14:45:26 +0530 Subject: [PATCH 2/2] ci(esp_wifi): Add h2e testcase --- .../test_apps/main/CMakeLists.txt | 1 + .../test_apps/main/test_sae_h2e.c | 152 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 components/wpa_supplicant/test_apps/main/test_sae_h2e.c diff --git a/components/wpa_supplicant/test_apps/main/CMakeLists.txt b/components/wpa_supplicant/test_apps/main/CMakeLists.txt index 3b5cff8647..d9528030ae 100644 --- a/components/wpa_supplicant/test_apps/main/CMakeLists.txt +++ b/components/wpa_supplicant/test_apps/main/CMakeLists.txt @@ -5,6 +5,7 @@ idf_component_register(SRCS "test_fast_pbkdf2.c" "test_offchannel.c" "test_sae.c" + "test_sae_h2e.c" "test_wpa_supplicant_main.c" "test_wifi_external_bss.c" PRIV_INCLUDE_DIRS "." diff --git a/components/wpa_supplicant/test_apps/main/test_sae_h2e.c b/components/wpa_supplicant/test_apps/main/test_sae_h2e.c new file mode 100644 index 0000000000..5be24c7aad --- /dev/null +++ b/components/wpa_supplicant/test_apps/main/test_sae_h2e.c @@ -0,0 +1,152 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef CONFIG_WPA3_SAE + +#include +#include +#include +#include +#include +#include "unity.h" +#include +#include "utils/common.h" +#include "utils/includes.h" +#include "crypto/crypto.h" +#include "common/sae.h" +#include "utils/wpabuf.h" +#include "test_utils.h" +#include "test_wpa_supplicant_common.h" + +/* Helper functions for random SSID and password generation */ +static void generate_random_string(char *str, size_t len, bool include_special) +{ + const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + const char special_chars[] = "!@#$%^&*()_+-=[]{}|;:,.<>?"; + size_t charset_len = strlen(charset); + size_t special_len = strlen(special_chars); + + srand(time(NULL)); + for (size_t i = 0; i < len - 1; i++) { + if (include_special && (rand() % 4 == 0) && i > 0) { // 25% chance for special char + str[i] = special_chars[rand() % special_len]; + } else { + str[i] = charset[rand() % charset_len]; + } + } + str[len - 1] = '\0'; +} + +static void generate_random_ssid(char *ssid, size_t *ssid_len) +{ + *ssid_len = (rand() % 28) + 4; // Random length between 4 and 32 + generate_random_string(ssid, *ssid_len + 1, false); // +1 for null terminator +} + +static void generate_random_password(char *password) +{ + size_t len = (rand() % 48) + 16; // Random length between 16 and 63 + generate_random_string(password, len + 1, true); // +1 for null terminator +} + +TEST_CASE("Test SAE H2E complete workflow", "[wpa3_sae_h2e]") +{ + set_leak_threshold(600); + struct sae_data sae; + struct wpabuf *buf = NULL; + const u8 addr1[ETH_ALEN] = { 0x4d, 0x3f, 0x2f, 0xff, 0xe3, 0x87 }; + const u8 addr2[ETH_ALEN] = { 0xa5, 0xd8, 0xaa, 0x95, 0x8e, 0x3c }; + char password[64]; + char ssid[33]; + size_t ssid_len; + + /* Generate random SSID and password */ + generate_random_ssid(ssid, &ssid_len); + generate_random_password(password); + + ESP_LOGI("H2E", "\nUsing random credentials:"); + ESP_LOGI("H2E", "SSID: %s (len=%zu)", ssid, ssid_len); + ESP_LOGI("H2E", "Password: %s (len=%zu)", password, strlen(password)); + + /* Step 1: Test H2E initialization */ + ESP_LOGI("H2E", "\nStep 1: Testing H2E initialization"); + memset(&sae, 0, sizeof(sae)); + ESP_LOGI("H2E", "- Initial SAE state: h2e=%d", sae.h2e); + + TEST_ASSERT_MESSAGE(sae_set_group(&sae, IANA_SECP256R1) == 0, "Failed to set SAE group"); + ESP_LOGI("H2E", "- After group set: group=%d", sae.group); + TEST_ASSERT_MESSAGE(sae.h2e == 0, "H2E should be disabled by default"); + + sae.h2e = 1; + ESP_LOGI("H2E", "- After H2E enable: h2e=%d", sae.h2e); + TEST_ASSERT_MESSAGE(sae.h2e == 1, "Failed to enable H2E"); + + /* Step 2: Test password identifier validation */ + ESP_LOGI("H2E", "\nStep 2: Testing password identifier validation"); + ESP_LOGI("H2E", "- Addr1: %02x:%02x:%02x:%02x:%02x:%02x", + addr1[0], addr1[1], addr1[2], addr1[3], addr1[4], addr1[5]); + ESP_LOGI("H2E", "- Addr2: %02x:%02x:%02x:%02x:%02x:%02x", + addr2[0], addr2[1], addr2[2], addr2[3], addr2[4], addr2[5]); + + struct sae_pt *pt = sae_derive_pt(NULL, (const u8 *)ssid, ssid_len, + (const u8 *)password, strlen(password), NULL); + TEST_ASSERT_MESSAGE(pt != NULL, "Failed to derive PT"); + TEST_ASSERT_MESSAGE(sae_prepare_commit_pt(&sae, pt, addr1, addr2, NULL, NULL) == 0, + "Failed to prepare SAE commit with password"); + sae.state = SAE_NOTHING; + ESP_LOGI("H2E", "- After commit prep: h2e=%d, tmp=%p", sae.h2e, (void*)sae.tmp); + TEST_ASSERT_MESSAGE(sae.h2e == 1, "H2E state not maintained after commit preparation"); + TEST_ASSERT_MESSAGE(sae.tmp != NULL, "Temporary data not allocated"); + + /* Step 3: Test commit message validation */ + ESP_LOGI("H2E", "\nStep 3: Testing commit message validation"); + buf = wpabuf_alloc(1000); + ESP_LOGI("H2E", "- Allocated buffer size: 1000 bytes"); + TEST_ASSERT_MESSAGE(buf != NULL, "Failed to allocate commit message buffer"); + + TEST_ASSERT_MESSAGE(sae_write_commit(&sae, buf, NULL, NULL) == 0, + "Failed to write SAE commit message"); + sae.state = SAE_COMMITTED; + ESP_LOGI("H2E", "- Commit message length: %zu bytes", wpabuf_len(buf)); + TEST_ASSERT_MESSAGE(wpabuf_len(buf) > 0, "Commit message length is zero"); + + ESP_LOGI("H2E", "- Parsing commit message..."); + /* Reset SAE context for parsing */ + sae_clear_data(&sae); + memset(&sae, 0, sizeof(sae)); + + /* Initialize SAE parameters for parsing */ + TEST_ASSERT_MESSAGE(sae_set_group(&sae, IANA_SECP256R1) == 0, "Failed to set SAE group for parsing"); + sae.h2e = 1; + sae.state = SAE_COMMITTED; + + /* Parse the commit message */ + TEST_ASSERT_MESSAGE(sae_parse_commit(&sae, wpabuf_head(buf), wpabuf_len(buf), + NULL, NULL, NULL, 1) == 0, + "Failed to parse SAE commit message"); + TEST_ASSERT_MESSAGE(sae.peer_commit_scalar != NULL, + "Peer commit scalar not parsed"); + TEST_ASSERT_MESSAGE(sae.tmp != NULL && + (sae.tmp->peer_commit_element_ecc != NULL || sae.tmp->peer_commit_element_ffc != NULL), + "Peer commit element not parsed"); + ESP_LOGI("H2E", "- Commit message parsed successfully"); + + /* Cleanup */ + if (buf) { + wpabuf_free(buf); + buf = NULL; + } + + /* Free SAE PT data */ + if (pt) { + sae_deinit_pt(pt); + pt = NULL; + } + + sae_clear_data(&sae); +} + +#endif /* CONFIG_WPA3_SAE */