ssl_tls13_client: Add downgrade attack protection
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index b05d2f2..6427259 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -711,6 +711,7 @@
/*
* Functions for parsing and processing Server Hello
*/
+
/**
* \brief Detect if the ServerHello contains a supported_versions extension
* or not.
@@ -793,6 +794,36 @@
}
/* 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
* to indicate which message is expected and to be parsed next.
@@ -846,20 +877,27 @@
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 @@
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: