From 43e1bed40cc027ca27ab6fb87c9993fe8a39d201 Mon Sep 17 00:00:00 2001 From: Cal Abel Date: Thu, 2 Jul 2026 22:05:22 -0400 Subject: [PATCH] Add async TLS 1.3 key exchange and AEAD record support Signed-off-by: Cal Abel --- library/ssl_misc.h | 11 ++++++ library/ssl_msg.c | 59 ++++++++++++++++++++++++++++++- library/ssl_tls13_keys.c | 76 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index ffe09a4d1a..ba642de50a 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -789,6 +789,7 @@ struct mbedtls_ssl_handshake_params { size_t xxdh_psa_peerkey_len; #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) psa_key_agreement_iop_t xxdh_psa_iop; + uint8_t xxdh_psa_iop_active; #endif #endif /* MBEDTLS_KEY_EXCHANGE_SOME_XXDH_PSA_ANY_ENABLED */ @@ -1763,6 +1764,16 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2(mbedtls_ssl_context *ssl, #endif void mbedtls_ssl_transform_init(mbedtls_ssl_transform *transform); +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +MBEDTLS_CHECK_RETURN_CRITICAL +int mbedtls_ssl_configure_async_aead_transform( + mbedtls_ssl_transform *transform, + psa_key_type_t key_type, + psa_algorithm_t alg, + const unsigned char *key_enc, + const unsigned char *key_dec, + size_t key_len); +#endif MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_encrypt_buf(mbedtls_ssl_context *ssl, mbedtls_ssl_transform *transform, diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 79e837aa7a..f92974b10a 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -98,6 +98,61 @@ static int samd_mbedtls_ssl_transform_has_aead( sizeof(transform->samd_aead_key_enc) && transform->ivlen == 12; } + +int mbedtls_ssl_configure_async_aead_transform( + mbedtls_ssl_transform *transform, + psa_key_type_t key_type, + psa_algorithm_t alg, + const unsigned char *key_enc, + const unsigned char *key_dec, + size_t key_len) +{ + unsigned char async_algorithm = 0; + + if (transform == NULL || key_enc == NULL || key_dec == NULL || + key_len == 0 || key_len > sizeof(transform->samd_aead_key_enc) || + transform->ivlen != 12 || transform->taglen != 16) { + return 0; + } + + if (key_type == PSA_KEY_TYPE_AES && alg == PSA_ALG_GCM) { + if (key_len == 16) { + async_algorithm = MBEDTLS_ASYNC_HARDWARE_TLS_AEAD_AES_128_GCM; + } else if (key_len == 32) { + async_algorithm = MBEDTLS_ASYNC_HARDWARE_TLS_AEAD_AES_256_GCM; + } + } else if (key_type == PSA_KEY_TYPE_CHACHA20 && + alg == PSA_ALG_CHACHA20_POLY1305 && key_len == 32) { + async_algorithm = MBEDTLS_ASYNC_HARDWARE_TLS_AEAD_CHACHA20_POLY1305; + } + + if (async_algorithm == 0) { + return 0; + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) + if (transform->tls_version == MBEDTLS_SSL_VERSION_TLS1_3) { + if (transform->fixed_ivlen != 12) { + return 0; + } + } else +#endif + { + if (transform->fixed_ivlen != 4 && + !(key_type == PSA_KEY_TYPE_CHACHA20 && + alg == PSA_ALG_CHACHA20_POLY1305 && + transform->fixed_ivlen == 12)) { + return 0; + } + } + + memcpy(transform->samd_aead_key_enc, key_enc, key_len); + memcpy(transform->samd_aead_key_dec, key_dec, key_len); + transform->samd_aead_key_len = key_len; + transform->samd_aead_algorithm = async_algorithm; + transform->samd_aead_keys_configured = 1; + return 1; +} #endif #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) @@ -4881,7 +4936,9 @@ static int ssl_get_next_record(mbedtls_ssl_context *ssl) if (ssl->transform_in != NULL && ssl->transform_in->samd_aead_pending != 0) { const size_t header_len = mbedtls_ssl_in_hdr_len(ssl); - const size_t explicit_iv_len = sizeof(rec.ctr); + const size_t explicit_iv_len = + ssl_transform_aead_dynamic_iv_is_explicit(ssl->transform_in) ? + sizeof(rec.ctr) : 0; const size_t record_len = MBEDTLS_GET_UINT16_BE(ssl->in_len, 0); if (record_len < explicit_iv_len + ssl->transform_in->taglen) { diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c index 865e02c2dc..1231e55731 100644 --- a/library/ssl_tls13_keys.c +++ b/library/ssl_tls13_keys.c @@ -1012,6 +1012,12 @@ int mbedtls_ssl_tls13_populate_transform( transform->psa_alg = alg; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + int async_aead_configured = mbedtls_ssl_configure_async_aead_transform( + transform, key_type, alg, key_enc, key_dec, PSA_BITS_TO_BYTES(key_bits)); + (void) async_aead_configured; +#endif + if (alg != MBEDTLS_SSL_NULL_CIPHER) { psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); psa_set_key_algorithm(&attributes, alg); @@ -1440,11 +1446,16 @@ static int ssl_tls13_key_schedule_stage_handshake(mbedtls_ssl_context *ssl) /* Compute ECDH shared secret. */ psa_status_t status = PSA_ERROR_GENERIC_ERROR; psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + mbedtls_svc_key_id_t shared_secret_key = MBEDTLS_SVC_KEY_ID_INIT; + psa_status_t shared_secret_key_destruction_status = + PSA_ERROR_GENERIC_ERROR; status = psa_get_key_attributes(handshake->xxdh_psa_privkey, &key_attributes); if (status != PSA_SUCCESS) { ret = PSA_TO_MBEDTLS_ERR(status); + MBEDTLS_SSL_DEBUG_RET(1, "psa_get_key_attributes", ret); + goto cleanup; } shared_secret_len = PSA_BITS_TO_BYTES( @@ -1454,6 +1465,70 @@ static int ssl_tls13_key_schedule_stage_handshake(mbedtls_ssl_context *ssl) return MBEDTLS_ERR_SSL_ALLOC_FAILED; } +#if defined(MBEDTLS_ASYNC_HARDWARE_ECDH) && \ + defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + if (handshake->xxdh_psa_iop_active == 0) { + psa_key_attributes_t secret_attributes = + psa_key_attributes_init(); + psa_set_key_usage_flags(&secret_attributes, + PSA_KEY_USAGE_EXPORT); + psa_set_key_type(&secret_attributes, PSA_KEY_TYPE_RAW_DATA); + psa_set_key_bits(&secret_attributes, + PSA_BYTES_TO_BITS(shared_secret_len)); + + status = psa_key_agreement_iop_setup( + &handshake->xxdh_psa_iop, + handshake->xxdh_psa_privkey, + handshake->xxdh_psa_peerkey, + handshake->xxdh_psa_peerkey_len, + alg, + &secret_attributes); + if (status != PSA_SUCCESS) { + (void) psa_key_agreement_iop_abort( + &handshake->xxdh_psa_iop); + ret = PSA_TO_MBEDTLS_ERR(status); + MBEDTLS_SSL_DEBUG_RET(1, "psa_key_agreement_iop_setup", + ret); + goto cleanup; + } + handshake->xxdh_psa_iop_active = 1; + } + + status = psa_key_agreement_iop_complete( + &handshake->xxdh_psa_iop, + &shared_secret_key); + if (status == PSA_OPERATION_INCOMPLETE) { + mbedtls_free(shared_secret); + return MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; + } + + (void) psa_key_agreement_iop_abort(&handshake->xxdh_psa_iop); + handshake->xxdh_psa_iop_active = 0; + + if (status != PSA_SUCCESS) { + ret = PSA_TO_MBEDTLS_ERR(status); + MBEDTLS_SSL_DEBUG_RET(1, "psa_key_agreement_iop_complete", + ret); + goto cleanup; + } + + status = psa_export_key(shared_secret_key, + shared_secret, + shared_secret_len, + &shared_secret_len); + shared_secret_key_destruction_status = + psa_destroy_key(shared_secret_key); + if (status != PSA_SUCCESS) { + ret = PSA_TO_MBEDTLS_ERR(status); + MBEDTLS_SSL_DEBUG_RET(1, "psa_export_key", ret); + goto cleanup; + } + if (shared_secret_key_destruction_status != PSA_SUCCESS) { + ret = PSA_TO_MBEDTLS_ERR(shared_secret_key_destruction_status); + MBEDTLS_SSL_DEBUG_RET(1, "psa_destroy_key", ret); + goto cleanup; + } +#else status = psa_raw_key_agreement( alg, handshake->xxdh_psa_privkey, handshake->xxdh_psa_peerkey, handshake->xxdh_psa_peerkey_len, @@ -1463,6 +1538,7 @@ static int ssl_tls13_key_schedule_stage_handshake(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_RET(1, "psa_raw_key_agreement", ret); goto cleanup; } +#endif status = psa_destroy_key(handshake->xxdh_psa_privkey); if (status != PSA_SUCCESS) {