mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
Merge branch 'feature/unified_priv_key_interface_across_idf' into 'master'
feat(esp-tls): Added a PSA driver for Secure Element See merge request espressif/esp-idf!44987
This commit is contained in:
@@ -22,7 +22,10 @@ endif()
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} esp-tls-crypto
|
||||
PRIV_INCLUDE_DIRS "private_include"
|
||||
REQUIRES mbedtls
|
||||
# mbedtls is public requirements because esp_tls.h
|
||||
# includes mbedtls header files.
|
||||
# esp_security is public because esp_tls.h includes esp_key_config.h
|
||||
REQUIRES mbedtls esp_security
|
||||
PRIV_REQUIRES ${priv_req})
|
||||
|
||||
idf_define_esp_err_codes(HEADERS esp_tls_errors.h)
|
||||
@@ -35,8 +38,3 @@ else()
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_TLS_WITH_LWIP=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(CONFIG_ESP_TLS_USE_SECURE_ELEMENT)
|
||||
idf_component_optional_requires(PRIVATE espressif__esp-cryptoauthlib esp-cryptoauthlib)
|
||||
endif()
|
||||
|
||||
@@ -22,16 +22,6 @@ menu "ESP-TLS"
|
||||
esp_tls_stack_ops_t interface.
|
||||
endchoice
|
||||
|
||||
config ESP_TLS_USE_SECURE_ELEMENT
|
||||
bool "Use Secure Element (ATECC608A) with ESP-TLS"
|
||||
depends on ESP_TLS_USING_MBEDTLS
|
||||
select ATCA_MBEDTLS_ECDSA
|
||||
select ATCA_MBEDTLS_ECDSA_SIGN
|
||||
select ATCA_MBEDTLS_ECDSA_VERIFY
|
||||
help
|
||||
Enable use of Secure Element for ESP-TLS, this enables internal support for
|
||||
ATECC608A peripheral, which can be used for TLS connection.
|
||||
|
||||
config ESP_TLS_USE_DS_PERIPHERAL
|
||||
bool "Use Digital Signature (DS) Peripheral with ESP-TLS"
|
||||
depends on ESP_TLS_USING_MBEDTLS && SOC_DIG_SIGN_SUPPORTED
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_tls_errors.h"
|
||||
#include "esp_key_config.h"
|
||||
#include "sdkconfig.h"
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
#include "mbedtls/ssl.h"
|
||||
@@ -160,6 +161,10 @@ typedef struct esp_tls_cfg {
|
||||
const unsigned char *clientkey_pem_buf; /*!< Client key legacy name */
|
||||
};
|
||||
|
||||
const esp_key_config_t *client_key; /*!< Unified key config. Must remain valid for session lifetime.
|
||||
Any PSA key referenced here remains owned by the caller; ESP-TLS does not
|
||||
destroy it on cleanup, so the application must release it with psa_destroy_key(). */
|
||||
|
||||
union {
|
||||
unsigned int clientkey_bytes; /*!< Size of client key pointed to by
|
||||
clientkey_pem_buf
|
||||
@@ -184,9 +189,6 @@ typedef struct esp_tls_cfg {
|
||||
underneath socket will be configured in non
|
||||
blocking mode after tls session is established */
|
||||
|
||||
bool use_secure_element; /*!< Enable this option to use secure element or
|
||||
atecc608a chip */
|
||||
|
||||
int timeout_ms; /*!< Network timeout in milliseconds.
|
||||
Note: If this value is not set, by default the timeout is
|
||||
set to 10 seconds. If you wish that the session should wait
|
||||
@@ -315,6 +317,10 @@ typedef struct esp_tls_cfg_server {
|
||||
const unsigned char *serverkey_pem_buf; /*!< Server key legacy name */
|
||||
};
|
||||
|
||||
const esp_key_config_t *server_key; /*!< Unified key config. Must remain valid for session lifetime.
|
||||
Any PSA key referenced here remains owned by the caller; ESP-TLS does not
|
||||
destroy it on cleanup, so the application must release it with psa_destroy_key(). */
|
||||
|
||||
union {
|
||||
unsigned int serverkey_bytes; /*!< Size of server key pointed to by
|
||||
serverkey_pem_buf */
|
||||
@@ -334,9 +340,6 @@ typedef struct esp_tls_cfg_server {
|
||||
|
||||
esp_tls_ecdsa_curve_t ecdsa_curve; /*!< ECDSA curve to use (SECP256R1 or SECP384R1) */
|
||||
|
||||
bool use_secure_element; /*!< Enable this option to use secure element or
|
||||
atecc608a chip */
|
||||
|
||||
uint32_t tls_handshake_timeout_ms; /*!< TLS handshake timeout in milliseconds.
|
||||
Note: If this value is not set, by default the timeout is
|
||||
set to 10 seconds. If you wish that the session should wait
|
||||
|
||||
@@ -32,16 +32,6 @@
|
||||
#include "esp_crt_bundle.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
/* cryptoauthlib includes */
|
||||
#include "mbedtls/atca_mbedtls_wrap.h"
|
||||
#include "tng_atca.h"
|
||||
#include "cryptoauthlib.h"
|
||||
static const atcacert_def_t *cert_def = NULL;
|
||||
/* Prototypes for functions */
|
||||
static esp_err_t esp_set_atecc608a_pki_context(esp_tls_t *tls, const void *pki);
|
||||
#endif /* CONFIG_ESP_TLS_USE_SECURE_ELEMENT */
|
||||
|
||||
#if defined(CONFIG_ESP_TLS_USE_DS_PERIPHERAL)
|
||||
#include <pk_wrap.h>
|
||||
#include "psa/crypto.h"
|
||||
@@ -493,27 +483,32 @@ void esp_mbedtls_cleanup(esp_tls_t *tls)
|
||||
mbedtls_x509_crt_free(&tls->cacert);
|
||||
mbedtls_x509_crt_free(&tls->clientcert);
|
||||
|
||||
/* For opaque keys (DS peripheral, hardware ECDSA), mbedtls_pk_free() does
|
||||
* not destroy the PSA key — ownership is external. Destroy it manually
|
||||
* before calling mbedtls_pk_free(). mbedtls_pk_wrap_psa() sets the pk_info
|
||||
* to mbedtls_{rsa,ecdsa}_opaque_info, both of which have type
|
||||
* MBEDTLS_PK_OPAQUE — so a single check covers both DS and ECDSA paths.
|
||||
* clientkey and serverkey share storage via union, so one branch suffices. */
|
||||
#if defined(CONFIG_ESP_TLS_USE_DS_PERIPHERAL) || defined(CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN)
|
||||
/* For opaque keys, mbedtls_pk_free() does not release the underlying PSA
|
||||
* key — ownership is tracked separately. Dispatch on ownership, not on the
|
||||
* key lifetime: a caller-supplied key (ESP_KEY_SOURCE_PSA, e.g. a
|
||||
* pre-provisioned secure element) is owned externally and must never be
|
||||
* destroyed on connection close — at most purge it to drop the cached slot
|
||||
* (a no-op for a volatile key). A key esp-tls created itself is always
|
||||
* volatile and is destroyed to release its slot. mbedtls_pk_wrap_psa() sets
|
||||
* the pk_info to mbedtls_{rsa,ecdsa}_opaque_info, both of type
|
||||
* MBEDTLS_PK_OPAQUE, so one runtime check covers every opaque path (DS
|
||||
* peripheral, hardware ECDSA, and caller-supplied PSA keys). clientkey and
|
||||
* serverkey share storage via union, so one branch suffices. */
|
||||
if (mbedtls_pk_get_type(&tls->clientkey) == MBEDTLS_PK_OPAQUE) {
|
||||
if (tls->clientkey.MBEDTLS_PRIVATE(priv_id) != PSA_KEY_ID_NULL) {
|
||||
psa_destroy_key(tls->clientkey.MBEDTLS_PRIVATE(priv_id));
|
||||
psa_key_id_t kid = tls->clientkey.MBEDTLS_PRIVATE(priv_id);
|
||||
if (kid != PSA_KEY_ID_NULL) {
|
||||
if (tls->opaque_key_is_external) {
|
||||
psa_purge_key(kid);
|
||||
} else {
|
||||
psa_destroy_key(kid);
|
||||
}
|
||||
tls->clientkey.MBEDTLS_PRIVATE(priv_id) = PSA_KEY_ID_NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mbedtls_pk_free(&tls->clientkey);
|
||||
mbedtls_ssl_config_free(&tls->conf);
|
||||
mbedtls_ssl_free(&tls->ssl);
|
||||
#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
atcab_release();
|
||||
#endif
|
||||
}
|
||||
|
||||
static esp_err_t set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacert_len)
|
||||
@@ -757,28 +752,53 @@ static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
|
||||
#endif // CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
|
||||
}
|
||||
|
||||
if (cfg->use_secure_element) {
|
||||
#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
if (cfg->server_key != NULL && cfg->server_key->source == ESP_KEY_SOURCE_BUFFER) {
|
||||
/* Unified key config with buffer source */
|
||||
esp_tls_pki_t pki = {
|
||||
.public_cert = &tls->servercert,
|
||||
.pk_key = &tls->serverkey,
|
||||
.publiccert_pem_buf = cfg->servercert_buf,
|
||||
.publiccert_pem_bytes = cfg->servercert_bytes,
|
||||
.privkey_pem_buf = NULL,
|
||||
.privkey_pem_bytes = 0,
|
||||
.privkey_password = NULL,
|
||||
.privkey_password_len = 0,
|
||||
.privkey_pem_buf = cfg->server_key->buffer.data,
|
||||
.privkey_pem_bytes = cfg->server_key->buffer.len,
|
||||
.privkey_password = (const unsigned char *)cfg->server_key->buffer.password,
|
||||
.privkey_password_len = cfg->server_key->buffer.password_len,
|
||||
};
|
||||
|
||||
ret = esp_set_atecc608a_pki_context(tls, (void*) &pki);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
esp_ret = set_pki_context(tls, &pki);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set server pki context");
|
||||
return esp_ret;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "Please enable secure element support for ESP-TLS in menuconfig");
|
||||
return ESP_FAIL;
|
||||
#endif /* CONFIG_ESP_TLS_USE_SECURE_ELEMENT */
|
||||
} else if (cfg->use_ecdsa_peripheral) {
|
||||
} else if (cfg->server_key != NULL && cfg->server_key->source == ESP_KEY_SOURCE_PSA) {
|
||||
if (cfg->servercert_buf == NULL) {
|
||||
ESP_LOGE(TAG, "Server certificate is required when using a PSA-backed server key");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
mbedtls_svc_key_id_t key_id = cfg->server_key->psa.key_id;
|
||||
mbedtls_pk_init(&tls->serverkey);
|
||||
tls->opaque_key_is_external = true;
|
||||
ret = mbedtls_pk_wrap_psa(&tls->serverkey, key_id);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_pk_wrap_psa returned -0x%04X", -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED;
|
||||
}
|
||||
ret = mbedtls_x509_crt_parse(&tls->servercert, cfg->servercert_buf, cfg->servercert_bytes);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%04X", -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
|
||||
}
|
||||
ret = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->servercert, &tls->serverkey);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%04X", -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED;
|
||||
}
|
||||
} else if (cfg->use_ecdsa_peripheral) {
|
||||
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
|
||||
tls->use_ecdsa_peripheral = cfg->use_ecdsa_peripheral;
|
||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
@@ -997,26 +1017,52 @@ esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cfg->use_secure_element) {
|
||||
#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
if (cfg->client_key != NULL && cfg->client_key->source == ESP_KEY_SOURCE_BUFFER) {
|
||||
/* Unified key config with buffer source */
|
||||
esp_tls_pki_t pki = {
|
||||
.public_cert = &tls->clientcert,
|
||||
.pk_key = &tls->clientkey,
|
||||
.publiccert_pem_buf = cfg->clientcert_buf,
|
||||
.publiccert_pem_bytes = cfg->clientcert_bytes,
|
||||
.privkey_pem_buf = NULL,
|
||||
.privkey_pem_bytes = 0,
|
||||
.privkey_password = NULL,
|
||||
.privkey_password_len = 0,
|
||||
.privkey_pem_buf = cfg->client_key->buffer.data,
|
||||
.privkey_pem_bytes = cfg->client_key->buffer.len,
|
||||
.privkey_password = (const unsigned char *)cfg->client_key->buffer.password,
|
||||
.privkey_password_len = cfg->client_key->buffer.password_len,
|
||||
};
|
||||
ret = esp_set_atecc608a_pki_context(tls, (void*) &pki);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
esp_err_t esp_ret = set_pki_context(tls, &pki);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set client pki context");
|
||||
return esp_ret;
|
||||
}
|
||||
} else if (cfg->client_key != NULL && cfg->client_key->source == ESP_KEY_SOURCE_PSA) {
|
||||
if (cfg->clientcert_buf == NULL) {
|
||||
ESP_LOGE(TAG, "Client certificate is required when using a PSA-backed client key");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
mbedtls_svc_key_id_t key_id = cfg->client_key->psa.key_id;
|
||||
mbedtls_pk_init(&tls->clientkey);
|
||||
tls->opaque_key_is_external = true;
|
||||
ret = mbedtls_pk_wrap_psa(&tls->clientkey, key_id);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_pk_wrap_psa returned -0x%04X", -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED;
|
||||
}
|
||||
ret = mbedtls_x509_crt_parse(&tls->clientcert, cfg->clientcert_buf, cfg->clientcert_bytes);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%04X", -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
|
||||
}
|
||||
ret = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->clientcert, &tls->clientkey);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%04X", -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "Please enable secure element support for ESP-TLS in menuconfig");
|
||||
return ESP_FAIL;
|
||||
#endif /* CONFIG_ESP_TLS_USE_SECURE_ELEMENT */
|
||||
} else if (cfg->ds_data != NULL) {
|
||||
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
if (cfg->clientcert_pem_buf == NULL) {
|
||||
@@ -1278,92 +1324,6 @@ const int *esp_mbedtls_get_ciphersuites_list(void)
|
||||
return mbedtls_ssl_list_ciphersuites();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
static esp_err_t esp_init_atecc608a(uint8_t i2c_addr)
|
||||
{
|
||||
cfg_ateccx08a_i2c_default.atcai2c.address = i2c_addr;
|
||||
int ret = atcab_init(&cfg_ateccx08a_i2c_default);
|
||||
if(ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to initialize atca device, returned -0x%04X", -ret);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_set_atecc608a_pki_context(esp_tls_t *tls, const void *pki)
|
||||
{
|
||||
int ret = 0;
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
ESP_LOGI(TAG, "Initialize the ATECC interface...");
|
||||
(void)esp_ret;
|
||||
(void)cert_def;
|
||||
#if defined(CONFIG_ATECC608A_TNG) || defined(CONFIG_ATECC608A_TFLEX)
|
||||
#ifdef CONFIG_ATECC608A_TNG
|
||||
esp_ret = esp_init_atecc608a(CONFIG_ATCA_I2C_ADDRESS);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_ERR_ESP_TLS_SE_FAILED;
|
||||
}
|
||||
#elif CONFIG_ATECC608A_TFLEX /* CONFIG_ATECC608A_TNG */
|
||||
esp_ret = esp_init_atecc608a(CONFIG_ATCA_I2C_ADDRESS);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_ERR_ESP_TLS_SE_FAILED;
|
||||
}
|
||||
#endif /* CONFIG_ATECC608A_TFLEX */
|
||||
mbedtls_x509_crt_init(&tls->clientcert);
|
||||
ret = tng_get_device_cert_def(&cert_def);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to get device cert def");
|
||||
return ESP_ERR_ESP_TLS_SE_FAILED;
|
||||
}
|
||||
|
||||
/* Extract the device certificate and convert to mbedtls cert */
|
||||
ret = atca_mbedtls_cert_add(&tls->clientcert, cert_def);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to parse cert from device, return 0x%04X", ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
return ESP_ERR_ESP_TLS_SE_FAILED;
|
||||
}
|
||||
#elif CONFIG_ATECC608A_TCUSTOM
|
||||
esp_ret = esp_init_atecc608a(CONFIG_ATCA_I2C_ADDRESS);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_ERR_ESP_TLS_SE_FAILED;
|
||||
}
|
||||
mbedtls_x509_crt_init(&tls->clientcert);
|
||||
|
||||
esp_tls_pki_t *pki_l = (esp_tls_pki_t *) pki;
|
||||
if (pki_l->publiccert_pem_buf != NULL) {
|
||||
ret = mbedtls_x509_crt_parse(&tls->clientcert, pki_l->publiccert_pem_buf, pki_l->publiccert_pem_bytes);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse of client cert returned -0x%04X", -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Device certificate must be provided for TrustCustom Certs");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif /* CONFIG_ATECC608A_TCUSTOM */
|
||||
ret = atca_mbedtls_pk_init(&tls->clientkey, 0);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to parse key from device");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
return ESP_ERR_ESP_TLS_SE_FAILED;
|
||||
}
|
||||
|
||||
ret = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->clientcert, &tls->clientkey);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to configure client cert, returned -0x%04X", ret);
|
||||
mbedtls_print_error_msg(ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_ESP_TLS_SE_FAILED;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* CONFIG_ESP_TLS_USE_SECURE_ELEMENT */
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
/*
|
||||
* tf-psa-crypto 1.1 made mbedtls_pk_wrap_psa() call psa_export_public_key() on
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
hint: "The struct 'esp_tls_t' has now been made private - its elements can be only be accessed/modified through respective getter/setter functions. Please refer to the migration guide for more information."
|
||||
-
|
||||
re: "fatal error: .*atca_mbedtls_wrap\\.h: No such file or directory"
|
||||
hint: "To use CONFIG_ESP_TLS_USE_SECURE_ELEMENT option, please install `esp-cryptoauthlib` using 'idf.py add-dependency espressif/esp-cryptoauthlib'"
|
||||
hint: "The cryptoauthlib mbedTLS wrapper (atca_mbedtls_wrap.h) is no longer used to integrate a secure element. Enable CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED, install `esp-cryptoauthlib` using 'idf.py add-dependency espressif/esp-cryptoauthlib', and provide the key via esp_key_config_t (ESP_KEY_SOURCE_PSA). Please refer to the migration guide for more information."
|
||||
|
||||
@@ -52,6 +52,10 @@ struct esp_tls {
|
||||
mbedtls_pk_context serverkey; /*!< Container for the private key of the server
|
||||
certificate */
|
||||
};
|
||||
|
||||
bool opaque_key_is_external; /*!< True when the opaque PSA client/server key was supplied
|
||||
by the caller (ESP_KEY_SOURCE_PSA). Such keys are owned
|
||||
externally and must never be destroyed on cleanup. */
|
||||
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
|
||||
bool use_ecdsa_peripheral; /*!< Use the ECDSA peripheral for the private key operations. */
|
||||
uint8_t ecdsa_efuse_blk; /*!< The efuse block number where the ECDSA key is stored. */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
if(NOT ${IDF_TARGET} STREQUAL "linux")
|
||||
set(req lwip esp_event)
|
||||
set(req lwip esp_event esp_security)
|
||||
else()
|
||||
set(req linux esp_event)
|
||||
set(req linux esp_event esp_security)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "esp_http_client.c"
|
||||
|
||||
@@ -938,12 +938,6 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
if (config->use_secure_element) {
|
||||
esp_transport_ssl_use_secure_element(ssl);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
if (config->ds_data != NULL) {
|
||||
esp_transport_ssl_set_ds_data(ssl, config->ds_data);
|
||||
@@ -962,26 +956,32 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config->client_key_pem) {
|
||||
if (!config->client_key_len) {
|
||||
esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem));
|
||||
} else {
|
||||
esp_transport_ssl_set_client_key_data_der(ssl, config->client_key_pem, config->client_key_len);
|
||||
/* Check for unified key config */
|
||||
if (config->client_key != NULL) {
|
||||
esp_transport_ssl_set_client_key_config(ssl, config->client_key);
|
||||
} else {
|
||||
/* Legacy key configuration */
|
||||
if (config->client_key_pem) {
|
||||
if (!config->client_key_len) {
|
||||
esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem));
|
||||
} else {
|
||||
esp_transport_ssl_set_client_key_data_der(ssl, config->client_key_pem, config->client_key_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
|
||||
if (config->use_ecdsa_peripheral) {
|
||||
if (config->use_ecdsa_peripheral) {
|
||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
esp_transport_ssl_set_client_key_ecdsa_peripheral_extended(ssl, config->ecdsa_key_efuse_blk, config->ecdsa_key_efuse_blk_high);
|
||||
esp_transport_ssl_set_client_key_ecdsa_peripheral_extended(ssl, config->ecdsa_key_efuse_blk, config->ecdsa_key_efuse_blk_high);
|
||||
#else
|
||||
esp_transport_ssl_set_client_key_ecdsa_peripheral(ssl, config->ecdsa_key_efuse_blk);
|
||||
esp_transport_ssl_set_client_key_ecdsa_peripheral(ssl, config->ecdsa_key_efuse_blk);
|
||||
#endif
|
||||
// Set the ECDSA curve
|
||||
esp_transport_ssl_set_ecdsa_curve(ssl, config->ecdsa_curve);
|
||||
}
|
||||
// Set the ECDSA curve
|
||||
esp_transport_ssl_set_ecdsa_curve(ssl, config->ecdsa_curve);
|
||||
}
|
||||
#endif
|
||||
if (config->client_key_password && config->client_key_password_len > 0) {
|
||||
esp_transport_ssl_set_client_key_password(ssl, config->client_key_password, config->client_key_password_len);
|
||||
if (config->client_key_password && config->client_key_password_len > 0) {
|
||||
esp_transport_ssl_set_client_key_password(ssl, config->client_key_password, config->client_key_password_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (config->skip_cert_common_name_check) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_key_config.h"
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -200,6 +201,7 @@ typedef struct {
|
||||
DER Certificate - Length of the buffer pointed to by client_cert_der. Should be the length of the certificate. */
|
||||
const char *client_key_pem; /*!< SSL client key, PEM format as string, if the server requires to verify client */
|
||||
size_t client_key_len; /*!< Length of the buffer pointed to by client_key_pem. May be 0 for null-terminated pem */
|
||||
const esp_key_config_t *client_key; /*!< Unified client key configuration. Takes precedence over client_key_pem when set */
|
||||
const char *client_key_password; /*!< Client key decryption password string */
|
||||
size_t client_key_password_len; /*!< String length of the password pointed to by client_key_password */
|
||||
esp_http_client_proto_ver_t tls_version; /*!< TLS protocol version of the connection, e.g., TLS 1.2, TLS 1.3 (default - no preference) */
|
||||
@@ -237,9 +239,6 @@ typedef struct {
|
||||
const char **alpn_protos; /*!< Application protocols required for HTTP2. If HTTP2/ALPN support is required, a list of protocols that should be negotiated. The format is length followed by protocol
|
||||
name. For the most common cases the following is ok: const char **alpn_protos = { "h2", NULL }; - where 'h2' is the protocol name */
|
||||
#endif
|
||||
#if CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
bool use_secure_element; /*!< Enable this option to use secure element */
|
||||
#endif
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
void *ds_data; /*!< Pointer for digital signature peripheral context, see ESP-TLS Documentation for more details */
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -105,6 +105,9 @@ struct httpd_ssl_config {
|
||||
/** Private key byte length */
|
||||
size_t prvtkey_len;
|
||||
|
||||
/** Unified key config. Takes precedence over prvtkey_pem when set */
|
||||
const esp_key_config_t *server_key;
|
||||
|
||||
/** Use ECDSA peripheral to use private key */
|
||||
bool use_ecdsa_peripheral;
|
||||
|
||||
@@ -129,9 +132,6 @@ struct httpd_ssl_config {
|
||||
/** Enable tls session tickets */
|
||||
bool session_tickets;
|
||||
|
||||
/** Enable secure element for server session */
|
||||
bool use_secure_element;
|
||||
|
||||
/** User callback for esp_https_server */
|
||||
esp_https_server_user_cb *user_cb;
|
||||
|
||||
@@ -219,6 +219,7 @@ typedef struct httpd_ssl_config httpd_ssl_config_t;
|
||||
HTTPD_SSL_CONFIG_CLIENT_AUTH_OPTIONAL_INIT \
|
||||
.prvtkey_pem = NULL, \
|
||||
.prvtkey_len = 0, \
|
||||
.server_key = NULL, \
|
||||
.use_ecdsa_peripheral = false, \
|
||||
.ecdsa_key_efuse_blk = 0, \
|
||||
.ecdsa_key_efuse_blk_high = 0, \
|
||||
@@ -227,7 +228,6 @@ typedef struct httpd_ssl_config httpd_ssl_config_t;
|
||||
.port_secure = 443, \
|
||||
.port_insecure = 80, \
|
||||
.session_tickets = false, \
|
||||
.use_secure_element = false, \
|
||||
.user_cb = NULL, \
|
||||
.ssl_userdata = NULL, \
|
||||
.cert_select_cb = NULL, \
|
||||
|
||||
@@ -348,48 +348,47 @@ static esp_err_t create_secure_context(const struct httpd_ssl_config *config, ht
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pass on secure element boolean */
|
||||
cfg->use_secure_element = config->use_secure_element;
|
||||
if (!cfg->use_secure_element) {
|
||||
if (config->use_ecdsa_peripheral) {
|
||||
if (config->use_ecdsa_peripheral) {
|
||||
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
|
||||
(*ssl_ctx)->tls_cfg->use_ecdsa_peripheral = config->use_ecdsa_peripheral;
|
||||
(*ssl_ctx)->tls_cfg->ecdsa_key_efuse_blk = config->ecdsa_key_efuse_blk;
|
||||
(*ssl_ctx)->tls_cfg->use_ecdsa_peripheral = config->use_ecdsa_peripheral;
|
||||
(*ssl_ctx)->tls_cfg->ecdsa_key_efuse_blk = config->ecdsa_key_efuse_blk;
|
||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
(*ssl_ctx)->tls_cfg->ecdsa_key_efuse_blk_high = config->ecdsa_key_efuse_blk_high;
|
||||
(*ssl_ctx)->tls_cfg->ecdsa_key_efuse_blk_high = config->ecdsa_key_efuse_blk_high;
|
||||
#endif
|
||||
(*ssl_ctx)->tls_cfg->ecdsa_curve = config->ecdsa_curve;
|
||||
(*ssl_ctx)->tls_cfg->ecdsa_curve = config->ecdsa_curve;
|
||||
#else
|
||||
ESP_LOGE(TAG, "Please enable the support for signing using ECDSA peripheral in menuconfig.");
|
||||
ret = ESP_ERR_NOT_SUPPORTED;
|
||||
goto exit;
|
||||
ESP_LOGE(TAG, "Please enable the support for signing using ECDSA peripheral in menuconfig.");
|
||||
ret = ESP_ERR_NOT_SUPPORTED;
|
||||
goto exit;
|
||||
#endif
|
||||
} else if (config->prvtkey_pem != NULL && config->prvtkey_len > 0) {
|
||||
cfg->serverkey_buf = malloc(config->prvtkey_len);
|
||||
} else if (config->server_key != NULL) {
|
||||
/* Unified key config - pass directly to esp_tls */
|
||||
cfg->server_key = config->server_key;
|
||||
} else if (config->prvtkey_pem != NULL && config->prvtkey_len > 0) {
|
||||
cfg->serverkey_buf = malloc(config->prvtkey_len);
|
||||
|
||||
if (cfg->serverkey_buf) {
|
||||
memcpy((char *) cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
|
||||
cfg->serverkey_bytes = config->prvtkey_len;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Could not allocate memory for server key");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto exit;
|
||||
}
|
||||
if (cfg->serverkey_buf) {
|
||||
memcpy((char *) cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
|
||||
cfg->serverkey_bytes = config->prvtkey_len;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Could not allocate memory for server key");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
#if defined(CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK)
|
||||
if (config->cert_select_cb == NULL) {
|
||||
ESP_LOGE(TAG, "No Server key supplied and no certificate selection hook is present");
|
||||
ret = ESP_ERR_INVALID_ARG;
|
||||
goto exit;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Server key not supplied, make sure to supply it in the certificate selection hook");
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "No Server key supplied");
|
||||
if (config->cert_select_cb == NULL) {
|
||||
ESP_LOGE(TAG, "No Server key supplied and no certificate selection hook is present");
|
||||
ret = ESP_ERR_INVALID_ARG;
|
||||
goto exit;
|
||||
#endif
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Server key not supplied, make sure to supply it in the certificate selection hook");
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "No Server key supplied");
|
||||
ret = ESP_ERR_INVALID_ARG;
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -2,7 +2,9 @@ idf_build_get_property(target IDF_TARGET)
|
||||
idf_build_get_property(non_os_build NON_OS_BUILD)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
# On linux, only provide headers (esp_key_config.h) without any source files
|
||||
idf_component_register(INCLUDE_DIRS "include")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(srcs "")
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Key format */
|
||||
typedef enum {
|
||||
ESP_KEY_FORMAT_AUTO = 0, /*!< Auto-detect */
|
||||
ESP_KEY_FORMAT_PEM, /*!< PEM (base64) */
|
||||
ESP_KEY_FORMAT_DER, /*!< DER (binary) */
|
||||
ESP_KEY_FORMAT_RAW, /*!< Raw key bytes */
|
||||
} esp_key_format_t;
|
||||
|
||||
/**
|
||||
* Key source types
|
||||
*
|
||||
* Hardware-backed key sources (DS peripheral, ECDSA peripheral,
|
||||
* secure element, key manager) as well as software PSA imported keys
|
||||
* are accessed via PSA Crypto drivers. Use ESP_KEY_SOURCE_PSA with
|
||||
* the PSA key ID obtained from psa_import_key() or the corresponding
|
||||
* hardware setup helper API.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_KEY_SOURCE_NONE = 0, /*!< No private key configured */
|
||||
ESP_KEY_SOURCE_BUFFER, /*!< Key in memory buffer (PEM/DER/RAW) */
|
||||
ESP_KEY_SOURCE_PSA, /*!< PSA Crypto key (opaque or transparent) */
|
||||
} esp_key_source_t;
|
||||
|
||||
/**
|
||||
* Unified private key configuration
|
||||
*
|
||||
* For hardware-backed keys (DS peripheral, ECDSA peripheral, ATECC608,
|
||||
* key manager), use ESP_KEY_SOURCE_PSA with the key ID returned by
|
||||
* the respective setup helper (e.g., esp_secure_element_psa_setup()).
|
||||
*
|
||||
* @note Must remain valid for the entire TLS session lifetime
|
||||
*/
|
||||
typedef struct esp_key_config {
|
||||
esp_key_source_t source; /*!< Key source type */
|
||||
|
||||
union {
|
||||
struct {
|
||||
const void *data; /*!< Key data (PEM/DER/RAW) */
|
||||
size_t len; /*!< Length (0 for null-terminated PEM) */
|
||||
const char *password; /*!< Decryption password */
|
||||
size_t password_len; /*!< Password length */
|
||||
esp_key_format_t format; /*!< Key format */
|
||||
} buffer;
|
||||
|
||||
struct {
|
||||
uint32_t key_id; /*!< PSA key identifier */
|
||||
} psa;
|
||||
};
|
||||
|
||||
} esp_key_config_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -481,6 +481,12 @@ 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")
|
||||
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")
|
||||
@@ -548,11 +554,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...")
|
||||
|
||||
+13
-18
@@ -1032,49 +1032,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
|
||||
@@ -1542,19 +1542,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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -267,12 +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
|
||||
#ifdef CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED
|
||||
#define SECURE_ELEMENT_DRIVER_ENABLED
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_HARDWARE_ECC
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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. Only the first
|
||||
* call succeeds; subsequent calls return PSA_ERROR_BAD_STATE.
|
||||
*
|
||||
* @param callbacks Pointer to callback table. The contents are copied
|
||||
* internally, so the struct need not remain valid after
|
||||
* this call returns.
|
||||
* @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 */
|
||||
+65
@@ -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
|
||||
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* 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 "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_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).
|
||||
* We keep a value copy so the caller's struct lifetime does not matter. */
|
||||
static secure_element_callbacks_t s_se_callbacks;
|
||||
static const secure_element_callbacks_t *s_se_callbacks_ptr = 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;
|
||||
}
|
||||
|
||||
if (s_se_callbacks_ptr != NULL) {
|
||||
ESP_LOGE(TAG, "Secure element callbacks already registered");
|
||||
return PSA_ERROR_BAD_STATE;
|
||||
}
|
||||
|
||||
s_se_callbacks = *callbacks;
|
||||
s_se_callbacks_ptr = &s_se_callbacks;
|
||||
|
||||
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_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
/* 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 (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);
|
||||
memcpy(&operation->opaque_key, key_buffer, sizeof(secure_element_opaque_key_t));
|
||||
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;
|
||||
}
|
||||
|
||||
if (sig_len == 0 || sig_len > sizeof(sig)) {
|
||||
ESP_LOGE(TAG, "SE returned invalid signature length: %zu", sig_len);
|
||||
return PSA_ERROR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
if (sig_len > signature_size) {
|
||||
return PSA_ERROR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
/* Copy signature to output (R || S format, big-endian - matches PSA) */
|
||||
memcpy(signature, sig, sig_len);
|
||||
*signature_length = sig_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;
|
||||
}
|
||||
|
||||
/* Callback must have written exactly 2 * key_len bytes (X || Y) - reject anything else
|
||||
* to avoid copying uninitialized stack memory into the caller's buffer. */
|
||||
if (pubkey_len != 2 * key_len) {
|
||||
ESP_LOGE(TAG, "SE export_pubkey returned %u bytes, expected %u",
|
||||
(unsigned)pubkey_len, (unsigned)(2 * key_len));
|
||||
return PSA_ERROR_HARDWARE_FAILURE;
|
||||
}
|
||||
|
||||
/* 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 /* CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED */
|
||||
@@ -0,0 +1,3 @@
|
||||
# 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
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -206,15 +206,6 @@ void esp_transport_ssl_set_common_name(esp_transport_handle_t t, const char *com
|
||||
*/
|
||||
void esp_transport_ssl_set_ciphersuites_list(esp_transport_handle_t t, const int *ciphersuites_list);
|
||||
|
||||
/**
|
||||
* @brief Set the ssl context to use secure element (atecc608a) for client(device) private key and certificate
|
||||
*
|
||||
* @note Recommended to be used with ESP32 series interfaced to ATECC608A based secure element
|
||||
*
|
||||
* @param t ssl transport
|
||||
*/
|
||||
void esp_transport_ssl_use_secure_element(esp_transport_handle_t t);
|
||||
|
||||
/**
|
||||
* @brief Set the ds_data handle in ssl context.(used for the digital signature operation)
|
||||
*
|
||||
@@ -223,6 +214,26 @@ void esp_transport_ssl_use_secure_element(esp_transport_handle_t t);
|
||||
*/
|
||||
void esp_transport_ssl_set_ds_data(esp_transport_handle_t t, void *ds_data);
|
||||
|
||||
/**
|
||||
* @brief Set unified client key configuration for mutual authentication
|
||||
*
|
||||
* This function provides a unified way to configure client private keys
|
||||
* from various sources (buffer, ECDSA peripheral, secure element, etc.)
|
||||
* using the esp_key_config_t structure.
|
||||
*
|
||||
* @note This function stores the pointer to config, rather than making a copy.
|
||||
* So the config must remain valid until after the connection is cleaned up.
|
||||
*
|
||||
* @note When client_key is set, it takes precedence over legacy key configuration
|
||||
* functions (set_client_key_data, set_client_key_ecdsa_peripheral, etc.)
|
||||
*
|
||||
* @param t ssl transport
|
||||
* @param[in] client_key Pointer to the unified key configuration
|
||||
*
|
||||
* @see esp_key_config_t for configuration options
|
||||
*/
|
||||
void esp_transport_ssl_set_client_key_config(esp_transport_handle_t t, const esp_key_config_t *client_key);
|
||||
|
||||
/**
|
||||
* @brief Set PSK key and hint for PSK server/client verification in esp-tls component.
|
||||
* Important notes:
|
||||
|
||||
@@ -502,14 +502,6 @@ void esp_transport_ssl_set_ciphersuites_list(esp_transport_handle_t t, const int
|
||||
ssl->cfg.ciphersuites_list = ciphersuites_list;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT
|
||||
void esp_transport_ssl_use_secure_element(esp_transport_handle_t t)
|
||||
{
|
||||
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
|
||||
ssl->cfg.use_secure_element = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
|
||||
void esp_transport_ssl_crt_bundle_attach(esp_transport_handle_t t, esp_err_t ((*crt_bundle_attach)(void *conf)))
|
||||
{
|
||||
@@ -575,6 +567,12 @@ void esp_transport_ssl_set_ds_data(esp_transport_handle_t t, void *ds_data)
|
||||
}
|
||||
#endif
|
||||
|
||||
void esp_transport_ssl_set_client_key_config(esp_transport_handle_t t, const esp_key_config_t *client_key)
|
||||
{
|
||||
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
|
||||
ssl->cfg.client_key = client_key;
|
||||
}
|
||||
|
||||
void esp_transport_ssl_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg)
|
||||
{
|
||||
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
|
||||
|
||||
Reference in New Issue
Block a user