Merge branch 'fix/ecdsa_ecc_hw_input_validation_v5.5' into 'release/v5.5'

Validate ECDSA signature range and harden ECC memory power-down (v5.5)

See merge request espressif/esp-idf!49431
This commit is contained in:
Jiang Jiang Jian
2026-06-17 11:59:02 +08:00
40 changed files with 632 additions and 129 deletions
+4
View File
@@ -87,6 +87,10 @@ if(CONFIG_ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_NO_MAP)
list(APPEND sources "patches/esp_rom_cache_writeback_esp32c5_esp32c61_esp32h4.c")
endif()
if(CONFIG_ESP_ROM_ECDSA_VERIFY_PATCH)
list(APPEND sources "patches/esp_rom_ecdsa.c")
endif()
idf_component_register(SRCS ${sources}
INCLUDE_DIRS ${include_dirs}
PRIV_REQUIRES ${private_required_comp}
@@ -127,6 +127,10 @@ config ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP
bool
default y
config ESP_ROM_ECDSA_VERIFY_PATCH
bool
default y
config ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_NO_MAP
bool
default y
@@ -37,4 +37,5 @@
#define ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY (1) // ROM mem/str functions are not optimized well for misaligned memory access.
#define ESP_ROM_DELAY_US_PATCH (1) // ROM ets_delay_us needs patch for U-mode operation
#define ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP (1) // ROM supports the secure boot fast wakeup feature
#define ESP_ROM_ECDSA_VERIFY_PATCH (1) // ROM ets_ecdsa_verify API requires a software patch
#define ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_NO_MAP (1) // ROM cache writeback related needs patch to avoid sync loss, no map parameter
+2 -3
View File
@@ -412,9 +412,8 @@ esp_rom_km_huk_risk = 0x40000898;
/* Functions */
ets_emsa_pss_verify = 0x4000089c;
ets_rsa_pss_verify = 0x400008a0;
ets_ecdsa_verify = 0x400008a4;
ets_secure_boot_verify_bootloader_with_keys = 0x400008a8;
ets_secure_boot_verify_signature = 0x400008ac;
_rom_ets_ecdsa_verify = 0x400008a4;
_rom_ets_secure_boot_verify_signature = 0x400008ac;
ets_secure_boot_read_key_digests = 0x400008b0;
ets_mgf1_sha256 = 0x400008b4;
ets_secure_boot_revoke_public_key_digest = 0x400008b8;
@@ -115,6 +115,10 @@ config ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY
bool
default y
config ESP_ROM_ECDSA_VERIFY_PATCH
bool
default y
config ESP_ROM_DELAY_US_PATCH
bool
default y
@@ -34,5 +34,6 @@
#define ESP_ROM_USB_OTG_NUM (-1) // No USB_OTG CDC in the ROM, set -1 for Kconfig usage.
#define ESP_ROM_HAS_OUTPUT_PUTC_FUNC (1) // ROM has esp_rom_output_putc (or ets_write_char_uart)
#define ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY (1) // ROM mem/str functions are not optimized well for misaligned memory access.
#define ESP_ROM_ECDSA_VERIFY_PATCH (1) // ROM ets_ecdsa_verify API requires a software patch
#define ESP_ROM_DELAY_US_PATCH (1) // ROM ets_delay_us needs patch for U-mode operation
#define ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_NO_MAP (1) // ROM cache writeback related needs patch to avoid sync loss, no map parameter
@@ -370,9 +370,8 @@ ets_efuse_usb_device_disabled = 0x40000808;
***************************************/
/* Functions */
ets_ecdsa_verify = 0x40000810;
ets_secure_boot_verify_bootloader_with_keys = 0x40000814;
ets_secure_boot_verify_signature = 0x40000818;
_rom_ets_ecdsa_verify = 0x40000810;
_rom_ets_secure_boot_verify_signature = 0x40000818;
ets_secure_boot_read_key_digests = 0x4000081c;
ets_secure_boot_revoke_public_key_digest = 0x40000820;
@@ -122,3 +122,7 @@ config ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY
config ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP
bool
default y
config ESP_ROM_ECDSA_VERIFY_PATCH
bool
default y
@@ -36,3 +36,4 @@
#define ESP_ROM_NO_USB_SERIAL_OUTPUT_API (1) // ROM does not export the usb-serial-jtag write char function
#define ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY (1) // ROM mem/str functions are not optimized well for misaligned memory access.
#define ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP (1) // ROM supports the secure boot fast wakeup feature
#define ESP_ROM_ECDSA_VERIFY_PATCH (1) // ROM ets_ecdsa_verify API requires a software patch
+2 -3
View File
@@ -361,9 +361,8 @@ ets_efuse_secure_boot_fast_wake_enabled = 0x40000830;
/* Functions */
ets_emsa_pss_verify = 0x40000834;
ets_rsa_pss_verify = 0x40000838;
ets_ecdsa_verify = 0x4000083c;
ets_secure_boot_verify_bootloader_with_keys = 0x40000840;
ets_secure_boot_verify_signature = 0x40000844;
_rom_ets_ecdsa_verify = 0x4000083c;
_rom_ets_secure_boot_verify_signature = 0x40000844;
ets_secure_boot_read_key_digests = 0x40000848;
ets_secure_boot_revoke_public_key_digest = 0x4000084c;
@@ -91,6 +91,10 @@ config ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY
bool
default y
config ESP_ROM_ECDSA_VERIFY_PATCH
bool
default y
config ESP_ROM_BOOTLOADER_OFFSET_FLASH
hex
default 0x2000
@@ -28,5 +28,6 @@
#define ESP_ROM_CLIC_INT_TYPE_PATCH (1) // ROM api esprv_intc_int_set_type configuring edge type interrupt (old revisions)
#define ESP_ROM_HAS_OUTPUT_PUTC_FUNC (1) // ROM has esp_rom_output_putc (or ets_write_char_uart)
#define ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY (1) // ROM mem/str functions are not optimized well for misaligned memory access.
#define ESP_ROM_ECDSA_VERIFY_PATCH (1) // ROM ets_ecdsa_verify API requires a software patch
#define ESP_ROM_BOOTLOADER_OFFSET_FLASH (0x2000) // Bootloader offset in flash determined by the ROM bootloader
#define ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_MAP (1) // ROM cache writeback related needs patch to avoid sync loss, need map parameter
@@ -448,9 +448,8 @@ esp_rom_km_huk_risk = 0x4fc00710;
/* Functions */
ets_emsa_pss_verify = 0x4fc00714;
ets_rsa_pss_verify = 0x4fc00718;
ets_ecdsa_verify = 0x4fc0071c;
ets_secure_boot_verify_bootloader_with_keys = 0x4fc00720;
ets_secure_boot_verify_signature = 0x4fc00724;
_rom_ets_ecdsa_verify = 0x4fc0071c;
_rom_ets_secure_boot_verify_signature = 0x4fc00724;
ets_secure_boot_read_key_digests = 0x4fc00728;
ets_secure_boot_revoke_public_key_digest = 0x4fc0072c;
+2 -3
View File
@@ -450,9 +450,8 @@ esp_rom_km_huk_risk = 0x4fc0071c;
/* Functions */
ets_emsa_pss_verify = 0x4fc00720;
ets_rsa_pss_verify = 0x4fc00724;
ets_ecdsa_verify = 0x4fc00728;
ets_secure_boot_verify_bootloader_with_keys = 0x4fc0072c;
ets_secure_boot_verify_signature = 0x4fc00730;
_rom_ets_ecdsa_verify = 0x4fc00728;
_rom_ets_secure_boot_verify_signature = 0x4fc00730;
ets_secure_boot_read_key_digests = 0x4fc00734;
ets_secure_boot_revoke_public_key_digest = 0x4fc00738;
+231
View File
@@ -0,0 +1,231 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_rom_caps.h"
#if ESP_ROM_ECDSA_VERIFY_PATCH
#include "soc/soc_caps.h"
#include "esp_fault_internal.h"
#include "hal/ecc_ll.h"
#include "rom/ecdsa.h"
#define VALID_MAGIC_OK 0x6A6A6A6AU
#define VALID_MAGIC_FAIL 0x95959595U
static const uint32_t ecdsa_n_p192[6] = {
0xb4d22831U, 0x146bc9b1U, 0x99def836U, 0xffffffffU, 0xffffffffU, 0xffffffffU,
};
static const uint32_t ecdsa_n_p256[8] = {
0xfc632551U, 0xf3b9cac2U, 0xa7179e84U, 0xbce6faadU, 0xffffffffU, 0xffffffffU, 0x00000000U, 0xffffffffU,
};
#if SOC_ECDSA_SUPPORT_CURVE_P384
static const uint32_t ecdsa_n_p384[12] = {
0xccc52973U, 0xecec196aU, 0x48b0a77aU, 0x581a0db2U, 0xf4372ddfU, 0xc7634d81U,
0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU,
};
#endif
static uint32_t ecdsa_mpi_isZero(const uint32_t *mpi, int num_words)
{
uint32_t bits = 0;
for (int i = 0; i < num_words; ++i) {
bits |= mpi[i];
}
return (bits == 0);
}
static int ecdsa_mpi_cmp_unsafe(const uint32_t *left, const uint32_t *right, int num_words)
{
for (int i = num_words - 1; i >= 0; --i) {
if (left[i] > right[i]) {
return 1;
} else if (left[i] < right[i]) {
return -1;
}
}
return 0;
}
static bool ecdsa_scalars_in_range(const uint32_t *r, const uint32_t *s, const uint32_t *n, int num_words, uint32_t *result)
{
volatile uint32_t verdict = VALID_MAGIC_FAIL;
if (ecdsa_mpi_isZero(r, num_words) == 0 && ecdsa_mpi_cmp_unsafe(n, r, num_words) == 1 && ecdsa_mpi_isZero(s, num_words) == 0
&& ecdsa_mpi_cmp_unsafe(n, s, num_words) == 1) {
verdict = VALID_MAGIC_OK;
}
if (verdict != VALID_MAGIC_OK) {
return false;
}
ESP_FAULT_ASSERT(verdict == VALID_MAGIC_OK);
*result = VALID_MAGIC_OK;
return true;
}
// TODO: IDF-15721
/*
* Runtime gate that decides whether the ROM ECDSA verification routines
* (ets_ecdsa_verify / ets_secure_boot_verify_signature) need the software patch
* in this file, or whether the ROM implementation is safe to call directly.
*
* When a future revision of one of these chips ships a ROM with these ECDSA
* verification issues fixed, add a ROM-version check here (e.g. compare the
* _rom_eco_version symbol against the first fixed ROM ECO version for that
* target) and return false for the fixed ROMs, so they skip the patch and jump
* straight to the _rom_ routine.
*/
extern int _rom_ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig,
ECDSA_CURVE curve_id, const uint8_t *image_digest,
uint8_t *verified_digest);
int ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig,
ECDSA_CURVE curve_id, const uint8_t *image_digest,
uint8_t *verified_digest)
{
int words;
int bytes;
const uint32_t *n;
if (curve_id == ECDSA_CURVE_P256) {
words = 8;
bytes = 32;
n = ecdsa_n_p256;
}
#if SOC_ECDSA_SUPPORT_CURVE_P384
else if (curve_id == ECDSA_CURVE_P384) {
words = 12;
bytes = 48;
n = ecdsa_n_p384;
}
#endif
else {
// curve_id == ECDSA_CURVE_P192
words = 6;
bytes = 24;
n = ecdsa_n_p192;
}
uint32_t r[12] = { 0 };
uint32_t s[12] = { 0 };
memcpy(r, &sig[0], bytes);
memcpy(s, &sig[bytes], bytes);
uint32_t ret_status = VALID_MAGIC_FAIL;
bool ok = ecdsa_scalars_in_range(r, s, n, words, &ret_status);
if (!ok || ret_status != VALID_MAGIC_OK) {
return 0;
}
ESP_FAULT_ASSERT(ok && ret_status == VALID_MAGIC_OK);
ecc_ll_power_up();
ESP_FAULT_ASSERT(ecc_ll_mem_force_pd_is_clear());
int ret = _rom_ets_ecdsa_verify(key, sig, curve_id, image_digest, verified_digest);
if (ret == 1) {
ESP_FAULT_ASSERT(ret_status == VALID_MAGIC_OK);
int sig_diff = (memcmp(r, &sig[0], bytes) | memcmp(s, &sig[bytes], bytes));
ESP_FAULT_ASSERT(sig_diff == 0);
ESP_FAULT_ASSERT(ret == 1);
return ret;
}
return 0;
}
#if CONFIG_SECURE_BOOT_V2_ENABLED || CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT
#include "rom/secure_boot.h"
#if CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
static bool esp_rom_ecdsa_scalars_in_range(const uint8_t *r_le, const uint8_t *s_le, size_t component_len)
{
const uint32_t *n;
int words;
switch (component_len) {
case 24: n = ecdsa_n_p192; words = 6; break;
case 32: n = ecdsa_n_p256; words = 8; break;
#if SOC_ECDSA_SUPPORT_CURVE_P384
case 48: n = ecdsa_n_p384; words = 12; break;
#endif
default: return false;
}
uint32_t r[12] = { 0 };
uint32_t s[12] = { 0 };
memcpy(r, r_le, component_len);
memcpy(s, s_le, component_len);
uint32_t result = VALID_MAGIC_FAIL;
bool ok = ecdsa_scalars_in_range(r, s, n, words, &result);
if (!ok || result != VALID_MAGIC_OK) {
return false;
}
ESP_FAULT_ASSERT(ok && result == VALID_MAGIC_OK);
return true;
}
static bool esp_rom_ecdsa_sig_block_in_range(const ets_secure_boot_sig_block_t *block)
{
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
return true;
}
size_t component_len;
switch (block->ecdsa.key.curve_id) {
case ECDSA_CURVE_P256: component_len = 32; break;
#if SOC_ECDSA_SUPPORT_CURVE_P384
case ECDSA_CURVE_P384: component_len = 48; break;
#endif
default: return false;
}
return esp_rom_ecdsa_scalars_in_range(&block->ecdsa.signature[0],
&block->ecdsa.signature[component_len],
component_len);
}
#endif /* CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME */
extern ets_secure_boot_status_t _rom_ets_secure_boot_verify_signature(const ets_secure_boot_signature_t *sig,
const uint8_t *image_digest,
const ets_secure_boot_key_digests_t *trusted_keys,
uint8_t *verified_digest);
ets_secure_boot_status_t ets_secure_boot_verify_signature(const ets_secure_boot_signature_t *sig,
const uint8_t *image_digest,
const ets_secure_boot_key_digests_t *trusted_keys,
uint8_t *verified_digest)
{
#if CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
volatile ets_secure_boot_status_t range_status = SB_FAILED;
unsigned blocks_in_range = 0;
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
if (esp_rom_ecdsa_sig_block_in_range(&sig->block[i])) {
blocks_in_range++;
}
}
if (blocks_in_range == SECURE_BOOT_NUM_BLOCKS) {
range_status = SB_SUCCESS;
}
if (range_status != SB_SUCCESS) {
return SB_FAILED;
}
ESP_FAULT_ASSERT(range_status == SB_SUCCESS);
ESP_FAULT_ASSERT(blocks_in_range == SECURE_BOOT_NUM_BLOCKS);
ecc_ll_power_up();
ESP_FAULT_ASSERT(ecc_ll_mem_force_pd_is_clear());
#endif /* CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME */
return _rom_ets_secure_boot_verify_signature(sig, image_digest, trusted_keys, verified_digest);
}
#endif /* CONFIG_SECURE_BOOT_V2_ENABLED || CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT */
#endif /* ESP_ROM_ECDSA_VERIFY_PATCH */