diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index e610d5c054f..261fc2e0a8d 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -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 diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index b4f53dc96be..f6c36b8388f 100644 --- a/components/efuse/src/esp_efuse_fields.c +++ b/components/efuse/src/esp_efuse_fields.c @@ -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 diff --git a/components/esp_hal_security/ecdsa_hal.c b/components/esp_hal_security/ecdsa_hal.c index 6f76a10faa9..50945591654 100644 --- a/components/esp_hal_security/ecdsa_hal.c +++ b/components/esp_hal_security/ecdsa_hal.c @@ -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) { diff --git a/components/esp_hal_security/esp32s31/include/hal/ecdsa_ll.h b/components/esp_hal_security/esp32s31/include/hal/ecdsa_ll.h index 842c66c38f8..4733e977a8b 100644 --- a/components/esp_hal_security/esp32s31/include/hal/ecdsa_ll.h +++ b/components/esp_hal_security/esp32s31/include/hal/ecdsa_ll.h @@ -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 * diff --git a/components/esp_hal_security/include/hal/ecdsa_hal.h b/components/esp_hal_security/include/hal/ecdsa_hal.h index 922232dd695..cf13c29561d 100644 --- a/components/esp_hal_security/include/hal/ecdsa_hal.h +++ b/components/esp_hal_security/include/hal/ecdsa_hal.h @@ -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 diff --git a/components/esp_hal_security/test_apps/crypto/main/app_main.c b/components/esp_hal_security/test_apps/crypto/main/app_main.c index c7c923e20cf..d177c28a5f5 100644 --- a/components/esp_hal_security/test_apps/crypto/main/app_main.c +++ b/components/esp_hal_security/test_apps/crypto/main/app_main.c @@ -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 diff --git a/components/esp_hal_security/test_apps/crypto/main/ecdsa/ecdsa_params.h b/components/esp_hal_security/test_apps/crypto/main/ecdsa/ecdsa_params.h index 011ea2fe3de..87ba5d7b7d2 100644 --- a/components/esp_hal_security/test_apps/crypto/main/ecdsa/ecdsa_params.h +++ b/components/esp_hal_security/test_apps/crypto/main/ecdsa/ecdsa_params.h @@ -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, +}; diff --git a/components/esp_hal_security/test_apps/crypto/main/ecdsa/test_ecdsa.c b/components/esp_hal_security/test_apps/crypto/main/ecdsa/test_ecdsa.c index 62aa5c73967..31c5365681d 100644 --- a/components/esp_hal_security/test_apps/crypto/main/ecdsa/test_ecdsa.c +++ b/components/esp_hal_security/test_apps/crypto/main/ecdsa/test_ecdsa.c @@ -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 */ } diff --git a/components/esp_hal_security/test_apps/crypto/main/key_manager/test_key_manager.c b/components/esp_hal_security/test_apps/crypto/main/key_manager/test_key_manager.c index 45eddcfd82e..bde15383cca 100644 --- a/components/esp_hal_security/test_apps/crypto/main/key_manager/test_key_manager.c +++ b/components/esp_hal_security/test_apps/crypto/main/key_manager/test_key_manager.c @@ -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 */ diff --git a/components/esp_security/src/esp_crypto_periph_clk.c b/components/esp_security/src/esp_crypto_periph_clk.c index c44abb56d6e..2236ce99cc2 100644 --- a/components/esp_security/src/esp_crypto_periph_clk.c +++ b/components/esp_security/src/esp_crypto_periph_clk.c @@ -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(); diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index f7168a4e8da..97843fd99e5 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -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) diff --git a/components/mbedtls/Kconfig b/components/mbedtls/Kconfig index 92660416518..db3b6e0f84a 100644 --- a/components/mbedtls/Kconfig +++ b/components/mbedtls/Kconfig @@ -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 diff --git a/components/mbedtls/mbedtls b/components/mbedtls/mbedtls index ce3f3485a12..f5c91881be9 160000 --- a/components/mbedtls/mbedtls +++ b/components/mbedtls/mbedtls @@ -1 +1 @@ -Subproject commit ce3f3485a121c100f58f36d700cb35b060f6e866 +Subproject commit f5c91881be98b4da0bf57c217bf45b668fb84f9f diff --git a/components/mbedtls/port/include/mbedtls/esp_config.h b/components/mbedtls/port/include/mbedtls/esp_config.h index f275cd51e84..7ac5c92a06a 100644 --- a/components/mbedtls/port/include/mbedtls/esp_config.h +++ b/components/mbedtls/port/include/mbedtls/esp_config.h @@ -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 diff --git a/components/mbedtls/port/psa_driver/esp_ecdsa/include/psa_crypto_driver_esp_ecdsa_utilities.h b/components/mbedtls/port/psa_driver/esp_ecdsa/include/psa_crypto_driver_esp_ecdsa_utilities.h new file mode 100644 index 00000000000..d7ed3f094c7 --- /dev/null +++ b/components/mbedtls/port/psa_driver/esp_ecdsa/include/psa_crypto_driver_esp_ecdsa_utilities.h @@ -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 diff --git a/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c index 46849f7a459..ede7cd07ee0 100644 --- a/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c +++ b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c @@ -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 diff --git a/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c new file mode 100644 index 00000000000..afda4de809c --- /dev/null +++ b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c @@ -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 +#include +#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 */ diff --git a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa.h b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa.h index a6181057d71..bdc1b7a7efe 100644 --- a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa.h +++ b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa.h @@ -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 diff --git a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h index 0b73ec155c0..15f5da8e5c1 100644 --- a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h +++ b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h @@ -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 diff --git a/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c b/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c index f7c22646dd5..7b1dcec3f85 100644 --- a/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c +++ b/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c @@ -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 */ diff --git a/components/mbedtls/test_apps/mbedtls_ut/pytest_mbedtls_ut.py b/components/mbedtls/test_apps/mbedtls_ut/pytest_mbedtls_ut.py index 16dfd67e22d..8b8c2122018 100644 --- a/components/mbedtls/test_apps/mbedtls_ut/pytest_mbedtls_ut.py +++ b/components/mbedtls/test_apps/mbedtls_ut/pytest_mbedtls_ut.py @@ -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', diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 66ddd660034..9c98367c407 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -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 diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 9d3fb268382..f2b4598fdb5 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -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)