Merge branch 'esp32p4/add_ecdsa_support' into 'master'

esp32p4: add ecdsa support

Closes IDF-7546

See merge request espressif/esp-idf!25191
This commit is contained in:
Mahavir Jain 2023-09-08 11:20:36 +08:00
commit 31e37c8313
13 changed files with 763 additions and 18 deletions

View File

@ -62,7 +62,7 @@ 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_XTS_AES_256_KEY_1 = 2, /**< XTS_AES_256_KEY_1 (flash/PSRAM encryption) */
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 = 3, /**< XTS_AES_256_KEY_2 (flash/PSRAM encryption) */
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4, /**< XTS_AES_128_KEY (flash/PSRAM encryption) */

View File

@ -9,17 +9,30 @@
#include "hal/ecdsa_hal.h"
#include "hal/efuse_hal.h"
#ifdef SOC_KEY_MANAGER_SUPPORTED
#include "soc/keymng_reg.h" // TODO: IDF-7901
#endif
#define ECDSA_HAL_P192_COMPONENT_LEN 24
#define ECDSA_HAL_P256_COMPONENT_LEN 32
static void configure_ecdsa_periph(ecdsa_hal_config_t *conf)
{
efuse_hal_set_ecdsa_key(conf->efuse_key_blk);
#ifdef SOC_KEY_MANAGER_SUPPORTED
REG_SET_FIELD(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY, 1); // TODO: IDF-7901
#endif
if (conf->use_km_key == 0) {
efuse_hal_set_ecdsa_key(conf->efuse_key_blk);
}
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);
if (conf->mode != ECDSA_MODE_EXPORT_PUBKEY) {
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,
@ -102,3 +115,39 @@ int ecdsa_hal_verify_signature(ecdsa_hal_config_t *conf, const uint8_t *hash, co
return (res ? 0 : -1);
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
void ecdsa_hal_export_pubkey(ecdsa_hal_config_t *conf, uint8_t *pub_x, 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_set_stage(ECDSA_STAGE_LOAD_DONE);
while (ecdsa_ll_get_state() != ECDSA_STATE_GET) {
;
}
ecdsa_ll_read_param(ECDSA_PARAM_QAX, pub_x, len);
ecdsa_ll_read_param(ECDSA_PARAM_QAY, pub_y, len);
ecdsa_ll_set_stage(ECDSA_STAGE_GET_DONE);
while (ecdsa_ll_get_state() != ECDSA_STATE_IDLE) {
;
}
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */

View File

@ -195,14 +195,18 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
case PERIPH_DS_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_CRYPTO | HP_SYS_CLKRST_REG_RST_EN_DS;
case PERIPH_ECC_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_CRYPTO | HP_SYS_CLKRST_REG_RST_EN_ECC;
ret = HP_SYS_CLKRST_REG_RST_EN_CRYPTO | HP_SYS_CLKRST_REG_RST_EN_ECC;
if (enable == true) {
ret |= HP_SYS_CLKRST_REG_RST_EN_ECDSA;
}
return ret;
case PERIPH_HMAC_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_CRYPTO | HP_SYS_CLKRST_REG_RST_EN_HMAC;
case PERIPH_RSA_MODULE:
ret = HP_SYS_CLKRST_REG_RST_EN_CRYPTO | HP_SYS_CLKRST_REG_RST_EN_RSA;
if (enable == true) {
// Clear reset on digital signature, otherwise RSA is held in reset
ret |= HP_SYS_CLKRST_REG_RST_EN_DS;
// Clear reset on digital signature, and ECDSA, otherwise RSA is held in reset
ret |= HP_SYS_CLKRST_REG_RST_EN_DS | HP_SYS_CLKRST_REG_RST_EN_ECDSA;
}
return ret;
case PERIPH_SEC_MODULE:

View File

@ -0,0 +1,389 @@
/*
* 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;
case ECDSA_MODE_EXPORT_PUBKEY:
REG_SET_FIELD(ECDSA_CONF_REG, ECDSA_WORK_MODE, 2);
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 uint32_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

@ -85,6 +85,11 @@ __attribute__((always_inline)) static inline uint32_t efuse_ll_get_chip_ver_pkg(
return 0;
}
__attribute__((always_inline)) static inline void efuse_ll_set_ecdsa_key_blk(int efuse_blk)
{
EFUSE.conf.cfg_ecdsa_blk = efuse_blk;
}
/******************* eFuse control functions *************************/
__attribute__((always_inline)) static inline bool efuse_ll_get_read_cmd(void)
@ -123,6 +128,11 @@ __attribute__((always_inline)) static inline void efuse_ll_set_pwr_off_num(uint1
EFUSE.wr_tim_conf2.pwr_off_num = value;
}
__attribute__((always_inline)) static inline void efuse_ll_rs_bypass_update(void)
{
EFUSE.wr_tim_conf0_rs_bypass.update = 1;
}
/******************* eFuse control functions *************************/
#ifdef __cplusplus

View File

@ -12,8 +12,10 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "hal/ecdsa_types.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
@ -28,6 +30,7 @@ typedef struct {
ecdsa_k_mode_t k_mode; /* Source of K */
ecdsa_sha_mode_t sha_mode; /* Source of SHA that needs to be signed */
int efuse_key_blk; /* Efuse block to use as ECDSA key (The purpose of the efuse block must be ECDSA_KEY) */
bool use_km_key; /* Use an ECDSA key from the Key Manager peripheral */
} ecdsa_hal_config_t;
/**
@ -59,6 +62,19 @@ void ecdsa_hal_gen_signature(ecdsa_hal_config_t *conf, const uint8_t *k, const u
*/
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 SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
/**
* @brief Export public key coordinates of an ECDSA private key
*
* @param conf Configuration for ECDSA operation, see ``ecdsa_hal_config_t``
* @param pub_x X coordinate of public key
* @param pub_y Y coordinate of public key
* @param len Length of pub_x and pub_y buffers (32 bytes for SECP256R1, 24 for SECP192R1)
*/
void ecdsa_hal_export_pubkey(ecdsa_hal_config_t *conf, uint8_t *pub_x, uint8_t *pub_y, uint16_t len);
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#ifdef __cplusplus
}
#endif

View File

@ -15,6 +15,7 @@ extern "C" {
typedef enum {
ECDSA_MODE_SIGN_VERIFY,
ECDSA_MODE_SIGN_GEN,
ECDSA_MODE_EXPORT_PUBKEY,
} ecdsa_mode_t;
/**

View File

@ -106,7 +106,7 @@ static void test_ecdsa_corrupt_data(bool is_p256, uint8_t* sha, uint8_t* r_le, u
}
static void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le)
static void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key)
{
uint8_t sha_le[32] = {0};
uint8_t zeroes[32] = {0};
@ -116,15 +116,20 @@ static void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t*
.mode = ECDSA_MODE_SIGN_GEN,
.k_mode = ECDSA_K_USE_TRNG,
.sha_mode = ECDSA_Z_USER_PROVIDED,
.use_km_key = use_km_key,
};
if (is_p256) {
conf.curve = ECDSA_CURVE_SECP256R1;
conf.efuse_key_blk = 6;
if (use_km_key == 0) {
conf.efuse_key_blk = 6;
}
len = 32;
} else {
conf.curve = ECDSA_CURVE_SECP192R1;
conf.efuse_key_blk = 5;
if (use_km_key == 0) {
conf.efuse_key_blk = 5;
}
len = 24;
}
@ -140,16 +145,57 @@ static void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t*
ecdsa_disable_and_reset();
}
static void test_ecdsa_sign_and_verify(bool is_p256, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y)
static void test_ecdsa_sign_and_verify(bool is_p256, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key)
{
uint8_t r_le[32] = {0};
uint8_t s_le[32] = {0};
test_ecdsa_sign(is_p256, sha, r_le, s_le);
test_ecdsa_sign(is_p256, sha, r_le, s_le, use_km_key);
TEST_ASSERT_EQUAL(0, test_ecdsa_verify(is_p256, sha, r_le, s_le, pub_x, pub_y));
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
static void test_ecdsa_export_pubkey(bool is_p256, bool use_km_key)
{
uint8_t pub_x[32] = {0};
uint8_t pub_y[32] = {0};
uint16_t len;
ecdsa_hal_config_t conf = {
.mode = ECDSA_MODE_EXPORT_PUBKEY,
.use_km_key = use_km_key,
};
if (is_p256) {
conf.curve = ECDSA_CURVE_SECP256R1;
if (use_km_key == 0) {
conf.efuse_key_blk = 6;
}
len = 32;
} else {
conf.curve = ECDSA_CURVE_SECP192R1;
if (use_km_key == 0) {
conf.efuse_key_blk = 5;
}
len = 24;
}
ecdsa_enable_and_reset();
ecdsa_hal_export_pubkey(&conf, pub_x, pub_y, len);
if (is_p256) {
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa256_pub_x, pub_x, len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa256_pub_y, pub_y, len);
} else {
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa192_pub_x, pub_x, len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa192_pub_y, pub_y, len);
}
ecdsa_disable_and_reset();
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
TEST_GROUP(ecdsa);
TEST_SETUP(ecdsa)
@ -172,7 +218,7 @@ TEST(ecdsa, ecdsa_SECP192R1_signature_verification)
TEST(ecdsa, ecdsa_SECP192R1_sign_and_verify)
{
test_ecdsa_sign_and_verify(0, sha, ecdsa192_pub_x, ecdsa192_pub_y);
test_ecdsa_sign_and_verify(0, sha, ecdsa192_pub_x, ecdsa192_pub_y, 0);
}
@ -190,7 +236,7 @@ TEST(ecdsa, ecdsa_SECP256R1_signature_verification)
TEST(ecdsa, ecdsa_SECP256R1_sign_and_verify)
{
test_ecdsa_sign_and_verify(1, sha, ecdsa256_pub_x, ecdsa256_pub_y);
test_ecdsa_sign_and_verify(1, sha, ecdsa256_pub_x, ecdsa256_pub_y, 0);
}
@ -199,6 +245,18 @@ TEST(ecdsa, ecdsa_SECP256R1_corrupt_signature)
test_ecdsa_corrupt_data(1, sha, ecdsa256_r, ecdsa256_s, ecdsa256_pub_x, ecdsa256_pub_y);
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
TEST(ecdsa, ecdsa_SECP192R1_export_pubkey)
{
test_ecdsa_export_pubkey(0, 0);
}
TEST(ecdsa, ecdsa_SECP256R1_export_pubkey)
{
test_ecdsa_export_pubkey(1, 0);
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
TEST_GROUP_RUNNER(ecdsa)
{
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_signature_verification)
@ -207,4 +265,8 @@ TEST_GROUP_RUNNER(ecdsa)
RUN_TEST_CASE(ecdsa, ecdsa_SECP256R1_signature_verification)
RUN_TEST_CASE(ecdsa, ecdsa_SECP256R1_sign_and_verify)
RUN_TEST_CASE(ecdsa, ecdsa_SECP256R1_corrupt_signature)
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_export_pubkey)
RUN_TEST_CASE(ecdsa, ecdsa_SECP256R1_export_pubkey)
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
}

View File

@ -6,7 +6,6 @@
#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"
@ -44,6 +43,64 @@ static void ecdsa_be_to_le(const uint8_t* be_point, uint8_t *le_point, uint8_t l
}
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
int esp_ecdsa_load_pubkey(mbedtls_ecp_keypair *keypair, int efuse_blk)
{
int ret = -1;
if (efuse_blk < EFUSE_BLK_KEY0 || efuse_blk >= EFUSE_BLK_KEY_MAX) {
ESP_LOGE(TAG, "Invalid efuse block selected");
return ret;
}
ecdsa_curve_t curve;
esp_efuse_block_t blk;
uint16_t len;
uint8_t zeroes[MAX_ECDSA_COMPONENT_LEN] = {0};
uint8_t qx_le[MAX_ECDSA_COMPONENT_LEN];
uint8_t qy_le[MAX_ECDSA_COMPONENT_LEN];
if (keypair->MBEDTLS_PRIVATE(grp).id == MBEDTLS_ECP_DP_SECP192R1) {
curve = ECDSA_CURVE_SECP192R1;
len = 24;
} else if (keypair->MBEDTLS_PRIVATE(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_hal_config_t conf = {
.mode = ECDSA_MODE_EXPORT_PUBKEY,
.curve = curve,
.use_km_key = 0, //TODO: IDF-7992
.efuse_key_blk = efuse_blk,
};
esp_ecdsa_acquire_hardware();
do {
ecdsa_hal_export_pubkey(&conf, qx_le, qy_le, len);
} while (!memcmp(qx_le, zeroes, len) || !memcmp(qy_le, zeroes, len));
esp_ecdsa_release_hardware();
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&(keypair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X)), qx_le, len));
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&(keypair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y)), qy_le, len));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&(keypair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z)), 1));
return 0;
cleanup:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
int esp_ecdsa_privkey_load_mpi(mbedtls_mpi *key, int efuse_blk)
{
@ -96,6 +153,48 @@ int esp_ecdsa_privkey_load_pk_context(mbedtls_pk_context *key_ctx, int efuse_blk
return esp_ecdsa_privkey_load_mpi(&(keypair->MBEDTLS_PRIVATE(d)), efuse_blk);
}
int esp_ecdsa_set_pk_context(mbedtls_pk_context *key_ctx, esp_ecdsa_pk_conf_t *conf)
{
int ret = -1;
if (!key_ctx) {
ESP_LOGE(TAG, "mbedtls_pk_context cannot be NULL");
return ret;
}
if (!conf) {
ESP_LOGE(TAG, "esp_ecdsa_pk_conf_t cannot be NULL");
return ret;
}
if (conf->grp_id != MBEDTLS_ECP_DP_SECP192R1 && conf->grp_id != MBEDTLS_ECP_DP_SECP256R1) {
ESP_LOGE(TAG, "Invalid EC curve group id mentioned in esp_ecdsa_pk_conf_t");
return ret;
}
if ((ret = esp_ecdsa_privkey_load_pk_context(key_ctx, conf->efuse_block)) != 0) {
ESP_LOGE(TAG, "Loading private key context failed, esp_ecdsa_privkey_load_pk_context() returned %d", ret);
return ret;
}
mbedtls_ecp_keypair *keypair = mbedtls_pk_ec(*key_ctx);
if ((ret = mbedtls_ecp_group_load(&(keypair->MBEDTLS_PRIVATE(grp)), conf->grp_id)) != 0) {
ESP_LOGE(TAG, "Loading ecp group failed, mbedtls_pk_ec() returned %d", ret);
return ret;
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
if (conf->load_pubkey) {
if ((ret = esp_ecdsa_load_pubkey(keypair, conf->efuse_block)) != 0) {
ESP_LOGE(TAG, "Loading public key context failed, esp_ecdsa_load_pubkey() returned %d", ret);
return ret;
}
}
#endif
return 0;
}
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)
{
@ -141,6 +240,7 @@ static int esp_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi* r, mbedtls_mpi* s
.k_mode = ECDSA_K_USE_TRNG,
.sha_mode = ECDSA_Z_USER_PROVIDED,
.efuse_key_blk = d->MBEDTLS_PRIVATE(n),
.use_km_key = 0, //TODO: IDF-7992
};
ecdsa_hal_gen_signature(&conf, NULL, sha_le, r_le, s_le, len);

View File

@ -6,14 +6,47 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "mbedtls/ecp.h"
#include "mbedtls/pk.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ECDSA private key context initialization config structure
* @note Contains configuration information like the efuse key block that should be used as the private key,
* EC group ID of the private key and if the export public key operation is supported
* by the peripheral, a flag load_pubkey that is used specify if the public key has to be populated
*/
typedef struct {
mbedtls_ecp_group_id grp_id;
uint8_t efuse_block;
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
bool load_pubkey;
#endif
} esp_ecdsa_pk_conf_t; //TODO: IDF-7925 (Add a config to select the ecdsa key from the key manager peripheral)
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
/**
* @brief Populate the public key buffer of the mbedtls_ecp_keypair context.
*
* @param keypair The mbedtls ECP key-pair structure
* @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
* - MBEDTLS_ERR_ECP_BAD_INPUT_DATA if invalid ecp group id specified
* - MBEDTLS_ERR_ECP_INVALID_KEY if efuse block with purpose ECDSA_KEY is not found
* - -1 if invalid efuse block is specified
*/
int esp_ecdsa_load_pubkey(mbedtls_ecp_keypair *keypair, int efuse_blk);
#endif
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
/**
@ -46,6 +79,24 @@ int esp_ecdsa_privkey_load_mpi(mbedtls_mpi *key, int efuse_blk);
* - -1 otherwise
*/
int esp_ecdsa_privkey_load_pk_context(mbedtls_pk_context *key_ctx, int efuse_blk);
/**
* @brief Initialize PK context and completely populate mbedtls_ecp_keypair context.
* 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.
* We also populate the ECP group field present in the mbedtls_ecp_keypair context.
* If the ECDSA peripheral of the chip supports exporting the public key,
* we can also populate the public key buffer of the mbedtls_ecp_keypair context
* if the load_pubkey flag is set in the esp_ecdsa_pk_conf_t config argument.
*
* @param key_ctx The context in which this functions stores the hardware context.
* This must be uninitialized
* @param conf ESP-ECDSA private key context initialization config structure
*
* @return - 0 if successful
* - -1 otherwise
*/
int esp_ecdsa_set_pk_context(mbedtls_pk_context *key_ctx, esp_ecdsa_pk_conf_t *conf);
#endif
#ifdef __cplusplus

View File

@ -1,6 +1,6 @@
/* mbedTLS Elliptic Curve Digital Signature performance tests
*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -16,6 +16,7 @@
#include <mbedtls/ecdsa.h>
#include <mbedtls/error.h>
#include "soc/soc_caps.h"
#include "test_utils.h"
#include "ccomp_timer.h"
#include "unity.h"
@ -234,4 +235,53 @@ TEST_CASE("mbedtls ECDSA signature generation on SECP256R1", "[mbedtls][efuse_ke
test_ecdsa_sign(MBEDTLS_ECP_DP_SECP256R1, sha, ecdsa256_sign_pub_x, ecdsa256_sign_pub_y);
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
void test_ecdsa_export_pubkey(mbedtls_ecp_group_id id, const uint8_t *pub_x, const uint8_t *pub_y)
{
uint8_t export_pub_x[32] = {0};
uint8_t export_pub_y[32] = {0};
int len = 0;
esp_ecdsa_pk_conf_t pk_conf = {
.grp_id = id,
.load_pubkey = true,
};
if (id == MBEDTLS_ECP_DP_SECP192R1) {
pk_conf.efuse_block = SECP192R1_EFUSE_BLOCK;
len = 24;
} else if (id == MBEDTLS_ECP_DP_SECP256R1) {
pk_conf.efuse_block = SECP256R1_EFUSE_BLOCK;
len = 32;
}
mbedtls_pk_context key_ctx;
int ret = esp_ecdsa_set_pk_context(&key_ctx, &pk_conf);
TEST_ASSERT_EQUAL(0, ret);
mbedtls_ecp_keypair *keypair = mbedtls_pk_ec(key_ctx);
mbedtls_mpi_write_binary(&(keypair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X)), export_pub_x, len);
mbedtls_mpi_write_binary(&(keypair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y)), export_pub_y, len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(pub_x, export_pub_x, len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(pub_y, export_pub_y, len);
mbedtls_ecdsa_free(keypair);
}
TEST_CASE("mbedtls ECDSA export public key on SECP192R1", "[mbedtls][efuse_key]")
{
test_ecdsa_export_pubkey(MBEDTLS_ECP_DP_SECP192R1, ecdsa192_sign_pub_x, ecdsa192_sign_pub_y);
}
TEST_CASE("mbedtls ECDSA export public key on SECP256R1", "[mbedtls][efuse_key]")
{
test_ecdsa_export_pubkey(MBEDTLS_ECP_DP_SECP256R1, ecdsa256_sign_pub_x, ecdsa256_sign_pub_y);
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN */

View File

@ -83,6 +83,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
@ -643,6 +647,10 @@ config SOC_SHA_SUPPORT_SHA256
bool
default y
config SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
bool
default y
config SOC_SDMMC_USE_IOMUX
bool
default y

View File

@ -62,6 +62,8 @@
#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_KEY_MANAGER_SUPPORTED 1 //TODO: IDF-7925
#define SOC_FLASH_ENC_SUPPORTED 1
// #define SOC_SECURE_BOOT_SUPPORTED 1 //TODO: IDF-7544
// #define SOC_BOD_SUPPORTED 1 //TODO: IDF-7519
@ -337,6 +339,9 @@
#define SOC_SHA_SUPPORT_SHA224 (1)
#define SOC_SHA_SUPPORT_SHA256 (1)
/*--------------------------- ECDSA CAPS ---------------------------------------*/
#define SOC_ECDSA_SUPPORT_EXPORT_PUBKEY (1)
#ifdef SDMMC_DEFAULT_IOMUX
#define SOC_SDMMC_USE_IOMUX 1
#else