esp32h2: Add support for ECDSA peripheral

This commit is contained in:
Sachin Parekh 2023-03-02 22:40:14 +05:30
parent 2002878eb9
commit d345c684ba
9 changed files with 612 additions and 0 deletions

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:
@ -163,6 +165,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
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 +247,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 +312,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

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