From ae02c5e86eb02f30a5954d4edd0c43653fa6e6a6 Mon Sep 17 00:00:00 2001 From: Joshua Siegel Date: Tue, 14 Dec 2021 21:20:11 -0500 Subject: [PATCH] use trial decryption if server rejects client 0-RTT attempt --- library/ssl_misc.h | 3 ++ library/ssl_msg.c | 68 +++++++++++++++++++++++++++++++++---- library/ssl_tls13_generic.c | 1 + library/ssl_tls13_server.c | 3 ++ tests/ssl-opt.sh | 13 +++++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 90a42fe43657..f0a804bf6422 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -876,6 +876,9 @@ struct mbedtls_ssl_handshake_params 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) */ int early_data; +#if defined(MBEDTLS_SSL_SRV_C) + int skip_failed_decryption; +#endif /* MBEDTLS_SSL_SRV_C */ #endif /* MBEDTLS_ZERO_RTT */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index f202c5904508..6d6fc0fa6af1 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -3957,10 +3957,21 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, return( ret ); } - if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && - update_hs_digest == 1 ) + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) { - mbedtls_ssl_update_handshake_status( ssl ); + if( update_hs_digest == 1) + mbedtls_ssl_update_handshake_status( ssl ); + +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_ZERO_RTT) + if( ssl->handshake != NULL && + ssl->handshake->skip_failed_decryption != 0 && + ssl->transform_in != NULL ) + { + /* Record deprotected successfully */ + ssl->handshake->skip_failed_decryption = 0; + MBEDTLS_SSL_DEBUG_MSG( 4, ( "disabling skip_failed_decryption" ) ); + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_ZERO_RTT */ } } else @@ -4554,6 +4565,41 @@ static int ssl_buffer_future_record( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_PROTO_DTLS */ +/* + * RFC 8446: + * "If the client attempts a 0-RTT handshake but the server + * rejects it, the server will generally not have the 0-RTT record + * protection keys and must instead use trial decryption (either with + * the 1-RTT handshake keys or by looking for a cleartext ClientHello in + * the case of a HelloRetryRequest) to find the first non-0-RTT message." + */ +#if defined(MBEDTLS_SSL_SRV_C) +static int ssl_should_drop_record( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_ZERO_RTT) && !defined(MBEDTLS_SSL_USE_MPS) + if( ssl->conf->endpoint != MBEDTLS_SSL_IS_SERVER || ssl->handshake == NULL ) + return( 0 ); + + /* + * Drop record iff: + * 1. Client indicated early data use (skip_failed_decryption). + * 2. Server does not have early data enabled (skip_failed_decryption). + * 3. First non-0-RTT record has not yet been found (skip_failed_decryption). + * 4. 1-RTT handshake keys are in use. + */ + if( ssl->handshake->skip_failed_decryption == 1 && + ssl->transform_in == ssl->handshake->transform_handshake ) + { + return( 1 ); + } + +#endif /* MBEDTLS_ZERO_RTT && !MBEDTLS_SSL_USE_MPS */ + ((void) ssl); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_C */ + static int ssl_get_next_record( mbedtls_ssl_context *ssl ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -4722,15 +4768,25 @@ static int ssl_get_next_record( mbedtls_ssl_context *ssl ) else #endif { - /* Error out (and send alert) on invalid records */ -#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) { +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->handshake != NULL && + ssl_should_drop_record( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid record (mac), dropping 0-RTT message" ) ); + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + /* Error out (and send alert) on invalid records */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); +#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */ } -#endif + return( ret ); } } diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 73d3b9409647..2f5e4469b83a 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -2482,6 +2482,7 @@ int mbedtls_ssl_write_early_data_ext( mbedtls_ssl_context *ssl, { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + ssl->handshake->skip_failed_decryption = 1; return( 0 ); } } diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 866dba1797d7..baa874d36464 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -2768,6 +2768,9 @@ static int ssl_client_hello_postprocess( mbedtls_ssl_context* ssl, int ret = 0; #if defined(MBEDTLS_ZERO_RTT) mbedtls_ssl_key_set traffic_keys; + + if( ssl->handshake->hello_retry_requests_sent == 1 ) + ssl->handshake->skip_failed_decryption = 0; #endif /* MBEDTLS_ZERO_RTT */ if( ssl->handshake->hello_retry_requests_sent == 0 && diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 03109836ce8b..cfb1b6d23665 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -2445,6 +2445,19 @@ run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - no 0 \ -c "early data status = 0" \ +# test early data status - rejected +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_SSL_USE_MPS +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - rejected" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=0 tls13_kex_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 tls13_kex_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -c "early data status = 1" \ + # test early data status - accepted requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL requires_config_enabled MBEDTLS_DEBUG_C