Implement TLS 1.3 anti-downgrade signal.

Change-Id: Ib4739350948ec339457d993daef582748ed8f100
Reviewed-on: https://boringssl-review.googlesource.com/30924
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 6b0d9bb..047101e 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -3664,10 +3664,14 @@
 OPENSSL_EXPORT void SSL_CTX_set_false_start_allowed_without_alpn(SSL_CTX *ctx,
                                                                  int allowed);
 
-// SSL_is_draft_downgrade returns one if the TLS 1.3 anti-downgrade mechanism
-// would have aborted |ssl|'s handshake and zero otherwise.
-OPENSSL_EXPORT int SSL_is_draft_downgrade(const SSL *ssl);
+// SSL_CTX_set_ignore_tls13_downgrade configures whether connections on |ctx|
+// ignore the downgrade signal in the server's random value.
+OPENSSL_EXPORT void SSL_CTX_set_ignore_tls13_downgrade(SSL_CTX *ctx,
+                                                       int ignore);
 
+// SSL_is_tls13_downgrade returns one if the TLS 1.3 anti-downgrade
+// mechanism would have aborted |ssl|'s handshake and zero otherwise.
+OPENSSL_EXPORT int SSL_is_tls13_downgrade(const SSL *ssl);
 
 // Deprecated functions.
 
@@ -4773,6 +4777,7 @@
 #define SSL_R_UNKNOWN_CERT_COMPRESSION_ALG 294
 #define SSL_R_INVALID_SIGNATURE_ALGORITHM 295
 #define SSL_R_DUPLICATE_SIGNATURE_ALGORITHM 296
+#define SSL_R_TLS13_DOWNGRADE 297
 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index cb9b6de..ebf86a9 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -588,19 +588,23 @@
   OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
                  SSL3_RANDOM_SIZE);
 
-  // Measure, but do not enforce, the TLS 1.3 anti-downgrade feature, with a
-  // different value.
-  //
-  // For draft TLS 1.3 versions, it is not safe to deploy this feature. However,
-  // some TLS terminators are non-compliant and copy the origin server's value,
-  // so we wish to measure eventual compatibility impact.
+  // Enforce the TLS 1.3 anti-downgrade feature.
   if (!ssl->s3->initial_handshake_complete &&
-      hs->max_version >= TLS1_3_VERSION &&
-      OPENSSL_memcmp(ssl->s3->server_random + SSL3_RANDOM_SIZE -
-                         sizeof(kDraftDowngradeRandom),
-                     kDraftDowngradeRandom,
-                     sizeof(kDraftDowngradeRandom)) == 0) {
-    ssl->s3->draft_downgrade = true;
+      ssl_supports_version(hs, TLS1_3_VERSION)) {
+    static_assert(
+        sizeof(kTLS12DowngradeRandom) == sizeof(kTLS13DowngradeRandom),
+        "downgrade signals have different size");
+    auto suffix =
+        MakeConstSpan(ssl->s3->server_random, sizeof(ssl->s3->server_random))
+            .subspan(SSL3_RANDOM_SIZE - sizeof(kTLS13DowngradeRandom));
+    if (suffix == kTLS12DowngradeRandom || suffix == kTLS13DowngradeRandom) {
+      ssl->s3->tls13_downgrade = true;
+      if (!ssl->ctx->ignore_tls13_downgrade) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_TLS13_DOWNGRADE);
+        ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+        return ssl_hs_error;
+      }
+    }
   }
 
   if (!ssl->s3->initial_handshake_complete && ssl->session != NULL &&
@@ -1477,18 +1481,32 @@
 static bool can_false_start(const SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
-  // False Start only for TLS 1.2 with an ECDHE+AEAD cipher.
+  // False Start bypasses the Finished check's downgrade protection. This can
+  // enable attacks where we send data under weaker settings than supported
+  // (e.g. the Logjam attack). Thus we require TLS 1.2 with an ECDHE+AEAD
+  // cipher, our strongest settings before TLS 1.3.
+  //
+  // Now that TLS 1.3 exists, we would like to avoid similar attacks between
+  // TLS 1.2 and TLS 1.3, but there are too many TLS 1.2 deployments to
+  // sacrifice False Start on them. TLS 1.3's downgrade signal fixes this, but
+  // |SSL_CTX_set_ignore_tls13_downgrade| can disable it due to compatibility
+  // issues.
+  //
+  // |SSL_CTX_set_ignore_tls13_downgrade| normally still retains Finished-based
+  // downgrade protection, but False Start bypasses that. Thus, we disable False
+  // Start based on the TLS 1.3 downgrade signal, even if otherwise unenforced.
   if (SSL_is_dtls(ssl) ||
       SSL_version(ssl) != TLS1_2_VERSION ||
       hs->new_cipher->algorithm_mkey != SSL_kECDHE ||
-      hs->new_cipher->algorithm_mac != SSL_AEAD) {
+      hs->new_cipher->algorithm_mac != SSL_AEAD ||
+      ssl->s3->tls13_downgrade) {
     return false;
   }
 
   // Additionally require ALPN or NPN by default.
   //
   // TODO(davidben): Can this constraint be relaxed globally now that cipher
-  // suite requirements have been relaxed?
+  // suite requirements have been tightened?
   if (!ssl->ctx->false_start_allowed_without_alpn &&
       ssl->s3->alpn_selected.empty() &&
       ssl->s3->next_proto_negotiated.empty()) {
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index 0159c9e..f0ed0d8 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -702,15 +702,17 @@
     return ssl_hs_error;
   }
 
-  // Implement the TLS 1.3 anti-downgrade feature, but with a different value.
-  //
-  // For draft TLS 1.3 versions, it is not safe to deploy this feature. However,
-  // some TLS terminators are non-compliant and copy the origin server's value,
-  // so we wish to measure eventual compatibility impact.
-  if (hs->max_version >= TLS1_3_VERSION) {
-    OPENSSL_memcpy(ssl->s3->server_random + SSL3_RANDOM_SIZE -
-                       sizeof(kDraftDowngradeRandom),
-                   kDraftDowngradeRandom, sizeof(kDraftDowngradeRandom));
+  // Implement the TLS 1.3 anti-downgrade feature.
+  if (ssl_supports_version(hs, TLS1_3_VERSION)) {
+    if (ssl_protocol_version(ssl) == TLS1_2_VERSION) {
+      OPENSSL_memcpy(ssl->s3->server_random + SSL3_RANDOM_SIZE -
+                         sizeof(kTLS13DowngradeRandom),
+                     kTLS13DowngradeRandom, sizeof(kTLS13DowngradeRandom));
+    } else {
+      OPENSSL_memcpy(ssl->s3->server_random + SSL3_RANDOM_SIZE -
+                         sizeof(kTLS12DowngradeRandom),
+                     kTLS12DowngradeRandom, sizeof(kTLS12DowngradeRandom));
+    }
   }
 
   const SSL_SESSION *session = hs->new_session.get();
diff --git a/ssl/internal.h b/ssl/internal.h
index f886070..e612f6d 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1018,7 +1018,8 @@
 #define SSL_MAX_HANDSHAKE_FLIGHT 7
 
 extern const uint8_t kHelloRetryRequest[SSL3_RANDOM_SIZE];
-extern const uint8_t kDraftDowngradeRandom[8];
+extern const uint8_t kTLS12DowngradeRandom[8];
+extern const uint8_t kTLS13DowngradeRandom[8];
 
 // ssl_max_handshake_message_len returns the maximum number of bytes permitted
 // in a handshake message for |ssl|.
@@ -2139,9 +2140,8 @@
   // early_data_accepted is true if early data was accepted by the server.
   bool early_data_accepted : 1;
 
-  // draft_downgrade is whether the TLS 1.3 anti-downgrade logic would have
-  // fired, were it not a draft.
-  bool draft_downgrade : 1;
+  // tls13_downgrade is whether the TLS 1.3 anti-downgrade logic fired.
+  bool tls13_downgrade : 1;
 
   // token_binding_negotiated is set if Token Binding was negotiated.
   bool token_binding_negotiated : 1;
@@ -3055,6 +3055,10 @@
   // |SSL_MODE_ENABLE_FALSE_START| is enabled) is allowed without ALPN.
   bool false_start_allowed_without_alpn : 1;
 
+  // ignore_tls13_downgrade is whether a connection should continue when the
+  // server random signals a downgrade.
+  bool ignore_tls13_downgrade:1;
+
   // handoff indicates that a server should stop after receiving the
   // ClientHello and pause the handshake in such a way that |SSL_get_error|
   // returns |SSL_HANDOFF|.
diff --git a/ssl/s3_lib.cc b/ssl/s3_lib.cc
index 9e4d7d8..0b24f94 100644
--- a/ssl/s3_lib.cc
+++ b/ssl/s3_lib.cc
@@ -177,7 +177,7 @@
       key_update_pending(false),
       wpend_pending(false),
       early_data_accepted(false),
-      draft_downgrade(false),
+      tls13_downgrade(false),
       token_binding_negotiated(false) {}
 
 SSL3_STATE::~SSL3_STATE() {}
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 8d2f134..a126561 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -546,6 +546,7 @@
       ed25519_enabled(false),
       rsa_pss_rsae_certs_enabled(true),
       false_start_allowed_without_alpn(false),
+      ignore_tls13_downgrade(false),
       handoff(false),
       enable_early_data(false) {
   CRYPTO_MUTEX_init(&lock);
@@ -2639,7 +2640,11 @@
   ctx->false_start_allowed_without_alpn = !!allowed;
 }
 
-int SSL_is_draft_downgrade(const SSL *ssl) { return ssl->s3->draft_downgrade; }
+int SSL_is_tls13_downgrade(const SSL *ssl) { return ssl->s3->tls13_downgrade; }
+
+void SSL_CTX_set_ignore_tls13_downgrade(SSL_CTX *ctx, int ignore) {
+  ctx->ignore_tls13_downgrade = !!ignore;
+}
 
 void SSL_set_shed_handshake_config(SSL *ssl, int enable) {
   if (!ssl->config) {
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 26173d3..dc12559 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -620,9 +620,9 @@
     return false;
   }
 
-  if (config->expect_draft_downgrade != !!SSL_is_draft_downgrade(ssl)) {
-    fprintf(stderr, "Got %sdraft downgrade signal, but wanted the opposite.\n",
-            SSL_is_draft_downgrade(ssl) ? "" : "no ");
+  if (config->expect_tls13_downgrade != !!SSL_is_tls13_downgrade(ssl)) {
+    fprintf(stderr, "Got %s downgrade signal, but wanted the opposite.\n",
+            SSL_is_tls13_downgrade(ssl) ? "" : "no ");
     return false;
   }
 
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index f2bb9dc..a627df9 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1587,13 +1587,17 @@
 	// that many bytes.
 	PadClientHello int
 
-	// SendDraftTLS13DowngradeRandom, if true, causes the server to send the
-	// draft TLS 1.3 anti-downgrade signal.
-	SendDraftTLS13DowngradeRandom bool
+	// SendTLS13DowngradeRandom, if true, causes the server to send the
+	// TLS 1.3 anti-downgrade signal.
+	SendTLS13DowngradeRandom bool
 
-	// ExpectDraftTLS13DowngradeRandom, if true, causes the client to
-	// require the server send the draft TLS 1.3 anti-downgrade signal.
-	ExpectDraftTLS13DowngradeRandom bool
+	// CheckTLS13DowngradeRandom, if true, causes the client to check the
+	// TLS 1.3 anti-downgrade signal regardless of its variant.
+	CheckTLS13DowngradeRandom bool
+
+	// IgnoreTLS13DowngradeRandom, if true, causes the client to ignore the
+	// TLS 1.3 anti-downgrade signal.
+	IgnoreTLS13DowngradeRandom bool
 
 	// SendCompressedCoordinates, if true, causes ECDH key shares over NIST
 	// curves to use compressed coordinates.
@@ -2063,8 +2067,6 @@
 	// See draft-ietf-tls-tls13-16, section 6.3.1.2.
 	downgradeTLS13 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01}
 	downgradeTLS12 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00}
-
-	downgradeTLS13Draft = []uint8{0x95, 0xb9, 0x9f, 0x87, 0x22, 0xfe, 0x9b, 0x64}
 )
 
 func containsGREASE(values []uint16) bool {
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 614671d..847c61a 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -602,23 +602,23 @@
 		return fmt.Errorf("tls: server sent non-matching version %x vs %x", serverWireVersion, serverHello.vers)
 	}
 
+	_, supportsTLS13 := c.config.isSupportedVersion(VersionTLS13, false)
 	// Check for downgrade signals in the server random, per
 	// draft-ietf-tls-tls13-16, section 4.1.3.
-	if c.vers <= VersionTLS12 && c.config.maxVersion(c.isDTLS) >= VersionTLS13 {
-		if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS13) {
-			c.sendAlert(alertProtocolVersion)
-			return errors.New("tls: downgrade from TLS 1.3 detected")
+	if (supportsTLS13 || c.config.Bugs.CheckTLS13DowngradeRandom) && !c.config.Bugs.IgnoreTLS13DowngradeRandom {
+		if c.vers <= VersionTLS12 && c.config.maxVersion(c.isDTLS) >= VersionTLS13 {
+			if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS13) {
+				c.sendAlert(alertProtocolVersion)
+				return errors.New("tls: downgrade from TLS 1.3 detected")
+			}
 		}
-	}
-	if c.vers <= VersionTLS11 && c.config.maxVersion(c.isDTLS) >= VersionTLS12 {
-		if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS12) {
-			c.sendAlert(alertProtocolVersion)
-			return errors.New("tls: downgrade from TLS 1.2 detected")
+		if c.vers <= VersionTLS11 && c.config.maxVersion(c.isDTLS) >= VersionTLS12 {
+			if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS12) {
+				c.sendAlert(alertProtocolVersion)
+				return errors.New("tls: downgrade from TLS 1.2 detected")
+			}
 		}
 	}
-	if c.config.Bugs.ExpectDraftTLS13DowngradeRandom && !bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS13Draft) {
-		return errors.New("tls: server did not send draft TLS 1.3 anti-downgrade signal")
-	}
 
 	suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite)
 	if suite == nil {
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 2ba438a..bdf72ae 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -1170,16 +1170,18 @@
 		c.sendAlert(alertInternalError)
 		return false, err
 	}
+
+	_, supportsTLS13 := c.config.isSupportedVersion(VersionTLS13, false)
+
 	// Signal downgrades in the server random, per draft-ietf-tls-tls13-16,
 	// section 4.1.3.
-	if c.vers <= VersionTLS12 && config.maxVersion(c.isDTLS) >= VersionTLS13 {
-		copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS13)
-	}
-	if c.vers <= VersionTLS11 && config.maxVersion(c.isDTLS) == VersionTLS12 {
-		copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
-	}
-	if config.Bugs.SendDraftTLS13DowngradeRandom {
-		copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS13Draft)
+	if supportsTLS13 || config.Bugs.SendTLS13DowngradeRandom {
+		if c.vers <= VersionTLS12 && config.maxVersion(c.isDTLS) >= VersionTLS13 {
+			copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS13)
+		}
+		if c.vers <= VersionTLS11 && config.maxVersion(c.isDTLS) == VersionTLS12 {
+			copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
+		}
 	}
 
 	if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID {
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 5ac6ec4..7c5b84c 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -5683,7 +5683,8 @@
 				config: Config{
 					TLS13Variant: vers.tls13Variant,
 					Bugs: ProtocolBugs{
-						SendSupportedVersions: []uint16{0x1111, vers.wire(protocol), 0x2222},
+						SendSupportedVersions:      []uint16{0x1111, vers.wire(protocol), 0x2222},
+						IgnoreTLS13DowngradeRandom: true,
 					},
 				},
 				expectedVersion: vers.version,
@@ -5723,8 +5724,9 @@
 		config: Config{
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
-				SendClientVersion:     0x0304,
-				OmitSupportedVersions: true,
+				SendClientVersion:          0x0304,
+				OmitSupportedVersions:      true,
+				IgnoreTLS13DowngradeRandom: true,
 			},
 		},
 		expectedVersion: VersionTLS12,
@@ -5735,8 +5737,9 @@
 		name:     "ConflictingVersionNegotiation",
 		config: Config{
 			Bugs: ProtocolBugs{
-				SendClientVersion:     VersionTLS12,
-				SendSupportedVersions: []uint16{VersionTLS11},
+				SendClientVersion:          VersionTLS12,
+				SendSupportedVersions:      []uint16{VersionTLS11},
+				IgnoreTLS13DowngradeRandom: true,
 			},
 		},
 		// The extension takes precedence over the ClientHello version.
@@ -5748,8 +5751,9 @@
 		name:     "ConflictingVersionNegotiation-2",
 		config: Config{
 			Bugs: ProtocolBugs{
-				SendClientVersion:     VersionTLS11,
-				SendSupportedVersions: []uint16{VersionTLS12},
+				SendClientVersion:          VersionTLS11,
+				SendSupportedVersions:      []uint16{VersionTLS12},
+				IgnoreTLS13DowngradeRandom: true,
 			},
 		},
 		// The extension takes precedence over the ClientHello version.
@@ -5790,8 +5794,9 @@
 		name:     "MinorVersionTolerance",
 		config: Config{
 			Bugs: ProtocolBugs{
-				SendClientVersion:     0x03ff,
-				OmitSupportedVersions: true,
+				SendClientVersion:          0x03ff,
+				OmitSupportedVersions:      true,
+				IgnoreTLS13DowngradeRandom: true,
 			},
 		},
 		expectedVersion: VersionTLS12,
@@ -5801,8 +5806,9 @@
 		name:     "MajorVersionTolerance",
 		config: Config{
 			Bugs: ProtocolBugs{
-				SendClientVersion:     0x0400,
-				OmitSupportedVersions: true,
+				SendClientVersion:          0x0400,
+				OmitSupportedVersions:      true,
+				IgnoreTLS13DowngradeRandom: true,
 			},
 		},
 		// TLS 1.3 must be negotiated with the supported_versions
@@ -5893,9 +5899,10 @@
 				NegotiateVersion: VersionTLS12,
 			},
 		},
-		expectedVersion: VersionTLS12,
-		// TODO(davidben): This test should fail once TLS 1.3 is final
-		// and the fallback signal restored.
+		tls13Variant:       TLS13RFC,
+		expectedVersion:    VersionTLS12,
+		shouldFail:         true,
+		expectedLocalError: "remote error: illegal parameter",
 	})
 	testCases = append(testCases, testCase{
 		testType: serverTest,
@@ -5905,30 +5912,103 @@
 				SendSupportedVersions: []uint16{VersionTLS12},
 			},
 		},
-		expectedVersion: VersionTLS12,
-		// TODO(davidben): This test should fail once TLS 1.3 is final
-		// and the fallback signal restored.
+		tls13Variant:       TLS13RFC,
+		expectedVersion:    VersionTLS12,
+		shouldFail:         true,
+		expectedLocalError: "tls: downgrade from TLS 1.3 detected",
 	})
 
 	testCases = append(testCases, testCase{
-		name: "Draft-Downgrade-Client",
+		name: "Downgrade-TLS11-Client",
 		config: Config{
-			MaxVersion: VersionTLS12,
 			Bugs: ProtocolBugs{
-				SendDraftTLS13DowngradeRandom: true,
+				NegotiateVersion: VersionTLS11,
 			},
 		},
-		flags: []string{"-expect-draft-downgrade"},
+		tls13Variant:       TLS13RFC,
+		expectedVersion:    VersionTLS11,
+		shouldFail:         true,
+		expectedLocalError: "remote error: illegal parameter",
 	})
 	testCases = append(testCases, testCase{
 		testType: serverTest,
-		name:     "Draft-Downgrade-Server",
+		name:     "Downgrade-TLS11-Server",
 		config: Config{
-			MaxVersion: VersionTLS12,
 			Bugs: ProtocolBugs{
-				ExpectDraftTLS13DowngradeRandom: true,
+				SendSupportedVersions: []uint16{VersionTLS11},
 			},
 		},
+		tls13Variant:       TLS13RFC,
+		expectedVersion:    VersionTLS11,
+		shouldFail:         true,
+		expectedLocalError: "tls: downgrade from TLS 1.2 detected",
+	})
+
+	// Test that the draft TLS 1.3 variants don't trigger the downgrade logic.
+	testCases = append(testCases, testCase{
+		name: "Downgrade-Draft-Client",
+		config: Config{
+			Bugs: ProtocolBugs{
+				NegotiateVersion:         VersionTLS12,
+				SendTLS13DowngradeRandom: true,
+			},
+		},
+		tls13Variant:    TLS13Draft28,
+		expectedVersion: VersionTLS12,
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "Downgrade-Draft-Server",
+		config: Config{
+			Bugs: ProtocolBugs{
+				CheckTLS13DowngradeRandom: true,
+			},
+		},
+		tls13Variant:    TLS13Draft28,
+		expectedVersion: VersionTLS13,
+	})
+
+	// Test that False Start is disabled when the downgrade logic triggers.
+	testCases = append(testCases, testCase{
+		name: "Downgrade-FalseStart",
+		config: Config{
+			NextProtos: []string{"foo"},
+			Bugs: ProtocolBugs{
+				NegotiateVersion:          VersionTLS12,
+				ExpectFalseStart:          true,
+				AlertBeforeFalseStartTest: alertAccessDenied,
+			},
+		},
+		tls13Variant:    TLS13RFC,
+		expectedVersion: VersionTLS12,
+		flags: []string{
+			"-false-start",
+			"-advertise-alpn", "\x03foo",
+			"-ignore-tls13-downgrade",
+		},
+		shimWritesFirst:    true,
+		shouldFail:         true,
+		expectedError:      ":TLSV1_ALERT_ACCESS_DENIED:",
+		expectedLocalError: "tls: peer did not false start: EOF",
+	})
+
+	testCases = append(testCases, testCase{
+		name: "Downgrade-FalseStart-Draft",
+		config: Config{
+			MaxVersion:   VersionTLS13,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			NextProtos:   []string{"foo"},
+			Bugs: ProtocolBugs{
+				ExpectFalseStart: true,
+			},
+		},
+		flags: []string{
+			"-false-start",
+			"-select-next-proto", "foo",
+			"-max-version", strconv.Itoa(VersionTLS12),
+		},
+		shimWritesFirst: true,
+		resumeSession:   true,
 	})
 
 	// SSL 3.0 support has been removed. Test that the shim does not
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 30cb98c..ef24ca0 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -133,7 +133,8 @@
   { "-use-custom-verify-callback", &TestConfig::use_custom_verify_callback },
   { "-allow-false-start-without-alpn",
     &TestConfig::allow_false_start_without_alpn },
-  { "-expect-draft-downgrade", &TestConfig::expect_draft_downgrade },
+  { "-ignore-tls13-downgrade", &TestConfig::ignore_tls13_downgrade },
+  { "-expect-tls13-downgrade", &TestConfig::expect_tls13_downgrade },
   { "-handoff", &TestConfig::handoff },
   { "-no-rsa-pss-rsae-certs", &TestConfig::no_rsa_pss_rsae_certs },
   { "-use-ocsp-callback", &TestConfig::use_ocsp_callback },
@@ -1271,6 +1272,10 @@
     SSL_CTX_set_false_start_allowed_without_alpn(ssl_ctx.get(), 1);
   }
 
+  if (ignore_tls13_downgrade) {
+    SSL_CTX_set_ignore_tls13_downgrade(ssl_ctx.get(), 1);
+  }
+
   if (use_ocsp_callback) {
     SSL_CTX_set_tlsext_status_cb(ssl_ctx.get(), LegacyOCSPCallback);
   }
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 835d29d..b65ca42 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -156,7 +156,8 @@
   bool use_custom_verify_callback = false;
   std::string expect_msg_callback;
   bool allow_false_start_without_alpn = false;
-  bool expect_draft_downgrade = false;
+  bool ignore_tls13_downgrade = false;
+  bool expect_tls13_downgrade = false;
   bool handoff = false;
   bool no_rsa_pss_rsae_certs = false;
   bool use_ocsp_callback = false;
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc
index d6ebb4c..ce9dd3c 100644
--- a/ssl/tls13_both.cc
+++ b/ssl/tls13_both.cc
@@ -43,12 +43,11 @@
     0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
 };
 
-// This value was selected by truncating the SHA-256 hash of "Draft TLS 1.3
-// Downgrade" to 8 bytes:
-//
-//   echo -n 'Draft TLS 1.3 Downgrade' | sha256sum | head -c 16
-const uint8_t kDraftDowngradeRandom[8] = {0x95, 0xb9, 0x9f, 0x87,
-                                          0x22, 0xfe, 0x9b, 0x64};
+const uint8_t kTLS12DowngradeRandom[8] = {0x44, 0x4f, 0x57, 0x4e,
+                                          0x47, 0x52, 0x44, 0x00};
+
+const uint8_t kTLS13DowngradeRandom[8] = {0x44, 0x4f, 0x57, 0x4e,
+                                          0x47, 0x52, 0x44, 0x01};
 
 
 bool tls13_get_cert_verify_signature_input(