diff --git a/components/esp_hal_security/esp32c5/include/hal/ecc_ll.h b/components/esp_hal_security/esp32c5/include/hal/ecc_ll.h index b5a5bca2e27..aa8d0738199 100644 --- a/components/esp_hal_security/esp32c5/include/hal/ecc_ll.h +++ b/components/esp_hal_security/esp32c5/include/hal/ecc_ll.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 */ @@ -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" { @@ -47,11 +48,17 @@ static inline void ecc_ll_reset_register(void) PCR.ecdsa_conf.ecdsa_rst_en = 0; } +static inline void ecc_ll_clear_force_pd(void) +{ + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); +} + static inline void ecc_ll_power_up(void) { /* Power up the ECC peripheral (default state is power-down) */ 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/esp_hal_security/esp32c6/include/hal/ecc_ll.h b/components/esp_hal_security/esp32c6/include/hal/ecc_ll.h index 264e89958ab..103ac78570a 100644 --- a/components/esp_hal_security/esp32c6/include/hal/ecc_ll.h +++ b/components/esp_hal_security/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/esp_hal_security/esp32c61/include/hal/ecc_ll.h b/components/esp_hal_security/esp32c61/include/hal/ecc_ll.h index 14c74e53168..717d81a7871 100644 --- a/components/esp_hal_security/esp32c61/include/hal/ecc_ll.h +++ b/components/esp_hal_security/esp32c61/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" #ifdef __cplusplus extern "C" { @@ -49,9 +50,10 @@ static inline void ecc_ll_reset_register(void) static inline void ecc_ll_power_up(void) { - /* Power up the ECC peripheral (default state is power-down) */ + /* Power up the ECC peripheral (default state is power-up) */ 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/esp_hal_security/esp32h2/include/hal/ecc_ll.h b/components/esp_hal_security/esp32h2/include/hal/ecc_ll.h index 3ad0a815b78..c3904280287 100644 --- a/components/esp_hal_security/esp32h2/include/hal/ecc_ll.h +++ b/components/esp_hal_security/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/esp_hal_security/esp32h21/include/hal/ecc_ll.h b/components/esp_hal_security/esp32h21/include/hal/ecc_ll.h index 6ac32c21aa4..98bc34e2854 100644 --- a/components/esp_hal_security/esp32h21/include/hal/ecc_ll.h +++ b/components/esp_hal_security/esp32h21/include/hal/ecc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-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" { @@ -52,6 +53,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/esp_hal_security/esp32h4/include/hal/ecc_ll.h b/components/esp_hal_security/esp32h4/include/hal/ecc_ll.h index 1c2e4b91002..5d0c1386e07 100644 --- a/components/esp_hal_security/esp32h4/include/hal/ecc_ll.h +++ b/components/esp_hal_security/esp32h4/include/hal/ecc_ll.h @@ -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" { @@ -50,9 +51,11 @@ static inline void ecc_ll_reset_register(void) static inline void ecc_ll_power_up(void) { - /* Power up the ECC peripheral (default state is power-down) */ + /* Power up the ECC peripheral (default state is power-up) */ REG_CLR_BIT(PCR_ECC_MEM_LP_CTRL_REG, PCR_ECC_MEM_LP_EN); - REG_CLR_BIT(PCR_ECC_MEM_LP_CTRL_REG, PCR_ECC_MEM_FORCE_CTRL); + REG_SET_BIT(PCR_ECC_MEM_LP_CTRL_REG, PCR_ECC_MEM_FORCE_CTRL); + ESP_FAULT_ASSERT(REG_GET_BIT(PCR_ECC_MEM_LP_CTRL_REG, PCR_ECC_MEM_LP_EN) == 0 && + REG_GET_BIT(PCR_ECC_MEM_LP_CTRL_REG, PCR_ECC_MEM_FORCE_CTRL) != 0); } static inline void ecc_ll_power_down(void) diff --git a/components/esp_hal_security/esp32p4/include/hal/ecc_ll.h b/components/esp_hal_security/esp32p4/include/hal/ecc_ll.h index ab4b65d187d..34a9e98db7f 100644 --- a/components/esp_hal_security/esp32p4/include/hal/ecc_ll.h +++ b/components/esp_hal_security/esp32p4/include/hal/ecc_ll.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 */ @@ -12,8 +12,10 @@ #include "hal/efuse_hal.h" #include "soc/ecc_mult_reg.h" #include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_system_reg.h" #include "soc/chip_revision.h" #include "hal/config.h" +#include "esp_fault.h" #ifdef __cplusplus extern "C" { @@ -65,8 +67,20 @@ static inline void ecc_ll_reset_register(void) ecc_ll_reset_register(__VA_ARGS__); \ } while(0) -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/esp_hal_security/esp32s31/include/hal/ecc_ll.h b/components/esp_hal_security/esp32s31/include/hal/ecc_ll.h index c23094a77bd..195886e14b4 100644 --- a/components/esp_hal_security/esp32s31/include/hal/ecc_ll.h +++ b/components/esp_hal_security/esp32s31/include/hal/ecc_ll.h @@ -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" { @@ -62,8 +64,21 @@ static inline void ecc_ll_reset_register(void) ecc_ll_reset_register(__VA_ARGS__); \ } while(0) -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_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_EN); + REG_SET_BIT(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_FORCE_CTRL); + /* Anti-FI: confirm the clears took effect. */ + ESP_FAULT_ASSERT(REG_GET_BIT(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_EN) == 0 && + REG_GET_BIT(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_FORCE_CTRL) != 0); +} + +static inline void ecc_ll_power_down(void) +{ + /* Power down the ECC peripheral */ + REG_SET_BIT(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_EN); +} static inline void ecc_ll_enable_interrupt(void) { diff --git a/components/esp_hal_security/test_apps/crypto/main/ecc/test_ecc.c b/components/esp_hal_security/test_apps/crypto/main/ecc/test_ecc.c index d2a4043aa66..f82cab91f85 100644 --- a/components/esp_hal_security/test_apps/crypto/main/ecc/test_ecc.c +++ b/components/esp_hal_security/test_apps/crypto/main/ecc/test_ecc.c @@ -207,6 +207,10 @@ static void test_ecc_point_mul_inner_constant_time(void) uint32_t max_time = 0, min_time = UINT32_MAX; int loop_count = 10; + /* Warm-up: the first call is otherwise an I-cache / branch-predictor + * outlier that dominates max_time and thus creating deviations */ + ecc_point_mul(scalar_le, x_le, y_le, ECC_P256_SIZE_BYTES, 0, x_res_le, y_res_le); + for (int i = 0; i < loop_count; i++) { ccomp_timer_start(); ecc_point_mul(scalar_le, x_le, y_le, ECC_P256_SIZE_BYTES, 0, x_res_le, y_res_le); @@ -230,6 +234,9 @@ static void test_ecc_point_mul_inner_constant_time(void) min_time = UINT32_MAX; total_elapsed_time = 0; + /* Warm-up — see comment on the P256 loop. */ + ecc_point_mul(scalar_le, x_le, y_le, ECC_P192_SIZE_BYTES, 0, x_res_le, y_res_le); + for (int i = 0; i < loop_count; i++) { ccomp_timer_start(); ecc_point_mul(scalar_le, x_le, y_le, ECC_P192_SIZE_BYTES, 0, x_res_le, y_res_le); @@ -255,6 +262,9 @@ static void test_ecc_point_mul_inner_constant_time(void) min_time = UINT32_MAX; total_elapsed_time = 0; + /* Warm-up — see comment on the P256 loop. */ + ecc_point_mul(scalar_le, x_le, y_le, ECC_P384_SIZE_BYTES, 0, x_res_le, y_res_le); + for (int i = 0; i < loop_count; i++) { ccomp_timer_start(); ecc_point_mul(scalar_le, x_le, y_le, ECC_P384_SIZE_BYTES, 0, x_res_le, y_res_le); diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index abab70d56c1..6deb2046dff 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -59,6 +59,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} diff --git a/components/esp_rom/esp32c5/Kconfig.soc_caps.in b/components/esp_rom/esp32c5/Kconfig.soc_caps.in index 11685088ea0..85394c8c99d 100644 --- a/components/esp_rom/esp32c5/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32c5/Kconfig.soc_caps.in @@ -119,6 +119,10 @@ config ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP bool default y +config ESP_ROM_ECDSA_VERIFY_PATCH + bool + default y + config ESP_ROM_BOOTLOADER_OFFSET_FLASH hex default 0x2000 diff --git a/components/esp_rom/esp32c5/esp_rom_caps.h b/components/esp_rom/esp32c5/esp_rom_caps.h index 465ead85a0c..a6de4f192ea 100644 --- a/components/esp_rom/esp32c5/esp_rom_caps.h +++ b/components/esp_rom/esp32c5/esp_rom_caps.h @@ -35,5 +35,6 @@ #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_BOOTLOADER_OFFSET_FLASH (0x2000) // Bootloader offset in flash determined by the ROM bootloader #define ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_NO_MAP (1) // ROM cache writeback related needs patch to avoid sync loss, no map parameter diff --git a/components/esp_rom/esp32c5/ld/esp32c5.rom.ld b/components/esp_rom/esp32c5/ld/esp32c5.rom.ld index bba9f0a735c..08cb232ef8c 100644 --- a/components/esp_rom/esp32c5/ld/esp32c5.rom.ld +++ b/components/esp_rom/esp32c5/ld/esp32c5.rom.ld @@ -412,7 +412,7 @@ esp_rom_km_huk_risk = 0x40000898; /* Functions */ ets_emsa_pss_verify = 0x4000089c; ets_rsa_pss_verify = 0x400008a0; -ets_ecdsa_verify = 0x400008a4; +_rom_ets_ecdsa_verify = 0x400008a4; ets_secure_boot_verify_bootloader_with_keys = 0x400008a8; ets_secure_boot_verify_signature = 0x400008ac; ets_secure_boot_read_key_digests = 0x400008b0; diff --git a/components/esp_rom/esp32c61/Kconfig.soc_caps.in b/components/esp_rom/esp32c61/Kconfig.soc_caps.in index 5bfd86f1bf1..199ba7765a7 100644 --- a/components/esp_rom/esp32c61/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32c61/Kconfig.soc_caps.in @@ -107,6 +107,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 diff --git a/components/esp_rom/esp32c61/esp_rom_caps.h b/components/esp_rom/esp32c61/esp_rom_caps.h index 6949dbcfaf0..ad8a90120b6 100644 --- a/components/esp_rom/esp32c61/esp_rom_caps.h +++ b/components/esp_rom/esp32c61/esp_rom_caps.h @@ -32,6 +32,7 @@ #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_BOOTLOADER_OFFSET_FLASH (0x0) // Bootloader offset in flash determined by the ROM bootloader #define ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_NO_MAP (1) // ROM cache writeback related needs patch to avoid sync loss, no map parameter diff --git a/components/esp_rom/esp32c61/ld/esp32c61.rom.ld b/components/esp_rom/esp32c61/ld/esp32c61.rom.ld index 5f72d41933d..599fea694eb 100644 --- a/components/esp_rom/esp32c61/ld/esp32c61.rom.ld +++ b/components/esp_rom/esp32c61/ld/esp32c61.rom.ld @@ -370,7 +370,7 @@ ets_efuse_usb_device_disabled = 0x40000808; ***************************************/ /* Functions */ -ets_ecdsa_verify = 0x40000810; +_rom_ets_ecdsa_verify = 0x40000810; ets_secure_boot_verify_bootloader_with_keys = 0x40000814; ets_secure_boot_verify_signature = 0x40000818; ets_secure_boot_read_key_digests = 0x4000081c; diff --git a/components/esp_rom/esp32h2/Kconfig.soc_caps.in b/components/esp_rom/esp32h2/Kconfig.soc_caps.in index 60c9ee4a150..4a5f0c20c80 100644 --- a/components/esp_rom/esp32h2/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32h2/Kconfig.soc_caps.in @@ -115,6 +115,10 @@ config ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP bool default y +config ESP_ROM_ECDSA_VERIFY_PATCH + bool + default y + config ESP_ROM_BOOTLOADER_OFFSET_FLASH hex default 0x0 diff --git a/components/esp_rom/esp32h2/esp_rom_caps.h b/components/esp_rom/esp32h2/esp_rom_caps.h index 6c1e8491a37..0cf8cb293e7 100644 --- a/components/esp_rom/esp32h2/esp_rom_caps.h +++ b/components/esp_rom/esp32h2/esp_rom_caps.h @@ -34,4 +34,5 @@ #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 #define ESP_ROM_BOOTLOADER_OFFSET_FLASH (0x0) // Bootloader offset in flash determined by the ROM bootloader diff --git a/components/esp_rom/esp32h2/ld/esp32h2.rom.ld b/components/esp_rom/esp32h2/ld/esp32h2.rom.ld index 854b22fb94d..03b9c4a9c48 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/esp32h4/Kconfig.soc_caps.in b/components/esp_rom/esp32h4/Kconfig.soc_caps.in index 9f22685b9a4..7b9f0c2fc46 100644 --- a/components/esp_rom/esp32h4/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32h4/Kconfig.soc_caps.in @@ -71,6 +71,10 @@ config ESP_ROM_RAM_APP_NEEDS_MMU_INIT bool default y +config ESP_ROM_ECDSA_VERIFY_PATCH + bool + default y + config ESP_ROM_BOOTLOADER_OFFSET_FLASH hex default 0x2000 diff --git a/components/esp_rom/esp32h4/esp_rom_caps.h b/components/esp_rom/esp32h4/esp_rom_caps.h index 6b1f02bcde4..24f69478c7d 100644 --- a/components/esp_rom/esp32h4/esp_rom_caps.h +++ b/components/esp_rom/esp32h4/esp_rom_caps.h @@ -23,5 +23,6 @@ #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_BOOTLOADER_OFFSET_FLASH (0x2000) // Bootloader offset in flash determined by the ROM bootloader #define ESP_ROM_CACHE_WRITEBACK_NEEDS_SYNC_TWICE_NO_MAP (1) // ROM cache writeback related needs patch to avoid sync loss, no map parameter diff --git a/components/esp_rom/esp32h4/ld/esp32h4.rom.ld b/components/esp_rom/esp32h4/ld/esp32h4.rom.ld index 44b02fa5e3d..78a1b8252b5 100644 --- a/components/esp_rom/esp32h4/ld/esp32h4.rom.ld +++ b/components/esp_rom/esp32h4/ld/esp32h4.rom.ld @@ -385,7 +385,7 @@ esp_rom_recover_key = 0x400007cc; ***************************************/ /* Functions */ -ets_ecdsa_verify = 0x400007d0; +_rom_ets_ecdsa_verify = 0x400007d0; ets_secure_boot_verify_bootloader_with_keys = 0x400007d4; ets_secure_boot_verify_signature = 0x400007d8; ets_secure_boot_read_key_digests = 0x400007dc; diff --git a/components/esp_rom/esp32p4/Kconfig.soc_caps.in b/components/esp_rom/esp32p4/Kconfig.soc_caps.in index 6fff9a2faff..989040149be 100644 --- a/components/esp_rom/esp32p4/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32p4/Kconfig.soc_caps.in @@ -87,6 +87,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 diff --git a/components/esp_rom/esp32p4/esp_rom_caps.h b/components/esp_rom/esp32p4/esp_rom_caps.h index 886e497993a..febf3eac42e 100644 --- a/components/esp_rom/esp32p4/esp_rom_caps.h +++ b/components/esp_rom/esp32p4/esp_rom_caps.h @@ -27,5 +27,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 diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.eco0_4.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.eco0_4.ld index fb11cb9265c..e6e7fa4a9fc 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.eco0_4.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.eco0_4.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/esp32p4/ld/esp32p4.rom.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.ld index 65f0d1eb20e..720246d6cae 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.ld @@ -448,7 +448,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/esp32s31/Kconfig.soc_caps.in b/components/esp_rom/esp32s31/Kconfig.soc_caps.in index 83db14746f3..f9ed1dab7d7 100644 --- a/components/esp_rom/esp32s31/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32s31/Kconfig.soc_caps.in @@ -91,6 +91,10 @@ config ESP_ROM_PRINTS_LOCKUP_STATUS bool default y +config ESP_ROM_ECDSA_VERIFY_PATCH + bool + default y + config ESP_ROM_BOOTLOADER_OFFSET_FLASH hex default 0x2000 diff --git a/components/esp_rom/esp32s31/esp_rom_caps.h b/components/esp_rom/esp32s31/esp_rom_caps.h index b4499994a0e..a0606da0bdb 100644 --- a/components/esp_rom/esp32s31/esp_rom_caps.h +++ b/components/esp_rom/esp32s31/esp_rom_caps.h @@ -29,5 +29,6 @@ #define ESP_ROM_HAS_VERSION (1) // ROM has version/eco information #define ESP_ROM_HAS_OUTPUT_PUTC_FUNC (1) // ROM has esp_rom_output_putc (or ets_write_char_uart) #define ESP_ROM_PRINTS_LOCKUP_STATUS (1) // ROM bootloader already prints CPU lockup diagnostic status +#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 diff --git a/components/esp_rom/esp32s31/ld/esp32s31.rom.ld b/components/esp_rom/esp32s31/ld/esp32s31.rom.ld index bcb1c01162d..01d792adcff 100644 --- a/components/esp_rom/esp32s31/ld/esp32s31.rom.ld +++ b/components/esp_rom/esp32s31/ld/esp32s31.rom.ld @@ -467,7 +467,7 @@ esp_rom_recover_key = 0x2f8008b8; /* Functions */ ets_emsa_pss_verify = 0x2f8008bc; ets_rsa_pss_verify = 0x2f8008c0; -ets_ecdsa_verify = 0x2f8008c4; +_rom_ets_ecdsa_verify = 0x2f8008c4; ets_secure_boot_verify_bootloader_with_keys = 0x2f8008c8; ets_secure_boot_verify_signature = 0x2f8008cc; ets_secure_boot_read_key_digests = 0x2f8008d0; 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 */ diff --git a/components/esp_system/port/soc/esp32c5/system_internal.c b/components/esp_system/port/soc/esp32c5/system_internal.c index 1ab861d269c..d1a00ba93ca 100644 --- a/components/esp_system/port/soc/esp32c5/system_internal.c +++ b/components/esp_system/port/soc/esp32c5/system_internal.c @@ -99,6 +99,7 @@ void esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_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/esp32c6/system_internal.c b/components/esp_system/port/soc/esp32c6/system_internal.c index a5391a5c3f9..17ffd0df04f 100644 --- a/components/esp_system/port/soc/esp32c6/system_internal.c +++ b/components/esp_system/port/soc/esp32c6/system_internal.c @@ -83,6 +83,8 @@ void 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/esp32c61/system_internal.c b/components/esp_system/port/soc/esp32c61/system_internal.c index 5e703bc3927..dec09f88be9 100644 --- a/components/esp_system/port/soc/esp32c61/system_internal.c +++ b/components/esp_system/port/soc/esp32c61/system_internal.c @@ -100,6 +100,7 @@ void esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_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/esp32h2/system_internal.c b/components/esp_system/port/soc/esp32h2/system_internal.c index 41140f44226..6a471aff8ff 100644 --- a/components/esp_system/port/soc/esp32h2/system_internal.c +++ b/components/esp_system/port/soc/esp32h2/system_internal.c @@ -82,6 +82,7 @@ void 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/esp32h21/system_internal.c b/components/esp_system/port/soc/esp32h21/system_internal.c index d39606dbeee..b519f67a75b 100644 --- a/components/esp_system/port/soc/esp32h21/system_internal.c +++ b/components/esp_system/port/soc/esp32h21/system_internal.c @@ -85,6 +85,7 @@ void esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_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/esp32h4/system_internal.c b/components/esp_system/port/soc/esp32h4/system_internal.c index 86c43c00268..c54e140e1e6 100644 --- a/components/esp_system/port/soc/esp32h4/system_internal.c +++ b/components/esp_system/port/soc/esp32h4/system_internal.c @@ -85,6 +85,8 @@ void esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); CLEAR_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECC_MEM_LP_CTRL_REG, PCR_ECC_MEM_LP_EN); + SET_PERI_REG_MASK(PCR_ECC_MEM_LP_CTRL_REG, PCR_ECC_MEM_FORCE_CTRL); // 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 5456d680631..a310fa296c7 100644 --- a/components/esp_system/port/soc/esp32p4/system_internal.c +++ b/components/esp_system/port/soc/esp32p4/system_internal.c @@ -131,6 +131,7 @@ void 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 < 101 if (efuse_hal_chip_revision() < 101) { diff --git a/components/esp_system/port/soc/esp32s31/system_internal.c b/components/esp_system/port/soc/esp32s31/system_internal.c index 470bd516425..2da0d2b1275 100644 --- a/components/esp_system/port/soc/esp32s31/system_internal.c +++ b/components/esp_system/port/soc/esp32s31/system_internal.c @@ -48,6 +48,9 @@ void esp_system_reset_modules_on_exit(void) esp_rom_output_tx_wait_idle(i); } } + + CLEAR_PERI_REG_MASK(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_EN); + SET_PERI_REG_MASK(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_FORCE_CTRL); } static void IRAM_ATTR __attribute__((noinline, noreturn)) esp_restart_noos_inner(void) diff --git a/components/esp_tee/include/private/esp_tee_binary.h b/components/esp_tee/include/private/esp_tee_binary.h index 5196dad1107..0abaa3e3a72 100644 --- a/components/esp_tee/include/private/esp_tee_binary.h +++ b/components/esp_tee/include/private/esp_tee_binary.h @@ -112,6 +112,14 @@ void esp_tee_configure_region_protection(void); */ void esp_tee_configure_apm_protection(void); +/** + * @brief Reset the crypto peripherals to a clean state. + * + * Mirrors esp_system_reset_modules_on_exit() in the non-TEE path. + * Intended to be called from the TEE panic handler before a software reset. + */ +void esp_tee_soc_reset_crypto_peripherals(void); + /** * @brief Switch to the REE app after TEE initialization is complete * diff --git a/components/esp_tee/subproject/main/CMakeLists.txt b/components/esp_tee/subproject/main/CMakeLists.txt index 9c0f7e3f366..6cd569cfa31 100644 --- a/components/esp_tee/subproject/main/CMakeLists.txt +++ b/components/esp_tee/subproject/main/CMakeLists.txt @@ -25,7 +25,8 @@ endif() # SoC specific implementation for TEE list(APPEND srcs "soc/${target}/esp_tee_secure_sys_cfg.c" "soc/${target}/esp_tee_pmp_pma_prot_cfg.c" - "soc/${target}/esp_tee_apm_prot_cfg.c") + "soc/${target}/esp_tee_apm_prot_cfg.c" + "soc/${target}/esp_tee_crypto_reset.c") list(APPEND srcs "soc/common/esp_tee_apm_intr.c") diff --git a/components/esp_tee/subproject/main/common/panic/esp_tee_panic.c b/components/esp_tee/subproject/main/common/panic/esp_tee_panic.c index 3fee6d506e3..ccf21e7c4d1 100644 --- a/components/esp_tee/subproject/main/common/panic/esp_tee_panic.c +++ b/components/esp_tee/subproject/main/common/panic/esp_tee_panic.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "hal/cache_ll.h" #include "hal/cache_hal.h" #include "hal/apm_hal.h" +#include "soc/soc_caps.h" #if SOC_INT_PLIC_SUPPORTED #include "soc/plic_reg.h" @@ -56,6 +57,12 @@ static void tee_panic_end(void) esp_rom_output_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); } + // Reset crypto peripherals before the panic-induced reset so the next boot + // sees them in a clean state. The SoC-specific implementation mirrors + // esp_system_reset_modules_on_exit() in the non-TEE path using register-level + // accesses. + esp_tee_soc_reset_crypto_peripherals(); + // Generate system reset esp_rom_software_reset_system(); } diff --git a/components/esp_tee/subproject/main/soc/esp32c5/esp_tee_crypto_reset.c b/components/esp_tee/subproject/main/soc/esp32c5/esp_tee_crypto_reset.c new file mode 100644 index 00000000000..a9e1ec6062e --- /dev/null +++ b/components/esp_tee/subproject/main/soc/esp32c5/esp_tee_crypto_reset.c @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "soc/pcr_reg.h" + +#include "esp_tee.h" + +void esp_tee_soc_reset_crypto_peripherals(void) +{ + SET_PERI_REG_MASK(PCR_AES_CONF_REG, PCR_AES_RST_EN); + CLEAR_PERI_REG_MASK(PCR_AES_CONF_REG, PCR_AES_RST_EN); + SET_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN); + CLEAR_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN); + SET_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + SET_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN); + SET_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); + CLEAR_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); + SET_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); + SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + 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); +} diff --git a/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_crypto_reset.c b/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_crypto_reset.c new file mode 100644 index 00000000000..1dde41e9401 --- /dev/null +++ b/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_crypto_reset.c @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "soc/pcr_reg.h" + +#include "esp_tee.h" + +void esp_tee_soc_reset_crypto_peripherals(void) +{ + SET_PERI_REG_MASK(PCR_AES_CONF_REG, PCR_AES_RST_EN); + SET_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN); + SET_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + SET_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); + SET_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); + SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_AES_CONF_REG, PCR_AES_RST_EN); + CLEAR_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + 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); + 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); +} diff --git a/components/esp_tee/subproject/main/soc/esp32c61/esp_tee_crypto_reset.c b/components/esp_tee/subproject/main/soc/esp32c61/esp_tee_crypto_reset.c new file mode 100644 index 00000000000..58013ff3755 --- /dev/null +++ b/components/esp_tee/subproject/main/soc/esp32c61/esp_tee_crypto_reset.c @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "soc/pcr_reg.h" + +#include "esp_tee.h" + +void esp_tee_soc_reset_crypto_peripherals(void) +{ + SET_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + SET_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN); + SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + 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); +} diff --git a/components/esp_tee/subproject/main/soc/esp32h2/esp_tee_crypto_reset.c b/components/esp_tee/subproject/main/soc/esp32h2/esp_tee_crypto_reset.c new file mode 100644 index 00000000000..96a73fd8c46 --- /dev/null +++ b/components/esp_tee/subproject/main/soc/esp32h2/esp_tee_crypto_reset.c @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "soc/pcr_reg.h" + +#include "esp_tee.h" + +void esp_tee_soc_reset_crypto_peripherals(void) +{ + SET_PERI_REG_MASK(PCR_AES_CONF_REG, PCR_AES_RST_EN); + SET_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN); + SET_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + SET_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN); + SET_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); + SET_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); + SET_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_AES_CONF_REG, PCR_AES_RST_EN); + CLEAR_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECC_CONF_REG, PCR_ECC_RST_EN); + CLEAR_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN); + 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); + 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); +} 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 911e8d241c9..eed84dce00d 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 @@ -18,6 +18,7 @@ #include "mbedtls/bignum.h" #include "esp_assert.h" +#include "esp_fault.h" #include "esp_crypto_lock.h" #include "esp_crypto_periph_clk.h" @@ -353,13 +354,22 @@ static psa_status_t check_ecdsa_signature_range(const uint8_t *signature, size_t goto cleanup; } - /* 1 <= scalar <= n-1: equivalently scalar > 0 and scalar < n. */ - 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) { + /* 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) { goto cleanup; } + ESP_FAULT_ASSERT(verdict == RANGE_OK); + #undef RANGE_OK + #undef RANGE_FAIL status = PSA_SUCCESS; @@ -562,6 +572,8 @@ psa_status_t esp_ecdsa_transparent_verify_hash_complete(esp_ecdsa_transparent_ve return PSA_ERROR_INVALID_SIGNATURE; } + ESP_FAULT_ASSERT(ret == 0); + return PSA_SUCCESS; } 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 08794629ba5..f7c22646dd5 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 @@ -10,6 +10,9 @@ #include #include +#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS +#include "mbedtls/private/ecp.h" +#include "mbedtls/private/bignum.h" #include "psa/crypto.h" #include "psa_crypto_driver_esp_ecdsa_contexts.h" #include "psa_crypto_driver_esp_ecdsa.h" @@ -334,6 +337,16 @@ TEST_CASE("mbedtls ECDSA signature verification performance on SECP384R1", "[mbe #define ECDSA_RANGE_CHECK_REJECT_STATUS PSA_ERROR_INVALID_SIGNATURE #endif +/* 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); +} + TEST_CASE("mbedtls ECDSA signature verification rejects out-of-range r, s on SECP256R1", "[mbedtls]") { #if SOC_ECDSA_SUPPORTED @@ -341,24 +354,17 @@ TEST_CASE("mbedtls ECDSA signature verification rejects out-of-range r, s on SEC TEST_IGNORE_MESSAGE("ECDSA is not supported"); } #endif - /* Case A: r = 0, s = 0 -- caught by 'r > 0' / 's > 0' check. */ static const uint8_t zero32[32] = { 0 }; - test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, - zero32, zero32, - ecdsa256_pub_x, ecdsa256_pub_y, - ECDSA_RANGE_CHECK_REJECT_STATUS); + uint8_t p256_n_be[32]; + ecdsa_get_curve_order_be(MBEDTLS_ECP_DP_SECP256R1, p256_n_be, sizeof(p256_n_be)); - /* Case B: r = N (SECP256R1 curve order), s = valid -- caught by 'r < N' check. */ - static const uint8_t p256_n_be[32] = { - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, - 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, - }; - test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, - p256_n_be, ecdsa256_s, - ecdsa256_pub_x, ecdsa256_pub_y, - ECDSA_RANGE_CHECK_REJECT_STATUS); + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, zero32, zero32, ecdsa256_pub_x, ecdsa256_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=0, s=0 */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, zero32, p256_n_be, ecdsa256_pub_x, ecdsa256_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=0, s=N */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, p256_n_be, zero32, ecdsa256_pub_x, ecdsa256_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=N, s=0 */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, p256_n_be, p256_n_be, ecdsa256_pub_x, ecdsa256_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=N, s=N */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_r, zero32, ecdsa256_pub_x, ecdsa256_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=valid, s=0 */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_r, p256_n_be, ecdsa256_pub_x, ecdsa256_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=valid, s=N */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP256R1, sha, p256_n_be, ecdsa256_s, ecdsa256_pub_x, ecdsa256_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=N, s=valid */ } #ifdef SOC_ECDSA_SUPPORT_CURVE_P384 @@ -369,26 +375,17 @@ TEST_CASE("mbedtls ECDSA signature verification rejects out-of-range r, s on SEC TEST_IGNORE_MESSAGE("ECDSA is not supported"); } #endif - /* Case A: r = 0, s = 0 */ static const uint8_t zero48[48] = { 0 }; - test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, - zero48, zero48, - ecdsa384_pub_x, ecdsa384_pub_y, - ECDSA_RANGE_CHECK_REJECT_STATUS); + uint8_t p384_n_be[48]; + ecdsa_get_curve_order_be(MBEDTLS_ECP_DP_SECP384R1, p384_n_be, sizeof(p384_n_be)); - /* Case B: r = N (SECP384R1 curve order), s = valid */ - static const uint8_t p384_n_be[48] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, - 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, - 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73, - }; - test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, - p384_n_be, ecdsa384_s, - ecdsa384_pub_x, ecdsa384_pub_y, - ECDSA_RANGE_CHECK_REJECT_STATUS); + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, zero48, zero48, ecdsa384_pub_x, ecdsa384_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=0, s=0 */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, zero48, p384_n_be, ecdsa384_pub_x, ecdsa384_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=0, s=N */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, p384_n_be, zero48, ecdsa384_pub_x, ecdsa384_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=N, s=0 */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, p384_n_be, p384_n_be, ecdsa384_pub_x, ecdsa384_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=N, s=N */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_r, zero48, ecdsa384_pub_x, ecdsa384_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=valid, s=0 */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_r, p384_n_be, ecdsa384_pub_x, ecdsa384_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=valid, s=N */ + test_ecdsa_verify(ESP_ECDSA_CURVE_SECP384R1, sha, p384_n_be, ecdsa384_s, ecdsa384_pub_x, ecdsa384_pub_y, ECDSA_RANGE_CHECK_REJECT_STATUS); /* r=N, s=valid */ } #endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */