From 8cb64703fff3526b9540e5f78ef640baaa4b3809 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Thu, 21 May 2026 13:43:28 +0800 Subject: [PATCH] fix(esp-tls): fixes DS peripheral use case with tf-psa-crypto 1.1 --- components/esp-tls/esp_tls_mbedtls.c | 122 ++++++++++++++------------- 1 file changed, 65 insertions(+), 57 deletions(-) diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index ebcfba4cf11..901d4ba713b 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -495,36 +495,17 @@ void esp_mbedtls_cleanup(esp_tls_t *tls) /* 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(). */ -#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL - if (mbedtls_pk_get_type(&tls->clientkey) == MBEDTLS_PK_RSASSA_PSS) { + * 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) + 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)); tls->clientkey.MBEDTLS_PRIVATE(priv_id) = PSA_KEY_ID_NULL; } } - if (mbedtls_pk_get_type(&tls->serverkey) == MBEDTLS_PK_RSASSA_PSS) { - if (tls->serverkey.MBEDTLS_PRIVATE(priv_id) != PSA_KEY_ID_NULL) { - psa_destroy_key(tls->serverkey.MBEDTLS_PRIVATE(priv_id)); - tls->serverkey.MBEDTLS_PRIVATE(priv_id) = PSA_KEY_ID_NULL; - } - } -#endif - -#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN - if (mbedtls_pk_get_type(&tls->clientkey) == MBEDTLS_PK_ECDSA) { - ESP_LOGD(TAG, "Cleaning up client key"); - if (tls->clientkey.MBEDTLS_PRIVATE(priv_id) != PSA_KEY_ID_NULL) { - psa_destroy_key(tls->clientkey.MBEDTLS_PRIVATE(priv_id)); - tls->clientkey.MBEDTLS_PRIVATE(priv_id) = PSA_KEY_ID_NULL; - } - } - if (mbedtls_pk_get_type(&tls->serverkey) == MBEDTLS_PK_ECDSA) { - if (tls->serverkey.MBEDTLS_PRIVATE(priv_id) != PSA_KEY_ID_NULL) { - psa_destroy_key(tls->serverkey.MBEDTLS_PRIVATE(priv_id)); - tls->serverkey.MBEDTLS_PRIVATE(priv_id) = PSA_KEY_ID_NULL; - } - } #endif mbedtls_pk_free(&tls->clientkey); @@ -624,6 +605,7 @@ static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki) // Import opaque key reference psa_status_t status = psa_import_key(&key_attr, (uint8_t*) &opaque_key, sizeof(opaque_key), &priv_key_id); + psa_reset_key_attributes(&key_attr); if (status != PSA_SUCCESS) { ESP_LOGE(TAG, "Failed to import opaque key reference"); return ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED; @@ -632,10 +614,9 @@ static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki) ret = mbedtls_pk_wrap_psa(pki->pk_key, priv_key_id); if (ret != 0) { ESP_LOGE(TAG, "Failed to wrap opaque key reference"); + psa_destroy_key(priv_key_id); return ret; } - - psa_reset_key_attributes(&key_attr); } else #endif if (pki->privkey_pem_buf != NULL) { @@ -1384,46 +1365,73 @@ static esp_err_t esp_set_atecc608a_pki_context(esp_tls_t *tls, const void *pki) #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 + * the imported PSA key. The DS peripheral cannot expose any key material + * (private or public), so the export fails with PK_INVALID_ALG. Copy the + * already-parsed raw public key from the device certificate so wrap_psa()'s + * export step short-circuits (pk.c:145-148, returns early when pub_raw_len>0). + */ +static esp_err_t inject_rsa_pubkey_from_cert(mbedtls_pk_context *dst, const mbedtls_x509_crt *cert) +{ + const mbedtls_pk_context *src = &cert->pk; + size_t src_len = src->MBEDTLS_PRIVATE(pub_raw_len); + if (src_len == 0 || src_len > sizeof(dst->MBEDTLS_PRIVATE(pub_raw))) { + ESP_LOGE(TAG, "Invalid cert pubkey length: %zu", src_len); + return ESP_ERR_INVALID_STATE; + } + memcpy(dst->MBEDTLS_PRIVATE(pub_raw), src->MBEDTLS_PRIVATE(pub_raw), src_len); + dst->MBEDTLS_PRIVATE(pub_raw_len) = src_len; + dst->MBEDTLS_PRIVATE(bits) = src->MBEDTLS_PRIVATE(bits); + dst->MBEDTLS_PRIVATE(psa_type) = PSA_KEY_TYPE_RSA_PUBLIC_KEY; + return ESP_OK; +} + +static psa_status_t import_ds_key(const esp_ds_data_ctx_t *ds_data, psa_key_id_t *out_key_id) +{ + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; + rsa_ds_opaque_key.ds_data_ctx = (esp_ds_data_ctx_t *)ds_data; + + psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_type(&attrs, PSA_KEY_TYPE_RSA_KEY_PAIR); + psa_set_key_bits(&attrs, ds_data->rsa_length_bits); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attrs, PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)); +#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 + psa_set_key_enrollment_algorithm(&attrs, PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH)); +#endif + psa_set_key_lifetime(&attrs, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); + + psa_status_t status = psa_import_key(&attrs, + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), + out_key_id); + psa_reset_key_attributes(&attrs); + return status; +} + static esp_err_t esp_mbedtls_init_pk_ctx_for_ds(const void *pki) { - esp_ds_data_ctx_t *ds_data = ((const esp_tls_pki_t*)pki)->esp_ds_data; - if (ds_data == NULL) { - ESP_LOGE(TAG, "DS data context is NULL"); - return ESP_ERR_INVALID_ARG; - } - - esp_tls_pki_t *pki_l = (esp_tls_pki_t *) pki; - if (pki_l->pk_key == NULL) { - ESP_LOGE(TAG, "PK key context is NULL"); + const esp_tls_pki_t *pki_l = (const esp_tls_pki_t *)pki; + if (pki_l->esp_ds_data == NULL || pki_l->pk_key == NULL || pki_l->public_cert == NULL) { + ESP_LOGE(TAG, "DS pki context missing required fields"); return ESP_ERR_INVALID_ARG; } psa_key_id_t ds_key_id = 0; - psa_status_t status = PSA_ERROR_GENERIC_ERROR; - - esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; - rsa_ds_opaque_key.ds_data_ctx = ds_data; - - psa_key_attributes_t ds_key_attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH); -#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 - psa_set_key_enrollment_algorithm(&ds_key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH)); -#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */ - - psa_set_key_type(&ds_key_attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); - psa_set_key_bits(&ds_key_attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); - psa_set_key_usage_flags(&ds_key_attributes, PSA_KEY_USAGE_SIGN_HASH); - psa_set_key_algorithm(&ds_key_attributes, alg); - psa_set_key_lifetime(&ds_key_attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); - status = psa_import_key(&ds_key_attributes, - (const uint8_t *)&rsa_ds_opaque_key, - sizeof(rsa_ds_opaque_key), - &ds_key_id); - psa_reset_key_attributes(&ds_key_attributes); + psa_status_t status = import_ds_key(pki_l->esp_ds_data, &ds_key_id); if (status != PSA_SUCCESS) { ESP_LOGE(TAG, "Failed to import DS key to PSA, status = %d", status); return ESP_ERR_INVALID_STATE; } + + /* Pre-populate pub_raw so wrap_psa() does not attempt to export it. */ + esp_err_t esp_ret = inject_rsa_pubkey_from_cert(pki_l->pk_key, pki_l->public_cert); + if (esp_ret != ESP_OK) { + psa_destroy_key(ds_key_id); + return esp_ret; + } + int ret = mbedtls_pk_wrap_psa(pki_l->pk_key, ds_key_id); if (ret != 0) { ESP_LOGE(TAG, "mbedtls_pk_wrap_psa failed with -0x%04X", -ret);