Merge branch 'fix/secure_boot_bootloader_ecdsa_range_gate_v6.0' into 'release/v6.0'

Add ECDSA signature bounds check in bootloader before Secure Boot verify (v6.0)

See merge request espressif/esp-idf!49633
This commit is contained in:
Aditya Patwardhan
2026-06-19 11:51:09 +05:30
26 changed files with 176 additions and 43 deletions
@@ -31,7 +31,7 @@
#endif
bootloader_stack_overhead = 0x2000; /* For safety margin between bootloader data section and startup stacks */
bootloader_dram_seg_len = 0x5000;
bootloader_iram_loader_seg_len = 0x7000;
bootloader_iram_loader_seg_len = 0x8000;
bootloader_iram_seg_len = 0x2D00;
/* Start of the lower region is determined by region size and the end of the higher region */
@@ -54,9 +54,9 @@ MEMORY
* 3. Update SRAM_DRAM_END in components/esp_system/ld/esp32p4/memory.ld.in to the same value.
*/
#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
#define BOOTLOADER_IRAM_LOADER_SEG_START_EXPECTED 0x4FFAEFC0
#define BOOTLOADER_IRAM_LOADER_SEG_START_EXPECTED 0x4FFADFC0
#else
#define BOOTLOADER_IRAM_LOADER_SEG_START_EXPECTED 0x4FF2CBD0
#define BOOTLOADER_IRAM_LOADER_SEG_START_EXPECTED 0x4FF2BBD0
#endif
ASSERT(bootloader_iram_loader_seg_start == BOOTLOADER_IRAM_LOADER_SEG_START_EXPECTED,
"bootloader_iram_loader_seg_start inconsistent with SRAM_DRAM_END");
+18 -6
View File
@@ -1,13 +1,14 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_rom_sys.h"
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
@@ -19,6 +20,10 @@ extern "C" {
* - Expands CONDITION multiple times (condition must have no side effects)
* - Compiler is told all registers are invalid before evaluating CONDITION each time, to avoid a fault
* causing a misread of a register used in all three evaluations of CONDITION.
* - The result of each evaluation is stored into a volatile variable and re-read before the branch.
* This prevents the compiler from constant-folding CONDITION and deleting the whole check when it
* has already proven the value - e.g. when this macro follows a normal "if (!cond) { ... }" check
* of the same value, which would otherwise silently remove the fault-injection protection.
* - If CONDITION is ever false, a system reset is triggered.
*
* @note Place this macro after a "normal" check of CONDITION that will fail with a normal error
@@ -41,12 +46,19 @@ extern "C" {
*
*/
#define ESP_FAULT_ASSERT(CONDITION) do { \
bool esp_fault_assert_chk; \
asm volatile ("" ::: "memory"); \
if(!(CONDITION)) _ESP_FAULT_RESET(); \
esp_fault_assert_chk = (CONDITION); \
asm volatile ("" : "+r"(esp_fault_assert_chk)); \
if(!esp_fault_assert_chk) _ESP_FAULT_RESET(); \
asm volatile ("" ::: "memory"); \
if(!(CONDITION)) _ESP_FAULT_RESET(); \
esp_fault_assert_chk = (CONDITION); \
asm volatile ("" : "+r"(esp_fault_assert_chk)); \
if(!esp_fault_assert_chk) _ESP_FAULT_RESET(); \
asm volatile ("" ::: "memory"); \
if(!(CONDITION)) _ESP_FAULT_RESET(); \
esp_fault_assert_chk = (CONDITION); \
asm volatile ("" : "+r"(esp_fault_assert_chk)); \
if(!esp_fault_assert_chk) _ESP_FAULT_RESET(); \
} while(0)
#if CONFIG_IDF_TARGET_ARCH_XTENSA
@@ -61,6 +61,11 @@ static inline void ecc_ll_power_up(void)
ESP_FAULT_ASSERT(REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0);
}
static inline bool ecc_ll_mem_force_pd_is_clear(void)
{
return REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0;
}
static inline void ecc_ll_power_down(void)
{
/* Power down the ECC peripheral */
@@ -56,6 +56,11 @@ static inline void ecc_ll_power_up(void)
ESP_FAULT_ASSERT(REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0);
}
static inline bool ecc_ll_mem_force_pd_is_clear(void)
{
return REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0;
}
static inline void ecc_ll_power_down(void)
{
/* Power down the ECC peripheral */
@@ -58,6 +58,11 @@ static inline void ecc_ll_power_up(void)
ESP_FAULT_ASSERT(REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0);
}
static inline bool ecc_ll_mem_force_pd_is_clear(void)
{
return REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0;
}
static inline void ecc_ll_power_down(void)
{
REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PU);
@@ -75,6 +75,11 @@ static inline void ecc_ll_power_up(void)
ESP_FAULT_ASSERT(REG_GET_BIT(HP_SYSTEM_ECC_PD_CTRL_REG, HP_SYSTEM_ECC_MEM_FORCE_PD) == 0);
}
static inline bool ecc_ll_mem_force_pd_is_clear(void)
{
return REG_GET_BIT(HP_SYSTEM_ECC_PD_CTRL_REG, HP_SYSTEM_ECC_MEM_FORCE_PD) == 0;
}
static inline void ecc_ll_power_down(void)
{
/* Power down the ECC peripheral */
+1 -1
View File
@@ -45,7 +45,7 @@ else()
endif()
endif()
list(APPEND private_required_comp soc hal esp_hal_uart)
list(APPEND private_required_comp soc hal esp_hal_uart esp_hal_security)
endif()
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
+1 -2
View File
@@ -413,8 +413,7 @@ esp_rom_km_huk_risk = 0x40000898;
ets_emsa_pss_verify = 0x4000089c;
ets_rsa_pss_verify = 0x400008a0;
_rom_ets_ecdsa_verify = 0x400008a4;
ets_secure_boot_verify_bootloader_with_keys = 0x400008a8;
ets_secure_boot_verify_signature = 0x400008ac;
_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;
@@ -371,8 +371,7 @@ ets_efuse_usb_device_disabled = 0x40000808;
/* Functions */
_rom_ets_ecdsa_verify = 0x40000810;
ets_secure_boot_verify_bootloader_with_keys = 0x40000814;
ets_secure_boot_verify_signature = 0x40000818;
_rom_ets_secure_boot_verify_signature = 0x40000818;
ets_secure_boot_read_key_digests = 0x4000081c;
ets_secure_boot_revoke_public_key_digest = 0x40000820;
+1 -2
View File
@@ -362,8 +362,7 @@ ets_efuse_secure_boot_fast_wake_enabled = 0x40000830;
ets_emsa_pss_verify = 0x40000834;
ets_rsa_pss_verify = 0x40000838;
_rom_ets_ecdsa_verify = 0x4000083c;
ets_secure_boot_verify_bootloader_with_keys = 0x40000840;
ets_secure_boot_verify_signature = 0x40000844;
_rom_ets_secure_boot_verify_signature = 0x40000844;
ets_secure_boot_read_key_digests = 0x40000848;
ets_secure_boot_revoke_public_key_digest = 0x4000084c;
@@ -79,10 +79,6 @@ config ESP_ROM_RAM_APP_NEEDS_MMU_INIT
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
@@ -25,5 +25,4 @@
#define ESP_ROM_USB_OTG_NUM (-1) // No USB_OTG CDC in the ROM, set -1 for Kconfig usage.
#define ESP_ROM_WDT_INIT_PATCH (1) // ROM version does not configure the clock
#define ESP_ROM_RAM_APP_NEEDS_MMU_INIT (1) // ROM doesn't init cache MMU when it's a RAM APP, needs MMU hal to init
#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
@@ -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;
+103
View File
@@ -6,12 +6,15 @@
#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.h"
#include "hal/ecc_ll.h"
#include "rom/ecdsa.h"
#define VALID_MAGIC_OK 0x6A6A6A6AU
@@ -69,6 +72,19 @@ static bool ecdsa_scalars_in_range(const uint32_t *r, const uint32_t *s, const u
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);
@@ -113,6 +129,9 @@ int ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig,
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) {
@@ -125,4 +144,88 @@ int ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig,
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 */
@@ -17,11 +17,11 @@
#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
#define SRAM_START 0x4FF00000 + CONFIG_CACHE_L2_CACHE_SIZE
#define SRAM_END 0x4FFAEFC0 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_END 0x4FFADFC0 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_SIZE SRAM_END - SRAM_START
#else
#define SRAM_LOW_START 0x4FF00000
#define SRAM_LOW_END 0x4FF2CBD0 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_LOW_END 0x4FF2BBD0 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_LOW_SIZE SRAM_LOW_END - SRAM_LOW_START
/* If the cache size is less than 512KB, then there is a region of RAM
@@ -0,0 +1,3 @@
# Increasing TEE IRAM size
# 38KB
CONFIG_SECURE_TEE_IRAM_SIZE=0x9800
@@ -2,8 +2,8 @@
# builds across various configurations - and is not intended for production use.
# Reducing TEE IRAM size
# 29KB
CONFIG_SECURE_TEE_IRAM_SIZE=0x7400
# 29.5KB
CONFIG_SECURE_TEE_IRAM_SIZE=0x7600
# TEE Secure Storage: Release mode
CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE=y
@@ -2,8 +2,8 @@
# builds across various configurations - and is not intended for production use.
# Increasing TEE I/DRAM sizes
# 34KB
CONFIG_SECURE_TEE_IRAM_SIZE=0x8800
# 38KB
CONFIG_SECURE_TEE_IRAM_SIZE=0x9800
# 22KB
CONFIG_SECURE_TEE_DRAM_SIZE=0x5800
@@ -16,3 +16,7 @@ CONFIG_SECURE_TEE_ATT_KEY_STR_ID="tee_att_keyN"
# Enabling flash protection over SPI1
CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1=y
# Increasing TEE IRAM size
# 38KB
CONFIG_SECURE_TEE_IRAM_SIZE=0x9800
@@ -1,5 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
factory, 0, 0, 0x10000, 1M
nvs, data, nvs, , 0x6000,
factory, 0, 0, , 1M
flash_test, data, fat, , 528K
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000, nvs, data, nvs, , 0x6000,
4 factory, 0, 0, 0x10000, 1M factory, 0, 0, , 1M
5 flash_test, data, fat, , 528K
@@ -1,4 +1,5 @@
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_PARTITION_TABLE_OFFSET=0X9000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_SECURE_FLASH_ENC_ENABLED=y
@@ -2,7 +2,7 @@
CONFIG_IDF_TARGET="esp32c5"
CONFIG_PARTITION_TABLE_OFFSET=0xE000
CONFIG_PARTITION_TABLE_OFFSET=0xF000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
@@ -2,7 +2,7 @@
CONFIG_IDF_TARGET="esp32c5"
CONFIG_PARTITION_TABLE_OFFSET=0xE000
CONFIG_PARTITION_TABLE_OFFSET=0xF000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
@@ -2,7 +2,7 @@
CONFIG_IDF_TARGET="esp32c5"
CONFIG_PARTITION_TABLE_OFFSET=0xD000
CONFIG_PARTITION_TABLE_OFFSET=0xE000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
@@ -2,7 +2,7 @@
CONFIG_IDF_TARGET="esp32p4"
CONFIG_PARTITION_TABLE_OFFSET=0xD000
CONFIG_PARTITION_TABLE_OFFSET=0XE000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"