feat(ecdsa): support software key as a key source for esp32s31

Starting from the ESP32-S31, the ECDSA peripheral can use a private key
written into its key registers by software, in addition to the eFuse
and Key Manager key sources.
This commit is contained in:
nilesh.kale
2026-10-01 10:39:09 +08:00
committed by Ashish Sharma
parent 421cdd4d15
commit 363426cbc9
23 changed files with 865 additions and 91 deletions
+9
View File
@@ -856,6 +856,15 @@ bool esp_efuse_is_ecdsa_p192_curve_supported(void);
* This function checks if the current eFuse configuration supports 256-bit ECDSA curve operations.
*/
bool esp_efuse_is_ecdsa_p256_curve_supported(void);
/**
* @brief Checks if a software-supplied ECDSA private key is allowed as a key source.
*
* This function checks if the eFuse configuration allows the ECDSA peripheral to use
* a private key written into its key registers by software. Returns false if the chip
* does not support a software key source or if it has been permanently disabled by eFuse.
*/
bool esp_efuse_is_ecdsa_software_key_allowed(void);
#endif /* SOC_ECDSA_SUPPORTED*/
#if SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED
+9
View File
@@ -122,6 +122,15 @@ bool esp_efuse_is_ecdsa_p256_curve_supported(void)
return true;
#endif /* SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED */
}
bool esp_efuse_is_ecdsa_software_key_allowed(void)
{
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
return !esp_efuse_read_field_bit(ESP_EFUSE_ECDSA_DISABLE_SOFT_K);
#else
return false;
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
}
#endif /* SOC_ECDSA_SUPPORTED */
#if SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED
+41 -12
View File
@@ -39,8 +39,25 @@ void ecdsa_hal_set_efuse_key(ecdsa_curve_t curve, int efuse_blk)
static void configure_ecdsa_periph(ecdsa_hal_config_t *conf)
{
bool use_hw_key = true;
if (conf->use_km_key == 0) {
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
if (conf->use_sw_key) {
HAL_ASSERT(conf->sw_key != NULL && "Software key not provided");
HAL_ASSERT(!conf->use_km_key && "Software key and Key Manager key are mutually exclusive");
/* The key itself can only be written during the LOAD state of the operation,
* so it is written by the operation functions, not here */
ecdsa_ll_set_key_source(ECDSA_KEY_SOURCE_SOFTWARE);
use_hw_key = false;
} else {
/* The hardware defaults to the software key source, so the hardware
* key source must be selected explicitly */
ecdsa_ll_set_key_source(ECDSA_KEY_SOURCE_HARDWARE);
}
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
if (use_hw_key && conf->use_km_key == 0) {
ecdsa_hal_set_efuse_key(conf->curve, conf->efuse_key_blk);
@@ -49,8 +66,7 @@ static void configure_ecdsa_periph(ecdsa_hal_config_t *conf)
key_mgr_hal_set_key_usage(ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_USE_EFUSE_KEY);
#endif
}
#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY
else {
else if (use_hw_key) {
if (!key_mgr_ll_is_supported()) {
HAL_ASSERT(false && "Key manager is not supported");
}
@@ -83,7 +99,7 @@ bool ecdsa_hal_get_operation_result(void)
return ecdsa_ll_get_operation_result();
}
static void ecdsa_hal_gen_signature_inner(const uint8_t *hash, uint8_t *r_out,
static void ecdsa_hal_gen_signature_inner(ecdsa_hal_config_t *conf, const uint8_t *hash, uint8_t *r_out,
uint8_t *s_out, uint16_t len)
{
ecdsa_ll_set_stage(ECDSA_STAGE_START_CALC);
@@ -92,6 +108,13 @@ static void ecdsa_hal_gen_signature_inner(const uint8_t *hash, uint8_t *r_out,
;
}
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
/* The key registers only accept writes while the peripheral is in the LOAD state */
if (conf->use_sw_key) {
ecdsa_ll_write_key(conf->sw_key, len);
}
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
ecdsa_ll_write_param(ECDSA_PARAM_Z, hash, len);
ecdsa_ll_set_stage(ECDSA_STAGE_LOAD_DONE);
@@ -111,7 +134,7 @@ static void ecdsa_hal_gen_signature_inner(const uint8_t *hash, uint8_t *r_out,
}
#if HAL_CONFIG(ECDSA_GEN_SIG_CM)
__attribute__((optimize("O0"))) static void ecdsa_hal_gen_signature_with_countermeasure(const uint8_t *hash, uint8_t *r_out,
__attribute__((optimize("O0"))) static void ecdsa_hal_gen_signature_with_countermeasure(ecdsa_hal_config_t *conf, const uint8_t *hash, uint8_t *r_out,
uint8_t *s_out, uint16_t len)
{
uint8_t tmp_r_out[32] = {};
@@ -126,15 +149,15 @@ __attribute__((optimize("O0"))) static void ecdsa_hal_gen_signature_with_counter
esp_fill_random(tmp_hash, 64);
/* Dummy ecdsa signature operations prior to the actual one */
for (int i = 0; i < dummy_op_count_prior; i++) {
ecdsa_hal_gen_signature_inner(tmp_hash + ((6 * i) % 32), (uint8_t *) tmp_r_out, (uint8_t *) tmp_s_out, len);
ecdsa_hal_gen_signature_inner(conf, tmp_hash + ((6 * i) % 32), (uint8_t *) tmp_r_out, (uint8_t *) tmp_s_out, len);
}
/* Actual ecdsa signature operation */
ecdsa_hal_gen_signature_inner(hash, r_out, s_out, len);
ecdsa_hal_gen_signature_inner(conf, hash, r_out, s_out, len);
/* Dummy ecdsa signature operations after the actual one */
for (int i = 0; i < dummy_op_count_later; i++) {
ecdsa_hal_gen_signature_inner(tmp_hash + ((6 * i) % 32), (uint8_t *)tmp_r_out, (uint8_t *)tmp_s_out, len);
ecdsa_hal_gen_signature_inner(conf, tmp_hash + ((6 * i) % 32), (uint8_t *)tmp_r_out, (uint8_t *)tmp_s_out, len);
}
}
@@ -164,15 +187,14 @@ void ecdsa_hal_gen_signature(ecdsa_hal_config_t *conf, const uint8_t *hash,
#if HAL_CONFIG(ECDSA_GEN_SIG_CM)
#if SOC_IS(ESP32H2)
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 102)) {
ecdsa_hal_gen_signature_with_countermeasure(hash, r_out, s_out, len);
ecdsa_hal_gen_signature_with_countermeasure(conf, hash, r_out, s_out, len);
return;
}
#endif
ecdsa_hal_gen_signature_with_countermeasure(hash, r_out, s_out, len);
ecdsa_hal_gen_signature_with_countermeasure(conf, hash, r_out, s_out, len);
#else /* HAL_CONFIG_ECDSA_GEN_SIG_CM */
ecdsa_hal_gen_signature_inner(hash, r_out, s_out, len);
ecdsa_hal_gen_signature_inner(conf, hash, r_out, s_out, len);
#endif /* !HAL_CONFIG_ECDSA_GEN_SIG_CM */
}
int ecdsa_hal_verify_signature(ecdsa_hal_config_t *conf, const uint8_t *hash, const uint8_t *r, const uint8_t *s,
@@ -238,6 +260,13 @@ void ecdsa_hal_export_pubkey(ecdsa_hal_config_t *conf, uint8_t *pub_x, uint8_t *
;
}
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
/* The key registers only accept writes while the peripheral is in the LOAD state */
if (conf->use_sw_key) {
ecdsa_ll_write_key(conf->sw_key, len);
}
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
ecdsa_ll_set_stage(ECDSA_STAGE_LOAD_DONE);
while (ecdsa_ll_get_state() != ECDSA_STATE_GET) {
@@ -64,6 +64,17 @@ typedef enum {
ECDSA_SHA_256
} ecdsa_ll_sha_type_t;
/**
* @brief Source of the ECDSA private key
*/
typedef enum {
ECDSA_KEY_SOURCE_HARDWARE, /* Key supplied by eFuse or the Key Manager peripheral */
ECDSA_KEY_SOURCE_SOFTWARE, /* Key written into the ECDSA key registers by software */
} ecdsa_ll_key_source_t;
/* Total size of the ECDSA_KEY_0..ECDSA_KEY_11 register bank */
#define ECDSA_LL_KEY_REG_BYTES 48
/**
* @brief Operation modes of SHA
*/
@@ -188,13 +199,9 @@ static inline void ecdsa_ll_set_mode(ecdsa_mode_t mode)
break;
case ECDSA_MODE_SIGN_GEN:
REG_SET_FIELD(ECDSA_CONF_REG, ECDSA_WORK_MODE, 1);
// TODO: IDF-15656 support software key as key source
REG_SET_BIT(ECDSA_CONF_REG, ECDSA_USE_HARDWARE_KEY);
break;
case ECDSA_MODE_EXPORT_PUBKEY:
REG_SET_FIELD(ECDSA_CONF_REG, ECDSA_WORK_MODE, 2);
// TODO: IDF-15656 support software key as key source
REG_SET_BIT(ECDSA_CONF_REG, ECDSA_USE_HARDWARE_KEY);
break;
default:
HAL_ASSERT(false && "Unsupported mode");
@@ -202,6 +209,51 @@ static inline void ecdsa_ll_set_mode(ecdsa_mode_t mode)
}
}
/**
* @brief Set the source of the ECDSA private key
*
* @note The hardware default is the software key source, thus the key source
* must be configured explicitly for every operation.
*
* @param source Source of the private key
*/
static inline void ecdsa_ll_set_key_source(ecdsa_ll_key_source_t source)
{
if (source == ECDSA_KEY_SOURCE_SOFTWARE) {
REG_CLR_BIT(ECDSA_CONF_REG, ECDSA_USE_HARDWARE_KEY);
} else {
REG_SET_BIT(ECDSA_CONF_REG, ECDSA_USE_HARDWARE_KEY);
}
}
/**
* @brief Write the software private key into the ECDSA key registers
*
* @note The key registers only accept writes while the peripheral is in the
* LOAD state (writes are silently ignored otherwise), so this must be
* called between the START_CALC and LOAD_DONE stages of an operation.
* The registers retain the key after the operation and only a module
* reset clears them, so the peripheral must be reset after a
* software-key operation to avoid leaking the key.
*
* @param key Private key in little-endian format
* @param len Length of the key in bytes (24, 32 or 48 depending on the curve)
*/
static inline void ecdsa_ll_write_key(const uint8_t *key, uint16_t len)
{
HAL_ASSERT(((len % 4) == 0) && (len <= ECDSA_LL_KEY_REG_BYTES));
uint32_t word;
uint16_t i = 0;
for (; i < len; i += 4) {
memcpy(&word, key + i, 4);
REG_WRITE(ECDSA_KEY_0_REG + i, word);
}
/* Zero out the remaining key registers for keys shorter than P-384 */
for (; i < ECDSA_LL_KEY_REG_BYTES; i += 4) {
REG_WRITE(ECDSA_KEY_0_REG + i, 0);
}
}
/**
* @brief Set curve for ECDSA operation
*
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -42,6 +42,13 @@ typedef struct {
ecdsa_sha_mode_t sha_mode; /* Source of SHA that needs to be signed */
int efuse_key_blk; /*!< The efuse block where ECDSA key is stored. If two blocks are used to store the key, then the macro HAL_ECDSA_COMBINE_KEY_BLOCKS() can be used to combine them. The macro is defined in hal/ecdsa_types.h */
bool use_km_key; /* Use an ECDSA key from the Key Manager peripheral */
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
bool use_sw_key; /* Use a software-supplied private key written into the ECDSA key registers.
* The key registers retain the key after the operation, so the caller must
* reset the ECDSA peripheral once done to scrub the key material (releasing
* the peripheral with esp_crypto_ecdsa_enable_periph_clk() takes care of it). */
const uint8_t *sw_key; /* Private key in little-endian format, length equal to the curve component length (24/32/48 bytes). Only used when use_sw_key is set */
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
ecdsa_sign_type_t sign_type; /* Type of signature generation */
uint16_t loop_number; /* Determines the loop number value in deterministic derivation algorithm to derive K.
* When using mbedtls APIs, this member of the config does not need any explicit
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -36,6 +36,13 @@ static void run_all_tests(void)
RUN_TEST_GROUP(key_manager);
#endif
#if (CONFIG_SOC_ECDSA_SUPPORTED && CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS && CONFIG_CRYPTO_TEST_APP_ENABLE_ECDSA_TESTS) \
|| CONFIG_SOC_ECDSA_SUPPORT_SOFTWARE_KEY
/* The eFuse-key test cases additionally need CONFIG_CRYPTO_TEST_APP_ENABLE_ECDSA_TESTS,
* see the gating inside the group runner; the software-key test cases need no eFuse */
RUN_TEST_GROUP(ecdsa)
#endif
#if CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS
#if CONFIG_SOC_HMAC_SUPPORTED && CONFIG_CRYPTO_TEST_APP_ENABLE_HMAC_TESTS
@@ -46,10 +53,6 @@ static void run_all_tests(void)
RUN_TEST_GROUP(ds);
#endif
#if CONFIG_SOC_ECDSA_SUPPORTED && CONFIG_CRYPTO_TEST_APP_ENABLE_ECDSA_TESTS
RUN_TEST_GROUP(ecdsa)
#endif
#if CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES && CONFIG_CRYPTO_TEST_APP_ENABLE_XTS_AES_TESTS
RUN_TEST_GROUP(xts_aes)
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -116,3 +116,31 @@ uint8_t ecdsa384_pub_y[] = {
0xd1, 0xf1, 0x81, 0x70, 0x7c, 0xce, 0x42, 0xf3,
0x3d, 0xa1, 0x64, 0x84, 0x91, 0xac, 0xee, 0xf7,
};
/* Private keys from the ecdsa*_priv_key.pem files in this directory,
* for targets that support a software-supplied ECDSA key */
/* Little endian */
uint8_t ecdsa192_priv[] = {
0x92, 0x65, 0x26, 0x4f, 0x58, 0x5e, 0x97, 0xbb,
0x67, 0x27, 0x51, 0x3c, 0xd3, 0xb7, 0xe6, 0x47,
0x78, 0x7c, 0xfe, 0x1c, 0x9e, 0xfc, 0xaf, 0xd6,
};
/* Little endian */
uint8_t ecdsa256_priv[] = {
0xf3, 0x47, 0x2b, 0x4c, 0xcf, 0xc7, 0xcb, 0x20,
0x30, 0x73, 0x10, 0xa3, 0x7f, 0x6d, 0x7e, 0x24,
0x3d, 0x36, 0x00, 0x3a, 0x48, 0x4b, 0xac, 0xd1,
0x2e, 0x36, 0x15, 0x3e, 0x32, 0x63, 0x25, 0x11,
};
/* Little endian */
uint8_t ecdsa384_priv[] = {
0x1f, 0x0f, 0x67, 0x51, 0xfe, 0xa6, 0x0d, 0xab,
0x02, 0xf3, 0x43, 0x01, 0x47, 0xfd, 0xc5, 0x6b,
0x65, 0x01, 0x7f, 0x19, 0xb6, 0xb7, 0x1c, 0xa0,
0x41, 0x12, 0x2f, 0xe6, 0x04, 0xc2, 0xc6, 0x6e,
0x74, 0xe1, 0x03, 0xb4, 0x2f, 0xd5, 0xec, 0xb8,
0xe4, 0xe4, 0x87, 0xb1, 0x71, 0xd3, 0x24, 0x25,
};
@@ -11,6 +11,7 @@
#include "esp_crypto_lock.h"
#include "esp_efuse_chip.h"
#include "esp_crypto_periph_clk.h"
#include "esp_private/esp_crypto_lock_internal.h"
#include "esp_random.h"
#include "esp_err.h"
#include "esp_efuse.h"
@@ -143,7 +144,7 @@ static void test_ecdsa_corrupt_data(ecdsa_curve_t curve, uint8_t* sha, uint8_t*
pub_y[r_bit / 8] ^= 1 << (r_bit % 8);
}
void test_ecdsa_sign(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type)
void test_ecdsa_sign(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type, const uint8_t *sw_key)
{
uint8_t sha_le[48] = {0};
uint8_t zeroes[48] = {0};
@@ -159,6 +160,14 @@ void test_ecdsa_sign(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t*
.use_km_key = use_km_key,
.sign_type = k_type,
};
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
if (sw_key) {
conf.use_sw_key = true;
conf.sw_key = sw_key;
}
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
switch (curve) {
case ECDSA_CURVE_SECP192R1:
conf.curve = ECDSA_CURVE_SECP192R1;
@@ -219,16 +228,16 @@ void test_ecdsa_sign(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t*
ecdsa_disable();
}
void test_ecdsa_sign_and_verify(ecdsa_curve_t curve, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type)
void test_ecdsa_sign_and_verify(ecdsa_curve_t curve, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type, const uint8_t *sw_key)
{
uint8_t r_le[48] = {0};
uint8_t s_le[48] = {0};
test_ecdsa_sign(curve, sha, r_le, s_le, use_km_key, k_type);
test_ecdsa_sign(curve, sha, r_le, s_le, use_km_key, k_type, sw_key);
TEST_ASSERT_EQUAL(0, test_ecdsa_verify(curve, sha, r_le, s_le, pub_x, pub_y));
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
void test_ecdsa_export_pubkey_inner(ecdsa_curve_t curve, uint8_t *exported_pub_x, uint8_t *exported_pub_y, bool use_km_key, uint16_t *len)
void test_ecdsa_export_pubkey_inner(ecdsa_curve_t curve, uint8_t *exported_pub_x, uint8_t *exported_pub_y, bool use_km_key, const uint8_t *sw_key, uint16_t *len)
{
uint8_t zeroes[48] = {0};
ecdsa_hal_config_t conf = {
@@ -236,6 +245,13 @@ void test_ecdsa_export_pubkey_inner(ecdsa_curve_t curve, uint8_t *exported_pub_x
.use_km_key = use_km_key,
};
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
if (sw_key) {
conf.use_sw_key = true;
conf.sw_key = sw_key;
}
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
switch (curve) {
case ECDSA_CURVE_SECP192R1:
conf.curve = ECDSA_CURVE_SECP192R1;
@@ -279,12 +295,12 @@ void test_ecdsa_export_pubkey_inner(ecdsa_curve_t curve, uint8_t *exported_pub_x
ecdsa_disable();
}
void test_ecdsa_export_pubkey(ecdsa_curve_t curve, uint8_t *ecdsa_pub_x, uint8_t *ecdsa_pub_y, bool use_km_key)
void test_ecdsa_export_pubkey(ecdsa_curve_t curve, uint8_t *ecdsa_pub_x, uint8_t *ecdsa_pub_y, bool use_km_key, const uint8_t *sw_key)
{
uint8_t pub_x[48] = {0};
uint8_t pub_y[48] = {0};
uint16_t len;
test_ecdsa_export_pubkey_inner(curve, pub_x, pub_y, use_km_key, &len);
test_ecdsa_export_pubkey_inner(curve, pub_x, pub_y, use_km_key, sw_key, &len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa_pub_x, pub_x, len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa_pub_y, pub_y, len);
@@ -321,7 +337,7 @@ TEST(ecdsa, ecdsa_SECP192R1_sign_and_verify)
} else if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP192R1, sha, ecdsa192_pub_x, ecdsa192_pub_y, false, ECDSA_K_TYPE_TRNG);
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP192R1, sha, ecdsa192_pub_x, ecdsa192_pub_y, false, ECDSA_K_TYPE_TRNG, NULL);
}
}
@@ -346,7 +362,7 @@ TEST(ecdsa, ecdsa_SECP256R1_sign_and_verify)
if (!ecdsa_ll_is_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA is not supported.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, ECDSA_K_TYPE_TRNG);
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, ECDSA_K_TYPE_TRNG, NULL);
}
}
@@ -369,7 +385,7 @@ TEST(ecdsa, ecdsa_SECP192R1_det_sign_and_verify)
} else if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP192R1, sha, ecdsa192_pub_x, ecdsa192_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC);
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP192R1, sha, ecdsa192_pub_x, ecdsa192_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC, NULL);
}
}
@@ -380,7 +396,7 @@ TEST(ecdsa, ecdsa_SECP256R1_det_sign_and_verify)
} else if (!ecdsa_ll_is_deterministic_mode_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA deterministic mode is not supported.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC);
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC, NULL);
}
}
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
@@ -393,7 +409,7 @@ TEST(ecdsa, ecdsa_SECP192R1_export_pubkey)
} else if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP192R1, ecdsa192_pub_x, ecdsa192_pub_y, 0);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP192R1, ecdsa192_pub_x, ecdsa192_pub_y, 0, NULL);
}
}
@@ -402,7 +418,7 @@ TEST(ecdsa, ecdsa_SECP256R1_export_pubkey)
if (!ecdsa_ll_is_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA is not supported.");
} else {
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, 0);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, 0, NULL);
}
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
@@ -422,7 +438,7 @@ TEST(ecdsa, ecdsa_SECP384R1_sign_and_verify)
if (!ecdsa_ll_is_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA is not supported.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, ECDSA_K_TYPE_TRNG);
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, ECDSA_K_TYPE_TRNG, NULL);
}
}
@@ -443,7 +459,7 @@ TEST(ecdsa, ecdsa_SECP384R1_det_sign_and_verify)
} else if (!ecdsa_ll_is_deterministic_mode_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA deterministic mode is not supported.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC);
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC, NULL);
}
}
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
@@ -454,14 +470,89 @@ TEST(ecdsa, ecdsa_SECP384R1_export_pubkey)
if (!ecdsa_ll_is_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA is not supported.");
} else {
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP384R1, ecdsa384_pub_x, ecdsa384_pub_y, 0);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP384R1, ecdsa384_pub_x, ecdsa384_pub_y, 0, NULL);
}
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
/* Software-key test cases do not need any key burnt in eFuse, so they are kept
* in a separate test group that runs without CONFIG_CRYPTO_TEST_APP_ENABLE_ECDSA_TESTS */
static void test_ecdsa_sw_key_on_curve(ecdsa_curve_t curve, uint8_t *pub_x, uint8_t *pub_y, const uint8_t *priv)
{
test_ecdsa_sign_and_verify(curve, sha, pub_x, pub_y, false, ECDSA_K_TYPE_TRNG, priv);
#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
test_ecdsa_sign_and_verify(curve, sha, pub_x, pub_y, false, ECDSA_K_TYPE_DETERMINISITIC, priv);
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
test_ecdsa_export_pubkey(curve, pub_x, pub_y, 0, priv);
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
}
TEST(ecdsa, sw_key_SECP192R1_operations)
{
if (!esp_efuse_is_ecdsa_software_key_allowed()) {
ESP_LOGI(TAG, "Skipping test because ECDSA software key is disabled by eFuse.");
} else if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_sw_key_on_curve(ECDSA_CURVE_SECP192R1, ecdsa192_pub_x, ecdsa192_pub_y, ecdsa192_priv);
}
}
TEST(ecdsa, sw_key_SECP256R1_operations)
{
if (!esp_efuse_is_ecdsa_software_key_allowed()) {
ESP_LOGI(TAG, "Skipping test because ECDSA software key is disabled by eFuse.");
} else {
test_ecdsa_sw_key_on_curve(ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, ecdsa256_priv);
}
}
#ifdef SOC_ECDSA_SUPPORT_CURVE_P384
TEST(ecdsa, sw_key_SECP384R1_operations)
{
if (!esp_efuse_is_ecdsa_software_key_allowed()) {
ESP_LOGI(TAG, "Skipping test because ECDSA software key is disabled by eFuse.");
} else {
test_ecdsa_sw_key_on_curve(ECDSA_CURVE_SECP384R1, ecdsa384_pub_x, ecdsa384_pub_y, ecdsa384_priv);
}
}
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
TEST(ecdsa, sw_key_registers_cleared_after_use)
{
if (!esp_efuse_is_ecdsa_software_key_allowed()) {
ESP_LOGI(TAG, "Skipping test because ECDSA software key is disabled by eFuse.");
return;
}
uint8_t r_le[48] = {0};
uint8_t s_le[48] = {0};
test_ecdsa_sign(ECDSA_CURVE_SECP256R1, sha, r_le, s_le, false, ECDSA_K_TYPE_DETERMINISITIC, ecdsa256_priv);
/* Releasing the peripheral must have scrubbed the key registers.
* Re-enable only the bus clock (without the reset that a regular acquire
* performs) so that any leftover key material would still be visible. */
ECDSA_RCC_ATOMIC() {
ecdsa_ll_enable_bus_clock(true);
}
for (uint16_t i = 0; i < ECDSA_LL_KEY_REG_BYTES; i += 4) {
TEST_ASSERT_EQUAL_HEX32(0, REG_READ(ECDSA_KEY_0_REG + i));
}
ECDSA_RCC_ATOMIC() {
ecdsa_ll_enable_bus_clock(false);
}
}
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
TEST_GROUP_RUNNER(ecdsa)
{
/* The following test cases need keys provisioned in eFuse,
* see CONFIG_CRYPTO_TEST_APP_ENABLE_ECDSA_TESTS */
#if CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS && CONFIG_CRYPTO_TEST_APP_ENABLE_ECDSA_TESTS
/* SECP192R1 test cases */
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_signature_verification)
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_sign_and_verify)
@@ -496,4 +587,15 @@ TEST_GROUP_RUNNER(ecdsa)
RUN_TEST_CASE(ecdsa, ecdsa_SECP384R1_export_pubkey)
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
#endif /* CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS && CONFIG_CRYPTO_TEST_APP_ENABLE_ECDSA_TESTS */
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
/* Software-key test cases need no key provisioned in eFuse */
RUN_TEST_CASE(ecdsa, sw_key_SECP192R1_operations)
RUN_TEST_CASE(ecdsa, sw_key_SECP256R1_operations)
#ifdef SOC_ECDSA_SUPPORT_CURVE_P384
RUN_TEST_CASE(ecdsa, sw_key_SECP384R1_operations)
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
RUN_TEST_CASE(ecdsa, sw_key_registers_cleared_after_use)
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
}
@@ -254,13 +254,13 @@ static void key_mgr_test_xts_aes_256_random_mode(void)
#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY
#if SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
extern void test_ecdsa_export_pubkey(ecdsa_curve_t curve, uint8_t *ecdsa_pub_x, uint8_t *ecdsa_pub_y, bool use_km_key);
extern void test_ecdsa_export_pubkey_inner(ecdsa_curve_t curve, uint8_t *exported_pub_x, uint8_t *exported_pub_y, bool use_km_key, uint16_t *len);
extern void test_ecdsa_export_pubkey(ecdsa_curve_t curve, uint8_t *ecdsa_pub_x, uint8_t *ecdsa_pub_y, bool use_km_key, const uint8_t *sw_key);
extern void test_ecdsa_export_pubkey_inner(ecdsa_curve_t curve, uint8_t *exported_pub_x, uint8_t *exported_pub_y, bool use_km_key, const uint8_t *sw_key, uint16_t *len);
#endif
extern void test_ecdsa_sign(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type);
extern void test_ecdsa_sign(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type, const uint8_t *sw_key);
extern int test_ecdsa_verify(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y);
extern void test_ecdsa_sign_and_verify(ecdsa_curve_t curve, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type);
extern void test_ecdsa_sign_and_verify(ecdsa_curve_t curve, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type, const uint8_t *sw_key);
/*
const uint8_t message[32] = { 0xDF, 0xDE, 0xD7, 0x4A, 0x47, 0xB1, 0x4F, 0x73, 0x00, 0x21, 0x62, 0xC7, 0x66, 0x6D, 0xA3, 0x95, 0x66, 0x19, 0x62, 0x7F, 0x71, 0x7B, 0x3C, 0x66, 0x82, 0xD3, 0x9F, 0x71, 0xAC, 0x9C, 0xC3, 0x39 };
@@ -270,9 +270,9 @@ uint8_t sha_digest[48] = { 0xF0, 0x94, 0xC4, 0x4A, 0xF0, 0xEE, 0x68, 0xDB, 0x5B,
void test_ecdsa_key_aes_mode(ecdsa_curve_t curve, uint8_t *sha_digest, uint8_t *pub_x, uint8_t *pub_y, ecdsa_sign_type_t k_type)
{
test_ecdsa_sign_and_verify(curve, sha_digest, pub_x, pub_y, 1, k_type);
test_ecdsa_sign_and_verify(curve, sha_digest, pub_x, pub_y, 1, k_type, NULL);
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
test_ecdsa_export_pubkey(curve, pub_x, pub_y, 1);
test_ecdsa_export_pubkey(curve, pub_x, pub_y, 1, NULL);
#endif
}
@@ -307,7 +307,7 @@ void key_mgr_test_ecdsa_key(esp_key_mgr_key_len_t key_len, ecdsa_sign_type_t k_t
return;
}
test_ecdsa_sign(curve, sha_digest, r_le, s_le, 1, k_type);
test_ecdsa_sign(curve, sha_digest, r_le, s_le, 1, k_type, NULL);
ESP_LOG_BUFFER_HEXDUMP("ECDSA message digest", sha_digest, sha_digest_len, ESP_LOG_DEBUG);
ESP_LOG_BUFFER_HEXDUMP("ECDSA signature r_le", r_le, sizeof(r_le), ESP_LOG_DEBUG);
@@ -315,7 +315,7 @@ void key_mgr_test_ecdsa_key(esp_key_mgr_key_len_t key_len, ecdsa_sign_type_t k_t
// Export the pubkey from ECDSA peripheral
uint16_t pubkey_len = 0;
test_ecdsa_export_pubkey_inner(curve, pub_x, pub_y, 1, &pubkey_len);
test_ecdsa_export_pubkey_inner(curve, pub_x, pub_y, 1, NULL, &pubkey_len);
ESP_LOG_BUFFER_HEXDUMP("ECDSA key pubx", pub_x, pubkey_len, ESP_LOG_DEBUG);
ESP_LOG_BUFFER_HEXDUMP("ECDSA key puby", pub_y, pubkey_len, ESP_LOG_DEBUG);
@@ -407,11 +407,11 @@ static void key_mgr_test_ecdsa_key_ecdh0_mode(esp_key_mgr_key_len_t key_len)
if (key_len == ESP_KEY_MGR_ECDSA_LEN_256) {
uint8_t pub_x_le[32], pub_y_le[32];
km_verify_ecdsa_pubkey_from_scalar(P256_LEN, x_be_stage0, 32, pub_x_le, pub_y_le);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP256R1, pub_x_le, pub_y_le, 1);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP256R1, pub_x_le, pub_y_le, 1, NULL);
} else if (key_len == ESP_KEY_MGR_ECDSA_LEN_192) {
uint8_t pub_x_le[24], pub_y_le[24];
km_verify_ecdsa_pubkey_from_scalar(P192_LEN, x_be_stage0 + 8, 24, pub_x_le, pub_y_le);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP192R1, pub_x_le, pub_y_le, 1);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP192R1, pub_x_le, pub_y_le, 1, NULL);
}
#if SOC_ECDSA_SUPPORT_CURVE_P384
else if (key_len == ESP_KEY_MGR_ECDSA_LEN_384) {
@@ -423,7 +423,7 @@ static void key_mgr_test_ecdsa_key_ecdh0_mode(esp_key_mgr_key_len_t key_len)
memcpy(scalar_be + 16, x_be_stage1, 32);
uint8_t pub_x_le[48], pub_y_le[48];
km_verify_ecdsa_pubkey_from_scalar(P384_LEN, scalar_be, 48, pub_x_le, pub_y_le);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP384R1, pub_x_le, pub_y_le, 1);
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP384R1, pub_x_le, pub_y_le, 1, NULL);
}
#endif
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
@@ -179,6 +179,15 @@ void esp_crypto_ecdsa_enable_periph_clk(bool enable)
esp_crypto_common_clk_enable(true);
}
ECDSA_RCC_ATOMIC() {
esp_crypto_common_clk_enable(enable);
#if SOC_ECDSA_SUPPORT_SOFTWARE_KEY
/* The ECDSA key registers retain a software-supplied key after an
* operation and ignore direct writes outside of an operation, so the
* peripheral is reset before release to scrub any key material */
if (!enable) {
ecdsa_ll_reset_register();
}
#endif /* SOC_ECDSA_SUPPORT_SOFTWARE_KEY */
ecdsa_ll_enable_bus_clock(enable);
if (enable) {
ecdsa_ll_reset_register();
+7 -1
View File
@@ -472,8 +472,14 @@ if(CONFIG_SOC_ECC_SUPPORTED)
endif()
endif()
if(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN OR CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY OR CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN)
if(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN OR CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY
OR CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN OR CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY)
target_sources(tfpsacrypto PRIVATE "${COMPONENT_DIR}/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c")
if(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY)
target_sources(tfpsacrypto PRIVATE
"${COMPONENT_DIR}/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c"
)
endif()
target_include_directories(tfpsacrypto PUBLIC "${COMPONENT_DIR}/port/psa_driver/include")
target_link_libraries(tfpsacrypto PRIVATE idf::efuse)
if(CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN)
+16
View File
@@ -1347,6 +1347,22 @@ menu "mbedTLS"
The key should be burnt in little endian format. espefuse utility handles it internally
but care needs to be taken while burning using esp_efuse APIs
config MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY
bool "Enable ECDSA signing with software keys using the on-chip ECDSA peripheral"
default y
depends on SOC_ECDSA_SUPPORT_SOFTWARE_KEY
help
Enable hardware accelerated ECDSA signing with plaintext keys using the
ECDSA peripheral's software key source.
Unlike MBEDTLS_HARDWARE_ECDSA_SIGN, this does not require the private key
to be provisioned in an eFuse key block or the Key Manager: any ECC key
pair imported through the PSA API is signed by the peripheral.
Note that deterministic signatures generated by the peripheral use its own
deterministic K derivation, which is not RFC 6979. Disable this option if
strict RFC 6979 deterministic signatures are required.
config MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
bool "Enable ECDSA signing using TEE secure storage"
default y
@@ -270,7 +270,8 @@
#define MBEDTLS_MPI_PRIME_SIEVE_VARIABLE_TIME
#endif
#if defined(CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY) || defined(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN) || defined(CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN)
#if defined(CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY) || defined(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN) \
|| defined(CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN) || defined(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY)
#define ESP_ECDSA_DRIVER_ENABLED
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY
#define ESP_ECDSA_VERIFY_DRIVER_ENABLED
@@ -278,6 +279,11 @@
#if defined(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN) || defined(CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN)
#define ESP_ECDSA_SIGN_DRIVER_ENABLED
#endif
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY
/* Accelerate signing with plaintext (transparent) keys using the ECDSA
* peripheral's software key source */
#define ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED
#endif
#endif
#ifdef CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED
@@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "psa/crypto.h"
#include "hal/ecdsa_types.h"
#include "psa_crypto_driver_esp_ecdsa_contexts.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reverse the byte order of a buffer (the ECDSA peripheral uses little endian)
*/
void esp_ecdsa_change_endianness(const uint8_t *old_point, uint8_t *new_point, uint8_t len);
/**
* @brief Map a key length in bytes to the driver's curve enum
*/
esp_ecdsa_curve_t esp_ecdsa_bits_to_curve(size_t key_len);
/**
* @brief Check that the hash algorithm matches the curve
*/
psa_status_t esp_ecdsa_validate_sha_alg(psa_algorithm_t alg, const esp_ecdsa_curve_t curve);
/**
* @brief Map the driver's curve enum to the HAL's curve enum
*/
ecdsa_curve_t esp_ecdsa_curve_to_hal_curve(esp_ecdsa_curve_t curve);
/**
* @brief Acquire the ECDSA hardware (locks and peripheral clocks)
*/
void esp_ecdsa_acquire_hardware(void);
/**
* @brief Release the ECDSA hardware
*/
void esp_ecdsa_release_hardware(void);
#ifdef __cplusplus
}
#endif
@@ -46,6 +46,7 @@
#endif /* SOC_MPI_SUPPORTED && SOC_ECDSA_USES_MPI */
#include "psa_crypto_driver_esp_ecdsa.h"
#include "include/psa_crypto_driver_esp_ecdsa_utilities.h"
#include "psa_crypto_driver_esp_opaque_common.h"
#include "psa_crypto_driver_wrappers_no_static.h"
#include "sdkconfig.h"
@@ -244,7 +245,7 @@ static psa_status_t esp_ecdsa_get_expected_storage_size(const uint8_t *key_buffe
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_CONSTANT_TIME_CM */
// Helper function to get curve from mbedtls group ID
static esp_ecdsa_curve_t psa_bits_to_ecdsa_curve(size_t key_len)
esp_ecdsa_curve_t esp_ecdsa_bits_to_curve(size_t key_len)
{
switch (key_len) {
case ECDSA_KEY_LEN_P192:
@@ -260,11 +261,12 @@ 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)
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || defined(ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED) \
|| (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)
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;
@@ -275,7 +277,7 @@ static ecdsa_curve_t esp_ecdsa_curve_to_hal_curve(esp_ecdsa_curve_t curve)
default: return (ecdsa_curve_t)-1;
}
}
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || (CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN && SOC_ECDSA_SUPPORT_EXPORT_PUBKEY) */
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED || (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)
@@ -293,7 +295,7 @@ static esp_tee_sec_storage_type_t esp_ecdsa_curve_to_tee_sec_storage_type(esp_ec
}
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
static void change_endianess(const uint8_t *old_point, uint8_t *new_point, uint8_t len)
void esp_ecdsa_change_endianness(const uint8_t *old_point, uint8_t *new_point, uint8_t len)
{
/* When the size is less than MAX_ECDSA_COMPONENT_LEN, it should be padded with 0 bytes*/
memset(new_point, 0x0, len);
@@ -303,7 +305,7 @@ static void change_endianess(const uint8_t *old_point, uint8_t *new_point, uint8
}
}
static psa_status_t validate_ecdsa_sha_alg(psa_algorithm_t alg, const esp_ecdsa_curve_t curve)
psa_status_t esp_ecdsa_validate_sha_alg(psa_algorithm_t alg, const esp_ecdsa_curve_t curve)
{
if ((PSA_ALG_SIGN_GET_HASH(alg) != PSA_ALG_SHA_256 && (curve == ESP_ECDSA_CURVE_SECP192R1 || curve == ESP_ECDSA_CURVE_SECP256R1))
#if SOC_ECDSA_SUPPORT_CURVE_P384
@@ -381,7 +383,7 @@ cleanup:
return status;
}
static void esp_ecdsa_acquire_hardware(void)
void esp_ecdsa_acquire_hardware(void)
{
esp_crypto_ecdsa_lock_acquire();
@@ -412,7 +414,7 @@ static void esp_ecdsa_acquire_hardware(void)
#endif /* SOC_ECDSA_USES_MPI */
}
static void esp_ecdsa_release_hardware(void)
void esp_ecdsa_release_hardware(void)
{
esp_crypto_ecdsa_enable_periph_clk(false);
@@ -469,12 +471,12 @@ psa_status_t esp_ecdsa_transparent_verify_hash_start(
}
size_t key_len = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes));
esp_ecdsa_curve_t curve = psa_bits_to_ecdsa_curve(key_len);
esp_ecdsa_curve_t curve = esp_ecdsa_bits_to_curve(key_len);
if (curve == ESP_ECDSA_CURVE_MAX) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = validate_ecdsa_sha_alg(alg, curve);
status = esp_ecdsa_validate_sha_alg(alg, curve);
if (status != PSA_SUCCESS) {
return status;
}
@@ -540,8 +542,8 @@ psa_status_t esp_ecdsa_transparent_verify_hash_start(
ecc_point_t point;
memset(&point, 0, sizeof(ecc_point_t));
change_endianess(public_key_buffer + 1, point.x, key_len);
change_endianess(public_key_buffer + 1 + key_len, point.y, key_len);
esp_ecdsa_change_endianness(public_key_buffer + 1, point.x, key_len);
esp_ecdsa_change_endianness(public_key_buffer + 1 + key_len, point.y, key_len);
point.len = key_len;
/* Reject the identity (point at infinity, all-zero coords) explicitly —
@@ -563,15 +565,15 @@ psa_status_t esp_ecdsa_transparent_verify_hash_start(
operation->curve = curve;
operation->key_len = key_len;
operation->sha_len = hash_length;
change_endianess(hash, operation->sha, key_len);
change_endianess(signature, operation->r, key_len);
change_endianess(signature + key_len, operation->s, key_len);
esp_ecdsa_change_endianness(hash, operation->sha, key_len);
esp_ecdsa_change_endianness(signature, operation->r, key_len);
esp_ecdsa_change_endianness(signature + key_len, operation->s, key_len);
/* The public key buffer is in the format 0x04 followed by the 2*key_len bytes public key */
/* The first byte is the format byte, which is ECDSA_UNCOMPRESSED_POINT_FORMAT */
/* The next key_len bytes are the x coordinate */
/* The next key_len bytes are the y coordinate */
change_endianess(public_key_buffer + 1, operation->qx, key_len);
change_endianess(public_key_buffer + 1 + key_len, operation->qy, key_len);
esp_ecdsa_change_endianness(public_key_buffer + 1, operation->qx, key_len);
esp_ecdsa_change_endianness(public_key_buffer + 1 + key_len, operation->qy, key_len);
return PSA_SUCCESS;
}
@@ -633,6 +635,7 @@ psa_status_t esp_ecdsa_transparent_verify_hash(
esp_ecdsa_transparent_verify_hash_abort(&operation);
return status;
}
#endif /* SOC_ECDSA_SUPPORTED */
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
@@ -738,7 +741,7 @@ static psa_status_t validate_ecdsa_opaque_key_attributes(const psa_key_attribute
return PSA_ERROR_NOT_SUPPORTED;
}
esp_ecdsa_curve_t expected_curve = psa_bits_to_ecdsa_curve(PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)));
esp_ecdsa_curve_t expected_curve = esp_ecdsa_bits_to_curve(PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)));
if (expected_curve == ESP_ECDSA_CURVE_MAX || expected_curve != opaque_key->curve) {
return PSA_ERROR_INVALID_ARGUMENT;
@@ -775,7 +778,7 @@ static psa_status_t validate_storage_curve(const psa_key_attributes_t *attribute
PSA_KEY_TYPE_ECC_GET_FAMILY(key_type) != PSA_ECC_FAMILY_SECP_R1) {
return PSA_ERROR_NOT_SUPPORTED;
}
esp_ecdsa_curve_t expected_curve = psa_bits_to_ecdsa_curve(PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)));
esp_ecdsa_curve_t expected_curve = esp_ecdsa_bits_to_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;
@@ -941,7 +944,7 @@ psa_status_t esp_ecdsa_opaque_sign_hash_start(
return status;
}
status = validate_ecdsa_sha_alg(alg, curve);
status = esp_ecdsa_validate_sha_alg(alg, curve);
if (status != PSA_SUCCESS) {
return status;
}
@@ -979,7 +982,7 @@ psa_status_t esp_ecdsa_opaque_sign_hash_start(
} else
#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */
{
change_endianess(hash, operation->sha, component_len);
esp_ecdsa_change_endianness(hash, operation->sha, component_len);
}
operation->key_buffer = key_buffer;
@@ -1186,9 +1189,9 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
#endif /* SOC_KEY_MANAGER_SUPPORTED */
// Convert r from little-endian to big-endian and copy to output
change_endianess(operation->r, signature, component_len);
esp_ecdsa_change_endianness(operation->r, signature, component_len);
// Convert s from little-endian to big-endian and copy to output
change_endianess(operation->s, signature + component_len, component_len);
esp_ecdsa_change_endianness(operation->s, signature + component_len, component_len);
#else
// This is an invalid operation as the hardware ECDSA signing is not supported on this chip
// and still the key is opaque.
@@ -1403,10 +1406,10 @@ psa_status_t esp_ecdsa_opaque_export_public_key(
data[0] = ECDSA_UNCOMPRESSED_POINT_FORMAT;
// Convert qx from little-endian to big-endian and copy to output
change_endianess(qx, data + 1, key_len);
esp_ecdsa_change_endianness(qx, data + 1, key_len);
// Convert qy from little-endian to big-endian and copy to output
change_endianess(qy, data + 1 + key_len, key_len);
esp_ecdsa_change_endianness(qy, data + 1 + key_len, key_len);
#else
// This is an invalid operation as the export public key is not supported on this chip
// and still the key is opaque
@@ -0,0 +1,229 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* ESP ECDSA PSA Crypto Transparent Sign Driver
*
* Signs with a plaintext (transparent) SECP-R1 key pair through the ECDSA
* peripheral's software key source, available from the ESP32-S31 onwards.
*/
#include <stdbool.h>
#include <string.h>
#include "soc/soc_caps.h"
#include "esp_log.h"
#include "esp_efuse.h"
#include "hal/ecdsa_types.h"
#include "hal/ecdsa_hal.h"
#include "hal/ecdsa_ll.h"
#include "psa_crypto_driver_esp_ecdsa.h"
#include "include/psa_crypto_driver_esp_ecdsa_utilities.h"
#include "sdkconfig.h"
#if defined(ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED)
static const char *TAG = "psa_crypto_driver_esp_ecdsa";
/* Bound for the zero-signature retry loop, in case the peripheral keeps
* failing for a given input */
#define ESP_ECDSA_SIGN_MAX_ATTEMPTS 16
psa_status_t esp_ecdsa_transparent_sign_hash_start(
esp_ecdsa_transparent_sign_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length)
{
if (!operation || !attributes || !key_buffer || !hash) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Any condition the peripheral cannot handle returns PSA_ERROR_NOT_SUPPORTED
* so that the PSA core falls back to the builtin implementation */
// Check if the ECDSA peripheral is supported on this chip revision
if (!ecdsa_ll_is_supported()) {
return PSA_ERROR_NOT_SUPPORTED;
}
// Check if the software key source has been permanently disabled by eFuse
if (!esp_efuse_is_ecdsa_software_key_allowed()) {
return PSA_ERROR_NOT_SUPPORTED;
}
if (!PSA_ALG_IS_ECDSA(alg)) {
return PSA_ERROR_NOT_SUPPORTED;
}
// Only plaintext SECP-R1 key pairs are supported
if (psa_get_key_type(attributes) != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
return PSA_ERROR_NOT_SUPPORTED;
}
if (PSA_ALG_ECDSA_IS_DETERMINISTIC(alg)) {
#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP
if (!ecdsa_ll_is_deterministic_mode_supported()) {
return PSA_ERROR_NOT_SUPPORTED;
}
#else
return PSA_ERROR_NOT_SUPPORTED;
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */
}
size_t key_len = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes));
esp_ecdsa_curve_t curve = esp_ecdsa_bits_to_curve(key_len);
if (curve == ESP_ECDSA_CURVE_MAX) {
return PSA_ERROR_NOT_SUPPORTED;
}
if (curve == ESP_ECDSA_CURVE_SECP192R1 && !esp_efuse_is_ecdsa_p192_curve_supported()) {
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t status = esp_ecdsa_validate_sha_alg(alg, curve);
if (status != PSA_SUCCESS) {
return status;
}
if ((curve == ESP_ECDSA_CURVE_SECP192R1 && hash_length != ECDSA_SHA_LEN) ||
(curve == ESP_ECDSA_CURVE_SECP256R1 && hash_length != ECDSA_SHA_LEN)
#if SOC_ECDSA_SUPPORT_CURVE_P384
|| (curve == ESP_ECDSA_CURVE_SECP384R1 && hash_length != ECDSA_SHA_LEN_P384)
#endif
) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* A transparent SECP-R1 key pair is stored as the raw private key in big-endian
* format. The PSA core has already validated 1 <= key < n at import time. */
if (key_buffer_size != key_len) {
return PSA_ERROR_NOT_SUPPORTED;
}
memset(operation, 0, sizeof(esp_ecdsa_transparent_sign_hash_operation_t));
operation->alg = alg;
operation->curve = curve;
operation->key_len = key_len;
operation->sha_len = hash_length;
esp_ecdsa_change_endianness(key_buffer, operation->key, key_len);
esp_ecdsa_change_endianness(hash, operation->sha, key_len);
return PSA_SUCCESS;
}
psa_status_t esp_ecdsa_transparent_sign_hash_complete(
esp_ecdsa_transparent_sign_hash_operation_t *operation,
uint8_t *signature, size_t signature_size,
size_t *signature_length)
{
if (!operation || !signature || !signature_length) {
return PSA_ERROR_INVALID_ARGUMENT;
}
size_t component_len = operation->key_len;
if (signature_size < 2 * component_len) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
ecdsa_curve_t hal_curve = esp_ecdsa_curve_to_hal_curve(operation->curve);
if (hal_curve == (ecdsa_curve_t)-1) {
return PSA_ERROR_INVALID_ARGUMENT;
}
ecdsa_sign_type_t k_type = ECDSA_K_TYPE_TRNG;
#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
if (PSA_ALG_ECDSA_IS_DETERMINISTIC(operation->alg)) {
k_type = ECDSA_K_TYPE_DETERMINISITIC;
}
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
uint8_t zeroes[MAX_ECDSA_COMPONENT_LEN] = {0};
ecdsa_hal_config_t conf = {
.mode = ECDSA_MODE_SIGN_GEN,
.curve = hal_curve,
.sha_mode = ECDSA_Z_USER_PROVIDED,
.sign_type = k_type,
.use_sw_key = true,
.sw_key = operation->key,
};
esp_ecdsa_acquire_hardware();
bool process_again = false;
int attempts = 0;
do {
ecdsa_hal_gen_signature(&conf, operation->sha, operation->r, operation->s, component_len);
process_again = !ecdsa_hal_get_operation_result()
|| !memcmp(operation->r, zeroes, component_len)
|| !memcmp(operation->s, zeroes, component_len);
} while (process_again && ++attempts < ESP_ECDSA_SIGN_MAX_ATTEMPTS);
esp_ecdsa_release_hardware();
if (process_again) {
ESP_LOGE(TAG, "Failed to generate an ECDSA signature using the software key");
return PSA_ERROR_GENERIC_ERROR;
}
// Convert r and s from little-endian to big-endian and copy to output
esp_ecdsa_change_endianness(operation->r, signature, component_len);
esp_ecdsa_change_endianness(operation->s, signature + component_len, component_len);
*signature_length = 2 * component_len;
return PSA_SUCCESS;
}
psa_status_t esp_ecdsa_transparent_sign_hash_abort(esp_ecdsa_transparent_sign_hash_operation_t *operation)
{
if (operation) {
/* Zeroizes the plaintext private key copy held in the operation context */
memset(operation, 0, sizeof(esp_ecdsa_transparent_sign_hash_operation_t));
}
return PSA_SUCCESS;
}
psa_status_t esp_ecdsa_transparent_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
esp_ecdsa_transparent_sign_hash_operation_t operation;
status = esp_ecdsa_transparent_sign_hash_start(&operation, attributes, key_buffer, key_buffer_size, alg, hash, hash_length);
if (status != PSA_SUCCESS) {
esp_ecdsa_transparent_sign_hash_abort(&operation);
return status;
}
status = esp_ecdsa_transparent_sign_hash_complete(&operation, signature, signature_size, signature_length);
if (status != PSA_SUCCESS) {
esp_ecdsa_transparent_sign_hash_abort(&operation);
return status;
}
return esp_ecdsa_transparent_sign_hash_abort(&operation);
}
#endif /* ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED */
@@ -242,6 +242,84 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete(
psa_status_t esp_ecdsa_opaque_sign_hash_abort(
esp_ecdsa_opaque_sign_hash_operation_t *operation);
#if defined(ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED)
/**
* @brief Sign a hash with a plaintext SECP-R1 key pair using the ECDSA peripheral's
* software key source
*
* Returns PSA_ERROR_NOT_SUPPORTED for any key/algorithm combination the peripheral
* cannot handle (or when the software key source is disabled by eFuse) so that the
* PSA core falls back to the builtin implementation.
*
* @param attributes Key attributes
* @param key_buffer Key buffer holding the raw private key (big endian)
* @param key_buffer_size Size of key buffer
* @param alg Algorithm
* @param hash Hash to sign
* @param hash_length Length of hash
* @param signature Signature buffer
* @param signature_size Size of signature buffer
* @param signature_length Actual signature length
* @return psa_status_t
*/
psa_status_t esp_ecdsa_transparent_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length);
/**
* @brief Start a hash signing operation using the ESP ECDSA transparent driver
*
* @param operation Operation context
* @param attributes Key attributes
* @param key_buffer Key buffer holding the raw private key (big endian)
* @param key_buffer_size Size of key buffer
* @param alg Algorithm
* @param hash Hash to sign
* @param hash_length Length of hash
* @return psa_status_t
*/
psa_status_t esp_ecdsa_transparent_sign_hash_start(
esp_ecdsa_transparent_sign_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length);
/**
* @brief Complete a hash signing operation using the ESP ECDSA transparent driver
*
* @param operation Operation context
* @param signature Signature buffer
* @param signature_size Size of signature buffer
* @param signature_length Actual signature length
* @return psa_status_t
*/
psa_status_t esp_ecdsa_transparent_sign_hash_complete(
esp_ecdsa_transparent_sign_hash_operation_t *operation,
uint8_t *signature, size_t signature_size,
size_t *signature_length);
/**
* @brief Abort a hash signing operation using the ESP ECDSA transparent driver
*
* Zeroizes the private key copy held in the operation context.
*
* @param operation Operation context
* @return psa_status_t
*/
psa_status_t esp_ecdsa_transparent_sign_hash_abort(
esp_ecdsa_transparent_sign_hash_operation_t *operation);
#endif /* ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED */
#ifdef __cplusplus
}
#endif
@@ -80,6 +80,20 @@ typedef struct {
size_t key_len;
bool is_persistent; /**< Cached persistence flag for use in complete */
} esp_ecdsa_opaque_sign_hash_operation_t;
#if defined(ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED)
/* The buffers are stored in the little-endian format */
typedef struct {
psa_algorithm_t alg;
esp_ecdsa_curve_t curve;
uint8_t key[MAX_ECDSA_COMPONENT_LEN]; /**< Plaintext private key copy, zeroized by the abort function */
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;
} esp_ecdsa_transparent_sign_hash_operation_t;
#endif /* ESP_ECDSA_TRANSPARENT_SIGN_DRIVER_ENABLED */
#endif /* !(__DOXYGEN__) */
#endif /* ESP_ECDSA_DRIVER_ENABLED */
#ifdef __cplusplus
@@ -391,7 +391,7 @@ TEST_CASE("mbedtls ECDSA signature verification rejects out-of-range r, s on SEC
#endif /* CONFIG_MBEDTLS_HARDWARE_ECC */
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY
#define USE_ECDSA_KEY_FROM_KEY_MANAGER INT_MAX
/*
@@ -424,7 +424,7 @@ const uint8_t k1_ecdsa384_encrypt[] = {
0x31, 0xd4, 0x4f, 0xf4, 0xf6, 0x1d, 0xa1, 0xc7, 0x1f, 0x2c, 0x11, 0xca, 0x9f, 0x21, 0x26, 0xaa, 0x37, 0xcf, 0x5b, 0x9e, 0x08, 0x26, 0x36, 0x31, 0xd7, 0x51, 0x3c, 0x33, 0x0d, 0x5d, 0x03, 0xad,
};
void test_ecdsa_sign(esp_ecdsa_curve_t curve, const uint8_t *hash, const uint8_t *pub_x, const uint8_t *pub_y, bool is_deterministic, int efuse_key_block, void *key_recovery_info)
void test_ecdsa_sign(esp_ecdsa_curve_t curve, const uint8_t *hash, const uint8_t *pub_x, const uint8_t *pub_y, bool is_deterministic, int efuse_key_block, void *key_recovery_info, const uint8_t *priv_key)
{
size_t hash_len = HASH_LEN;
uint8_t signature[2 * MAX_ECDSA_COMPONENT_LEN];
@@ -468,15 +468,23 @@ void test_ecdsa_sign(esp_ecdsa_curve_t curve, const uint8_t *hash, const uint8_t
psa_algorithm_t alg = (is_deterministic ? PSA_ALG_DETERMINISTIC_ECDSA(sha_alg) : PSA_ALG_ECDSA(sha_alg));
// Set attributes for opaque private key
// Set attributes for the private key
psa_set_key_type(&priv_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&priv_attr, plen);
psa_set_key_usage_flags(&priv_attr, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&priv_attr, alg);
psa_set_key_lifetime(&priv_attr, PSA_KEY_LIFETIME_ESP_ECDSA_VOLATILE); // Opaque key
// Import opaque key reference
psa_status_t status = psa_import_key(&priv_attr, (uint8_t*) &opaque_key, sizeof(opaque_key), &priv_key_id);
psa_status_t status;
if (priv_key) {
/* Plaintext key pair with the default (transparent) lifetime, signed
* through the ECDSA peripheral's software key source */
status = psa_import_key(&priv_attr, priv_key, plen_bytes, &priv_key_id);
} else {
psa_set_key_lifetime(&priv_attr, PSA_KEY_LIFETIME_ESP_ECDSA_VOLATILE); // Opaque key
// Import opaque key reference
status = psa_import_key(&priv_attr, (uint8_t*) &opaque_key, sizeof(opaque_key), &priv_key_id);
}
TEST_ASSERT_EQUAL_HEX32(PSA_SUCCESS, status);
TEST_ASSERT_NOT_EQUAL(0, priv_key_id);
@@ -493,12 +501,15 @@ void test_ecdsa_sign(esp_ecdsa_curve_t curve, const uint8_t *hash, const uint8_t
psa_reset_key_attributes(&priv_attr);
}
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
/* The following test cases need a key provisioned in eFuse or deployed
* through the Key Manager */
TEST_CASE("mbedtls ECDSA signature generation on SECP256R1", "[mbedtls][efuse_key]")
{
if (!ecdsa_ll_is_supported()) {
TEST_IGNORE_MESSAGE("ECDSA is not supported");
}
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, SECP256R1_EFUSE_BLOCK, NULL);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, SECP256R1_EFUSE_BLOCK, NULL, NULL);
}
#ifdef SOC_ECDSA_SUPPORT_CURVE_P384
@@ -508,7 +519,7 @@ TEST_CASE("mbedtls ECDSA signature generation on SECP384R1", "[mbedtls][efuse_ke
TEST_IGNORE_MESSAGE("ECDSA is not supported");
}
uint8_t efuse_key_block = HAL_ECDSA_COMBINE_KEY_BLOCKS(SECP384R1_EFUSE_BLOCK_HIGH, SECP384R1_EFUSE_BLOCK_LOW);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, efuse_key_block, NULL);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, efuse_key_block, NULL, NULL);
}
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
@@ -551,7 +562,7 @@ TEST_CASE("mbedtls ECDSA signature generation on SECP256R1", "[mbedtls][key_mana
TEST_ASSERT_NOT_NULL(key_recovery_info);
deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256, key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x_km, ecdsa256_pub_y_km, false, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x_km, ecdsa256_pub_y_km, false, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info, NULL);
free(key_recovery_info);
}
#ifdef SOC_ECDSA_SUPPORT_CURVE_P384
@@ -569,7 +580,7 @@ TEST_CASE("mbedtls ECDSA signature generation on SECP384R1", "[mbedtls][key_mana
TEST_ASSERT_NOT_NULL(key_recovery_info);
deploy_key_in_key_manager(k1_ecdsa384_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_384, key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x_km, ecdsa384_pub_y_km, false, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x_km, ecdsa384_pub_y_km, false, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info, NULL);
free(key_recovery_info);
}
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
@@ -585,7 +596,7 @@ TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP256R1", "[mbe
if (!ecdsa_ll_is_deterministic_mode_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA deterministic mode is not supported.");
} else {
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, true, SECP256R1_EFUSE_BLOCK, NULL);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, true, SECP256R1_EFUSE_BLOCK, NULL, NULL);
}
}
@@ -596,7 +607,7 @@ TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP384R1", "[mbe
TEST_IGNORE_MESSAGE("ECDSA is not supported");
}
uint8_t efuse_key_block = HAL_ECDSA_COMBINE_KEY_BLOCKS(SECP384R1_EFUSE_BLOCK_HIGH, SECP384R1_EFUSE_BLOCK_LOW);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, true, efuse_key_block, NULL);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, true, efuse_key_block, NULL, NULL);
}
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
@@ -618,7 +629,7 @@ TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP256R1", "[mbe
TEST_ASSERT_NOT_NULL(key_recovery_info);
deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256, key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x_km, ecdsa256_pub_y_km, true, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x_km, ecdsa256_pub_y_km, true, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info, NULL);
free(key_recovery_info);
}
}
@@ -641,7 +652,7 @@ TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP384R1", "[mbe
TEST_ASSERT_NOT_NULL(key_recovery_info);
deploy_key_in_key_manager(k1_ecdsa384_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_384, key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x_km, ecdsa384_pub_y_km, true, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info);
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x_km, ecdsa384_pub_y_km, true, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info, NULL);
free(key_recovery_info);
}
}
@@ -920,4 +931,99 @@ TEST_CASE("mbedtls ECDSA signature generation verification, import and export er
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN */
#if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY && (CONFIG_MBEDTLS_HARDWARE_ECC || CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY)
/*
* Software-key tests: the private key is a plaintext (transparent) PSA key,
* signed by the ECDSA peripheral through its software key source. These tests
* do not need any key provisioned in eFuse or the Key Manager.
*
* The keys below match the ecdsa_key_p256.pem / ecdsa_key_p384.pem files in
* the test app directory (and the ecdsa256/384_pub_x/y constants above).
*/
/* Big endian */
static const uint8_t ecdsa256_priv[] = {
0x11, 0x25, 0x63, 0x32, 0x3e, 0x15, 0x36, 0x2e,
0xd1, 0xac, 0x4b, 0x48, 0x3a, 0x00, 0x36, 0x3d,
0x24, 0x7e, 0x6d, 0x7f, 0xa3, 0x10, 0x73, 0x30,
0x20, 0xcb, 0xc7, 0xcf, 0x4c, 0x2b, 0x47, 0xf3,
};
#if SOC_ECDSA_SUPPORT_CURVE_P384
/* Big endian */
static const uint8_t ecdsa384_priv[] = {
0x25, 0x24, 0xd3, 0x71, 0xb1, 0x87, 0xe4, 0xe4,
0xb8, 0xec, 0xd5, 0x2f, 0xb4, 0x03, 0xe1, 0x74,
0x6e, 0xc6, 0xc2, 0x04, 0xe6, 0x2f, 0x12, 0x41,
0xa0, 0x1c, 0xb7, 0xb6, 0x19, 0x7f, 0x01, 0x65,
0x6b, 0xc5, 0xfd, 0x47, 0x01, 0x43, 0xf3, 0x02,
0xab, 0x0d, 0xa6, 0xfe, 0x51, 0x67, 0x0f, 0x1f,
};
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
TEST_CASE("mbedtls ECDSA signature generation with software key on SECP256R1", "[mbedtls][ecdsa_sw_key]")
{
if (!ecdsa_ll_is_supported()) {
TEST_IGNORE_MESSAGE("ECDSA is not supported");
}
if (!esp_efuse_is_ecdsa_software_key_allowed()) {
TEST_IGNORE_MESSAGE("ECDSA software key is disabled by eFuse");
}
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, 0, NULL, ecdsa256_priv);
#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, true, 0, NULL, ecdsa256_priv);
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
}
#ifdef SOC_ECDSA_SUPPORT_CURVE_P384
TEST_CASE("mbedtls ECDSA signature generation with software key on SECP384R1", "[mbedtls][ecdsa_sw_key]")
{
if (!ecdsa_ll_is_supported()) {
TEST_IGNORE_MESSAGE("ECDSA is not supported");
}
if (!esp_efuse_is_ecdsa_software_key_allowed()) {
TEST_IGNORE_MESSAGE("ECDSA software key is disabled by eFuse");
}
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, 0, NULL, ecdsa384_priv);
#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, true, 0, NULL, ecdsa384_priv);
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
}
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
TEST_CASE("mbedtls ECDSA software fallback for combinations unsupported by the peripheral", "[mbedtls][ecdsa_sw_key]")
{
/* P-256 key with a SHA-384 sized hash is not supported by the transparent
* sign driver, so this exercises the software fallback path end-to-end */
uint8_t signature[2 * ECDSA_P256_HASH_COMPONENT_LEN];
size_t signature_len = 0;
psa_key_id_t priv_key_id = 0;
psa_key_attributes_t priv_attr = PSA_KEY_ATTRIBUTES_INIT;
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_384);
psa_set_key_type(&priv_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&priv_attr, 256);
psa_set_key_usage_flags(&priv_attr, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&priv_attr, alg);
psa_status_t status = psa_import_key(&priv_attr, ecdsa256_priv, sizeof(ecdsa256_priv), &priv_key_id);
TEST_ASSERT_EQUAL_HEX32(PSA_SUCCESS, status);
status = psa_sign_hash(priv_key_id, alg, sha, 48, signature, sizeof(signature), &signature_len);
TEST_ASSERT_EQUAL_HEX32(PSA_SUCCESS, status);
TEST_ASSERT_TRUE(signature_len == sizeof(signature));
status = psa_verify_hash(priv_key_id, alg, sha, 48, signature, signature_len);
TEST_ASSERT_EQUAL_HEX32(PSA_SUCCESS, status);
psa_destroy_key(priv_key_id);
psa_reset_key_attributes(&priv_attr);
}
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY && (CONFIG_MBEDTLS_HARDWARE_ECC || CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY) */
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN || CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_SOFTWARE_KEY */
@@ -127,6 +127,20 @@ def test_mbedtls_ecdsa_sign(dut: Dut) -> None:
dut.run_all_single_board_cases(group='efuse_key')
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'default',
],
indirect=True,
)
@idf_parametrize('target', ['esp32s31'], indirect=['target'])
def test_mbedtls_ecdsa_sw_key_sign(dut: Dut) -> None:
# Software-key ECDSA tests need no eFuse provisioning and are enabled by default
dut.run_all_single_board_cases(group='ecdsa_sw_key')
@pytest.mark.nvs_encr_hmac
@pytest.mark.parametrize(
'config',
@@ -1147,6 +1147,10 @@ config SOC_ECDSA_SUPPORT_CURVE_SPECIFIC_KEY_PURPOSES
bool
default y
config SOC_ECDSA_SUPPORT_SOFTWARE_KEY
bool
default y
config SOC_DS_SIGNATURE_MAX_BIT_LEN
int
default 4096
@@ -423,6 +423,7 @@
#define SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP (1)
#define SOC_ECDSA_SUPPORT_CURVE_P384 (1)
#define SOC_ECDSA_SUPPORT_CURVE_SPECIFIC_KEY_PURPOSES (1) /*!< Support individual key purposes for different ECDSA curves (P192, P256, P384) */
#define SOC_ECDSA_SUPPORT_SOFTWARE_KEY (1) /*!< Support software supplied private key written into the ECDSA key registers */
/*-------------------------- Digital Signature CAPS ----------------------------------------*/
#define SOC_DS_SIGNATURE_MAX_BIT_LEN (4096)