From 7016e506de620ff158db1c562f5b9ed3529ca048 Mon Sep 17 00:00:00 2001 From: Cal Abel Date: Fri, 10 Jul 2026 12:50:48 -0400 Subject: [PATCH] Resume asynchronous TLS 1.3 handshake operations Signed-off-by: Cal Abel --- library/ssl_misc.h | 2 + library/ssl_msg.c | 22 ++++++--- library/ssl_tls13_client.c | 93 ++++++++++++++++++++++++++++++++++++-- library/ssl_tls13_server.c | 92 ++++++++++++++++++++++++++++++++++++- 4 files changed, 198 insertions(+), 11 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index b655bc464e..c2f18c7606 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -724,6 +724,8 @@ struct mbedtls_ssl_handshake_params { ssl_ecrs_crt_verify, /*!< Certificate: crt_verify() */ ssl_ecrs_ske_start_processing, /*!< ServerKeyExchange: pk_verify() */ ssl_ecrs_ske_sign, /*!< ServerKeyExchange: pk_sign() */ + ssl_ecrs_tls13_server_hello_finalize, /*!< ServerHello: key schedule */ + ssl_ecrs_tls13_server_hello_postprocess, /*!< ServerHello: peer key schedule */ ssl_ecrs_cke_ecdh_calc_secret, /*!< ClientKeyExchange: ECDH step 2 */ ssl_ecrs_crt_vrfy_sign, /*!< CertificateVerify: pk_sign() */ } ecrs_state; /*!< current (or last) operation */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index d5ce7a55b4..c6ee7bdf75 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -970,12 +970,22 @@ int mbedtls_ssl_encrypt_buf(mbedtls_ssl_context *ssl, size_t padding = ssl_compute_padding_length(rec->data_len, MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY); - if (ssl_build_inner_plaintext(data, - &rec->data_len, - post_avail, - rec->type, - padding) != 0) { - return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + if (transform->async_hardware_aead_pending != 0) { + if (post_avail < padding + 1) { + return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; + } + rec->data_len += padding + 1; + } else +#endif + { + if (ssl_build_inner_plaintext(data, + &rec->data_len, + post_avail, + rec->type, + padding) != 0) { + return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; + } } rec->type = MBEDTLS_SSL_MSG_APPLICATION_DATA; diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 9b7ca82f91..b10b0e35df 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -1859,6 +1859,13 @@ static int ssl_tls13_postprocess_server_hello(mbedtls_ssl_context *ssl) int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_ssl_handshake_params *handshake = ssl->handshake; +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + if (handshake->ecrs_state == + ssl_ecrs_tls13_server_hello_postprocess) { + goto compute_handshake_transform; + } +#endif + /* Determine the key exchange mode: * 1) If both the pre_shared_key and key_share extensions were received * then the key exchange mode is PSK with EPHEMERAL. @@ -1932,7 +1939,16 @@ static int ssl_tls13_postprocess_server_hello(mbedtls_ssl_context *ssl) } } +compute_handshake_transform: ret = mbedtls_ssl_tls13_compute_handshake_transform(ssl); +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) { + ssl->handshake->ecrs_state = + ssl_ecrs_tls13_server_hello_postprocess; + goto cleanup; + } + ssl->handshake->ecrs_state = ssl_ecrs_none; +#endif if (ret != 0) { MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_tls13_compute_handshake_transform", @@ -1945,7 +1961,7 @@ static int ssl_tls13_postprocess_server_hello(mbedtls_ssl_context *ssl) ssl->session_in = ssl->session_negotiate; cleanup: - if (ret != 0) { + if (ret != 0 && ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) { MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE); @@ -1997,6 +2013,18 @@ static int ssl_tls13_process_server_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> %s", __func__)); +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + if (ssl->handshake->ecrs_state == + ssl_ecrs_tls13_server_hello_postprocess) { + ret = ssl_tls13_postprocess_server_hello(ssl); + if (ret == 0) { + mbedtls_ssl_handshake_set_state( + ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS); + } + goto cleanup; + } +#endif + MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, &buf, &buf_len)); @@ -2628,18 +2656,46 @@ static int ssl_tls13_process_server_finished(mbedtls_ssl_context *ssl) /* * Handler for MBEDTLS_SSL_CLIENT_CERTIFICATE */ +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +static int ssl_tls13_resume_pending_record(mbedtls_ssl_context *ssl) +{ + if (ssl->transform_out == NULL || + ssl->transform_out->async_hardware_aead_pending == 0) { + return 0; + } + + int ret = mbedtls_ssl_write_record(ssl, 1); + return ret == 0 ? 1 : ret; +} +#endif + MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_tls13_write_client_certificate(mbedtls_ssl_context *ssl) { int non_empty_certificate_msg = 0; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) || \ + defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) + int ret; +#endif MBEDTLS_SSL_DEBUG_MSG(1, ("Switch to handshake traffic keys for outbound traffic")); mbedtls_ssl_set_outbound_transform(ssl, ssl->handshake->transform_handshake); +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + ret = ssl_tls13_resume_pending_record(ssl); + if (ret < 0) { + return ret; + } + if (ret > 0) { + non_empty_certificate_msg = mbedtls_ssl_own_cert(ssl) != NULL; + goto client_certificate_written; + } +#endif + #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) if (ssl->handshake->client_auth) { - int ret = mbedtls_ssl_tls13_write_certificate(ssl); + ret = mbedtls_ssl_tls13_write_certificate(ssl); if (ret != 0) { return ret; } @@ -2652,6 +2708,9 @@ static int ssl_tls13_write_client_certificate(mbedtls_ssl_context *ssl) } #endif +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +client_certificate_written: +#endif if (non_empty_certificate_msg) { mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY); @@ -2670,8 +2729,22 @@ static int ssl_tls13_write_client_certificate(mbedtls_ssl_context *ssl) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_tls13_write_client_certificate_verify(mbedtls_ssl_context *ssl) { - int ret = mbedtls_ssl_tls13_write_certificate_verify(ssl); + int ret; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + ret = ssl_tls13_resume_pending_record(ssl); + if (ret < 0) { + return ret; + } + if (ret > 0) { + ret = 0; + goto client_certificate_verify_written; + } +#endif + ret = mbedtls_ssl_tls13_write_certificate_verify(ssl); +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +client_certificate_verify_written: +#endif if (ret == 0) { mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_FINISHED); } @@ -2688,11 +2761,25 @@ static int ssl_tls13_write_client_finished(mbedtls_ssl_context *ssl) { int ret; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + ret = ssl_tls13_resume_pending_record(ssl); + if (ret < 0) { + return ret; + } + if (ret > 0) { + ret = 0; + goto client_finished_written; + } +#endif + ret = mbedtls_ssl_tls13_write_finished_message(ssl); if (ret != 0) { return ret; } +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +client_finished_written: +#endif ret = mbedtls_ssl_tls13_compute_resumption_master_secret(ssl); if (ret != 0) { MBEDTLS_SSL_DEBUG_RET( diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index dc7c776830..675812d9b4 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -2410,6 +2410,12 @@ static int ssl_tls13_write_server_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> write server hello")); +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + if (ssl->handshake->ecrs_state == ssl_ecrs_tls13_server_hello_finalize) { + goto finalize_server_hello; + } +#endif + MBEDTLS_SSL_PROC_CHK(ssl_tls13_prepare_server_hello(ssl)); MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_start_handshake_msg( @@ -2426,7 +2432,20 @@ static int ssl_tls13_write_server_hello(mbedtls_ssl_context *ssl) MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_finish_handshake_msg( ssl, buf_len, msg_len)); - MBEDTLS_SSL_PROC_CHK(ssl_tls13_finalize_server_hello(ssl)); +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) +finalize_server_hello: +#endif + ret = ssl_tls13_finalize_server_hello(ssl); +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) { + ssl->handshake->ecrs_state = ssl_ecrs_tls13_server_hello_finalize; + goto cleanup; + } + ssl->handshake->ecrs_state = ssl_ecrs_none; +#endif + if (ret != 0) { + goto cleanup; + } #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE) /* The server sends a dummy change_cipher_spec record immediately @@ -2522,6 +2541,19 @@ cleanup: * Handler for MBEDTLS_SSL_ENCRYPTED_EXTENSIONS */ +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +static int ssl_tls13_resume_pending_record(mbedtls_ssl_context *ssl) +{ + if (ssl->transform_out == NULL || + ssl->transform_out->async_hardware_aead_pending == 0) { + return 0; + } + + int ret = mbedtls_ssl_write_record(ssl, 1); + return ret == 0 ? 1 : ret; +} +#endif + /* * struct { * Extension extensions<0..2 ^ 16 - 1>; @@ -2607,6 +2639,17 @@ static int ssl_tls13_write_encrypted_extensions(mbedtls_ssl_context *ssl) MBEDTLS_SSL_DEBUG_MSG(2, ("=> write encrypted extensions")); +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + ret = ssl_tls13_resume_pending_record(ssl); + if (ret < 0) { + goto cleanup; + } + if (ret > 0) { + ret = 0; + goto encrypted_extensions_written; + } +#endif + MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_start_handshake_msg( ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS, &buf, &buf_len)); @@ -2621,6 +2664,9 @@ static int ssl_tls13_write_encrypted_extensions(mbedtls_ssl_context *ssl) MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_finish_handshake_msg( ssl, buf_len, msg_len)); +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +encrypted_extensions_written: +#endif #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED) if (mbedtls_ssl_tls13_key_exchange_mode_with_psk(ssl)) { mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_SERVER_FINISHED); @@ -2781,6 +2827,17 @@ static int ssl_tls13_write_server_certificate(mbedtls_ssl_context *ssl) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + ret = ssl_tls13_resume_pending_record(ssl); + if (ret < 0) { + return ret; + } + if (ret > 0) { + ret = 0; + goto server_certificate_written; + } +#endif + #if defined(MBEDTLS_X509_CRT_PARSE_C) if ((ssl_tls13_pick_key_cert(ssl) != 0) || mbedtls_ssl_own_cert(ssl) == NULL) { @@ -2795,6 +2852,9 @@ static int ssl_tls13_write_server_certificate(mbedtls_ssl_context *ssl) if (ret != 0) { return ret; } +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +server_certificate_written: +#endif mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CERTIFICATE_VERIFY); return 0; } @@ -2805,10 +2865,24 @@ static int ssl_tls13_write_server_certificate(mbedtls_ssl_context *ssl) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_tls13_write_certificate_verify(mbedtls_ssl_context *ssl) { - int ret = mbedtls_ssl_tls13_write_certificate_verify(ssl); + int ret; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + ret = ssl_tls13_resume_pending_record(ssl); + if (ret < 0) { + return ret; + } + if (ret > 0) { + ret = 0; + goto certificate_verify_written; + } +#endif + ret = mbedtls_ssl_tls13_write_certificate_verify(ssl); if (ret != 0) { return ret; } +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +certificate_verify_written: +#endif mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_SERVER_FINISHED); return 0; } @@ -2875,11 +2949,25 @@ static int ssl_tls13_write_server_finished(mbedtls_ssl_context *ssl) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) + ret = ssl_tls13_resume_pending_record(ssl); + if (ret < 0) { + return ret; + } + if (ret > 0) { + ret = 0; + goto server_finished_written; + } +#endif + ret = mbedtls_ssl_tls13_write_finished_message(ssl); if (ret != 0) { return ret; } +#if defined(MBEDTLS_ASYNC_HARDWARE_AEAD) +server_finished_written: +#endif ret = mbedtls_ssl_tls13_compute_application_transform(ssl); if (ret != 0) { MBEDTLS_SSL_PEND_FATAL_ALERT(