Merge branch 'h2/support-ecdsa' into 'master'

H2: Add support for ECDSA peripheral

Closes IDF-6287

See merge request espressif/esp-idf!22663
This commit is contained in:
Sachin Parekh 2023-03-24 17:11:36 +08:00
commit 089b11c989
18 changed files with 1008 additions and 6 deletions

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -62,7 +62,8 @@ typedef enum {
*/
typedef enum {
ESP_EFUSE_KEY_PURPOSE_USER = 0, /**< User purposes (software-only use) */
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1, /**< Reserved */
ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY = 1, /**< ECDSA private key (Expected in little endian order)*/
ESP_EFUSE_KEY_PURPOSE_RESERVED = 2, /**< Reserved (Used as a place holder)*/
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4, /**< XTS_AES_128_KEY (flash/PSRAM encryption) */
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5, /**< HMAC Downstream mode */
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6, /**< JTAG soft enable key (uses HMAC Downstream mode) */

View File

@ -287,6 +287,9 @@ esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpo
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 ||
#endif //#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS
#if SOC_ECDSA_SUPPORTED
purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY ||
#endif
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG ||
purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE ||

View File

@ -27,7 +27,8 @@ extern "C" {
typedef enum {
ETS_EFUSE_KEY_PURPOSE_USER = 0,
ETS_EFUSE_KEY_PURPOSE_RESERVED = 1,
ETS_EFUSE_KEY_PURPOSE_ECDSA_KEY = 1,
ETS_EFUSE_KEY_PURPOSE_RESERVED = 2,
ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4,
ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5,
ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6,

View File

@ -121,6 +121,10 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "ecc_hal.c")
endif()
if(CONFIG_SOC_ECDSA_SUPPORTED)
list(APPEND srcs "ecdsa_hal.c")
endif()
if(CONFIG_SOC_SHA_SUPPORTED)
list(APPEND srcs "sha_hal.c")
endif()

View File

@ -0,0 +1,99 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "hal/assert.h"
#include "hal/ecdsa_ll.h"
#include "hal/ecdsa_hal.h"
#define ECDSA_HAL_P192_COMPONENT_LEN 24
#define ECDSA_HAL_P256_COMPONENT_LEN 32
static void configure_ecdsa_periph(ecdsa_hal_config_t *conf)
{
ecdsa_ll_set_mode(conf->mode);
ecdsa_ll_set_curve(conf->curve);
ecdsa_ll_set_k_mode(conf->k_mode);
ecdsa_ll_set_z_mode(conf->sha_mode);
}
void ecdsa_hal_gen_signature(ecdsa_hal_config_t *conf, const uint8_t *k, const uint8_t *hash,
uint8_t *r_out, uint8_t *s_out, uint16_t len)
{
if (len != ECDSA_HAL_P192_COMPONENT_LEN && len != ECDSA_HAL_P256_COMPONENT_LEN) {
HAL_ASSERT(false && "Incorrect length");
}
if (conf->k_mode == ECDSA_K_USER_PROVIDED && k == NULL) {
HAL_ASSERT(false && "Mismatch in K configuration");
}
if (conf->sha_mode == ECDSA_Z_USER_PROVIDED && hash == NULL) {
HAL_ASSERT(false && "Mismatch in SHA configuration");
}
if (ecdsa_ll_get_state() != ECDSA_STATE_IDLE) {
HAL_ASSERT(false && "Incorrect ECDSA state");
}
configure_ecdsa_periph(conf);
ecdsa_ll_set_stage(ECDSA_STAGE_START_CALC);
while(ecdsa_ll_get_state() != ECDSA_STATE_LOAD) {
;
}
ecdsa_ll_set_stage(ECDSA_STAGE_LOAD_DONE);
while (ecdsa_ll_get_state() != ECDSA_STATE_GET) {
;
}
ecdsa_ll_read_param(ECDSA_PARAM_R, r_out, len);
ecdsa_ll_read_param(ECDSA_PARAM_S, s_out, len);
ecdsa_ll_set_stage(ECDSA_STAGE_GET_DONE);
while (ecdsa_ll_get_state() != ECDSA_STATE_IDLE) {
;
}
}
int ecdsa_hal_verify_signature(ecdsa_hal_config_t *conf, const uint8_t *hash, const uint8_t *r, const uint8_t *s,
const uint8_t *pub_x, const uint8_t *pub_y, uint16_t len)
{
if (len != ECDSA_HAL_P192_COMPONENT_LEN && len != ECDSA_HAL_P256_COMPONENT_LEN) {
HAL_ASSERT(false && "Incorrect length");
}
if (ecdsa_ll_get_state() != ECDSA_STATE_IDLE) {
HAL_ASSERT(false && "Incorrect ECDSA state");
}
configure_ecdsa_periph(conf);
ecdsa_ll_set_stage(ECDSA_STAGE_START_CALC);
while(ecdsa_ll_get_state() != ECDSA_STATE_LOAD) {
;
}
ecdsa_ll_write_param(ECDSA_PARAM_Z, hash, len);
ecdsa_ll_write_param(ECDSA_PARAM_R, r, len);
ecdsa_ll_write_param(ECDSA_PARAM_S, s, len);
ecdsa_ll_write_param(ECDSA_PARAM_QAX, pub_x, len);
ecdsa_ll_write_param(ECDSA_PARAM_QAY, pub_y, len);
ecdsa_ll_set_stage(ECDSA_STAGE_LOAD_DONE);
while (ecdsa_ll_get_state() != ECDSA_STATE_IDLE) {
;
}
int res = ecdsa_ll_get_verification_result();
return (res ? 0 : -1);
}

View File

@ -71,6 +71,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
return PCR_HMAC_CLK_EN;
case PERIPH_DS_MODULE:
return PCR_DS_CLK_EN;
case PERIPH_ECDSA_MODULE:
return PCR_ECDSA_CLK_EN;
case PERIPH_TEMPSENSOR_MODULE:
return PCR_TSENS_CLK_EN;
// case PERIPH_RNG_MODULE:
@ -139,6 +141,10 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
case PERIPH_TEMPSENSOR_MODULE:
return PCR_TSENS_RST_EN;
case PERIPH_ECC_MODULE:
if (enable == true) {
// Clear reset on ECDSA, otherwise ECC is held in reset
CLEAR_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN);
}
return PCR_ECC_RST_EN;
case PERIPH_AES_MODULE:
if (enable == true) {
@ -148,21 +154,25 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
return PCR_AES_RST_EN;
case PERIPH_SHA_MODULE:
if (enable == true) {
// Clear reset on digital signature and HMAC, otherwise SHA is held in reset
// Clear reset on digital signature, HMAC, and ECDSA, otherwise SHA is held in reset
CLEAR_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN);
CLEAR_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN);
CLEAR_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN);
}
return PCR_SHA_RST_EN;
case PERIPH_RSA_MODULE:
if (enable == true) {
// Clear reset on digital signature, otherwise RSA is held in reset
// Clear reset on digital signature, and ECDSA, otherwise RSA is held in reset
CLEAR_PERI_REG_MASK(PCR_DS_CONF_REG, PCR_DS_RST_EN);
CLEAR_PERI_REG_MASK(PCR_ECDSA_CONF_REG, PCR_ECDSA_RST_EN);
}
return PCR_RSA_RST_EN;
case PERIPH_HMAC_MODULE:
return PCR_HMAC_RST_EN;
case PERIPH_DS_MODULE:
return PCR_DS_RST_EN;
case PERIPH_ECDSA_MODULE:
return PCR_ECDSA_RST_EN;
// case PERIPH_RNG_MODULE:
// return PCR_WIFI_CLK_RNG_EN;
// case PERIPH_WIFI_MODULE:
@ -243,6 +253,8 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
return PCR_HMAC_CONF_REG;
case PERIPH_DS_MODULE:
return PCR_DS_CONF_REG;
case PERIPH_ECDSA_MODULE:
return PCR_ECDSA_CONF_REG;
case PERIPH_TEMPSENSOR_MODULE:
return PCR_TSENS_CLK_CONF_REG;
default:
@ -306,6 +318,8 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
return PCR_HMAC_CONF_REG;
case PERIPH_DS_MODULE:
return PCR_DS_CONF_REG;
case PERIPH_ECDSA_MODULE:
return PCR_ECDSA_CONF_REG;
case PERIPH_TEMPSENSOR_MODULE:
return PCR_TSENS_CLK_CONF_REG;
default:

View File

@ -0,0 +1,386 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <string.h>
#include "hal/assert.h"
#include "soc/ecdsa_reg.h"
#include "hal/ecdsa_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Memory blocks of ECDSA parameters
*/
typedef enum {
ECDSA_PARAM_R,
ECDSA_PARAM_S,
ECDSA_PARAM_Z,
ECDSA_PARAM_K,
ECDSA_PARAM_QAX,
ECDSA_PARAM_QAY
} ecdsa_ll_param_t;
/**
* @brief Interrupt types in ECDSA
*/
typedef enum {
ECDSA_INT_CALC_DONE,
ECDSA_INT_SHA_RELEASE,
} ecdsa_ll_intr_type_t;
/**
* @brief Stages of ECDSA operation
*/
typedef enum {
ECDSA_STAGE_START_CALC,
ECDSA_STAGE_LOAD_DONE,
ECDSA_STAGE_GET_DONE
} ecdsa_ll_stage_t;
/**
* @brief States of ECDSA peripheral
*/
typedef enum {
ECDSA_STATE_IDLE,
ECDSA_STATE_LOAD,
ECDSA_STATE_GET,
ECDSA_STATE_BUSY
} ecdsa_ll_state_t;
/**
* @brief Types of SHA
*/
typedef enum {
ECDSA_SHA_224,
ECDSA_SHA_256
} ecdsa_ll_sha_type_t;
/**
* @brief Operation modes of SHA
*/
typedef enum {
ECDSA_MODE_SHA_START,
ECDSA_MODE_SHA_CONTINUE
} ecdsa_ll_sha_mode_t;
/**
* @brief Enable interrupt of a given type
*
* @param type Interrupt type
*/
static inline void ecdsa_ll_enable_intr(ecdsa_ll_intr_type_t type)
{
switch (type) {
case ECDSA_INT_CALC_DONE:
REG_SET_FIELD(ECDSA_INT_ENA_REG, ECDSA_CALC_DONE_INT_ENA, 1);
break;
case ECDSA_INT_SHA_RELEASE:
REG_SET_FIELD(ECDSA_INT_ENA_REG, ECDSA_SHA_RELEASE_INT_ENA, 1);
break;
default:
HAL_ASSERT(false && "Unsupported interrupt type");
break;
}
}
/**
* @brief Disable interrupt of a given type
*
* @param type Interrupt type
*/
static inline void ecdsa_ll_disable_intr(ecdsa_ll_intr_type_t type)
{
switch (type) {
case ECDSA_INT_CALC_DONE:
REG_SET_FIELD(ECDSA_INT_ENA_REG, ECDSA_CALC_DONE_INT_ENA, 0);
break;
case ECDSA_INT_SHA_RELEASE:
REG_SET_FIELD(ECDSA_INT_ENA_REG, ECDSA_SHA_RELEASE_INT_ENA, 0);
break;
default:
HAL_ASSERT(false && "Unsupported interrupt type");
break;
}
}
/**
* @brief Clear interrupt of a given type
*
* @param type Interrupt type
*/
static inline void ecdsa_ll_clear_intr(ecdsa_ll_intr_type_t type)
{
switch (type) {
case ECDSA_INT_CALC_DONE:
REG_SET_FIELD(ECDSA_INT_CLR_REG, ECDSA_CALC_DONE_INT_CLR, 1);
break;
case ECDSA_INT_SHA_RELEASE:
REG_SET_FIELD(ECDSA_INT_CLR_REG, ECDSA_SHA_RELEASE_INT_CLR, 1);
break;
default:
HAL_ASSERT(false && "Unsupported interrupt type");
break;
}
}
/**
* @brief Set working mode of ECDSA
*
* @param mode Mode of operation
*/
static inline void ecdsa_ll_set_mode(ecdsa_mode_t mode)
{
switch (mode) {
case ECDSA_MODE_SIGN_VERIFY:
REG_SET_FIELD(ECDSA_CONF_REG, ECDSA_WORK_MODE, 0);
break;
case ECDSA_MODE_SIGN_GEN:
REG_SET_FIELD(ECDSA_CONF_REG, ECDSA_WORK_MODE, 1);
break;
default:
HAL_ASSERT(false && "Unsupported mode");
break;
}
}
/**
* @brief Set curve for ECDSA operation
*
* @param curve ECDSA curve
*/
static inline void ecdsa_ll_set_curve(ecdsa_curve_t curve)
{
switch (curve) {
case ECDSA_CURVE_SECP256R1:
REG_SET_BIT(ECDSA_CONF_REG, ECDSA_ECC_CURVE);
break;
case ECDSA_CURVE_SECP192R1:
REG_CLR_BIT(ECDSA_CONF_REG, ECDSA_ECC_CURVE);
break;
default:
HAL_ASSERT(false && "Unsupported curve");
return;
}
}
/**
* @brief Set the source of `K`
*
* @param mode Mode of K generation
*/
static inline void ecdsa_ll_set_k_mode(ecdsa_k_mode_t mode)
{
switch (mode) {
case ECDSA_K_USE_TRNG:
REG_CLR_BIT(ECDSA_CONF_REG, ECDSA_SOFTWARE_SET_K);
break;
case ECDSA_K_USER_PROVIDED:
REG_SET_BIT(ECDSA_CONF_REG, ECDSA_SOFTWARE_SET_K);
break;
default:
HAL_ASSERT(false && "Unsupported curve");
break;
}
}
/**
* @brief Set the source of `Z` (SHA message)
*
* @param mode Mode of SHA generation
*/
static inline void ecdsa_ll_set_z_mode(ecdsa_ll_sha_mode_t mode)
{
switch (mode) {
case ECDSA_Z_USE_SHA_PERI:
REG_CLR_BIT(ECDSA_CONF_REG, ECDSA_SOFTWARE_SET_Z);
break;
case ECDSA_Z_USER_PROVIDED:
REG_SET_BIT(ECDSA_CONF_REG, ECDSA_SOFTWARE_SET_Z);
break;
default:
HAL_ASSERT(false && "Unsupported curve");
break;
}
}
/**
* @brief Set the stage of ECDSA operation
*
* @param stage Stage of operation
*/
static inline void ecdsa_ll_set_stage(ecdsa_ll_stage_t stage)
{
switch (stage) {
case ECDSA_STAGE_START_CALC:
REG_SET_BIT(ECDSA_START_REG, ECDSA_START);
break;
case ECDSA_STAGE_LOAD_DONE:
REG_SET_BIT(ECDSA_START_REG, ECDSA_LOAD_DONE);
break;
case ECDSA_STAGE_GET_DONE:
REG_SET_BIT(ECDSA_START_REG, ECDSA_GET_DONE);
break;
default:
HAL_ASSERT(false && "Unsupported state");
break;
}
}
/**
* @brief Get the state of ECDSA peripheral
*
* @return State of ECDSA
*/
static inline ecdsa_ll_state_t ecdsa_ll_get_state(void)
{
return REG_GET_FIELD(ECDSA_STATE_REG, ECDSA_BUSY);
}
/**
* @brief Set the SHA type
*
* @param type Type of SHA
*/
static inline void ecdsa_ll_sha_set_type(ecdsa_ll_sha_type_t type)
{
switch (type) {
case ECDSA_SHA_224:
REG_SET_FIELD(ECDSA_SHA_MODE_REG, ECDSA_SHA_MODE, 1);
break;
case ECDSA_SHA_256:
REG_SET_FIELD(ECDSA_SHA_MODE_REG, ECDSA_SHA_MODE, 2);
break;
default:
HAL_ASSERT(false && "Unsupported type");
break;
}
}
/**
* @brief Set the SHA operation mode
*
* @param mode Mode of SHA operation
*/
static inline void ecdsa_ll_sha_set_mode(ecdsa_ll_sha_mode_t mode)
{
switch (mode) {
case ECDSA_MODE_SHA_START:
REG_SET_BIT(ECDSA_SHA_START_REG, ECDSA_SHA_START);
break;
case ECDSA_MODE_SHA_CONTINUE:
REG_SET_BIT(ECDSA_SHA_CONTINUE_REG, ECDSA_SHA_CONTINUE);
break;
default:
HAL_ASSERT(false && "Unsupported type");
break;
}
}
/**
* @brief Check if SHA is busy
*
* @return - true, if SHA is busy
* - false, if SHA is IDLE
*/
static inline bool ecdsa_ll_sha_is_busy(void)
{
return REG_GET_BIT(ECDSA_SHA_BUSY_REG, ECDSA_SHA_BUSY);
}
/**
* @brief Write the ECDSA parameter
*
* @param param Parameter to be writen
* @param buf Buffer containing data
* @param len Length of buffer
*/
static inline void ecdsa_ll_write_param(ecdsa_ll_param_t param, const uint8_t *buf, uint16_t len)
{
uint32_t reg;
uint32_t word;
switch (param) {
case ECDSA_PARAM_R:
reg = ECDSA_R_MEM;
break;
case ECDSA_PARAM_S:
reg = ECDSA_S_MEM;
break;
case ECDSA_PARAM_Z:
reg = ECDSA_Z_MEM;
break;
case ECDSA_PARAM_K:
case ECDSA_PARAM_QAX:
reg = ECDSA_QAX_MEM;
break;
case ECDSA_PARAM_QAY:
reg = ECDSA_QAY_MEM;
break;
default:
HAL_ASSERT(false && "Invalid parameter");
return;
}
for (int i = 0; i < len; i += 4) {
memcpy(&word, buf + i, 4);
REG_WRITE(reg + i, word);
}
}
/**
* @brief Read the ECDSA parameter
*
* @param param Parameter to be read
* @param buf Buffer where the data will be written
* @param len Length of buffer
*/
static inline void ecdsa_ll_read_param(ecdsa_ll_param_t param, uint8_t *buf, uint16_t len)
{
uint32_t reg;
switch (param) {
case ECDSA_PARAM_R:
reg = ECDSA_R_MEM;
break;
case ECDSA_PARAM_S:
reg = ECDSA_S_MEM;
break;
case ECDSA_PARAM_Z:
reg = ECDSA_Z_MEM;
break;
case ECDSA_PARAM_K:
case ECDSA_PARAM_QAX:
reg = ECDSA_QAX_MEM;
break;
case ECDSA_PARAM_QAY:
reg = ECDSA_QAY_MEM;
break;
default:
HAL_ASSERT(false && "Invalid parameter");
return;
}
memcpy(buf, (void *)reg, len);
}
/**
* @brief Get result of ECDSA verification operation
*
* This is only valid for ECDSA verify mode
*
* @return - 1, if signature verification succeeds
* - 0, otherwise
*/
static inline int ecdsa_ll_get_verification_result(void)
{
return REG_GET_BIT(ECDSA_RESULT_REG, ECDSA_OPERATION_RESULT);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The HAL is not public api, don't use in application code.
* See readme.md in soc/README.md
******************************************************************************/
#pragma once
#include <stdint.h>
#include "hal/ecdsa_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* ECDSA peripheral config structure
*/
typedef struct {
ecdsa_mode_t mode; /* Mode of operation */
ecdsa_curve_t curve; /* Curve to use for operation */
ecdsa_k_mode_t k_mode; /* Source of K */
ecdsa_sha_mode_t sha_mode; /* Source of SHA that needs to be signed */
} ecdsa_hal_config_t;
/**
* @brief Generate ECDSA signature
*
* @param conf Configuration for ECDSA operation, see ``ecdsa_hal_config_t``
* @param k Value of K used internally. Set this to NULL if K is generated by hardware
* @param hash Hash that is to be signed
* @param r_out Buffer that will contain `R` component of ECDSA signature
* @param s_out Buffer that will contain `S` component of ECDSA signature
* @param len Length of the r_out and s_out buffer (32 bytes for SECP256R1, 24 for SECP192R1)
*/
void ecdsa_hal_gen_signature(ecdsa_hal_config_t *conf, const uint8_t *k, const uint8_t *hash,
uint8_t *r_out, uint8_t *s_out, uint16_t len);
/**
* @brief Verify given ECDSA signature
*
* @param conf Configuration for ECDSA operation, see ``ecdsa_hal_config_t``
* @param hash Hash that was signed
* @param r `R` component of ECDSA signature
* @param s `S` component of ECDSA signature
* @param pub_x X coordinate of public key
* @param pub_y Y coordinate of public key
* @param len Length of r and s buffer (32 bytes for SECP256R1, 24 for SECP192R1)
*
* @return - 0, if the signature matches
* - -1, if verification fails
*/
int ecdsa_hal_verify_signature(ecdsa_hal_config_t *conf, const uint8_t *hash, const uint8_t *r, const uint8_t *s,
const uint8_t *pub_x, const uint8_t *pub_y, uint16_t len);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ECDSA peripheral work modes
*/
typedef enum {
ECDSA_MODE_SIGN_VERIFY,
ECDSA_MODE_SIGN_GEN,
} ecdsa_mode_t;
/**
* @brief ECDSA curve options
*/
typedef enum {
ECDSA_CURVE_SECP192R1,
ECDSA_CURVE_SECP256R1,
} ecdsa_curve_t;
/**
* @brief Source of 'K' used internally for generating signature
*/
typedef enum {
ECDSA_K_USE_TRNG,
ECDSA_K_USER_PROVIDED,
} ecdsa_k_mode_t;
/**
* @brief Source of SHA message that is to be signed/verified
*/
typedef enum {
ECDSA_Z_USE_SHA_PERI,
ECDSA_Z_USER_PROVIDED,
} ecdsa_sha_mode_t;
#ifdef __cplusplus
}
#endif

View File

@ -235,6 +235,18 @@ if(CONFIG_MBEDTLS_HARDWARE_ECC)
"${COMPONENT_DIR}/port/ecc/ecc_alt.c")
endif()
if(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN OR CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY)
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/ecdsa/ecdsa_alt.c")
if(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=mbedtls_ecdsa_sign")
endif()
if(CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=mbedtls_ecdsa_verify")
endif()
endif()
if(CONFIG_MBEDTLS_ROM_MD5)
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/md/esp_md.c")
endif()
@ -267,6 +279,10 @@ if(CONFIG_PM_ENABLE)
target_link_libraries(mbedcrypto PRIVATE idf::esp_pm)
endif()
if(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN OR CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY)
target_link_libraries(mbedcrypto PRIVATE idf::efuse)
endif()
target_link_libraries(${COMPONENT_LIB} ${linkage_type} ${mbedtls_targets})
if(CONFIG_ESP_TLS_USE_DS_PERIPHERAL)

View File

@ -455,6 +455,29 @@ menu "mbedTLS"
help
Use ROM MD5 in mbedTLS.
config MBEDTLS_HARDWARE_ECDSA_SIGN
bool "Enable ECDSA signing using on-chip ECDSA peripheral"
default n
depends on SOC_ECDSA_SUPPORTED
help
Enable hardware accelerated ECDSA peripheral to sign data
on curve SECP192R1 and SECP256R1 in mbedTLS.
Note that for signing, the private key has to be burnt in an efuse key block
with key purpose set to ECDSA_KEY.
If no key is burnt, it will report an error
The key should be burnt in little endian format. espefuse.py utility handles it internally
but care needs to be taken while burning using esp_efuse APIs
config MBEDTLS_HARDWARE_ECDSA_VERIFY
bool "Enable ECDSA signature verification using on-chip ECDSA peripheral"
default y
depends on SOC_ECDSA_SUPPORTED
help
Enable hardware accelerated ECDSA peripheral to verify signature
on curve SECP192R1 and SECP256R1 in mbedTLS.
config MBEDTLS_ATCA_HW_ECDSA_SIGN
bool "Enable hardware ECDSA sign acceleration when using ATECC608A"
default n

View File

@ -0,0 +1,276 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "hal/ecdsa_hal.h"
#include "esp_efuse.h"
#include "mbedtls/ecp.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/platform_util.h"
#include "esp_private/periph_ctrl.h"
#include "ecdsa/ecdsa_alt.h"
#define ECDSA_KEY_MAGIC 0xECD5A
#define ECDSA_SHA_LEN 32
#define MAX_ECDSA_COMPONENT_LEN 32
__attribute__((unused)) static const char *TAG = "ecdsa_alt";
static _lock_t s_crypto_ecdsa_lock;
static void esp_ecdsa_acquire_hardware(void)
{
_lock_acquire(&s_crypto_ecdsa_lock);
periph_module_enable(PERIPH_ECDSA_MODULE);
}
static void esp_ecdsa_release_hardware(void)
{
periph_module_disable(PERIPH_ECDSA_MODULE);
_lock_release(&s_crypto_ecdsa_lock);
}
static void ecdsa_be_to_le(const uint8_t* be_point, uint8_t *le_point, uint8_t len)
{
/* When the size is 24 bytes, it should be padded with 0 bytes*/
memset(le_point, 0x0, 32);
for(int i = 0; i < len; i++) {
le_point[i] = be_point[len - i - 1];
}
}
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
int esp_ecdsa_privkey_load_mpi(mbedtls_mpi *key, int efuse_blk)
{
if (!key) {
ESP_LOGE(TAG, "Invalid memory");
return -1;
}
if (efuse_blk < EFUSE_BLK_KEY0 || efuse_blk >= EFUSE_BLK_KEY_MAX) {
ESP_LOGE(TAG, "Invalid efuse block");
return -1;
}
mbedtls_mpi_init(key);
/* We use the mbedtls_mpi struct to pass our own context to hardware ECDSA peripheral
* MPI struct expects `s` to be either 1 or -1, by setting it to 0xECD5A, we ensure that it does
* not collide with a valid MPI. This is done to differentiate between using the private key stored in efuse
* or using the private key provided by software
*
* `n` is used to store the efuse block which should be used as key
*/
key->MBEDTLS_PRIVATE(s) = ECDSA_KEY_MAGIC;
key->MBEDTLS_PRIVATE(n) = efuse_blk;
key->MBEDTLS_PRIVATE(p) = NULL;
return 0;
}
int esp_ecdsa_privkey_load_pk_context(mbedtls_pk_context *key_ctx, int efuse_blk)
{
const mbedtls_pk_info_t *pk_info;
mbedtls_ecp_keypair *keypair;
if (!key_ctx) {
ESP_LOGE(TAG, "Invalid memory");
return -1;
}
if (efuse_blk < EFUSE_BLK_KEY0 || efuse_blk >= EFUSE_BLK_KEY_MAX) {
ESP_LOGE(TAG, "Invalid efuse block");
return -1;
}
mbedtls_pk_init(key_ctx);
pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECDSA);
mbedtls_pk_setup(key_ctx, pk_info);
keypair = mbedtls_pk_ec(*key_ctx);
return esp_ecdsa_privkey_load_mpi(&(keypair->MBEDTLS_PRIVATE(d)), efuse_blk);
}
static int esp_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi* r, mbedtls_mpi* s,
const mbedtls_mpi *d, const unsigned char* msg, size_t msg_len)
{
ecdsa_curve_t curve;
esp_efuse_block_t blk;
uint16_t len;
uint8_t zeroes[MAX_ECDSA_COMPONENT_LEN] = {0};
uint8_t sha_le[ECDSA_SHA_LEN];
uint8_t r_le[MAX_ECDSA_COMPONENT_LEN];
uint8_t s_le[MAX_ECDSA_COMPONENT_LEN];
if (!grp || !r || !s || !d || !msg) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
if (msg_len != ECDSA_SHA_LEN) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
if (grp->id == MBEDTLS_ECP_DP_SECP192R1) {
curve = ECDSA_CURVE_SECP192R1;
len = 24;
} else if (grp->id == MBEDTLS_ECP_DP_SECP256R1) {
curve = ECDSA_CURVE_SECP256R1;
len = 32;
} else {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
if (!esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY, &blk)) {
ESP_LOGE(TAG, "No efuse block with purpose ECDSA_KEY found");
return MBEDTLS_ERR_ECP_INVALID_KEY;
}
ecdsa_be_to_le(msg, sha_le, len);
esp_ecdsa_acquire_hardware();
do {
ecdsa_hal_config_t conf = {
.mode = ECDSA_MODE_SIGN_GEN,
.curve = curve,
.k_mode = ECDSA_K_USE_TRNG,
.sha_mode = ECDSA_Z_USER_PROVIDED,
};
ecdsa_hal_gen_signature(&conf, NULL, sha_le, r_le, s_le, len);
} while (!memcmp(r_le, zeroes, len) || !memcmp(s_le, zeroes, len));
esp_ecdsa_release_hardware();
mbedtls_mpi_read_binary_le(r, r_le, len);
mbedtls_mpi_read_binary_le(s, s_le, len);
return 0;
}
/*
* Compute ECDSA signature of a hashed message;
*/
extern int __real_mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
int __wrap_mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
int __wrap_mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
/*
* Check `d` whether it contains the hardware key
*/
if (d->MBEDTLS_PRIVATE(s) == ECDSA_KEY_MAGIC) {
// Use hardware ECDSA peripheral
return esp_ecdsa_sign(grp, r, s, d, buf, blen);
} else {
return __real_mbedtls_ecdsa_sign(grp, r, s, d, buf, blen, f_rng, p_rng);
}
}
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN */
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY
static int esp_ecdsa_verify(mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen,
const mbedtls_ecp_point *Q,
const mbedtls_mpi *r,
const mbedtls_mpi *s)
{
ecdsa_curve_t curve;
uint16_t len;
uint8_t r_le[MAX_ECDSA_COMPONENT_LEN];
uint8_t s_le[MAX_ECDSA_COMPONENT_LEN];
uint8_t qx_le[MAX_ECDSA_COMPONENT_LEN];
uint8_t qy_le[MAX_ECDSA_COMPONENT_LEN];
uint8_t sha_le[ECDSA_SHA_LEN];
if (!grp || !buf || !Q || !r || !s) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
if (blen != ECDSA_SHA_LEN) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
if (grp->id == MBEDTLS_ECP_DP_SECP192R1) {
curve = ECDSA_CURVE_SECP192R1;
len = 24;
} else if (grp->id == MBEDTLS_ECP_DP_SECP256R1) {
curve = ECDSA_CURVE_SECP256R1;
len = 32;
} else {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
if (mbedtls_mpi_cmp_int(r, 1) < 0 || mbedtls_mpi_cmp_mpi(r, &grp->N) >= 0 ||
mbedtls_mpi_cmp_int(s, 1) < 0 || mbedtls_mpi_cmp_mpi(s, &grp->N) >= 0 )
{
return MBEDTLS_ERR_ECP_VERIFY_FAILED;
}
ecdsa_be_to_le(buf, sha_le, len);
mbedtls_mpi_write_binary_le(&Q->MBEDTLS_PRIVATE(X), qx_le, len);
mbedtls_mpi_write_binary_le(&Q->MBEDTLS_PRIVATE(Y), qy_le, len);
mbedtls_mpi_write_binary_le(r, r_le, len);
mbedtls_mpi_write_binary_le(s, s_le, len);
esp_ecdsa_acquire_hardware();
ecdsa_hal_config_t conf = {
.mode = ECDSA_MODE_SIGN_VERIFY,
.curve = curve,
.k_mode = ECDSA_K_USE_TRNG,
.sha_mode = ECDSA_Z_USER_PROVIDED,
};
int ret = ecdsa_hal_verify_signature(&conf, sha_le, r_le, s_le, qx_le, qy_le, len);
esp_ecdsa_release_hardware();
if (ret != 0) {
return MBEDTLS_ERR_ECP_VERIFY_FAILED;
}
return ret;
}
/*
* Verify ECDSA signature of hashed message
*/
extern int __real_mbedtls_ecdsa_verify(mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen,
const mbedtls_ecp_point *Q,
const mbedtls_mpi *r,
const mbedtls_mpi *s);
int __wrap_mbedtls_ecdsa_verify(mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen,
const mbedtls_ecp_point *Q,
const mbedtls_mpi *r,
const mbedtls_mpi *s);
int __wrap_mbedtls_ecdsa_verify(mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen,
const mbedtls_ecp_point *Q,
const mbedtls_mpi *r,
const mbedtls_mpi *s)
{
if (grp->id == MBEDTLS_ECP_DP_SECP192R1 || grp->id == MBEDTLS_ECP_DP_SECP256R1) {
return esp_ecdsa_verify(grp, buf, blen, Q, r, s);
} else {
return __real_mbedtls_ecdsa_verify(grp, buf, blen, Q, r, s);
}
}
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY */

View File

@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#include "mbedtls/pk.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
/**
* @brief Initialize MPI to notify mbedtls_ecdsa_sign to use the private key in efuse
* We break the MPI struct of the private key in order to
* differentiate between hardware key and software key
*
* @note Currently, `efuse_blk` is not used internally.
* Hardware will choose the efuse block that has purpose set to ECDSA_KEY.
* In case of multiple ECDSA_KEY burnt in efuse, hardware will choose the
* greater efuse block number as the private key.
*
* @param key The MPI in which this functions stores the hardware context.
* This must be uninitialized
* @param efuse_blk The efuse key block that should be used as the private key.
* The key purpose of this block must be ECDSA_KEY
*
* @return - 0 if successful
* - -1 otherwise
*
*/
int esp_ecdsa_privkey_load_mpi(mbedtls_mpi *key, int efuse_blk);
/**
* @brief Initialize PK context to notify mbedtls_ecdsa_sign to use the private key in efuse
* We break the MPI struct used to represent the private key `d` in ECP keypair
* in order to differentiate between hardware key and software key
*
* @note Currently, `efuse_blk` is not used internally.
* Hardware will choose the efuse block that has purpose set to ECDSA_KEY.
* In case of multiple ECDSA_KEY burnt in efuse, hardware will choose the
* greater efuse block number as the private key.
*
* @param key_ctx The context in which this functions stores the hardware context.
* This must be uninitialized
* @param efuse_blk The efuse key block that should be used as the private key.
* The key purpose of this block must be ECDSA_KEY
*
* @return - 0 if successful
* - -1 otherwise
*/
int esp_ecdsa_privkey_load_pk_context(mbedtls_pk_context *key_ctx, int efuse_blk);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -224,6 +224,7 @@
#undef MBEDTLS_ECP_VERIFY_ALT
#undef MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK
#endif
/**
* \def MBEDTLS_ENTROPY_HARDWARE_ALT
*

View File

@ -30,7 +30,7 @@
#define NEWLIB_NANO_COMPAT_CAST(int64_t_var) int64_t_var
#endif
#if CONFIG_MBEDTLS_HARDWARE_ECC
#if CONFIG_MBEDTLS_HARDWARE_ECC || CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY
/*
* All the following values are in big endian format, as required by the mbedTLS APIs

View File

@ -143,6 +143,10 @@ config SOC_ECC_EXTENDED_MODES_SUPPORTED
bool
default y
config SOC_ECDSA_SUPPORTED
bool
default y
config SOC_FLASH_ENC_SUPPORTED
bool
default y

View File

@ -38,6 +38,7 @@ typedef enum {
PERIPH_ECC_MODULE,
PERIPH_HMAC_MODULE,
PERIPH_DS_MODULE,
PERIPH_ECDSA_MODULE,
PERIPH_GDMA_MODULE,
PERIPH_MCPWM0_MODULE,
PERIPH_ETM_MODULE,

View File

@ -61,6 +61,7 @@
#define SOC_DIG_SIGN_SUPPORTED 1
#define SOC_ECC_SUPPORTED 1
#define SOC_ECC_EXTENDED_MODES_SUPPORTED 1
#define SOC_ECDSA_SUPPORTED 1
#define SOC_FLASH_ENC_SUPPORTED 1
#define SOC_SECURE_BOOT_SUPPORTED 1
#define SOC_BOD_SUPPORTED 1