feat(esp_tee): Support ECDSA secp384r1 keys in TEE secure storage

This commit is contained in:
Laukik Hase
2026-01-29 11:49:13 +05:30
parent 9ed8ae514a
commit 39f392f943
13 changed files with 350 additions and 109 deletions
@@ -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
*/
@@ -16,7 +16,11 @@ extern "C" {
#include "esp_err.h"
#include "esp_bit_defs.h"
#define MAX_ECDSA_SUPPORTED_KEY_LEN 32 /*!< Maximum supported size for the ECDSA key */
#if SOC_ECDSA_SUPPORT_CURVE_P384
#define MAX_ECDSA_SUPPORTED_KEY_LEN 48 /*!< Maximum supported size for the ECDSA key (SECP384R1) */
#else
#define MAX_ECDSA_SUPPORTED_KEY_LEN 32 /*!< Maximum supported size for the ECDSA key (SECP256R1) */
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
#define MAX_AES_SUPPORTED_KEY_LEN 32 /*!< Maximum supported size for the AES key */
#define SEC_STORAGE_FLAG_NONE 0 /*!< No flags */
@@ -30,6 +34,9 @@ typedef enum {
ESP_SEC_STG_KEY_AES256 = 0,
ESP_SEC_STG_KEY_ECDSA_SECP256R1 = 1,
ESP_SEC_STG_KEY_ECDSA_SECP192R1 = 2,
#if SOC_ECDSA_SUPPORT_CURVE_P384
ESP_SEC_STG_KEY_ECDSA_SECP384R1 = 3,
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
ESP_SEC_STG_TYPE_MAX,
} esp_tee_sec_storage_type_t;
@@ -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
*/
@@ -34,6 +34,7 @@
#define AES256_KEY_BITS (AES256_KEY_LEN * 8)
#define AES256_DEFAULT_IV_LEN 16
#define AES256_GCM_IV_LEN 12
#define ECDSA_SECP384R1_KEY_LEN 48
#define ECDSA_SECP256R1_KEY_LEN 32
#define ECDSA_SECP192R1_KEY_LEN 24
@@ -44,6 +45,12 @@
#define PBKDF2_HMAC_ITER 2048
/* Structure to hold ECDSA SECP384R1 key pair */
typedef struct {
uint8_t priv_key[ECDSA_SECP384R1_KEY_LEN]; /* Private key for ECDSA SECP384R1 */
uint8_t pub_key[2 * ECDSA_SECP384R1_KEY_LEN]; /* Public key for ECDSA SECP384R1 (X and Y coordinates) */
} __attribute__((aligned(4))) __attribute__((__packed__)) sec_stg_ecdsa_secp384r1_t;
/* Structure to hold ECDSA SECP256R1 key pair */
typedef struct {
uint8_t priv_key[ECDSA_SECP256R1_KEY_LEN]; /* Private key for ECDSA SECP256R1 */
@@ -67,11 +74,12 @@ typedef struct {
const esp_tee_sec_storage_type_t type; /* Type of the key */
uint32_t flags; /* Flags associated with the key */
union {
sec_stg_ecdsa_secp384r1_t ecdsa_secp384r1; /* ECDSA SECP384R1 key pair */
sec_stg_ecdsa_secp256r1_t ecdsa_secp256r1; /* ECDSA SECP256R1 key pair */
sec_stg_ecdsa_secp192r1_t ecdsa_secp192r1; /* ECDSA SECP192R1 key pair */
sec_stg_aes256_t aes256; /* AES-256 key and IV */
};
uint32_t reserved[38]; /* Reserved space for future use */
uint32_t reserved[26]; /* Reserved space for future use */
} __attribute__((aligned(4))) __attribute__((__packed__)) sec_stg_key_t;
_Static_assert(sizeof(sec_stg_key_t) == 256, "Incorrect sec_stg_key_t size");
@@ -296,6 +304,50 @@ esp_err_t esp_tee_sec_storage_clear_key(const char *key_id)
return err;
}
static esp_err_t get_ecdsa_curve_info(esp_tee_sec_storage_type_t type, sec_stg_key_t *ctx,
uint8_t **priv_key, size_t *priv_key_len, uint8_t **pub_key, size_t *pub_key_len)
{
if (!ctx || !priv_key || !priv_key_len || !pub_key || !pub_key_len) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = ESP_FAIL;
switch (type) {
case ESP_SEC_STG_KEY_ECDSA_SECP256R1:
*priv_key_len = ECDSA_SECP256R1_KEY_LEN;
*priv_key = ctx->ecdsa_secp256r1.priv_key;
*pub_key_len = sizeof(ctx->ecdsa_secp256r1.pub_key);
*pub_key = ctx->ecdsa_secp256r1.pub_key;
err = ESP_OK;
break;
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
case ESP_SEC_STG_KEY_ECDSA_SECP192R1:
*priv_key_len = ECDSA_SECP192R1_KEY_LEN;
*priv_key = ctx->ecdsa_secp192r1.priv_key;
*pub_key_len = sizeof(ctx->ecdsa_secp192r1.pub_key);
*pub_key = ctx->ecdsa_secp192r1.pub_key;
err = ESP_OK;
break;
#endif
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP384R1_SIGN
case ESP_SEC_STG_KEY_ECDSA_SECP384R1:
*priv_key_len = ECDSA_SECP384R1_KEY_LEN;
*priv_key = ctx->ecdsa_secp384r1.priv_key;
*pub_key_len = sizeof(ctx->ecdsa_secp384r1.pub_key);
*pub_key = ctx->ecdsa_secp384r1.pub_key;
err = ESP_OK;
break;
#endif
default:
ESP_LOGE(TAG, "Unsupported ECDSA curve type");
err = ESP_ERR_INVALID_ARG;
break;
}
return err;
}
static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t key_type)
{
if (keyctx == NULL) {
@@ -304,19 +356,20 @@ static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t
psa_key_id_t key_id = 0;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_bits(&key_attributes, ECDSA_SECP256R1_KEY_LEN * 8);
uint8_t *priv_key_buf = NULL;
size_t priv_key_buf_size = 0;
uint8_t *pub_key_buf = NULL;
size_t pub_key_buf_size = 0;
esp_err_t err = get_ecdsa_curve_info(key_type, keyctx, &priv_key_buf, &priv_key_buf_size, &pub_key_buf, &pub_key_buf_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to get ECDSA curve info: %d", err);
return -1;
}
psa_set_key_bits(&key_attributes, priv_key_buf_size * 8);
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
if (key_type == ESP_SEC_STG_KEY_ECDSA_SECP192R1) {
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
psa_set_key_bits(&key_attributes, ECDSA_SECP192R1_KEY_LEN * 8);
#else
ESP_LOGE(TAG, "Unsupported key-type!");
return -1;
#endif
}
psa_status_t status = psa_generate_key(&key_attributes, &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to generate ECDSA key: %ld", status);
@@ -326,26 +379,6 @@ static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t
size_t priv_key_len = 0;
size_t pub_key_len = 0;
/* Use the correct union member based on key type */
uint8_t *priv_key_buf = NULL;
size_t priv_key_buf_size = 0;
uint8_t *pub_key_buf = NULL;
size_t pub_key_buf_size = 0;
if (key_type == ESP_SEC_STG_KEY_ECDSA_SECP192R1) {
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
priv_key_buf = keyctx->ecdsa_secp192r1.priv_key;
priv_key_buf_size = sizeof(keyctx->ecdsa_secp192r1.priv_key);
pub_key_buf = keyctx->ecdsa_secp192r1.pub_key;
pub_key_buf_size = sizeof(keyctx->ecdsa_secp192r1.pub_key);
#endif
} else {
priv_key_buf = keyctx->ecdsa_secp256r1.priv_key;
priv_key_buf_size = sizeof(keyctx->ecdsa_secp256r1.priv_key);
pub_key_buf = keyctx->ecdsa_secp256r1.pub_key;
pub_key_buf_size = sizeof(keyctx->ecdsa_secp256r1.pub_key);
}
status = psa_export_key(key_id, priv_key_buf, priv_key_buf_size, &priv_key_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to export ECDSA private key: %ld", status);
@@ -356,7 +389,7 @@ static int generate_ecdsa_key(sec_stg_key_t *keyctx, esp_tee_sec_storage_type_t
* We need to strip the prefix and store only X and Y coordinates (64 bytes for secp256r1, 48 bytes for secp192r1)
* Use fixed-size array to avoid VLA issues with goto statements
*/
uint8_t pub_key_with_prefix[(2 * ECDSA_SECP256R1_KEY_LEN) + 1]; /* Max size: 65 bytes for secp256r1 */
uint8_t pub_key_with_prefix[(2 * ECDSA_SECP384R1_KEY_LEN) + 1]; /* Max size: 65 bytes for secp256r1 */
size_t pub_key_len_with_prefix = 0;
size_t expected_pub_key_len_with_prefix = pub_key_buf_size + 1;
@@ -421,6 +454,9 @@ esp_err_t esp_tee_sec_storage_gen_key(const esp_tee_sec_storage_key_cfg_t *cfg)
case ESP_SEC_STG_KEY_ECDSA_SECP256R1:
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
case ESP_SEC_STG_KEY_ECDSA_SECP192R1:
#endif
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP384R1_SIGN
case ESP_SEC_STG_KEY_ECDSA_SECP384R1:
#endif
if (generate_ecdsa_key(&keyctx, cfg->type) != 0) {
ESP_LOGE(TAG, "Failed to generate ECDSA keypair");
@@ -449,7 +485,12 @@ esp_err_t esp_tee_sec_storage_ecdsa_sign(const esp_tee_sec_storage_key_cfg_t *cf
#if !CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
if (cfg->type == ESP_SEC_STG_KEY_ECDSA_SECP192R1) {
ESP_LOGE(TAG, "Unsupported key-type!");
return ESP_ERR_NOT_SUPPORTED;
}
#endif
#if SOC_ECC_SUPPORT_CURVE_P384 && !CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP384R1_SIGN
if (cfg->type == ESP_SEC_STG_KEY_ECDSA_SECP384R1) {
return ESP_ERR_NOT_SUPPORTED;
}
#endif
@@ -490,12 +531,18 @@ esp_err_t esp_tee_sec_storage_ecdsa_sign(const esp_tee_sec_storage_key_cfg_t *cf
psa_set_key_bits(&key_attributes, ECDSA_SECP192R1_KEY_LEN * 8);
priv_key = keyctx.ecdsa_secp192r1.priv_key;
priv_key_len = sizeof(keyctx.ecdsa_secp192r1.priv_key);
#endif
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP384R1_SIGN
} else if (cfg->type == ESP_SEC_STG_KEY_ECDSA_SECP384R1) {
psa_set_key_bits(&key_attributes, ECDSA_SECP384R1_KEY_LEN * 8);
priv_key = keyctx.ecdsa_secp384r1.priv_key;
priv_key_len = sizeof(keyctx.ecdsa_secp384r1.priv_key);
#endif
}
psa_status_t status = psa_import_key(&key_attributes, priv_key, priv_key_len, &key_id);
if (status != PSA_SUCCESS) {
err = ESP_FAIL;
err = ESP_ERR_INVALID_ARG;
ESP_LOGE(TAG, "Failed to import ECDSA private key: %ld", status);
goto exit;
}
@@ -559,6 +606,12 @@ esp_err_t esp_tee_sec_storage_ecdsa_get_pubkey(const esp_tee_sec_storage_key_cfg
pub_key_src = keyctx.ecdsa_secp192r1.pub_key;
pub_key_len = ECDSA_SECP192R1_KEY_LEN;
break;
#endif
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP384R1_SIGN
case ESP_SEC_STG_KEY_ECDSA_SECP384R1:
pub_key_src = keyctx.ecdsa_secp384r1.pub_key;
pub_key_len = ECDSA_SECP384R1_KEY_LEN;
break;
#endif
default:
ESP_LOGE(TAG, "Unsupported key-type");
@@ -683,7 +736,11 @@ esp_err_t esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pbkdf2
}
int cfg_key_id = (int)CONFIG_SECURE_TEE_PBKDF2_EFUSE_HMAC_KEY_ID;
if (cfg_key_id < 0 || cfg_key_id >= HMAC_KEY_MAX) {
/* Split the checks to keep Coverity happy */
if (cfg_key_id < 0) {
return ESP_ERR_INVALID_ARG;
}
if (cfg_key_id >= HMAC_KEY_MAX) {
return ESP_ERR_INVALID_ARG;
}