feat(mbedtls): Add PSA Crypto driver for external secure elements

Add generic secure element PSA driver with runtime callback registration.
Consolidate Kconfig into single MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED option.

Closes https://github.com/espressif/esp-idf/issues/18388

(cherry picked from commit 1c20f525b4)
This commit is contained in:
Aditya Patwardhan
2026-04-08 18:39:34 +05:30
parent 2325a727d8
commit a35e056816
10 changed files with 889 additions and 47 deletions

View File

@@ -477,6 +477,14 @@ if(CONFIG_MBEDTLS_USE_CRYPTO_ROM_IMPL)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u mbedtls_rom_osi_functions_init")
endif()
if(CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED)
target_sources(tfpsacrypto PRIVATE
"${COMPONENT_DIR}/port/psa_driver/secure_element/psa_crypto_driver_secure_element.c")
target_include_directories(tfpsacrypto PUBLIC "${COMPONENT_DIR}/port/psa_driver/include")
target_compile_definitions(tfpsacrypto PRIVATE
SECURE_ELEMENT_DRIVER_ENABLED)
endif()
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-analyzer")
target_compile_options(tfpsacrypto PRIVATE "-fno-analyzer")
@@ -544,11 +552,6 @@ if(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_CONSTANT_TIME_CM)
target_link_libraries(tfpsacrypto PRIVATE idf::esp_timer)
endif()
# # Link esp-cryptoauthlib to mbedtls
# if(CONFIG_ATCA_MBEDTLS_ECDSA)
# mbedcrypto_optional_deps(espressif__esp-cryptoauthlib esp-cryptoauthlib)
# endif()
# Apply -fno-analyzer to ALL mbedTLS targets at the very end when all targets are created
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU")
message(STATUS "Applying -fno-analyzer to all mbedTLS targets...")

View File

@@ -1000,49 +1000,49 @@ menu "mbedTLS"
config MBEDTLS_ECP_DP_SECP384R1_ENABLED
bool "Enable SECP384R1 curve"
depends on MBEDTLS_ECP_C
default y if !(MBEDTLS_ATCA_HW_ECDSA_SIGN || MBEDTLS_ATCA_HW_ECDSA_VERIFY)
default y
help
Enable support for SECP384R1 Elliptic Curve.
config MBEDTLS_ECP_DP_SECP521R1_ENABLED
bool "Enable SECP521R1 curve"
depends on MBEDTLS_ECP_C
default y if !(MBEDTLS_ATCA_HW_ECDSA_SIGN || MBEDTLS_ATCA_HW_ECDSA_VERIFY)
default y
help
Enable support for SECP521R1 Elliptic Curve.
config MBEDTLS_ECP_DP_SECP256K1_ENABLED
bool "Enable SECP256K1 curve"
depends on MBEDTLS_ECP_C
default y if !(MBEDTLS_ATCA_HW_ECDSA_SIGN || MBEDTLS_ATCA_HW_ECDSA_VERIFY)
default y
help
Enable support for SECP256K1 Elliptic Curve.
config MBEDTLS_ECP_DP_BP256R1_ENABLED
bool "Enable BP256R1 curve"
depends on MBEDTLS_ECP_C
default y if !(MBEDTLS_ATCA_HW_ECDSA_SIGN || MBEDTLS_ATCA_HW_ECDSA_VERIFY)
default y
help
support for DP Elliptic Curve.
config MBEDTLS_ECP_DP_BP384R1_ENABLED
bool "Enable BP384R1 curve"
depends on MBEDTLS_ECP_C
default y if !(MBEDTLS_ATCA_HW_ECDSA_SIGN || MBEDTLS_ATCA_HW_ECDSA_VERIFY)
default y
help
support for DP Elliptic Curve.
config MBEDTLS_ECP_DP_BP512R1_ENABLED
bool "Enable BP512R1 curve"
depends on MBEDTLS_ECP_C
default y if !(MBEDTLS_ATCA_HW_ECDSA_SIGN || MBEDTLS_ATCA_HW_ECDSA_VERIFY)
default y
help
support for DP Elliptic Curve.
config MBEDTLS_ECP_DP_CURVE25519_ENABLED
bool "Enable CURVE25519 curve"
depends on MBEDTLS_ECP_C
default y if !(MBEDTLS_ATCA_HW_ECDSA_SIGN || MBEDTLS_ATCA_HW_ECDSA_VERIFY)
default y
help
Enable support for CURVE25519 Elliptic Curve.
endmenu
@@ -1510,19 +1510,14 @@ menu "mbedTLS"
it also increases the binary size by ~1.2 KB as it pulls in the peripheral's block
mode code as well.
config MBEDTLS_ATCA_HW_ECDSA_SIGN
bool "Enable hardware ECDSA sign acceleration when using ATECC608A"
config MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED
bool "Enable secure element hardware support (e.g., ATECC608A)"
default n
help
This option enables hardware acceleration for ECDSA sign function, only
when using ATECC608A cryptoauth chip.
config MBEDTLS_ATCA_HW_ECDSA_VERIFY
bool "Enable hardware ECDSA verify acceleration when using ATECC608A"
default n
help
This option enables hardware acceleration for ECDSA sign function, only
when using ATECC608A cryptoauth chip.
Enable PSA Crypto driver support for external secure elements.
This enables sign, verify, and key export operations via runtime-registered
callbacks from the secure element component (e.g., esp-cryptoauthlib).
The private key never leaves the secure element.
config MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL
bool "Enable hardware RSA digital signature peripheral acceleration"

View File

@@ -153,8 +153,7 @@ CONFIG_MBEDTLS_HARDWARE_ECC=y
CONFIG_MBEDTLS_ECC_OTHER_CURVES_SOFT_FALLBACK=y
CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN=n
CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY=y
CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN=n
CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY=n
CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED=n
CONFIG_MBEDTLS_PKCS7_C=y
CONFIG_MBEDTLS_PKCS1_V15=y

View File

@@ -267,13 +267,8 @@
#endif
#endif
#ifdef CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN
#define MBEDTLS_ECDSA_SIGN_ALT
#endif
#ifdef CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY
#define MBEDTLS_ECDSA_VERIFY_ALT
#endif
/* SECURE_ELEMENT_DRIVER_ENABLED is set via target_compile_definitions in
* CMakeLists.txt when CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED is set. */
#ifdef CONFIG_MBEDTLS_HARDWARE_ECC
#ifdef CONFIG_MBEDTLS_ECC_OTHER_CURVES_SOFT_FALLBACK

View File

@@ -0,0 +1,239 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "psa/crypto.h"
#include "psa/crypto_types.h"
#include "psa_crypto_driver_secure_element_contexts.h"
#if defined(SECURE_ELEMENT_DRIVER_ENABLED) || defined(CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED)
#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Secure element PSA driver location
*
* Vendor-specific location for secure element keys.
* Bits 8-31 are location, using vendor flag (0x800000) + SE vendor ID.
*/
#define PSA_KEY_LOCATION_SECURE_ELEMENT ((psa_key_location_t) 0x800004)
/**
* @brief Construct a lifetime for secure element keys with default persistence
*/
#define PSA_KEY_LIFETIME_SECURE_ELEMENT \
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \
PSA_KEY_PERSISTENCE_DEFAULT, \
PSA_KEY_LOCATION_SECURE_ELEMENT)
/**
* @brief Construct a volatile lifetime for secure element keys
*/
#define PSA_KEY_LIFETIME_SECURE_ELEMENT_VOLATILE \
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \
PSA_KEY_PERSISTENCE_VOLATILE, \
PSA_KEY_LOCATION_SECURE_ELEMENT)
/*
* Callback typedefs for secure element operations.
*
* These allow the SE-specific backend (e.g. esp-cryptoauthlib for ATECC608A)
* to register its implementation at runtime without any build-time dependency.
*/
/**
* @brief Callback to sign a hash using the secure element
*
* @param slot_id Slot containing the private key
* @param hash Hash to sign
* @param hash_len Length of hash (e.g. 32 for SHA-256)
* @param sig Output buffer for raw signature (R || S)
* @param sig_size Size of sig buffer
* @param sig_len Actual signature length written
* @return psa_status_t
*/
typedef psa_status_t (*secure_element_sign_cb_t)(uint8_t slot_id, const uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t sig_size, size_t *sig_len);
/**
* @brief Callback to export the public key from a secure element slot
*
* @param slot_id Slot containing the key pair
* @param pubkey Output buffer for raw public key (X || Y)
* @param pubkey_size Size of pubkey buffer
* @param pubkey_len Actual public key length written
* @return psa_status_t
*/
typedef psa_status_t (*secure_element_export_pubkey_cb_t)(uint8_t slot_id, uint8_t *pubkey,
size_t pubkey_size, size_t *pubkey_len);
/**
* @brief Callback to verify a hash signature using the secure element
*
* @param hash Hash that was signed
* @param hash_len Length of hash
* @param sig Raw signature (R || S)
* @param sig_len Length of signature
* @param pubkey Raw public key (X || Y)
* @param pubkey_len Length of public key
* @param is_verified Output: true if signature is valid
* @return psa_status_t
*/
typedef psa_status_t (*secure_element_verify_cb_t)(const uint8_t *hash, size_t hash_len,
const uint8_t *sig, size_t sig_len, const uint8_t *pubkey, size_t pubkey_len, bool *is_verified);
/**
* @brief Secure element callback table
*
* The algorithm, key_type, and key_bits fields declare what the SE supports.
* The driver validates incoming requests against these and returns
* PSA_ERROR_NOT_SUPPORTED for anything that doesn't match, allowing the
* PSA framework to fall back to software.
*/
typedef struct {
secure_element_sign_cb_t sign; /**< Sign hash callback (NULL if not supported) */
secure_element_export_pubkey_cb_t export_pubkey; /**< Export public key callback (NULL if not supported) */
secure_element_verify_cb_t verify; /**< Verify hash callback (NULL if not supported) */
psa_algorithm_t algorithm; /**< Supported algorithm, e.g. PSA_ALG_ECDSA(PSA_ALG_SHA_256) */
psa_key_type_t key_type; /**< Supported key type, e.g. PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1) */
size_t key_bits; /**< Supported key size in bits, e.g. 256 */
} secure_element_callbacks_t;
/**
* @brief Register secure element callbacks
*
* Must be called once during application initialization, before any PSA
* operations targeting PSA_KEY_LOCATION_SECURE_ELEMENT. Uses atomic
* compare-and-swap so only the first call succeeds.
*
* @param callbacks Pointer to callback table (must remain valid for program lifetime)
* @return PSA_SUCCESS on success
* @return PSA_ERROR_BAD_STATE if callbacks were already registered
* @return PSA_ERROR_INVALID_ARGUMENT if callbacks is NULL
*/
psa_status_t secure_element_register_callbacks(const secure_element_callbacks_t *callbacks);
/**
* @brief Sign a hash using secure element opaque driver
*/
psa_status_t secure_element_opaque_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length);
/**
* @brief Import a secure element key reference (not actual key material)
*/
psa_status_t secure_element_opaque_import_key(
const psa_key_attributes_t *attributes,
const uint8_t *data,
size_t data_length,
uint8_t *key_buffer,
size_t key_buffer_size,
size_t *key_buffer_length,
size_t *bits);
/**
* @brief Export the public key from a secure element opaque key
*/
psa_status_t secure_element_opaque_export_public_key(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
uint8_t *data,
size_t data_size,
size_t *data_length);
/**
* @brief Get the key buffer size for a secure element opaque key
*/
size_t secure_element_opaque_size_function(
psa_key_type_t key_type,
size_t key_bits);
/**
* @brief Verify a hash using secure element transparent driver
*/
psa_status_t secure_element_transparent_verify_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length);
/**
* @brief Start a hash verification operation
*/
psa_status_t secure_element_transparent_verify_hash_start(
secure_element_transparent_verify_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length);
/**
* @brief Complete a hash verification operation
*/
psa_status_t secure_element_transparent_verify_hash_complete(
secure_element_transparent_verify_hash_operation_t *operation);
/**
* @brief Abort a hash verification operation
*/
psa_status_t secure_element_transparent_verify_hash_abort(
secure_element_transparent_verify_hash_operation_t *operation);
/**
* @brief Start a hash signing operation using opaque driver
*/
psa_status_t secure_element_opaque_sign_hash_start(
secure_element_opaque_sign_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length);
/**
* @brief Complete a hash signing operation using opaque driver
*/
psa_status_t secure_element_opaque_sign_hash_complete(
secure_element_opaque_sign_hash_operation_t *operation,
uint8_t *signature, size_t signature_size,
size_t *signature_length);
/**
* @brief Abort a hash signing operation using opaque driver
*/
psa_status_t secure_element_opaque_sign_hash_abort(
secure_element_opaque_sign_hash_operation_t *operation);
#ifdef __cplusplus
}
#endif
#endif /* SECURE_ELEMENT_DRIVER_ENABLED || CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED */

View File

@@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Maximum key component length in bytes.
* Supports up to P-384 (48 bytes). Increase to 66 for P-521 if needed.
*/
#define SECURE_ELEMENT_MAX_KEY_BYTES 48
/**
* @brief Opaque key structure for secure element import
*
* This struct is passed as the "key material" to psa_import_key().
* It identifies which SE slot the key refers to.
*/
typedef struct {
uint8_t slot_id; /**< Slot index on the secure element */
} secure_element_opaque_key_t;
/**
* @brief Operation context for transparent verify_hash
*
* Used by the interruptible verify API to store intermediate state
* between start / complete / abort calls.
*/
typedef struct {
uint8_t sha[SECURE_ELEMENT_MAX_KEY_BYTES];
uint8_t r[SECURE_ELEMENT_MAX_KEY_BYTES];
uint8_t s[SECURE_ELEMENT_MAX_KEY_BYTES];
uint8_t qx[SECURE_ELEMENT_MAX_KEY_BYTES];
uint8_t qy[SECURE_ELEMENT_MAX_KEY_BYTES];
size_t key_len;
size_t sha_len;
} secure_element_transparent_verify_hash_operation_t;
/**
* @brief Operation context for opaque sign_hash
*
* Used by the interruptible sign API to store intermediate state
* between start / complete / abort calls.
*/
typedef struct {
uint8_t sha[SECURE_ELEMENT_MAX_KEY_BYTES];
size_t key_len;
size_t sha_len;
secure_element_opaque_key_t *opaque_key;
unsigned int alg;
} secure_element_opaque_sign_hash_operation_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,487 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Generic Secure Element PSA Crypto Driver
*
* This driver provides PSA Crypto API integration for external secure elements
* (e.g., ATECC608A). The SE-specific operations are dispatched through
* runtime-registered callbacks, removing any build-time dependency on a
* particular SE library.
*
* The callbacks struct declares which algorithm/key_type/key_bits the SE
* supports. The driver validates each request against these and returns
* PSA_ERROR_NOT_SUPPORTED for mismatches, letting PSA fall back to software.
*/
#include <string.h>
#include <stdatomic.h>
#include "sdkconfig.h"
#ifdef SECURE_ELEMENT_DRIVER_ENABLED
#include "esp_log.h"
#include "psa_crypto_driver_secure_element.h"
static const char *TAG = "psa_crypto_driver_secure_element";
#define UNCOMPRESSED_POINT_FORMAT 0x04
/* Runtime-registered SE callbacks (set once via secure_element_register_callbacks) */
static const secure_element_callbacks_t *s_se_callbacks = NULL;
psa_status_t secure_element_register_callbacks(const secure_element_callbacks_t *callbacks)
{
if (callbacks == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (callbacks->key_bits == 0) {
ESP_LOGE(TAG, "key_bits must be set in callbacks");
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Atomic compare-and-swap: only the first registration succeeds */
const secure_element_callbacks_t *expected = NULL;
if (!atomic_compare_exchange_strong((volatile _Atomic(const secure_element_callbacks_t *) *)&s_se_callbacks,
&expected, callbacks)) {
ESP_LOGE(TAG, "Secure element callbacks already registered");
return PSA_ERROR_BAD_STATE;
}
return PSA_SUCCESS;
}
/**
* @brief Get the registered callbacks, or NULL if not yet registered
*/
static inline const secure_element_callbacks_t *se_get_callbacks(void)
{
return s_se_callbacks;
}
/**
* @brief Check if a request matches the registered SE capabilities
*
* Compares the algorithm and key type from the request against what the SE
* declared at registration time. Returns PSA_ERROR_NOT_SUPPORTED on mismatch.
*/
static psa_status_t validate_request(psa_algorithm_t alg, const psa_key_attributes_t *attributes)
{
const secure_element_callbacks_t *cbs = se_get_callbacks();
if (!cbs) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* Check algorithm family matches (e.g., both are ECDSA) */
psa_algorithm_t registered_alg = cbs->algorithm;
/* Use PSA_ALG_SIGN_GET_HASH to compare base algorithm ignoring hash */
if (PSA_ALG_IS_ECDSA(registered_alg)) {
if (!PSA_ALG_IS_ECDSA(alg)) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* If registered with a specific hash, check it matches */
psa_algorithm_t reg_hash = PSA_ALG_SIGN_GET_HASH(registered_alg);
if (reg_hash != PSA_ALG_ANY_HASH && reg_hash != PSA_ALG_SIGN_GET_HASH(alg)) {
return PSA_ERROR_NOT_SUPPORTED;
}
} else if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(registered_alg)) {
if (!PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg)) {
return PSA_ERROR_NOT_SUPPORTED;
}
} else if (registered_alg != alg) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* Check key type matches */
if (attributes) {
psa_key_type_t req_type = psa_get_key_type(attributes);
/* Accept both key pair and public key for the same family */
psa_key_type_t reg_base = PSA_KEY_TYPE_IS_KEY_PAIR(cbs->key_type)
? PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY(PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(cbs->key_type))
: cbs->key_type;
psa_key_type_t req_base = PSA_KEY_TYPE_IS_KEY_PAIR(req_type)
? PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY(PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(req_type))
: req_type;
if (reg_base != req_base) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* Check key size matches */
size_t req_bits = psa_get_key_bits(attributes);
if (req_bits != 0 && req_bits != cbs->key_bits) {
return PSA_ERROR_NOT_SUPPORTED;
}
}
return PSA_SUCCESS;
}
/* Transparent verify operations */
psa_status_t secure_element_transparent_verify_hash_start(
secure_element_transparent_verify_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
if (!operation || !attributes || !key_buffer || !hash || !signature) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Validate against registered SE capabilities */
psa_status_t status = validate_request(alg, attributes);
if (status != PSA_SUCCESS) {
return status;
}
size_t key_len = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes));
if (key_len == 0 || key_len > SECURE_ELEMENT_MAX_KEY_BYTES) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Verify key buffer can hold the uncompressed public key (0x04 || X || Y) */
if (key_buffer_size < 1 + 2 * key_len) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Validate hash length matches key component length */
if (hash_length != key_len) {
return PSA_ERROR_NOT_SUPPORTED;
}
if (signature_length != 2 * key_len) {
return PSA_ERROR_INVALID_SIGNATURE;
}
/* Handle public key format - must be uncompressed (0x04 || X || Y) */
if (key_buffer[0] != UNCOMPRESSED_POINT_FORMAT) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size != 2 * key_len + 1) {
return PSA_ERROR_INVALID_ARGUMENT;
}
memset(operation, 0, sizeof(secure_element_transparent_verify_hash_operation_t));
operation->key_len = key_len;
operation->sha_len = hash_length;
/* Big-endian format, matching PSA format */
memcpy(operation->sha, hash, key_len);
memcpy(operation->r, signature, key_len);
memcpy(operation->s, signature + key_len, key_len);
/* Extract public key coordinates (skip 0x04 format byte) */
memcpy(operation->qx, key_buffer + 1, key_len);
memcpy(operation->qy, key_buffer + 1 + key_len, key_len);
return PSA_SUCCESS;
}
psa_status_t secure_element_transparent_verify_hash_complete(secure_element_transparent_verify_hash_operation_t *operation)
{
if (!operation) {
return PSA_ERROR_INVALID_ARGUMENT;
}
const secure_element_callbacks_t *cbs = se_get_callbacks();
if (!cbs || !cbs->verify) {
ESP_LOGE(TAG, "Secure element verify callback not registered");
return PSA_ERROR_NOT_SUPPORTED;
}
size_t key_len = operation->key_len;
/* Construct public key (X || Y) */
uint8_t pubkey[2 * SECURE_ELEMENT_MAX_KEY_BYTES];
memcpy(pubkey, operation->qx, key_len);
memcpy(pubkey + key_len, operation->qy, key_len);
/* Construct signature (R || S) */
uint8_t sig[2 * SECURE_ELEMENT_MAX_KEY_BYTES];
memcpy(sig, operation->r, key_len);
memcpy(sig + key_len, operation->s, key_len);
/* Verify using registered SE callback */
bool is_verified = false;
psa_status_t status = cbs->verify(operation->sha, operation->sha_len,
sig, 2 * key_len,
pubkey, 2 * key_len,
&is_verified);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "SE verify callback failed: 0x%04x", (unsigned)status);
return status;
}
if (!is_verified) {
return PSA_ERROR_INVALID_SIGNATURE;
}
return PSA_SUCCESS;
}
psa_status_t secure_element_transparent_verify_hash_abort(secure_element_transparent_verify_hash_operation_t *operation)
{
if (operation) {
memset(operation, 0, sizeof(secure_element_transparent_verify_hash_operation_t));
}
return PSA_SUCCESS;
}
psa_status_t secure_element_transparent_verify_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
secure_element_transparent_verify_hash_operation_t operation;
psa_status_t status = secure_element_transparent_verify_hash_start(
&operation, attributes, key_buffer, key_buffer_size,
alg, hash, hash_length, signature, signature_length);
if (status != PSA_SUCCESS) {
return status;
}
status = secure_element_transparent_verify_hash_complete(&operation);
if (status != PSA_SUCCESS) {
return status;
}
return secure_element_transparent_verify_hash_abort(&operation);
}
/* Opaque sign operations */
psa_status_t secure_element_opaque_import_key(
const psa_key_attributes_t *attributes,
const uint8_t *data,
size_t data_length,
uint8_t *key_buffer,
size_t key_buffer_size,
size_t *key_buffer_length,
size_t *bits)
{
if (!attributes || !data || data_length < 1 || !key_buffer || !key_buffer_length || !bits) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size < sizeof(secure_element_opaque_key_t) || data_length < sizeof(secure_element_opaque_key_t)) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
/* Validate the key attributes match what the SE supports */
const secure_element_callbacks_t *cbs = se_get_callbacks();
if (!cbs) {
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t status = validate_request(psa_get_key_algorithm(attributes), attributes);
if (status != PSA_SUCCESS) {
return status;
}
memcpy(key_buffer, data, sizeof(secure_element_opaque_key_t));
*key_buffer_length = sizeof(secure_element_opaque_key_t);
*bits = psa_get_key_bits(attributes);
return PSA_SUCCESS;
}
psa_status_t secure_element_opaque_sign_hash_start(
secure_element_opaque_sign_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length)
{
if (!operation || !attributes || !key_buffer || !hash) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size < sizeof(secure_element_opaque_key_t)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Validate against registered SE capabilities */
psa_status_t status = validate_request(alg, attributes);
if (status != PSA_SUCCESS) {
return status;
}
size_t component_len = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes));
if (component_len == 0 || component_len > SECURE_ELEMENT_MAX_KEY_BYTES) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Validate hash length matches key component length */
if (hash_length != component_len) {
return PSA_ERROR_INVALID_ARGUMENT;
}
memset(operation, 0, sizeof(secure_element_opaque_sign_hash_operation_t));
operation->key_len = component_len;
memcpy(operation->sha, hash, component_len);
operation->opaque_key = (secure_element_opaque_key_t *) key_buffer;
operation->alg = alg;
operation->sha_len = hash_length;
return PSA_SUCCESS;
}
psa_status_t secure_element_opaque_sign_hash_complete(
secure_element_opaque_sign_hash_operation_t *operation,
uint8_t *signature, size_t signature_size,
size_t *signature_length)
{
if (!operation || !signature || !signature_length) {
return PSA_ERROR_INVALID_ARGUMENT;
}
size_t component_len = operation->key_len;
if (signature_size < 2 * component_len) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
const secure_element_callbacks_t *cbs = se_get_callbacks();
if (!cbs || !cbs->sign) {
ESP_LOGE(TAG, "Secure element sign callback not registered");
return PSA_ERROR_NOT_SUPPORTED;
}
/* Sign using registered SE callback */
uint8_t sig[2 * SECURE_ELEMENT_MAX_KEY_BYTES];
size_t sig_len = 0;
psa_status_t status = cbs->sign(operation->opaque_key->slot_id,
operation->sha, operation->sha_len,
sig, sizeof(sig), &sig_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "SE sign callback failed: 0x%04x", (unsigned)status);
return status;
}
/* Copy signature to output (R || S format, big-endian - matches PSA) */
memcpy(signature, sig, 2 * component_len);
*signature_length = 2 * component_len;
return PSA_SUCCESS;
}
psa_status_t secure_element_opaque_sign_hash_abort(secure_element_opaque_sign_hash_operation_t *operation)
{
if (operation) {
memset(operation, 0, sizeof(secure_element_opaque_sign_hash_operation_t));
}
return PSA_SUCCESS;
}
psa_status_t secure_element_opaque_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
secure_element_opaque_sign_hash_operation_t operation;
psa_status_t status = secure_element_opaque_sign_hash_start(
&operation, attributes, key_buffer, key_buffer_size, alg, hash, hash_length);
if (status != PSA_SUCCESS) {
secure_element_opaque_sign_hash_abort(&operation);
return status;
}
status = secure_element_opaque_sign_hash_complete(&operation, signature, signature_size, signature_length);
if (status != PSA_SUCCESS) {
secure_element_opaque_sign_hash_abort(&operation);
return status;
}
return secure_element_opaque_sign_hash_abort(&operation);
}
psa_status_t secure_element_opaque_export_public_key(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
uint8_t *data,
size_t data_size,
size_t *data_length)
{
if (!attributes || !key_buffer || !data || !data_length) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size < sizeof(secure_element_opaque_key_t)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
const secure_element_opaque_key_t *opaque_key = (const secure_element_opaque_key_t *) key_buffer;
const secure_element_callbacks_t *cbs = se_get_callbacks();
if (!cbs || !cbs->export_pubkey) {
ESP_LOGE(TAG, "Secure element export_pubkey callback not registered");
return PSA_ERROR_NOT_SUPPORTED;
}
/* Get key length from registered capabilities */
size_t key_len = PSA_BITS_TO_BYTES(cbs->key_bits);
/* Need 1 byte for format + key_len bytes for x + key_len bytes for y */
size_t required_size = 1 + (2 * key_len);
if (data_size < required_size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
/* Export public key using registered SE callback */
uint8_t pubkey[2 * SECURE_ELEMENT_MAX_KEY_BYTES];
size_t pubkey_len = 0;
psa_status_t status = cbs->export_pubkey(opaque_key->slot_id, pubkey, sizeof(pubkey), &pubkey_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "SE export_pubkey callback failed: 0x%04x", (unsigned)status);
return status;
}
/* Format: uncompressed point (0x04 followed by x and y coordinates) */
data[0] = UNCOMPRESSED_POINT_FORMAT;
memcpy(data + 1, pubkey, key_len); /* X coordinate */
memcpy(data + 1 + key_len, pubkey + key_len, key_len); /* Y coordinate */
*data_length = required_size;
return PSA_SUCCESS;
}
size_t secure_element_opaque_size_function(
psa_key_type_t key_type,
size_t key_bits)
{
(void)key_type;
(void)key_bits;
/* Opaque keys always use the same size structure */
return sizeof(secure_element_opaque_key_t);
}
#endif /* SECURE_ELEMENT_DRIVER_ENABLED */

View File

@@ -0,0 +1,5 @@
# Renamed ATCA/SE ECDSA options to generic secure element (v6.0)
CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED
CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED
CONFIG_MBEDTLS_SE_HW_ECDSA_SIGN CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED
CONFIG_MBEDTLS_SE_HW_ECDSA_VERIFY CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED

View File

@@ -207,23 +207,23 @@ To use a custom TLS stack in your project, follow these steps:
ATECC608A (Secure Element) with ESP-TLS
--------------------------------------------------
ESP-TLS provides support for using ATECC608A cryptoauth chip with ESP32 series of SoCs. The use of ATECC608A is supported only when ESP-TLS is used with MbedTLS as its underlying SSL/TLS stack. ESP-TLS uses MbedTLS as its underlying TLS/SSL stack by default unless changed manually.
ESP-TLS provides support for using ATECC608A cryptoauth chip with ESP32 series of SoCs via the PSA Crypto opaque driver interface. The use of ATECC608A is supported only when ESP-TLS is used with MbedTLS as its underlying SSL/TLS stack. ESP-TLS uses MbedTLS as its underlying TLS/SSL stack by default unless changed manually.
.. note::
ATECC608A chip interfaced to ESP32 series must be already configured. For details, please refer to `esp_cryptoauth_utility <https://github.com/espressif/esp-cryptoauthlib/blob/master/esp_cryptoauth_utility/README.md#esp_cryptoauth_utility>`_.
To enable the secure element support, and use it in your project for TLS connection, you have to follow the below steps:
To enable the secure element support, and use it in your project for TLS connection, follow the steps below:
1) Add `esp-cryptoauthlib <https://github.com/espressif/esp-cryptoauthlib>`_ in your project, for details please refer `how to use esp-cryptoauthlib with ESP-IDF <https://github.com/espressif/esp-cryptoauthlib#how-to-use-esp-cryptoauthlib-with-esp-idf>`_.
1) Add `esp-cryptoauthlib <https://github.com/espressif/esp-cryptoauthlib>`_ as a dependency in your project. For details, please refer to `how to use esp-cryptoauthlib with ESP-IDF <https://github.com/espressif/esp-cryptoauthlib#how-to-use-esp-cryptoauthlib-with-esp-idf>`_.
2) Enable the menuconfig option :ref:`CONFIG_ESP_TLS_USE_SECURE_ELEMENT`:
2) Enable the menuconfig option :ref:`CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED`:
.. code-block:: none
menuconfig > Component config > ESP-TLS > Use Secure Element (ATECC608A) with ESP-TLS
menuconfig > Component config > mbedTLS > Enable secure element hardware support
3) Select type of ATECC608A chip with following option:
3) Select the type of ATECC608A chip:
.. code-block:: none
@@ -231,13 +231,40 @@ To enable the secure element support, and use it in your project for TLS connect
To know more about different types of ATECC608A chips and how to obtain the type of ATECC608A connected to your ESP module, please visit `ATECC608A chip type <https://github.com/espressif/esp-cryptoauthlib/blob/master/esp_cryptoauth_utility/README.md#find-type-of-atecc608a-chip-connected-to-esp32-wroom32-se>`_.
4) Enable the use of ATECC608A in ESP-TLS by providing the following config option in :cpp:type:`esp_tls_cfg_t`:
4) Import the ATECC608A key and configure ESP-TLS to use it via :cpp:type:`esp_key_config_t`:
.. code-block:: c
#include "psa/crypto.h"
#include "psa_crypto_driver_secure_element.h"
#include "psa_crypto_driver_secure_element_contexts.h"
#include "esp_key_config.h"
/* Import ATECC608A key reference into PSA */
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_lifetime(&key_attr, PSA_KEY_LIFETIME_SECURE_ELEMENT_VOLATILE);
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attr, 256);
secure_element_opaque_key_t opaque_key = {
.slot_id = 0, /* Private key slot on ATECC608A */
};
psa_key_id_t psa_key_id;
psa_import_key(&key_attr, (const uint8_t *)&opaque_key,
sizeof(opaque_key), &psa_key_id);
/* Configure ESP-TLS to use the PSA key */
esp_key_config_t key_config = {
.source = ESP_KEY_SOURCE_PSA,
.psa.key_id = psa_key_id,
};
esp_tls_cfg_t cfg = {
/* other configurations options */
.use_secure_element = true,
/* other configuration options */
.client_key = &key_config,
};
.. only:: SOC_DIG_SIGN_SUPPORTED

View File

@@ -207,7 +207,7 @@ ESP-TLS 组件支持通过 :cpp:func:`esp_tls_register_stack` API 注册自定
ESP-TLS 中的 ATECC608A安全元件
-----------------------------------------
ESP-TLS 支持在 ESP32 系列芯片上使用 ATECC608A 加密芯片,但必须将 MbedTLS 作为 ESP-TLS 的底层 SSL/TLS 协议栈。未经手动更改ESP-TLS 默认以 MbedTLS 为其底层 TLS/SSL 协议栈。
ESP-TLS 支持通过 PSA Crypto 不透明驱动接口在 ESP32 系列芯片上使用 ATECC608A 加密芯片。使用 ATECC608A 时必须将 MbedTLS 作为 ESP-TLS 的底层 SSL/TLS 协议栈。未经手动更改ESP-TLS 默认以 MbedTLS 为其底层 TLS/SSL 协议栈。
.. note::
@@ -215,13 +215,13 @@ ESP-TLS 支持在 ESP32 系列芯片上使用 ATECC608A 加密芯片,但必须
要启用安全元件支持,并将其应用于工程 TLS 连接,请遵循以下步骤:
1) 在工程中添加 `esp-cryptoauthlib <https://github.com/espressif/esp-cryptoauthlib>`_,详情请参阅 `如何在 ESP-IDF 中使用 esp-cryptoauthlib <https://github.com/espressif/esp-cryptoauthlib#how-to-use-esp-cryptoauthlib-with-esp-idf>`_
1) 在工程中添加 `esp-cryptoauthlib <https://github.com/espressif/esp-cryptoauthlib>`_ 作为依赖,详情请参阅 `如何在 ESP-IDF 中使用 esp-cryptoauthlib <https://github.com/espressif/esp-cryptoauthlib#how-to-use-esp-cryptoauthlib-with-esp-idf>`_
2) 启用 menuconfig 选项 :ref:`CONFIG_ESP_TLS_USE_SECURE_ELEMENT`
2) 启用 menuconfig 选项 :ref:`CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED`
.. code-block:: none
menuconfig > Component config > ESP-TLS > Use Secure Element (ATECC608A) with ESP-TLS
menuconfig > Component config > mbedTLS > Enable secure element hardware support
3) 选择 ATECC608A 芯片类型:
@@ -231,13 +231,40 @@ ESP-TLS 支持在 ESP32 系列芯片上使用 ATECC608A 加密芯片,但必须
如需了解更多 ATECC608A 芯片类型,或需了解如何获取连接到特定 ESP 模块的 ATECC608A 芯片类型,请参阅 `ATECC608A 芯片类型 <https://github.com/espressif/esp-cryptoauthlib/blob/master/esp_cryptoauth_utility/README.md#find-type-of-atecc608a-chip-connected-to-esp32-wroom32-se>`_
4) :cpp:type:`esp_tls_cfg_t` 中提供以下配置,在 ESP-TLS 中启用 ATECC608A
4) 初始化 PSA Crypto导入 ATECC608A 密钥,并通过 :cpp:type:`esp_key_config_t` 配置 ESP-TLS 使用
.. code-block:: c
#include "psa/crypto.h"
#include "psa_crypto_driver_secure_element.h"
#include "psa_crypto_driver_secure_element_contexts.h"
#include "esp_key_config.h"
/* 将 ATECC608A 密钥引用导入 PSA */
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_lifetime(&key_attr, PSA_KEY_LIFETIME_SECURE_ELEMENT_VOLATILE);
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attr, 256);
secure_element_opaque_key_t opaque_key = {
.slot_id = 0, /* ATECC608A 上的私钥槽位 */
};
psa_key_id_t psa_key_id;
psa_import_key(&key_attr, (const uint8_t *)&opaque_key,
sizeof(opaque_key), &psa_key_id);
/* 配置 ESP-TLS 使用 PSA 密钥 */
esp_key_config_t key_config = {
.source = ESP_KEY_SOURCE_PSA,
.psa.key_id = psa_key_id,
};
esp_tls_cfg_t cfg = {
/* 其他配置选项 */
.use_secure_element = true,
.client_key = &key_config,
};
.. only:: SOC_DIG_SIGN_SUPPORTED