external/boringssl: Sync to 9113e0996fd445ce187ae9dfeabfc95805b947a2.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/fa3aadcd40ec4fd27a6e9492ef099b3dcc6eb2af..9113e0996fd445ce187ae9dfeabfc95805b947a2

Test: atest CtsLibcoreTestCases
Change-Id: I31ed8a7c9481e7b42f0454f0ee64c26e17a85d52
diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc
index b1da056..058a793 100644
--- a/src/ssl/handshake.cc
+++ b/src/ssl/handshake.cc
@@ -147,7 +147,8 @@
       pending_private_key_op(false),
       grease_seeded(false),
       handback(false),
-      cert_compression_negotiated(false) {
+      cert_compression_negotiated(false),
+      apply_jdk11_workaround(false) {
   assert(ssl);
 }
 
diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc
index 24331ba..c1d54bd 100644
--- a/src/ssl/handshake_client.cc
+++ b/src/ssl/handshake_client.cc
@@ -177,6 +177,7 @@
 enum ssl_client_hs_state_t {
   state_start_connect = 0,
   state_enter_early_data,
+  state_early_reverify_server_certificate,
   state_read_hello_verify_request,
   state_read_server_hello,
   state_tls13,
@@ -466,10 +467,26 @@
 
   // Stash the early data session, so connection properties may be queried out
   // of it.
-  hs->in_early_data = true;
   hs->early_session = UpRef(ssl->session);
-  hs->can_early_write = true;
+  hs->state = state_early_reverify_server_certificate;
+  return ssl_hs_ok;
+}
 
+static enum ssl_hs_wait_t do_early_reverify_server_certificate(SSL_HANDSHAKE *hs) {
+  if (hs->ssl->ctx->reverify_on_resume) {
+    switch (ssl_reverify_peer_cert(hs)) {
+    case ssl_verify_ok:
+      break;
+    case ssl_verify_invalid:
+      return ssl_hs_error;
+    case ssl_verify_retry:
+      hs->state = state_early_reverify_server_certificate;
+      return ssl_hs_certificate_verify;
+    }
+  }
+
+  hs->in_early_data = true;
+  hs->can_early_write = true;
   hs->state = state_read_server_hello;
   return ssl_hs_early_return;
 }
@@ -595,10 +612,14 @@
     static_assert(
         sizeof(kTLS12DowngradeRandom) == sizeof(kTLS13DowngradeRandom),
         "downgrade signals have different size");
+    static_assert(
+        sizeof(kJDK11DowngradeRandom) == 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) {
+    if (suffix == kTLS12DowngradeRandom || suffix == kTLS13DowngradeRandom ||
+        suffix == kJDK11DowngradeRandom) {
       ssl->s3->tls13_downgrade = true;
       if (!hs->config->ignore_tls13_downgrade) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_TLS13_DOWNGRADE);
@@ -1692,6 +1713,9 @@
       case state_enter_early_data:
         ret = do_enter_early_data(hs);
         break;
+      case state_early_reverify_server_certificate:
+        ret = do_early_reverify_server_certificate(hs);
+        break;
       case state_read_hello_verify_request:
         ret = do_read_hello_verify_request(hs);
         break;
@@ -1775,6 +1799,8 @@
       return "TLS client start_connect";
     case state_enter_early_data:
       return "TLS client enter_early_data";
+    case state_early_reverify_server_certificate:
+      return "TLS client early_reverify_server_certificate";
     case state_read_hello_verify_request:
       return "TLS client read_hello_verify_request";
     case state_read_server_hello:
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index c546088..c4f3b75 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -401,6 +401,109 @@
   return ssl_hs_ok;
 }
 
+// is_probably_jdk11_with_tls13 returns whether |client_hello| was probably sent
+// from a JDK 11 client (11.0.1 or earlier) with both TLS 1.3 and a prior
+// version enabled.
+static bool is_probably_jdk11_with_tls13(const SSL_CLIENT_HELLO *client_hello) {
+  // JDK 11 ClientHellos contain a number of unusual properties which should
+  // limit false positives.
+
+  // JDK 11 does not support ChaCha20-Poly1305. This is unusual: many modern
+  // clients implement ChaCha20-Poly1305.
+  if (ssl_client_cipher_list_contains_cipher(
+          client_hello, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
+    return false;
+  }
+
+  // JDK 11 always sends extensions in a particular order.
+  constexpr uint16_t kMaxFragmentLength = 0x0001;
+  constexpr uint16_t kStatusRequestV2 = 0x0011;
+  static CONSTEXPR_ARRAY struct {
+    uint16_t id;
+    bool required;
+  } kJavaExtensions[] = {
+      {TLSEXT_TYPE_server_name, false},
+      {kMaxFragmentLength, false},
+      {TLSEXT_TYPE_status_request, false},
+      {TLSEXT_TYPE_supported_groups, true},
+      {TLSEXT_TYPE_ec_point_formats, false},
+      {TLSEXT_TYPE_signature_algorithms, true},
+      // Java always sends signature_algorithms_cert.
+      {TLSEXT_TYPE_signature_algorithms_cert, true},
+      {TLSEXT_TYPE_application_layer_protocol_negotiation, false},
+      {kStatusRequestV2, false},
+      {TLSEXT_TYPE_extended_master_secret, false},
+      {TLSEXT_TYPE_supported_versions, true},
+      {TLSEXT_TYPE_cookie, false},
+      {TLSEXT_TYPE_psk_key_exchange_modes, true},
+      {TLSEXT_TYPE_key_share, true},
+      {TLSEXT_TYPE_renegotiate, false},
+      {TLSEXT_TYPE_pre_shared_key, false},
+  };
+  Span<const uint8_t> sigalgs, sigalgs_cert;
+  bool has_status_request = false, has_status_request_v2 = false;
+  CBS extensions, supported_groups;
+  CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
+  for (const auto &java_extension : kJavaExtensions) {
+    CBS copy = extensions;
+    uint16_t id;
+    if (CBS_get_u16(&copy, &id) && id == java_extension.id) {
+      // The next extension is the one we expected.
+      extensions = copy;
+      CBS body;
+      if (!CBS_get_u16_length_prefixed(&extensions, &body)) {
+        return false;
+      }
+      switch (id) {
+        case TLSEXT_TYPE_status_request:
+          has_status_request = true;
+          break;
+        case kStatusRequestV2:
+          has_status_request_v2 = true;
+          break;
+        case TLSEXT_TYPE_signature_algorithms:
+          sigalgs = body;
+          break;
+        case TLSEXT_TYPE_signature_algorithms_cert:
+          sigalgs_cert = body;
+          break;
+        case TLSEXT_TYPE_supported_groups:
+          supported_groups = body;
+          break;
+      }
+    } else if (java_extension.required) {
+      return false;
+    }
+  }
+  if (CBS_len(&extensions) != 0) {
+    return false;
+  }
+
+  // JDK 11 never advertises X25519. It is not offered by default, and
+  // -Djdk.tls.namedGroups=x25519 does not work. This is unusual: many modern
+  // clients implement X25519.
+  while (CBS_len(&supported_groups) > 0) {
+    uint16_t group;
+    if (!CBS_get_u16(&supported_groups, &group) ||
+        group == SSL_CURVE_X25519) {
+      return false;
+    }
+  }
+
+  if (// JDK 11 always sends the same contents in signature_algorithms and
+      // signature_algorithms_cert. This is unusual: signature_algorithms_cert,
+      // if omitted, is treated as if it were signature_algorithms.
+      sigalgs != sigalgs_cert ||
+      // When TLS 1.2 or below is enabled, JDK 11 sends status_request_v2 iff it
+      // sends status_request. This is unusual: status_request_v2 is not widely
+      // implemented.
+      has_status_request != has_status_request_v2) {
+    return false;
+  }
+
+  return true;
+}
+
 static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
@@ -446,6 +549,11 @@
     return ssl_hs_error;
   }
 
+  if (hs->config->jdk11_workaround &&
+      is_probably_jdk11_with_tls13(&client_hello)) {
+    hs->apply_jdk11_workaround = true;
+  }
+
   uint8_t alert = SSL_AD_DECODE_ERROR;
   if (!negotiate_version(hs, &alert, &client_hello)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
@@ -674,6 +782,12 @@
   return ssl_hs_ok;
 }
 
+static void copy_suffix(Span<uint8_t> out, Span<const uint8_t> in) {
+  out = out.subspan(out.size() - in.size());
+  assert(out.size() == in.size());
+  OPENSSL_memcpy(out.data(), in.data(), in.size());
+}
+
 static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
@@ -705,13 +819,18 @@
   // 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));
+      if (hs->apply_jdk11_workaround) {
+        // JDK 11 implements the TLS 1.3 downgrade signal, so we cannot send it
+        // here. However, the signal is only effective if all TLS 1.2
+        // ServerHellos produced by the server are marked. Thus we send a
+        // different non-standard signal for the time being, until JDK 11.0.2 is
+        // released and clients have updated.
+        copy_suffix(ssl->s3->server_random, kJDK11DowngradeRandom);
+      } else {
+        copy_suffix(ssl->s3->server_random, kTLS13DowngradeRandom);
+      }
     } else {
-      OPENSSL_memcpy(ssl->s3->server_random + SSL3_RANDOM_SIZE -
-                         sizeof(kTLS12DowngradeRandom),
-                     kTLS12DowngradeRandom, sizeof(kTLS12DowngradeRandom));
+      copy_suffix(ssl->s3->server_random, kTLS12DowngradeRandom);
     }
   }
 
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index fa86bda..f8a2ea7 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -1040,6 +1040,7 @@
 extern const uint8_t kHelloRetryRequest[SSL3_RANDOM_SIZE];
 extern const uint8_t kTLS12DowngradeRandom[8];
 extern const uint8_t kTLS13DowngradeRandom[8];
+extern const uint8_t kJDK11DowngradeRandom[8];
 
 // ssl_max_handshake_message_len returns the maximum number of bytes permitted
 // in a handshake message for |ssl|.
@@ -1596,6 +1597,10 @@
   // cert_compression_negotiated is true iff |cert_compression_alg_id| is valid.
   bool cert_compression_negotiated : 1;
 
+  // apply_jdk11_workaround is true if the peer is probably a JDK 11 client
+  // which implemented TLS 1.3 incorrectly.
+  bool apply_jdk11_workaround : 1;
+
   // client_version is the value sent or received in the ClientHello version.
   uint16_t client_version = 0;
 
@@ -2489,7 +2494,11 @@
 
   // ignore_tls13_downgrade is whether the connection should continue when the
   // server random signals a downgrade.
-  bool ignore_tls13_downgrade:1;
+  bool ignore_tls13_downgrade : 1;
+
+  // jdk11_workaround is whether to disable TLS 1.3 for JDK 11 clients, as a
+  // workaround for https://bugs.openjdk.java.net/browse/JDK-8211806.
+  bool jdk11_workaround : 1;
 };
 
 // From RFC 8446, used in determining PSK modes.
diff --git a/src/ssl/ssl_asn1.cc b/src/ssl/ssl_asn1.cc
index caccef4..669f776 100644
--- a/src/ssl/ssl_asn1.cc
+++ b/src/ssl/ssl_asn1.cc
@@ -80,13 +80,6 @@
  * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
  * OTHERWISE. */
 
-// Per C99, various stdint.h macros are unavailable in C++ unless some macros
-// are defined. C++11 overruled this decision, but older Android NDKs still
-// require it.
-#if !defined(__STDC_LIMIT_MACROS)
-#define __STDC_LIMIT_MACROS
-#endif
-
 #include <openssl/ssl.h>
 
 #include <limits.h>
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index 8a88802..b9c823d 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -711,7 +711,8 @@
       retain_only_sha256_of_client_certs(false),
       handoff(false),
       shed_handshake_config(false),
-      ignore_tls13_downgrade(false) {
+      ignore_tls13_downgrade(false),
+      jdk11_workaround(false) {
   assert(ssl);
 }
 
@@ -948,6 +949,33 @@
   return 1;
 }
 
+int SSL_process_quic_post_handshake(SSL *ssl) {
+  ssl_reset_error_state(ssl);
+
+  if (SSL_in_init(ssl)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    return 0;
+  }
+
+  // Replay post-handshake message errors.
+  if (!check_read_error(ssl)) {
+    return 0;
+  }
+
+  // Process any buffered post-handshake messages.
+  SSLMessage msg;
+  while (ssl->method->get_message(ssl, &msg)) {
+    // Handle the post-handshake message and try again.
+    if (!ssl_do_post_handshake(ssl, msg)) {
+      ssl_set_read_error(ssl);
+      return 0;
+    }
+    ssl->method->next_message(ssl);
+  }
+
+  return 1;
+}
+
 static int ssl_read_impl(SSL *ssl) {
   ssl_reset_error_state(ssl);
 
@@ -2748,6 +2776,13 @@
   ssl->config->shed_handshake_config = !!enable;
 }
 
+void SSL_set_jdk11_workaround(SSL *ssl, int enable) {
+  if (!ssl->config) {
+    return;
+  }
+  ssl->config->jdk11_workaround = !!enable;
+}
+
 int SSL_clear(SSL *ssl) {
   if (!ssl->config) {
     return 0;  // SSL_clear may not be used after shedding config.
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index f945898..470379c 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -4727,6 +4727,21 @@
     return true;
   }
 
+  bool CreateSecondClientAndServer() {
+    client_.reset(SSL_new(client_ctx_.get()));
+    server_.reset(SSL_new(server_ctx_.get()));
+    if (!client_ || !server_) {
+      return false;
+    }
+
+    SSL_set_connect_state(client_.get());
+    SSL_set_accept_state(server_.get());
+
+    ex_data_.Set(client_.get(), second_transport_.client());
+    ex_data_.Set(server_.get(), second_transport_.server());
+    return true;
+  }
+
   // The following functions may be configured on an |SSL_QUIC_METHOD| as
   // default implementations.
 
@@ -4760,6 +4775,7 @@
 
   static UnownedSSLExData<MockQUICTransport> ex_data_;
   MockQUICTransportPair transport_;
+  MockQUICTransportPair second_transport_;
 
   bssl::UniquePtr<SSL> client_;
   bssl::UniquePtr<SSL> server_;
@@ -4776,6 +4792,10 @@
       SendAlertCallback,
   };
 
+  g_last_session = nullptr;
+
+  SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH);
+  SSL_CTX_sess_set_new_cb(client_ctx_.get(), SaveLastSession);
   ASSERT_TRUE(SSL_CTX_set_quic_method(client_ctx_.get(), &quic_method));
   ASSERT_TRUE(SSL_CTX_set_quic_method(server_ctx_.get(), &quic_method));
   ASSERT_TRUE(CreateClientAndServer());
@@ -4807,13 +4827,43 @@
   EXPECT_FALSE(transport_.server()->has_alert());
 
   // The server sent NewSessionTicket messages in the handshake.
-  //
-  // TODO(davidben,svaldez): Add an API for the client to consume post-handshake
-  // messages and update these tests.
-  std::vector<uint8_t> new_session_ticket;
-  ASSERT_TRUE(transport_.client()->ReadHandshakeData(
-      &new_session_ticket, ssl_encryption_application));
-  EXPECT_FALSE(new_session_ticket.empty());
+  EXPECT_FALSE(g_last_session);
+  ASSERT_TRUE(ProvideHandshakeData(client_.get()));
+  EXPECT_EQ(SSL_process_quic_post_handshake(client_.get()), 1);
+  EXPECT_TRUE(g_last_session);
+
+  // Create a second connection to verify resumption works.
+  ASSERT_TRUE(CreateSecondClientAndServer());
+  bssl::UniquePtr<SSL_SESSION> session = std::move(g_last_session);
+  SSL_set_session(client_.get(), session.get());
+
+  for (;;) {
+    ASSERT_TRUE(ProvideHandshakeData(client_.get()));
+    int client_ret = SSL_do_handshake(client_.get());
+    if (client_ret != 1) {
+      ASSERT_EQ(client_ret, -1);
+      ASSERT_EQ(SSL_get_error(client_.get(), client_ret), SSL_ERROR_WANT_READ);
+    }
+
+    ASSERT_TRUE(ProvideHandshakeData(server_.get()));
+    int server_ret = SSL_do_handshake(server_.get());
+    if (server_ret != 1) {
+      ASSERT_EQ(server_ret, -1);
+      ASSERT_EQ(SSL_get_error(server_.get(), server_ret), SSL_ERROR_WANT_READ);
+    }
+
+    if (client_ret == 1 && server_ret == 1) {
+      break;
+    }
+  }
+
+  EXPECT_EQ(SSL_do_handshake(client_.get()), 1);
+  EXPECT_EQ(SSL_do_handshake(server_.get()), 1);
+  EXPECT_TRUE(transport_.SecretsMatch(ssl_encryption_application));
+  EXPECT_FALSE(transport_.client()->has_alert());
+  EXPECT_FALSE(transport_.server()->has_alert());
+  EXPECT_TRUE(SSL_session_reused(client_.get()));
+  EXPECT_TRUE(SSL_session_reused(server_.get()));
 }
 
 // Test only releasing data to QUIC one byte at a time on request, to maximize
@@ -5073,6 +5123,56 @@
       SSL_provide_quic_data(client_.get(), ssl_encryption_initial, &b, 1));
 }
 
+// Provide invalid post-handshake data.
+TEST_F(QUICMethodTest, BadPostHandshake) {
+  const SSL_QUIC_METHOD quic_method = {
+      SetEncryptionSecretsCallback,
+      AddHandshakeDataCallback,
+      FlushFlightCallback,
+      SendAlertCallback,
+  };
+
+  g_last_session = nullptr;
+
+  SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH);
+  SSL_CTX_sess_set_new_cb(client_ctx_.get(), SaveLastSession);
+  ASSERT_TRUE(SSL_CTX_set_quic_method(client_ctx_.get(), &quic_method));
+  ASSERT_TRUE(SSL_CTX_set_quic_method(server_ctx_.get(), &quic_method));
+  ASSERT_TRUE(CreateClientAndServer());
+
+  for (;;) {
+    ASSERT_TRUE(ProvideHandshakeData(client_.get()));
+    int client_ret = SSL_do_handshake(client_.get());
+    if (client_ret != 1) {
+      ASSERT_EQ(client_ret, -1);
+      ASSERT_EQ(SSL_get_error(client_.get(), client_ret), SSL_ERROR_WANT_READ);
+    }
+
+    ASSERT_TRUE(ProvideHandshakeData(server_.get()));
+    int server_ret = SSL_do_handshake(server_.get());
+    if (server_ret != 1) {
+      ASSERT_EQ(server_ret, -1);
+      ASSERT_EQ(SSL_get_error(server_.get(), server_ret), SSL_ERROR_WANT_READ);
+    }
+
+    if (client_ret == 1 && server_ret == 1) {
+      break;
+    }
+  }
+
+  EXPECT_EQ(SSL_do_handshake(client_.get()), 1);
+  EXPECT_EQ(SSL_do_handshake(server_.get()), 1);
+  EXPECT_TRUE(transport_.SecretsMatch(ssl_encryption_application));
+  EXPECT_FALSE(transport_.client()->has_alert());
+  EXPECT_FALSE(transport_.server()->has_alert());
+
+  // Junk sent as part of post-handshake data should cause an error.
+  uint8_t kJunk[] = {0x17, 0x0, 0x0, 0x4, 0xB, 0xE, 0xE, 0xF};
+  ASSERT_TRUE(SSL_provide_quic_data(client_.get(), ssl_encryption_application,
+                                    kJunk, sizeof(kJunk)));
+  EXPECT_EQ(SSL_process_quic_post_handshake(client_.get()), 0);
+}
+
 // TODO(davidben): Convert this file to GTest properly.
 TEST(SSLTest, AllTests) {
   if (!TestSSL_SESSIONEncoding(kOpenSSLSession) ||
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index 7df7fe7..8616967 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -340,6 +340,18 @@
       continue;
     }
 
+    // JDK 11, prior to 11.0.2, has a buggy TLS 1.3 implementation which fails
+    // to send SNI when offering 1.3 sessions. Disable TLS 1.3 for such
+    // clients. We apply this logic here rather than |ssl_supports_version| so
+    // the downgrade signal continues to query the true capabilities. (The
+    // workaround is a limitation of the peer's capabilities rather than our
+    // own.)
+    //
+    // See https://bugs.openjdk.java.net/browse/JDK-8211806.
+    if (versions[i] == TLS1_3_VERSION && hs->apply_jdk11_workaround) {
+      continue;
+    }
+
     CBS copy = *peer_versions;
     while (CBS_len(&copy) != 0) {
       uint16_t version;
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index dc12559..675a08a 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -12,10 +12,6 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-#if !defined(__STDC_FORMAT_MACROS)
-#define __STDC_FORMAT_MACROS
-#endif
-
 #include <openssl/base.h>
 
 #if !defined(OPENSSL_WINDOWS)
@@ -708,6 +704,7 @@
 
     // Reset the connection and try again at 1-RTT.
     SSL_reset_early_data_reject(ssl.get());
+    GetTestState(ssl.get())->cert_verified = false;
 
     // After reseting, the socket should report it is no longer in an early data
     // state.
diff --git a/src/ssl/test/runner/chacha20_poly1305_test.go b/src/ssl/test/runner/chacha20_poly1305_test.go
index 38c4b70..b59bb02 100644
--- a/src/ssl/test/runner/chacha20_poly1305_test.go
+++ b/src/ssl/test/runner/chacha20_poly1305_test.go
@@ -16,7 +16,6 @@
 
 import (
 	"bytes"
-	"encoding/hex"
 	"testing"
 )
 
@@ -80,14 +79,6 @@
 	}
 }
 
-func decodeHexOrPanic(in string) []byte {
-	out, err := hex.DecodeString(in)
-	if err != nil {
-		panic(err)
-	}
-	return out
-}
-
 var chaCha20Poly1305TestVectors = []struct {
 	key, input, nonce, ad, output string
 }{
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 702814d..73b8889 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -1626,6 +1626,25 @@
 	// SendCertUncompressedLength, if not zero, sets the uncompressed length that
 	// will be sent in the compressed certificate message.
 	SendCertUncompressedLength uint32
+
+	// SendClientHelloWithFixes, if not nil, sends the specified byte string
+	// instead of the ClientHello. This string is incorporated into the
+	// transcript as if it were the real ClientHello, but the handshake will
+	// otherwise behave as if this was not sent in terms of what ciphers it
+	// will accept, etc.
+	//
+	// The input is modified to match key share entries. DefaultCurves must
+	// be configured to match. The random and session ID fields are
+	// extracted from the ClientHello.
+	SendClientHelloWithFixes []byte
+
+	// SendJDK11DowngradeRandom, if true, causes the server to send the JDK
+	// 11 downgrade signal.
+	SendJDK11DowngradeRandom bool
+
+	// ExpectJDK11DowngradeRandom is whether the client should expect the
+	// server to send the JDK 11 downgrade signal.
+	ExpectJDK11DowngradeRandom bool
 }
 
 func (c *Config) serverInit() {
@@ -2067,6 +2086,9 @@
 	// See RFC 8446, section 4.1.3.
 	downgradeTLS13 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01}
 	downgradeTLS12 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00}
+
+	// This is a non-standard randomly-generated value.
+	downgradeJDK11 = []byte{0xed, 0xbf, 0xb4, 0xa8, 0xc2, 0x47, 0x10, 0xff}
 )
 
 func containsGREASE(values []uint16) bool {
diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json
index a840f37..1a154c2 100644
--- a/src/ssl/test/runner/fuzzer_mode.json
+++ b/src/ssl/test/runner/fuzzer_mode.json
@@ -44,8 +44,7 @@
     "EarlyData-ALPNOmitted1-Server-*": "Trial decryption does not work with the NULL cipher.",
     "EarlyData-ALPNOmitted2-Server-*": "Trial decryption does not work with the NULL cipher.",
     "*-EarlyData-RejectUnfinishedWrite-Client-*": "Trial decryption does not work with the NULL cipher.",
-    "EarlyData-Reject-Client-*": "Trial decryption does not work with the NULL cipher.",
-    "EarlyData-RejectTicket-Client-*": "Trial decryption does not work with the NULL cipher.",
+    "EarlyData-Reject*-Client-*": "Trial decryption does not work with the NULL cipher.",
     "CustomExtensions-Server-EarlyDataOffered": "Trial decryption does not work with the NULL cipher.",
 
     "Renegotiate-Client-BadExt*": "Fuzzer mode does not check renegotiation_info.",
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 4dfa469..ab1f4dd 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -49,6 +49,32 @@
 	panic("Unknown ClientHello version.")
 }
 
+func fixClientHellos(hello *clientHelloMsg, in []byte) ([]byte, error) {
+	ret := append([]byte{}, in...)
+	newHello := new(clientHelloMsg)
+	if !newHello.unmarshal(ret) {
+		return nil, errors.New("tls: invalid ClientHello")
+	}
+
+	hello.random = newHello.random
+	hello.sessionId = newHello.sessionId
+
+	// Replace |ret|'s key shares with those of |hello|. For simplicity, we
+	// require their lengths match, which is satisfied by matching the
+	// DefaultCurves setting to the selection in the replacement
+	// ClientHello.
+	bb := newByteBuilder()
+	hello.marshalKeyShares(bb)
+	keyShares := bb.finish()
+	if len(keyShares) != len(newHello.keySharesRaw) {
+		return nil, errors.New("tls: ClientHello key share length is inconsistent with DefaultCurves setting")
+	}
+	// |newHello.keySharesRaw| aliases |ret|.
+	copy(newHello.keySharesRaw, keyShares)
+
+	return ret, nil
+}
+
 func (c *Conn) clientHandshake() error {
 	if c.config == nil {
 		c.config = defaultConfig()
@@ -405,7 +431,14 @@
 			}
 			generatePSKBinders(version, hello, pskCipherSuite, session.masterSecret, []byte{}, []byte{}, c.config)
 		}
-		helloBytes = hello.marshal()
+		if c.config.Bugs.SendClientHelloWithFixes != nil {
+			helloBytes, err = fixClientHellos(hello, c.config.Bugs.SendClientHelloWithFixes)
+			if err != nil {
+				return err
+			}
+		} else {
+			helloBytes = hello.marshal()
+		}
 
 		if c.config.Bugs.PartialClientFinishedWithClientHello {
 			// Include one byte of Finished. We can compute it
@@ -604,21 +637,30 @@
 
 	_, supportsTLS13 := c.config.isSupportedVersion(VersionTLS13, false)
 	// Check for downgrade signals in the server random, per RFC 8446, section 4.1.3.
+	gotDowngrade := serverHello.random[len(serverHello.random)-8:]
 	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) {
+			if bytes.Equal(gotDowngrade, 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) {
+			if bytes.Equal(gotDowngrade, downgradeTLS12) {
 				c.sendAlert(alertProtocolVersion)
 				return errors.New("tls: downgrade from TLS 1.2 detected")
 			}
 		}
 	}
 
+	if bytes.Equal(gotDowngrade, downgradeJDK11) != c.config.Bugs.ExpectJDK11DowngradeRandom {
+		c.sendAlert(alertProtocolVersion)
+		if c.config.Bugs.ExpectJDK11DowngradeRandom {
+			return errors.New("tls: server did not send a JDK 11 downgrade signal")
+		}
+		return errors.New("tls: server sent an unexpected JDK 11 downgrade signal")
+	}
+
 	suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite)
 	if suite == nil {
 		c.sendAlert(alertHandshakeFailure)
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index edc5a92..e0867a5 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -266,6 +266,7 @@
 	supportedPoints         []uint8
 	hasKeyShares            bool
 	keyShares               []keyShareEntry
+	keySharesRaw            []byte
 	trailingKeyShareData    bool
 	pskIdentities           []pskIdentity
 	pskKEModes              []byte
@@ -352,6 +353,18 @@
 		eqUint16s(m.compressedCertAlgs, m1.compressedCertAlgs)
 }
 
+func (m *clientHelloMsg) marshalKeyShares(bb *byteBuilder) {
+	keyShares := bb.addU16LengthPrefixed()
+	for _, keyShare := range m.keyShares {
+		keyShares.addU16(uint16(keyShare.group))
+		keyExchange := keyShares.addU16LengthPrefixed()
+		keyExchange.addBytes(keyShare.keyExchange)
+	}
+	if m.trailingKeyShareData {
+		keyShares.addU8(0)
+	}
+}
+
 func (m *clientHelloMsg) marshal() []byte {
 	if m.raw != nil {
 		return m.raw
@@ -456,17 +469,7 @@
 	if m.hasKeyShares {
 		extensions.addU16(extensionKeyShare)
 		keyShareList := extensions.addU16LengthPrefixed()
-
-		keyShares := keyShareList.addU16LengthPrefixed()
-		for _, keyShare := range m.keyShares {
-			keyShares.addU16(uint16(keyShare.group))
-			keyExchange := keyShares.addU16LengthPrefixed()
-			keyExchange.addBytes(keyShare.keyExchange)
-		}
-
-		if m.trailingKeyShareData {
-			keyShares.addU8(0)
-		}
+		m.marshalKeyShares(keyShareList)
 	}
 	if len(m.pskKEModes) > 0 {
 		extensions.addU16(extensionPSKKeyExchangeModes)
@@ -763,11 +766,12 @@
 			m.sessionTicket = []byte(body)
 		case extensionKeyShare:
 			// https://tools.ietf.org/html/rfc8446#section-4.2.8
+			m.hasKeyShares = true
+			m.keySharesRaw = body
 			var keyShares byteReader
 			if !body.readU16LengthPrefixed(&keyShares) || len(body) != 0 {
 				return false
 			}
-			m.hasKeyShares = true
 			for len(keyShares) > 0 {
 				var entry keyShareEntry
 				var group uint16
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 4950a4f..6a75242 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -1182,6 +1182,9 @@
 			copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
 		}
 	}
+	if config.Bugs.SendJDK11DowngradeRandom {
+		copy(hs.hello.random[len(hs.hello.random)-8:], downgradeJDK11)
+	}
 
 	if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID {
 		return false, errors.New("tls: expected non-empty session ID from client")
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 9631e6e..fadc890 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -42,6 +42,8 @@
 	"sync"
 	"syscall"
 	"time"
+
+	"boringssl.googlesource.com/boringssl/util/testresult"
 )
 
 var (
@@ -303,6 +305,14 @@
 	return ret
 }
 
+func decodeHexOrPanic(in string) []byte {
+	ret, err := hex.DecodeString(in)
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
 type testType int
 
 const (
@@ -908,7 +918,7 @@
 
 		for i, v := range buf {
 			if v != testMessage[i]^0xff {
-				return fmt.Errorf("bad reply contents at byte %d", i)
+				return fmt.Errorf("bad reply contents at byte %d; got %q and wanted %q", i, buf, testMessage)
 			}
 		}
 	}
@@ -5016,6 +5026,165 @@
 						}, flags...),
 						resumeSession: true,
 					})
+					if vers.version >= VersionTLS13 {
+						tests = append(tests, testCase{
+							testType: testType,
+							name:     "EarlyData-RejectTicket-Client-Reverify" + suffix,
+							config: Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+							},
+							resumeConfig: &Config{
+								MaxVersion:             vers.version,
+								MaxEarlyDataSize:       16384,
+								SessionTicketsDisabled: true,
+							},
+							tls13Variant:         vers.tls13Variant,
+							resumeSession:        true,
+							expectResumeRejected: true,
+							flags: append([]string{
+								"-enable-early-data",
+								"-expect-ticket-supports-early-data",
+								"-reverify-on-resume",
+								"-on-resume-shim-writes-first",
+								// Session tickets are disabled, so the runner will not send a ticket.
+								"-on-retry-expect-no-session",
+								"-expect-reject-early-data",
+							}, flags...),
+						})
+						tests = append(tests, testCase{
+							testType: testType,
+							name:     "EarlyData-Reject0RTT-Client-Reverify" + suffix,
+							config: Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+							},
+							resumeConfig: &Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+								Bugs: ProtocolBugs{
+									AlwaysRejectEarlyData: true,
+								},
+							},
+							tls13Variant:         vers.tls13Variant,
+							resumeSession:        true,
+							expectResumeRejected: false,
+							flags: append([]string{
+								"-enable-early-data",
+								"-expect-reject-early-data",
+								"-expect-ticket-supports-early-data",
+								"-reverify-on-resume",
+								"-on-resume-shim-writes-first",
+							}, flags...),
+						})
+						tests = append(tests, testCase{
+							testType: testType,
+							name:     "EarlyData-RejectTicket-Client-ReverifyFails" + suffix,
+							config: Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+							},
+							resumeConfig: &Config{
+								MaxVersion:             vers.version,
+								MaxEarlyDataSize:       16384,
+								SessionTicketsDisabled: true,
+							},
+							tls13Variant:         vers.tls13Variant,
+							resumeSession:        true,
+							expectResumeRejected: true,
+							shouldFail:           true,
+							expectedError:        ":CERTIFICATE_VERIFY_FAILED:",
+							flags: append([]string{
+								"-enable-early-data",
+								"-expect-ticket-supports-early-data",
+								"-reverify-on-resume",
+								"-on-resume-shim-writes-first",
+								// Session tickets are disabled, so the runner will not send a ticket.
+								"-on-retry-expect-no-session",
+								"-on-retry-verify-fail",
+								"-expect-reject-early-data",
+							}, flags...),
+						})
+						tests = append(tests, testCase{
+							testType: testType,
+							name:     "EarlyData-Reject0RTT-Client-ReverifyFails" + suffix,
+							config: Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+							},
+							resumeConfig: &Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+								Bugs: ProtocolBugs{
+									AlwaysRejectEarlyData: true,
+								},
+							},
+							tls13Variant:         vers.tls13Variant,
+							resumeSession:        true,
+							expectResumeRejected: false,
+							shouldFail:           true,
+							expectedError:        ":CERTIFICATE_VERIFY_FAILED:",
+							flags: append([]string{
+								"-enable-early-data",
+								"-expect-reject-early-data",
+								"-expect-ticket-supports-early-data",
+								"-reverify-on-resume",
+								"-on-resume-shim-writes-first",
+								"-on-retry-verify-fail",
+							}, flags...),
+						})
+						// This tests that we only call the verify callback once.
+						tests = append(tests, testCase{
+							testType: testType,
+							name:     "EarlyData-Accept0RTT-Client-Reverify" + suffix,
+							config: Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+							},
+							resumeConfig: &Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+								Bugs: ProtocolBugs{
+									ExpectEarlyData: [][]byte{[]byte("hello")},
+								},
+							},
+							tls13Variant:         vers.tls13Variant,
+							resumeSession:        true,
+							expectResumeRejected: false,
+							flags: append([]string{
+								"-enable-early-data",
+								"-expect-ticket-supports-early-data",
+								"-reverify-on-resume",
+								"-on-resume-shim-writes-first",
+							}, flags...),
+						})
+						tests = append(tests, testCase{
+							testType: testType,
+							name:     "EarlyData-Accept0RTT-Client-ReverifyFails" + suffix,
+							config: Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+							},
+							resumeConfig: &Config{
+								MaxVersion:       vers.version,
+								MaxEarlyDataSize: 16384,
+								Bugs: ProtocolBugs{
+									ExpectEarlyData: [][]byte{[]byte("hello")},
+								},
+							},
+							tls13Variant:  vers.tls13Variant,
+							resumeSession: true,
+							shouldFail:    true,
+							expectedError: ":CERTIFICATE_VERIFY_FAILED:",
+							flags: append([]string{
+								"-enable-early-data",
+								"-expect-ticket-supports-early-data",
+								"-reverify-on-resume",
+								"-on-resume-verify-fail",
+								"-on-resume-shim-writes-first",
+							}, flags...),
+						})
+					}
 				}
 			}
 		}
@@ -14467,6 +14636,162 @@
 	}
 }
 
+func addJDK11WorkaroundTests() {
+	// Test the client treats the JDK 11 downgrade random like the usual one.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "Client-RejectJDK11DowngradeRandom",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				SendJDK11DowngradeRandom: true,
+			},
+		},
+		shouldFail:         true,
+		expectedError:      ":TLS13_DOWNGRADE:",
+		expectedLocalError: "remote error: illegal parameter",
+	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "Client-AcceptJDK11DowngradeRandom",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				SendJDK11DowngradeRandom: true,
+			},
+		},
+		flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+	})
+
+	var clientHelloTests = []struct {
+		clientHello []byte
+		isJDK11     bool
+	}{
+		{
+			// A default JDK 11 ClientHello.
+			decodeHexOrPanic("010001a9030336a379aa355a22a064b4402760efae1c73977b0b4c975efc7654c35677723dde201fe3f8a2bca60418a68f72463ea19f3c241e7cbfceb347e451a62bd2417d8981005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000106000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d000201010033004700450017004104721f007464cb08a0f36e093ad178eb78d6968df20077b2dd882694a85dc4c9884caf5092db41f16cc3f8d41f59426992fa5e32cfb9ad08deee752cdd95b1a6b5"),
+			true,
+		},
+		{
+			// The above with supported_versions and
+			// psk_key_exchange_modes in the wrong order.
+			decodeHexOrPanic("010001a9030336a379aa355a22a064b4402760efae1c73977b0b4c975efc7654c35677723dde201fe3f8a2bca60418a68f72463ea19f3c241e7cbfceb347e451a62bd2417d8981005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000106000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002d00020101002b00090803040303030203010033004700450017004104721f007464cb08a0f36e093ad178eb78d6968df20077b2dd882694a85dc4c9884caf5092db41f16cc3f8d41f59426992fa5e32cfb9ad08deee752cdd95b1a6b5"),
+			false,
+		},
+		{
+			// The above with a padding extension added at the end.
+			decodeHexOrPanic("010001b4030336a379aa355a22a064b4402760efae1c73977b0b4c975efc7654c35677723dde201fe3f8a2bca60418a68f72463ea19f3c241e7cbfceb347e451a62bd2417d8981005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000111000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d000201010033004700450017004104721f007464cb08a0f36e093ad178eb78d6968df20077b2dd882694a85dc4c9884caf5092db41f16cc3f8d41f59426992fa5e32cfb9ad08deee752cdd95b1a6b50015000770616464696e67"),
+			false,
+		},
+		{
+			// A JDK 11 ClientHello offering a TLS 1.3 PSK.
+			decodeHexOrPanic("0100024c0303a8d71b20f060545a398226e807d21371a7a02b7ca2f96f476c2dea7e5860c5a400005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff010001c9000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d000201010033004700450017004104aaec585ea9e121b24710a23560571322b2cf8ab8cd14e5762ef0486d8a6d0ecd721d8f2abda2eb8ed5ab7195505660450f49bba94bbf0c3f0070a531d9a1be4f002900cb00a600a0e6f7586d9a2bf64a54c1adf55a2f76657047e8e88e26629e2e7b9d630941e06fd87792770f6834e159a70b252157a9b4b082183f24629c8ff5049088b07ce37c49de8cf752a2ed7a545aff63bdc7a1b18e1bc201f23f159ee75d4987a04e00f840824f764691ab83a20e3032646e793065874cdb46138a52f50ed71406f399f96f9309eba4e5b1966148c22a63dc4aa1364269dd41dd5cc0e848d07af0095622c52cfcfc00212009cc315259e2328d65ad17a3de7c182c7874140a9356fecdd4614657806cd659"),
+			true,
+		},
+		{
+			// A JDK 11 ClientHello offering a TLS 1.2 session.
+			decodeHexOrPanic("010001a903038cdec49f4836d064a75046c93f22d0b9c2cf4900917332e6f0e1f41d692d3146201a3e99047492285ec65ab4e0eeee59f8f9d1eb7687398887bcd7b81353e93923005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000106000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d0002010100330047004500170041041c83c42fcd8fc06265b9f6e4f076f7e7ee17ace915c587845c0e1bc8cd177f904befeb611b682cae4702509a5f5d0c7162a282b8152d843169b91136e7c6f3e7"),
+			true,
+		},
+		{
+			// A JDK 11 ClientHello with EMS disabled.
+			decodeHexOrPanic("010001a50303323a857c324a9ef57d6e2544d129073830385cb1dc75ea79f6a2ec8ae09d2e7320f85fdd081678874c67ebab235e6d6a81d947f690bc0af9be4d39854ed67d9ef9005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000102000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b040105010601040203030301030202030201020200110009000702000400000000002b0009080304030303020301002d0002010100330047004500170041049c904c4850b495d75522f955d79e9cabea065c90279d6037a101a4c4ee712afc93ad0df5d12d287d53e458c7075d9a3ce3969c939bb62222bda779cecf54a603"),
+			true,
+		},
+		{
+			// A JDK 11 ClientHello with OCSP stapling disabled.
+			decodeHexOrPanic("0100019303038a50481dc85ee4f6581670821c50f2b3d34ac3251dc6e9b751bfd2521ab47ab02069a963c5486034c37ae0577ddb4c2db28cab592380ef8e4599d1305148712112005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff010000f0000000080006000003736e69000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b040105010601040203030301030202030201020200170000002b0009080304030303020301002d00020101003300470045001700410438a97824f842c549e3c339322d8b2dbaa85d10bd7bca9c969376cb0c60b1e929eb4d13db38dcb0082ad8c637b24f55466a9acbb0b63634c1f431ec8342cf720d"),
+			true,
+		},
+		{
+			// A JDK 11 ClientHello configured with a smaller set of
+			// ciphers.
+			decodeHexOrPanic("0100015603036f5706bbdf1dcae671cd9be043603f5ed20f8fc195b426504cafb4f353edb0012007aabd35e588bc2504a72eda42cbbf89d69cfc0a6a1d77db0d757606f1f4811800061301c02bc02f01000107000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b00050403040303002d000201010033004700450017004104d283f3d5a90259b61d43ea1511211f568ce5d18457326b717e1f9d6b7d1476f2b51cdc3c798d3bdfba5095edff0ffd0540f6bc0c324bd9744f3b3f24317496e3ff01000100"),
+			true,
+		},
+		{
+			// The above with TLS_CHACHA20_POLY1305_SHA256 added,
+			// which JDK 11 does not support.
+			decodeHexOrPanic("0100015803036f5706bbdf1dcae671cd9be043603f5ed20f8fc195b426504cafb4f353edb0012007aabd35e588bc2504a72eda42cbbf89d69cfc0a6a1d77db0d757606f1f48118000813011303c02bc02f01000107000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b00050403040303002d000201010033004700450017004104d283f3d5a90259b61d43ea1511211f568ce5d18457326b717e1f9d6b7d1476f2b51cdc3c798d3bdfba5095edff0ffd0540f6bc0c324bd9744f3b3f24317496e3ff01000100"),
+			false,
+		},
+		{
+			// The above with X25519 added, which JDK 11 does not
+			// support.
+			decodeHexOrPanic("0100015803036f5706bbdf1dcae671cd9be043603f5ed20f8fc195b426504cafb4f353edb0012007aabd35e588bc2504a72eda42cbbf89d69cfc0a6a1d77db0d757606f1f4811800061301c02bc02f01000109000000080006000003736e69000500050100000000000a00220020001d0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b00050403040303002d000201010033004700450017004104d283f3d5a90259b61d43ea1511211f568ce5d18457326b717e1f9d6b7d1476f2b51cdc3c798d3bdfba5095edff0ffd0540f6bc0c324bd9744f3b3f24317496e3ff01000100"),
+			false,
+		},
+		{
+			// A JDK 11 ClientHello with ALPN protocols configured.
+			decodeHexOrPanic("010001bb0303c0e0ea707b00c5311eb09cabd58626692cebfaefaef7265637e4550811dae16220da86d6eea04e214e873675223f08a6926bcf79f16d866280bdbab85e9e09c3ff005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000118000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020010000e000c02683208687474702f312e310011000900070200040000000000170000002b0009080304030303020301002d00020101003300470045001700410416def07c1d66ddde5fc9dcc328c8e77022d321c590c0d30cb41d515b38dca34540819a216c6c053bd47b9068f4f6b960f03647de4e36e8b7ffeea78f7252e3d9"),
+			true,
+		},
+	}
+	for i, t := range clientHelloTests {
+		expectedVersion := uint16(VersionTLS13)
+		if t.isJDK11 {
+			expectedVersion = VersionTLS12
+		}
+
+		// In each of these tests, we set DefaultCurves to P-256 to
+		// match the test inputs. SendClientHelloWithFixes requires the
+		// key_shares extension to match in type.
+
+		// With the workaround enabled, we should negotiate TLS 1.2 on
+		// JDK 11 ClientHellos.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     fmt.Sprintf("Server-JDK11-%d", i),
+			config: Config{
+				MaxVersion:    VersionTLS13,
+				DefaultCurves: []CurveID{CurveP256},
+				Bugs: ProtocolBugs{
+					SendClientHelloWithFixes:   t.clientHello,
+					ExpectJDK11DowngradeRandom: t.isJDK11,
+				},
+			},
+			expectedVersion: expectedVersion,
+			flags:           []string{"-jdk11-workaround"},
+		})
+
+		// With the workaround disabled, we always negotiate TLS 1.3.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     fmt.Sprintf("Server-JDK11-NoWorkaround-%d", i),
+			config: Config{
+				MaxVersion:    VersionTLS13,
+				DefaultCurves: []CurveID{CurveP256},
+				Bugs: ProtocolBugs{
+					SendClientHelloWithFixes:   t.clientHello,
+					ExpectJDK11DowngradeRandom: false,
+				},
+			},
+			expectedVersion: VersionTLS13,
+		})
+
+		// If the server does not support TLS 1.3, the workaround should
+		// be a no-op. In particular, it should not send the downgrade
+		// signal.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     fmt.Sprintf("Server-JDK11-TLS12-%d", i),
+			config: Config{
+				MaxVersion:    VersionTLS13,
+				DefaultCurves: []CurveID{CurveP256},
+				Bugs: ProtocolBugs{
+					SendClientHelloWithFixes:   t.clientHello,
+					ExpectJDK11DowngradeRandom: false,
+				},
+			},
+			expectedVersion: VersionTLS12,
+			flags: []string{
+				"-jdk11-workaround",
+				"-max-version", strconv.Itoa(VersionTLS12),
+			},
+		})
+	}
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -14502,10 +14827,10 @@
 	err     error
 }
 
-func statusPrinter(doneChan chan *testOutput, statusChan chan statusMsg, total int) {
+func statusPrinter(doneChan chan *testresult.Results, statusChan chan statusMsg, total int) {
 	var started, done, failed, unimplemented, lineLen int
 
-	testOutput := newTestOutput()
+	testOutput := testresult.NewResults()
 	for msg := range statusChan {
 		if !*pipe {
 			// Erase the previous status line.
@@ -14528,18 +14853,22 @@
 						fmt.Printf("UNIMPLEMENTED (%s)\n", msg.test.name)
 					}
 					unimplemented++
-					testOutput.addResult(msg.test.name, "UNIMPLEMENTED")
+					if *allowUnimplemented {
+						testOutput.AddSkip(msg.test.name)
+					} else {
+						testOutput.AddResult(msg.test.name, "SKIP")
+					}
 				} else {
 					fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
 					failed++
-					testOutput.addResult(msg.test.name, "FAIL")
+					testOutput.AddResult(msg.test.name, "FAIL")
 				}
 			} else {
 				if *pipe {
 					// Print each test instead of a status line.
 					fmt.Printf("PASSED (%s)\n", msg.test.name)
 				}
-				testOutput.addResult(msg.test.name, "PASS")
+				testOutput.AddResult(msg.test.name, "PASS")
 			}
 		}
 
@@ -14596,6 +14925,7 @@
 	addExtraHandshakeTests()
 	addOmitExtensionsTests()
 	addCertCompressionTests()
+	addJDK11WorkaroundTests()
 
 	testCases = append(testCases, convertToSplitHandshakeTests(testCases)...)
 
@@ -14603,7 +14933,7 @@
 
 	statusChan := make(chan statusMsg, *numWorkers)
 	testChan := make(chan *testCase, *numWorkers)
-	doneChan := make(chan *testOutput)
+	doneChan := make(chan *testresult.Results)
 
 	if len(*shimConfigFile) != 0 {
 		encoded, err := ioutil.ReadFile(*shimConfigFile)
@@ -14676,16 +15006,12 @@
 	fmt.Printf("\n")
 
 	if *jsonOutput != "" {
-		if err := testOutput.writeTo(*jsonOutput); err != nil {
+		if err := testOutput.WriteToFile(*jsonOutput); err != nil {
 			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
 		}
 	}
 
-	if !*allowUnimplemented && testOutput.NumFailuresByType["UNIMPLEMENTED"] > 0 {
-		os.Exit(1)
-	}
-
-	if !testOutput.noneFailed {
+	if !testOutput.HasUnexpectedResults() {
 		os.Exit(1)
 	}
 }
diff --git a/src/ssl/test/runner/test_output.go b/src/ssl/test/runner/test_output.go
deleted file mode 100644
index eb54638..0000000
--- a/src/ssl/test/runner/test_output.go
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Copyright (c) 2015, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-package runner
-
-import (
-	"encoding/json"
-	"os"
-	"time"
-)
-
-// testOutput is a representation of Chromium's JSON test result format. See
-// https://www.chromium.org/developers/the-json-test-results-format
-type testOutput struct {
-	Version           int                   `json:"version"`
-	Interrupted       bool                  `json:"interrupted"`
-	PathDelimiter     string                `json:"path_delimiter"`
-	SecondsSinceEpoch float64               `json:"seconds_since_epoch"`
-	NumFailuresByType map[string]int        `json:"num_failures_by_type"`
-	Tests             map[string]testResult `json:"tests"`
-	noneFailed        bool
-}
-
-type testResult struct {
-	Actual       string `json:"actual"`
-	Expected     string `json:"expected"`
-	IsUnexpected bool   `json:"is_unexpected"`
-}
-
-func newTestOutput() *testOutput {
-	return &testOutput{
-		Version:           3,
-		PathDelimiter:     ".",
-		SecondsSinceEpoch: float64(time.Now().UnixNano()) / float64(time.Second/time.Nanosecond),
-		NumFailuresByType: make(map[string]int),
-		Tests:             make(map[string]testResult),
-		noneFailed:        true,
-	}
-}
-
-func (t *testOutput) addResult(name, result string) {
-	if _, found := t.Tests[name]; found {
-		panic(name)
-	}
-	t.Tests[name] = testResult{
-		Actual:       result,
-		Expected:     "PASS",
-		IsUnexpected: result != "PASS",
-	}
-	t.NumFailuresByType[result]++
-	if result != "PASS" && result != "UNIMPLEMENTED" {
-		t.noneFailed = false
-	}
-}
-
-func (t *testOutput) writeTo(name string) error {
-	file, err := os.Create(name)
-	if err != nil {
-		return err
-	}
-	defer file.Close()
-	out, err := json.MarshalIndent(t, "", "  ")
-	if err != nil {
-		return err
-	}
-	_, err = file.Write(out)
-	return err
-}
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 52e6cf7..7447d5a 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -146,6 +146,7 @@
   { "-is-handshaker-supported", &TestConfig::is_handshaker_supported },
   { "-handshaker-resume", &TestConfig::handshaker_resume },
   { "-reverify-on-resume", &TestConfig::reverify_on_resume },
+  { "-jdk11-workaround", &TestConfig::jdk11_workaround },
 };
 
 const Flag<std::string> kStringFlags[] = {
@@ -1624,6 +1625,9 @@
       return nullptr;
     }
   }
+  if (jdk11_workaround) {
+    SSL_set_jdk11_workaround(ssl.get(), 1);
+  }
 
   if (session != NULL) {
     if (!is_server) {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index b65ca42..bffe911 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -169,6 +169,7 @@
   bool is_handshaker_supported = false;
   bool handshaker_resume = false;
   std::string handshaker_path;
+  bool jdk11_workaround = false;
 
   int argc;
   char **argv;
diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc
index 299fc14..6baeaf7 100644
--- a/src/ssl/tls13_both.cc
+++ b/src/ssl/tls13_both.cc
@@ -43,12 +43,15 @@
     0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
 };
 
+// See RFC 8446, section 4.1.3.
 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};
 
+// This is a non-standard randomly-generated value.
+const uint8_t kJDK11DowngradeRandom[8] = {0xed, 0xbf, 0xb4, 0xa8,
+                                          0xc2, 0x47, 0x10, 0xff};
 
 bool tls13_get_cert_verify_signature_input(
     SSL_HANDSHAKE *hs, Array<uint8_t> *out,
diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc
index fb56001..0d3e877 100644
--- a/src/ssl/tls13_client.cc
+++ b/src/ssl/tls13_client.cc
@@ -465,7 +465,7 @@
   SSL *const ssl = hs->ssl;
   // CertificateRequest may only be sent in non-resumption handshakes.
   if (ssl->s3->session_reused) {
-    if (ssl->ctx->reverify_on_resume) {
+    if (ssl->ctx->reverify_on_resume && !ssl->s3->early_data_accepted) {
       hs->tls13_state = state_server_certificate_reverify;
       return ssl_hs_ok;
     }
diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc
index 969d4b1..b4c4ca5 100644
--- a/src/ssl/tls13_server.cc
+++ b/src/ssl/tls13_server.cc
@@ -12,13 +12,6 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-// Per C99, various stdint.h macros are unavailable in C++ unless some macros
-// are defined. C++11 overruled this decision, but older Android NDKs still
-// require it.
-#if !defined(__STDC_LIMIT_MACROS)
-#define __STDC_LIMIT_MACROS
-#endif
-
 #include <openssl/ssl.h>
 
 #include <assert.h>