diff --git a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c index c4424c56ebb..0cd378230d3 100644 --- a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c +++ b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c @@ -1,48 +1,69 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "esp_tinycrypt_port.h" +#include + #include "esp_crypto_lock.h" -#include "esp_private/esp_crypto_lock_internal.h" +#include "esp_crypto_periph_clk.h" +#include #if SOC_ECC_SUPPORTED #include "hal/ecc_hal.h" -#include "hal/ecc_ll.h" #endif /* SOC_ECC_SUPPORTED */ +#define ECC_MAX_PARAM_BYTES 48 #if SOC_ECC_SUPPORTED -static void esp_tinycrypt_acquire_ecc_hardware(void) +static void uecc_vli_native_to_le(uint8_t *le, const uECC_word_t *native, uint16_t len) +{ + uint8_t be[ECC_MAX_PARAM_BYTES]; + + uECC_vli_nativeToBytes(be, len, native); + for (uint16_t i = 0; i < len; i++) { + le[i] = be[len - 1 - i]; + } +} + +static void uecc_vli_le_to_native(uECC_word_t *native, const uint8_t *le, uint16_t len) +{ + uint8_t be[ECC_MAX_PARAM_BYTES]; + + for (uint16_t i = 0; i < len; i++) { + be[i] = le[len - 1 - i]; + } + uECC_vli_bytesToNative(native, be, len); +} + +static void esp_tinycrypt_acquire_ecc_hardware(void) { esp_crypto_ecc_lock_acquire(); - - ECC_RCC_ATOMIC() { - ecc_ll_enable_bus_clock(true); - ecc_ll_power_up(); - ecc_ll_reset_register(); - } + esp_crypto_ecc_enable_periph_clk(true); } -static void esp_tinycrypt_release_ecc_hardware(void) +static void esp_tinycrypt_release_ecc_hardware(void) { - ECC_RCC_ATOMIC() { - ecc_ll_enable_bus_clock(false); - ecc_ll_power_down(); - } - + esp_crypto_ecc_enable_periph_clk(false); esp_crypto_ecc_lock_release(); } +#endif /* SOC_ECC_SUPPORTED */ int esp_tinycrypt_verify_ecc_point(const uint8_t *pk_x, const uint8_t *pk_y, uint8_t length) { +#if SOC_ECC_SUPPORTED int result; + uint8_t px_le[ECC_MAX_PARAM_BYTES]; + uint8_t py_le[ECC_MAX_PARAM_BYTES]; + + uecc_vli_native_to_le(px_le, (const uECC_word_t *)pk_x, length); + uecc_vli_native_to_le(py_le, (const uECC_word_t *)pk_y, length); esp_tinycrypt_acquire_ecc_hardware(); - ecc_hal_write_verify_param(pk_x, pk_y, length); + ecc_hal_write_verify_param(px_le, py_le, length); ecc_hal_set_mode(ECC_MODE_VERIFY); ecc_hal_start_calc(); while (!ecc_hal_is_calc_finished()); @@ -55,17 +76,40 @@ int esp_tinycrypt_verify_ecc_point(const uint8_t *pk_x, const uint8_t *pk_y, uin } else { return -1; } +#else + (void)pk_x; + (void)pk_y; + (void)length; + return -1; +#endif /* SOC_ECC_SUPPORTED */ } -int esp_tinycrypt_calc_ecc_mult(const uint8_t *p_x, const uint8_t *p_y, const uint8_t *scalar, - uint8_t *r_x, uint8_t *r_y, uint8_t num_bytes, bool verify_first) +int esp_tinycrypt_calc_ecc_mult(const uECC_word_t *point_x, const uECC_word_t *point_y, + const uECC_word_t *scalar, uECC_word_t *result_x, + uECC_word_t *result_y, uint8_t num_bytes, bool verify_first) { - int ret = -1; +#if SOC_ECC_SUPPORTED + int ret; ecc_mode_t work_mode = verify_first ? ECC_MODE_VERIFY_THEN_POINT_MUL : ECC_MODE_POINT_MUL; + uint8_t k_le[ECC_MAX_PARAM_BYTES]; + uint8_t px_le[ECC_MAX_PARAM_BYTES]; + uint8_t py_le[ECC_MAX_PARAM_BYTES]; + uint8_t rx_le[ECC_MAX_PARAM_BYTES]; + uint8_t ry_le[ECC_MAX_PARAM_BYTES]; + + memset(k_le, 0, sizeof(k_le)); + memset(px_le, 0, sizeof(px_le)); + memset(py_le, 0, sizeof(py_le)); + memset(rx_le, 0, sizeof(rx_le)); + memset(ry_le, 0, sizeof(ry_le)); + + uecc_vli_native_to_le(k_le, scalar, num_bytes); + uecc_vli_native_to_le(px_le, point_x, num_bytes); + uecc_vli_native_to_le(py_le, point_y, num_bytes); esp_tinycrypt_acquire_ecc_hardware(); - ecc_hal_write_mul_param(scalar, p_x, p_y, num_bytes); + ecc_hal_write_mul_param(k_le, px_le, py_le, num_bytes); ecc_hal_set_mode(work_mode); /* * Enable constant-time point multiplication operations for the ECC hardware accelerator, @@ -78,10 +122,25 @@ int esp_tinycrypt_calc_ecc_mult(const uint8_t *p_x, const uint8_t *p_y, const ui while (!ecc_hal_is_calc_finished()); - ret = ecc_hal_read_mul_result(r_x, r_y, num_bytes); + ret = ecc_hal_read_mul_result(rx_le, ry_le, num_bytes); esp_tinycrypt_release_ecc_hardware(); - return ret; -} + if (ret != 0) { + return -1; + } + + uecc_vli_le_to_native(result_x, rx_le, num_bytes); + uecc_vli_le_to_native(result_y, ry_le, num_bytes); + return 0; +#else + (void)point_x; + (void)point_y; + (void)scalar; + (void)result_x; + (void)result_y; + (void)num_bytes; + (void)verify_first; + return -1; #endif /* SOC_ECC_SUPPORTED */ +} diff --git a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h index 4fdf82c2f9c..90e6ef0c2e9 100644 --- a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h +++ b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h @@ -1,15 +1,20 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#pragma once + #include #include #include "soc/soc_caps.h" #if SOC_ECC_SUPPORTED +#include + int esp_tinycrypt_verify_ecc_point(const uint8_t *pk_x, const uint8_t *pk_y, uint8_t length); -int esp_tinycrypt_calc_ecc_mult(const uint8_t *p_x, const uint8_t *p_y, const uint8_t *scalar, - uint8_t *r_x, uint8_t *r_y, uint8_t num_bytes, bool verify_first); +int esp_tinycrypt_calc_ecc_mult(const uECC_word_t *point_x, const uECC_word_t *point_y, + const uECC_word_t *scalar, uECC_word_t *result_x, + uECC_word_t *result_y, uint8_t num_bytes, bool verify_first); #endif /* SOC_ECC_SUPPORTED */ diff --git a/components/bt/common/tinycrypt/src/ecc.c b/components/bt/common/tinycrypt/src/ecc.c index d35031be68d..72cc5f299dd 100644 --- a/components/bt/common/tinycrypt/src/ecc.c +++ b/components/bt/common/tinycrypt/src/ecc.c @@ -58,7 +58,6 @@ #include #include -#include #include #include @@ -664,7 +663,6 @@ void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z, uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ } -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER /* P = (x1, y1) => 2P, (x2, y2) => P' */ static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, uECC_word_t * Y2, @@ -730,7 +728,6 @@ static void XYcZ_addC(uECC_word_t * X1, uECC_word_t * Y1, uECC_vli_set(X1, t7, num_words); } -#endif /* !SOC_ECC_SUPPORTED */ void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, uECC_word_t * Y2, @@ -763,16 +760,28 @@ void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, const uECC_word_t * initial_Z, bitcount_t num_bits, uECC_Curve curve) { -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - wordcount_t num_words = curve->num_words; +#if SOC_ECC_SUPPORTED + wordcount_t num_words = curve->num_words; - /* Only p256r1 is supported currently. */ - assert (curve == uECC_secp256r1()); - - esp_tinycrypt_calc_ecc_mult((const uint8_t *)&point[0], (const uint8_t *)&point[num_words], - (uint8_t *)scalar, (uint8_t *)&result[0], (uint8_t *)&result[num_words], - num_words * uECC_WORD_SIZE, false); -#else + /* + * The ECC peripheral accepts canonical scalars only. Calls using the + * regularized software scalar use one additional bit and must stay on + * the software ladder. + */ + if (initial_Z == 0 && num_bits == curve->num_n_bits && + (curve == uECC_secp256r1() +#if uECC_SUPPORTS_secp192r1 + || curve == uECC_secp192r1() +#endif /* uECC_SUPPORTS_secp192r1 */ + )) { + if (esp_tinycrypt_calc_ecc_mult(point, point + num_words, scalar, + result, result + num_words, + num_words * uECC_WORD_SIZE, false) == 0) { + return; + } + } +#endif /* SOC_ECC_SUPPORTED */ + { /* R0 and R1 */ uECC_word_t Rx[2][NUM_ECC_WORDS]; uECC_word_t Ry[2][NUM_ECC_WORDS]; @@ -811,7 +820,7 @@ void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, uECC_vli_set(result, Rx[0], num_words); uECC_vli_set(result + num_words, Ry[0], num_words); -#endif /* SOC_ECC_SUPPORTED */ + } } uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, @@ -847,22 +856,33 @@ uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, uECC_word_t *private_key, uECC_Curve curve) { -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER +#if SOC_ECC_SUPPORTED + /* + * The ECC peripheral requires a canonical scalar. regularize_k() + * produces k + n or k + 2n for the software constant-time ladder, + * which is mathematically equivalent but outside the HW input range. + */ + if (curve == uECC_secp256r1() +#if uECC_SUPPORTS_secp192r1 + || curve == uECC_secp192r1() +#endif /* uECC_SUPPORTS_secp192r1 */ + ) { + EccPoint_mult(result, curve->G, private_key, 0, + curve->num_n_bits, curve); + return !EccPoint_isZero(result, curve); + } +#endif /* SOC_ECC_SUPPORTED */ + uECC_word_t tmp1[NUM_ECC_WORDS]; - uECC_word_t tmp2[NUM_ECC_WORDS]; + uECC_word_t tmp2[NUM_ECC_WORDS]; uECC_word_t *p2[2] = {tmp1, tmp2}; uECC_word_t carry; -#endif -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - EccPoint_mult(result, curve->G, private_key, 0, curve->num_n_bits, curve); -#else /* Regularize the bitcount for the private key so that attackers cannot * use a side channel attack to learn the number of leading zeros. */ carry = regularize_k(private_key, tmp1, tmp2, curve); EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve); -#endif if (EccPoint_isZero(result, curve)) { return 0; @@ -935,18 +955,20 @@ int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) return -2; } -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - /* Only p256r1 is supported currently. */ - if (curve != uECC_secp256r1()) { - return -5; - } - - if (esp_tinycrypt_verify_ecc_point((const uint8_t *)&point[0], - (const uint8_t *)&point[num_words], - num_words * uECC_WORD_SIZE)) { - return -3; - } -#else +#if SOC_ECC_SUPPORTED + if (curve == uECC_secp256r1() +#if uECC_SUPPORTS_secp192r1 + || curve == uECC_secp192r1() +#endif /* uECC_SUPPORTS_secp192r1 */ + ) { + if (esp_tinycrypt_verify_ecc_point((const uint8_t *)&point[0], + (const uint8_t *)&point[num_words], + num_words * uECC_WORD_SIZE) == 0) { + return 0; + } + } +#endif /* SOC_ECC_SUPPORTED */ + { uECC_word_t tmp1[NUM_ECC_WORDS]; uECC_word_t tmp2[NUM_ECC_WORDS]; @@ -954,9 +976,10 @@ int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ /* Make sure that y^2 == x^3 + ax + b */ - if (uECC_vli_equal(tmp1, tmp2, num_words) != 0) + if (uECC_vli_equal(tmp1, tmp2, num_words) != 0) { return -3; -#endif /* SOC_ECC_SUPPORTED */ + } + } return 0; } diff --git a/components/bt/common/tinycrypt/src/ecc_dh.c b/components/bt/common/tinycrypt/src/ecc_dh.c index eeee90d6aa2..d740a429eb8 100644 --- a/components/bt/common/tinycrypt/src/ecc_dh.c +++ b/components/bt/common/tinycrypt/src/ecc_dh.c @@ -147,11 +147,9 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, uECC_word_t _private[NUM_ECC_WORDS]; uECC_word_t tmp[NUM_ECC_WORDS]; -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER uECC_word_t *p2[2] = {_private, tmp}; uECC_word_t *initial_Z = 0; uECC_word_t carry; -#endif wordcount_t num_words = curve->num_words; wordcount_t num_bytes = curve->num_bytes; int r; @@ -167,11 +165,11 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, public_key + num_bytes, num_bytes); -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - EccPoint_mult(_public, _public, _private, 0, curve->num_n_bits, curve); -#else - /* Regularize the bitcount for the private key so that attackers cannot use a - * side channel attack to learn the number of leading zeros. */ + /* + * Use the software ladder for ECDH. Its regularized scalar is unsuitable + * for the ECC peripheral, and EccPoint_mult() can otherwise silently fall + * back to the software ladder with an unregularized scalar. + */ carry = regularize_k(_private, _private, tmp, curve); /* If an RNG function was specified, try to get a random initial Z value to @@ -187,17 +185,14 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); -#endif uECC_vli_nativeToBytes(secret, num_bytes, _public); r = !EccPoint_isZero(_public, curve); clear_and_out: /* erasing temporary buffer used to store secret: */ -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER memset(p2, 0, sizeof(p2)); __asm__ __volatile__("" :: "g"(p2) : "memory"); -#endif memset(_public, 0, sizeof(_public)); __asm__ __volatile__("" :: "g"(_public) : "memory"); memset(tmp, 0, sizeof(tmp)); diff --git a/components/bt/common/tinycrypt/src/ecc_dsa.c b/components/bt/common/tinycrypt/src/ecc_dsa.c index d167ee9104a..aef4bfe2fa9 100644 --- a/components/bt/common/tinycrypt/src/ecc_dsa.c +++ b/components/bt/common/tinycrypt/src/ecc_dsa.c @@ -101,10 +101,8 @@ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, uECC_word_t tmp[NUM_ECC_WORDS]; uECC_word_t s[NUM_ECC_WORDS]; -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER uECC_word_t *k2[2] = {tmp, s}; uECC_word_t carry; -#endif uECC_word_t p[NUM_ECC_WORDS * 2]; wordcount_t num_words = curve->num_words; wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); @@ -116,12 +114,8 @@ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, return 0; } -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - EccPoint_mult(p, curve->G, k, 0, num_n_bits, curve); -#else carry = regularize_k(k, tmp, s, curve); EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve); -#endif if (uECC_vli_isZero(p, num_words)) { return 0; } diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 05eb8804bd5..d53d8f2b863 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 05eb8804bd50c7bc68c8c752ff322c8052254a39 +Subproject commit d53d8f2b8639f5ee858f92d75efa80df6e6e1a52