From f8d0bae631d89b5c98f1e371620cfc3e1fd9d4f4 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Fri, 21 Aug 2026 17:30:59 +0530 Subject: [PATCH] feat(esp_tee): Disable the `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS` option for TEE build --- .../attestation/esp_att_utils_part_info.c | 21 ++- .../tee_sec_storage/tee_sec_storage.c | 165 ++++++++++++------ .../test_apps/tee_test_fw/main/CMakeLists.txt | 3 +- .../mbedtls/esp_tee/esp_tee_mbedtls_config.h | 1 - components/mbedtls/port/sha/esp_sha.c | 15 +- .../test_apps/mbedtls_ut/main/test_sha.c | 7 - 6 files changed, 139 insertions(+), 73 deletions(-) diff --git a/components/esp_tee/subproject/components/attestation/esp_att_utils_part_info.c b/components/esp_tee/subproject/components/attestation/esp_att_utils_part_info.c index c6aff792ef5..114184cdb01 100644 --- a/components/esp_tee/subproject/components/attestation/esp_att_utils_part_info.c +++ b/components/esp_tee/subproject/components/attestation/esp_att_utils_part_info.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -71,6 +71,21 @@ static size_t digest_type_to_len(esp_att_part_digest_type_t digest) } #if ESP_TEE_BUILD +#define DIGEST_CHUNK_LEN (1024) + +static psa_status_t hash_update_chunked(psa_hash_operation_t *hash_op, const void *data, uint32_t len) +{ + psa_status_t status = PSA_SUCCESS; + + for (uint32_t offset = 0; offset < len; offset += DIGEST_CHUNK_LEN) { + status = psa_hash_update(hash_op, (const uint8_t *)data + offset, MIN(DIGEST_CHUNK_LEN, len - offset)); + if (status != PSA_SUCCESS) { + break; + } + } + + return status; +} static esp_err_t read_partition(uint32_t offset, void *buf, size_t size) { @@ -99,12 +114,12 @@ esp_err_t get_flash_contents_sha256(uint32_t flash_offset, uint32_t len, uint8_t psa_hash_abort(&hash_op); return ESP_FAIL; } - status = psa_hash_update(&hash_op, image, mmap_len); + status = hash_update_chunked(&hash_op, image, mmap_len); + esp_tee_flash_munmap(image); if (status != PSA_SUCCESS) { psa_hash_abort(&hash_op); return ESP_FAIL; } - esp_tee_flash_munmap(image); flash_offset += mmap_len; len -= mmap_len; diff --git a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c index 6136b79591a..ed06175f282 100644 --- a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c +++ b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c @@ -6,6 +6,7 @@ #include #include +#include #include "soc/soc_caps.h" #include "esp_log.h" @@ -36,8 +37,8 @@ #define AES256_KEY_LEN 32 #define AES256_KEY_BITS (AES256_KEY_LEN * 8) #define AES256_GCM_IV_LEN 12 -#define AES256_GCM_TAG_LEN_MIN 12 /* NIST SP800-38D general-use minimum (96-bit tag) */ -#define AES256_GCM_TAG_LEN_MAX 16 /* full GCM tag (128-bit) */ +#define AES256_GCM_TAG_LEN_MIN 12 /* NIST SP800-38D general-use minimum (96-bit tag) */ +#define AES256_GCM_TAG_LEN_MAX 16 /* full GCM tag (128-bit) */ #define ECDSA_SECP384R1_KEY_LEN 48 #define ECDSA_SECP256R1_KEY_LEN 32 @@ -678,6 +679,46 @@ cleanup: return err; } +#define AEAD_CHUNK_LEN (1024) + +static psa_status_t aead_update_ad_chunked(psa_aead_operation_t *op, const uint8_t *aad, size_t aad_len) +{ + psa_status_t status = PSA_SUCCESS; + + for (size_t offset = 0; offset < aad_len; offset += AEAD_CHUNK_LEN) { + status = psa_aead_update_ad(op, aad + offset, MIN(AEAD_CHUNK_LEN, aad_len - offset)); + if (status != PSA_SUCCESS) { + break; + } + } + + return status; +} + +static psa_status_t aead_update_chunked(psa_aead_operation_t *op, psa_algorithm_t alg, + const uint8_t *input, size_t len, + uint8_t *out, size_t out_size, size_t *out_len) +{ + psa_status_t status = PSA_SUCCESS; + size_t total = 0; + + for (size_t offset = 0; offset < len; offset += AEAD_CHUNK_LEN) { + const size_t chunk = MIN(AEAD_CHUNK_LEN, len - offset); + const size_t update_osize = PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, alg, chunk); + const size_t osize = MIN(out_size - total, update_osize); + size_t olen = 0; + + status = psa_aead_update(op, input + offset, chunk, out + total, osize, &olen); + if (status != PSA_SUCCESS) { + break; + } + total += olen; + } + + *out_len = total; + return status; +} + static esp_err_t tee_sec_storage_crypt_common(const char *key_id, const uint8_t *input, size_t len, const uint8_t *aad, size_t aad_len, uint8_t *iv, size_t iv_len, uint8_t *tag, size_t tag_len, uint8_t *output, bool is_encrypt) @@ -700,21 +741,16 @@ static esp_err_t tee_sec_storage_crypt_common(const char *key_id, const uint8_t return ESP_ERR_INVALID_SIZE; } - esp_err_t err = secure_storage_find_key(key_id); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Key ID not found"); - return err; - } - psa_key_id_t psa_key_id = 0; - uint8_t *aead_buf = NULL; - size_t aead_buf_len = 0; + psa_aead_operation_t aead_op = PSA_AEAD_OPERATION_INIT; + uint8_t *plaintext = NULL; sec_stg_key_t keyctx; size_t keyctx_len = sizeof(keyctx); - err = secure_storage_read(key_id, (void *)&keyctx, &keyctx_len); + esp_err_t err = secure_storage_read(key_id, (void *)&keyctx, &keyctx_len); if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to fetch key from storage"); + ESP_LOGE(TAG, "%s", (err == ESP_ERR_NVS_NOT_FOUND) ? + "Key ID not found" : "Failed to fetch key from storage"); goto cleanup; } @@ -724,10 +760,12 @@ static esp_err_t tee_sec_storage_crypt_common(const char *key_id, const uint8_t goto cleanup; } + const psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, tag_len); + // Setup PSA key attributes psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&attributes, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, tag_len)); + psa_set_key_usage_flags(&attributes, is_encrypt ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, alg); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, AES256_KEY_BITS); psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); @@ -741,56 +779,75 @@ static esp_err_t tee_sec_storage_crypt_common(const char *key_id, const uint8_t goto cleanup; } - /* PSA AEAD wants ciphertext+tag concatenated in a single buffer for both - * encrypt (output) and decrypt (input). */ - aead_buf_len = len + tag_len; - aead_buf = malloc(aead_buf_len); - if (!aead_buf) { - err = ESP_ERR_NO_MEM; + uint8_t iv_local[AES256_GCM_IV_LEN]; + uint8_t tag_local[AES256_GCM_TAG_LEN_MAX]; + + size_t out_len = 0, fin_len = 0, tag_out_len = tag_len; + + uint8_t *out_buf = output; + + if (is_encrypt) { + status = psa_aead_encrypt_setup(&aead_op, psa_key_id, alg); + if (status == PSA_SUCCESS) { + status = psa_generate_random(iv_local, iv_len); + } + } else { + memcpy(iv_local, iv, iv_len); + memcpy(tag_local, tag, tag_len); + + /* NOTE: Only the AEAD-written prefix is ever copied out; zeroized at cleanup */ + plaintext = malloc(len); + if (!plaintext) { + err = ESP_ERR_NO_MEM; + goto cleanup; + } + out_buf = plaintext; + + status = psa_aead_decrypt_setup(&aead_op, psa_key_id, alg); + } + + /* Shared spine: nonce, then AAD, then the payload in bounded chunks. */ + if (status == PSA_SUCCESS) { + status = psa_aead_set_nonce(&aead_op, iv_local, iv_len); + } + if (status == PSA_SUCCESS) { + status = aead_update_ad_chunked(&aead_op, aad, aad_len); + } + if (status == PSA_SUCCESS) { + status = aead_update_chunked(&aead_op, alg, input, len, out_buf, len, &out_len); + } + if (status == PSA_SUCCESS) { + const size_t osize_fv = PSA_AEAD_FINISH_OUTPUT_SIZE(PSA_KEY_TYPE_AES, alg); + const size_t osize = MIN(len - out_len, osize_fv); + if (is_encrypt) { + status = psa_aead_finish(&aead_op, out_buf + out_len, osize, &fin_len, + tag_local, tag_len, &tag_out_len); + } else { + status = psa_aead_verify(&aead_op, out_buf + out_len, osize, &fin_len, + tag_local, tag_len); + } + } + + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Error in %scrypting data: %d", is_encrypt ? "en" : "de", status); + err = ESP_FAIL; goto cleanup; } if (is_encrypt) { - status = psa_generate_random(iv, iv_len); - if (status != PSA_SUCCESS) { - err = ESP_FAIL; - goto cleanup; - } - - size_t output_length = 0; - status = psa_aead_encrypt(psa_key_id, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, tag_len), - iv, iv_len, aad, aad_len, input, len, - aead_buf, aead_buf_len, &output_length); - if (status != PSA_SUCCESS) { - ESP_LOGE(TAG, "Error in encrypting data: %d", status); - err = ESP_FAIL; - goto cleanup; - } - - // Separate ciphertext and tag - memcpy(output, aead_buf, len); - memcpy(tag, aead_buf + len, tag_len); + memcpy(iv, iv_local, iv_len); + memcpy(tag, tag_local, tag_out_len); } else { - memcpy(aead_buf, input, len); - memcpy(aead_buf + len, tag, tag_len); - - size_t output_length = 0; - status = psa_aead_decrypt(psa_key_id, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, tag_len), - iv, iv_len, aad, aad_len, aead_buf, aead_buf_len, - output, len, &output_length); - if (status != PSA_SUCCESS) { - ESP_LOGE(TAG, "Error in decrypting data: %d", status); - err = ESP_FAIL; - goto cleanup; - } + memcpy(output, plaintext, out_len + fin_len); } err = ESP_OK; cleanup: - if (aead_buf) { - mbedtls_platform_zeroize(aead_buf, aead_buf_len); - free(aead_buf); + psa_aead_abort(&aead_op); + if (plaintext) { + mbedtls_platform_zeroize(plaintext, len); + free(plaintext); } if (psa_key_id != 0) { psa_destroy_key(psa_key_id); diff --git a/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt b/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt index 9c8e4c6e968..a4bb62ec758 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt @@ -31,8 +31,7 @@ endif() # SHA if(CONFIG_SOC_SHA_SUPPORTED) - list(APPEND srcs "${mbedtls_test_srcs_dir}/test_sha.c" - "${mbedtls_test_srcs_dir}/test_sha_perf.c") + list(APPEND srcs "${mbedtls_test_srcs_dir}/test_sha_perf.c") endif() # Mixed diff --git a/components/mbedtls/esp_tee/esp_tee_mbedtls_config.h b/components/mbedtls/esp_tee/esp_tee_mbedtls_config.h index 3ba1e1c44e6..74c5e272429 100644 --- a/components/mbedtls/esp_tee/esp_tee_mbedtls_config.h +++ b/components/mbedtls/esp_tee/esp_tee_mbedtls_config.h @@ -27,7 +27,6 @@ #pragma once -#define MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS #ifndef CONFIG_IDF_TARGET_LINUX #undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY #define MBEDTLS_PSA_DRIVER_GET_ENTROPY diff --git a/components/mbedtls/port/sha/esp_sha.c b/components/mbedtls/port/sha/esp_sha.c index 0c39bf6e74d..00def753fa6 100644 --- a/components/mbedtls/port/sha/esp_sha.c +++ b/components/mbedtls/port/sha/esp_sha.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include #include "psa/crypto.h" +#include "mbedtls/platform_util.h" #include "hal/sha_hal.h" #include "hal/sha_types.h" @@ -64,18 +65,20 @@ void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, uns if (alg == PSA_ALG_NONE) { ESP_LOGE(TAG, "SHA type %d not supported", (int)sha_type); - abort(); + return; } size_t olen; size_t output_len = PSA_HASH_LENGTH(alg); status = psa_hash_compute(alg, input, ilen, output, output_len, &olen); if (status != PSA_SUCCESS) { - ESP_LOGE(TAG, "SHA computation failed, status %d", status); - abort(); + ESP_LOGE(TAG, "SHA computation failed (status %d), output zeroed", (int)status); + mbedtls_platform_zeroize(output, output_len); + return; } if (olen != output_len) { - ESP_LOGE(TAG, "SHA output length mismatch, expected %u, got %u", output_len, olen); - abort(); + ESP_LOGE(TAG, "SHA output length mismatch (expected %u, got %u), output zeroed", output_len, olen); + mbedtls_platform_zeroize(output, output_len); + return; } } diff --git a/components/mbedtls/test_apps/mbedtls_ut/main/test_sha.c b/components/mbedtls/test_apps/mbedtls_ut/main/test_sha.c index 3f90a9ca73b..9f710e816a1 100644 --- a/components/mbedtls/test_apps/mbedtls_ut/main/test_sha.c +++ b/components/mbedtls/test_apps/mbedtls_ut/main/test_sha.c @@ -112,12 +112,6 @@ TEST_CASE("Test esp_sha()", "[hw_crypto]") #endif } -/* NOTE: This test attempts to mmap 1MB of flash starting from address 0x00, which overlaps - * the entire TEE protected region, causing the mmap operation to fail and triggering an - * exception in the subsequent steps. - */ -#if !CONFIG_SECURE_ENABLE_TEE - TEST_CASE("Test esp_sha() function with long input", "[hw_crypto]") { int r = -1; @@ -176,4 +170,3 @@ TEST_CASE("Test esp_sha() function with long input", "[hw_crypto]") } #endif -#endif // SOC_SHA_SUPPORTED && CONFIG_MBEDTLS_HARDWARE_SHA