# Elliptic Curve Digital Signature Algorithm (ECDSA)

[中文]

The Elliptic Curve Digital Signature Algorithm (ECDSA) offers a variant of the Digital Signature Algorithm (DSA) which uses elliptic-curve cryptography.

ESP32-H2's ECDSA peripheral provides a secure and efficient environment for computing ECDSA signatures. It offers fast computations while ensuring the confidentiality of the signing process to prevent information leakage. ECDSA private key used in the signing process is accessible only to the hardware peripheral, and it is not readable by software.

ECDSA peripheral can help to establish Secure Device Identity for TLS mutual authentication and similar use-cases.

## Supported Features

- ECDSA digital signature generation and verification

- Two different elliptic curves, namely P-192 and P-256 (FIPS 186-3 specification)

- Two hash algorithms for message hash in the ECDSA operation, namely SHA-224 and SHA-256 (FIPS PUB 180-4 specification)

## ECDSA on ESP32-H2

On ESP32-H2, the ECDSA module works with a secret key burnt into an eFuse block. This eFuse key is made completely inaccessible (default mode) for any resources outside the cryptographic modules, thus avoiding key leakage.

### ECDSA Key Storage

ECDSA private keys are stored in eFuse key blocks. One eFuse key block (256 bits) is required for P-256 curve.

Configure the following field:

- Set `esp_tls_cfg_t::ecdsa_key_efuse_blk` to the block number and leave `esp_tls_cfg_t::ecdsa_key_efuse_blk_high` as 0 or unassigned.

ECDSA key can be programmed externally through `idf.py` script. Here is an example of how to program the ECDSA key:

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

Note

Five physical eFuse blocks can be used as keys for the ECDSA module: block 4 ~ block 8. E.g., for block 4 (which is the first key block) , the argument should be `BLOCK_KEY0`.

Alternatively the ECDSA key can also be programmed through the application running on the target.

Following code snippet uses `esp_efuse_write_key()` to set physical key block 0 in the eFuse with key purpose as `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 Curve Configuration

The ECDSA peripheral of the ESP32-H2 supports both ECDSA-P192 and ECDSA-P256 operations. However, starting with ESP32-H2 revision 1.2, only ECDSA-P256 operations are enabled by default. You can enable ECDSA-P192 operations using the following configuration options:

- CONFIG_ESP_ECDSA_ENABLE_P192_CURVE enables support for ECDSA-P192 curve operations, allowing the device to perform ECDSA operations with both 192-bit and 256-bit curves. However, if ECDSA-P192 operations have already been permanently disabled during eFuse write protection, enabling this option can not re-enable ECDSA-P192 curve operations.

- `esp_efuse_enable_ecdsa_p192_curve_mode()` enables ECDSA-P192 curve operations programmatically by writing the appropriate value to the eFuse, allowing both P-192 and P-256 curve operations. Note that this API will fail if the eFuse is already write-protected.

## Deterministic Signature Generation

The ECDSA peripheral of ESP32-H2 also supports generation of deterministic signatures using deterministic derivation of the parameter K as specified in the RFC 6979 section 3.2.

## Non-Determinisitic Signature Generation

### Dependency on TRNG

ECDSA peripheral relies on the hardware True Random Number Generator (TRNG) for its internal entropy requirement for generating non-deterministic signatures. During ECDSA signature creation, the algorithm requires a random integer to be generated as specified in the RFC 6090 section 5.3.2.

Please ensure that hardware RNG is enabled before starting ECDSA computations (primarily signing) in the application.

## Application Outline

Please refer to the ECDSA Peripheral with ESP-TLS guide for details on how-to use ECDSA peripheral for establishing a mutually authenticated TLS connection.

The ECDSA peripheral in Mbed TLS stack is integrated by overriding the ECDSA signing and verifying APIs. Please note that, the ECDSA peripheral does not support all curves or hash algorithms, and hence for cases where the hardware requirements are not met, the implementation falls back to the software.

For a particular TLS context, additional APIs have been supplied to populate certain fields (e.g., private key ctx) to differentiate routing to hardware. ESP-TLS layer integrates these APIs internally and hence no additional work is required at the application layer. However, for custom use-cases please refer to API details below.

## API Reference

### 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.

  Parameters:

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Parameters:

    - 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

  Returns:

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

  Parameters:

    - keypair -- The mbedtls ECP key-pair structure

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

  Returns:

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

  Parameters:

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

  Returns:

    - 0 if successful

    - -1 otherwise

### Structures

struct esp_ecdsa_pk_conf_t

  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

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

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.