# 椭圆曲线数字签名算法 (ECDSA)

[English]

椭圆曲线数字签名算法 (ECDSA) 是数字签名算法 (DSA) 基于椭圆曲线密码学的变体。

ESP32-H21 的 ECDSA 外设为计算 ECDSA 签名提供了一个安全高效的环境，不仅能确保签名过程的机密性，防止信息泄露，也提供了快速的计算。在签名过程中使用的 ECDSA 私钥只能由硬件外设访问，软件无法读取。

ECDSA 外设可以为 TLS 双向身份验证等用例建立 安全设备身份认证。

## 支持的特性

- ECDSA 数字签名生成和验证

- 两种不同的椭圆曲线，P-192 和 P-256（FIPS 186-3 规范）

- ECDSA 操作中哈希消息的两种哈希算法，SHA-224 和 SHA-256（FIPS PUB 180-4 规范）

## ESP32-H21 上的 ECDSA

在 ESP32-H21 上，ECDSA 模块使用烧录到 eFuse 块中的密钥。密码模块外的任何资源都不可访问此密钥（默认模式），从而避免密钥泄露。

### ECDSA 密钥存储

ECDSA 私钥存储在 eFuse 密钥块中。一个 eFuse 密钥块（256 位）是 P-256 曲线所需的。

配置以下字段：

- 将 `esp_tls_cfg_t::ecdsa_key_efuse_blk` 设置为块号，将 `esp_tls_cfg_t::ecdsa_key_efuse_blk_high` 保持为 0 或不赋值。

ECDSA 密钥可以通过 `idf.py` 脚本在外部编程。以下是关于编程 ECDSA 密钥的示例：

    idf.py efuse-burn-key <BLOCK_NUM> </path/to/ecdsa_private_key.pem> ECDSA_KEY

备注

五个物理 eFuse 块可作为 ECDSA 模块的密钥：块 4 ~ 块 8。例如，对于块 4（第一个密钥块），参数为 `BLOCK_KEY0`。

另外，ECDSA 密钥也可以通过在目标上运行的应用程序进行编程。

以下代码片段使用 `esp_efuse_write_key()` 将 eFuse 中的物理密钥块 0 的密钥目的设置为 `esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY`:

    #include "esp_efuse.h"

    const uint8_t key_data[32] = { ... };

    esp_err_t status = esp_efuse_write_key(EFUSE_BLK_KEY0,
                        ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY,
                        key_data, sizeof(key_data));

    if (status == ESP_OK) {
        // written key
    } else {
        // writing key failed, maybe written already
    }

## ECDSA 曲线配置

ESP32-H21 的 ECDSA 外设支持 ECDSA-P192 和 ECDSA-P256 两种曲线操作，但默认仅启用 ECDSA-P256 操作。可以通过以下配置项启用 ECDSA-P192 操作：

- CONFIG_ESP_ECDSA_ENABLE_P192_CURVE 启用对 ECDSA-P192 曲线操作的支持，使设备可以同时执行 192 位和 256 位的 ECDSA 曲线操作。但请注意，如果 eFuse 写保护期间已永久禁用 ECDSA-P192 操作，则启用该配置项也无法重新启用该功能。

- `esp_efuse_enable_ecdsa_p192_curve_mode()` 可用于以编程方式启用 ECDSA-P192 曲线操作。它会向 eFuse 写入相应值，从而使设备支持 P-192 和 P-256 曲线操作。但请注意，若对应的 eFuse 区域已被写保护，则此 API 将调用失败。

## 生成确定性签名

ESP32-H21 的 ECDSA 外设还支持使用确定性推导参数 K 来生成确定性签名，详见 RFC 6979 第 3.2 节。

## 生成非确定性签名

### 对 TRNG 的依赖

ECDSA 外设依靠硬件真随机数生成器 (TRNG) 来满足其内部熵要求，从而生成非确定性签名。在创建 ECDSA 签名时，算法需要生成一个随机整数，在 RFC 6090 第 5.3.2 节有说明。

在应用程序中启动 ECDSA 计算（主要是签名）之前，请确保硬件 RNG 已经启用。

## 应用程序概述

有关如何使用 ECDSA 外设建立 TLS 双向身份验证连接的详细信息，请参阅 在 ESP-TLS 中使用 ECDSA 外设 指南。

通过覆盖 ECDSA 签名以及验证 API，可以集成 Mbed TLS 堆栈中的 ECDSA 外设。请注意，ECDSA 外设并不支持所有曲线或哈希算法。因此，在不满足硬件要求时，实现会退回到软件。

对于特定的 TLS 上下文，可用额外的 API 来填充某些字段（例如私钥 ctx），以区分路由到硬件的路径。ESP-TLS 层在内部集成了这些 API，因此在应用程序层不需要额外的操作。对于自定义用例，请参阅以下 API 详细信息。

## API 参考

### Header File

- components/mbedtls/port/include/ecdsa/ecdsa_alt.h

- This header file can be included with:

  >     #include "ecdsa/ecdsa_alt.h"

- This header file is a part of the API provided by the `mbedtls` component. To declare that your component depends on `mbedtls`, add the following to your CMakeLists.txt:

  >     REQUIRES mbedtls

  > or

  >     PRIV_REQUIRES mbedtls

### Functions

int esp_ecdsa_load_pubkey(mbedtls_ecp_keypair *keypair, int efuse_blk)

  Populate the public key buffer of the mbedtls_ecp_keypair context.

  参数:

    - keypair -- The mbedtls ECP key-pair structure

    - efuse_blk -- The efuse key block that should be used as the private key. The efuse block where ECDSA key is stored. If two blocks are used to store the key, then the macro HAL_ECDSA_COMBINE_KEY_BLOCKS() can be used to combine them. The macro is defined in hal/ecdsa_types.h.

  返回:

    - 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_privkey_load_mpi(mbedtls_mpi *key, int efuse_blk)

  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.

  参数:

    - key -- The MPI in which this functions stores the hardware context. This must be uninitialized

    - efuse_blk -- The efuse key block that should be used as the private key. The efuse block where ECDSA key is stored. If two blocks are used to store the key, then the macro HAL_ECDSA_COMBINE_KEY_BLOCKS() can be used to combine them. The macro is defined in hal/ecdsa_types.h.

  返回:

    - 0 if successful

    - -1 otherwise

int esp_ecdsa_privkey_load_pk_context(mbedtls_pk_context *key_ctx, int efuse_blk)

  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.

  参数:

    - key_ctx -- The context in which this functions stores the hardware context. This must be uninitialized

    - efuse_blk -- The efuse key block that should be used as the private key. The efuse block where ECDSA key is stored. If two blocks are used to store the key, then the macro HAL_ECDSA_COMBINE_KEY_BLOCKS() can be used to combine them. The macro is defined in hal/ecdsa_types.h.

  返回:

    - 0 if successful

    - -1 otherwise

int esp_ecdsa_set_pk_context(mbedtls_pk_context *key_ctx, esp_ecdsa_pk_conf_t *conf)

  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.

  参数:

    - key_ctx -- The context in which this functions stores the hardware context. This must be uninitialized

    - conf -- ESP-ECDSA private key context initialization config structure

  返回:

    - 0 if successful

    - -1 otherwise

int esp_ecdsa_tee_load_pubkey(mbedtls_ecp_keypair *keypair, const char *tee_key_id)

  Populate the public key buffer of the mbedtls_ecp_keypair context from the TEE secure storage.

  参数:

    - keypair -- The mbedtls ECP key-pair structure

    - tee_key_id -- The TEE secure storage key id of the private key

  返回:

    - 0 if successful else MBEDTLS_ERR_ECP_BAD_INPUT_DATA

int esp_ecdsa_tee_set_pk_context(mbedtls_pk_context *key_ctx, esp_ecdsa_pk_conf_t *conf)

  Initialize PK context and fully populate the mbedtls_ecp_keypair context. This function modifies the MPI struct used to represent the private key `d` in the ECP keypair to differentiate between TEE secure storage keys and software keys. It also populates the ECP group field in the mbedtls_ecp_keypair context. Additionally, if the load_pubkey flag is set in the esp_ecdsa_pk_conf_t config argument, the public key buffer of the mbedtls_ecp_keypair context will be populated.

  参数:

    - key_ctx -- The context in which this function stores the TEE secure storage context. This must be uninitialized.

    - conf -- ESP-ECDSA private key context initialization config structure.

  返回:

    - 0 if successful

    - -1 otherwise

### Structures

struct esp_ecdsa_pk_conf_t

  ECDSA private key context initialization config structure.

  备注

  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

  Public Members

  mbedtls_ecp_group_id grp_id

    MbedTLS ECP group identifier

  uint8_t efuse_block

    EFuse block id for ECDSA private key

  const char *tee_key_id

    TEE secure storage key id for ECDSA private key

  union esp_ecdsa_pk_conf_t

    Union to hold either EFuse block id or TEE secure storage key id for ECDSA private key

  bool load_pubkey

    Export ECDSA public key from the hardware

  bool use_km_key

    Use key deployed in the key manager for ECDSA operation. Note: The key must be already deployed by the application and it must be activated for the lifetime of this context

### Macros

USE_ECDSA_KEY_FROM_KEY_MANAGER

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。