fix(nimble): Fix ECC HW byte-order and dropped SOC_ESP_NIMBLE_CONTROLLER

This commit is contained in:
Rahul Tank
2026-07-16 10:30:17 +05:30
committed by BOT
parent 98ee8310b5
commit 891278ef2a
5 changed files with 150 additions and 81 deletions

View File

@@ -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 <string.h>
#include "esp_crypto_lock.h"
#include "esp_private/esp_crypto_lock_internal.h"
#include "esp_crypto_periph_clk.h"
#include <tinycrypt/ecc.h>
#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 */
}

View File

@@ -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 <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#if SOC_ECC_SUPPORTED
#include <tinycrypt/ecc.h>
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 */

View File

@@ -58,7 +58,6 @@
#include <tinycrypt/ecc.h>
#include <tinycrypt/ecc_platform_specific.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
@@ -699,7 +698,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,
@@ -765,7 +763,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,
@@ -798,20 +795,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 and p192r1 are supported currently. */
assert(curve == uECC_secp256r1()
/*
* 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 /* #if uECC_SUPPORTS_secp192r1 */
);
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
|| 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];
@@ -850,7 +855,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,
@@ -886,22 +891,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;
@@ -974,21 +990,20 @@ int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve)
return -2;
}
#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER
if (curve != uECC_secp256r1()
#if SOC_ECC_SUPPORTED
if (curve == uECC_secp256r1()
#if uECC_SUPPORTS_secp192r1
&& curve != uECC_secp192r1()
|| curve == uECC_secp192r1()
#endif /* uECC_SUPPORTS_secp192r1 */
) {
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 (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];
@@ -996,9 +1011,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;
}

View File

@@ -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));

View File

@@ -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;
}