diff --git a/components/bootloader_support/src/bootloader_sha.c b/components/bootloader_support/src/bootloader_sha.c index 7558ef91481..a8bb39973b1 100644 --- a/components/bootloader_support/src/bootloader_sha.c +++ b/components/bootloader_support/src/bootloader_sha.c @@ -183,19 +183,13 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest bootloader_sha256_handle_t bootloader_sha256_start(void) { - // Initialize PSA Crypto subsystem - psa_status_t status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - return NULL; - } - psa_hash_operation_t *op = (psa_hash_operation_t *)malloc(sizeof(psa_hash_operation_t)); if (!op) { return NULL; } *op = psa_hash_operation_init(); - status = psa_hash_setup(op, PSA_ALG_SHA_256); + psa_status_t status = psa_hash_setup(op, PSA_ALG_SHA_256); if (status != PSA_SUCCESS) { free(op); return NULL; @@ -224,6 +218,8 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest psa_status_t status = psa_hash_finish(op, digest, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &hash_len); assert(status == PSA_SUCCESS); assert(hash_len == PSA_HASH_LENGTH(PSA_ALG_SHA_256)); + (void)status; // Suppress unused variable warning in release builds + (void)hash_len; // Suppress unused variable warning in release builds } else { psa_hash_abort(op); } diff --git a/components/bootloader_support/src/secure_boot_v1/secure_boot_signatures_app.c b/components/bootloader_support/src/secure_boot_v1/secure_boot_signatures_app.c index 89b9b4e4e90..7f8fbe3720c 100644 --- a/components/bootloader_support/src/secure_boot_v1/secure_boot_signatures_app.c +++ b/components/bootloader_support/src/secure_boot_v1/secure_boot_signatures_app.c @@ -23,6 +23,8 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver #define SIGNATURE_VERIFICATION_KEYLEN 64 #define PSA_ECDSA_PUB_KEY_SIZE_BITS 256 +#define UNCOMPRESSED_SECP256R1_KEY_SIZE 65 // Size for uncompressed SECP256R1 (1 + 32 + 32) +#define ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR 0x04 esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) { uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN]; @@ -75,14 +77,29 @@ esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_id_t key_handle; + // Format the public key for PSA import + uint8_t formatted_key[UNCOMPRESSED_SECP256R1_KEY_SIZE]; + formatted_key[0] = ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR; + + // Copy X and Y coordinates + if (keylen == 64) { // Raw coordinates without format byte + memcpy(&formatted_key[1], signature_verification_key_start, 64); + } else if (keylen == UNCOMPRESSED_SECP256R1_KEY_SIZE && signature_verification_key_start[0] == ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR) { + // Key is already in correct format + memcpy(formatted_key, signature_verification_key_start, UNCOMPRESSED_SECP256R1_KEY_SIZE); + } else { + ESP_LOGE(TAG, "Invalid key format or length"); + return ESP_FAIL; + } + // Set key attributes psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH); psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); psa_set_key_bits(&key_attributes, PSA_ECDSA_PUB_KEY_SIZE_BITS); - // Import the public key - status = psa_import_key(&key_attributes, signature_verification_key_start, keylen, &key_handle); + // Import the properly formatted public key + status = psa_import_key(&key_attributes, formatted_key, sizeof(formatted_key), &key_handle); if (status != PSA_SUCCESS) { ESP_LOGE(TAG, "Failed to import key, status:%d", status); return ESP_FAIL; diff --git a/components/bootloader_support/src/secure_boot_v2/secure_boot_rsa_signature.c b/components/bootloader_support/src/secure_boot_v2/secure_boot_rsa_signature.c index d551e5344f1..1f4c9e5bca1 100644 --- a/components/bootloader_support/src/secure_boot_v2/secure_boot_rsa_signature.c +++ b/components/bootloader_support/src/secure_boot_v2/secure_boot_rsa_signature.c @@ -6,6 +6,8 @@ #include "esp_log.h" #include "esp_secure_boot.h" #include "psa/crypto.h" +#include "mbedtls/pk.h" +#include "mbedtls/rsa.h" #include "secure_boot_signature_priv.h" @@ -30,45 +32,59 @@ esp_err_t verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_bloc psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_id_t key_id = 0; + + /* Prepare the RSA public key data */ + const mbedtls_mpi N = { .MBEDTLS_PRIVATE(s) = 1, + .MBEDTLS_PRIVATE(n) = sizeof(trusted_block->key.n)/sizeof(mbedtls_mpi_uint), + .MBEDTLS_PRIVATE(p) = (void *)trusted_block->key.n, + }; + const mbedtls_mpi e = { .MBEDTLS_PRIVATE(s) = 1, + .MBEDTLS_PRIVATE(n) = sizeof(trusted_block->key.e)/sizeof(mbedtls_mpi_uint), // 1 + .MBEDTLS_PRIVATE(p) = (void *)&trusted_block->key.e, + }; + + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + + mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + mbedtls_rsa_context *rsa = mbedtls_pk_rsa(pk); + + ret = mbedtls_rsa_import(rsa, &N, NULL, NULL, NULL, &e); + if (ret != 0) { + ESP_LOGE(TAG, "Failed to import RSA public key, err: %d", ret); + mbedtls_pk_free(&pk); + goto cleanup; + } + ret = mbedtls_rsa_complete(rsa); + if (ret != 0) { + ESP_LOGE(TAG, "Failed to complete RSA context, err: %d", ret); + mbedtls_pk_free(&pk); + goto cleanup; + } + + // Load the public key into PSA + ret = mbedtls_pk_get_psa_attributes(&pk, PSA_KEY_USAGE_VERIFY_HASH, &key_attributes); + if (ret != 0) { + ESP_LOGE(TAG, "Failed to get key attributes, err: %d", ret); + mbedtls_pk_free(&pk); + goto cleanup; + } + /* Set key attributes */ psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH); psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256)); psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY); - /* Set the key size in bits (RSA key size is typically 2048 or 3072 bits) */ - psa_set_key_bits(&key_attributes, PSA_BYTES_TO_BITS(rsa_key_size)); - - /* Prepare the RSA public key in the format expected by PSA */ - /* PSA expects the key in big-endian format as a sequence of {N, E} */ - size_t n_size = rsa_key_size; /* N size in bytes */ - size_t e_size = sizeof(trusted_block->key.e); /* E size in bytes */ - size_t key_data_size = n_size + e_size + 8; /* Additional bytes for encoding */ - - uint8_t *key_data = calloc(1, key_data_size); - if (key_data == NULL) { - free(sig_be); - return ESP_ERR_NO_MEM; - } - - /* Construct the key data - would normally need proper DER encoding, - but PSA may accept raw concatenated N and E values */ - uint8_t *p = key_data; - - /* Copy N (modulus) */ - memcpy(p, trusted_block->key.n, n_size); - p += n_size; - - /* Copy E (exponent) */ - memcpy(p, &trusted_block->key.e, e_size); - - /* Import the RSA public key */ - status = psa_import_key(&key_attributes, key_data, key_data_size, &key_id); - if (status != PSA_SUCCESS) { - ESP_LOGE(TAG, "Failed to import RSA public key, err: %d", status); - ret = ESP_FAIL; + ret = mbedtls_pk_import_into_psa(&pk, &key_attributes, &key_id); + if (ret != 0) { + ESP_LOGE(TAG, "Failed to import key into PSA, err: %d", ret); + mbedtls_pk_free(&pk); goto cleanup; } + mbedtls_rsa_free(rsa); + mbedtls_pk_free(&pk); + /* Signature needs to be byte swapped into BE representation */ for (int j = 0; j < rsa_key_size; j++) { sig_be[rsa_key_size - j - 1] = trusted_block->signature[j]; @@ -93,7 +109,6 @@ cleanup: psa_destroy_key(key_id); } psa_reset_key_attributes(&key_attributes); - free(key_data); free(sig_be); return ret; diff --git a/components/bootloader_support/test_apps/bootloader_support/main/CMakeLists.txt b/components/bootloader_support/test_apps/bootloader_support/main/CMakeLists.txt index cef35455e5c..af5ce7f25d8 100644 --- a/components/bootloader_support/test_apps/bootloader_support/main/CMakeLists.txt +++ b/components/bootloader_support/test_apps/bootloader_support/main/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRCS "test_app_main.c" "test_verify_image.c" INCLUDE_DIRS "." - REQUIRES unity bootloader_support esp_partition app_update mbedtls + REQUIRES unity bootloader_support esp_partition app_update WHOLE_ARCHIVE) diff --git a/components/bootloader_support/test_apps/bootloader_support/main/test_app_main.c b/components/bootloader_support/test_apps/bootloader_support/main/test_app_main.c index 2bac9375ba7..65b7f884803 100644 --- a/components/bootloader_support/test_apps/bootloader_support/main/test_app_main.c +++ b/components/bootloader_support/test_apps/bootloader_support/main/test_app_main.c @@ -8,7 +8,6 @@ #include "unity_test_runner.h" #include "esp_heap_caps.h" #include "esp_ota_ops.h" -#include "psa/crypto.h" // Some resources are lazy allocated, e.g. newlib locks, GDMA channel lazy installed by crypto driver // the threshold is left for those cases @@ -28,7 +27,6 @@ void setUp(void) { // load the partition table before measuring the initial free heap size. TEST_ASSERT_NOT_EQUAL(NULL, esp_ota_get_running_partition()); - psa_crypto_init(); before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index eb968584c80..b7a2214ea08 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -121,12 +121,6 @@ esp_err_t esp_create_mbedtls_handle(const char *hostname, size_t hostlen, const int ret; esp_err_t esp_ret = ESP_FAIL; - psa_status_t status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - ESP_LOGE(TAG, "Failed to initialize PSA crypto, returned %d", (int) status); - return esp_ret; - } - tls->server_fd.fd = tls->sockfd; mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_config_init(&tls->conf); diff --git a/components/esp-tls/test_apps/main/app_main.c b/components/esp-tls/test_apps/main/app_main.c index 2c1a5935abc..09f7f9d9472 100644 --- a/components/esp-tls/test_apps/main/app_main.c +++ b/components/esp-tls/test_apps/main/app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,7 @@ #include "sha/sha_core.h" #endif #include "esp_newlib.h" +#include "psa/crypto.h" #if SOC_SHA_SUPPORT_SHA512 #define SHA_TYPE SHA2_512 @@ -50,7 +51,6 @@ void setUp(void) test_utils_record_free_mem(); TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL)); TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_GENERAL)); - } /* tearDown runs after every test */ @@ -62,6 +62,8 @@ void tearDown(void) /* clean up some of the newlib's lazy allocations */ esp_reent_cleanup(); + mbedtls_psa_crypto_free(); + /* check if unit test has caused heap corruption in any heap */ TEST_ASSERT_MESSAGE( heap_caps_check_integrity(MALLOC_CAP_INVALID, true), "The test has corrupted the heap"); diff --git a/components/esp_http_client/lib/http_auth.c b/components/esp_http_client/lib/http_auth.c index a6e125ec9f4..d2738cab01b 100644 --- a/components/esp_http_client/lib/http_auth.c +++ b/components/esp_http_client/lib/http_auth.c @@ -88,11 +88,6 @@ static int sha256_sprintf(char *sha, const char *fmt, ...) psa_status_t status; psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; - status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - goto exit; - } - status = psa_hash_setup(&operation, PSA_ALG_SHA_256); if (status != PSA_SUCCESS) { goto exit; diff --git a/components/esp_http_server/src/httpd_ws.c b/components/esp_http_server/src/httpd_ws.c index 371bff47c07..949addc674a 100644 --- a/components/esp_http_server/src/httpd_ws.c +++ b/components/esp_http_server/src/httpd_ws.c @@ -143,16 +143,9 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *suppor ESP_LOGD(TAG, LOG_FMT("Server key before encoding: %s"), server_raw_text); - /* Initialize PSA Crypto library */ - psa_status_t status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - ESP_LOGE(TAG, "Failed to initialize PSA Crypto"); - return ESP_FAIL; - } - /* Generate SHA-1 hash */ psa_hash_operation_t sha1_operation = PSA_HASH_OPERATION_INIT; - status = psa_hash_setup(&sha1_operation, PSA_ALG_SHA_1); + psa_status_t status = psa_hash_setup(&sha1_operation, PSA_ALG_SHA_1); if (status != PSA_SUCCESS) { ESP_LOGE(TAG, "Failed to setup SHA-1 operation"); return ESP_FAIL; @@ -161,6 +154,7 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *suppor status = psa_hash_update(&sha1_operation, (uint8_t *)server_raw_text, strlen(server_raw_text)); if (status != PSA_SUCCESS) { ESP_LOGE(TAG, "Failed to update SHA-1 hash"); + psa_hash_abort(&sha1_operation); return ESP_FAIL; } diff --git a/components/esp_security/CMakeLists.txt b/components/esp_security/CMakeLists.txt index 362f942aebd..a35b5c8fe1d 100644 --- a/components/esp_security/CMakeLists.txt +++ b/components/esp_security/CMakeLists.txt @@ -57,6 +57,9 @@ idf_component_register(SRCS ${srcs} if(NOT non_os_build) target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_security_init_include_impl") + if(CONFIG_MBEDTLS_PSA_CRYPTO_C) + idf_component_optional_requires(PRIVATE mbedtls) + endif() elseif(esp_tee_build) target_link_libraries(${COMPONENT_LIB} PRIVATE idf::efuse) endif() diff --git a/components/esp_security/src/init.c b/components/esp_security/src/init.c index 9a3a3fc147c..f9993914a15 100644 --- a/components/esp_security/src/init.c +++ b/components/esp_security/src/init.c @@ -13,6 +13,9 @@ #include "esp_security_priv.h" #include "esp_err.h" #include "hal/efuse_hal.h" +#if defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) +#include "psa/crypto.h" +#endif /* CONFIG_MBEDTLS_PSA_CRYPTO_C */ #if SOC_HUK_MEM_NEEDS_RECHARGE #include "hal/huk_hal.h" diff --git a/components/espcoredump/src/core_dump_sha.c b/components/espcoredump/src/core_dump_sha.c index 015a8cd766f..f40e1a94ffd 100644 --- a/components/espcoredump/src/core_dump_sha.c +++ b/components/espcoredump/src/core_dump_sha.c @@ -21,12 +21,17 @@ uint32_t esp_core_dump_elf_version(void) __attribute__((alias("core_dump_sha_ver static void core_dump_sha256_start(core_dump_sha_ctx_t *sha_ctx) { - psa_hash_operation_init(sha_ctx->ctx); + sha_ctx->ctx = psa_hash_operation_init(); psa_hash_setup(&sha_ctx->ctx, PSA_ALG_SHA_256); } static void core_dump_sha256_update(core_dump_sha_ctx_t *sha_ctx, const void *data, size_t data_len) { +#if CONFIG_MBEDTLS_HARDWARE_SHA + mbedtls_psa_hash_operation_t *op = &sha_ctx->ctx.MBEDTLS_PRIVATE(ctx).mbedtls_ctx; + mbedtls_sha256_context *ctx = &op->MBEDTLS_PRIVATE(ctx).sha256; + ctx->mode = ESP_MBEDTLS_SHA256_SOFTWARE; +#endif /* (CONFIG_MBEDTLS_HARDWARE_SHA) */ psa_hash_update(&sha_ctx->ctx, data, data_len); } diff --git a/components/espcoredump/test_apps/main/CMakeLists.txt b/components/espcoredump/test_apps/main/CMakeLists.txt index 7f8382a3b78..20730d7300e 100644 --- a/components/espcoredump/test_apps/main/CMakeLists.txt +++ b/components/espcoredump/test_apps/main/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND priv_includes "${espcoredump_dir}/include_core_dump") # list(APPEND SRCS "${espcoredump_dir}/src/core_dump_sha.c") idf_component_register(SRCS ${SRCS} INCLUDE_DIRS "." - PRIV_REQUIRES unity espcoredump + PRIV_REQUIRES unity PRIV_INCLUDE_DIRS ${priv_includes} + REQUIRES mbedtls espcoredump WHOLE_ARCHIVE) diff --git a/components/espcoredump/test_apps/pytest_coredump.py b/components/espcoredump/test_apps/pytest_coredump.py index 38ba25f978e..006384b3393 100644 --- a/components/espcoredump/test_apps/pytest_coredump.py +++ b/components/espcoredump/test_apps/pytest_coredump.py @@ -12,6 +12,12 @@ def test_coredump(dut: Dut) -> None: @pytest.mark.generic -@pytest.mark.parametrize('config', ['checksum_sha256',], indirect=True) +@pytest.mark.parametrize( + 'config', + [ + 'checksum_sha256', + ], + indirect=True, +) def test_coredump_sha(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/mbedtls/port/include/mbedtls/esp_config.h b/components/mbedtls/port/include/mbedtls/esp_config.h index 611d0878a80..1ae5cf2366b 100644 --- a/components/mbedtls/port/include/mbedtls/esp_config.h +++ b/components/mbedtls/port/include/mbedtls/esp_config.h @@ -29,13 +29,32 @@ #include "mbedtls/mbedtls_config.h" #include "soc/soc_caps.h" +/** + * \def MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS + * + * Assume all buffers passed to PSA functions are owned exclusively by the + * PSA function and are not stored in shared memory. + * + * This option may be enabled if all buffers passed to any PSA function reside + * in memory that is accessible only to the PSA function during its execution. + * + * This option MUST be disabled whenever buffer arguments are in memory shared + * with an untrusted party, for example where arguments to PSA calls are passed + * across a trust boundary. + * + * \note Enabling this option reduces memory usage and code size. + * + * \note Enabling this option causes overlap of input and output buffers + * not to be supported by PSA functions. + */ +#define MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS + /** * \name SECTION: System support * * This section sets system specific settings. * \{ */ - /** * \def MBEDTLS_HAVE_TIME * diff --git a/components/protocomm/src/crypto/srp6a/esp_srp.c b/components/protocomm/src/crypto/srp6a/esp_srp.c index bf3dd25cc5b..675ca34b087 100644 --- a/components/protocomm/src/crypto/srp6a/esp_srp.c +++ b/components/protocomm/src/crypto/srp6a/esp_srp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,9 +9,10 @@ #include "esp_log.h" #include "esp_err.h" -#include +#include "psa/crypto.h" #include "esp_srp_mpi.h" #include "esp_srp.h" +#include "esp_check.h" #define SHA512_HASH_SZ 64 @@ -178,33 +179,63 @@ void esp_srp_free(esp_srp_handle_t *hd) static esp_mpi_t *calculate_x(char *bytes_salt, int salt_len, const char *username, int username_len, const char *pass, int pass_len) { - unsigned char digest[SHA512_HASH_SZ]; - mbedtls_sha512_context ctx; - ESP_LOGD(TAG, "Username: %s | Passphrase: %s | Passphrase length: %d", username, pass, pass_len); - mbedtls_sha512_init(&ctx); - mbedtls_sha512_starts(&ctx, 0); - mbedtls_sha512_update(&ctx, (unsigned char *)username, username_len); - mbedtls_sha512_update(&ctx, (unsigned char *)":", 1); - mbedtls_sha512_update(&ctx, (unsigned char *)pass, pass_len); - mbedtls_sha512_finish(&ctx, digest); + // ret is unused here as it is required by the esp_check macros, suppressing the unused variable warning + __attribute__((unused)) esp_err_t ret = ESP_FAIL; - mbedtls_sha512_init(&ctx); - mbedtls_sha512_starts(&ctx, 0); - mbedtls_sha512_update(&ctx, (unsigned char *)bytes_salt, salt_len); - mbedtls_sha512_update(&ctx, digest, sizeof(digest)); - mbedtls_sha512_finish(&ctx, digest); - mbedtls_sha512_free(&ctx); + unsigned char digest[SHA512_HASH_SZ]; + psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT; + psa_status_t status; + + /* Add validation for input parameters */ + if (!bytes_salt || !username || !pass || salt_len <= 0 || username_len <= 0 || pass_len <= 0) { + ESP_LOGE(TAG, "Invalid parameters: salt=%p, username=%p, pass=%p, salt_len=%d, username_len=%d, pass_len=%d", + bytes_salt, username, pass, salt_len, username_len, pass_len); + return NULL; + } + + ESP_LOGD(TAG, "Username: %s | Passphrase: %s | Passphrase length: %d", username, pass, pass_len); + + status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, NULL, TAG, "Failed to setup hash operation: %d", status); + psa_hash_update(&hash_op, (unsigned char *)username, username_len); + psa_hash_update(&hash_op, (unsigned char *)":", 1); + psa_hash_update(&hash_op, (unsigned char *)pass, pass_len); + + size_t hash_len = 0; + status = psa_hash_finish(&hash_op, digest, sizeof(digest), &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); + status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, NULL, TAG, "Failed to setup hash operation: %d", status); + + psa_hash_update(&hash_op, (unsigned char *)bytes_salt, salt_len); + psa_hash_update(&hash_op, digest, sizeof(digest)); + status = psa_hash_finish(&hash_op, digest, sizeof(digest), &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); return esp_mpi_new_from_bin((char *)digest, sizeof(digest)); +error: + psa_hash_abort(&hash_op); + return NULL; } static esp_mpi_t *calculate_padded_hash(esp_srp_handle_t *hd, const char *a, int len_a, const char *b, int len_b) { unsigned char digest[SHA512_HASH_SZ]; - mbedtls_sha512_context ctx; + psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT; + psa_status_t status; int pad_len; + size_t hash_len = 0; char *s = NULL; + /* Add validation for input parameters */ + if (!hd || !a || !b || len_a <= 0 || len_b <= 0) { + ESP_LOGE(TAG, "Invalid parameters: hd=%p, a=%p, b=%p, len_a=%d, len_b=%d", + hd, a, b, len_a, len_b); + return NULL; + } + if (len_a > len_b) { pad_len = hd->len_n - len_b; } else { @@ -218,28 +249,37 @@ static esp_mpi_t *calculate_padded_hash(esp_srp_handle_t *hd, const char *a, int } } - mbedtls_sha512_init(&ctx); - mbedtls_sha512_starts(&ctx, 0); - /* PAD (a) */ - if (s && (len_a != hd->len_n)) { - mbedtls_sha512_update(&ctx, (unsigned char *)s, hd->len_n - len_a); + status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to setup hash operation: %d", status); + if (s) { + free(s); + } + return NULL; } - mbedtls_sha512_update(&ctx, (unsigned char *)a, len_a); + /* PAD (a) */ + if (s && (len_a != hd->len_n)) { + psa_hash_update(&hash_op, (unsigned char *)s, hd->len_n - len_a); + } + + psa_hash_update(&hash_op, (unsigned char *)a, len_a); /* PAD (b) */ if (s && (len_b != hd->len_n)) { - mbedtls_sha512_update(&ctx, (unsigned char *)s, hd->len_n - len_b); + psa_hash_update(&hash_op, (unsigned char *)s, hd->len_n - len_b); } - mbedtls_sha512_update(&ctx, (unsigned char *)b, len_b); - - mbedtls_sha512_finish(&ctx, digest); - mbedtls_sha512_free(&ctx); - + psa_hash_update(&hash_op, (unsigned char *)b, len_b); + status = psa_hash_finish(&hash_op, digest, sizeof(digest), &hash_len); if (s) { free(s); } + if (status != PSA_SUCCESS || hash_len != SHA512_HASH_SZ) { + psa_hash_abort(&hash_op); + ESP_LOGE(TAG, "Hash operation failed: status=%d, hash_len=%d", status, hash_len); + return NULL; + } return esp_mpi_new_from_bin((char *)digest, sizeof(digest)); } @@ -250,24 +290,53 @@ static esp_mpi_t *calculate_padded_hash(esp_srp_handle_t *hd, const char *a, int */ static esp_mpi_t *calculate_k(esp_srp_handle_t *hd) { + if (!hd) { + ESP_LOGE(TAG, "Invalid parameter: hd=%p", hd); + return NULL; + } return calculate_padded_hash(hd, hd->bytes_n, hd->len_n, hd->bytes_g, hd->len_g); } static esp_mpi_t *calculate_u(esp_srp_handle_t *hd, char *A, int len_A) { + if (!hd || !A || len_A <= 0) { + ESP_LOGE(TAG, "Invalid parameters: hd=%p, A=%p, len_A=%d", hd, A, len_A); + return NULL; + } return calculate_padded_hash(hd, A, len_A, hd->bytes_B, hd->len_B); } static esp_err_t __esp_srp_srv_pubkey(esp_srp_handle_t *hd, char **bytes_B, int *len_B) { - esp_mpi_t *k = calculate_k(hd); + esp_mpi_t *k = NULL; esp_mpi_t *kv = NULL; esp_mpi_t *gb = NULL; + + /* Add validation for input parameters */ + if (!hd || !bytes_B || !len_B) { + ESP_LOGE(TAG, "Invalid parameters: hd=%p, bytes_B=%p, len_B=%p", hd, bytes_B, len_B); + return ESP_ERR_INVALID_ARG; + } + + if (!hd->v) { + ESP_LOGE(TAG, "Verifier must be set before generating server public key"); + return ESP_ERR_INVALID_STATE; + } + + k = calculate_k(hd); if (!k) { goto error; } hexdump_mpi("k", k); + // At this point hd->b, hd->B must be NULL + // If it is not NULL, then free it. + if (hd->b || hd->B) { + esp_mpi_free(hd->b); + hd->b = NULL; + esp_mpi_free(hd->B); + hd->B = NULL; + } hd->b = esp_mpi_new(); if (!hd->b) { goto error; @@ -317,6 +386,18 @@ error: static esp_err_t _esp_srp_gen_salt_verifier(esp_srp_handle_t *hd, const char *username, int username_len, const char *pass, int pass_len, int salt_len) { + /* Add validation for input parameters */ + if (!hd || !username || !pass) { + ESP_LOGE(TAG, "Invalid parameters: hd=%p, username=%p, pass=%p", hd, username, pass); + return ESP_ERR_INVALID_ARG; + } + + if (username_len <= 0 || pass_len <= 0 || salt_len <= 0) { + ESP_LOGE(TAG, "Invalid length parameters: username_len=%d, pass_len=%d, salt_len=%d", + username_len, pass_len, salt_len); + return ESP_ERR_INVALID_ARG; + } + /* Get Salt */ int str_salt_len; esp_mpi_t *x = NULL; @@ -382,9 +463,16 @@ esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int use const char *pass, int pass_len, int salt_len, char **bytes_B, int *len_B, char **bytes_salt) { - if (!hd || !username || !pass) { + if (!hd || !username || !pass || !bytes_B || !len_B || !bytes_salt) { return ESP_ERR_INVALID_ARG; } + + if (username_len <= 0 || pass_len <= 0 || salt_len <= 0) { + ESP_LOGE(TAG, "Invalid length parameters: username_len=%d, pass_len=%d, salt_len=%d", + username_len, pass_len, salt_len); + return ESP_ERR_INVALID_ARG; + } + if (ESP_OK != _esp_srp_gen_salt_verifier(hd, username, username_len, pass, pass_len, salt_len)) { goto error; } @@ -429,6 +517,19 @@ esp_err_t esp_srp_gen_salt_verifier(const char *username, int username_len, { esp_err_t ret = ESP_FAIL; + /* Add validation for input parameters */ + if (!username || !pass || !bytes_salt || !verifier || !verifier_len) { + ESP_LOGE(TAG, "Invalid parameters: username=%p, pass=%p, bytes_salt=%p, verifier=%p, verifier_len=%p", + username, pass, bytes_salt, verifier, verifier_len); + return ESP_ERR_INVALID_ARG; + } + + if (username_len <= 0 || pass_len <= 0 || salt_len <= 0) { + ESP_LOGE(TAG, "Invalid length parameters: username_len=%d, pass_len=%d, salt_len=%d", + username_len, pass_len, salt_len); + return ESP_ERR_INVALID_ARG; + } + /* allocate and init temporary SRP handle */ esp_srp_handle_t *srp_hd = esp_srp_init(ESP_NG_3072); if (!srp_hd) { @@ -461,6 +562,16 @@ cleanup: esp_err_t esp_srp_set_salt_verifier(esp_srp_handle_t *hd, const char *salt, int salt_len, const char *verifier, int verifier_len) { + if (!hd || !salt || !verifier) { + return ESP_ERR_INVALID_ARG; + } + + if (salt_len <= 0 || verifier_len <= 0) { + ESP_LOGE(TAG, "Invalid length parameters: salt_len=%d, verifier_len=%d", + salt_len, verifier_len); + return ESP_ERR_INVALID_ARG; + } + hd->bytes_s = malloc(salt_len); if (!hd->bytes_s) { goto error; @@ -498,6 +609,26 @@ error: esp_err_t esp_srp_get_session_key(esp_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, uint16_t *len_key) { + esp_err_t ret = ESP_FAIL; + + /* Add validation for input parameters */ + if (!hd || !bytes_A || !bytes_key || !len_key) { + ESP_LOGE(TAG, "Invalid parameters: hd=%p, bytes_A=%p, bytes_key=%p, len_key=%p", + hd, bytes_A, bytes_key, len_key); + return ESP_ERR_INVALID_ARG; + } + + if (len_A <= 0) { + ESP_LOGE(TAG, "Invalid length parameter: len_A=%d", len_A); + return ESP_ERR_INVALID_ARG; + } + + /* Check if the necessary SRP parameters are initialized */ + if (!hd->b || !hd->v || !hd->n) { + ESP_LOGE(TAG, "SRP parameters not properly initialized"); + return ESP_ERR_INVALID_STATE; + } + esp_mpi_t *u = NULL; esp_mpi_t *vu = NULL; esp_mpi_t *avu = NULL; @@ -545,9 +676,17 @@ esp_err_t esp_srp_get_session_key(esp_srp_handle_t *hd, char *bytes_A, int len_A goto error; } - mbedtls_sha512((unsigned char *)bytes_S, len_S, (unsigned char *)hd->session_key, 0); + psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT; + psa_status_t status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, ESP_FAIL, TAG, "Failed to setup hash operation: %d", status); + + psa_hash_update(&hash_op, (unsigned char *)bytes_S, len_S); + size_t hash_len = 0; + status = psa_hash_finish(&hash_op, (unsigned char *)hd->session_key, SHA512_HASH_SZ, &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); + *len_key = hash_len; *bytes_key = hd->session_key; - *len_key = SHA512_HASH_SZ; free(bytes_S); esp_mpi_free(vu); @@ -583,73 +722,109 @@ error: free(hd->bytes_A); hd->bytes_A = NULL; } - return ESP_FAIL; + psa_hash_abort(&hash_op); + return ret; } esp_err_t esp_srp_exchange_proofs(esp_srp_handle_t *hd, char *username, uint16_t username_len, char *bytes_user_proof, char *bytes_host_proof) { + esp_err_t ret = ESP_FAIL; + + /* Add validation for input parameters */ + if (!hd || !username || !bytes_user_proof || !bytes_host_proof) { + ESP_LOGE(TAG, "Invalid parameters: hd=%p, username=%p, bytes_user_proof=%p, bytes_host_proof=%p", + hd, username, bytes_user_proof, bytes_host_proof); + return ESP_ERR_INVALID_ARG; + } + + if (username_len <= 0) { + ESP_LOGE(TAG, "Invalid username length: %d", username_len); + return ESP_ERR_INVALID_ARG; + } + + /* Check if the necessary SRP parameters and session key are initialized */ + if (!hd->bytes_A || !hd->bytes_B || !hd->bytes_s || !hd->session_key) { + ESP_LOGE(TAG, "SRP exchange not properly initialized: A=%p, B=%p, s=%p, key=%p", + hd->bytes_A, hd->bytes_B, hd->bytes_s, hd->session_key); + return ESP_ERR_INVALID_STATE; + } + /* First calculate M */ unsigned char hash_n[SHA512_HASH_SZ]; unsigned char hash_g[SHA512_HASH_SZ]; unsigned char hash_n_xor_g[SHA512_HASH_SZ]; int i; - + char *s = NULL; unsigned char hash_I[SHA512_HASH_SZ]; - mbedtls_sha512((unsigned char *)username, username_len, (unsigned char *)hash_I, 0); - mbedtls_sha512((unsigned char *)hd->bytes_n, hd->len_n, (unsigned char *)hash_n, 0); + size_t hash_len = 0; + psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT; + psa_status_t status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, ESP_FAIL, TAG, "Failed to setup hash operation: %d", status); + psa_hash_update(&hash_op, (unsigned char *)username, username_len); + status = psa_hash_finish(&hash_op, (unsigned char *)hash_I, SHA512_HASH_SZ, &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); + + status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, ESP_FAIL, TAG, "Failed to setup hash operation: %d", status); + + psa_hash_update(&hash_op, (unsigned char *)hd->bytes_n, hd->len_n); + status = psa_hash_finish(&hash_op, (unsigned char *)hash_n, SHA512_HASH_SZ, &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); int pad_len = hd->len_n - hd->len_g; - char *s = calloc(pad_len, sizeof(char)); - if (!s) { - return ESP_ERR_NO_MEM; - } + s = calloc(pad_len, sizeof(char)); + ESP_RETURN_ON_FALSE(s, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory"); - mbedtls_sha512_context ctx; - mbedtls_sha512_init(&ctx); - mbedtls_sha512_starts(&ctx, 0); - mbedtls_sha512_update(&ctx, (unsigned char *)s, pad_len); - mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_g, hd->len_g); - mbedtls_sha512_finish(&ctx, hash_g); - mbedtls_sha512_free(&ctx); + status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, ESP_FAIL, TAG, "Failed to setup hash operation: %d", status); + psa_hash_update(&hash_op, (unsigned char *)s, pad_len); + psa_hash_update(&hash_op, (unsigned char *)hd->bytes_g, hd->len_g); + status = psa_hash_finish(&hash_op, (unsigned char *)hash_g, SHA512_HASH_SZ, &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); for (i = 0; i < SHA512_HASH_SZ; i++) { hash_n_xor_g[i] = hash_n[i] ^ hash_g[i]; } unsigned char digest[SHA512_HASH_SZ]; - mbedtls_sha512_init(&ctx); - mbedtls_sha512_starts(&ctx, 0); - mbedtls_sha512_update(&ctx, hash_n_xor_g, SHA512_HASH_SZ); - mbedtls_sha512_update(&ctx, hash_I, SHA512_HASH_SZ); - mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_s, hd->len_s); - mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_A, hd->len_A); - mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_B, hd->len_B); - mbedtls_sha512_update(&ctx, (unsigned char *)hd->session_key, SHA512_HASH_SZ); - mbedtls_sha512_finish(&ctx, digest); - mbedtls_sha512_free(&ctx); + status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, ESP_FAIL, TAG, "Failed to setup hash operation: %d", status); + psa_hash_update(&hash_op, hash_n_xor_g, SHA512_HASH_SZ); + psa_hash_update(&hash_op, hash_I, SHA512_HASH_SZ); + psa_hash_update(&hash_op, (unsigned char *)hd->bytes_s, hd->len_s); + psa_hash_update(&hash_op, (unsigned char *)hd->bytes_A, hd->len_A); + psa_hash_update(&hash_op, (unsigned char *)hd->bytes_B, hd->len_B); + psa_hash_update(&hash_op, (unsigned char *)hd->session_key, SHA512_HASH_SZ); + status = psa_hash_finish(&hash_op, digest, SHA512_HASH_SZ, &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); ESP_LOGD(TAG, "M ->"); ESP_LOG_BUFFER_HEX_LEVEL(TAG, (char *)digest, sizeof(digest), ESP_LOG_DEBUG); - if (memcmp(bytes_user_proof, digest, SHA512_HASH_SZ) != 0) { - free(s); - return ESP_FAIL; - } + ESP_GOTO_ON_FALSE(memcmp(bytes_user_proof, digest, SHA512_HASH_SZ) == 0, ESP_FAIL, error, TAG, "Failed to validate user proof"); /* M is now validated, let's proceed to H(AMK) */ - mbedtls_sha512_init(&ctx); - mbedtls_sha512_starts(&ctx, 0); - mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_A, hd->len_A); - mbedtls_sha512_update(&ctx, digest, SHA512_HASH_SZ); - mbedtls_sha512_update(&ctx, (unsigned char *)hd->session_key, SHA512_HASH_SZ); - mbedtls_sha512_finish(&ctx, (unsigned char *)bytes_host_proof); - mbedtls_sha512_free(&ctx); + status = psa_hash_setup(&hash_op, PSA_ALG_SHA_512); + ESP_RETURN_ON_FALSE(status == PSA_SUCCESS, ESP_FAIL, TAG, "Failed to setup hash operation: %d", status); + psa_hash_update(&hash_op, (unsigned char *)hd->bytes_A, hd->len_A); + psa_hash_update(&hash_op, digest, SHA512_HASH_SZ); + psa_hash_update(&hash_op, (unsigned char *)hd->session_key, SHA512_HASH_SZ); + status = psa_hash_finish(&hash_op, (unsigned char *)bytes_host_proof, SHA512_HASH_SZ, &hash_len); + ESP_GOTO_ON_FALSE(status == PSA_SUCCESS && hash_len == SHA512_HASH_SZ, ESP_FAIL, error, TAG, + "Hash operation failed: status=%d, hash_len=%d", status, hash_len); ESP_LOGD(TAG, "AMK ->"); ESP_LOG_BUFFER_HEX_LEVEL(TAG, (char *)bytes_host_proof, SHA512_HASH_SZ, ESP_LOG_DEBUG); + ret = ESP_OK; +error: + psa_hash_abort(&hash_op); if (s) { free(s); } - return ESP_OK; + return ret; } diff --git a/components/protocomm/test_apps/main/CMakeLists.txt b/components/protocomm/test_apps/main/CMakeLists.txt index 74dc603fa6a..e12000e0085 100644 --- a/components/protocomm/test_apps/main/CMakeLists.txt +++ b/components/protocomm/test_apps/main/CMakeLists.txt @@ -1,3 +1,4 @@ idf_component_register(SRC_DIRS "." PRIV_INCLUDE_DIRS "." - PRIV_REQUIRES cmock mbedtls protocomm protobuf-c test_utils unity) + PRIV_REQUIRES cmock mbedtls protocomm protobuf-c test_utils unity + WHOLE_ARCHIVE) diff --git a/components/protocomm/test_apps/main/app_main.c b/components/protocomm/test_apps/main/app_main.c new file mode 100644 index 00000000000..03f8252580c --- /dev/null +++ b/components/protocomm/test_apps/main/app_main.c @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "test_utils.h" +#include "memory_checks.h" +#include "esp_newlib.h" +#include "psa/crypto.h" +#include "mbedtls/aes.h" +#if SOC_SHA_SUPPORT_PARALLEL_ENG +#include "sha/sha_parallel_engine.h" +#else +#include "sha/sha_core.h" +#endif +#include "bignum_impl.h" + +/* setUp runs before every test */ +void setUp(void) +{ +#if SOC_SHA_SUPPORTED + // Execute esp_sha operation to allocate internal SHA semaphore (in case of ESP32) + // and initial DMA setup memory which is considered as leaked otherwise + const uint8_t input_buffer[64] = {0}; + uint8_t output_buffer[64]; +#if SOC_SHA_SUPPORT_SHA256 + esp_sha(SHA2_256, input_buffer, sizeof(input_buffer), output_buffer); +#endif // SOC_SHA_SUPPORT_SHA256 +#if SOC_SHA_SUPPORT_SHA512 + esp_sha(SHA2_512, input_buffer, sizeof(input_buffer), output_buffer); +#endif // SOC_SHA_SUPPORT_SHA512 +#endif // SOC_SHA_SUPPORTED + +#if defined(CONFIG_MBEDTLS_HARDWARE_MPI) + esp_mpi_enable_hardware_hw_op(); + esp_mpi_disable_hardware_hw_op(); +#endif // CONFIG_MBEDTLS_HARDWARE_MPI + +#if SOC_AES_SUPPORTED + // Execute mbedtls_aes_init operation to allocate AES interrupt + // allocation memory which is considered as leak otherwise + const uint8_t plaintext[16] = {0}; + uint8_t ciphertext[16]; + const uint8_t key[16] = { 0 }; + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_enc(&ctx, key, 128); + mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, ciphertext); + mbedtls_aes_free(&ctx); +#endif // SOC_AES_SUPPORTED + + test_utils_record_free_mem(); + TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL)); + TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_GENERAL)); +} + +/* tearDown runs after every test */ +void tearDown(void) +{ + /* some FreeRTOS stuff is cleaned up by idle task */ + vTaskDelay(5); + + /* clean up some of the newlib's lazy allocations */ + esp_reent_cleanup(); + + mbedtls_psa_crypto_free(); + + /* check if unit test has caused heap corruption in any heap */ + TEST_ASSERT_MESSAGE( heap_caps_check_integrity(MALLOC_CAP_INVALID, true), "The test has corrupted the heap"); + + test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL), + test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL)); +} + +static void test_task(void *pvParameters) +{ + vTaskDelay(2); /* Delay a bit to let the main task be deleted */ + unity_run_menu(); +} + +void app_main(void) +{ + xTaskCreatePinnedToCore(test_task, "testTask", CONFIG_UNITY_FREERTOS_STACK_SIZE, NULL, CONFIG_UNITY_FREERTOS_PRIORITY, NULL, CONFIG_UNITY_FREERTOS_CPU); +} diff --git a/components/protocomm/test_apps/main/test_protocomm.c b/components/protocomm/test_apps/main/test_protocomm.c index 5ec35485841..3d3c8c5df38 100644 --- a/components/protocomm/test_apps/main/test_protocomm.c +++ b/components/protocomm/test_apps/main/test_protocomm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -715,7 +715,7 @@ static esp_err_t test_security1_no_encryption (void) return ESP_ERR_INVALID_STATE; } - // Intialise protocomm session with zero public keys + // Initialise protocomm session with zero public keys if (test_new_session(session) != ESP_OK) { ESP_LOGE(TAG, "Error creating new session"); stop_test_service(); @@ -794,7 +794,7 @@ static esp_err_t test_security1_session_overflow (void) return ESP_FAIL; } - // Intialise protocomm session with zero public keys + // Initialise protocomm session with zero public keys if (test_new_session(session1) != ESP_OK) { ESP_LOGE(TAG, "Error creating new session"); stop_test_service(); @@ -860,7 +860,7 @@ static esp_err_t test_security1_wrong_pop (void) return ESP_FAIL; } - // Intialise protocomm session with zero public keys + // Initialise protocomm session with zero public keys if (test_new_session(session) != ESP_OK) { ESP_LOGE(TAG, "Error creating new session"); stop_test_service(); @@ -975,7 +975,7 @@ static esp_err_t test_security1_weak_session (void) return ESP_FAIL; } - // Intialise protocomm session with zero public keys + // Initialise protocomm session with zero public keys if (test_new_session(session) != ESP_OK) { ESP_LOGE(TAG, "Error creating new session"); stop_test_service(); @@ -1028,7 +1028,7 @@ static esp_err_t test_protocomm (session_t *session) return ESP_FAIL; } - // Intialise protocomm session with zero public keys + // Initialise protocomm session with zero public keys if (test_new_session(session) != ESP_OK) { ESP_LOGE(TAG, "Error creating new session"); stop_test_service(); @@ -1190,8 +1190,3 @@ TEST_CASE("security 1 weak session test", "[PROTOCOMM]") { TEST_ASSERT(test_security1_weak_session() == ESP_OK); } - -void app_main(void) -{ - unity_run_menu(); -} diff --git a/components/protocomm/test_apps/main/test_srp.c b/components/protocomm/test_apps/main/test_srp.c new file mode 100644 index 00000000000..ccd5b46e46a --- /dev/null +++ b/components/protocomm/test_apps/main/test_srp.c @@ -0,0 +1,325 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include "esp_srp.h" +#include "esp_log.h" +#include "test_utils.h" +#include "esp_rom_crc.h" + +static const char *TAG = "srp_test"; + +// Example username and password +static const char *username = "wifiprov"; +static const char *password = "abcd1234"; + +static const char sec2_salt[] = { + 0x03, 0x6e, 0xe0, 0xc7, 0xbc, 0xb9, 0xed, 0xa8, 0x4c, 0x9e, 0xac, 0x97, 0xd9, 0x3d, 0xec, 0xf4 +}; + +static const char sec2_verifier[] = { + 0x7c, 0x7c, 0x85, 0x47, 0x65, 0x08, 0x94, 0x6d, 0xd6, 0x36, 0xaf, 0x37, 0xd7, 0xe8, 0x91, 0x43, + 0x78, 0xcf, 0xfd, 0x61, 0x6c, 0x59, 0xd2, 0xf8, 0x39, 0x08, 0x12, 0x72, 0x38, 0xde, 0x9e, 0x24, + 0xa4, 0x70, 0x26, 0x1c, 0xdf, 0xa9, 0x03, 0xc2, 0xb2, 0x70, 0xe7, 0xb1, 0x32, 0x24, 0xda, 0x11, + 0x1d, 0x97, 0x18, 0xdc, 0x60, 0x72, 0x08, 0xcc, 0x9a, 0xc9, 0x0c, 0x48, 0x27, 0xe2, 0xae, 0x89, + 0xaa, 0x16, 0x25, 0xb8, 0x04, 0xd2, 0x1a, 0x9b, 0x3a, 0x8f, 0x37, 0xf6, 0xe4, 0x3a, 0x71, 0x2e, + 0xe1, 0x27, 0x86, 0x6e, 0xad, 0xce, 0x28, 0xff, 0x54, 0x46, 0x60, 0x1f, 0xb9, 0x96, 0x87, 0xdc, + 0x57, 0x40, 0xa7, 0xd4, 0x6c, 0xc9, 0x77, 0x54, 0xdc, 0x16, 0x82, 0xf0, 0xed, 0x35, 0x6a, 0xc4, + 0x70, 0xad, 0x3d, 0x90, 0xb5, 0x81, 0x94, 0x70, 0xd7, 0xbc, 0x65, 0xb2, 0xd5, 0x18, 0xe0, 0x2e, + 0xc3, 0xa5, 0xf9, 0x68, 0xdd, 0x64, 0x7b, 0xb8, 0xb7, 0x3c, 0x9c, 0xfc, 0x00, 0xd8, 0x71, 0x7e, + 0xb7, 0x9a, 0x7c, 0xb1, 0xb7, 0xc2, 0xc3, 0x18, 0x34, 0x29, 0x32, 0x43, 0x3e, 0x00, 0x99, 0xe9, + 0x82, 0x94, 0xe3, 0xd8, 0x2a, 0xb0, 0x96, 0x29, 0xb7, 0xdf, 0x0e, 0x5f, 0x08, 0x33, 0x40, 0x76, + 0x52, 0x91, 0x32, 0x00, 0x9f, 0x97, 0x2c, 0x89, 0x6c, 0x39, 0x1e, 0xc8, 0x28, 0x05, 0x44, 0x17, + 0x3f, 0x68, 0x02, 0x8a, 0x9f, 0x44, 0x61, 0xd1, 0xf5, 0xa1, 0x7e, 0x5a, 0x70, 0xd2, 0xc7, 0x23, + 0x81, 0xcb, 0x38, 0x68, 0xe4, 0x2c, 0x20, 0xbc, 0x40, 0x57, 0x76, 0x17, 0xbd, 0x08, 0xb8, 0x96, + 0xbc, 0x26, 0xeb, 0x32, 0x46, 0x69, 0x35, 0x05, 0x8c, 0x15, 0x70, 0xd9, 0x1b, 0xe9, 0xbe, 0xcc, + 0xa9, 0x38, 0xa6, 0x67, 0xf0, 0xad, 0x50, 0x13, 0x19, 0x72, 0x64, 0xbf, 0x52, 0xc2, 0x34, 0xe2, + 0x1b, 0x11, 0x79, 0x74, 0x72, 0xbd, 0x34, 0x5b, 0xb1, 0xe2, 0xfd, 0x66, 0x73, 0xfe, 0x71, 0x64, + 0x74, 0xd0, 0x4e, 0xbc, 0x51, 0x24, 0x19, 0x40, 0x87, 0x0e, 0x92, 0x40, 0xe6, 0x21, 0xe7, 0x2d, + 0x4e, 0x37, 0x76, 0x2f, 0x2e, 0xe2, 0x68, 0xc7, 0x89, 0xe8, 0x32, 0x13, 0x42, 0x06, 0x84, 0x84, + 0x53, 0x4a, 0xb3, 0x0c, 0x1b, 0x4c, 0x8d, 0x1c, 0x51, 0x97, 0x19, 0xab, 0xae, 0x77, 0xff, 0xdb, + 0xec, 0xf0, 0x10, 0x95, 0x34, 0x33, 0x6b, 0xcb, 0x3e, 0x84, 0x0f, 0xb9, 0xd8, 0x5f, 0xb8, 0xa0, + 0xb8, 0x55, 0x53, 0x3e, 0x70, 0xf7, 0x18, 0xf5, 0xce, 0x7b, 0x4e, 0xbf, 0x27, 0xce, 0xce, 0xa8, + 0xb3, 0xbe, 0x40, 0xc5, 0xc5, 0x32, 0x29, 0x3e, 0x71, 0x64, 0x9e, 0xde, 0x8c, 0xf6, 0x75, 0xa1, + 0xe6, 0xf6, 0x53, 0xc8, 0x31, 0xa8, 0x78, 0xde, 0x50, 0x40, 0xf7, 0x62, 0xde, 0x36, 0xb2, 0xba +}; + +static void test_srp_init_and_free(void) { + esp_srp_handle_t *handle = esp_srp_init(ESP_NG_3072); + TEST_ASSERT_NOT_NULL(handle); + esp_srp_free(handle); +} + +static void test_srp_gen_salt_verifier(void) { + char *bytes_salt = NULL; + char *verifier = NULL; + int verifier_len = 0; + esp_err_t err = esp_srp_gen_salt_verifier(username, strlen(username), + password, strlen(password), + &bytes_salt, 16, &verifier, &verifier_len); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(bytes_salt); + TEST_ASSERT_NOT_NULL(verifier); + + // Verify salt length is as requested + TEST_ASSERT_EQUAL(16, 16); + + // Verify verifier length is correct for 3072-bit SRP + TEST_ASSERT_GREATER_THAN(0, verifier_len); + + // Log the generated salt and verifier for debugging + ESP_LOG_BUFFER_HEXDUMP("Generated Salt", bytes_salt, 16, ESP_LOG_INFO); + ESP_LOG_BUFFER_HEXDUMP("Generated Verifier", verifier, verifier_len, ESP_LOG_INFO); + + free(bytes_salt); + free(verifier); +} + +static void test_srp_set_salt_verifier(void) { + esp_srp_handle_t *handle = esp_srp_init(ESP_NG_3072); + TEST_ASSERT_NOT_NULL(handle); + + esp_err_t err = esp_srp_set_salt_verifier(handle, sec2_salt, sizeof(sec2_salt), + sec2_verifier, sizeof(sec2_verifier)); + TEST_ASSERT_EQUAL(ESP_OK, err); + + char *bytes_B = NULL; + int len_B = 0; + err = esp_srp_srv_pubkey_from_salt_verifier(handle, &bytes_B, &len_B); + TEST_ASSERT_EQUAL(ESP_OK, err); + // Verify B length is correct for 3072-bit SRP (384 bytes) + TEST_ASSERT_EQUAL(384, len_B); + + esp_srp_free(handle); +} + +static void test_srp_srv_pubkey(void) { + esp_srp_handle_t *handle = esp_srp_init(ESP_NG_3072); + TEST_ASSERT_NOT_NULL(handle); + + char *bytes_B = NULL; + int len_B = 0; + char *bytes_salt = NULL; + esp_err_t err = esp_srp_srv_pubkey(handle, username, strlen(username), + password, strlen(password), 16, + &bytes_B, &len_B, &bytes_salt); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(bytes_B); + TEST_ASSERT_NOT_NULL(bytes_salt); + + // Verify salt and B length + TEST_ASSERT_EQUAL(16, 16); + TEST_ASSERT_EQUAL(384, len_B); + + // Log for debugging + ESP_LOG_BUFFER_HEXDUMP("Generated Salt", bytes_salt, 16, ESP_LOG_INFO); + ESP_LOG_BUFFER_HEXDUMP("Generated Server Public Key B", bytes_B, len_B, ESP_LOG_INFO); + + esp_srp_free(handle); +} + +static void test_srp_get_session_key(void) { + esp_srp_handle_t *handle = esp_srp_init(ESP_NG_3072); + TEST_ASSERT_NOT_NULL(handle); + + char *bytes_B = NULL; + int len_B = 0; + char *bytes_salt = NULL; + esp_err_t err = esp_srp_srv_pubkey(handle, username, strlen(username), + password, strlen(password), 16, + &bytes_B, &len_B, &bytes_salt); + TEST_ASSERT_EQUAL(ESP_OK, err); + + // In a real scenario, bytes_A would be from client + // For testing purposes, we use bytes_B as a convenient value (server talks to itself) + char *bytes_key = NULL; + uint16_t len_key = 0; + err = esp_srp_get_session_key(handle, bytes_B, len_B, &bytes_key, &len_key); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(bytes_key); + + // Verify session key length (SHA512 hash) + TEST_ASSERT_EQUAL(64, len_key); + + // Log session key for debugging + ESP_LOG_BUFFER_HEXDUMP("Session Key", bytes_key, len_key, ESP_LOG_INFO); + + esp_srp_free(handle); +} + +static void test_srp_exchange_proofs(void) { + esp_srp_handle_t *handle = esp_srp_init(ESP_NG_3072); + TEST_ASSERT_NOT_NULL(handle); + + char *bytes_B = NULL; + int len_B = 0; + char *bytes_salt = NULL; + esp_err_t err = esp_srp_srv_pubkey(handle, username, strlen(username), + password, strlen(password), 16, + &bytes_B, &len_B, &bytes_salt); + TEST_ASSERT_EQUAL(ESP_OK, err); + + char *bytes_key = NULL; + uint16_t len_key = 0; + err = esp_srp_get_session_key(handle, bytes_B, len_B, &bytes_key, &len_key); + TEST_ASSERT_EQUAL(ESP_OK, err); + + // In a real environment, bytes_user_proof would be calculated by the client + // For our test, we'll generate zeros - this simulates an authentication failure scenario + char bytes_user_proof[64] = {0}; // Example proof + char bytes_host_proof[64] = {0}; + + // This should fail since user proof is zeros and doesn't match expected value + err = esp_srp_exchange_proofs(handle, (char *)username, strlen(username), + bytes_user_proof, bytes_host_proof); + TEST_ASSERT_EQUAL(ESP_FAIL, err); + + esp_srp_free(handle); +} + +// Add test for error handling with invalid parameters +static void test_srp_error_handling(void) { + esp_srp_handle_t *handle = esp_srp_init(ESP_NG_3072); + TEST_ASSERT_NOT_NULL(handle); + + // Test with NULL salt + esp_err_t err = esp_srp_set_salt_verifier(handle, NULL, sizeof(sec2_salt), + sec2_verifier, sizeof(sec2_verifier)); + TEST_ASSERT_NOT_EQUAL(ESP_OK, err); + + // Test with zero salt length + err = esp_srp_set_salt_verifier(handle, sec2_salt, 0, + sec2_verifier, sizeof(sec2_verifier)); + TEST_ASSERT_NOT_EQUAL(ESP_OK, err); + + // Test with NULL verifier + err = esp_srp_set_salt_verifier(handle, sec2_salt, sizeof(sec2_salt), + NULL, sizeof(sec2_verifier)); + TEST_ASSERT_NOT_EQUAL(ESP_OK, err); + + // Test with zero verifier length + err = esp_srp_set_salt_verifier(handle, sec2_salt, sizeof(sec2_salt), + sec2_verifier, 0); + TEST_ASSERT_NOT_EQUAL(ESP_OK, err); + + esp_srp_free(handle); +} + +// Test verifier calculation consistency +static void test_srp_verifier_consistency(void) { + char *bytes_salt1 = NULL; + char *verifier1 = NULL; + int verifier_len1 = 0; + + // Generate first salt/verifier pair + esp_err_t err = esp_srp_gen_salt_verifier(username, strlen(username), + password, strlen(password), + &bytes_salt1, 16, &verifier1, &verifier_len1); + TEST_ASSERT_EQUAL(ESP_OK, err); + + // Generate second salt/verifier pair + char *bytes_salt2 = NULL; + char *verifier2 = NULL; + int verifier_len2 = 0; + err = esp_srp_gen_salt_verifier(username, strlen(username), + password, strlen(password), + &bytes_salt2, 16, &verifier2, &verifier_len2); + TEST_ASSERT_EQUAL(ESP_OK, err); + + // Salts should be different (randomly generated) + TEST_ASSERT_NOT_EQUAL(0, memcmp(bytes_salt1, bytes_salt2, 16)); + + // Verifiers should also be different since they depend on the salt + TEST_ASSERT_NOT_EQUAL(0, memcmp(verifier1, verifier2, verifier_len1)); + + free(bytes_salt1); + free(verifier1); + free(bytes_salt2); + free(verifier2); +} + +static void test_srp_pubkey_randomness(void) { + esp_srp_handle_t *handle = esp_srp_init(ESP_NG_3072); + TEST_ASSERT_NOT_NULL(handle); + + esp_err_t err = esp_srp_set_salt_verifier(handle, sec2_salt, sizeof(sec2_salt), + sec2_verifier, sizeof(sec2_verifier)); + TEST_ASSERT_EQUAL(ESP_OK, err); + + // Generate first public key + char *bytes_B1 = NULL; + int len_B1 = 0; + err = esp_srp_srv_pubkey_from_salt_verifier(handle, &bytes_B1, &len_B1); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(bytes_B1); + TEST_ASSERT_EQUAL(384, len_B1); + + // Generate second public key with same salt/verifier + char *bytes_B2 = NULL; + int len_B2 = 0; + err = esp_srp_srv_pubkey_from_salt_verifier(handle, &bytes_B2, &len_B2); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(bytes_B2); + TEST_ASSERT_EQUAL(384, len_B2); + + // Keys should be different due to random b generation + TEST_ASSERT_NOT_EQUAL(0, memcmp(bytes_B1, bytes_B2, len_B1)); + + // Calculate CRCs for logging + uint32_t crc1 = esp_rom_crc32_le(0, (uint8_t*)bytes_B1, len_B1); + uint32_t crc2 = esp_rom_crc32_le(0, (uint8_t*)bytes_B2, len_B2); + ESP_LOGI(TAG, "Public key CRCs: %u, %u (should be different)", crc1, crc2); + + free(bytes_B1); + bytes_B1 = NULL; + esp_srp_free(handle); +} + +TEST_CASE("SRP init and free test", "[SRP]") +{ + test_srp_init_and_free(); +} + +TEST_CASE("SRP generate salt and verifier test", "[SRP]") +{ + test_srp_gen_salt_verifier(); +} + +TEST_CASE("SRP set salt and verifier test", "[SRP]") +{ + test_srp_set_salt_verifier(); +} + +TEST_CASE("SRP server public key test", "[SRP]") +{ + test_srp_srv_pubkey(); +} + +TEST_CASE("SRP get session key test", "[SRP]") +{ + test_srp_get_session_key(); +} + +TEST_CASE("SRP exchange proofs test", "[SRP]") +{ + test_srp_exchange_proofs(); +} + +TEST_CASE("SRP error handling test", "[SRP]") +{ + test_srp_error_handling(); +} + +TEST_CASE("SRP verifier consistency test", "[SRP]") +{ + test_srp_verifier_consistency(); +} + +TEST_CASE("SRP public key randomness test", "[SRP]") +{ + test_srp_pubkey_randomness(); +} diff --git a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c index 4eef749d73d..f0c580238dd 100644 --- a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c +++ b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c @@ -651,13 +651,6 @@ struct tls_connection * tls_connection_init(void *tls_ctx) wpa_printf(MSG_ERROR, "TLS: Failed to allocate connection memory"); return NULL; } -#ifdef CONFIG_TLSV13 - psa_status_t status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - wpa_printf(MSG_ERROR, "Failed to initialize PSA crypto, returned %d", (int) status); - return NULL; - } -#endif /* CONFIG_TLSV13 */ return conn; } diff --git a/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c b/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c index 27109aba6d1..bd7557566d7 100644 --- a/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c +++ b/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c @@ -9,7 +9,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * SPDX-FileContributor: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2015-2025 Espressif Systems (Shanghai) CO LTD */ #include #include @@ -61,14 +61,6 @@ static void https_get_task(void *pvParameters) mbedtls_ssl_config conf; mbedtls_net_context server_fd; -#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 - psa_status_t status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - ESP_LOGE(TAG, "Failed to initialize PSA crypto, returned %d", (int) status); - return; - } -#endif - mbedtls_ssl_init(&ssl); mbedtls_x509_crt_init(&cacert); mbedtls_ctr_drbg_init(&ctr_drbg); diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc new file mode 100644 index 00000000000..e98781f6920 --- /dev/null +++ b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc @@ -0,0 +1,9 @@ +CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y +CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN=y +CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y +CONFIG_LOG_DEFAULT_LEVEL_INFO=y + +# static D/IRAM usage 97%, add this to reduce +CONFIG_HAL_ASSERTION_DISABLE=y + +CONFIG_MBEDTLS_PSA_CRYPTO_C=n