From fd6193c285096f72ccbdbe5e16836a100976dd70 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Tue, 5 Apr 2022 11:04:20 +0200 Subject: [PATCH] ssl_tls13_client: Add downgrade attack protection Signed-off-by: Ronald Cron --- library/ssl_tls13_client.c | 50 +++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index b05d2f239..64272590b 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -711,6 +711,7 @@ int mbedtls_ssl_tls13_write_client_hello_exts( mbedtls_ssl_context *ssl, /* * Functions for parsing and processing Server Hello */ + /** * \brief Detect if the ServerHello contains a supported_versions extension * or not. @@ -792,6 +793,36 @@ static int ssl_tls13_is_supported_versions_ext_present( return( 0 ); } +/* Returns a negative value on failure, and otherwise + * - 1 if the last eight bytes of the ServerHello random bytes indicate that + * the server is TLS 1.3 capable but negotiating TLS 1.2 or below. + * - 0 otherwise + */ +static int ssl_tls13_is_downgrade_negotiation( mbedtls_ssl_context *ssl, + const unsigned char *buf, + const unsigned char *end ) +{ + /* First seven bytes of the magic downgrade strings, see RFC 8446 4.1.3 */ + static const unsigned char magic_downgrade_string[] = + { 0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44 }; + const unsigned char *last_eight_bytes_of_random; + unsigned char last_byte_of_random; + + MBEDTLS_SSL_CHK_BUF_READ_PTR( buf, end, MBEDTLS_SERVER_HELLO_RANDOM_LEN + 2 ); + last_eight_bytes_of_random = buf + 2 + MBEDTLS_SERVER_HELLO_RANDOM_LEN - 8; + + if( memcmp( last_eight_bytes_of_random, + magic_downgrade_string, + sizeof( magic_downgrade_string ) ) == 0 ) + { + last_byte_of_random = last_eight_bytes_of_random[7]; + return( last_byte_of_random == 0 || + last_byte_of_random == 1 ); + } + + return( 0 ); +} + /* Returns a negative value on failure, and otherwise * - SSL_SERVER_HELLO_COORDINATE_HELLO or * - SSL_SERVER_HELLO_COORDINATE_HRR @@ -846,20 +877,27 @@ static int ssl_tls13_server_hello_coordinate( mbedtls_ssl_context *ssl, size_t *buf_len ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *end; MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_tls13_fetch_handshake_msg( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, buf, buf_len ) ); + end = *buf + *buf_len; MBEDTLS_SSL_PROC_CHK_NEG( ssl_tls13_is_supported_versions_ext_present( - ssl, *buf, *buf + *buf_len ) ); + ssl, *buf, end ) ); if( ret == 0 ) { - /* If the supported versions extension is not present but we were - * expecting it, abort the handshake. Otherwise, switch to TLS 1.2 - * handshake. + MBEDTLS_SSL_PROC_CHK_NEG( + ssl_tls13_is_downgrade_negotiation( ssl, *buf, end ) ); + + /* If the server is negotiating TLS 1.2 or below and: + * . we did not propose TLS 1.2 or + * . the server responded it is TLS 1.3 capable but negotiating a lower + * version of the protocol and thus we are under downgrade attack + * abort the handshake with an "illegal parameter" alert. */ - if( ssl->handshake->min_tls_version > MBEDTLS_SSL_VERSION_TLS1_2 ) + if( ssl->handshake->min_tls_version > MBEDTLS_SSL_VERSION_TLS1_2 || ret ) { MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER ); @@ -881,7 +919,7 @@ static int ssl_tls13_server_hello_coordinate( mbedtls_ssl_context *ssl, return( SSL_SERVER_HELLO_COORDINATE_TLS1_2 ); } - ret = ssl_server_hello_is_hrr( ssl, *buf, *buf + *buf_len ); + ret = ssl_server_hello_is_hrr( ssl, *buf, end ); switch( ret ) { case SSL_SERVER_HELLO_COORDINATE_HELLO: