From 57d95ead73c7ebace715c4ff184e069398695e13 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 3 Apr 2026 16:35:47 +0530 Subject: [PATCH] ci(wpa_supplicant): Add UT for supplicant crypto --- components/esp_wifi/Kconfig | 2 +- .../src/crypto/crypto_mbedtls-ec.c | 44 +- components/wpa_supplicant/src/common/dpp.c | 61 ++ components/wpa_supplicant/src/common/dpp.h | 11 + .../test_apps/main/CMakeLists.txt | 6 +- .../test_apps/main/test_crypto.c | 693 +++++++++++++++++- .../wpa_supplicant/test_apps/main/test_dpp.c | 168 ++++- .../wpa_supplicant/test_apps/main/test_sae.c | 60 +- .../test_apps/main/test_wpa_supplicant_main.c | 2 +- .../test_apps/sdkconfig.defaults | 2 + 10 files changed, 1021 insertions(+), 28 deletions(-) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 18db4d14e0e..ce144e54b19 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -633,7 +633,7 @@ menu "Wi-Fi" config ESP_WIFI_P256_ACCEL bool "Enable P-256 crypto acceleration" depends on ESP_WIFI_MBEDTLS_CRYPTO - default y + default n help Enable Espressif-specific P-256 acceleration in the WPA supplicant crypto layer. This reduces SAE and DPP latency on supported targets 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 4f64fda97b2..e1e011ffb9f 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 @@ -604,6 +604,12 @@ static void p256_fast_point_from_affine(p256_fast_jac_point *p, os_memcpy(p->Z, one_mont, sizeof(p->Z)); } +#define P256_WINDOW_BITS 4U +#define P256_WINDOW_ENTRY_COUNT (1U << P256_WINDOW_BITS) +#define P256_WINDOW_PRECOMP_COUNT (P256_WINDOW_ENTRY_COUNT - 1U) +#define P256_WINDOW_BATCH_COUNT (P256_WINDOW_PRECOMP_COUNT - 1U) +#define P256_SCALAR_WINDOW_COUNT ((P256_WORDS * 32U) / P256_WINDOW_BITS) + static void p256_fast_point_double(p256_fast_jac_point *r) { u32 z2[P256_WORDS], y2[P256_WORDS], y4[P256_WORDS]; @@ -739,7 +745,7 @@ static int p256_fast_points_batch_to_affine_mont( const p256_fast_jac_point *points, size_t num, u32(*xs)[P256_WORDS], u32(*ys)[P256_WORDS]) { - u32 prefix[14][P256_WORDS]; + u32 prefix[P256_WINDOW_BATCH_COUNT][P256_WORDS]; u32 prod_std[P256_WORDS], inv_std[P256_WORDS]; u32 running_inv[P256_WORDS], inv_z[P256_WORDS]; u32 tmp[P256_WORDS]; @@ -789,9 +795,9 @@ static int p256_fast_points_batch_to_affine_mont( } struct p256_window4_scratch { - p256_fast_jac_point precomp[15]; - u32 table_x[16][P256_WORDS]; - u32 table_y[16][P256_WORDS]; + p256_fast_jac_point precomp[P256_WINDOW_PRECOMP_COUNT]; + u32 table_x[P256_WINDOW_ENTRY_COUNT][P256_WORDS]; + u32 table_y[P256_WINDOW_ENTRY_COUNT][P256_WORDS]; }; static int crypto_ec_point_mul_p256_window4_core(const mbedtls_ecp_group *grp, @@ -846,14 +852,15 @@ static int crypto_ec_point_mul_p256_window4_core(const mbedtls_ecp_group *grp, p256_fast_point_from_affine(&scratch->precomp[0], x_mont, y_mont, one_mont); os_memcpy(&scratch->precomp[1], &scratch->precomp[0], sizeof(scratch->precomp[1])); p256_fast_point_double(&scratch->precomp[1]); - for (window = 2; window < 15; window++) { + for (window = 2; window < P256_WINDOW_PRECOMP_COUNT; window++) { os_memcpy(&scratch->precomp[window], &scratch->precomp[window - 1], sizeof(scratch->precomp[window])); p256_fast_point_add_mixed(&scratch->precomp[window], x_mont, y_mont, one_mont); } - if (p256_fast_points_batch_to_affine_mont(&scratch->precomp[1], 14, + if (p256_fast_points_batch_to_affine_mont(&scratch->precomp[1], + P256_WINDOW_BATCH_COUNT, &scratch->table_x[2], &scratch->table_y[2]) != 0) { ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; @@ -862,14 +869,17 @@ static int crypto_ec_point_mul_p256_window4_core(const mbedtls_ecp_group *grp, p256_fast_point_set_zero(r); - for (window = 63; window >= 0; window--) { - u32 idx = p256_words_get_window(scalar, (unsigned) window * 4, 4); + for (window = P256_SCALAR_WINDOW_COUNT - 1; window >= 0; window--) { + u32 idx = p256_words_get_window(scalar, + (unsigned) window * P256_WINDOW_BITS, + P256_WINDOW_BITS); if (started) { - p256_fast_point_double(r); - p256_fast_point_double(r); - p256_fast_point_double(r); - p256_fast_point_double(r); + unsigned int dbl; + + for (dbl = 0; dbl < P256_WINDOW_BITS; dbl++) { + p256_fast_point_double(r); + } } if (idx == 0U) { @@ -1001,9 +1011,7 @@ static int crypto_ec_point_mul_fast(const mbedtls_ecp_group *grp, if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) { return ret; } -#endif - -#if ESP_WIFI_P256_SOFT_ACCEL +#elif ESP_WIFI_P256_SOFT_ACCEL if (crypto_ec_is_p256_group(grp)) { return crypto_ec_point_mul_p256_jacobian_fast(grp, p, k, res); } @@ -1152,7 +1160,6 @@ struct crypto_bignum *crypto_ec_point_compute_y_sqr(struct crypto_ec *e, (const struct crypto_bignum *) &grp->P, (struct crypto_bignum *) &temp)); -#if CONFIG_ESP_WIFI_P256_ACCEL if (mbedtls_ecp_group_a_is_minus_3(grp)) { /* * For NIST P-curves used in SAE, a == -3. Compute (-3x + b) mod p @@ -1178,11 +1185,6 @@ struct crypto_bignum *crypto_ec_point_compute_y_sqr(struct crypto_ec *e, &grp->A)); MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &grp->P)); } -#else - MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *) x, - &grp->A)); - MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &grp->P)); -#endif MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &grp->B)); while (mbedtls_mpi_cmp_mpi(&temp2, &grp->P) >= 0) { diff --git a/components/wpa_supplicant/src/common/dpp.c b/components/wpa_supplicant/src/common/dpp.c index 7fa67d10fa3..64665b7a95b 100644 --- a/components/wpa_supplicant/src/common/dpp.c +++ b/components/wpa_supplicant/src/common/dpp.c @@ -44,6 +44,42 @@ struct dpp_global { extern struct dpp_curve_params dpp_curves[]; +#ifdef CONFIG_TESTING_OPTIONS +u64 dpp_last_auth_req_parse_us; +u64 dpp_last_auth_resp_form_us; +u64 dpp_last_auth_req_total_us; + +static u64 dpp_time_us(void) +{ + struct os_reltime now; + + if (os_get_reltime(&now) < 0) + return 0; + + return ((u64) now.sec * 1000000) + now.usec; +} + +static void dpp_auth_req_set_timing(struct dpp_authentication *auth, + u64 start_us, u64 parse_done_us) +{ + u64 end_us; + + if (!auth || !start_us || !parse_done_us || parse_done_us < start_us) + return; + + end_us = dpp_time_us(); + if (!end_us || end_us < parse_done_us) + return; + + auth->auth_req_parse_us = parse_done_us - start_us; + auth->auth_resp_form_us = end_us - parse_done_us; + auth->auth_req_total_us = end_us - start_us; + dpp_last_auth_req_parse_us = auth->auth_req_parse_us; + dpp_last_auth_resp_form_us = auth->auth_resp_form_us; + dpp_last_auth_req_total_us = auth->auth_req_total_us; +} +#endif + #define TRANSACTION_ID_ATTR_SET_LEN 5 #define CONNECTOR_ATTR_SET_LEN 4 @@ -1707,6 +1743,13 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, u16 i_capab_len; u16 i_bootstrap_len; struct dpp_authentication *auth = NULL; +#ifdef CONFIG_TESTING_OPTIONS + u64 start_us = dpp_time_us(); + u64 parse_done_us = 0; + dpp_last_auth_req_parse_us = 0; + dpp_last_auth_resp_form_us = 0; + dpp_last_auth_req_total_us = 0; +#endif #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) { @@ -1892,9 +1935,15 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, wpa_printf(MSG_DEBUG, "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time"); +#ifdef CONFIG_TESTING_OPTIONS + parse_done_us = dpp_time_us(); +#endif if (dpp_auth_build_resp_status(auth, DPP_STATUS_RESPONSE_PENDING) < 0) goto fail; +#ifdef CONFIG_TESTING_OPTIONS + dpp_auth_req_set_timing(auth, start_us, parse_done_us); +#endif i_bootstrap = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, &i_bootstrap_len); @@ -1912,8 +1961,14 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, "%s", hex); return auth; } +#ifdef CONFIG_TESTING_OPTIONS + parse_done_us = dpp_time_us(); +#endif if (dpp_auth_build_resp_ok(auth) < 0) goto fail; +#ifdef CONFIG_TESTING_OPTIONS + dpp_auth_req_set_timing(auth, start_us, parse_done_us); +#endif return auth; @@ -1926,8 +1981,14 @@ not_compatible: auth->configurator = 0; auth->peer_protocol_key = pi; pi = NULL; +#ifdef CONFIG_TESTING_OPTIONS + parse_done_us = dpp_time_us(); +#endif if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0) goto fail; +#ifdef CONFIG_TESTING_OPTIONS + dpp_auth_req_set_timing(auth, start_us, parse_done_us); +#endif auth->remove_on_tx_status = 1; return auth; diff --git a/components/wpa_supplicant/src/common/dpp.h b/components/wpa_supplicant/src/common/dpp.h index 84a9416ae9b..c2464546a8f 100644 --- a/components/wpa_supplicant/src/common/dpp.h +++ b/components/wpa_supplicant/src/common/dpp.h @@ -317,8 +317,19 @@ struct dpp_authentication { char *groups_override; unsigned int ignore_netaccesskey_mismatch:1; #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_TESTING_OPTIONS + u64 auth_req_parse_us; + u64 auth_resp_form_us; + u64 auth_req_total_us; +#endif }; +#ifdef CONFIG_TESTING_OPTIONS +extern u64 dpp_last_auth_req_parse_us; +extern u64 dpp_last_auth_resp_form_us; +extern u64 dpp_last_auth_req_total_us; +#endif + struct dpp_configurator { struct dl_list list; unsigned int id; diff --git a/components/wpa_supplicant/test_apps/main/CMakeLists.txt b/components/wpa_supplicant/test_apps/main/CMakeLists.txt index 5dcdf7b250e..e0a1935f31c 100644 --- a/components/wpa_supplicant/test_apps/main/CMakeLists.txt +++ b/components/wpa_supplicant/test_apps/main/CMakeLists.txt @@ -7,7 +7,7 @@ idf_component_register(SRCS "test_sae.c" "test_wpa_supplicant_main.c" PRIV_INCLUDE_DIRS "." - PRIV_REQUIRES wpa_supplicant mbedtls esp_wifi esp_event unity + PRIV_REQUIRES wpa_supplicant mbedtls esp_wifi esp_event unity esp_psram esp_timer WHOLE_ARCHIVE) idf_component_get_property(esp_supplicant_dir wpa_supplicant COMPONENT_DIR) @@ -23,3 +23,7 @@ target_include_directories(${COMPONENT_LIB} PRIVATE ${esp_supplicant_dir}/src) add_definitions(-DWIFI_SUPPLICANT_MD5=\"${WIFI_SUPPLICANT_MD5}\") add_definitions(-DCONFIG_WPA3_SAE) add_definitions(-DCONFIG_DPP) + +if(CONFIG_ESP_WIFI_TESTING_OPTIONS) + target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_TESTING_OPTIONS) +endif() diff --git a/components/wpa_supplicant/test_apps/main/test_crypto.c b/components/wpa_supplicant/test_apps/main/test_crypto.c index 23f14b8da52..dfcd3cfef5c 100644 --- a/components/wpa_supplicant/test_apps/main/test_crypto.c +++ b/components/wpa_supplicant/test_apps/main/test_crypto.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,12 +14,211 @@ #include "utils/includes.h" #include "crypto/crypto.h" +#include "esp_timer.h" +#include "mbedtls/ecdh.h" #include "mbedtls/ecp.h" +#include "mbedtls/pk.h" #include "test_utils.h" #include "test_wpa_supplicant_common.h" typedef struct crypto_bignum crypto_bignum; +static const uint8_t test_secp256r1_prime[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, 0xff +}; + +static const uint8_t test_p256_bignum_vals[][32] = { + { + 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, + 0xca, 0xfe, 0xba, 0xbe, 0x88, 0x99, 0xaa, 0xbb, + 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, + 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 + }, + { + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x0f, 0xed, 0xcb, 0xa9, 0x87, 0x65, 0x43, 0x21, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }, + { + 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, + 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, + 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, + 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0 + } +}; + +static const uint8_t test_p256_scalar_seeds[][32] = { + { + 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef, + 0xca, 0xfe, 0xba, 0xbe, 0x88, 0x99, 0xaa, 0xbb, + 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, + 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 + }, + { + 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, + 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, + 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, + 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0 + }, + { + 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78, + 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, 0xf0, + 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, + 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f + } +}; + +static const unsigned int test_p256_point_multipliers[] = { 7, 13 }; +static const unsigned int test_small_exponents[] = { 0, 1, 2, 3 }; + +static int test_mbedtls_rng(void *ctx, unsigned char *buf, size_t len) +{ + (void) ctx; + return os_get_random(buf, len) == 0 ? 0 : MBEDTLS_ERR_ECP_RANDOM_FAILED; +} + +static void test_load_valid_p256_scalar(const mbedtls_ecp_group *grp, + const uint8_t *seed, size_t seed_len, + mbedtls_mpi *scalar) +{ + mbedtls_mpi range; + + mbedtls_mpi_init(&range); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_sub_int(&range, &grp->N, 1)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_read_binary(scalar, seed, seed_len)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mod_mpi(scalar, scalar, &range)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_add_int(scalar, scalar, 1)); + mbedtls_mpi_free(&range); +} + +static void test_make_p256_affine_point(mbedtls_ecp_group *grp, + unsigned int multiplier, + mbedtls_ecp_point *point) +{ + mbedtls_mpi k; + + mbedtls_mpi_init(&k); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_lset(&k, multiplier)); + TEST_ASSERT_EQUAL(0, mbedtls_ecp_mul(grp, point, &k, &grp->G, + test_mbedtls_rng, NULL)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_cmp_int(&point->MBEDTLS_PRIVATE(Z), 1)); + mbedtls_mpi_free(&k); +} + +static int test_legendre_reference(const mbedtls_mpi *a, const mbedtls_mpi *p) +{ + mbedtls_mpi a_mod, exp, res, one, pm1; + int legendre = -2; + + mbedtls_mpi_init(&a_mod); + mbedtls_mpi_init(&exp); + mbedtls_mpi_init(&res); + mbedtls_mpi_init(&one); + mbedtls_mpi_init(&pm1); + + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mod_mpi(&a_mod, a, p)); + if (mbedtls_mpi_cmp_int(&a_mod, 0) == 0) { + legendre = 0; + goto cleanup; + } + + TEST_ASSERT_EQUAL(0, mbedtls_mpi_copy(&exp, p)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_sub_int(&exp, &exp, 1)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_shift_r(&exp, 1)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_exp_mod(&res, &a_mod, &exp, p, NULL)); + + TEST_ASSERT_EQUAL(0, mbedtls_mpi_lset(&one, 1)); + if (mbedtls_mpi_cmp_mpi(&res, &one) == 0) { + legendre = 1; + goto cleanup; + } + + TEST_ASSERT_EQUAL(0, mbedtls_mpi_copy(&pm1, p)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_sub_int(&pm1, &pm1, 1)); + if (mbedtls_mpi_cmp_mpi(&res, &pm1) == 0) { + legendre = -1; + goto cleanup; + } + + TEST_FAIL_MESSAGE("Unexpected Legendre reference result"); + +cleanup: + mbedtls_mpi_free(&a_mod); + mbedtls_mpi_free(&exp); + mbedtls_mpi_free(&res); + mbedtls_mpi_free(&one); + mbedtls_mpi_free(&pm1); + return legendre; +} + +static void test_print_crypto_timing(const char *label, + int64_t generic_total_us, size_t generic_ops, + int64_t api_total_us, size_t api_ops) +{ + long long generic_avg = generic_ops ? (long long)(generic_total_us / (int64_t) generic_ops) : 0; + long long api_avg = api_ops ? (long long)(api_total_us / (int64_t) api_ops) : 0; + + printf("%s timing(us): generic_avg=%lld api_avg=%lld generic_total=%lld api_total=%lld ops=%u\n", + label, generic_avg, api_avg, + (long long) generic_total_us, (long long) api_total_us, + (unsigned int) api_ops); +} + +static int test_mbedtls_ecdh(const struct crypto_ec_key *key_own, + const struct crypto_ec_key *key_peer, + u8 *secret, size_t *secret_len) +{ + mbedtls_ecdh_context ctx; + mbedtls_pk_context *own = (mbedtls_pk_context *) key_own; + mbedtls_pk_context *peer = (mbedtls_pk_context *) key_peer; + int ret = -1; + + mbedtls_ecdh_init(&ctx); + + if (mbedtls_ecdh_get_params(&ctx, mbedtls_pk_ec(*own), + MBEDTLS_ECDH_OURS) != 0) { + goto out; + } + + if (mbedtls_ecdh_get_params(&ctx, mbedtls_pk_ec(*peer), + MBEDTLS_ECDH_THEIRS) != 0) { + goto out; + } + + if (mbedtls_ecdh_calc_secret(&ctx, secret_len, secret, 66, + test_mbedtls_rng, NULL) != 0) { + goto out; + } + + ret = 0; + +out: + mbedtls_ecdh_free(&ctx); + return ret; +} + +static int test_mbedtls_key_gen_p256(mbedtls_pk_context *kctx) +{ + mbedtls_pk_init(kctx); + + if (mbedtls_pk_setup(kctx, + mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) != 0) { + return -1; + } + + if (mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*kctx), + test_mbedtls_rng, NULL) != 0) { + mbedtls_pk_free(kctx); + return -1; + } + + return 0; +} + TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") { set_leak_threshold(300); @@ -203,6 +402,38 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") } + { /** BN mul mod on secp256r1 prime */ + uint8_t val[32]; + uint8_t one[32] = {0}; + crypto_bignum *bn1, *bn2, *bn3, *mulmod; + + one[0] = 1; + os_memcpy(val, test_secp256r1_prime, sizeof(val)); + val[31]--; + + mulmod = crypto_bignum_init(); + TEST_ASSERT_NOT_NULL(mulmod); + + bn1 = crypto_bignum_init_set(val, sizeof(val)); + TEST_ASSERT_NOT_NULL(bn1); + + bn2 = crypto_bignum_init_set(val, sizeof(val)); + TEST_ASSERT_NOT_NULL(bn2); + + bn3 = crypto_bignum_init_set(test_secp256r1_prime, + sizeof(test_secp256r1_prime)); + TEST_ASSERT_NOT_NULL(bn3); + + TEST_ASSERT(crypto_bignum_mulmod(bn1, bn2, bn3, mulmod) == 0); + TEST_ASSERT(crypto_bignum_to_bin(mulmod, val, sizeof(val), 0) == 1); + TEST_ASSERT_EQUAL_UINT8_ARRAY(one, val, 1); + + crypto_bignum_deinit(bn1, 1); + crypto_bignum_deinit(bn2, 1); + crypto_bignum_deinit(bn3, 1); + crypto_bignum_deinit(mulmod, 1); + } + { /** BN exp mod*/ uint8_t buf1[32], buf2[32], buf3[32], buf4[32], buf5[32]; @@ -273,6 +504,84 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") crypto_bignum_deinit(bn2, 1); } + + { /** BN Legendre symbol test on secp256r1 prime */ + uint8_t val[32] = {0}; + crypto_bignum *bn_val, *bn_p; + + bn_p = crypto_bignum_init_set(test_secp256r1_prime, + sizeof(test_secp256r1_prime)); + TEST_ASSERT_NOT_NULL(bn_p); + + val[31] = 1; + bn_val = crypto_bignum_init_set(val, sizeof(val)); + TEST_ASSERT_NOT_NULL(bn_val); + TEST_ASSERT(crypto_bignum_legendre(bn_val, bn_p) == 1); + crypto_bignum_deinit(bn_val, 1); + + os_memset(val, 0, sizeof(val)); + val[31] = 3; + bn_val = crypto_bignum_init_set(val, sizeof(val)); + TEST_ASSERT_NOT_NULL(bn_val); + TEST_ASSERT(crypto_bignum_legendre(bn_val, bn_p) == -1); + crypto_bignum_deinit(bn_val, 1); + + os_memset(val, 0, sizeof(val)); + bn_val = crypto_bignum_init_set(val, sizeof(val)); + TEST_ASSERT_NOT_NULL(bn_val); + TEST_ASSERT(crypto_bignum_legendre(bn_val, bn_p) == 0); + crypto_bignum_deinit(bn_val, 1); + + crypto_bignum_deinit(bn_p, 1); + } +} + +TEST_CASE("Test secp256r1 fast bignum paths against mbedtls reference", "[wpa_crypto]") +{ + crypto_bignum *bn_p; + int i; + + set_leak_threshold(620); + + bn_p = crypto_bignum_init_set(test_secp256r1_prime, + sizeof(test_secp256r1_prime)); + TEST_ASSERT_NOT_NULL(bn_p); + + for (i = 0; i < ARRAY_SIZE(test_p256_bignum_vals); i++) { + crypto_bignum *bn_a = crypto_bignum_init_set(test_p256_bignum_vals[i], sizeof(test_p256_bignum_vals[i])); + crypto_bignum *bn_b = crypto_bignum_init_set( + test_p256_bignum_vals[(i + 1) % ARRAY_SIZE(test_p256_bignum_vals)], + sizeof(test_p256_bignum_vals[0])); + crypto_bignum *bn_mul = crypto_bignum_init(); + mbedtls_mpi ref_mul; + int ref_legendre; + + TEST_ASSERT_NOT_NULL(bn_a); + TEST_ASSERT_NOT_NULL(bn_b); + TEST_ASSERT_NOT_NULL(bn_mul); + + mbedtls_mpi_init(&ref_mul); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mul_mpi(&ref_mul, + (const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_b)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mod_mpi(&ref_mul, &ref_mul, + (const mbedtls_mpi *) bn_p)); + + TEST_ASSERT_EQUAL(0, crypto_bignum_mulmod(bn_a, bn_b, bn_p, bn_mul)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_cmp_mpi((const mbedtls_mpi *) bn_mul, + &ref_mul)); + + ref_legendre = test_legendre_reference((const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_p); + TEST_ASSERT_EQUAL(ref_legendre, crypto_bignum_legendre(bn_a, bn_p)); + + mbedtls_mpi_free(&ref_mul); + crypto_bignum_deinit(bn_a, 1); + crypto_bignum_deinit(bn_b, 1); + crypto_bignum_deinit(bn_mul, 1); + } + + crypto_bignum_deinit(bn_p, 1); } /* @@ -536,3 +845,385 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") } } + +TEST_CASE("Test secp256r1 point multiply against mbedtls reference", "[wpa_crypto]") +{ + struct crypto_ec *e; + struct crypto_ec_point *p = NULL; + struct crypto_ec_point *res = NULL; + mbedtls_ecp_point ref; + int i, j; + + set_leak_threshold(620); + + e = crypto_ec_init(19); + TEST_ASSERT_NOT_NULL(e); + + p = crypto_ec_point_init(e); + TEST_ASSERT_NOT_NULL(p); + res = crypto_ec_point_init(e); + TEST_ASSERT_NOT_NULL(res); + mbedtls_ecp_point_init(&ref); + + for (i = 0; i < ARRAY_SIZE(test_p256_point_multipliers); i++) { + test_make_p256_affine_point((mbedtls_ecp_group *) e, + test_p256_point_multipliers[i], + (mbedtls_ecp_point *) p); + + for (j = 0; j < ARRAY_SIZE(test_p256_scalar_seeds); j++) { + mbedtls_mpi scalar; + + mbedtls_mpi_init(&scalar); + test_load_valid_p256_scalar((const mbedtls_ecp_group *) e, + test_p256_scalar_seeds[j], + sizeof(test_p256_scalar_seeds[j]), + &scalar); + + TEST_ASSERT_EQUAL(0, crypto_ec_point_mul(e, p, + (struct crypto_bignum *) &scalar, + res)); + TEST_ASSERT_EQUAL(0, mbedtls_ecp_mul((mbedtls_ecp_group *) e, + &ref, &scalar, + (const mbedtls_ecp_point *) p, + test_mbedtls_rng, NULL)); + TEST_ASSERT_EQUAL(0, crypto_ec_point_cmp(e, res, + (const struct crypto_ec_point *) &ref)); + + mbedtls_mpi_free(&scalar); + } + } + + mbedtls_ecp_point_free(&ref); + crypto_ec_point_deinit(p, 1); + crypto_ec_point_deinit(res, 1); + crypto_ec_deinit(e); +} + +TEST_CASE("Measure secp256r1 bignum API timings against mbedtls reference", "[wpa_crypto]") +{ + const unsigned int loops = 64; + crypto_bignum *bn_p; + int64_t generic_total_us = 0; + int64_t api_total_us = 0; + size_t ops = 0; + int i, loop; + + set_leak_threshold(700); + + bn_p = crypto_bignum_init_set(test_secp256r1_prime, + sizeof(test_secp256r1_prime)); + TEST_ASSERT_NOT_NULL(bn_p); + + for (i = 0; i < ARRAY_SIZE(test_p256_bignum_vals); i++) { + crypto_bignum *bn_a = crypto_bignum_init_set(test_p256_bignum_vals[i], + sizeof(test_p256_bignum_vals[i])); + crypto_bignum *bn_b = crypto_bignum_init_set( + test_p256_bignum_vals[(i + 1) % ARRAY_SIZE(test_p256_bignum_vals)], + sizeof(test_p256_bignum_vals[0])); + crypto_bignum *bn_mul = crypto_bignum_init(); + mbedtls_mpi ref_mul; + int ref_legendre; + + TEST_ASSERT_NOT_NULL(bn_a); + TEST_ASSERT_NOT_NULL(bn_b); + TEST_ASSERT_NOT_NULL(bn_mul); + + mbedtls_mpi_init(&ref_mul); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mul_mpi(&ref_mul, + (const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_b)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mod_mpi(&ref_mul, &ref_mul, + (const mbedtls_mpi *) bn_p)); + TEST_ASSERT_EQUAL(0, crypto_bignum_mulmod(bn_a, bn_b, bn_p, bn_mul)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_cmp_mpi((const mbedtls_mpi *) bn_mul, + &ref_mul)); + ref_legendre = test_legendre_reference((const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_p); + TEST_ASSERT_EQUAL(ref_legendre, crypto_bignum_legendre(bn_a, bn_p)); + + for (loop = 0; loop < loops; loop++) { + int64_t start_us = esp_timer_get_time(); + + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mul_mpi(&ref_mul, + (const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_b)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_mod_mpi(&ref_mul, &ref_mul, + (const mbedtls_mpi *) bn_p)); + generic_total_us += esp_timer_get_time() - start_us; + } + + for (loop = 0; loop < loops; loop++) { + int64_t start_us = esp_timer_get_time(); + + TEST_ASSERT_EQUAL(0, crypto_bignum_mulmod(bn_a, bn_b, bn_p, bn_mul)); + api_total_us += esp_timer_get_time() - start_us; + } + + ops += loops; + mbedtls_mpi_free(&ref_mul); + crypto_bignum_deinit(bn_a, 1); + crypto_bignum_deinit(bn_b, 1); + crypto_bignum_deinit(bn_mul, 1); + } + + test_print_crypto_timing("secp256r1 mulmod", generic_total_us, ops, + api_total_us, ops); + + generic_total_us = 0; + api_total_us = 0; + ops = 0; + + for (i = 0; i < ARRAY_SIZE(test_small_exponents); i++) { + crypto_bignum *bn_exp = crypto_bignum_init_uint(test_small_exponents[i]); + char label[48]; + + TEST_ASSERT_NOT_NULL(bn_exp); + + generic_total_us = 0; + api_total_us = 0; + ops = 0; + + for (loop = 0; loop < ARRAY_SIZE(test_p256_bignum_vals); loop++) { + crypto_bignum *bn_a = crypto_bignum_init_set(test_p256_bignum_vals[loop], + sizeof(test_p256_bignum_vals[loop])); + crypto_bignum *bn_res = crypto_bignum_init(); + mbedtls_mpi ref_res; + int iter; + + TEST_ASSERT_NOT_NULL(bn_a); + TEST_ASSERT_NOT_NULL(bn_res); + + mbedtls_mpi_init(&ref_res); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_exp_mod(&ref_res, + (const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_exp, + (const mbedtls_mpi *) bn_p, + NULL)); + TEST_ASSERT_EQUAL(0, crypto_bignum_exptmod(bn_a, bn_exp, bn_p, + bn_res)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_cmp_mpi((const mbedtls_mpi *) bn_res, + &ref_res)); + + for (iter = 0; iter < loops; iter++) { + int64_t start_us = esp_timer_get_time(); + + TEST_ASSERT_EQUAL(0, mbedtls_mpi_exp_mod(&ref_res, + (const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_exp, + (const mbedtls_mpi *) bn_p, + NULL)); + generic_total_us += esp_timer_get_time() - start_us; + } + + for (iter = 0; iter < loops; iter++) { + int64_t start_us = esp_timer_get_time(); + + TEST_ASSERT_EQUAL(0, crypto_bignum_exptmod(bn_a, bn_exp, bn_p, + bn_res)); + api_total_us += esp_timer_get_time() - start_us; + } + + ops += loops; + mbedtls_mpi_free(&ref_res); + crypto_bignum_deinit(bn_a, 1); + crypto_bignum_deinit(bn_res, 1); + } + + snprintf(label, sizeof(label), "secp256r1 exptmod e=%u", + test_small_exponents[i]); + test_print_crypto_timing(label, generic_total_us, ops, + api_total_us, ops); + crypto_bignum_deinit(bn_exp, 1); + } + + generic_total_us = 0; + api_total_us = 0; + ops = 0; + + for (i = 0; i < ARRAY_SIZE(test_p256_bignum_vals); i++) { + crypto_bignum *bn_a = crypto_bignum_init_set(test_p256_bignum_vals[i], + sizeof(test_p256_bignum_vals[i])); + TEST_ASSERT_NOT_NULL(bn_a); + + TEST_ASSERT_EQUAL(test_legendre_reference((const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_p), + crypto_bignum_legendre(bn_a, bn_p)); + + for (loop = 0; loop < loops; loop++) { + int64_t start_us = esp_timer_get_time(); + + (void) test_legendre_reference((const mbedtls_mpi *) bn_a, + (const mbedtls_mpi *) bn_p); + generic_total_us += esp_timer_get_time() - start_us; + } + + for (loop = 0; loop < loops; loop++) { + int64_t start_us = esp_timer_get_time(); + + (void) crypto_bignum_legendre(bn_a, bn_p); + api_total_us += esp_timer_get_time() - start_us; + } + + ops += loops; + crypto_bignum_deinit(bn_a, 1); + } + + test_print_crypto_timing("secp256r1 legendre", generic_total_us, ops, + api_total_us, ops); + + crypto_bignum_deinit(bn_p, 1); +} + +TEST_CASE("Measure secp256r1 EC API timings against mbedtls reference", "[wpa_crypto]") +{ + const unsigned int point_mul_loops = 4; + const unsigned int key_gen_loops = 4; + const unsigned int ecdh_loops = 4; + struct crypto_ec *e; + struct crypto_ec_point *p = NULL; + struct crypto_ec_point *res = NULL; + mbedtls_ecp_point ref; + int64_t generic_total_us = 0; + int64_t api_total_us = 0; + size_t ops = 0; + int i, j, loop; + + set_leak_threshold(900); + + e = crypto_ec_init(19); + TEST_ASSERT_NOT_NULL(e); + + p = crypto_ec_point_init(e); + TEST_ASSERT_NOT_NULL(p); + res = crypto_ec_point_init(e); + TEST_ASSERT_NOT_NULL(res); + mbedtls_ecp_point_init(&ref); + + for (i = 0; i < ARRAY_SIZE(test_p256_point_multipliers); i++) { + test_make_p256_affine_point((mbedtls_ecp_group *) e, + test_p256_point_multipliers[i], + (mbedtls_ecp_point *) p); + + for (j = 0; j < ARRAY_SIZE(test_p256_scalar_seeds); j++) { + mbedtls_mpi scalar; + + mbedtls_mpi_init(&scalar); + test_load_valid_p256_scalar((const mbedtls_ecp_group *) e, + test_p256_scalar_seeds[j], + sizeof(test_p256_scalar_seeds[j]), + &scalar); + + TEST_ASSERT_EQUAL(0, crypto_ec_point_mul(e, p, + (struct crypto_bignum *) &scalar, + res)); + TEST_ASSERT_EQUAL(0, mbedtls_ecp_mul((mbedtls_ecp_group *) e, + &ref, &scalar, + (const mbedtls_ecp_point *) p, + test_mbedtls_rng, NULL)); + TEST_ASSERT_EQUAL(0, crypto_ec_point_cmp(e, res, + (const struct crypto_ec_point *) &ref)); + + for (loop = 0; loop < point_mul_loops; loop++) { + int64_t start_us = esp_timer_get_time(); + + TEST_ASSERT_EQUAL(0, mbedtls_ecp_mul((mbedtls_ecp_group *) e, + &ref, &scalar, + (const mbedtls_ecp_point *) p, + test_mbedtls_rng, NULL)); + generic_total_us += esp_timer_get_time() - start_us; + } + + for (loop = 0; loop < point_mul_loops; loop++) { + int64_t start_us = esp_timer_get_time(); + + TEST_ASSERT_EQUAL(0, crypto_ec_point_mul(e, p, + (struct crypto_bignum *) &scalar, + res)); + api_total_us += esp_timer_get_time() - start_us; + } + + ops += point_mul_loops; + mbedtls_mpi_free(&scalar); + } + } + + test_print_crypto_timing("secp256r1 point_mul", generic_total_us, ops, + api_total_us, ops); + + generic_total_us = 0; + api_total_us = 0; + + for (loop = 0; loop < key_gen_loops; loop++) { + mbedtls_pk_context kctx; + int64_t start_us = esp_timer_get_time(); + + TEST_ASSERT_EQUAL(0, test_mbedtls_key_gen_p256(&kctx)); + generic_total_us += esp_timer_get_time() - start_us; + mbedtls_pk_free(&kctx); + } + + for (loop = 0; loop < key_gen_loops; loop++) { + struct crypto_ec_key *key; + int64_t start_us = esp_timer_get_time(); + + key = crypto_ec_key_gen(19); + TEST_ASSERT_NOT_NULL(key); + api_total_us += esp_timer_get_time() - start_us; + crypto_ec_key_deinit(key); + } + + test_print_crypto_timing("secp256r1 key_gen", generic_total_us, key_gen_loops, + api_total_us, key_gen_loops); + + { + struct crypto_ec_key *key_own = crypto_ec_key_gen(19); + struct crypto_ec_key *key_peer = crypto_ec_key_gen(19); + u8 secret_generic[66]; + u8 secret_api[66]; + size_t secret_generic_len = 0; + size_t secret_api_len = 0; + + TEST_ASSERT_NOT_NULL(key_own); + TEST_ASSERT_NOT_NULL(key_peer); + TEST_ASSERT_EQUAL(0, test_mbedtls_ecdh(key_own, key_peer, + secret_generic, + &secret_generic_len)); + TEST_ASSERT_EQUAL(0, crypto_ecdh(key_own, key_peer, + secret_api, &secret_api_len)); + TEST_ASSERT_EQUAL(secret_generic_len, secret_api_len); + TEST_ASSERT_EQUAL_MEMORY(secret_generic, secret_api, secret_api_len); + + generic_total_us = 0; + api_total_us = 0; + + for (loop = 0; loop < ecdh_loops; loop++) { + int64_t start_us = esp_timer_get_time(); + size_t secret_len = 0; + + TEST_ASSERT_EQUAL(0, test_mbedtls_ecdh(key_own, key_peer, + secret_generic, + &secret_len)); + generic_total_us += esp_timer_get_time() - start_us; + } + + for (loop = 0; loop < ecdh_loops; loop++) { + int64_t start_us = esp_timer_get_time(); + size_t secret_len = 0; + + TEST_ASSERT_EQUAL(0, crypto_ecdh(key_own, key_peer, + secret_api, &secret_len)); + api_total_us += esp_timer_get_time() - start_us; + } + + test_print_crypto_timing("secp256r1 ecdh", generic_total_us, ecdh_loops, + api_total_us, ecdh_loops); + + crypto_ec_key_deinit(key_own); + crypto_ec_key_deinit(key_peer); + } + + mbedtls_ecp_point_free(&ref); + crypto_ec_point_deinit(p, 1); + crypto_ec_point_deinit(res, 1); + crypto_ec_deinit(e); +} diff --git a/components/wpa_supplicant/test_apps/main/test_dpp.c b/components/wpa_supplicant/test_apps/main/test_dpp.c index 69b5176fe82..7cbd8a9e164 100644 --- a/components/wpa_supplicant/test_apps/main/test_dpp.c +++ b/components/wpa_supplicant/test_apps/main/test_dpp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include #include #include +#include #include "unity.h" #include #include "utils/common.h" @@ -18,8 +19,16 @@ #include "common/dpp.h" #include "sdkconfig.h" #include "test_wpa_supplicant_common.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #ifdef CONFIG_ESP_WIFI_TESTING_OPTIONS +static unsigned int dpp_test_task_stack_high_watermark_bytes(void) +{ + return (unsigned int)(uxTaskGetStackHighWaterMark(NULL) * + sizeof(StackType_t)); +} + struct dpp_global { void *msg_ctx; struct dl_list bootstrap; /* struct dpp_bootstrap_info */ @@ -32,9 +41,46 @@ extern u8 dpp_nonce_override[DPP_MAX_NONCE_LEN]; extern size_t dpp_nonce_override_len; #define MAX_FRAME_SIZE 1200 +static void dpp_test_clear_overrides(void) +{ + dpp_protocol_key_override_len = 0; + dpp_nonce_override_len = 0; + os_memset(dpp_protocol_key_override, 0, sizeof(dpp_protocol_key_override)); + os_memset(dpp_nonce_override, 0, sizeof(dpp_nonce_override)); +} + +static u32 dpp_test_prod_limit_us(void) +{ +#if CONFIG_MBEDTLS_HARDWARE_ECC + return 200000; +#else + return 425000; +#endif +} + +static int dpp_test_leak_threshold(void) +{ + return 800; +} + +static void dpp_test_log_auth_timing(const char *label, + const struct dpp_authentication *auth) +{ + TEST_ASSERT_NOT_NULL(auth); + + ESP_LOGI("DPP Test", + "%s timing(us): parse=%llu response_form=%llu total=%llu", + label, + (unsigned long long) auth->auth_req_parse_us, + (unsigned long long) auth->auth_resp_form_us, + (unsigned long long) auth->auth_req_total_us); + ESP_LOGI("DPP Test", "%s task stack high watermark(bytes): %u", + label, dpp_test_task_stack_high_watermark_bytes()); +} + TEST_CASE("Test vectors DPP responder p256", "[wpa_dpp]") { - set_leak_threshold(130); + set_leak_threshold(dpp_test_leak_threshold()); /* Global variables */ char command[1200] = {0}; const u8 *frame; @@ -66,6 +112,10 @@ TEST_CASE("Test vectors DPP responder p256", "[wpa_dpp]") sprintf(command, "type=qrcode key=%s", key); id = dpp_bootstrap_gen(dpp, command); uri = dpp_bootstrap_get_uri(dpp, id); + if (uri == NULL) { + ESP_LOGE("DPP Test", "Failed to get URI from bootstrap id"); + TEST_ASSERT(0); + } printf("uri is =%s\n", uri); printf("is be =%s\n", bootstrap_info); TEST_ASSERT((strcmp(uri, bootstrap_info) == 0)); @@ -129,6 +179,9 @@ TEST_CASE("Test vectors DPP responder p256", "[wpa_dpp]") len -= 26; auth_instance = dpp_auth_req_rx(NULL, 1, 0, NULL, dpp_bootstrap_get_id(dpp, id), 2412, frame, frame + 6, len - 6); + TEST_ASSERT_NOT_NULL(auth_instance); + TEST_ASSERT_NOT_NULL(auth_instance->resp_msg); + dpp_test_log_auth_timing("Vector responder", auth_instance); /* auth response u8 */ hex_len = os_strlen(auth_resp); @@ -172,7 +225,118 @@ TEST_CASE("Test vectors DPP responder p256", "[wpa_dpp]") { dpp_auth_deinit(auth_instance); dpp_global_deinit(dpp); + dpp_test_clear_overrides(); } ESP_LOGI("DPP Test", "Test case passed"); } + +TEST_CASE("Test DPP responder p256 production timing", "[wpa_dpp][performance]") +{ + struct dpp_global_config dpp_conf; + struct dpp_global *dpp = NULL; + struct dpp_bootstrap_info *responder_bi = NULL; + struct dpp_bootstrap_info *initiator_bi = NULL; + struct dpp_authentication *initiator_auth = NULL; + struct dpp_authentication *responder_auth = NULL; + struct wpabuf *conf = NULL; + const u8 *frame; + size_t len; + int responder_id; + int initiator_id; + u32 limit_us = dpp_test_prod_limit_us(); + u64 total_us = 0; + const char *failure = NULL; + + set_leak_threshold(dpp_test_leak_threshold()); + os_memset(&dpp_conf, 0, sizeof(dpp_conf)); + dpp = dpp_global_init(&dpp_conf); + if (!dpp) { + TEST_FAIL_MESSAGE("Failed to initialize DPP global context"); + } + + responder_id = dpp_bootstrap_gen(dpp, "type=qrcode curve=P-256"); + if (responder_id <= 0) { + failure = "Failed to generate responder bootstrap"; + goto cleanup; + } + initiator_id = dpp_bootstrap_gen(dpp, "type=qrcode curve=P-256"); + if (initiator_id <= 0) { + failure = "Failed to generate initiator bootstrap"; + goto cleanup; + } + + responder_bi = dpp_bootstrap_get_id(dpp, responder_id); + initiator_bi = dpp_bootstrap_get_id(dpp, initiator_id); + if (!responder_bi || !initiator_bi) { + failure = "Failed to resolve bootstrap info"; + goto cleanup; + } + + dpp_test_clear_overrides(); + initiator_auth = dpp_auth_init(NULL, responder_bi, initiator_bi, + DPP_CAPAB_CONFIGURATOR, 2412, NULL, 0); + if (!initiator_auth || !initiator_auth->req_msg) { + failure = "Failed to initialize DPP initiator authentication"; + goto cleanup; + } + + frame = wpabuf_head_u8(initiator_auth->req_msg) + 2; + len = wpabuf_len(initiator_auth->req_msg) - 2; + responder_auth = dpp_auth_req_rx(NULL, DPP_CAPAB_ENROLLEE, 0, + NULL, responder_bi, 2412, + frame, frame + DPP_HDR_LEN, + len - DPP_HDR_LEN); + if (!responder_auth || !responder_auth->resp_msg) { + failure = "Failed to process DPP authentication request"; + goto cleanup; + } + dpp_test_log_auth_timing("Production responder", responder_auth); + total_us = responder_auth->auth_req_total_us; + if (limit_us) { + ESP_LOGI("DPP Test", + "Production responder timing gate(us): total=%llu limit=%" PRIu32, + (unsigned long long) total_us, + limit_us); + } + + frame = wpabuf_head_u8(responder_auth->resp_msg) + 2; + len = wpabuf_len(responder_auth->resp_msg) - 2; + conf = dpp_auth_resp_rx(initiator_auth, frame, frame + DPP_HDR_LEN, + len - DPP_HDR_LEN); + if (!conf) { + failure = "Failed to process DPP authentication response"; + goto cleanup; + } + if (initiator_auth->auth_success != 1) { + failure = "Initiator authentication did not complete successfully"; + goto cleanup; + } + + frame = wpabuf_head_u8(conf) + 2; + len = wpabuf_len(conf) - 2; + if (dpp_auth_conf_rx(responder_auth, frame, frame + DPP_HDR_LEN, + len - DPP_HDR_LEN) != 0) { + failure = "Failed to process DPP authentication confirmation"; + goto cleanup; + } + if (responder_auth->auth_success != 1) { + failure = "Responder authentication did not complete successfully"; + goto cleanup; + } + +cleanup: + wpabuf_free(conf); + dpp_auth_deinit(responder_auth); + dpp_auth_deinit(initiator_auth); + dpp_global_deinit(dpp); + dpp_test_clear_overrides(); + + if (failure) { + TEST_FAIL_MESSAGE(failure); + } + if (limit_us) { + TEST_ASSERT_MESSAGE(total_us <= limit_us, + "DPP responder production timing regression"); + } +} #endif diff --git a/components/wpa_supplicant/test_apps/main/test_sae.c b/components/wpa_supplicant/test_apps/main/test_sae.c index bb1e36728dd..6b558dab1fb 100644 --- a/components/wpa_supplicant/test_apps/main/test_sae.c +++ b/components/wpa_supplicant/test_apps/main/test_sae.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,9 +20,41 @@ #include "utils/wpabuf.h" #include "test_utils.h" #include "test_wpa_supplicant_common.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" typedef struct crypto_bignum crypto_bignum; +static unsigned int test_task_stack_high_watermark_bytes(void) +{ + return (unsigned int)(uxTaskGetStackHighWaterMark(NULL) * + sizeof(StackType_t)); +} + +static int sae_commit_parse_limit_us(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + return 400000; +#elif CONFIG_IDF_TARGET_ESP32S3 + return 300000; +#elif CONFIG_IDF_TARGET_ESP32S2 + return 380000; +#elif CONFIG_IDF_TARGET_ESP32C3 + return 340000; +#elif CONFIG_IDF_TARGET_ESP32C5 + return 130000; +#elif CONFIG_IDF_TARGET_ESP32C6 + return 180000; +#elif CONFIG_IDF_TARGET_ESP32C61 + return 200000; +#elif CONFIG_IDF_TARGET_ESP32C2 + return 230000; +#else + return 230000; +#endif +} + static struct wpabuf *wpabuf_alloc2(size_t len) { struct wpabuf *buf = (struct wpabuf *)os_zalloc(sizeof(struct wpabuf) + len); @@ -233,26 +265,52 @@ TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") u8 pwd[] = "ESP32-WPA3"; struct wpabuf *buf; int default_groups[] = { IANA_SECP256R1, 0 }; + int64_t start_us; + int64_t total_start_us; + int64_t total_us; + int64_t prepare_us; + int64_t write_us; + int64_t parse_us; + int64_t formation_us; + int limit_us = sae_commit_parse_limit_us(); memset(&sae, 0, sizeof(sae)); + total_start_us = esp_timer_get_time(); TEST_ASSERT(sae_set_group(&sae, IANA_SECP256R1) == 0); + start_us = esp_timer_get_time(); TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd, strlen((const char *)pwd), &sae) == 0); + prepare_us = esp_timer_get_time() - start_us; buf = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT(buf != NULL); + start_us = esp_timer_get_time(); sae_write_commit(&sae, buf, NULL, NULL);// No anti-clogging token + write_us = esp_timer_get_time() - start_us; + formation_us = prepare_us + write_us; /* Parsing commit created by self will be detected as reflection attack*/ + start_us = esp_timer_get_time(); TEST_ASSERT(sae_parse_commit(&sae, wpabuf_mhead(buf), buf->used, NULL, 0, default_groups, 0) == SAE_SILENTLY_DISCARD); + parse_us = esp_timer_get_time() - start_us; wpabuf_free2(buf); sae_clear_temp_data(&sae); sae_clear_data(&sae); + total_us = esp_timer_get_time() - total_start_us; + + ESP_LOGI("SAE Test", + "Commit/parse timing(us): prepare=%lld write=%lld formation=%lld parse=%lld total=%lld limit=%d", + (long long) prepare_us, (long long) write_us, + (long long) formation_us, (long long) parse_us, + (long long) total_us, limit_us); + ESP_LOGI("SAE Test", "Task stack high watermark(bytes): %u", + test_task_stack_high_watermark_bytes()); + TEST_ASSERT_MESSAGE(total_us <= limit_us, "SAE commit/parse timing regression"); } ESP_LOGI("SAE Test", "=========== Complete ============"); diff --git a/components/wpa_supplicant/test_apps/main/test_wpa_supplicant_main.c b/components/wpa_supplicant/test_apps/main/test_wpa_supplicant_main.c index ea7a63123f4..a659d8ab6e9 100644 --- a/components/wpa_supplicant/test_apps/main/test_wpa_supplicant_main.c +++ b/components/wpa_supplicant/test_apps/main/test_wpa_supplicant_main.c @@ -32,7 +32,7 @@ static void check_leak(size_t before_free, size_t after_free, const char *type) { ssize_t delta = after_free - before_free; printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d, threshold %d)\n", type, before_free, after_free, delta, leak_threshold); - TEST_ASSERT_MESSAGE(delta > leak_threshold, "memory leak"); + TEST_ASSERT_MESSAGE(delta >= leak_threshold, "memory leak"); } #if SOC_SHA_SUPPORT_SHA512 diff --git a/components/wpa_supplicant/test_apps/sdkconfig.defaults b/components/wpa_supplicant/test_apps/sdkconfig.defaults index e6de7dac542..46ab76ce142 100644 --- a/components/wpa_supplicant/test_apps/sdkconfig.defaults +++ b/components/wpa_supplicant/test_apps/sdkconfig.defaults @@ -1,5 +1,7 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n CONFIG_ESP_WIFI_TESTING_OPTIONS=y +CONFIG_ESP_WIFI_DEBUG_PRINT=y CONFIG_ESP_WIFI_DPP_SUPPORT=y CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP_WIFI_P256_ACCEL=y