Files
esp-idf/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c
nilesh.kale 68f06a94bd feat: add ecdsa-p384 testcases and relative support for ESP32C5 ECO2
This commit adds testcases in crypto/hal and mbedtls testapps.
2025-08-11 16:01:01 +05:30

452 lines
15 KiB
C

/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "esp_crypto_lock.h"
#include "esp_efuse_chip.h"
#include "esp_crypto_periph_clk.h"
#include "esp_random.h"
#include "esp_err.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "hal/ecc_ll.h"
#include "hal/ecdsa_hal.h"
#include "hal/efuse_ll.h"
#include "hal/ecdsa_ll.h"
#include "hal/ecdsa_types.h"
#ifdef SOC_MPI_SUPPORTED
#include "hal/mpi_ll.h"
#endif
#include "soc/soc_caps.h"
#include "memory_checks.h"
#include "unity_fixture.h"
#include "ecdsa_params.h"
#include "hal_crypto_common.h"
__attribute__((unused)) static const char * TAG = "crypto_test";
static void ecdsa_enable_and_reset(void)
{
esp_crypto_ecdsa_enable_periph_clk(true);
esp_crypto_ecc_enable_periph_clk(true);
#ifdef SOC_ECDSA_USES_MPI
esp_crypto_mpi_enable_periph_clk(true);
#endif
}
static void ecdsa_disable(void)
{
#ifdef SOC_ECDSA_USES_MPI
esp_crypto_mpi_enable_periph_clk(false);
#endif
esp_crypto_ecc_enable_periph_clk(false);
esp_crypto_ecdsa_enable_periph_clk(false);
}
static void ecc_be_to_le(const uint8_t* be_point, uint8_t *le_point, uint8_t len)
{
memset(le_point, 0x0, 32);
for (int i = 0; i < len; i++) {
le_point[i] = be_point[len - i - 1];
}
}
int test_ecdsa_verify(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y)
{
uint16_t len = 0;
uint8_t sha_le[48];
ecdsa_hal_config_t conf = {
.mode = ECDSA_MODE_SIGN_VERIFY,
.sha_mode = ECDSA_Z_USER_PROVIDED,
};
switch (curve) {
case ECDSA_CURVE_SECP192R1:
conf.curve = ECDSA_CURVE_SECP192R1;
len = 24;
break;
case ECDSA_CURVE_SECP256R1:
conf.curve = ECDSA_CURVE_SECP256R1;
len = 32;
break;
#if SOC_ECDSA_SUPPORT_CURVE_P384
case ECDSA_CURVE_SECP384R1:
conf.curve = ECDSA_CURVE_SECP384R1;
len = 48;
break;
#endif
default:
break;
}
/* Set HASH */
ecc_be_to_le(sha, sha_le, len);
ecdsa_enable_and_reset();
int ret = ecdsa_hal_verify_signature(&conf, sha_le, r_le, s_le, pub_x, pub_y, len);
ecdsa_disable();
return ret;
}
static void test_ecdsa_corrupt_data(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y)
{
int len = 0;
switch (curve) {
case ECDSA_CURVE_SECP192R1: len = 24; break;
case ECDSA_CURVE_SECP256R1: len = 32; break;
#if SOC_ECDSA_SUPPORT_CURVE_P384
case ECDSA_CURVE_SECP384R1: len = 48; break;
#endif
default: break;
}
// Randomly select a bit and corrupt its corresponding value
uint16_t r_bit = esp_random() % (len * 8);
printf("Corrupting SHA bit %d...\n", r_bit);
sha[r_bit / 8] ^= 1 << (r_bit % 8);
TEST_ASSERT_EQUAL(-1, test_ecdsa_verify(curve, sha, r_le, s_le, pub_x, pub_y));
sha[r_bit / 8] ^= 1 << (r_bit % 8);
printf("Corrupting R bit %d...\n", r_bit);
r_le[r_bit / 8] ^= 1 << (r_bit % 8);
TEST_ASSERT_EQUAL(-1, test_ecdsa_verify(curve, sha, r_le, s_le, pub_x, pub_y));
r_le[r_bit / 8] ^= 1 << (r_bit % 8);
printf("Corrupting S bit %d...\n", r_bit);
s_le[r_bit / 8] ^= 1 << (r_bit % 8);
TEST_ASSERT_EQUAL(-1, test_ecdsa_verify(curve, sha, r_le, s_le, pub_x, pub_y));
s_le[r_bit / 8] ^= 1 << (r_bit % 8);
printf("Corrupting pub_x bit %d...\n", r_bit);
pub_x[r_bit / 8] ^= 1 << (r_bit % 8);
TEST_ASSERT_EQUAL(-1, test_ecdsa_verify(curve, sha, r_le, s_le, pub_x, pub_y));
pub_x[r_bit / 8] ^= 1 << (r_bit % 8);
printf("Corrupting pub_y bit %d...\n", r_bit);
pub_y[r_bit / 8] ^= 1 << (r_bit % 8);
TEST_ASSERT_EQUAL(-1, test_ecdsa_verify(curve, sha, r_le, s_le, pub_x, pub_y));
pub_y[r_bit / 8] ^= 1 << (r_bit % 8);
}
void test_ecdsa_sign(ecdsa_curve_t curve, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type)
{
uint8_t sha_le[48] = {0};
uint8_t zeroes[48] = {0};
uint16_t len = 0;
#if !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP
uint16_t det_loop_number = 1;
#endif /* !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */
ecdsa_hal_config_t conf = {
.mode = ECDSA_MODE_SIGN_GEN,
.sha_mode = ECDSA_Z_USER_PROVIDED,
.use_km_key = use_km_key,
.sign_type = k_type,
};
switch (curve) {
case ECDSA_CURVE_SECP192R1:
conf.curve = ECDSA_CURVE_SECP192R1;
if (use_km_key == 0) {
conf.efuse_key_blk = EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_1;
}
len = 24;
break;
case ECDSA_CURVE_SECP256R1:
conf.curve = ECDSA_CURVE_SECP256R1;
if (use_km_key == 0) {
conf.efuse_key_blk = EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_2;
}
len = 32;
break;
#if SOC_ECDSA_SUPPORT_CURVE_P384
case ECDSA_CURVE_SECP384R1:
conf.curve = ECDSA_CURVE_SECP384R1;
if (use_km_key == 0) {
// Store two key blocks in a single 8-bit integer
// Most significant 4 bits for first block where, lower 4 bits for second block
conf.efuse_key_blk = HAL_ECDSA_COMBINE_KEY_BLOCKS(EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_3, EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_4);
}
len = 48;
break;
#endif
default:
break;
}
/* Set HASH */
ecc_be_to_le(sha, sha_le, len);
ecdsa_enable_and_reset();
bool process_again = false;
do {
#if !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP
if (ecdsa_ll_is_deterministic_mode_supported() && k_type == ECDSA_K_TYPE_DETERMINISITIC) {
conf.loop_number = det_loop_number++;
}
#endif /* !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */
ecdsa_hal_gen_signature(&conf, sha_le, r_le, s_le, len);
process_again = !ecdsa_hal_get_operation_result()
|| !memcmp(r_le, zeroes, len)
|| !memcmp(s_le, zeroes, len);
#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP
if (ecdsa_ll_is_deterministic_mode_supported() && k_type == ECDSA_K_TYPE_DETERMINISITIC) {
process_again |= !ecdsa_hal_det_signature_k_check();
}
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */
} while(process_again);
ecdsa_disable();
}
void test_ecdsa_sign_and_verify(ecdsa_curve_t curve, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type)
{
uint8_t r_le[48] = {0};
uint8_t s_le[48] = {0};
test_ecdsa_sign(curve, sha, r_le, s_le, use_km_key, k_type);
TEST_ASSERT_EQUAL(0, test_ecdsa_verify(curve, sha, r_le, s_le, pub_x, pub_y));
}
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
void test_ecdsa_export_pubkey_inner(ecdsa_curve_t curve, uint8_t *exported_pub_x, uint8_t *exported_pub_y, bool use_km_key, uint16_t *len)
{
uint8_t zeroes[48] = {0};
ecdsa_hal_config_t conf = {
.mode = ECDSA_MODE_EXPORT_PUBKEY,
.use_km_key = use_km_key,
};
switch (curve) {
case ECDSA_CURVE_SECP192R1:
conf.curve = ECDSA_CURVE_SECP192R1;
if (use_km_key == 0) {
conf.efuse_key_blk = EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_1;
}
*len = 24;
break;
case ECDSA_CURVE_SECP256R1:
conf.curve = ECDSA_CURVE_SECP256R1;
if (use_km_key == 0) {
conf.efuse_key_blk = EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_2;
}
*len = 32;
break;
#if SOC_ECDSA_SUPPORT_CURVE_P384
case ECDSA_CURVE_SECP384R1:
conf.curve = ECDSA_CURVE_SECP384R1;
if (use_km_key == 0) {
// Store two key blocks in a single 8-bit integer
// Most significant 4 bits for first block where, lower 4 bits for second block
conf.efuse_key_blk = HAL_ECDSA_COMBINE_KEY_BLOCKS(EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_3, EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_4);
}
*len = 48;
break;
#endif
default:
break;
}
ecdsa_enable_and_reset();
bool process_again = false;
do {
ecdsa_hal_export_pubkey(&conf, exported_pub_x, exported_pub_y, *len);
process_again = !ecdsa_hal_get_operation_result()
|| !memcmp(exported_pub_x, zeroes, *len)
|| !memcmp(exported_pub_y, zeroes, *len);
} while (process_again);
ecdsa_disable();
}
void test_ecdsa_export_pubkey(ecdsa_curve_t curve, uint8_t *ecdsa_pub_x, uint8_t *ecdsa_pub_y, bool use_km_key)
{
uint8_t pub_x[48] = {0};
uint8_t pub_y[48] = {0};
uint16_t len;
test_ecdsa_export_pubkey_inner(curve, pub_x, pub_y, use_km_key, &len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa_pub_x, pub_x, len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa_pub_y, pub_y, len);
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
TEST_GROUP(ecdsa);
TEST_SETUP(ecdsa)
{
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
}
TEST_TEAR_DOWN(ecdsa)
{
test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL),
test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL));
}
TEST(ecdsa, ecdsa_SECP192R1_signature_verification)
{
if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
TEST_ASSERT_EQUAL(0, test_ecdsa_verify(ECDSA_CURVE_SECP192R1, sha, ecdsa192_r, ecdsa192_s, ecdsa192_pub_x, ecdsa192_pub_y));
}
}
TEST(ecdsa, ecdsa_SECP192R1_sign_and_verify)
{
if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP192R1, sha, ecdsa192_pub_x, ecdsa192_pub_y, false, ECDSA_K_TYPE_TRNG);
}
}
TEST(ecdsa, ecdsa_SECP192R1_corrupt_signature)
{
if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_corrupt_data(ECDSA_CURVE_SECP192R1, sha, ecdsa192_r, ecdsa192_s, ecdsa192_pub_x, ecdsa192_pub_y);
}
}
TEST(ecdsa, ecdsa_SECP256R1_signature_verification)
{
TEST_ASSERT_EQUAL(0, test_ecdsa_verify(ECDSA_CURVE_SECP256R1, sha, ecdsa256_r, ecdsa256_s, ecdsa256_pub_x, ecdsa256_pub_y));
}
TEST(ecdsa, ecdsa_SECP256R1_sign_and_verify)
{
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, ECDSA_K_TYPE_TRNG);
}
TEST(ecdsa, ecdsa_SECP256R1_corrupt_signature)
{
test_ecdsa_corrupt_data(ECDSA_CURVE_SECP256R1, sha, ecdsa256_r, ecdsa256_s, ecdsa256_pub_x, ecdsa256_pub_y);
}
#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
TEST(ecdsa, ecdsa_SECP192R1_det_sign_and_verify)
{
if (!ecdsa_ll_is_deterministic_mode_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA deterministic mode is not supported.");
} else if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP192R1, sha, ecdsa192_pub_x, ecdsa192_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC);
}
}
TEST(ecdsa, ecdsa_SECP256R1_det_sign_and_verify)
{
if (!ecdsa_ll_is_deterministic_mode_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA deterministic mode is not supported.");
} else {
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC);
}
}
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
TEST(ecdsa, ecdsa_SECP192R1_export_pubkey)
{
if (!esp_efuse_is_ecdsa_p192_curve_supported()) {
ESP_LOGI(TAG, "Skipping test because ECDSA 192-curve operations are disabled.");
} else {
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP192R1, ecdsa192_pub_x, ecdsa192_pub_y, 0);
}
}
TEST(ecdsa, ecdsa_SECP256R1_export_pubkey)
{
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, 0);
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#ifdef SOC_ECDSA_SUPPORT_CURVE_P384
TEST(ecdsa, ecdsa_SECP384R1_signature_verification)
{
TEST_ASSERT_EQUAL(0, test_ecdsa_verify(ECDSA_CURVE_SECP384R1, sha, ecdsa384_r, ecdsa384_s, ecdsa384_pub_x, ecdsa384_pub_y));
}
TEST(ecdsa, ecdsa_SECP384R1_sign_and_verify)
{
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, ECDSA_K_TYPE_TRNG);
}
TEST(ecdsa, ecdsa_SECP384R1_corrupt_signature)
{
test_ecdsa_corrupt_data(ECDSA_CURVE_SECP384R1, sha, ecdsa384_r, ecdsa384_s, ecdsa384_pub_x, ecdsa384_pub_y);
}
#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
TEST(ecdsa, ecdsa_SECP384R1_det_sign_and_verify)
{
test_ecdsa_sign_and_verify(ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, ECDSA_K_TYPE_DETERMINISITIC);
}
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
TEST(ecdsa, ecdsa_SECP384R1_export_pubkey)
{
test_ecdsa_export_pubkey(ECDSA_CURVE_SECP384R1, ecdsa384_pub_x, ecdsa384_pub_y, 0);
}
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
TEST_GROUP_RUNNER(ecdsa)
{
/* SECP192R1 test cases */
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_signature_verification)
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_sign_and_verify)
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_corrupt_signature)
#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_det_sign_and_verify)
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
RUN_TEST_CASE(ecdsa, ecdsa_SECP192R1_export_pubkey)
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
/* SECP256R1 test cases */
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_DETERMINISTIC_MODE
RUN_TEST_CASE(ecdsa, ecdsa_SECP256R1_det_sign_and_verify)
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
RUN_TEST_CASE(ecdsa, ecdsa_SECP256R1_export_pubkey)
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
/* SECP384R1 test cases */
#ifdef SOC_ECDSA_SUPPORT_CURVE_P384
RUN_TEST_CASE(ecdsa, ecdsa_SECP384R1_signature_verification)
RUN_TEST_CASE(ecdsa, ecdsa_SECP384R1_sign_and_verify)
RUN_TEST_CASE(ecdsa, ecdsa_SECP384R1_corrupt_signature)
#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
RUN_TEST_CASE(ecdsa, ecdsa_SECP384R1_det_sign_and_verify)
#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */
#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
RUN_TEST_CASE(ecdsa, ecdsa_SECP384R1_export_pubkey)
#endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */
#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */
}