Merge branch 'feature/esp_tee_sec_stg_sign_w_pbkdf2' into 'master'

feat(esp_tee): Support for PBKDF2-based (HMAC) ECDSA signing

See merge request espressif/esp-idf!41074
This commit is contained in:
Laukik Hase
2025-09-20 10:28:00 +05:30
18 changed files with 375 additions and 33 deletions

View File

@@ -81,13 +81,20 @@ menu "ESP-TEE (Trusted Execution Environment)"
endchoice
config SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID
int "Secure Storage: eFuse HMAC key ID"
int "Secure Storage: eFuse HMAC key ID for storage encryption keys"
depends on SECURE_TEE_SEC_STG_MODE_RELEASE
range -1 5
default -1
help
eFuse block key ID storing the HMAC key for deriving the TEE secure storage encryption keys
config SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID
int "Secure Storage: eFuse HMAC key ID for PBKDF2 key derivation"
range -1 5
default -1
help
eFuse block key ID storing the HMAC key for deriving PBKDF2-based ECDSA keys
config SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
bool "Secure Storage: Support signing with the ECDSA SECP192R1 curve"
default n

View File

@@ -314,6 +314,10 @@ secure_services:
type: custom
function: esp_tee_sec_storage_aead_decrypt
args: 4
- id: 181
type: custom
function: esp_tee_sec_storage_ecdsa_sign_pbkdf2
args: 5
# ID: 195-199 (5) - OTA
- family: ota
entries:

View File

@@ -278,6 +278,10 @@ secure_services:
type: custom
function: esp_tee_sec_storage_aead_decrypt
args: 4
- id: 181
type: custom
function: esp_tee_sec_storage_ecdsa_sign_pbkdf2
args: 5
# ID: 195-199 (5) - OTA
- family: ota
entries:

View File

@@ -282,6 +282,10 @@ secure_services:
type: custom
function: esp_tee_sec_storage_aead_decrypt
args: 4
- id: 181
type: custom
function: esp_tee_sec_storage_ecdsa_sign_pbkdf2
args: 5
# ID: 195-199 (5) - OTA
- family: ota
entries:

View File

@@ -5,7 +5,7 @@ set(priv_requires esp_tee)
if(esp_tee_build)
list(APPEND srcs "tee_sec_storage.c")
list(APPEND priv_requires efuse esp_partition log mbedtls nvs_flash spi_flash tee_flash_mgr)
list(APPEND priv_requires efuse esp_partition esp_security log mbedtls nvs_flash spi_flash tee_flash_mgr)
else()
if(CONFIG_SECURE_ENABLE_TEE)
list(APPEND srcs "tee_sec_storage_wrapper.c")

View File

@@ -55,6 +55,16 @@ typedef struct {
size_t input_len; /*!< Length of input data */
} esp_tee_sec_storage_aead_ctx_t;
/**
* @brief Context structure for ECDSA signing with PBKDF2 (HMAC) derived key
*
*/
typedef struct {
const uint8_t *salt; /*!< Salt for PBKDF2 */
size_t salt_len; /*!< Length of the salt */
esp_tee_sec_storage_type_t key_type; /*!< Key type to be generated and used */
} esp_tee_sec_storage_pbkdf2_ctx_t;
/**
* @brief Structure holding the X and Y components of the ECDSA public key
*
@@ -149,6 +159,22 @@ esp_err_t esp_tee_sec_storage_aead_encrypt(const esp_tee_sec_storage_aead_ctx_t
*/
esp_err_t esp_tee_sec_storage_aead_decrypt(const esp_tee_sec_storage_aead_ctx_t *ctx, const uint8_t *tag, size_t tag_len, uint8_t *output);
/**
* @brief Generate and return the signature for the specified message digest using
* the key pair derived via PBKDF2-HMAC-SHA256 using the HMAC peripheral
* with the given salt and the configured HMAC eFuse key ID
* (`CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID`).
*
* @param[in] ctx Pointer to the PBKDF2 context
* @param[in] hash Message digest
* @param[in] hlen Digest length
* @param[out] out_sign Output context holding the signature
* @param[out] out_pubkey Output context holding the public key
*
* @return esp_err_t ESP_OK on success, appropriate error code otherwise.
*/
esp_err_t esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pbkdf2_ctx_t *ctx, const uint8_t *hash, size_t hlen, esp_tee_sec_storage_ecdsa_sign_t *out_sign, esp_tee_sec_storage_ecdsa_pubkey_t *out_pubkey);
#ifdef __cplusplus
}
#endif

View File

@@ -11,6 +11,8 @@
#include "esp_fault.h"
#include "esp_flash.h"
#include "esp_efuse.h"
#include "esp_efuse_chip.h"
#include "esp_hmac.h"
#include "esp_random.h"
#include "spi_flash_mmap.h"
@@ -19,11 +21,8 @@
#include "mbedtls/sha256.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/error.h"
#include "esp_hmac_pbkdf2.h"
#include "rom/efuse.h"
#if SOC_HMAC_SUPPORTED
#include "rom/hmac.h"
#endif
#include "esp_rom_sys.h"
#include "nvs.h"
#include "nvs_flash.h"
@@ -40,9 +39,13 @@
#define ECDSA_SECP256R1_KEY_LEN 32
#define ECDSA_SECP192R1_KEY_LEN 24
#define SHA256_DIGEST_SZ 32
#define EKEY_SEED 0xAEBE5A5A
#define TKEY_SEED 0xCEDEA5A5
#define PBKDF2_HMAC_ITER 2048
/* Structure to hold ECDSA SECP256R1 key pair */
typedef struct {
uint8_t priv_key[ECDSA_SECP256R1_KEY_LEN]; /* Private key for ECDSA SECP256R1 */
@@ -84,6 +87,10 @@ static const char *TAG = "secure_storage";
#error "TEE Secure Storage: Configured eFuse block (CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID) out of range!"
#endif
#if CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID == CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID
#error "TEE Secure Storage: Configured eFuse block for storage encryption keys (CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID) and PBKDF2 key derivation (CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID) cannot be the same!"
#endif
static int buffer_hexdump(const char *label, const void *buffer, size_t length)
{
#if CONFIG_SECURE_TEE_LOG_LEVEL >= 4
@@ -130,24 +137,21 @@ static int rand_func(void *rng_state, unsigned char *output, size_t len)
}
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
static esp_err_t compute_nvs_keys_with_hmac(ets_efuse_block_t hmac_key, nvs_sec_cfg_t *cfg)
static esp_err_t compute_nvs_keys_with_hmac(hmac_key_id_t hmac_key_id, nvs_sec_cfg_t *cfg)
{
uint32_t ekey_seed[8] = {[0 ... 7] = EKEY_SEED};
uint32_t tkey_seed[8] = {[0 ... 7] = TKEY_SEED};
memset(cfg, 0x00, sizeof(nvs_sec_cfg_t));
int ret = -1;
ets_hmac_enable();
ret = ets_hmac_calculate_message(hmac_key, ekey_seed, sizeof(ekey_seed), (uint8_t *)cfg->eky);
ret = ets_hmac_calculate_message(hmac_key, tkey_seed, sizeof(tkey_seed), (uint8_t *)cfg->tky);
ets_hmac_disable();
if (ret != 0) {
esp_err_t err = ESP_FAIL;
err = esp_hmac_calculate(hmac_key_id, ekey_seed, sizeof(ekey_seed), (uint8_t *)cfg->eky);
err |= esp_hmac_calculate(hmac_key_id, tkey_seed, sizeof(tkey_seed), (uint8_t *)cfg->tky);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to calculate seed HMAC");
return ESP_FAIL;
}
ESP_FAULT_ASSERT(ret == 0);
ESP_FAULT_ASSERT(err == ESP_OK);
/* NOTE: If the XTS E-key and T-key are the same, we have a hash collision */
ESP_FAULT_ASSERT(memcmp(cfg->eky, cfg->tky, NVS_KEY_SIZE) != 0);
@@ -163,14 +167,14 @@ static esp_err_t read_security_cfg_hmac(nvs_sec_cfg_t *cfg)
}
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
ets_efuse_block_t hmac_key = (ets_efuse_block_t)(ETS_EFUSE_BLOCK_KEY0 + CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
ets_efuse_purpose_t hmac_efuse_blk_purpose = ets_efuse_get_key_purpose(hmac_key);
if (hmac_efuse_blk_purpose != ETS_EFUSE_KEY_PURPOSE_HMAC_UP) {
esp_efuse_block_t hmac_key_blk = (esp_efuse_block_t)(EFUSE_BLK_KEY0 + (esp_efuse_block_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
esp_efuse_purpose_t hmac_efuse_blk_purpose = esp_efuse_get_key_purpose(hmac_key_blk);
if (hmac_efuse_blk_purpose != ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
ESP_LOGE(TAG, "HMAC key is not burnt in eFuse block");
return ESP_ERR_NOT_FOUND;
}
esp_err_t err = compute_nvs_keys_with_hmac(hmac_key, cfg);
esp_err_t err = compute_nvs_keys_with_hmac((hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID, cfg);
if (err != ESP_OK) {
return err;
}
@@ -304,11 +308,6 @@ static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t
NULL;
#endif
ret = mbedtls_mpi_write_binary(&ctxECDSA.MBEDTLS_PRIVATE(d), priv_key, key_len);
if (ret != 0) {
goto exit;
}
ret = mbedtls_mpi_write_binary(&(ctxECDSA.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X)), pub_key, key_len);
if (ret != 0) {
goto exit;
@@ -319,6 +318,11 @@ static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t
goto exit;
}
ret = mbedtls_mpi_write_binary(&ctxECDSA.MBEDTLS_PRIVATE(d), priv_key, key_len);
if (ret != 0) {
goto exit;
}
buffer_hexdump("Private key", priv_key, key_len);
buffer_hexdump("Public key", pub_key, key_len * 2);
@@ -457,18 +461,17 @@ esp_err_t esp_tee_sec_storage_ecdsa_sign(const esp_tee_sec_storage_key_cfg_t *cf
}
memset(out_sign, 0x00, sizeof(esp_tee_sec_storage_ecdsa_sign_t));
ret = mbedtls_mpi_write_binary(&r, out_sign->sign_r, key_len);
if (ret == 0) {
ret = mbedtls_mpi_write_binary(&s, out_sign->sign_s, key_len);
}
if (ret != 0) {
memset(out_sign, 0x00, sizeof(esp_tee_sec_storage_ecdsa_sign_t));
err = ESP_FAIL;
goto exit;
}
ret = mbedtls_mpi_write_binary(&s, out_sign->sign_s, key_len);
if (ret != 0) {
err = ESP_FAIL;
goto exit;
}
err = ESP_OK;
exit:
@@ -606,3 +609,132 @@ esp_err_t esp_tee_sec_storage_aead_decrypt(const esp_tee_sec_storage_aead_ctx_t
{
return tee_sec_storage_crypt_common(ctx->key_id, ctx->input, ctx->input_len, ctx->aad, ctx->aad_len, (uint8_t *)tag, tag_len, output, false);
}
esp_err_t esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pbkdf2_ctx_t *ctx,
const uint8_t *hash, size_t hlen,
esp_tee_sec_storage_ecdsa_sign_t *out_sign,
esp_tee_sec_storage_ecdsa_pubkey_t *out_pubkey)
{
if (!ctx || !hash || !out_sign || !out_pubkey || !ctx->salt || ctx->salt_len == 0) {
return ESP_ERR_INVALID_ARG;
}
if (hlen != SHA256_DIGEST_SZ) {
return ESP_ERR_INVALID_SIZE;
}
esp_err_t err = ESP_FAIL;
size_t key_len;
mbedtls_ecp_group_id curve_id = MBEDTLS_ECP_DP_NONE;
switch (ctx->key_type) {
case ESP_SEC_STG_KEY_ECDSA_SECP256R1:
key_len = ECDSA_SECP256R1_KEY_LEN;
curve_id = MBEDTLS_ECP_DP_SECP256R1;
break;
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
case ESP_SEC_STG_KEY_ECDSA_SECP192R1:
key_len = ECDSA_SECP192R1_KEY_LEN;
curve_id = MBEDTLS_ECP_DP_SECP192R1;
break;
#endif
default:
ESP_LOGE(TAG, "Unsupported key type");
return ESP_ERR_INVALID_ARG;
}
hmac_key_id_t key_id = (hmac_key_id_t)(CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
esp_efuse_block_t blk = EFUSE_BLK_KEY0 + (esp_efuse_block_t)(key_id);
if (esp_efuse_get_key_purpose(blk) != ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
ESP_LOGE(TAG, "HMAC key is not burnt in the specified eFuse block ID");
return ESP_ERR_NOT_FOUND;
}
uint8_t *derived_key = calloc(1, key_len);
if (!derived_key) {
return ESP_ERR_NO_MEM;
}
err = esp_hmac_derive_pbkdf2_key(key_id, ctx->salt, ctx->salt_len, PBKDF2_HMAC_ITER, key_len, derived_key);
if (err != ESP_OK) {
goto exit;
}
mbedtls_ecp_keypair keypair;
mbedtls_mpi r, s;
mbedtls_ecp_keypair_init(&keypair);
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
int ret = -1;
ret = mbedtls_ecp_group_load(&keypair.MBEDTLS_PRIVATE(grp), curve_id);
if (ret != 0) {
err = ESP_FAIL;
goto exit;
}
ret = mbedtls_mpi_read_binary(&keypair.MBEDTLS_PRIVATE(d), derived_key, key_len);
if (ret != 0) {
err = ESP_FAIL;
goto exit;
}
ret = mbedtls_ecp_check_privkey(&keypair.MBEDTLS_PRIVATE(grp), &keypair.MBEDTLS_PRIVATE(d));
if (ret != 0) {
ESP_LOGE(TAG, "Invalid private key!");
err = ESP_FAIL;
goto exit;
}
ret = mbedtls_ecp_keypair_calc_public(&keypair, rand_func, NULL);
if (ret != 0) {
err = ESP_FAIL;
goto exit;
}
ret = mbedtls_ecdsa_sign(&keypair.MBEDTLS_PRIVATE(grp), &r, &s,
&keypair.MBEDTLS_PRIVATE(d), hash, hlen,
rand_func, NULL);
if (ret != 0) {
err = ESP_FAIL;
goto exit;
}
memset(out_sign, 0x00, sizeof(esp_tee_sec_storage_ecdsa_sign_t));
ret = mbedtls_mpi_write_binary(&r, out_sign->sign_r, key_len);
if (ret == 0) {
ret = mbedtls_mpi_write_binary(&s, out_sign->sign_s, key_len);
}
if (ret != 0) {
memset(out_sign, 0x00, sizeof(esp_tee_sec_storage_ecdsa_sign_t));
err = ESP_FAIL;
goto exit;
}
memset(out_pubkey, 0x00, sizeof(esp_tee_sec_storage_ecdsa_pubkey_t));
ret = mbedtls_mpi_write_binary(&keypair.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), out_pubkey->pub_x, key_len);
if (ret == 0) {
ret = mbedtls_mpi_write_binary(&keypair.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), out_pubkey->pub_y, key_len);
}
if (ret != 0) {
memset(out_pubkey, 0x00, sizeof(esp_tee_sec_storage_ecdsa_pubkey_t));
err = ESP_FAIL;
goto exit;
}
err = ESP_OK;
exit:
if (derived_key) {
memset(derived_key, 0x00, key_len);
free(derived_key);
}
mbedtls_ecp_keypair_free(&keypair);
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
return err;
}

View File

@@ -37,3 +37,8 @@ esp_err_t esp_tee_sec_storage_aead_decrypt(const esp_tee_sec_storage_aead_ctx_t
{
return esp_tee_service_call_with_noniram_intr_disabled(5, SS_ESP_TEE_SEC_STORAGE_AEAD_DECRYPT, ctx, tag, tag_len, output);
}
esp_err_t esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pbkdf2_ctx_t *ctx, const uint8_t *hash, size_t hlen, esp_tee_sec_storage_ecdsa_sign_t *out_sign, esp_tee_sec_storage_ecdsa_pubkey_t *out_pubkey)
{
return esp_tee_service_call(6, SS_ESP_TEE_SEC_STORAGE_ECDSA_SIGN_PBKDF2, ctx, hash, hlen, out_sign, out_pubkey);
}

View File

@@ -220,6 +220,7 @@ esp_err_t _ss_esp_hmac_calculate(hmac_key_id_t key_id, const void *message, size
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) {
return ESP_ERR_INVALID_ARG;
@@ -236,6 +237,7 @@ esp_err_t _ss_esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token)
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) {
return ESP_ERR_INVALID_ARG;
@@ -262,6 +264,7 @@ esp_err_t _ss_esp_ds_sign(const void *message,
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) {
return ESP_ERR_INVALID_ARG;
@@ -283,6 +286,7 @@ esp_err_t _ss_esp_ds_start_sign(const void *message,
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) {
return ESP_ERR_INVALID_ARG;

View File

@@ -194,6 +194,26 @@ esp_err_t _ss_esp_tee_sec_storage_aead_decrypt(const esp_tee_sec_storage_aead_ct
return esp_tee_sec_storage_aead_decrypt(ctx, tag, tag_len, output);
}
esp_err_t _ss_esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pbkdf2_ctx_t *ctx, const uint8_t *hash, size_t hlen, esp_tee_sec_storage_ecdsa_sign_t *out_sign, esp_tee_sec_storage_ecdsa_pubkey_t *out_pubkey)
{
bool valid_addr = (esp_tee_ptr_in_ree((void *)ctx) &&
esp_tee_ptr_in_ree((void *)hash) &&
esp_tee_ptr_in_ree((void *)out_sign) &&
esp_tee_ptr_in_ree((void *)out_pubkey));
valid_addr &= (esp_tee_ptr_in_ree((void *)((char *)ctx + sizeof(esp_tee_sec_storage_pbkdf2_ctx_t))) &&
esp_tee_ptr_in_ree((void *)(hash + hlen)) &&
esp_tee_ptr_in_ree((void *)((char *)out_sign + sizeof(esp_tee_sec_storage_ecdsa_sign_t))) &&
esp_tee_ptr_in_ree((void *)((char *)out_pubkey + sizeof(esp_tee_sec_storage_ecdsa_pubkey_t))));
if (!valid_addr) {
return ESP_ERR_INVALID_ARG;
}
ESP_FAULT_ASSERT(valid_addr);
return esp_tee_sec_storage_ecdsa_sign_pbkdf2(ctx, hash, hlen, out_sign, out_pubkey);
}
/* ---------------------------------------------- MMU HAL ------------------------------------------------- */
void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr,

View File

@@ -21,7 +21,7 @@ Configure the Secure Storage mode for determining how the NVS XTS encryption key
- **Development** Mode: Encryption keys are embedded in the ESP-TEE firmware (identical across all instances).
- **Release** Mode: Encryption keys are derived via the HMAC peripheral using a key stored in eFuse.
- Set the eFuse key ID storing the HMAC key at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID`.
- Set the eFuse key ID storing the HMAC key at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID for storage encryption keys`.
- Snippet for burning the secure storage key in eFuse is given below.
```shell

View File

@@ -252,7 +252,6 @@ TEST_CASE("Test TEE Secure Storage - Operations with invalid/non-existent keys",
// Test ECDSA key with AES operation
ESP_LOGI(TAG, "Key ID: %s - Trying AES operation with ECDSA key...", key_cfg.id);
esp_err_t err = esp_tee_sec_storage_clear_key(key_cfg.id);
ESP_LOGW(TAG, "err: %x", err);
TEST_ASSERT_TRUE(err == ESP_OK || err == ESP_ERR_NOT_FOUND);
TEST_ESP_OK(esp_tee_sec_storage_gen_key(&key_cfg));
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_tee_sec_storage_aead_encrypt(&aead_ctx, tag, sizeof(tag), ciphertext));

View File

@@ -280,6 +280,10 @@ target_sources(mbedcrypto PRIVATE
"${COMPONENT_DIR}/port/esp_ds/esp_ds_common.c")
endif()
if(CONFIG_SOC_HMAC_SUPPORTED)
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_hmac_pbkdf2.c")
endif()
# Note: some mbedTLS hardware acceleration can be enabled/disabled by config.
#
# We don't need to filter aes.c as this uses a different prefix (esp_aes_x) and the

View File

@@ -65,3 +65,6 @@ target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/sha/core/sha.c"
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/ecc/esp_ecc.c"
"${COMPONENT_DIR}/port/ecc/ecc_alt.c")
# HMAC-based PBKDF2 implementation
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_hmac_pbkdf2.c")

View File

@@ -0,0 +1,82 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include <string.h>
#include "esp_hmac.h"
#include "sdkconfig.h"
#include "esp_hmac_pbkdf2.h"
#define SHA256_DIGEST_SZ 32
esp_err_t esp_hmac_derive_pbkdf2_key(hmac_key_id_t key_id, const uint8_t *salt, size_t salt_len, int iterations, size_t key_len, uint8_t *out_key)
{
if (!out_key || !salt || key_len == 0 || salt_len == 0 || iterations <= 0) {
return ESP_ERR_INVALID_ARG;
}
if (key_id >= HMAC_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}
uint8_t U[SHA256_DIGEST_SZ] = {0};
uint8_t T[SHA256_DIGEST_SZ] = {0};
uint8_t counter[4] = {0, 0, 0, 1};
uint8_t *hmac_input = calloc(1, salt_len + sizeof(counter));
if (!hmac_input) {
return ESP_ERR_NO_MEM;
}
esp_err_t err = ESP_FAIL;
size_t remaining = key_len;
uint8_t *out_p = out_key;
while (remaining > 0) {
memcpy(hmac_input, salt, salt_len);
memcpy(hmac_input + salt_len, counter, sizeof(counter));
err = esp_hmac_calculate(key_id, hmac_input, salt_len + sizeof(counter), U);
if (err != ESP_OK) {
goto cleanup;
}
memcpy(T, U, SHA256_DIGEST_SZ);
for (int i = 1; i < iterations; i++) {
err = esp_hmac_calculate(key_id, U, SHA256_DIGEST_SZ, U);
if (err != ESP_OK) {
goto cleanup;
}
for (int j = 0; j < SHA256_DIGEST_SZ; j++) {
T[j] ^= U[j];
}
}
size_t copy_len = (remaining < SHA256_DIGEST_SZ) ? remaining : SHA256_DIGEST_SZ;
memcpy(out_p, T, copy_len);
out_p += copy_len;
remaining -= copy_len;
for (int i = 3; i >= 0; i--) {
if (++counter[i]) {
break;
}
}
}
err = ESP_OK;
cleanup:
memset(U, 0x00, sizeof(U));
memset(T, 0x00, sizeof(T));
if (hmac_input) {
memset(hmac_input, 0x00, salt_len + sizeof(counter));
free(hmac_input);
}
return err;
}

View File

@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "esp_err.h"
#include "hal/hmac_types.h"
/**
* @brief Derive a key using PBKDF2-HMAC-SHA256 algorithm with HMAC peripheral
*
* This function implements PBKDF2 (Password-Based Key Derivation Function 2) using HMAC-SHA256
* to derive a cryptographic key from the efuse key and salt. The function uses the HMAC peripheral
* in upstream mode to perform the underlying HMAC calculations.
*
* @param key_id Determines which of the 6 key blocks in the efuses should be used as the base key.
* The corresponding purpose field of the key block must be set to HMAC upstream purpose.
* @param salt Input salt for the PBKDF2 algorithm
* @param salt_len Length of the salt in bytes (must be > 0)
* @param iterations Number of iterations (recommended >= 2048)
* @param key_len Length of the derived key to generate in bytes (must be > 0)
* @param[out] out_key Buffer to store the derived key. Must be at least key_len bytes.
* @return esp_err_t
* - ESP_OK: Key derivation successful
* - ESP_ERR_INVALID_ARG: Invalid arguments (null pointers, zero lengths, or key_id out of range)
* - ESP_ERR_NO_MEM: Memory allocation failed
* - ESP_FAIL: HMAC calculation failed
*/
esp_err_t esp_hmac_derive_pbkdf2_key(hmac_key_id_t key_id, const uint8_t *salt, size_t salt_len, int iterations, size_t key_len, uint8_t *out_key);
#ifdef __cplusplus
}
#endif

View File

@@ -21,6 +21,13 @@ Additionally, the secure storage provides interfaces for performing the followin
As per the current implementation, the TEE Secure Storage partition **must** have the label ``secure_storage``.
TEE secure storage also supports ECDSA signing with keys derived via PBKDF2 (Password-Based Key Derivation Function 2), using an HMAC key programmed in eFuse along with a user-provided salt. This mechanism enables ECDSA signing on both P-256 and P-192 curves without requiring storage of the actual private keys. The eFuse HMAC key ID for the PBKDF2 operations is specified via the :ref:`CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID` option.
.. important::
- The eFuse HMAC key ID used for PBKDF2-based signing **CANNOT** be the same as the one used for deriving TEE secure storage encryption keys (i.e., :ref:`CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID`).
- This eFuse ID is also exclusive to the TEE and **CANNOT** be used by the REE for any purpose.
Internals
---------

View File

@@ -39,7 +39,7 @@ TEE Secure Storage follows the NVS partition format and uses an AES-XTS encrypti
#### Configure the eFuse key ID storing the HMAC key
- Navigate to `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: Mode` and enable the `Release` mode configuration.
- Set the eFuse key ID storing the HMAC key at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID`.
- Set the eFuse key ID storing the HMAC key at `ESP-TEE (Trusted Execution Environment) → Secure Services → Secure Storage: eFuse HMAC key ID for storage encryption keys`.
**Note:** Before running the example, users must program the HMAC key into the configured eFuse block - refer to the snippet below. The TEE checks whether the specified eFuse block is empty or already programmed with a key. If the block is empty, an error will be returned; otherwise, the pre-programmed key will be used.