Add downgrade protection mechanism
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c
index b781adc..3080046 100644
--- a/library/ssl_tls12_server.c
+++ b/library/ssl_tls12_server.c
@@ -2213,11 +2213,36 @@
p += 4;
#endif /* MBEDTLS_HAVE_TIME */
- if ((ret = ssl->conf->f_rng(ssl->conf->p_rng, p, 28)) != 0) {
+ if ((ret = ssl->conf->f_rng(ssl->conf->p_rng, p, 20)) != 0) {
return ret;
}
+ p += 20;
- p += 28;
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ /*
+ * RFC 8446
+ * TLS 1.3 has a downgrade protection mechanism embedded in the server's
+ * random value. TLS 1.3 servers which negotiate TLS 1.2 or below in
+ * response to a ClientHello MUST set the last 8 bytes of their Random
+ * value specially in their ServerHello.
+ */
+ if (mbedtls_ssl_conf_is_tls13_enabled(ssl->conf)) {
+ static const unsigned char magic_tls12_downgrade_string[] =
+ { 'D', 'O', 'W', 'N', 'G', 'R', 'D', 1 };
+
+ MBEDTLS_STATIC_ASSERT(
+ sizeof(magic_tls12_downgrade_string) == 8,
+ "magic_tls12_downgrade_string does not have the expected size");
+
+ memcpy(p, magic_tls12_downgrade_string, 8);
+ } else
+#endif
+ {
+ if ((ret = ssl->conf->f_rng(ssl->conf->p_rng, p, 8)) != 0) {
+ return ret;
+ }
+ }
+ p += 8;
memcpy(ssl->handshake->randbytes + 32, buf + 6, 32);
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 74fb9f2..da95814 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1946,12 +1946,33 @@
-s "Protocol is DTLSv1.2" \
-s "Ciphersuite is TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"
+# GnuTLS can be setup to send a ClientHello containing a supported versions
+# extension proposing TLS 1.2 (preferred) and then TLS 1.3. In that case,
+# a TLS 1.3 and TLS 1.2 capable server is supposed to negotiate TLS 1.2 and
+# to indicate in the ServerHello that it downgrades from TLS 1.3. The GnuTLS
+# client then detects the downgrade indication and aborts the handshake even
+# if TLS 1.2 was its preferred version. Keeping the test even if the
+# handshake fails eventually as it exercices parts of the Mbed TLS
+# implementation that are otherwise not exercised.
requires_gnutls_tls1_3
requires_config_enabled MBEDTLS_DEBUG_C
requires_config_enabled MBEDTLS_SSL_SRV_C
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
-run_test "Server selecting TLS 1.2, over TLS 1.3 if supported" \
+run_test "Server selecting TLS 1.2 over TLS 1.3" \
+ "$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key" \
+ "$G_NEXT_CLI localhost --priority=NORMAL:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3" \
+ 1 \
+ -c "Detected downgrade to TLS 1.2 from TLS 1.3"
+
+requires_gnutls_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_SRV_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+run_test "Server selecting TLS 1.2" \
"$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key" \
"$G_NEXT_CLI localhost --priority=NORMAL:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3" \
0 \
@@ -8733,7 +8754,7 @@
"$P_SRV debug_level=1 \
async_operations=s async_private_delay1=1 async_private_delay2=1" \
"$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA;
- [ \$? -eq 1 ] && $P_CLI" \
+ [ \$? -eq 1 ] && $P_CLI force_version=tls12" \
0 \
-S "Async decrypt callback" \
-s "! mbedtls_ssl_handshake returned" \