From abcbe87e2dc71169e2c4aca1234cfcc7c79bf506 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 12 Jun 2026 17:07:33 +0530 Subject: [PATCH 1/6] fix(mbedtls): validate ECDSA signature range and harden ECC memory power-down Co-Authored-By: Ashish Sharma --- .../port/soc/esp32c6/system_internal.c | 2 ++ .../port/soc/esp32h2/system_internal.c | 1 + .../port/soc/esp32p4/system_internal.c | 1 + components/hal/esp32c6/include/hal/ecc_ll.h | 4 ++- components/hal/esp32h2/include/hal/ecc_ll.h | 4 ++- components/hal/esp32p4/include/hal/ecc_ll.h | 20 +++++++++++-- components/mbedtls/port/ecdsa/ecdsa_alt.c | 28 ++++++++++++++++--- 7 files changed, 51 insertions(+), 9 deletions(-) diff --git a/components/esp_system/port/soc/esp32c6/system_internal.c b/components/esp_system/port/soc/esp32c6/system_internal.c index 46e588f9042..a8fb73bce13 100644 --- a/components/esp_system/port/soc/esp32c6/system_internal.c +++ b/components/esp_system/port/soc/esp32c6/system_internal.c @@ -80,6 +80,8 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); CLEAR_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); CLEAR_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); + CLEAR_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // UART's sclk is controlled in the PCR register and does not reset with the UART module. The ROM missed enabling diff --git a/components/esp_system/port/soc/esp32h2/system_internal.c b/components/esp_system/port/soc/esp32h2/system_internal.c index e87ad824358..ffd47ac2144 100644 --- a/components/esp_system/port/soc/esp32h2/system_internal.c +++ b/components/esp_system/port/soc/esp32h2/system_internal.c @@ -79,6 +79,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); CLEAR_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); CLEAR_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); // UART's sclk is controlled in the PCR register and does not reset with the UART module. The ROM missed enabling // it when initializing the ROM UART. If it is not turned on, it will trigger LP_WDT in the ROM. diff --git a/components/esp_system/port/soc/esp32p4/system_internal.c b/components/esp_system/port/soc/esp32p4/system_internal.c index 898a104ba6c..3e68b4cc760 100644 --- a/components/esp_system/port/soc/esp32p4/system_internal.c +++ b/components/esp_system/port/soc/esp32p4/system_internal.c @@ -122,6 +122,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_KM); CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_RSA); CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_SHA); + CLEAR_PERI_REG_MASK(HP_SYSTEM_ECC_PD_CTRL_REG, HP_SYSTEM_ECC_MEM_FORCE_PD); #if CONFIG_ESP32P4_REV_MIN_FULL <= 100 // enable soc clk and reset parent crypto diff --git a/components/hal/esp32c6/include/hal/ecc_ll.h b/components/hal/esp32c6/include/hal/ecc_ll.h index d144dbff297..fc0861b3148 100644 --- a/components/hal/esp32c6/include/hal/ecc_ll.h +++ b/components/hal/esp32c6/include/hal/ecc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" #include "soc/pcr_reg.h" +#include "esp_fault.h" #ifdef __cplusplus extern "C" { @@ -46,6 +47,7 @@ static inline void ecc_ll_power_up(void) { REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); + ESP_FAULT_ASSERT(REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0); } static inline void ecc_ll_power_down(void) diff --git a/components/hal/esp32h2/include/hal/ecc_ll.h b/components/hal/esp32h2/include/hal/ecc_ll.h index c57200f6273..9db578ed305 100644 --- a/components/hal/esp32h2/include/hal/ecc_ll.h +++ b/components/hal/esp32h2/include/hal/ecc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" #include "soc/pcr_reg.h" +#include "esp_fault.h" #include "soc/chip_revision.h" #include "hal/efuse_hal.h" @@ -54,6 +55,7 @@ static inline void ecc_ll_power_up(void) { REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); + ESP_FAULT_ASSERT(REG_GET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD) == 0); } static inline void ecc_ll_power_down(void) diff --git a/components/hal/esp32p4/include/hal/ecc_ll.h b/components/hal/esp32p4/include/hal/ecc_ll.h index 05a7ed8fcd0..320424a22a0 100644 --- a/components/hal/esp32p4/include/hal/ecc_ll.h +++ b/components/hal/esp32p4/include/hal/ecc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,8 @@ #include "hal/ecc_types.h" #include "soc/ecc_mult_reg.h" #include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_system_reg.h" +#include "esp_fault.h" #ifdef __cplusplus extern "C" { @@ -56,8 +58,20 @@ static inline void ecc_ll_reset_register(void) /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define ecc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; ecc_ll_reset_register(__VA_ARGS__) -static inline void ecc_ll_power_up(void) {} -static inline void ecc_ll_power_down(void) {} +static inline void ecc_ll_power_up(void) +{ + /* Power up the ECC peripheral (default state is power-up) */ + REG_CLR_BIT(HP_SYSTEM_ECC_PD_CTRL_REG, HP_SYSTEM_ECC_MEM_PD); + REG_CLR_BIT(HP_SYSTEM_ECC_PD_CTRL_REG, HP_SYSTEM_ECC_MEM_FORCE_PD); + ESP_FAULT_ASSERT(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 */ + REG_CLR_BIT(HP_SYSTEM_ECC_PD_CTRL_REG, HP_SYSTEM_ECC_MEM_FORCE_PU); + REG_SET_BIT(HP_SYSTEM_ECC_PD_CTRL_REG, HP_SYSTEM_ECC_MEM_PD); +} static inline void ecc_ll_enable_interrupt(void) { diff --git a/components/mbedtls/port/ecdsa/ecdsa_alt.c b/components/mbedtls/port/ecdsa/ecdsa_alt.c index b6db8b0ae6d..58bee397fed 100644 --- a/components/mbedtls/port/ecdsa/ecdsa_alt.c +++ b/components/mbedtls/port/ecdsa/ecdsa_alt.c @@ -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 */ @@ -10,6 +10,15 @@ #ifdef SOC_MPI_SUPPORTED #include "hal/mpi_ll.h" #endif + +#include "esp_err.h" +#include "esp_log.h" +#include "esp_fault.h" + +#include "hal/ecdsa_types.h" +#include "ecdsa/ecdsa_alt.h" +#include "soc/soc_caps.h" + #include "esp_crypto_lock.h" #include "esp_efuse.h" #include "esp_private/esp_crypto_lock_internal.h" @@ -681,11 +690,22 @@ static int esp_ecdsa_verify(mbedtls_ecp_group *grp, return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } - if (mbedtls_mpi_cmp_int(r, 1) < 0 || mbedtls_mpi_cmp_mpi(r, &grp->N) >= 0 || - mbedtls_mpi_cmp_int(s, 1) < 0 || mbedtls_mpi_cmp_mpi(s, &grp->N) >= 0 ) - { + /* 1 <= scalar <= n-1: that is, scalar > 0 and scalar < n. */ + #define RANGE_OK 0x6A6A6A6AU + #define RANGE_FAIL 0x95959595U + volatile uint32_t verdict = RANGE_FAIL; + if (mbedtls_mpi_cmp_int(r, 0) > 0 && + mbedtls_mpi_cmp_mpi(r, &grp->N) < 0 && + mbedtls_mpi_cmp_int(s, 0) > 0 && + mbedtls_mpi_cmp_mpi(s, &grp->N) < 0) { + verdict = RANGE_OK; + } + if (verdict != RANGE_OK) { return MBEDTLS_ERR_ECP_VERIFY_FAILED; } + ESP_FAULT_ASSERT(verdict == RANGE_OK); + #undef RANGE_OK + #undef RANGE_FAIL ecdsa_be_to_le(buf, sha_le, len); From d9a3c1f866c18b9a03c13d0c0abe96243d7fb7bf Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 12 Jun 2026 17:45:55 +0530 Subject: [PATCH 2/6] fix(esp_rom): Patch ets_ecdsa_verify() to include signature bounds check --- components/esp_rom/CMakeLists.txt | 4 + .../esp_rom/esp32h2/Kconfig.soc_caps.in | 4 + components/esp_rom/esp32h2/esp_rom_caps.h | 1 + components/esp_rom/esp32h2/ld/esp32h2.rom.ld | 2 +- .../esp_rom/esp32p4/Kconfig.soc_caps.in | 4 + components/esp_rom/esp32p4/esp_rom_caps.h | 1 + .../esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld | 2 +- components/esp_rom/esp32p4/ld/esp32p4.rom.ld | 2 +- components/esp_rom/patches/esp_rom_ecdsa.c | 128 ++++++++++++++++++ 9 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 components/esp_rom/patches/esp_rom_ecdsa.c diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 3ff4b62d438..bd46c01725e 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -83,6 +83,10 @@ if(CONFIG_ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_MAP) list(APPEND sources "patches/esp_rom_cache_writeback_esp32p4.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} diff --git a/components/esp_rom/esp32h2/Kconfig.soc_caps.in b/components/esp_rom/esp32h2/Kconfig.soc_caps.in index d0156a4cfc7..58f145b8f1a 100644 --- a/components/esp_rom/esp32h2/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32h2/Kconfig.soc_caps.in @@ -110,3 +110,7 @@ config ESP_ROM_NO_USB_SERIAL_OUTPUT_API config ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP bool default y + +config ESP_ROM_ECDSA_VERIFY_PATCH + bool + default y diff --git a/components/esp_rom/esp32h2/esp_rom_caps.h b/components/esp_rom/esp32h2/esp_rom_caps.h index a823cb1d2c2..819bbd2de53 100644 --- a/components/esp_rom/esp32h2/esp_rom_caps.h +++ b/components/esp_rom/esp32h2/esp_rom_caps.h @@ -33,3 +33,4 @@ #define ESP_ROM_HAS_OUTPUT_PUTC_FUNC (1) // ROM has esp_rom_output_putc (or ets_write_char_uart) #define ESP_ROM_NO_USB_SERIAL_OUTPUT_API (1) // ROM does not export the usb-serial-jtag write char function #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 diff --git a/components/esp_rom/esp32h2/ld/esp32h2.rom.ld b/components/esp_rom/esp32h2/ld/esp32h2.rom.ld index b7b8775614e..bdd35767165 100644 --- a/components/esp_rom/esp32h2/ld/esp32h2.rom.ld +++ b/components/esp_rom/esp32h2/ld/esp32h2.rom.ld @@ -361,7 +361,7 @@ ets_efuse_secure_boot_fast_wake_enabled = 0x40000830; /* Functions */ ets_emsa_pss_verify = 0x40000834; ets_rsa_pss_verify = 0x40000838; -ets_ecdsa_verify = 0x4000083c; +_rom_ets_ecdsa_verify = 0x4000083c; ets_secure_boot_verify_bootloader_with_keys = 0x40000840; ets_secure_boot_verify_signature = 0x40000844; ets_secure_boot_read_key_digests = 0x40000848; diff --git a/components/esp_rom/esp32p4/Kconfig.soc_caps.in b/components/esp_rom/esp32p4/Kconfig.soc_caps.in index 465fa704af4..28d3fcd3ad7 100644 --- a/components/esp_rom/esp32p4/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32p4/Kconfig.soc_caps.in @@ -83,6 +83,10 @@ config ESP_ROM_HAS_OUTPUT_PUTC_FUNC bool default y +config ESP_ROM_ECDSA_VERIFY_PATCH + bool + default y + config ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_MAP bool default y diff --git a/components/esp_rom/esp32p4/esp_rom_caps.h b/components/esp_rom/esp32p4/esp_rom_caps.h index 43cefe53ac4..bc7aca390c7 100644 --- a/components/esp_rom/esp32p4/esp_rom_caps.h +++ b/components/esp_rom/esp32p4/esp_rom_caps.h @@ -26,4 +26,5 @@ #define ESP_ROM_HAS_VERSION (1) // ROM has version/eco information #define ESP_ROM_CLIC_INT_TYPE_PATCH (1) // ROM api esprv_intc_int_set_type configuring edge type interrupt is invalid TODO: IDF-13409 #define ESP_ROM_HAS_OUTPUT_PUTC_FUNC (1) // ROM has esp_rom_output_putc (or ets_write_char_uart) +#define ESP_ROM_ECDSA_VERIFY_PATCH (1) // ROM ets_ecdsa_verify API requires a software patch #define ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_MAP (1) // ROM cache writeback related needs patch to avoid sync loss, need map parameter diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld index f1aae1cc64a..2627fc5db58 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld @@ -470,7 +470,7 @@ esp_rom_km_huk_risk = 0x4fc00710; /* Functions */ ets_emsa_pss_verify = 0x4fc00714; ets_rsa_pss_verify = 0x4fc00718; -ets_ecdsa_verify = 0x4fc0071c; +_rom_ets_ecdsa_verify = 0x4fc0071c; ets_secure_boot_verify_bootloader_with_keys = 0x4fc00720; ets_secure_boot_verify_signature = 0x4fc00724; ets_secure_boot_read_key_digests = 0x4fc00728; diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.ld index 0a35cde1b5e..7e03c5cd2e8 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.ld @@ -450,7 +450,7 @@ esp_rom_km_huk_risk = 0x4fc0071c; /* Functions */ ets_emsa_pss_verify = 0x4fc00720; ets_rsa_pss_verify = 0x4fc00724; -ets_ecdsa_verify = 0x4fc00728; +_rom_ets_ecdsa_verify = 0x4fc00728; ets_secure_boot_verify_bootloader_with_keys = 0x4fc0072c; ets_secure_boot_verify_signature = 0x4fc00730; ets_secure_boot_read_key_digests = 0x4fc00734; diff --git a/components/esp_rom/patches/esp_rom_ecdsa.c b/components/esp_rom/patches/esp_rom_ecdsa.c new file mode 100644 index 00000000000..0667fadca61 --- /dev/null +++ b/components/esp_rom/patches/esp_rom_ecdsa.c @@ -0,0 +1,128 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_rom_caps.h" +#if ESP_ROM_ECDSA_VERIFY_PATCH +#include "soc/soc_caps.h" +#include "esp_fault.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; +} + +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); + + 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; +} +#endif /* ESP_ROM_ECDSA_VERIFY_PATCH */ From 551fad393d3643611fdbc23830839460fdd5d5d7 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Tue, 9 Jun 2026 15:43:45 +0530 Subject: [PATCH 3/6] test(mbedtls): Add out-of-bounds test for the ECDSA hardware driver --- .../main/key_manager/test_key_manager.c | 4 +- .../test_apps/main/test_mbedtls_ecdsa.c | 41 +++++++++++++++---- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/components/hal/test_apps/crypto/main/key_manager/test_key_manager.c b/components/hal/test_apps/crypto/main/key_manager/test_key_manager.c index 2def4096e8f..6c196f92a05 100644 --- a/components/hal/test_apps/crypto/main/key_manager/test_key_manager.c +++ b/components/hal/test_apps/crypto/main/key_manager/test_key_manager.c @@ -140,7 +140,7 @@ void test_ecdsa_key_aes_mode(test_data_aes_mode_t *ecdsa_test_data, ecdsa_sign_t extern void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type); -extern int test_ecdsa_verify(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y); +extern int test_ecdsa_verify(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y, int expected_ret); void key_mgr_test_ecdsa_key(bool is_p256, ecdsa_sign_type_t k_type) { @@ -161,7 +161,7 @@ void key_mgr_test_ecdsa_key(bool is_p256, ecdsa_sign_type_t k_type) print_data_in_hex(pub_x, pubkey_len, "ECDSA key pubx"); print_data_in_hex(pub_y, pubkey_len, "ECDSA key puby"); - TEST_ASSERT_EQUAL(0, test_ecdsa_verify(is_p256, sha256_digest, r_le, s_le, pub_x, pub_y)); + TEST_ASSERT_EQUAL(0, test_ecdsa_verify(is_p256, sha256_digest, r_le, s_le, pub_x, pub_y, 0)); } diff --git a/components/mbedtls/test_apps/main/test_mbedtls_ecdsa.c b/components/mbedtls/test_apps/main/test_mbedtls_ecdsa.c index 2a4366b7208..309a54a62e2 100644 --- a/components/mbedtls/test_apps/main/test_mbedtls_ecdsa.c +++ b/components/mbedtls/test_apps/main/test_mbedtls_ecdsa.c @@ -1,6 +1,6 @@ /* mbedTLS Elliptic Curve Digital Signature performance tests * - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "soc/soc_caps.h" #include "test_utils.h" @@ -108,8 +110,18 @@ const uint8_t ecdsa192_pub_y[] = { 0x7e, 0x4b, 0x23, 0xad, 0x46, 0x5c, 0x87, 0xc2 }; +/* Curve order N in big-endian, taken from mbedtls instead of a hard-coded table. */ +static void ecdsa_get_curve_order_be(mbedtls_ecp_group_id id, uint8_t *n_be, size_t len) +{ + mbedtls_ecp_group grp; + mbedtls_ecp_group_init(&grp); + TEST_ASSERT_EQUAL(0, mbedtls_ecp_group_load(&grp, id)); + TEST_ASSERT_EQUAL(0, mbedtls_mpi_write_binary(&grp.N, n_be, len)); + mbedtls_ecp_group_free(&grp); +} + void test_ecdsa_verify(mbedtls_ecp_group_id id, const uint8_t *hash, const uint8_t *r_comp, const uint8_t *s_comp, - const uint8_t *pub_x, const uint8_t *pub_y) + const uint8_t *pub_x, const uint8_t *pub_y, int expected_ret) { int64_t elapsed_time; mbedtls_mpi r, s; @@ -132,7 +144,8 @@ void test_ecdsa_verify(mbedtls_ecp_group_id id, const uint8_t *hash, const uint8 TEST_ASSERT_MBEDTLS_OK(mbedtls_mpi_lset(&ecdsa_context.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1)); ccomp_timer_start(); - TEST_ASSERT_MBEDTLS_OK(mbedtls_ecdsa_verify(&ecdsa_context.MBEDTLS_PRIVATE(grp), hash, 32, &ecdsa_context.MBEDTLS_PRIVATE(Q), &r, &s)); + int actual_ret = mbedtls_ecdsa_verify(&ecdsa_context.MBEDTLS_PRIVATE(grp), hash, 32, &ecdsa_context.MBEDTLS_PRIVATE(Q), &r, &s); + TEST_ASSERT_EQUAL(expected_ret, actual_ret); elapsed_time = ccomp_timer_stop(); if (id == MBEDTLS_ECP_DP_SECP192R1) { @@ -149,15 +162,29 @@ void test_ecdsa_verify(mbedtls_ecp_group_id id, const uint8_t *hash, const uint8 TEST_CASE("mbedtls ECDSA signature verification performance on SECP192R1", "[mbedtls]") { test_ecdsa_verify(MBEDTLS_ECP_DP_SECP192R1, sha, ecdsa192_r, ecdsa192_s, - ecdsa192_pub_x, ecdsa192_pub_y); + ecdsa192_pub_x, ecdsa192_pub_y, 0); } TEST_CASE("mbedtls ECDSA signature verification performance on SECP256R1", "[mbedtls]") { test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, ecdsa256_r, ecdsa256_s, - ecdsa256_pub_x, ecdsa256_pub_y); + ecdsa256_pub_x, ecdsa256_pub_y, 0); } +TEST_CASE("mbedtls ECDSA signature verification rejects out-of-range r, s on SECP256R1", "[mbedtls]") +{ + static const uint8_t zero32[32] = { 0 }; + uint8_t p256_n_be[32]; + ecdsa_get_curve_order_be(MBEDTLS_ECP_DP_SECP256R1, p256_n_be, sizeof(p256_n_be)); + + test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, zero32, zero32, ecdsa256_pub_x, ecdsa256_pub_y, MBEDTLS_ERR_ECP_VERIFY_FAILED); /* r=0, s=0 */ + test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, zero32, p256_n_be, ecdsa256_pub_x, ecdsa256_pub_y, MBEDTLS_ERR_ECP_VERIFY_FAILED); /* r=0, s=N */ + test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, p256_n_be, zero32, ecdsa256_pub_x, ecdsa256_pub_y, MBEDTLS_ERR_ECP_VERIFY_FAILED); /* r=N, s=0 */ + test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, p256_n_be, p256_n_be, ecdsa256_pub_x, ecdsa256_pub_y, MBEDTLS_ERR_ECP_VERIFY_FAILED); /* r=N, s=N */ + test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, ecdsa256_r, zero32, ecdsa256_pub_x, ecdsa256_pub_y, MBEDTLS_ERR_ECP_VERIFY_FAILED); /* r=valid, s=0 */ + test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, ecdsa256_r, p256_n_be, ecdsa256_pub_x, ecdsa256_pub_y, MBEDTLS_ERR_ECP_VERIFY_FAILED); /* r=valid, s=N */ + test_ecdsa_verify(MBEDTLS_ECP_DP_SECP256R1, sha, p256_n_be, ecdsa256_s, ecdsa256_pub_x, ecdsa256_pub_y, MBEDTLS_ERR_ECP_VERIFY_FAILED); /* r=N, s=valid */ +} #endif /* CONFIG_MBEDTLS_HARDWARE_ECC */ #if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN @@ -250,9 +277,9 @@ void test_ecdsa_sign(mbedtls_ecp_group_id id, const uint8_t *hash, const uint8_t if (id == MBEDTLS_ECP_DP_SECP192R1) { // Skip the initial zeroes - test_ecdsa_verify(id, sha, &r_be[8], &s_be[8], pub_x, pub_y); + test_ecdsa_verify(id, sha, &r_be[8], &s_be[8], pub_x, pub_y, 0); } else if (id == MBEDTLS_ECP_DP_SECP256R1) { - test_ecdsa_verify(id, sha, r_be, s_be, pub_x, pub_y); + test_ecdsa_verify(id, sha, r_be, s_be, pub_x, pub_y, 0); } mbedtls_mpi_free(&r); From ad8d86f725d894ba0af07158dd398d5c12a50a22 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 12 Jun 2026 13:54:10 +0530 Subject: [PATCH 4/6] fix(esp_common): Add esp_fault_internal.h for use by G0 components In release/v5.x, esp_fault.h resides in the esp_hw_support (G1) component, so the G0 components (hal, esp_rom) must not depend on it. Copy its contents to esp_common as esp_fault_internal.h, keep esp_fault.h as a compatibility wrapper around it, and switch the hal and esp_rom ECDSA/ECC code to the internal header. --- .../esp_common/include/esp_fault_internal.h | 94 +++++++++++++++++++ components/esp_hw_support/include/esp_fault.h | 90 +----------------- components/esp_rom/patches/esp_rom_ecdsa.c | 2 +- components/hal/ecdsa_hal.c | 2 +- components/hal/esp32c6/include/hal/ecc_ll.h | 2 +- components/hal/esp32h2/include/hal/ecc_ll.h | 2 +- components/hal/esp32p4/include/hal/ecc_ll.h | 2 +- 7 files changed, 101 insertions(+), 93 deletions(-) create mode 100644 components/esp_common/include/esp_fault_internal.h diff --git a/components/esp_common/include/esp_fault_internal.h b/components/esp_common/include/esp_fault_internal.h new file mode 100644 index 00000000000..871f2e8e773 --- /dev/null +++ b/components/esp_common/include/esp_fault_internal.h @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include "esp_rom_sys.h" + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Assert a condition is true, in a way that should be resistant to fault injection for + * single fault attacks. + * + * - 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. + * - 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 + * message. This is the fallback in case a fault injection attack skips or corrupts the result of + * that check. (Although ensure that an attacker can't use fault injection to skip past the "normal" + * error message, to avoid this check entirely.) + * + * @note This macro increases binary size and is slow and should be used sparingly. + * + * @note This macro does not guarantee fault injection resistance. In particular CONDITION must be + * chosen carefully - a fault injection attack which sets CONDITION to true will not be detected by + * this macro. Care must also be taken that an attacker can't use a fault to completely bypass calling + * whatever function tests ESP_FAULT_ASSERT. + * + * @note This is difficult to debug as a failure triggers an instant software reset, and UART output + * is often truncated (as FIFO is not flushed). Define the ESP_FAULT_ASSERT_DEBUG macro to debug any + * failures of this macro due to software bugs. + * + * @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system calculation. + * + */ +#define ESP_FAULT_ASSERT(CONDITION) do { \ + asm volatile ("" ::: "memory"); \ + if(!(CONDITION)) _ESP_FAULT_RESET(); \ + asm volatile ("" ::: "memory"); \ + if(!(CONDITION)) _ESP_FAULT_RESET(); \ + asm volatile ("" ::: "memory"); \ + if(!(CONDITION)) _ESP_FAULT_RESET(); \ +} while(0) + +#if CONFIG_IDF_TARGET_ARCH_XTENSA +#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("ill.n; ill.n; ill.n; ill.n; ill.n; ill.n; ill.n;") +#elif CONFIG_IDF_TARGET_ARCH_RISCV +#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("unimp; unimp; unimp; unimp; unimp;") +#elif CONFIG_IDF_TARGET_LINUX +#define _ESP_FAULT_ILLEGAL_INSTRUCTION +#else +#error "_ESP_FAULT_ILLEGAL_INSTRUCTION is not defined for this TARGET" +#endif + +// Uncomment this macro to get debug output if ESP_FAULT_ASSERT() fails +// +// Note that uncommenting this macro reduces the anti-FI effectiveness +// +//#define ESP_FAULT_ASSERT_DEBUG + +/* Internal macro, purpose is to trigger a system reset if an inconsistency due to fault injection + is detected. + + Illegal instruction opcodes are there as a fallback to crash the CPU in case it doesn't + reset as expected. +*/ +#ifndef ESP_FAULT_ASSERT_DEBUG + +#define _ESP_FAULT_RESET() do { \ + esp_rom_software_reset_system(); \ + _ESP_FAULT_ILLEGAL_INSTRUCTION; \ + } while(0) + +#else // ESP_FAULT_ASSERT_DEBUG + +#warning "Enabling ESP_FAULT_ASSERT_DEBUG makes ESP_FAULT_ASSERT() less effective" + +#define _ESP_FAULT_RESET() do { \ + esp_rom_printf("ESP_FAULT_ASSERT %s:%d\n", __FILE__, __LINE__); \ + _ESP_FAULT_ILLEGAL_INSTRUCTION; \ + } while(0) + +#endif // ESP_FAULT_ASSERT_DEBUG + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/esp_fault.h b/components/esp_hw_support/include/esp_fault.h index 81c47741aa5..d8ec9c8e1ed 100644 --- a/components/esp_hw_support/include/esp_fault.h +++ b/components/esp_hw_support/include/esp_fault.h @@ -1,94 +1,8 @@ /* - * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "sdkconfig.h" -#include "esp_rom_sys.h" - #pragma once -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Assert a condition is true, in a way that should be resistant to fault injection for - * single fault attacks. - * - * - 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. - * - 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 - * message. This is the fallback in case a fault injection attack skips or corrupts the result of - * that check. (Although ensure that an attacker can't use fault injection to skip past the "normal" - * error message, to avoid this check entirely.) - * - * @note This macro increases binary size and is slow and should be used sparingly. - * - * @note This macro does not guarantee fault injection resistance. In particular CONDITION must be - * chosen carefully - a fault injection attack which sets CONDITION to true will not be detected by - * this macro. Care must also be taken that an attacker can't use a fault to completely bypass calling - * whatever function tests ESP_FAULT_ASSERT. - * - * @note This is difficult to debug as a failure triggers an instant software reset, and UART output - * is often truncated (as FIFO is not flushed). Define the ESP_FAULT_ASSERT_DEBUG macro to debug any - * failures of this macro due to software bugs. - * - * @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system calculation. - * - */ -#define ESP_FAULT_ASSERT(CONDITION) do { \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ -} while(0) - -#if CONFIG_IDF_TARGET_ARCH_XTENSA -#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("ill.n; ill.n; ill.n; ill.n; ill.n; ill.n; ill.n;") -#elif CONFIG_IDF_TARGET_ARCH_RISCV -#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("unimp; unimp; unimp; unimp; unimp;") -#elif CONFIG_IDF_TARGET_LINUX -#define _ESP_FAULT_ILLEGAL_INSTRUCTION -#else -#error "_ESP_FAULT_ILLEGAL_INSTRUCTION is not defined for this TARGET" -#endif - -// Uncomment this macro to get debug output if ESP_FAULT_ASSERT() fails -// -// Note that uncommenting this macro reduces the anti-FI effectiveness -// -//#define ESP_FAULT_ASSERT_DEBUG - -/* Internal macro, purpose is to trigger a system reset if an inconsistency due to fault injection - is detected. - - Illegal instruction opcodes are there as a fallback to crash the CPU in case it doesn't - reset as expected. -*/ -#ifndef ESP_FAULT_ASSERT_DEBUG - -#define _ESP_FAULT_RESET() do { \ - esp_rom_software_reset_system(); \ - _ESP_FAULT_ILLEGAL_INSTRUCTION; \ - } while(0) - -#else // ESP_FAULT_ASSERT_DEBUG - -#warning "Enabling ESP_FAULT_ASSERT_DEBUG makes ESP_FAULT_ASSERT() less effective" - -#define _ESP_FAULT_RESET() do { \ - esp_rom_printf("ESP_FAULT_ASSERT %s:%d\n", __FILE__, __LINE__); \ - _ESP_FAULT_ILLEGAL_INSTRUCTION; \ - } while(0) - -#endif // ESP_FAULT_ASSERT_DEBUG - -#ifdef __cplusplus -} -#endif +#include "esp_fault_internal.h" diff --git a/components/esp_rom/patches/esp_rom_ecdsa.c b/components/esp_rom/patches/esp_rom_ecdsa.c index 0667fadca61..ae409a24f7e 100644 --- a/components/esp_rom/patches/esp_rom_ecdsa.c +++ b/components/esp_rom/patches/esp_rom_ecdsa.c @@ -11,7 +11,7 @@ #include "esp_rom_caps.h" #if ESP_ROM_ECDSA_VERIFY_PATCH #include "soc/soc_caps.h" -#include "esp_fault.h" +#include "esp_fault_internal.h" #include "rom/ecdsa.h" #define VALID_MAGIC_OK 0x6A6A6A6AU diff --git a/components/hal/ecdsa_hal.c b/components/hal/ecdsa_hal.c index 8f5d463a26c..78b7ad0ea0c 100644 --- a/components/hal/ecdsa_hal.c +++ b/components/hal/ecdsa_hal.c @@ -10,7 +10,7 @@ #include "hal/efuse_hal.h" #if CONFIG_HAL_ECDSA_GEN_SIG_CM -#include "esp_fault.h" +#include "esp_fault_internal.h" #include "esp_random.h" #include "soc/chip_revision.h" #endif diff --git a/components/hal/esp32c6/include/hal/ecc_ll.h b/components/hal/esp32c6/include/hal/ecc_ll.h index fc0861b3148..a51b99b26ac 100644 --- a/components/hal/esp32c6/include/hal/ecc_ll.h +++ b/components/hal/esp32c6/include/hal/ecc_ll.h @@ -12,7 +12,7 @@ #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" #include "soc/pcr_reg.h" -#include "esp_fault.h" +#include "esp_fault_internal.h" #ifdef __cplusplus extern "C" { diff --git a/components/hal/esp32h2/include/hal/ecc_ll.h b/components/hal/esp32h2/include/hal/ecc_ll.h index 9db578ed305..2f73bb26f1e 100644 --- a/components/hal/esp32h2/include/hal/ecc_ll.h +++ b/components/hal/esp32h2/include/hal/ecc_ll.h @@ -12,7 +12,7 @@ #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" #include "soc/pcr_reg.h" -#include "esp_fault.h" +#include "esp_fault_internal.h" #include "soc/chip_revision.h" #include "hal/efuse_hal.h" diff --git a/components/hal/esp32p4/include/hal/ecc_ll.h b/components/hal/esp32p4/include/hal/ecc_ll.h index 320424a22a0..c4da4afe42f 100644 --- a/components/hal/esp32p4/include/hal/ecc_ll.h +++ b/components/hal/esp32p4/include/hal/ecc_ll.h @@ -12,7 +12,7 @@ #include "soc/ecc_mult_reg.h" #include "soc/hp_sys_clkrst_struct.h" #include "soc/hp_system_reg.h" -#include "esp_fault.h" +#include "esp_fault_internal.h" #ifdef __cplusplus extern "C" { From 8110949d88ece9183f474d6e860cad8400741381 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 12 Jun 2026 17:51:31 +0530 Subject: [PATCH 5/6] fix(secure_boot): range-check ECDSA r,s in bootloader before ROM verify --- components/esp_rom/esp32h2/ld/esp32h2.rom.ld | 3 +- .../esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld | 3 +- components/esp_rom/esp32p4/ld/esp32p4.rom.ld | 3 +- components/esp_rom/patches/esp_rom_ecdsa.c | 103 ++++++++++++++++++ components/hal/esp32h2/include/hal/ecc_ll.h | 5 + components/hal/esp32p4/include/hal/ecc_ll.h | 5 + .../sdkconfig.ci.virt_sb_v2_and_fe.esp32c5 | 2 +- 7 files changed, 117 insertions(+), 7 deletions(-) diff --git a/components/esp_rom/esp32h2/ld/esp32h2.rom.ld b/components/esp_rom/esp32h2/ld/esp32h2.rom.ld index bdd35767165..c51219fa8e0 100644 --- a/components/esp_rom/esp32h2/ld/esp32h2.rom.ld +++ b/components/esp_rom/esp32h2/ld/esp32h2.rom.ld @@ -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; diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld index 2627fc5db58..aa5f3c58b13 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.eco5.ld @@ -471,8 +471,7 @@ esp_rom_km_huk_risk = 0x4fc00710; ets_emsa_pss_verify = 0x4fc00714; ets_rsa_pss_verify = 0x4fc00718; _rom_ets_ecdsa_verify = 0x4fc0071c; -ets_secure_boot_verify_bootloader_with_keys = 0x4fc00720; -ets_secure_boot_verify_signature = 0x4fc00724; +_rom_ets_secure_boot_verify_signature = 0x4fc00724; ets_secure_boot_read_key_digests = 0x4fc00728; ets_secure_boot_revoke_public_key_digest = 0x4fc0072c; diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.ld index 7e03c5cd2e8..9c6f065d0cd 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.ld @@ -451,8 +451,7 @@ esp_rom_km_huk_risk = 0x4fc0071c; ets_emsa_pss_verify = 0x4fc00720; ets_rsa_pss_verify = 0x4fc00724; _rom_ets_ecdsa_verify = 0x4fc00728; -ets_secure_boot_verify_bootloader_with_keys = 0x4fc0072c; -ets_secure_boot_verify_signature = 0x4fc00730; +_rom_ets_secure_boot_verify_signature = 0x4fc00730; ets_secure_boot_read_key_digests = 0x4fc00734; ets_secure_boot_revoke_public_key_digest = 0x4fc00738; diff --git a/components/esp_rom/patches/esp_rom_ecdsa.c b/components/esp_rom/patches/esp_rom_ecdsa.c index ae409a24f7e..834500531bb 100644 --- a/components/esp_rom/patches/esp_rom_ecdsa.c +++ b/components/esp_rom/patches/esp_rom_ecdsa.c @@ -6,12 +6,15 @@ #include #include +#include #include +#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 @@ -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 */ diff --git a/components/hal/esp32h2/include/hal/ecc_ll.h b/components/hal/esp32h2/include/hal/ecc_ll.h index 2f73bb26f1e..8189929ed49 100644 --- a/components/hal/esp32h2/include/hal/ecc_ll.h +++ b/components/hal/esp32h2/include/hal/ecc_ll.h @@ -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); diff --git a/components/hal/esp32p4/include/hal/ecc_ll.h b/components/hal/esp32p4/include/hal/ecc_ll.h index c4da4afe42f..e8aa4fea8d9 100644 --- a/components/hal/esp32p4/include/hal/ecc_ll.h +++ b/components/hal/esp32p4/include/hal/ecc_ll.h @@ -66,6 +66,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 */ diff --git a/examples/system/efuse/sdkconfig.ci.virt_sb_v2_and_fe.esp32c5 b/examples/system/efuse/sdkconfig.ci.virt_sb_v2_and_fe.esp32c5 index 9b3f48228f9..08c00f84374 100644 --- a/examples/system/efuse/sdkconfig.ci.virt_sb_v2_and_fe.esp32c5 +++ b/examples/system/efuse/sdkconfig.ci.virt_sb_v2_and_fe.esp32c5 @@ -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" From 4e4cb4123fb156b7ce83f4e471eea557046aaac8 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Sun, 14 Jun 2026 17:05:24 +0530 Subject: [PATCH 6/6] fix(esp_common/esp_fault): make ESP_FAULT_ASSERT survive optimization ESP_FAULT_ASSERT(C) was silently deleted by the optimizer when C is a cached flag/status already proven by a preceding `if (!C) return/goto`: the compiler folds C to a constant and drops all three checks, removing the fault-injection protection with no warning. --- .../esp_common/include/esp_fault_internal.h | 30 +++++--- .../test_apps/.build-test-rules.yml | 7 ++ .../fault_assert_opt_check/CMakeLists.txt | 19 +++++ .../fault_assert_opt_check/README.md | 2 + .../check_fault_asserts.py | 75 +++++++++++++++++++ .../main/CMakeLists.txt | 2 + .../main/test_fault_assert.c | 58 ++++++++++++++ .../sdkconfig.ci.opt_perf | 2 + .../sdkconfig.ci.opt_size | 2 + .../fault_assert_opt_check/sdkconfig.defaults | 4 + .../test_apps/flash_encryption/partitions.csv | 4 +- .../flash_encryption/sdkconfig.defaults | 1 + .../sdkconfig.ci.virt_secure_boot_v2.esp32c5 | 2 +- .../sdkconfig.ci.virt_secure_boot_v2.esp32p4 | 2 +- 14 files changed, 197 insertions(+), 13 deletions(-) create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/CMakeLists.txt create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/README.md create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/check_fault_asserts.py create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/main/CMakeLists.txt create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/main/test_fault_assert.c create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_perf create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_size create mode 100644 components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.defaults diff --git a/components/esp_common/include/esp_fault_internal.h b/components/esp_common/include/esp_fault_internal.h index 871f2e8e773..0a67e08d885 100644 --- a/components/esp_common/include/esp_fault_internal.h +++ b/components/esp_common/include/esp_fault_internal.h @@ -3,11 +3,12 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#pragma once + +#include #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 @@ -40,13 +45,20 @@ extern "C" { * @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system calculation. * */ -#define ESP_FAULT_ASSERT(CONDITION) do { \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ +#define ESP_FAULT_ASSERT(CONDITION) do { \ + bool esp_fault_assert_chk; \ + asm volatile ("" ::: "memory"); \ + esp_fault_assert_chk = (CONDITION); \ + asm volatile ("" : "+r"(esp_fault_assert_chk)); \ + if(!esp_fault_assert_chk) _ESP_FAULT_RESET(); \ + asm volatile ("" ::: "memory"); \ + esp_fault_assert_chk = (CONDITION); \ + asm volatile ("" : "+r"(esp_fault_assert_chk)); \ + if(!esp_fault_assert_chk) _ESP_FAULT_RESET(); \ + asm volatile ("" ::: "memory"); \ + 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 diff --git a/components/esp_security/test_apps/.build-test-rules.yml b/components/esp_security/test_apps/.build-test-rules.yml index 6802faf7539..801962d89dc 100644 --- a/components/esp_security/test_apps/.build-test-rules.yml +++ b/components/esp_security/test_apps/.build-test-rules.yml @@ -5,3 +5,10 @@ components/esp_security/test_apps/crypto_drivers: - if: ((SOC_HMAC_SUPPORTED == 1) or (SOC_DIG_SIGN_SUPPORTED == 1)) or (SOC_KEY_MANAGER_SUPPORTED == 1) depends_components: - esp_security + - esp_hal_security + +components/esp_security/test_apps/fault_assert_opt_check: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3"] # one Xtensa + one RISC-V + depends_components: + - esp_common diff --git a/components/esp_security/test_apps/fault_assert_opt_check/CMakeLists.txt b/components/esp_security/test_apps/fault_assert_opt_check/CMakeLists.txt new file mode 100644 index 00000000000..853b87d4eaf --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/CMakeLists.txt @@ -0,0 +1,19 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + +project(fault_assert_opt_check) + +# Regression guard: fail the build if ESP_FAULT_ASSERT() gets optimized away. +idf_build_get_property(python PYTHON) +add_custom_command( + TARGET ${CMAKE_PROJECT_NAME}.elf POST_BUILD + COMMAND ${python} "${CMAKE_CURRENT_SOURCE_DIR}/check_fault_asserts.py" + "$" "${CMAKE_OBJDUMP}" + COMMENT "Verifying ESP_FAULT_ASSERT() survived optimization" + VERBATIM) diff --git a/components/esp_security/test_apps/fault_assert_opt_check/README.md b/components/esp_security/test_apps/fault_assert_opt_check/README.md new file mode 100644 index 00000000000..1fb88efd154 --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C3 | +| ----------------- | ----- | -------- | diff --git a/components/esp_security/test_apps/fault_assert_opt_check/check_fault_asserts.py b/components/esp_security/test_apps/fault_assert_opt_check/check_fault_asserts.py new file mode 100644 index 00000000000..5d5994c33cf --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/check_fault_asserts.py @@ -0,0 +1,75 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +"""Post-build regression guard for ESP_FAULT_ASSERT(). + +Disassembles the test app and verifies that the ESP_FAULT_ASSERT() calls in the +known test functions still emit their reset blocks. One intact assert produces +three independent reset-on-failure paths, i.e. three references to +``esp_rom_software_reset_system`` in the function. If the macro ever regresses +and the optimizer folds the checks away, the count drops and this exits non-zero, +failing the build. + +Usage: check_fault_asserts.py +""" +import re +import subprocess +import sys + +RESET_SYM = 'esp_rom_software_reset_system' + +# function name -> number of ESP_FAULT_ASSERT calls it contains (x3 reset blocks each) +EXPECTED = { + 'test_fa_guarded_flag': 1, + 'test_fa_guarded_status': 1, +} + +FUNC_RE = re.compile(r'^[0-9a-fA-F]+ <(.+)>:$') + + +def reset_counts(elf: str, objdump: str) -> dict: + dis = subprocess.run([objdump, '-d', elf], capture_output=True, text=True, check=True).stdout + counts: dict = {} + cur = None + for line in dis.splitlines(): + m = FUNC_RE.match(line) + if m: + cur = m.group(1) + counts.setdefault(cur, 0) + elif cur and RESET_SYM in line: + counts[cur] += 1 + return counts + + +def main() -> int: + if len(sys.argv) != 3: + print(__doc__) + return 2 + elf, objdump = sys.argv[1], sys.argv[2] + counts = reset_counts(elf, objdump) + + failed = False + for fn, n_asserts in EXPECTED.items(): + expected = 3 * n_asserts + found = counts.get(fn) + if found is None: + print(f'ERROR: {fn} not found in {elf} (renamed/removed?)') + failed = True + elif found < expected: + print( + f'ERROR: ESP_FAULT_ASSERT optimized away in {fn}: ' + f'{found} reset checks, expected {expected}. ' + f'See components/esp_common/include/esp_fault.h' + ) + failed = True + else: + print(f'OK: {fn} -> {found} reset checks ({found // 3} assert(s) x3)') + + if failed: + print('FAILED: ESP_FAULT_ASSERT regression check') + return 1 + print('PASSED: ESP_FAULT_ASSERT checks survived optimization') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/components/esp_security/test_apps/fault_assert_opt_check/main/CMakeLists.txt b/components/esp_security/test_apps/fault_assert_opt_check/main/CMakeLists.txt new file mode 100644 index 00000000000..d71200c0946 --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "test_fault_assert.c" + INCLUDE_DIRS ".") diff --git a/components/esp_security/test_apps/fault_assert_opt_check/main/test_fault_assert.c b/components/esp_security/test_apps/fault_assert_opt_check/main/test_fault_assert.c new file mode 100644 index 00000000000..920c09ecb01 --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/main/test_fault_assert.c @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Regression guard for ESP_FAULT_ASSERT() being silently optimised away. + * + * ESP_FAULT_ASSERT(C) must emit three independent "evaluate C -> reset if false" + * checks. When C is a value the optimiser can already prove (e.g. a flag pinned + * by a preceding "if (!C) return"), a naive implementation lets GCC constant-fold + * C and delete all three checks, removing the fault-injection protection with no + * warning. + * + * The functions below place ESP_FAULT_ASSERT in exactly that + * "proven-true cached value" shape. check_fault_asserts.py disassembles the built + * app and fails the build if any of them lost its reset blocks. Keep them + * noinline+used so each is an independent symbol the checker can find. + */ + +#include +#include "esp_fault.h" +#include "esp_attr.h" + +/* volatile so the initial value is opaque: only the early-return "proves" it, + * which is the precise condition that triggers the optimiser elimination. */ +volatile bool fa_test_flag = true; +volatile int fa_test_status = 0; +volatile int fa_test_sink; + +/* Cached bool guarded by an early return -> the original elimination case. */ +bool NOINLINE_ATTR test_fa_guarded_flag(void) +{ + bool valid = fa_test_flag; + if (!valid) { + return false; + } + ESP_FAULT_ASSERT(valid); + return true; +} + +/* Cached status compared to a constant, guarded by an early return. */ +int NOINLINE_ATTR test_fa_guarded_status(void) +{ + int status = fa_test_status; + if (status != 0) { + return status; + } + ESP_FAULT_ASSERT(status == 0); + return 0; +} + +void app_main(void) +{ + /* Reference the test functions so they are linked (not GC'd). */ + fa_test_sink = (int)test_fa_guarded_flag() + test_fa_guarded_status(); +} diff --git a/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_perf b/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_perf new file mode 100644 index 00000000000..4de2cc6f3ad --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_perf @@ -0,0 +1,2 @@ +# -O2 +CONFIG_COMPILER_OPTIMIZATION_PERF=y diff --git a/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_size b/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_size new file mode 100644 index 00000000000..f6da2fb1fbc --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.ci.opt_size @@ -0,0 +1,2 @@ +# -Os +CONFIG_COMPILER_OPTIMIZATION_SIZE=y diff --git a/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.defaults b/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.defaults new file mode 100644 index 00000000000..72548452f94 --- /dev/null +++ b/components/esp_security/test_apps/fault_assert_opt_check/sdkconfig.defaults @@ -0,0 +1,4 @@ +# The clang-built esp32 (Xtensa) bootloader is slightly larger than the GCC one and +# overflows the default 0x7000 limit; move the partition table offset to give it room. +# Harmless for GCC builds. +CONFIG_PARTITION_TABLE_OFFSET=0x9000 diff --git a/components/spi_flash/test_apps/flash_encryption/partitions.csv b/components/spi_flash/test_apps/flash_encryption/partitions.csv index c941d8f4f1c..f5933e6f71f 100644 --- a/components/spi_flash/test_apps/flash_encryption/partitions.csv +++ b/components/spi_flash/test_apps/flash_encryption/partitions.csv @@ -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 diff --git a/components/spi_flash/test_apps/flash_encryption/sdkconfig.defaults b/components/spi_flash/test_apps/flash_encryption/sdkconfig.defaults index d0ef86b66cf..c41595c93ec 100644 --- a/components/spi_flash/test_apps/flash_encryption/sdkconfig.defaults +++ b/components/spi_flash/test_apps/flash_encryption/sdkconfig.defaults @@ -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 diff --git a/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32c5 b/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32c5 index 08ebca9f6ba..2f243f622ae 100644 --- a/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32c5 +++ b/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32c5 @@ -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" diff --git a/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32p4 b/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32p4 index 5305d602c62..1b83c3d5946 100644 --- a/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32p4 +++ b/examples/system/efuse/sdkconfig.ci.virt_secure_boot_v2.esp32p4 @@ -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"