From 2bf6a3cf8b154cf740f0f4a4f52a7ea954bc0bad Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 5 Jul 2024 15:54:22 +0530 Subject: [PATCH 1/5] feat(hal/ecc): Support ECC hardware constant-time point multiplication operations --- components/hal/ecc_hal.c | 9 ++++++++- components/hal/esp32c5/include/hal/ecc_ll.h | 9 +++++++++ components/hal/esp32c61/include/hal/ecc_ll.h | 9 +++++++++ components/hal/include/hal/ecc_hal.h | 11 ++++++++++- .../soc/esp32c5/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c5/include/soc/soc_caps.h | 3 +++ .../soc/esp32c61/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c61/include/soc/soc_caps.h | 3 +++ 8 files changed, 50 insertions(+), 2 deletions(-) diff --git a/components/hal/ecc_hal.c b/components/hal/ecc_hal.c index 18ca952f8e..3de372cdf5 100644 --- a/components/hal/ecc_hal.c +++ b/components/hal/ecc_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -177,3 +177,10 @@ int ecc_hal_read_mod_op_result(uint8_t *r, uint16_t len) } #endif /* SOC_ECC_EXTENDED_MODES_SUPPORTED */ + +#ifdef SOC_ECC_CONSTANT_TIME_POINT_MUL +void ecc_hal_enable_constant_time_point_mul(bool enable) +{ + ecc_ll_enable_constant_time_point_mul(enable); +} +#endif /* SOC_ECC_CONSTANT_TIME_POINT_MUL */ diff --git a/components/hal/esp32c5/include/hal/ecc_ll.h b/components/hal/esp32c5/include/hal/ecc_ll.h index b9f04d7a8a..9e56f188b8 100644 --- a/components/hal/esp32c5/include/hal/ecc_ll.h +++ b/components/hal/esp32c5/include/hal/ecc_ll.h @@ -148,6 +148,15 @@ static inline void ecc_ll_set_mod_base(ecc_mod_base_t base) } } +static inline void ecc_ll_enable_constant_time_point_mul(bool enable) +{ + if (enable) { + REG_SET_BIT(ECC_MULT_CONF_REG, ECC_MULT_SECURITY_MODE); + } else { + REG_CLR_BIT(ECC_MULT_CONF_REG, ECC_MULT_SECURITY_MODE); + } +} + static inline void ecc_ll_write_param(ecc_ll_param_t param, const uint8_t *buf, uint16_t len) { uint32_t reg; diff --git a/components/hal/esp32c61/include/hal/ecc_ll.h b/components/hal/esp32c61/include/hal/ecc_ll.h index b9f04d7a8a..9e56f188b8 100644 --- a/components/hal/esp32c61/include/hal/ecc_ll.h +++ b/components/hal/esp32c61/include/hal/ecc_ll.h @@ -148,6 +148,15 @@ static inline void ecc_ll_set_mod_base(ecc_mod_base_t base) } } +static inline void ecc_ll_enable_constant_time_point_mul(bool enable) +{ + if (enable) { + REG_SET_BIT(ECC_MULT_CONF_REG, ECC_MULT_SECURITY_MODE); + } else { + REG_CLR_BIT(ECC_MULT_CONF_REG, ECC_MULT_SECURITY_MODE); + } +} + static inline void ecc_ll_write_param(ecc_ll_param_t param, const uint8_t *buf, uint16_t len) { uint32_t reg; diff --git a/components/hal/include/hal/ecc_hal.h b/components/hal/include/hal/ecc_hal.h index 23cfbbbda1..4d9916e251 100644 --- a/components/hal/include/hal/ecc_hal.h +++ b/components/hal/include/hal/ecc_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -195,6 +195,15 @@ int ecc_hal_read_mod_op_result(uint8_t *r, uint16_t len); #endif /* SOC_ECC_EXTENDED_MODES_SUPPORTED */ +#ifdef SOC_ECC_CONSTANT_TIME_POINT_MUL +/** + * @brief Enable constant time multiplication operations + * + * @param true: enable; false: disable + */ +void ecc_hal_enable_constant_time_point_mul(bool enable); +#endif /* SOC_ECC_CONSTANT_TIME_POINT_MUL */ + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 0ac05a0ce3..d3ffe65191 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -935,6 +935,10 @@ config SOC_SHA_SUPPORT_SHA256 bool default y +config SOC_ECC_CONSTANT_TIME_POINT_MUL + bool + default y + config SOC_ECDSA_SUPPORT_EXPORT_PUBKEY bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 2cad5a7f94..4924ed158d 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -395,6 +395,9 @@ #define SOC_SHA_SUPPORT_SHA224 (1) #define SOC_SHA_SUPPORT_SHA256 (1) +/*--------------------------- ECC CAPS ---------------------------------------*/ +#define SOC_ECC_CONSTANT_TIME_POINT_MUL 1 + /*--------------------------- ECDSA CAPS ---------------------------------------*/ #define SOC_ECDSA_SUPPORT_EXPORT_PUBKEY (1) diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 4a904e190f..02a66ec774 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -515,6 +515,10 @@ config SOC_SHA_SUPPORT_SHA256 bool default y +config SOC_ECC_CONSTANT_TIME_POINT_MUL + bool + default y + config SOC_ECDSA_SUPPORT_EXPORT_PUBKEY bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 62086ac264..d529db4a62 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -289,6 +289,9 @@ #define SOC_SHA_SUPPORT_SHA224 (1) #define SOC_SHA_SUPPORT_SHA256 (1) +/*--------------------------- ECC CAPS ---------------------------------------*/ +#define SOC_ECC_CONSTANT_TIME_POINT_MUL 1 + /*--------------------------- ECDSA CAPS ---------------------------------------*/ #define SOC_ECDSA_SUPPORT_EXPORT_PUBKEY (1) #define SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE (1) From 49ced36d7a5c8446e2f5d6255d5e790c0a86f545 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Sun, 10 Mar 2024 19:33:42 +0530 Subject: [PATCH 2/5] ci(hal/crypto): Add ECC hardware constant-time point multiplication test --- .../hal/test_apps/crypto/main/ecc/test_ecc.c | 100 +++++++++++++++--- .../test_apps/crypto/main/idf_component.yml | 3 + 2 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 components/hal/test_apps/crypto/main/idf_component.yml diff --git a/components/hal/test_apps/crypto/main/ecc/test_ecc.c b/components/hal/test_apps/crypto/main/ecc/test_ecc.c index fcf72814f2..6869315c88 100644 --- a/components/hal/test_apps/crypto/main/ecc/test_ecc.c +++ b/components/hal/test_apps/crypto/main/ecc/test_ecc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ @@ -7,6 +7,7 @@ #include #include #include +#include #include "sdkconfig.h" #include "esp_private/esp_crypto_lock_internal.h" #include "esp_log.h" @@ -17,8 +18,8 @@ #include "memory_checks.h" #include "unity_fixture.h" +#include "ccomp_timer.h" -#define _DEBUG_ 0 #define SOC_ECC_SUPPORT_POINT_MULT 1 #define SOC_ECC_SUPPORT_POINT_VERIFY 1 @@ -86,6 +87,9 @@ static void ecc_point_mul(const uint8_t *k_le, const uint8_t *x_le, const uint8_ } else { ecc_hal_set_mode(ECC_MODE_POINT_MUL); } +#ifdef SOC_ECC_CONSTANT_TIME_POINT_MUL + ecc_hal_enable_constant_time_point_mul(true); +#endif /* SOC_ECC_CONSTANT_TIME_POINT_MUL */ ecc_hal_start_calc(); while (!ecc_hal_is_calc_finished()) { @@ -118,13 +122,11 @@ static void test_ecc_point_mul_inner(bool verify_first) ecc_be_to_le(ecc_p256_mul_res_x, x_mul_le, 32); ecc_be_to_le(ecc_p256_mul_res_y, y_mul_le, 32); -#if _DEBUG_ - ESP_LOG_BUFFER_HEX("Expected X:", x_mul_le, 32); - ESP_LOG_BUFFER_HEX("Got X:", x_res_le, 32); + ESP_LOG_BUFFER_HEXDUMP("Expected X:", x_mul_le, 32, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP("Got X:", x_res_le, 32, ESP_LOG_DEBUG); - ESP_LOG_BUFFER_HEX("Expected Y:", y_mul_le, 32); - ESP_LOG_BUFFER_HEX("Got Y:", y_res_le, 32); -#endif + ESP_LOG_BUFFER_HEXDUMP("Expected Y:", y_mul_le, 32, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP("Got Y:", y_res_le, 32, ESP_LOG_DEBUG); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(x_mul_le, x_res_le, 32, "X coordinate of P256 point multiplication "); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(y_mul_le, y_res_le, 32, "Y coordinate of P256 point multiplication "); @@ -144,13 +146,11 @@ static void test_ecc_point_mul_inner(bool verify_first) ecc_be_to_le(ecc_p192_mul_res_x, x_mul_le, 24); ecc_be_to_le(ecc_p192_mul_res_y, y_mul_le, 24); -#if _DEBUG_ - ESP_LOG_BUFFER_HEX("Expected X:", x_mul_le, 32); - ESP_LOG_BUFFER_HEX("Got X:", x_res_le, 32); + ESP_LOG_BUFFER_HEXDUMP("Expected X:", x_mul_le, 32, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP("Got X:", x_res_le, 32, ESP_LOG_DEBUG); - ESP_LOG_BUFFER_HEX("Expected Y:", y_mul_le, 32); - ESP_LOG_BUFFER_HEX("Got Y:", y_res_le, 32); -#endif + ESP_LOG_BUFFER_HEXDUMP("Expected Y:", y_mul_le, 32, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP("Got Y:", y_res_le, 32, ESP_LOG_DEBUG); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(x_mul_le, x_res_le, 24, "X coordinate of P192 point multiplication "); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(y_mul_le, y_res_le, 24, "Y coordinate of P192 point multiplication "); @@ -160,6 +160,74 @@ TEST(ecc, ecc_point_multiplication_on_SECP192R1_and_SECP256R1) { test_ecc_point_mul_inner(false); } + +#if SOC_ECC_CONSTANT_TIME_POINT_MUL + +#define CONST_TIME_DEVIATION_PERCENT 0.002 + +static void test_ecc_point_mul_inner_constant_time(void) +{ + uint8_t scalar_le[32]; + uint8_t x_le[32]; + uint8_t y_le[32]; + + /* P256 */ + ecc_be_to_le(ecc_p256_scalar, scalar_le, 32); + ecc_be_to_le(ecc_p256_point_x, x_le, 32); + ecc_be_to_le(ecc_p256_point_y, y_le, 32); + + uint8_t x_res_le[32]; + uint8_t y_res_le[32]; + + double deviation = 0; + uint32_t elapsed_time, mean_elapsed_time, total_elapsed_time = 0; + uint32_t max_time = 0, min_time = UINT32_MAX; + int loop_count = 10; + + for (int i = 0; i < loop_count; i++) { + ccomp_timer_start(); + ecc_point_mul(scalar_le, x_le, y_le, 32, 0, x_res_le, y_res_le); + elapsed_time = ccomp_timer_stop(); + + max_time = MAX(elapsed_time, max_time); + min_time = MIN(elapsed_time, min_time); + total_elapsed_time += elapsed_time; + } + mean_elapsed_time = total_elapsed_time / loop_count; + deviation = ((double)(max_time - mean_elapsed_time) / mean_elapsed_time); + + TEST_ASSERT_LESS_THAN_DOUBLE(CONST_TIME_DEVIATION_PERCENT, deviation); + + /* P192 */ + ecc_be_to_le(ecc_p192_scalar, scalar_le, 24); + ecc_be_to_le(ecc_p192_point_x, x_le, 24); + ecc_be_to_le(ecc_p192_point_y, y_le, 24); + + max_time = 0; + min_time = UINT32_MAX; + total_elapsed_time = 0; + + for (int i = 0; i < loop_count; i++) { + ccomp_timer_start(); + ecc_point_mul(scalar_le, x_le, y_le, 24, 0, x_res_le, y_res_le); + elapsed_time = ccomp_timer_stop(); + + max_time = MAX(elapsed_time, max_time); + min_time = MIN(elapsed_time, min_time); + total_elapsed_time += elapsed_time; + } + mean_elapsed_time = total_elapsed_time / loop_count; + deviation = ((double)(max_time - mean_elapsed_time) / mean_elapsed_time); + + TEST_ASSERT_LESS_THAN_DOUBLE(CONST_TIME_DEVIATION_PERCENT, deviation); +} + +TEST(ecc, ecc_point_multiplication_const_time_check_on_SECP192R1_and_SECP256R1) +{ + test_ecc_point_mul_inner_constant_time(); +} +#endif + #endif #if SOC_ECC_SUPPORT_POINT_VERIFY && !defined(SOC_ECC_SUPPORT_POINT_VERIFY_QUIRK) @@ -493,6 +561,9 @@ TEST_GROUP_RUNNER(ecc) { #if SOC_ECC_SUPPORT_POINT_MULT RUN_TEST_CASE(ecc, ecc_point_multiplication_on_SECP192R1_and_SECP256R1); +#if SOC_ECC_CONSTANT_TIME_POINT_MUL + RUN_TEST_CASE(ecc, ecc_point_multiplication_const_time_check_on_SECP192R1_and_SECP256R1); +#endif #endif #if SOC_ECC_SUPPORT_POINT_VERIFY && !defined(SOC_ECC_SUPPORT_POINT_VERIFY_QUIRK) @@ -534,5 +605,4 @@ TEST_GROUP_RUNNER(ecc) #if SOC_ECC_SUPPORT_MOD_MUL RUN_TEST_CASE(ecc, ecc_mod_multiplication_using_SECP192R1_and_SECP256R1_order_of_curve); #endif - } diff --git a/components/hal/test_apps/crypto/main/idf_component.yml b/components/hal/test_apps/crypto/main/idf_component.yml new file mode 100644 index 0000000000..ff66c8bc7f --- /dev/null +++ b/components/hal/test_apps/crypto/main/idf_component.yml @@ -0,0 +1,3 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/ccomp_timer: ">=1.0.0" From 46cbaa7d4de4ae338f6cb838b684ebfaff6a3d1b Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Mon, 2 Sep 2024 14:06:59 +0530 Subject: [PATCH 3/5] fix(mbedtls/ecc): Enable hardware ECC mult operations only for SOC_ECC_CONSTANT_TIME_MUL Co-authored-by: aditya.patwardhan --- components/mbedtls/port/ecc/esp_ecc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/mbedtls/port/ecc/esp_ecc.c b/components/mbedtls/port/ecc/esp_ecc.c index 0cb4e72e9c..d6b0c6a632 100644 --- a/components/mbedtls/port/ecc/esp_ecc.c +++ b/components/mbedtls/port/ecc/esp_ecc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include "ecc_impl.h" #include "hal/ecc_hal.h" #include "hal/ecc_ll.h" +#include "soc/soc_caps.h" static void esp_ecc_acquire_hardware(void) { @@ -44,6 +45,14 @@ int esp_ecc_point_multiply(const ecc_point_t *point, const uint8_t *scalar, ecc_ ecc_hal_write_mul_param(scalar, point->x, point->y, len); ecc_hal_set_mode(work_mode); +#ifdef SOC_ECC_CONSTANT_TIME_POINT_MUL + /* Enable constant-time point multiplication operations for the ECC hardware accelerator + This protects the ECC multiplication operation from timing attacks. + This increases the time taken (by almost 50%) for some point multiplication + operations performed by the ECC hardware accelerator. + */ + ecc_hal_enable_constant_time_point_mul(true); +#endif /* SOC_ECC_CONSTANT_TIME_POINT_MUL */ ecc_hal_start_calc(); memset(result, 0, sizeof(ecc_point_t)); From 39872a55753f5b512670af90e7d5d029e4984ccd Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Thu, 4 Jul 2024 09:31:07 +0530 Subject: [PATCH 4/5] feat(esp_security): Config to forcefully enable ECC constant-time operations during bootup --- components/esp_security/Kconfig | 13 +++++++++++++ components/esp_security/src/init.c | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/components/esp_security/Kconfig b/components/esp_security/Kconfig index 308816c490..bedc822779 100644 --- a/components/esp_security/Kconfig +++ b/components/esp_security/Kconfig @@ -37,4 +37,17 @@ menu "ESP Security Specific" default 3 if ESP_CRYPTO_DPA_PROTECTION_LEVEL_HIGH endmenu + config ESP_CRYPTO_FORCE_ECC_CONSTANT_TIME_POINT_MUL + bool "Forcfully enable ECC constant time point multiplication operations" + depends on SOC_ECC_CONSTANT_TIME_POINT_MUL + default N + help + If enabled, the app startup code will burn the ECC_FORCE_CONST_TIME efuse bit to force the + ECC peripheral to always perform constant time point multiplication operations, + irrespective of the ECC_MULT_SECURITY_MODE status bit that is present in the ECC_MULT_CONF_REG + register. By default, ESP-IDF configures the ECC peripheral to perform constant time point + multiplication operations, so enabling this config would provide security enhancement only in + the cases when trusted boot is not enabled and the attacker tries carrying out non-constant + time point multiplication operations by changing the default ESP-IDF configurations. + Performing constant time operations protect the ECC multiplication operations from timing attacks. endmenu diff --git a/components/esp_security/src/init.c b/components/esp_security/src/init.c index d835de10c8..989e6e2890 100644 --- a/components/esp_security/src/init.c +++ b/components/esp_security/src/init.c @@ -7,7 +7,12 @@ #include "esp_private/startup_internal.h" #include "sdkconfig.h" #include "esp_crypto_clk.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" #include "esp_security_priv.h" +#include "esp_err.h" + +__attribute__((unused)) static const char *TAG = "esp_security"; ESP_SYSTEM_INIT_FN(esp_security_init, SECONDARY, BIT(0), 103) { @@ -15,6 +20,17 @@ ESP_SYSTEM_INIT_FN(esp_security_init, SECONDARY, BIT(0), 103) #if CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP esp_crypto_dpa_protection_startup(); #endif + +#ifdef CONFIG_ESP_CRYPTO_FORCE_ECC_CONSTANT_TIME_POINT_MUL + if (!esp_efuse_read_field_bit(ESP_EFUSE_ECC_FORCE_CONST_TIME)) { + ESP_EARLY_LOGD(TAG, "Forcefully enabling ECC constant time operations"); + esp_err_t err = esp_efuse_write_field_bit(ESP_EFUSE_ECC_FORCE_CONST_TIME); + if (err != ESP_OK) { + ESP_EARLY_LOGE(TAG, "Enabling ECC constant time operations forcefully failed."); + return err; + } + } +#endif return ESP_OK; } From e1cd5b909e61214df029a80692e937bb9c3cc11a Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Wed, 4 Sep 2024 13:22:07 +0530 Subject: [PATCH 5/5] fix(esp_security): Fix build failure when dpa protection at startup is disabled --- components/esp_security/src/esp_dpa_protection.c | 2 ++ components/esp_security/src/esp_security_priv.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/components/esp_security/src/esp_dpa_protection.c b/components/esp_security/src/esp_dpa_protection.c index 19e9435373..f9f5e19714 100644 --- a/components/esp_security/src/esp_dpa_protection.c +++ b/components/esp_security/src/esp_dpa_protection.c @@ -16,10 +16,12 @@ static inline void esp_crypto_dpa_set_level(esp_crypto_dpa_sec_level_t level) REG_SET_FIELD(HP_SYSTEM_SEC_DPA_CONF_REG, HP_SYSTEM_SEC_DPA_LEVEL, level); } +#if CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP void esp_crypto_dpa_protection_startup(void) { esp_crypto_dpa_set_level(CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL); } +#endif void esp_crypto_dpa_protection_enable(esp_crypto_dpa_sec_level_t level) { diff --git a/components/esp_security/src/esp_security_priv.h b/components/esp_security/src/esp_security_priv.h index 18cba2c90f..f17d6c4e4d 100644 --- a/components/esp_security/src/esp_security_priv.h +++ b/components/esp_security/src/esp_security_priv.h @@ -5,7 +5,10 @@ */ #pragma once +#include "sdkconfig.h" /* Private interface file */ +#if CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP void esp_crypto_dpa_protection_startup(void); +#endif