From 5663e9329846ba02d2161d353ebcf942435675fb Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Tue, 23 Dec 2025 11:01:52 +0800 Subject: [PATCH] feat: migrates nvs_flash to PSA APIs --- components/nvs_flash/src/nvs_bootloader_aes.c | 72 ++++++++++++++----- .../nvs_flash/src/nvs_bootloader_xts_aes.c | 4 +- .../nvs_flash/src/nvs_encrypted_partition.hpp | 10 ++- .../nvs_flash/test_apps/main/app_main.c | 12 +--- .../nvs_flash/test_apps/main/test_nvs.c | 3 +- examples/storage/nvs/.build-test-rules.yml | 3 + 6 files changed, 69 insertions(+), 35 deletions(-) diff --git a/components/nvs_flash/src/nvs_bootloader_aes.c b/components/nvs_flash/src/nvs_bootloader_aes.c index 5cbbab5ad0..bd39b7d965 100644 --- a/components/nvs_flash/src/nvs_bootloader_aes.c +++ b/components/nvs_flash/src/nvs_bootloader_aes.c @@ -70,7 +70,9 @@ int nvs_bootloader_aes_crypt_ecb(enum AES_TYPE mode, } #endif /* CONFIG_ESP_ROM_HAS_MBEDTLS_CRYPTO_LIB */ #else /* BOOTLOADER_BUILD && !CONFIG_MBEDTLS_USE_CRYPTO_ROM_IMPL_BOOTLOADER */ -#include "mbedtls/aes.h" +#include "psa/crypto.h" + +static const char *TAG = "nvs_bootloader_aes"; int nvs_bootloader_aes_crypt_ecb(enum AES_TYPE mode, const unsigned char *key, @@ -78,34 +80,66 @@ int nvs_bootloader_aes_crypt_ecb(enum AES_TYPE mode, const unsigned char input[16], unsigned char output[16]) { - int ret = -1; - + psa_status_t status; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + psa_key_id_t key_id = 0; + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING); + psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); uint16_t keybits = key_bits == AES256 ? 256 : key_bits == AES192 ? 192 : 128; - int mbedtls_aes_mode = mode == AES_ENC ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT; - - mbedtls_aes_context ctx; - mbedtls_aes_init(&ctx); + psa_set_key_bits(&key_attributes, keybits); + status = psa_import_key(&key_attributes, key, keybits / 8, &key_id); + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to import key: %d", status); + return -1; + } + psa_reset_key_attributes(&key_attributes); if (mode == AES_ENC) { - ret = mbedtls_aes_setkey_enc(&ctx, key, keybits); + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_ECB_NO_PADDING); } else { - ret = mbedtls_aes_setkey_dec(&ctx, key, keybits); + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_ECB_NO_PADDING); + } + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to setup cipher operation: %d", status); + psa_destroy_key(key_id); + return -1; } - if (ret != 0) { - mbedtls_aes_free(&ctx); - return ret; + size_t output_len = 0; + status = psa_cipher_update(&operation, input, 16, output, 16, &output_len); + if (status != PSA_SUCCESS || output_len != 16) { + ESP_LOGE(TAG, "Failed to update cipher operation: %d", status); + psa_cipher_abort(&operation); + psa_destroy_key(key_id); + return -1; } - ret = mbedtls_aes_crypt_ecb(&ctx, mbedtls_aes_mode, input, output); - - if (ret != 0) { - mbedtls_aes_free(&ctx); - return ret; + status = psa_cipher_finish(&operation, output + output_len, 16 - output_len, &output_len); + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to finish cipher operation: %d", status); + psa_cipher_abort(&operation); + psa_destroy_key(key_id); + return -1; } - mbedtls_aes_free(&ctx); - return ret; + if (output_len != 0) { + ESP_LOGE(TAG, "Output length mismatch: expected 0, got %zu", output_len); + psa_cipher_abort(&operation); + psa_destroy_key(key_id); + return -1; + } + + status = psa_cipher_finish(&operation, output, 16, &output_len); + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to finish cipher operation: %d", status); + psa_destroy_key(key_id); + return -1; + } + + psa_destroy_key(key_id); + return 0; } #endif /* !(BOOTLOADER_BUILD && !CONFIG_MBEDTLS_USE_CRYPTO_ROM_IMPL_BOOTLOADER) */ #endif /* !SOC_AES_SUPPORTED */ diff --git a/components/nvs_flash/src/nvs_bootloader_xts_aes.c b/components/nvs_flash/src/nvs_bootloader_xts_aes.c index ce204f6a9d..331483e6e1 100644 --- a/components/nvs_flash/src/nvs_bootloader_xts_aes.c +++ b/components/nvs_flash/src/nvs_bootloader_xts_aes.c @@ -257,7 +257,8 @@ int nvs_bootloader_aes_crypt_xts(nvs_bootloader_xts_aes_context *ctx, #endif /* CONFIG_ESP_ROM_HAS_MBEDTLS_CRYPTO_LIB */ #else /* BOOTLOADER_BUILD && !CONFIG_MBEDTLS_USE_CRYPTO_ROM_IMPL_BOOTLOADER */ -#include "mbedtls/aes.h" +#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS +#include "mbedtls/private/aes.h" static mbedtls_aes_xts_context ctx_xts; @@ -291,7 +292,6 @@ int nvs_bootloader_aes_crypt_xts(nvs_bootloader_xts_aes_context *ctx, unsigned char *output) { (void) ctx; - int mbedtls_aes_mode = mode == AES_ENC ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT; return mbedtls_aes_crypt_xts(&ctx_xts, mbedtls_aes_mode, length, data_unit, input, output); } diff --git a/components/nvs_flash/src/nvs_encrypted_partition.hpp b/components/nvs_flash/src/nvs_encrypted_partition.hpp index 6cf128203d..d1060999ef 100644 --- a/components/nvs_flash/src/nvs_encrypted_partition.hpp +++ b/components/nvs_flash/src/nvs_encrypted_partition.hpp @@ -6,8 +6,14 @@ #pragma once #include "sdkconfig.h" // For CONFIG_NVS_BDL_STACK -#include "mbedtls/aes.h" // For mbedtls_aes_xts_context -#include "nvs_flash.h" // For nvs_sec_cfg_t + +/* NOTE: Using legacy mbedtls XTS API until PSA Crypto adds XTS support +* With TF-PSA-Crypto 1.0, AES headers moved to mbedtls/private/. +* Need MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS to access XTS functions. +*/ +#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS +#include "mbedtls/private/aes.h" +#include "nvs_flash.h" #include "nvs_partition.hpp" namespace nvs { diff --git a/components/nvs_flash/test_apps/main/app_main.c b/components/nvs_flash/test_apps/main/app_main.c index 17601f77a1..42db99809c 100644 --- a/components/nvs_flash/test_apps/main/app_main.c +++ b/components/nvs_flash/test_apps/main/app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -7,9 +7,6 @@ #include "freertos/task.h" #include "unity.h" #include "esp_partition.h" -#ifdef CONFIG_NVS_ENCRYPTION -#include "mbedtls/aes.h" -#endif #include "memory_checks.h" #include "esp_newlib.h" @@ -60,13 +57,6 @@ int32_t get_heap_free_difference(const bool nvs_active_pool) /* setUp runs before every test */ void setUp(void) { - // Execute mbedtls_aes_init operation to allocate AES interrupt - // allocation memory which is considered as memory leak otherwise -#if defined(CONFIG_NVS_ENCRYPTION) && defined(SOC_AES_SUPPORTED) - mbedtls_aes_context ctx; - mbedtls_aes_init(&ctx); -#endif - // Calling esp_partition_find_first ensures that the partitions have been loaded // and subsequent calls to esp_partition_find_first from the tests would not // load partitions which otherwise gets considered as a memory leak. diff --git a/components/nvs_flash/test_apps/main/test_nvs.c b/components/nvs_flash/test_apps/main/test_nvs.c index 04e4efc061..e4d1dfc5ca 100644 --- a/components/nvs_flash/test_apps/main/test_nvs.c +++ b/components/nvs_flash/test_apps/main/test_nvs.c @@ -29,7 +29,8 @@ #include "esp_random.h" #ifdef CONFIG_NVS_ENCRYPTION -#include "mbedtls/aes.h" +#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS +#include "mbedtls/private/aes.h" #endif #ifdef CONFIG_SOC_HMAC_SUPPORTED diff --git a/examples/storage/nvs/.build-test-rules.yml b/examples/storage/nvs/.build-test-rules.yml index f6abffbff6..e125c86d71 100644 --- a/examples/storage/nvs/.build-test-rules.yml +++ b/examples/storage/nvs/.build-test-rules.yml @@ -8,6 +8,9 @@ examples/storage/nvs/nvs_bootloader: - if: CONFIG_NAME == "nvs_enc_flash_enc" and (SOC_AES_SUPPORTED != 1 and ESP_ROM_HAS_MBEDTLS_CRYPTO_LIB != 1) - if: CONFIG_NAME == "nvs_enc_hmac" and (SOC_HMAC_SUPPORTED != 1 or (SOC_HMAC_SUPPORTED == 1 and (SOC_AES_SUPPORTED != 1 and ESP_ROM_HAS_MBEDTLS_CRYPTO_LIB != 1))) reason: As of now in such cases, we do not have any way to perform AES operations in the bootloader build + # TODO: IDF-15012 + - if: IDF_TARGET in ["esp32c2"] and CONFIG_NAME in ["nvs_enc_flash_enc", "nvs_enc_hmac"] + reason: PSA is not yet available for ESP32-C2 examples/storage/nvs/nvs_console: depends_components: