mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-02 18:10:57 +02:00
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:
@@ -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
|
||||
|
@@ -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:
|
||||
|
@@ -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:
|
||||
|
@@ -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:
|
||||
|
@@ -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")
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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));
|
||||
|
@@ -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
|
||||
|
@@ -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")
|
||||
|
82
components/mbedtls/port/esp_hmac_pbkdf2.c
Normal file
82
components/mbedtls/port/esp_hmac_pbkdf2.c
Normal 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;
|
||||
}
|
41
components/mbedtls/port/include/esp_hmac_pbkdf2.h
Normal file
41
components/mbedtls/port/include/esp_hmac_pbkdf2.h
Normal 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
|
@@ -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
|
||||
---------
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
Reference in New Issue
Block a user