mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
fix(mbedtls): Flash compatibility across multiple key sources (ECDSA, HMAC)
This commit is contained in:
Submodule components/mbedtls/mbedtls updated: 582ff48203...ae71b9e470
@@ -14,6 +14,7 @@
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_assert.h"
|
||||
#include "esp_crypto_lock.h"
|
||||
#include "esp_crypto_periph_clk.h"
|
||||
|
||||
@@ -40,6 +41,7 @@
|
||||
#endif /* SOC_MPI_SUPPORTED && SOC_ECDSA_USES_MPI */
|
||||
|
||||
#include "psa_crypto_driver_esp_ecdsa.h"
|
||||
#include "psa_crypto_driver_esp_opaque_common.h"
|
||||
#include "psa_crypto_driver_wrappers_no_static.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@@ -49,6 +51,160 @@ static const char *TAG = "psa_crypto_driver_esp_ecdsa";
|
||||
#include "esp_tee_sec_storage.h"
|
||||
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
|
||||
|
||||
/*
|
||||
* Per-source storage structs — internal to the driver.
|
||||
* These are what actually get persisted to NVS, not the user-facing esp_ecdsa_opaque_key_t.
|
||||
*
|
||||
* All storage structs share a common prefix: [version][key_source][curve]
|
||||
* so that the driver can identify the key source at operation time.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_ECDSA_KEY_STORAGE_VERSION_INVALID = 0,
|
||||
ESP_ECDSA_KEY_STORAGE_VERSION_V1 = 1,
|
||||
ESP_ECDSA_KEY_STORAGE_VERSION_MAX = 2,
|
||||
} esp_ecdsa_key_storage_version_t;
|
||||
|
||||
/* TEE secure storage key IDs are NVS key names, max 16 bytes including null terminator */
|
||||
#define ESP_ECDSA_TEE_KEY_ID_MAX_LEN 16
|
||||
ESP_STATIC_ASSERT(ESP_ECDSA_TEE_KEY_ID_MAX_LEN < UINT8_MAX, "ESP_ECDSA_TEE_KEY_ID_MAX_LEN must be less than 255 as we use uint8_t for tee_key_id_len");
|
||||
|
||||
typedef enum {
|
||||
ESP_ECDSA_KEY_SOURCE_EFUSE = 0,
|
||||
ESP_ECDSA_KEY_SOURCE_TEE = 1,
|
||||
ESP_ECDSA_KEY_SOURCE_KEY_MGR = 2,
|
||||
} esp_ecdsa_key_source_t;
|
||||
|
||||
/* Storage structs use uint8_t for curve instead of esp_ecdsa_curve_t (enum)
|
||||
* to ensure stable serialized size across compilers. */
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t version;
|
||||
uint8_t key_source; /* esp_ecdsa_key_source_t */
|
||||
uint8_t curve; /* esp_ecdsa_curve_t */
|
||||
} esp_ecdsa_common_key_storage_metadata_t;
|
||||
|
||||
ESP_STATIC_ASSERT(sizeof(esp_ecdsa_common_key_storage_metadata_t) == 3 * sizeof(uint8_t), "esp_ecdsa_common_key_storage_metadata_t structure must be exactly 3 bytes");
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
esp_ecdsa_common_key_storage_metadata_t metadata;
|
||||
uint8_t efuse_block;
|
||||
} esp_ecdsa_efuse_key_storage_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
esp_ecdsa_common_key_storage_metadata_t metadata;
|
||||
uint8_t tee_key_id_len;
|
||||
/* followed by: char tee_key_id[tee_key_id_len] */
|
||||
} esp_ecdsa_tee_key_storage_t;
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
typedef struct {
|
||||
esp_ecdsa_common_key_storage_metadata_t metadata;
|
||||
uint8_t reserved; /* explicit padding for alignment */
|
||||
esp_key_mgr_key_recovery_info_t key_recovery_info;
|
||||
} esp_ecdsa_km_key_storage_t;
|
||||
|
||||
ESP_STATIC_ASSERT(offsetof(esp_ecdsa_km_key_storage_t, key_recovery_info) % 4 == 0,
|
||||
"key_recovery_info must be 4-byte aligned in esp_ecdsa_km_key_storage_t");
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
|
||||
/**
|
||||
* Pointer-based storage for volatile keys.
|
||||
* Embeds the user-facing opaque key struct (which contains pointers).
|
||||
* The caller must keep all referenced data valid until psa_destroy_key().
|
||||
*/
|
||||
typedef struct {
|
||||
esp_ecdsa_common_key_storage_metadata_t metadata;
|
||||
esp_ecdsa_opaque_key_t opaque_key;
|
||||
} esp_ecdsa_volatile_key_storage_t;
|
||||
|
||||
/**
|
||||
* @brief Read the key_source tag from any storage struct.
|
||||
*
|
||||
* All storage structs share the layout: [version(1)][key_source(1)][...]
|
||||
*/
|
||||
static inline esp_ecdsa_key_source_t storage_get_key_source(const uint8_t *key_buffer)
|
||||
{
|
||||
return (esp_ecdsa_key_source_t)key_buffer[1];
|
||||
}
|
||||
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
/**
|
||||
* @brief Calculate the storage buffer size required for a given user-facing opaque key.
|
||||
*
|
||||
* Inspects the user struct to determine the key source and returns the
|
||||
* corresponding storage struct size. Used by both the PSA size function
|
||||
* and for key_buffer_size validation at operation time.
|
||||
*/
|
||||
static size_t esp_ecdsa_get_storage_size(const esp_ecdsa_opaque_key_t *key, bool persistent)
|
||||
{
|
||||
if (!persistent) {
|
||||
(void)key;
|
||||
return sizeof(esp_ecdsa_volatile_key_storage_t);
|
||||
}
|
||||
|
||||
/* persistent: per-source inline storage */
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
if (key->tee_key_id) {
|
||||
size_t len = strnlen(key->tee_key_id, ESP_ECDSA_TEE_KEY_ID_MAX_LEN);
|
||||
return sizeof(esp_ecdsa_tee_key_storage_t) + len + 1;
|
||||
}
|
||||
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
if (key->key_recovery_info) {
|
||||
return sizeof(esp_ecdsa_km_key_storage_t);
|
||||
}
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
|
||||
(void)key;
|
||||
return sizeof(esp_ecdsa_efuse_key_storage_t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate the expected storage size from an already-serialized storage buffer.
|
||||
*
|
||||
* Reads the key_source tag to determine the storage struct type and returns
|
||||
* the expected minimum buffer size. Used for key_buffer_size validation at
|
||||
* operation time (sign, export).
|
||||
*/
|
||||
static psa_status_t esp_ecdsa_get_expected_storage_size(const uint8_t *key_buffer, bool persistent, size_t *expected_storage_size)
|
||||
{
|
||||
if (key_buffer[0] <= ESP_ECDSA_KEY_STORAGE_VERSION_INVALID || key_buffer[0] >= ESP_ECDSA_KEY_STORAGE_VERSION_MAX) {
|
||||
return PSA_ERROR_DATA_INVALID;
|
||||
}
|
||||
|
||||
*expected_storage_size = 0;
|
||||
|
||||
if (!persistent) {
|
||||
*expected_storage_size = sizeof(esp_ecdsa_volatile_key_storage_t);
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
/* persistent: dispatch by key_source */
|
||||
esp_ecdsa_key_source_t key_source = storage_get_key_source(key_buffer);
|
||||
|
||||
switch (key_source) {
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
case ESP_ECDSA_KEY_SOURCE_TEE:
|
||||
const esp_ecdsa_tee_key_storage_t *tee_st =
|
||||
(const esp_ecdsa_tee_key_storage_t *)key_buffer;
|
||||
*expected_storage_size = sizeof(esp_ecdsa_tee_key_storage_t) + tee_st->tee_key_id_len;
|
||||
return PSA_SUCCESS;
|
||||
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
case ESP_ECDSA_KEY_SOURCE_KEY_MGR:
|
||||
*expected_storage_size = sizeof(esp_ecdsa_km_key_storage_t);
|
||||
return PSA_SUCCESS;
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
case ESP_ECDSA_KEY_SOURCE_EFUSE:
|
||||
*expected_storage_size = sizeof(esp_ecdsa_efuse_key_storage_t);
|
||||
return PSA_SUCCESS;
|
||||
default:
|
||||
return PSA_ERROR_DATA_INVALID;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
|
||||
|
||||
/* Key lengths for different ECDSA curves */
|
||||
#define ECDSA_KEY_LEN_P192 24
|
||||
#define ECDSA_KEY_LEN_P256 32
|
||||
@@ -97,6 +253,23 @@ static esp_ecdsa_curve_t psa_bits_to_ecdsa_curve(size_t key_len)
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || (CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN && SOC_ECDSA_SUPPORT_EXPORT_PUBKEY)
|
||||
/**
|
||||
* @brief Map the driver's esp_ecdsa_curve_t enum to the HAL's ecdsa_curve_t enum.
|
||||
*/
|
||||
static ecdsa_curve_t esp_ecdsa_curve_to_hal_curve(esp_ecdsa_curve_t curve)
|
||||
{
|
||||
switch (curve) {
|
||||
case ESP_ECDSA_CURVE_SECP192R1: return ECDSA_CURVE_SECP192R1;
|
||||
case ESP_ECDSA_CURVE_SECP256R1: return ECDSA_CURVE_SECP256R1;
|
||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
case ESP_ECDSA_CURVE_SECP384R1: return ECDSA_CURVE_SECP384R1;
|
||||
#endif
|
||||
default: return (ecdsa_curve_t)-1;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || (CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN && SOC_ECDSA_SUPPORT_EXPORT_PUBKEY) */
|
||||
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
static esp_tee_sec_storage_type_t esp_ecdsa_curve_to_tee_sec_storage_type(esp_ecdsa_curve_t curve)
|
||||
{
|
||||
@@ -434,7 +607,7 @@ static psa_status_t esp_ecdsa_validate_efuse_block(esp_ecdsa_curve_t curve, int
|
||||
#endif /* !SOC_ECDSA_SUPPORT_CURVE_SPECIFIC_KEY_PURPOSES */
|
||||
|
||||
if (expected_key_purpose_low != esp_efuse_get_key_purpose((esp_efuse_block_t)low_blk)) {
|
||||
ESP_LOGE(TAG, "Key burned in efuse has incorrect purpose, expected: %d, got: %d, low_blk: %d", expected_key_purpose_low, esp_efuse_get_key_purpose((esp_efuse_block_t)low_blk), low_blk);
|
||||
ESP_LOGE(TAG, "Key burned in efuse has incorrect purpose");
|
||||
return PSA_ERROR_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
@@ -454,6 +627,10 @@ static psa_status_t esp_ecdsa_validate_efuse_block(esp_ecdsa_curve_t curve, int
|
||||
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN */
|
||||
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
|
||||
/**
|
||||
* @brief Validate the user-facing opaque key struct at import time.
|
||||
*/
|
||||
static psa_status_t validate_ecdsa_opaque_key_attributes(const psa_key_attributes_t *attributes, const esp_ecdsa_opaque_key_t *opaque_key)
|
||||
{
|
||||
esp_ecdsa_curve_t expected_curve = psa_bits_to_ecdsa_curve(PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)));
|
||||
@@ -480,6 +657,33 @@ static psa_status_t validate_ecdsa_opaque_key_attributes(const psa_key_attribute
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validate the stored curve against PSA key attributes at operation time.
|
||||
*
|
||||
* This is called when reading from a per-source storage struct (after import/NVS load)
|
||||
* to detect NVS corruption or wrong-blob scenarios.
|
||||
*/
|
||||
static psa_status_t validate_storage_curve(const psa_key_attributes_t *attributes, esp_ecdsa_curve_t stored_curve)
|
||||
{
|
||||
esp_ecdsa_curve_t expected_curve = psa_bits_to_ecdsa_curve(PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)));
|
||||
if (expected_curve == ESP_ECDSA_CURVE_MAX || expected_curve != stored_curve) {
|
||||
ESP_LOGE(TAG, "Invalid curve expected");
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extract curve from a storage struct in key_buffer.
|
||||
*
|
||||
* All storage structs share the layout: [version(1)] [key_source(1)] [curve(1)].
|
||||
* This helper reads the curve from the common prefix.
|
||||
*/
|
||||
static esp_ecdsa_curve_t storage_get_curve(const uint8_t *key_buffer)
|
||||
{
|
||||
return (esp_ecdsa_curve_t)key_buffer[2];
|
||||
}
|
||||
|
||||
psa_status_t esp_ecdsa_opaque_import_key(
|
||||
const psa_key_attributes_t *attributes,
|
||||
const uint8_t *data,
|
||||
@@ -489,22 +693,99 @@ psa_status_t esp_ecdsa_opaque_import_key(
|
||||
size_t *key_buffer_length,
|
||||
size_t *bits)
|
||||
{
|
||||
if (!attributes || !data || data_length < 1 || !key_buffer || !key_buffer_length || !bits) {
|
||||
if (!attributes || !data || data_length < sizeof(esp_ecdsa_opaque_key_t) || !key_buffer || !key_buffer_length || !bits) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_opaque_key_t) || data_length < sizeof(esp_ecdsa_opaque_key_t)) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
const esp_ecdsa_opaque_key_t *opaque_key = (const esp_ecdsa_opaque_key_t *) data;
|
||||
psa_status_t status = validate_ecdsa_opaque_key_attributes(attributes, opaque_key);
|
||||
if (status != PSA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
memcpy(key_buffer, opaque_key, sizeof(esp_ecdsa_opaque_key_t));
|
||||
*key_buffer_length = sizeof(esp_ecdsa_opaque_key_t);
|
||||
bool is_persistent = esp_opaque_key_is_persistent(attributes);
|
||||
|
||||
/* Determine key source from user struct */
|
||||
esp_ecdsa_key_source_t key_source = ESP_ECDSA_KEY_SOURCE_EFUSE;
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
if (opaque_key->tee_key_id) {
|
||||
key_source = ESP_ECDSA_KEY_SOURCE_TEE;
|
||||
} else
|
||||
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
if (opaque_key->key_recovery_info) {
|
||||
key_source = ESP_ECDSA_KEY_SOURCE_KEY_MGR;
|
||||
} else
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
{
|
||||
key_source = ESP_ECDSA_KEY_SOURCE_EFUSE;
|
||||
}
|
||||
|
||||
if (!is_persistent) {
|
||||
/* Volatile: store pointers -- caller keeps data alive */
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_volatile_key_storage_t)) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
esp_ecdsa_volatile_key_storage_t *storage = (esp_ecdsa_volatile_key_storage_t *)key_buffer;
|
||||
storage->metadata.version = ESP_ECDSA_KEY_STORAGE_VERSION_V1;
|
||||
storage->metadata.key_source = key_source;
|
||||
storage->metadata.curve = (uint8_t)opaque_key->curve;
|
||||
memcpy(&storage->opaque_key, opaque_key, sizeof(esp_ecdsa_opaque_key_t));
|
||||
*key_buffer_length = sizeof(esp_ecdsa_volatile_key_storage_t);
|
||||
} else {
|
||||
/* Persistent: per-source inline storage */
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_TEE) {
|
||||
size_t str_len = strnlen(opaque_key->tee_key_id, ESP_ECDSA_TEE_KEY_ID_MAX_LEN);
|
||||
if (str_len == 0 || str_len >= ESP_ECDSA_TEE_KEY_ID_MAX_LEN) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
uint8_t id_len = (uint8_t)(str_len + 1); /* include null terminator */
|
||||
size_t required_len = sizeof(esp_ecdsa_tee_key_storage_t) + id_len;
|
||||
if (key_buffer_size < required_len) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
esp_ecdsa_tee_key_storage_t *storage = (esp_ecdsa_tee_key_storage_t *)key_buffer;
|
||||
storage->metadata.version = ESP_ECDSA_KEY_STORAGE_VERSION_V1;
|
||||
storage->metadata.key_source = ESP_ECDSA_KEY_SOURCE_TEE;
|
||||
storage->metadata.curve = (uint8_t)opaque_key->curve;
|
||||
storage->tee_key_id_len = id_len;
|
||||
memcpy((uint8_t *)storage + sizeof(esp_ecdsa_tee_key_storage_t), opaque_key->tee_key_id, str_len);
|
||||
/* Explicitly null-terminate */
|
||||
*((uint8_t *)storage + sizeof(esp_ecdsa_tee_key_storage_t) + str_len) = '\0';
|
||||
*key_buffer_length = required_len;
|
||||
} else
|
||||
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_KEY_MGR) {
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_km_key_storage_t)) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
esp_ecdsa_km_key_storage_t *storage = (esp_ecdsa_km_key_storage_t *)key_buffer;
|
||||
storage->metadata.version = ESP_ECDSA_KEY_STORAGE_VERSION_V1;
|
||||
storage->metadata.key_source = ESP_ECDSA_KEY_SOURCE_KEY_MGR;
|
||||
storage->metadata.curve = (uint8_t)opaque_key->curve;
|
||||
storage->reserved = 0;
|
||||
memcpy(&storage->key_recovery_info, opaque_key->key_recovery_info,
|
||||
sizeof(esp_key_mgr_key_recovery_info_t));
|
||||
*key_buffer_length = sizeof(esp_ecdsa_km_key_storage_t);
|
||||
} else
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
{
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_efuse_key_storage_t)) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
esp_ecdsa_efuse_key_storage_t *storage = (esp_ecdsa_efuse_key_storage_t *)key_buffer;
|
||||
storage->metadata.version = ESP_ECDSA_KEY_STORAGE_VERSION_V1;
|
||||
storage->metadata.key_source = ESP_ECDSA_KEY_SOURCE_EFUSE;
|
||||
storage->metadata.curve = (uint8_t)opaque_key->curve;
|
||||
storage->efuse_block = opaque_key->efuse_block;
|
||||
*key_buffer_length = sizeof(esp_ecdsa_efuse_key_storage_t);
|
||||
}
|
||||
}
|
||||
|
||||
*bits = psa_get_key_bits(attributes);
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
@@ -522,22 +803,35 @@ psa_status_t esp_ecdsa_opaque_sign_hash_start(
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_opaque_key_t)) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
// Check if ECDSA algorithm
|
||||
if (!PSA_ALG_IS_ECDSA(alg)) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const esp_ecdsa_opaque_key_t *opaque_key = (const esp_ecdsa_opaque_key_t *) key_buffer;
|
||||
psa_status_t status = validate_ecdsa_opaque_key_attributes(attributes, opaque_key);
|
||||
bool is_persistent = esp_opaque_key_is_persistent(attributes);
|
||||
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_efuse_key_storage_t)) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
size_t expected_storage_size = 0;
|
||||
psa_status_t status = esp_ecdsa_get_expected_storage_size(key_buffer, is_persistent, &expected_storage_size);
|
||||
if (status != PSA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = validate_ecdsa_sha_alg(alg, opaque_key->curve);
|
||||
if (key_buffer_size < expected_storage_size) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* Read curve from the storage struct and validate against attributes */
|
||||
esp_ecdsa_curve_t curve = storage_get_curve(key_buffer);
|
||||
status = validate_storage_curve(attributes, curve);
|
||||
if (status != PSA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = validate_ecdsa_sha_alg(alg, curve);
|
||||
if (status != PSA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
@@ -545,28 +839,31 @@ psa_status_t esp_ecdsa_opaque_sign_hash_start(
|
||||
size_t component_len = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes));
|
||||
|
||||
// Validate hash length
|
||||
if ((opaque_key->curve == ESP_ECDSA_CURVE_SECP192R1 && hash_length != ECDSA_SHA_LEN
|
||||
if ((curve == ESP_ECDSA_CURVE_SECP192R1 && hash_length != ECDSA_SHA_LEN
|
||||
#if SOC_ECDSA_SUPPORTED
|
||||
&& esp_efuse_is_ecdsa_p192_curve_supported()
|
||||
#endif
|
||||
) || (opaque_key->curve == ESP_ECDSA_CURVE_SECP256R1 && hash_length != ECDSA_SHA_LEN
|
||||
) || (curve == ESP_ECDSA_CURVE_SECP256R1 && hash_length != ECDSA_SHA_LEN
|
||||
#if SOC_ECDSA_SUPPORTED
|
||||
&& esp_efuse_is_ecdsa_p256_curve_supported()
|
||||
#endif
|
||||
)
|
||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
|| (opaque_key->curve == ESP_ECDSA_CURVE_SECP384R1 && hash_length != ECDSA_SHA_LEN_P384)
|
||||
|| (curve == ESP_ECDSA_CURVE_SECP384R1 && hash_length != ECDSA_SHA_LEN_P384)
|
||||
#endif
|
||||
) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
memset(operation, 0, sizeof(esp_ecdsa_opaque_sign_hash_operation_t));
|
||||
operation->is_persistent = is_persistent;
|
||||
|
||||
operation->key_len = component_len;
|
||||
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
if (opaque_key->tee_key_id) {
|
||||
/* Determine hash endianness based on key source */
|
||||
esp_ecdsa_key_source_t key_source = storage_get_key_source(key_buffer);
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_TEE) {
|
||||
// The ESP-TEE API expects the hash in big endian order
|
||||
memcpy(operation->sha, hash, component_len);
|
||||
} else
|
||||
@@ -575,7 +872,7 @@ psa_status_t esp_ecdsa_opaque_sign_hash_start(
|
||||
change_endianess(hash, operation->sha, component_len);
|
||||
}
|
||||
|
||||
operation->opaque_key = opaque_key;
|
||||
operation->key_buffer = key_buffer;
|
||||
operation->alg = alg;
|
||||
operation->sha_len = hash_length;
|
||||
|
||||
@@ -597,16 +894,34 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
esp_ecdsa_key_source_t key_source __attribute__((unused)) = storage_get_key_source(operation->key_buffer);
|
||||
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
const esp_ecdsa_opaque_key_t *opaque_key = operation->opaque_key;
|
||||
if (opaque_key->tee_key_id) {
|
||||
esp_tee_sec_storage_type_t tee_sec_storage_type = esp_ecdsa_curve_to_tee_sec_storage_type(opaque_key->curve);
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_TEE) {
|
||||
/* TEE key path */
|
||||
const char *tee_key_id = NULL;
|
||||
uint8_t stored_curve;
|
||||
|
||||
if (!operation->is_persistent) {
|
||||
const esp_ecdsa_volatile_key_storage_t *ptr_st =
|
||||
(const esp_ecdsa_volatile_key_storage_t *)operation->key_buffer;
|
||||
tee_key_id = ptr_st->opaque_key.tee_key_id;
|
||||
stored_curve = ptr_st->metadata.curve;
|
||||
} else {
|
||||
const esp_ecdsa_tee_key_storage_t *tee_st =
|
||||
(const esp_ecdsa_tee_key_storage_t *)operation->key_buffer;
|
||||
tee_key_id =
|
||||
(const char *)((const uint8_t *)tee_st + sizeof(esp_ecdsa_tee_key_storage_t));
|
||||
stored_curve = tee_st->metadata.curve;
|
||||
}
|
||||
|
||||
esp_tee_sec_storage_type_t tee_sec_storage_type = esp_ecdsa_curve_to_tee_sec_storage_type(stored_curve);
|
||||
if (tee_sec_storage_type == (esp_tee_sec_storage_type_t) -1) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
esp_tee_sec_storage_key_cfg_t cfg = {
|
||||
.id = opaque_key->tee_key_id,
|
||||
.id = tee_key_id,
|
||||
.type = tee_sec_storage_type
|
||||
};
|
||||
|
||||
@@ -618,7 +933,6 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
|
||||
}
|
||||
|
||||
memcpy(signature, sign.signature, 2 * component_len);
|
||||
*signature_length = 2 * component_len;
|
||||
|
||||
} else
|
||||
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
|
||||
@@ -630,6 +944,8 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
|
||||
return PSA_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_ecdsa_curve_t curve = storage_get_curve(operation->key_buffer);
|
||||
|
||||
ecdsa_sign_type_t k_type = ECDSA_K_TYPE_TRNG;
|
||||
|
||||
#if CONFIG_MBEDTLS_ECDSA_DETERMINISTIC && SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
|
||||
@@ -645,9 +961,18 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
|
||||
uint8_t zeroes[MAX_ECDSA_COMPONENT_LEN] = {0};
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
esp_key_mgr_key_recovery_info_t *key_recovery_info = operation->opaque_key->key_recovery_info;
|
||||
if (key_recovery_info) {
|
||||
esp_err_t err = esp_key_mgr_activate_key(key_recovery_info);
|
||||
const esp_key_mgr_key_recovery_info_t *key_recovery_info = NULL;
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_KEY_MGR) {
|
||||
if (!operation->is_persistent) {
|
||||
const esp_ecdsa_volatile_key_storage_t *ptr_st =
|
||||
(const esp_ecdsa_volatile_key_storage_t *)operation->key_buffer;
|
||||
key_recovery_info = ptr_st->opaque_key.key_recovery_info;
|
||||
} else {
|
||||
const esp_ecdsa_km_key_storage_t *km_st =
|
||||
(const esp_ecdsa_km_key_storage_t *)operation->key_buffer;
|
||||
key_recovery_info = &km_st->key_recovery_info;
|
||||
}
|
||||
esp_err_t err = esp_key_mgr_activate_key((esp_key_mgr_key_recovery_info_t *)key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to activate key: 0x%x", err);
|
||||
return PSA_ERROR_INVALID_HANDLE;
|
||||
@@ -664,10 +989,16 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
|
||||
uint16_t deterministic_loop_number __attribute__((unused)) = 1;
|
||||
#endif /* CONFIG_MBEDTLS_ECDSA_DETERMINISTIC && !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */
|
||||
|
||||
ecdsa_curve_t hal_curve = esp_ecdsa_curve_to_hal_curve(curve);
|
||||
if (hal_curve == (ecdsa_curve_t)-1) {
|
||||
esp_ecdsa_release_hardware();
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
do {
|
||||
ecdsa_hal_config_t conf = {
|
||||
.mode = ECDSA_MODE_SIGN_GEN,
|
||||
.curve = operation->opaque_key->curve,
|
||||
.curve = hal_curve,
|
||||
.sha_mode = ECDSA_Z_USER_PROVIDED,
|
||||
.sign_type = k_type,
|
||||
};
|
||||
@@ -679,13 +1010,20 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
|
||||
#endif /* CONFIG_MBEDTLS_ECDSA_DETERMINISTIC && !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
// Set key source (consistent with esp_ecdsa_pk_conf_t)
|
||||
if (key_recovery_info) {
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_KEY_MGR) {
|
||||
conf.use_km_key = 1;
|
||||
} else
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
{
|
||||
conf.efuse_key_blk = operation->opaque_key->efuse_block;
|
||||
if (!operation->is_persistent) {
|
||||
const esp_ecdsa_volatile_key_storage_t *ptr_st =
|
||||
(const esp_ecdsa_volatile_key_storage_t *)operation->key_buffer;
|
||||
conf.efuse_key_blk = ptr_st->opaque_key.efuse_block;
|
||||
} else {
|
||||
const esp_ecdsa_efuse_key_storage_t *efuse_st =
|
||||
(const esp_ecdsa_efuse_key_storage_t *)operation->key_buffer;
|
||||
conf.efuse_key_blk = efuse_st->efuse_block;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_CONSTANT_TIME_CM
|
||||
@@ -791,16 +1129,31 @@ psa_status_t esp_ecdsa_opaque_export_public_key(
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_opaque_key_t)) {
|
||||
bool is_persistent = esp_opaque_key_is_persistent(attributes);
|
||||
|
||||
if (key_buffer_size < sizeof(esp_ecdsa_efuse_key_storage_t)) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const esp_ecdsa_opaque_key_t *opaque_key = (const esp_ecdsa_opaque_key_t *) key_buffer;
|
||||
status = validate_ecdsa_opaque_key_attributes(attributes, opaque_key);
|
||||
size_t expected_storage_size = 0;
|
||||
status = esp_ecdsa_get_expected_storage_size(key_buffer, is_persistent, &expected_storage_size);
|
||||
if (status != PSA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (key_buffer_size < expected_storage_size) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* Validate stored curve against attributes */
|
||||
esp_ecdsa_curve_t curve = storage_get_curve(key_buffer);
|
||||
status = validate_storage_curve(attributes, curve);
|
||||
if (status != PSA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
esp_ecdsa_key_source_t key_source __attribute__((unused)) = storage_get_key_source(key_buffer);
|
||||
|
||||
// Get curve parameters from attributes
|
||||
size_t key_len = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes));
|
||||
|
||||
@@ -813,14 +1166,28 @@ psa_status_t esp_ecdsa_opaque_export_public_key(
|
||||
}
|
||||
|
||||
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
|
||||
if (opaque_key->tee_key_id) {
|
||||
esp_tee_sec_storage_type_t tee_sec_storage_type = esp_ecdsa_curve_to_tee_sec_storage_type(opaque_key->curve);
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_TEE) {
|
||||
/* TEE key path */
|
||||
const char *tee_key_id = NULL;
|
||||
|
||||
if (!is_persistent) {
|
||||
const esp_ecdsa_volatile_key_storage_t *ptr_st =
|
||||
(const esp_ecdsa_volatile_key_storage_t *)key_buffer;
|
||||
tee_key_id = ptr_st->opaque_key.tee_key_id;
|
||||
} else {
|
||||
const esp_ecdsa_tee_key_storage_t *tee_st =
|
||||
(const esp_ecdsa_tee_key_storage_t *)key_buffer;
|
||||
tee_key_id =
|
||||
(const char *)((const uint8_t *)tee_st + sizeof(esp_ecdsa_tee_key_storage_t));
|
||||
}
|
||||
|
||||
esp_tee_sec_storage_type_t tee_sec_storage_type = esp_ecdsa_curve_to_tee_sec_storage_type(curve);
|
||||
if (tee_sec_storage_type == (esp_tee_sec_storage_type_t) -1) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
esp_tee_sec_storage_key_cfg_t cfg = {
|
||||
.id = opaque_key->tee_key_id,
|
||||
.id = tee_key_id,
|
||||
.type = tee_sec_storage_type,
|
||||
};
|
||||
|
||||
@@ -848,15 +1215,29 @@ psa_status_t esp_ecdsa_opaque_export_public_key(
|
||||
uint8_t qx[MAX_ECDSA_COMPONENT_LEN];
|
||||
uint8_t qy[MAX_ECDSA_COMPONENT_LEN];
|
||||
|
||||
ecdsa_curve_t hal_curve = esp_ecdsa_curve_to_hal_curve(curve);
|
||||
if (hal_curve == (ecdsa_curve_t)-1) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ecdsa_hal_config_t conf = {
|
||||
.mode = ECDSA_MODE_EXPORT_PUBKEY,
|
||||
.curve = opaque_key->curve,
|
||||
.curve = hal_curve,
|
||||
};
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
esp_key_mgr_key_recovery_info_t *key_recovery_info = opaque_key->key_recovery_info;
|
||||
if (key_recovery_info) {
|
||||
esp_err_t err = esp_key_mgr_activate_key(key_recovery_info);
|
||||
const esp_key_mgr_key_recovery_info_t *key_recovery_info = NULL;
|
||||
if (key_source == ESP_ECDSA_KEY_SOURCE_KEY_MGR) {
|
||||
if (!is_persistent) {
|
||||
const esp_ecdsa_volatile_key_storage_t *ptr_st =
|
||||
(const esp_ecdsa_volatile_key_storage_t *)key_buffer;
|
||||
key_recovery_info = ptr_st->opaque_key.key_recovery_info;
|
||||
} else {
|
||||
const esp_ecdsa_km_key_storage_t *km_st =
|
||||
(const esp_ecdsa_km_key_storage_t *)key_buffer;
|
||||
key_recovery_info = &km_st->key_recovery_info;
|
||||
}
|
||||
esp_err_t err = esp_key_mgr_activate_key((esp_key_mgr_key_recovery_info_t *)key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to activate key: 0x%x", err);
|
||||
return PSA_ERROR_INVALID_HANDLE;
|
||||
@@ -865,7 +1246,15 @@ psa_status_t esp_ecdsa_opaque_export_public_key(
|
||||
} else
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
{
|
||||
conf.efuse_key_blk = opaque_key->efuse_block;
|
||||
if (!is_persistent) {
|
||||
const esp_ecdsa_volatile_key_storage_t *ptr_st =
|
||||
(const esp_ecdsa_volatile_key_storage_t *)key_buffer;
|
||||
conf.efuse_key_blk = ptr_st->opaque_key.efuse_block;
|
||||
} else {
|
||||
const esp_ecdsa_efuse_key_storage_t *efuse_st =
|
||||
(const esp_ecdsa_efuse_key_storage_t *)key_buffer;
|
||||
conf.efuse_key_blk = efuse_st->efuse_block;
|
||||
}
|
||||
}
|
||||
|
||||
esp_ecdsa_acquire_hardware();
|
||||
@@ -909,13 +1298,22 @@ psa_status_t esp_ecdsa_opaque_export_public_key(
|
||||
}
|
||||
|
||||
size_t esp_ecdsa_opaque_size_function(
|
||||
const psa_key_attributes_t *attributes,
|
||||
psa_key_type_t key_type,
|
||||
size_t key_bits)
|
||||
const uint8_t *data,
|
||||
size_t data_length)
|
||||
{
|
||||
(void)key_type;
|
||||
(void)key_bits;
|
||||
bool is_persistent = esp_opaque_key_is_persistent(attributes);
|
||||
|
||||
// Opaque keys always use the same size structure
|
||||
return sizeof(esp_ecdsa_opaque_key_t);
|
||||
if (!data || data_length < sizeof(esp_ecdsa_opaque_key_t)) {
|
||||
/* Return minimum storage size so PSA core allocates a buffer.
|
||||
* The import function will validate data_length and return
|
||||
* PSA_ERROR_INVALID_ARGUMENT if the input is too short. */
|
||||
return is_persistent ? sizeof(esp_ecdsa_efuse_key_storage_t)
|
||||
: sizeof(esp_ecdsa_volatile_key_storage_t);
|
||||
}
|
||||
|
||||
return esp_ecdsa_get_storage_size((const esp_ecdsa_opaque_key_t *)data, is_persistent);
|
||||
}
|
||||
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN */
|
||||
|
||||
@@ -8,15 +8,119 @@
|
||||
#include <string.h>
|
||||
#include "psa/crypto.h"
|
||||
#include "psa_crypto_driver_esp_hmac_opaque.h"
|
||||
#include "psa_crypto_driver_esp_opaque_common.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_chip.h"
|
||||
#include "esp_assert.h"
|
||||
#include "hal/hmac_types.h"
|
||||
#include "esp_hmac.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
#include "esp_key_mgr.h"
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
|
||||
/*
|
||||
* Per-source storage structs — internal to the driver.
|
||||
* All storage structs share a common prefix: [version][key_source]
|
||||
* so that the driver can identify the key source at operation time.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HMAC_KEY_STORAGE_VERSION_INVALID = 0,
|
||||
ESP_HMAC_KEY_STORAGE_VERSION_V1 = 1,
|
||||
ESP_HMAC_KEY_STORAGE_VERSION_MAX = 2,
|
||||
} esp_hmac_key_storage_version_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_HMAC_KEY_SOURCE_EFUSE = 0,
|
||||
ESP_HMAC_KEY_SOURCE_KEY_MGR = 1,
|
||||
} esp_hmac_key_source_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t version;
|
||||
uint8_t key_source; /* esp_hmac_key_source_t */
|
||||
} esp_hmac_common_key_storage_metadata_t;
|
||||
|
||||
ESP_STATIC_ASSERT(sizeof(esp_hmac_common_key_storage_metadata_t) == 2 * sizeof(uint8_t), "esp_hmac_common_key_storage_metadata_t structure must be exactly 2 bytes");
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
esp_hmac_common_key_storage_metadata_t metadata;
|
||||
uint8_t efuse_key_id;
|
||||
} esp_hmac_efuse_key_storage_t;
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
typedef struct {
|
||||
esp_hmac_common_key_storage_metadata_t metadata;
|
||||
uint8_t reserved[2]; /* explicit padding for alignment */
|
||||
esp_key_mgr_key_recovery_info_t key_recovery_info;
|
||||
} esp_hmac_km_key_storage_t;
|
||||
|
||||
ESP_STATIC_ASSERT(offsetof(esp_hmac_km_key_storage_t, key_recovery_info) % 4 == 0,
|
||||
"key_recovery_info must be 4-byte aligned in esp_hmac_km_key_storage_t");
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
|
||||
/**
|
||||
* Pointer-based storage for volatile keys.
|
||||
* Embeds the user-facing opaque key struct (which contains pointers).
|
||||
* The caller must keep all referenced data valid until psa_destroy_key().
|
||||
*/
|
||||
typedef struct {
|
||||
esp_hmac_common_key_storage_metadata_t metadata;
|
||||
esp_hmac_opaque_key_t opaque_key;
|
||||
} esp_hmac_volatile_key_storage_t;
|
||||
|
||||
static inline esp_hmac_key_source_t hmac_storage_get_key_source(const uint8_t *key_buffer)
|
||||
{
|
||||
return (esp_hmac_key_source_t)key_buffer[1];
|
||||
}
|
||||
|
||||
static size_t esp_hmac_get_storage_size(const esp_hmac_opaque_key_t *key, bool persistent)
|
||||
{
|
||||
if (!persistent) {
|
||||
(void)key;
|
||||
return sizeof(esp_hmac_volatile_key_storage_t);
|
||||
}
|
||||
|
||||
/* Persistent: per-source dispatch */
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
if (key->key_recovery_info) {
|
||||
return sizeof(esp_hmac_km_key_storage_t);
|
||||
}
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
|
||||
return sizeof(esp_hmac_efuse_key_storage_t);
|
||||
}
|
||||
|
||||
static psa_status_t esp_hmac_get_expected_storage_size(const uint8_t *key_buffer, bool persistent, size_t *expected_storage_size)
|
||||
{
|
||||
if (key_buffer[0] <= ESP_HMAC_KEY_STORAGE_VERSION_INVALID || key_buffer[0] >= ESP_HMAC_KEY_STORAGE_VERSION_MAX) {
|
||||
return PSA_ERROR_DATA_INVALID;
|
||||
}
|
||||
|
||||
*expected_storage_size = 0;
|
||||
|
||||
if (!persistent) {
|
||||
*expected_storage_size = sizeof(esp_hmac_volatile_key_storage_t);
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
/* Persistent: per-source dispatch */
|
||||
esp_hmac_key_source_t key_source = hmac_storage_get_key_source(key_buffer);
|
||||
|
||||
switch (key_source) {
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
case ESP_HMAC_KEY_SOURCE_KEY_MGR:
|
||||
*expected_storage_size = sizeof(esp_hmac_km_key_storage_t);
|
||||
return PSA_SUCCESS;
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
case ESP_HMAC_KEY_SOURCE_EFUSE:
|
||||
*expected_storage_size = sizeof(esp_hmac_efuse_key_storage_t);
|
||||
return PSA_SUCCESS;
|
||||
default:
|
||||
return PSA_ERROR_DATA_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static bool validate_hmac_opaque_key_attributes(const esp_hmac_opaque_key_t *opaque_key)
|
||||
{
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
@@ -42,11 +146,16 @@ psa_status_t esp_hmac_import_key_opaque(
|
||||
size_t *key_buffer_length,
|
||||
size_t *bits)
|
||||
{
|
||||
if (!attributes || !data || !key_buffer || !key_buffer_length || !bits) {
|
||||
if (!attributes || !data || data_length < sizeof(esp_hmac_opaque_key_t) || !key_buffer || !key_buffer_length || !bits) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (key_buffer_size < sizeof(esp_hmac_opaque_key_t) || data_length < sizeof(esp_hmac_opaque_key_t)) {
|
||||
psa_algorithm_t hash_alg = PSA_ALG_GET_HASH(psa_get_key_algorithm(attributes));
|
||||
if (hash_alg != PSA_ALG_SHA_256) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (psa_get_key_bits(attributes) != 256) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
@@ -56,8 +165,54 @@ psa_status_t esp_hmac_import_key_opaque(
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
memcpy(key_buffer, opaque_key, sizeof(esp_hmac_opaque_key_t));
|
||||
*key_buffer_length = sizeof(esp_hmac_opaque_key_t);
|
||||
/* Convert user-facing struct to per-source storage struct */
|
||||
bool is_persistent = esp_opaque_key_is_persistent(attributes);
|
||||
|
||||
if (!is_persistent) {
|
||||
/* Volatile: store pointers — caller keeps data alive */
|
||||
if (key_buffer_size < sizeof(esp_hmac_volatile_key_storage_t)) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
esp_hmac_volatile_key_storage_t *storage = (esp_hmac_volatile_key_storage_t *)key_buffer;
|
||||
storage->metadata.version = ESP_HMAC_KEY_STORAGE_VERSION_V1;
|
||||
esp_hmac_key_source_t key_source = ESP_HMAC_KEY_SOURCE_EFUSE;
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
if (opaque_key->key_recovery_info) {
|
||||
key_source = ESP_HMAC_KEY_SOURCE_KEY_MGR;
|
||||
}
|
||||
#endif
|
||||
storage->metadata.key_source = key_source;
|
||||
memcpy(&storage->opaque_key, opaque_key, sizeof(esp_hmac_opaque_key_t));
|
||||
*key_buffer_length = sizeof(esp_hmac_volatile_key_storage_t);
|
||||
} else {
|
||||
/* Persistent: per-source inline storage */
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
if (opaque_key->key_recovery_info) {
|
||||
if (key_buffer_size < sizeof(esp_hmac_km_key_storage_t)) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
esp_hmac_km_key_storage_t *storage = (esp_hmac_km_key_storage_t *)key_buffer;
|
||||
storage->metadata.version = ESP_HMAC_KEY_STORAGE_VERSION_V1;
|
||||
storage->metadata.key_source = ESP_HMAC_KEY_SOURCE_KEY_MGR;
|
||||
memset(storage->reserved, 0, sizeof(storage->reserved));
|
||||
memcpy(&storage->key_recovery_info, opaque_key->key_recovery_info,
|
||||
sizeof(esp_key_mgr_key_recovery_info_t));
|
||||
*key_buffer_length = sizeof(esp_hmac_km_key_storage_t);
|
||||
} else
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
{
|
||||
if (key_buffer_size < sizeof(esp_hmac_efuse_key_storage_t)) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
esp_hmac_efuse_key_storage_t *storage = (esp_hmac_efuse_key_storage_t *)key_buffer;
|
||||
storage->metadata.version = ESP_HMAC_KEY_STORAGE_VERSION_V1;
|
||||
storage->metadata.key_source = ESP_HMAC_KEY_SOURCE_EFUSE;
|
||||
storage->efuse_key_id = opaque_key->efuse_key_id;
|
||||
*key_buffer_length = sizeof(esp_hmac_efuse_key_storage_t);
|
||||
}
|
||||
}
|
||||
|
||||
*bits = psa_get_key_bits(attributes);
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
@@ -81,7 +236,19 @@ psa_status_t esp_hmac_setup_opaque(
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (key_buffer_size < sizeof(esp_hmac_opaque_key_t)) {
|
||||
if (key_buffer_size < sizeof(esp_hmac_efuse_key_storage_t)) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
bool is_persistent = esp_opaque_key_is_persistent(attributes);
|
||||
|
||||
size_t expected_storage_size = 0;
|
||||
psa_status_t status = esp_hmac_get_expected_storage_size(key_buffer, is_persistent, &expected_storage_size);
|
||||
if (status != PSA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (key_buffer_size < expected_storage_size) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
@@ -97,13 +264,8 @@ psa_status_t esp_hmac_setup_opaque(
|
||||
|
||||
memset(esp_hmac_ctx, 0, sizeof(esp_hmac_opaque_operation_t));
|
||||
|
||||
const esp_hmac_opaque_key_t *opaque_key = (const esp_hmac_opaque_key_t *) key_buffer;
|
||||
|
||||
if (!validate_hmac_opaque_key_attributes(opaque_key)) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
esp_hmac_ctx->opaque_key = opaque_key;
|
||||
esp_hmac_ctx->key_buffer = key_buffer;
|
||||
esp_hmac_ctx->is_persistent = is_persistent;
|
||||
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
@@ -114,20 +276,52 @@ psa_status_t esp_hmac_update_opaque(esp_hmac_opaque_operation_t *esp_hmac_ctx, c
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
hmac_key_id_t hmac_key_id = esp_hmac_ctx->opaque_key->efuse_key_id;
|
||||
hmac_key_id_t hmac_key_id = 0;
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD
|
||||
esp_key_mgr_key_recovery_info_t *key_recovery_info = esp_hmac_ctx->opaque_key->key_recovery_info;
|
||||
if (key_recovery_info) {
|
||||
esp_err_t err = esp_key_mgr_activate_key(key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE("ESP_HMAC_OPAQUE", "Failed to activate key: 0x%x", err);
|
||||
return PSA_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
hmac_key_id = HMAC_KEY_KM;
|
||||
}
|
||||
const esp_key_mgr_key_recovery_info_t *key_recovery_info = NULL;
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD */
|
||||
|
||||
if (!esp_hmac_ctx->is_persistent) {
|
||||
const esp_hmac_volatile_key_storage_t *ptr_st =
|
||||
(const esp_hmac_volatile_key_storage_t *)esp_hmac_ctx->key_buffer;
|
||||
#if SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD
|
||||
esp_hmac_key_source_t key_source = hmac_storage_get_key_source(esp_hmac_ctx->key_buffer);
|
||||
if (key_source == ESP_HMAC_KEY_SOURCE_KEY_MGR) {
|
||||
key_recovery_info = ptr_st->opaque_key.key_recovery_info;
|
||||
esp_err_t err = esp_key_mgr_activate_key((esp_key_mgr_key_recovery_info_t *)key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE("ESP_HMAC_OPAQUE", "Failed to activate key: 0x%x", err);
|
||||
return PSA_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
hmac_key_id = HMAC_KEY_KM;
|
||||
} else
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD */
|
||||
{
|
||||
hmac_key_id = ptr_st->opaque_key.efuse_key_id;
|
||||
}
|
||||
} else {
|
||||
#if SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD
|
||||
esp_hmac_key_source_t key_source = hmac_storage_get_key_source(esp_hmac_ctx->key_buffer);
|
||||
if (key_source == ESP_HMAC_KEY_SOURCE_KEY_MGR) {
|
||||
const esp_hmac_km_key_storage_t *km_st =
|
||||
(const esp_hmac_km_key_storage_t *)esp_hmac_ctx->key_buffer;
|
||||
key_recovery_info = &km_st->key_recovery_info;
|
||||
esp_err_t err = esp_key_mgr_activate_key((esp_key_mgr_key_recovery_info_t *)key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE("ESP_HMAC_OPAQUE", "Failed to activate key: 0x%x", err);
|
||||
return PSA_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
hmac_key_id = HMAC_KEY_KM;
|
||||
} else
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD */
|
||||
{
|
||||
const esp_hmac_efuse_key_storage_t *efuse_st =
|
||||
(const esp_hmac_efuse_key_storage_t *)esp_hmac_ctx->key_buffer;
|
||||
hmac_key_id = efuse_st->efuse_key_id;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t hmac_ret = esp_hmac_calculate(hmac_key_id, data, data_length, esp_hmac_ctx->hmac);
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD
|
||||
@@ -221,20 +415,19 @@ psa_status_t esp_hmac_verify_finish_opaque(
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the size of the ESP HMAC opaque key
|
||||
*
|
||||
* @param key_type Key type
|
||||
* @param key_bits Key bits
|
||||
* @return size_t Size of the ESP HMAC opaque key
|
||||
*/
|
||||
size_t esp_hmac_opaque_size_function(
|
||||
const psa_key_attributes_t *attributes,
|
||||
psa_key_type_t key_type,
|
||||
size_t key_bits)
|
||||
const uint8_t *data,
|
||||
size_t data_length)
|
||||
{
|
||||
(void)key_type;
|
||||
(void)key_bits;
|
||||
bool is_persistent = esp_opaque_key_is_persistent(attributes);
|
||||
|
||||
// Opaque keys always use the same size structure
|
||||
return sizeof(esp_hmac_opaque_key_t);
|
||||
if (!data || data_length < sizeof(esp_hmac_opaque_key_t)) {
|
||||
return is_persistent ? sizeof(esp_hmac_efuse_key_storage_t)
|
||||
: sizeof(esp_hmac_volatile_key_storage_t);
|
||||
}
|
||||
|
||||
return esp_hmac_get_storage_size((const esp_hmac_opaque_key_t *)data, is_persistent);
|
||||
}
|
||||
|
||||
@@ -116,13 +116,21 @@ psa_status_t esp_ecdsa_opaque_export_public_key(
|
||||
/**
|
||||
* @brief Get the key buffer size for an ESP ECDSA opaque key
|
||||
*
|
||||
* Inspects the user-provided import data to determine the key source
|
||||
* (eFuse or TEE) and returns the size of the corresponding internal
|
||||
* storage struct.
|
||||
*
|
||||
* @param attributes Key attributes (used to determine persistence)
|
||||
* @param key_type Key type
|
||||
* @param key_bits Key size in bits
|
||||
* @param data Import data (esp_ecdsa_opaque_key_t)
|
||||
* @param data_length Length of import data
|
||||
* @return size_t Required buffer size
|
||||
*/
|
||||
size_t esp_ecdsa_opaque_size_function(
|
||||
const psa_key_attributes_t *attributes,
|
||||
psa_key_type_t key_type,
|
||||
size_t key_bits);
|
||||
const uint8_t *data,
|
||||
size_t data_length);
|
||||
|
||||
/**
|
||||
* @brief Verify a hash using ESP ECDSA transparent driver
|
||||
|
||||
@@ -72,12 +72,13 @@ typedef struct {
|
||||
/* The buffers are stored in the little-endian format */
|
||||
typedef struct {
|
||||
psa_algorithm_t alg;
|
||||
const esp_ecdsa_opaque_key_t *opaque_key;
|
||||
uint8_t r[MAX_ECDSA_COMPONENT_LEN];
|
||||
const uint8_t *key_buffer; /**< Pointer to the per-source storage struct in key slot */
|
||||
uint8_t r[MAX_ECDSA_COMPONENT_LEN]; /**< Must be 4-byte aligned for ECDSA HAL MMIO reads */
|
||||
uint8_t s[MAX_ECDSA_COMPONENT_LEN];
|
||||
uint8_t sha[MAX_ECDSA_SHA_LEN];
|
||||
size_t sha_len;
|
||||
size_t key_len;
|
||||
bool is_persistent; /**< Cached persistence flag for use in complete */
|
||||
} esp_ecdsa_opaque_sign_hash_operation_t;
|
||||
#endif /* !(__DOXYGEN__) */
|
||||
#endif /* ESP_ECDSA_DRIVER_ENABLED */
|
||||
|
||||
@@ -64,7 +64,9 @@ psa_status_t esp_hmac_import_key_opaque(const psa_key_attributes_t *attributes,
|
||||
size_t *key_buffer_length,
|
||||
size_t *bits);
|
||||
|
||||
size_t esp_hmac_opaque_size_function(psa_key_type_t key_type, size_t key_bits);
|
||||
size_t esp_hmac_opaque_size_function(const psa_key_attributes_t *attributes,
|
||||
psa_key_type_t key_type,
|
||||
const uint8_t *data, size_t data_length);
|
||||
|
||||
psa_status_t esp_hmac_compute_opaque(const psa_key_attributes_t *attributes,
|
||||
const uint8_t *key_buffer,
|
||||
|
||||
+2
-1
@@ -38,8 +38,9 @@ typedef struct {
|
||||
* @brief Structure to store opaque HMAC operation context.
|
||||
*/
|
||||
typedef struct {
|
||||
const esp_hmac_opaque_key_t *opaque_key; /**< Pointer to the opaque key structure */
|
||||
const uint8_t *key_buffer; /**< Pointer to the per-source storage struct in key slot */
|
||||
uint8_t hmac[ESP_HMAC_RESULT_SIZE]; /**< Buffer to store the HMAC result */
|
||||
bool is_persistent; /**< Cached persistence flag for use in update */
|
||||
} esp_hmac_opaque_operation_t;
|
||||
|
||||
#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "psa/crypto.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Check whether a PSA key is persistent based on its attributes.
|
||||
*
|
||||
* Used by ESP opaque drivers to decide between inline (persistent) and
|
||||
* pointer-based (volatile) storage formats.
|
||||
*/
|
||||
static inline bool esp_opaque_key_is_persistent(const psa_key_attributes_t *attributes)
|
||||
{
|
||||
return PSA_KEY_LIFETIME_GET_PERSISTENCE(psa_get_key_lifetime(attributes))
|
||||
!= PSA_KEY_PERSISTENCE_VOLATILE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -761,7 +761,7 @@ void test_ecdsa_sign_verify_import_export_error_codes(esp_ecdsa_curve_t curve, c
|
||||
|
||||
// incorrect opaque key buffer length
|
||||
status = psa_import_key(&priv_attr, (uint8_t*) &opaque_key, sizeof(opaque_key) - 1, &priv_key_id);
|
||||
TEST_ASSERT_EQUAL_HEX32(PSA_ERROR_BUFFER_TOO_SMALL, status);
|
||||
TEST_ASSERT_EQUAL_HEX32(PSA_ERROR_INVALID_ARGUMENT, status);
|
||||
|
||||
// incorrect curve
|
||||
opaque_key.curve = curve + 1;
|
||||
|
||||
Reference in New Issue
Block a user