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

This commit is contained in:
Laukik Hase
2025-07-30 15:17:18 +05:30
parent 333a2c0ebc
commit c152663408
18 changed files with 375 additions and 33 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,7 @@ set(priv_requires esp_tee)
if(esp_tee_build) if(esp_tee_build)
list(APPEND srcs "tee_sec_storage.c") 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() else()
if(CONFIG_SECURE_ENABLE_TEE) if(CONFIG_SECURE_ENABLE_TEE)
list(APPEND srcs "tee_sec_storage_wrapper.c") list(APPEND srcs "tee_sec_storage_wrapper.c")

View File

@@ -55,6 +55,16 @@ typedef struct {
size_t input_len; /*!< Length of input data */ size_t input_len; /*!< Length of input data */
} esp_tee_sec_storage_aead_ctx_t; } 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 * @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); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -11,6 +11,8 @@
#include "esp_fault.h" #include "esp_fault.h"
#include "esp_flash.h" #include "esp_flash.h"
#include "esp_efuse.h" #include "esp_efuse.h"
#include "esp_efuse_chip.h"
#include "esp_hmac.h"
#include "esp_random.h" #include "esp_random.h"
#include "spi_flash_mmap.h" #include "spi_flash_mmap.h"
@@ -19,11 +21,8 @@
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#include "mbedtls/error.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 "esp_rom_sys.h"
#include "nvs.h" #include "nvs.h"
#include "nvs_flash.h" #include "nvs_flash.h"
@@ -40,9 +39,13 @@
#define ECDSA_SECP256R1_KEY_LEN 32 #define ECDSA_SECP256R1_KEY_LEN 32
#define ECDSA_SECP192R1_KEY_LEN 24 #define ECDSA_SECP192R1_KEY_LEN 24
#define SHA256_DIGEST_SZ 32
#define EKEY_SEED 0xAEBE5A5A #define EKEY_SEED 0xAEBE5A5A
#define TKEY_SEED 0xCEDEA5A5 #define TKEY_SEED 0xCEDEA5A5
#define PBKDF2_HMAC_ITER 2048
/* Structure to hold ECDSA SECP256R1 key pair */ /* Structure to hold ECDSA SECP256R1 key pair */
typedef struct { typedef struct {
uint8_t priv_key[ECDSA_SECP256R1_KEY_LEN]; /* Private key for ECDSA SECP256R1 */ 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!" #error "TEE Secure Storage: Configured eFuse block (CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID) out of range!"
#endif #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) static int buffer_hexdump(const char *label, const void *buffer, size_t length)
{ {
#if CONFIG_SECURE_TEE_LOG_LEVEL >= 4 #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 #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 ekey_seed[8] = {[0 ... 7] = EKEY_SEED};
uint32_t tkey_seed[8] = {[0 ... 7] = TKEY_SEED}; uint32_t tkey_seed[8] = {[0 ... 7] = TKEY_SEED};
memset(cfg, 0x00, sizeof(nvs_sec_cfg_t)); memset(cfg, 0x00, sizeof(nvs_sec_cfg_t));
int ret = -1; esp_err_t err = ESP_FAIL;
ets_hmac_enable(); err = esp_hmac_calculate(hmac_key_id, ekey_seed, sizeof(ekey_seed), (uint8_t *)cfg->eky);
ret = ets_hmac_calculate_message(hmac_key, 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);
ret = ets_hmac_calculate_message(hmac_key, tkey_seed, sizeof(tkey_seed), (uint8_t *)cfg->tky); if (err != ESP_OK) {
ets_hmac_disable();
if (ret != 0) {
ESP_LOGE(TAG, "Failed to calculate seed HMAC"); ESP_LOGE(TAG, "Failed to calculate seed HMAC");
return ESP_FAIL; 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 */ /* 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); 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 #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); 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);
ets_efuse_purpose_t hmac_efuse_blk_purpose = ets_efuse_get_key_purpose(hmac_key); esp_efuse_purpose_t hmac_efuse_blk_purpose = esp_efuse_get_key_purpose(hmac_key_blk);
if (hmac_efuse_blk_purpose != ETS_EFUSE_KEY_PURPOSE_HMAC_UP) { if (hmac_efuse_blk_purpose != ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
ESP_LOGE(TAG, "HMAC key is not burnt in eFuse block"); ESP_LOGE(TAG, "HMAC key is not burnt in eFuse block");
return ESP_ERR_NOT_FOUND; 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) { if (err != ESP_OK) {
return err; return err;
} }
@@ -304,11 +308,6 @@ static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t
NULL; NULL;
#endif #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); ret = mbedtls_mpi_write_binary(&(ctxECDSA.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X)), pub_key, key_len);
if (ret != 0) { if (ret != 0) {
goto exit; goto exit;
@@ -319,6 +318,11 @@ static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t
goto exit; 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("Private key", priv_key, key_len);
buffer_hexdump("Public key", pub_key, key_len * 2); 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)); memset(out_sign, 0x00, sizeof(esp_tee_sec_storage_ecdsa_sign_t));
ret = mbedtls_mpi_write_binary(&r, out_sign->sign_r, key_len); 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) { if (ret != 0) {
memset(out_sign, 0x00, sizeof(esp_tee_sec_storage_ecdsa_sign_t));
err = ESP_FAIL; err = ESP_FAIL;
goto exit; 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; err = ESP_OK;
exit: 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); 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); 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 #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); valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif #endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) { if (!valid_addr) {
return ESP_ERR_INVALID_ARG; 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 #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); valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif #endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) { if (!valid_addr) {
return ESP_ERR_INVALID_ARG; 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 #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); valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif #endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) { if (!valid_addr) {
return ESP_ERR_INVALID_ARG; 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 #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); valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID);
#endif #endif
valid_addr &= (key_id != (hmac_key_id_t)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID);
if (!valid_addr) { if (!valid_addr) {
return ESP_ERR_INVALID_ARG; 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); 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 ------------------------------------------------- */ /* ---------------------------------------------- MMU HAL ------------------------------------------------- */
void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr, 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). - **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. - **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. - Snippet for burning the secure storage key in eFuse is given below.
```shell ```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 // Test ECDSA key with AES operation
ESP_LOGI(TAG, "Key ID: %s - Trying AES operation with ECDSA key...", key_cfg.id); 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_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_ASSERT_TRUE(err == ESP_OK || err == ESP_ERR_NOT_FOUND);
TEST_ESP_OK(esp_tee_sec_storage_gen_key(&key_cfg)); 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)); 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") "${COMPONENT_DIR}/port/esp_ds/esp_ds_common.c")
endif() 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. # 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 # 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" target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/ecc/esp_ecc.c"
"${COMPONENT_DIR}/port/ecc/ecc_alt.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``. 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 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 #### 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. - 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. **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.