external/boringssl: Sync to c3889634a1aa52575c5d26497696238208fbd0f5.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/41c10e2b5f37edce8b9f292f7f3bacb7e30e25c4..c3889634a1aa52575c5d26497696238208fbd0f5

Test: atest CtsLibcoreTestCases
Change-Id: Ia1c2941ccf58a9e0d736b3409a2d13c21603a205
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt
index d6c1294..dc89dca 100644
--- a/src/ssl/CMakeLists.txt
+++ b/src/ssl/CMakeLists.txt
@@ -52,12 +52,11 @@
   ssl_test.cc
 
   $<TARGET_OBJECTS:boringssl_gtest_main>
-  $<TARGET_OBJECTS:test_support>
 )
 
 add_dependencies(ssl_test global_target)
 
-target_link_libraries(ssl_test ssl crypto boringssl_gtest)
+target_link_libraries(ssl_test test_support_lib boringssl_gtest ssl crypto)
 if(WIN32)
   target_link_libraries(ssl_test ws2_32)
 endif()
diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc
index 058a793..89be48f 100644
--- a/src/ssl/handshake.cc
+++ b/src/ssl/handshake.cc
@@ -135,6 +135,7 @@
       cert_request(false),
       certificate_status_expected(false),
       ocsp_stapling_requested(false),
+      delegated_credential_requested(false),
       should_ack_sni(false),
       in_false_start(false),
       in_early_data(false),
@@ -544,7 +545,7 @@
       case ssl_hs_read_server_hello:
       case ssl_hs_read_message:
       case ssl_hs_read_change_cipher_spec: {
-        if (ssl->ctx->quic_method) {
+        if (ssl->quic_method) {
           hs->wait = ssl_hs_ok;
           // The change cipher spec is omitted in QUIC.
           if (hs->wait != ssl_hs_read_change_cipher_spec) {
diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc
index 0274dc2..b0de670 100644
--- a/src/ssl/handshake_client.cc
+++ b/src/ssl/handshake_client.cc
@@ -416,8 +416,6 @@
     return ssl_hs_error;
   }
 
-  // Initialize a random session ID for the experimental TLS 1.3 variant
-  // requiring a session id.
   if (ssl->session != nullptr &&
       !ssl->s3->initial_handshake_complete &&
       ssl->session->session_id_length > 0) {
@@ -425,6 +423,7 @@
     OPENSSL_memcpy(hs->session_id, ssl->session->session_id,
                    hs->session_id_len);
   } else if (hs->max_version >= TLS1_3_VERSION) {
+    // Initialize a random session ID.
     hs->session_id_len = sizeof(hs->session_id);
     if (!RAND_bytes(hs->session_id, hs->session_id_len)) {
       return ssl_hs_error;
@@ -1219,7 +1218,7 @@
     }
   }
 
-  if (!ssl_has_certificate(hs->config)) {
+  if (!ssl_has_certificate(hs)) {
     // Without a client certificate, the handshake buffer may be released.
     hs->transcript.FreeBuffer();
   }
@@ -1249,6 +1248,27 @@
   Array<uint8_t> pms;
   uint32_t alg_k = hs->new_cipher->algorithm_mkey;
   uint32_t alg_a = hs->new_cipher->algorithm_auth;
+  if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+    CRYPTO_BUFFER *leaf =
+        sk_CRYPTO_BUFFER_value(hs->new_session->certs.get(), 0);
+    CBS leaf_cbs;
+    CBS_init(&leaf_cbs, CRYPTO_BUFFER_data(leaf), CRYPTO_BUFFER_len(leaf));
+
+    // Check the key usage matches the cipher suite. We do this unconditionally
+    // for non-RSA certificates. In particular, it's needed to distinguish ECDH
+    // certificates, which we do not support, from ECDSA certificates.
+    // Historically, we have not checked RSA key usages, so it is controlled by
+    // a flag for now. See https://crbug.com/795089.
+    ssl_key_usage_t intended_use = (alg_k & SSL_kRSA)
+                                       ? key_usage_encipherment
+                                       : key_usage_digital_signature;
+    if (ssl->config->enforce_rsa_key_usage ||
+        EVP_PKEY_id(hs->peer_pubkey.get()) != EVP_PKEY_RSA) {
+      if (!ssl_cert_check_key_usage(&leaf_cbs, intended_use)) {
+        return ssl_hs_error;
+      }
+    }
+  }
 
   // If using a PSK key exchange, prepare the pre-shared key.
   unsigned psk_len = 0;
@@ -1386,12 +1406,12 @@
 static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
-  if (!hs->cert_request || !ssl_has_certificate(hs->config)) {
+  if (!hs->cert_request || !ssl_has_certificate(hs)) {
     hs->state = state_send_client_finished;
     return ssl_hs_ok;
   }
 
-  assert(ssl_has_private_key(hs->config));
+  assert(ssl_has_private_key(hs));
   ScopedCBB cbb;
   CBB body, child;
   if (!ssl->method->init_message(ssl, cbb.get(), &body,
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index 8b3b942..cb4e9d1 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -303,7 +303,7 @@
   uint32_t mask_k = 0;
   uint32_t mask_a = 0;
 
-  if (ssl_has_certificate(hs->config)) {
+  if (ssl_has_certificate(hs)) {
     mask_a |= ssl_cipher_auth_mask_for_key(hs->local_pubkey.get());
     if (EVP_PKEY_id(hs->local_pubkey.get()) == EVP_PKEY_RSA) {
       mask_k |= SSL_kRSA;
@@ -402,8 +402,7 @@
 }
 
 // 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.
+// from a JDK 11 client 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.
@@ -868,7 +867,7 @@
   ScopedCBB cbb;
 
   if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
-    if (!ssl_has_certificate(hs->config)) {
+    if (!ssl_has_certificate(hs)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
       return ssl_hs_error;
     }
@@ -974,7 +973,7 @@
 
   // Add a signature.
   if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
-    if (!ssl_has_private_key(hs->config)) {
+    if (!ssl_has_private_key(hs)) {
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return ssl_hs_error;
     }
@@ -1226,6 +1225,8 @@
       return ssl_hs_error;
     }
 
+    CONSTTIME_SECRET(decrypt_buf.data(), decrypt_len);
+
     // Prepare a random premaster, to be used on invalid padding. See RFC 5246,
     // section 7.4.7.1.
     if (!premaster_secret.Init(SSL_MAX_MASTER_KEY_LENGTH) ||
@@ -1348,6 +1349,8 @@
     return ssl_hs_error;
   }
   hs->new_session->extended_master_secret = hs->extended_master_secret;
+  CONSTTIME_DECLASSIFY(hs->new_session->master_key,
+                       hs->new_session->master_key_length);
 
   ssl->method->next_message(ssl);
   hs->state = state12_read_client_certificate_verify;
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index bbce7ec..0df9a5f 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -359,8 +359,7 @@
 
 // Protocol versions.
 //
-// Due to DTLS's historical wire version differences and to support multiple
-// variants of the same protocol during development, we maintain two notions of
+// Due to DTLS's historical wire version differences, we maintain two notions of
 // version.
 //
 // The "version" or "wire version" is the actual 16-bit value that appears on
@@ -369,9 +368,8 @@
 // versions are opaque values and may not be compared numerically.
 //
 // The "protocol version" identifies the high-level handshake variant being
-// used. DTLS versions map to the corresponding TLS versions. Draft TLS 1.3
-// variants all map to TLS 1.3. Protocol versions are sequential and may be
-// compared numerically.
+// used. DTLS versions map to the corresponding TLS versions. Protocol versions
+// are sequential and may be compared numerically.
 
 // ssl_protocol_version_from_wire sets |*out| to the protocol version
 // corresponding to wire version |version| and returns true. If |version| is not
@@ -408,10 +406,6 @@
 // call this function before the version is determined.
 uint16_t ssl_protocol_version(const SSL *ssl);
 
-// ssl_is_draft28 returns whether the version corresponds to a draft28 TLS 1.3
-// variant.
-bool ssl_is_draft28(uint16_t version);
-
 // Cipher suites.
 
 BSSL_NAMESPACE_END
@@ -785,8 +779,6 @@
   // omit_length_in_ad_ is true if the length should be omitted in the
   // AEAD's ad parameter.
   bool omit_length_in_ad_ : 1;
-  // omit_ad_ is true if the AEAD's ad parameter should be omitted.
-  bool omit_ad_ : 1;
   // ad_is_header_ is true if the AEAD's ad parameter is the record header.
   bool ad_is_header_ : 1;
 };
@@ -919,8 +911,8 @@
 
 // Private key operations.
 
-// ssl_has_private_key returns whether |cfg| has a private key configured.
-bool ssl_has_private_key(const SSL_CONFIG *cfg);
+// ssl_has_private_key returns whether |hs| has a private key configured.
+bool ssl_has_private_key(const SSL_HANDSHAKE *hs);
 
 // ssl_private_key_* perform the corresponding operation on
 // |SSL_PRIVATE_KEY_METHOD|. If there is a custom private key configured, they
@@ -1173,7 +1165,7 @@
 
 // ssl_has_certificate returns whether a certificate and private key are
 // configured.
-bool ssl_has_certificate(const SSL_CONFIG *cfg);
+bool ssl_has_certificate(const SSL_HANDSHAKE *hs);
 
 // ssl_parse_cert_chain parses a certificate list from |cbs| in the format used
 // by a TLS Certificate message. On success, it advances |cbs| and returns
@@ -1197,11 +1189,15 @@
 // an empty certificate list. It returns true on success and false on error.
 bool ssl_add_cert_chain(SSL_HANDSHAKE *hs, CBB *cbb);
 
-// ssl_cert_check_digital_signature_key_usage parses the DER-encoded, X.509
-// certificate in |in| and returns true if doesn't specify a key usage or, if it
-// does, if it includes digitalSignature. Otherwise it pushes to the error queue
-// and returns false.
-bool ssl_cert_check_digital_signature_key_usage(const CBS *in);
+enum ssl_key_usage_t {
+  key_usage_digital_signature = 0,
+  key_usage_encipherment = 2,
+};
+
+// ssl_cert_check_key_usage parses the DER-encoded, X.509 certificate in |in|
+// and returns true if doesn't specify a key usage or, if it does, if it
+// includes |bit|. Otherwise it pushes to the error queue and returns false.
+bool ssl_cert_check_key_usage(const CBS *in, enum ssl_key_usage_t bit);
 
 // ssl_cert_parse_pubkey extracts the public key from the DER-encoded, X.509
 // certificate in |in|. It returns an allocated |EVP_PKEY| or else returns
@@ -1299,8 +1295,7 @@
 // tls13_derive_session_psk calculates the PSK for this session based on the
 // resumption master secret and |nonce|. It returns true on success, and false
 // on failure.
-bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce,
-                              bool use_quic);
+bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce);
 
 // tls13_write_psk_binder calculates the PSK binder value and replaces the last
 // bytes of |msg| with the resulting value. It returns true on success, and
@@ -1379,6 +1374,46 @@
   handback_after_handshake,
 };
 
+
+// Delegated credentials.
+
+// This structure stores a delegated credential (DC) as defined by
+// draft-ietf-tls-subcerts-03.
+struct DC {
+  static constexpr bool kAllowUniquePtr = true;
+  ~DC();
+
+  // Dup returns a copy of this DC and takes references to |raw| and |pkey|.
+  UniquePtr<DC> Dup();
+
+  // Parse parses the delegated credential stored in |in|. If successful it
+  // returns the parsed structure, otherwise it returns |nullptr| and sets
+  // |*out_alert|.
+  static UniquePtr<DC> Parse(CRYPTO_BUFFER *in, uint8_t *out_alert);
+
+  // raw is the delegated credential encoded as specified in draft-ietf-tls-
+  // subcerts-02.
+  UniquePtr<CRYPTO_BUFFER> raw;
+
+  // expected_cert_verify_algorithm is the signature scheme of the DC public
+  // key.
+  uint16_t expected_cert_verify_algorithm = 0;
+
+  // pkey is the public key parsed from |public_key|.
+  UniquePtr<EVP_PKEY> pkey;
+
+ private:
+  friend DC* New<DC>();
+  DC();
+};
+
+// ssl_signing_with_dc returns true if the peer has indicated support for
+// delegated credentials and this host has sent a delegated credential in
+// response. If this is true then we've committed to using the DC in the
+// handshake.
+bool ssl_signing_with_dc(const SSL_HANDSHAKE *hs);
+
+
 struct SSL_HANDSHAKE {
   explicit SSL_HANDSHAKE(SSL *ssl);
   ~SSL_HANDSHAKE();
@@ -1550,6 +1585,10 @@
   // ocsp_stapling_requested is true if a client requested OCSP stapling.
   bool ocsp_stapling_requested : 1;
 
+  // delegated_credential_requested is true if the peer indicated support for
+  // the delegated credential extension.
+  bool delegated_credential_requested : 1;
+
   // should_ack_sni is used by a server and indicates that the SNI extension
   // should be echoed in the ServerHello.
   bool should_ack_sni : 1;
@@ -1614,8 +1653,7 @@
   // record layer.
   uint16_t early_data_written = 0;
 
-  // session_id is the session ID in the ClientHello, used for the experimental
-  // TLS 1.3 variant.
+  // session_id is the session ID in the ClientHello.
   uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH] = {0};
   uint8_t session_id_len = 0;
 
@@ -1649,6 +1687,11 @@
 const char *tls13_client_handshake_state(SSL_HANDSHAKE *hs);
 const char *tls13_server_handshake_state(SSL_HANDSHAKE *hs);
 
+// tls13_add_key_update queues a KeyUpdate message on |ssl|. The
+// |update_requested| argument must be one of |SSL_KEY_UPDATE_REQUESTED| or
+// |SSL_KEY_UPDATE_NOT_REQUESTED|.
+bool tls13_add_key_update(SSL *ssl, int update_requested);
+
 // tls13_post_handshake processes a post-handshake message. It returns true on
 // success and false on failure.
 bool tls13_post_handshake(SSL *ssl, const SSLMessage &msg);
@@ -1791,6 +1834,15 @@
 // supported. It returns true on success and false on error.
 bool tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out);
 
+// tls1_get_peer_verify_algorithms returns the signature schemes for which the
+// peer indicated support.
+//
+// NOTE: The related function |SSL_get0_peer_verify_algorithms| only has
+// well-defined behavior during the callbacks set by |SSL_CTX_set_cert_cb| and
+// |SSL_CTX_set_client_cert_cb|, or when the handshake is paused because of
+// them.
+Span<const uint16_t> tls1_get_peer_verify_algorithms(const SSL_HANDSHAKE *hs);
+
 // tls12_add_verify_sigalgs adds the signature algorithms acceptable for the
 // peer signature to |out|. It returns true on success and false on error. If
 // |for_certs| is true, the potentially more restrictive list of algorithms for
@@ -1884,6 +1936,19 @@
   // ticket key. Only sessions with a matching value will be accepted.
   uint8_t sid_ctx_length = 0;
   uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH] = {0};
+
+  // Delegated credentials.
+
+  // dc is the delegated credential to send to the peer (if requested).
+  UniquePtr<DC> dc = nullptr;
+
+  // dc_privatekey is used instead of |privatekey| or |key_method| to
+  // authenticate the host if a delegated credential is used in the handshake.
+  UniquePtr<EVP_PKEY> dc_privatekey = nullptr;
+
+  // dc_key_method, if not NULL, is used instead of |dc_privatekey| to
+  // authenticate the host.
+  const SSL_PRIVATE_KEY_METHOD *dc_key_method = nullptr;
 };
 
 // |SSL_PROTOCOL_METHOD| abstracts between TLS and DTLS.
@@ -2049,7 +2114,7 @@
 
 DEFINE_LHASH_OF(SSL_SESSION)
 
-DEFINE_NAMED_STACK_OF(CertCompressionAlg, bssl::CertCompressionAlg);
+DEFINE_NAMED_STACK_OF(CertCompressionAlg, bssl::CertCompressionAlg)
 
 BSSL_NAMESPACE_BEGIN
 
@@ -2479,6 +2544,11 @@
   // advertise support.
   bool channel_id_enabled : 1;
 
+  // If enforce_rsa_key_usage is true, the handshake will fail if the
+  // keyUsage extension is present and incompatible with the TLS usage.
+  // This field is not read until after certificate verification.
+  bool enforce_rsa_key_usage : 1;
+
   // retain_only_sha256_of_client_certs is true if we should compute the SHA256
   // hash of the peer's certificate and then discard it to save memory and
   // session space. Only effective on the server side.
@@ -2506,10 +2576,6 @@
 // From RFC 8446, used in determining PSK modes.
 #define SSL_PSK_DHE_KE 0x1
 
-// From RFC 8446, used in determining whether to respond with a KeyUpdate.
-#define SSL_KEY_UPDATE_NOT_REQUESTED 0
-#define SSL_KEY_UPDATE_REQUESTED 1
-
 // kMaxEarlyDataAccepted is the advertised number of plaintext bytes of early
 // data that will be accepted. This value should be slightly below
 // kMaxEarlyDataSkipped in tls_record.c, which is measured in ciphertext.
@@ -2834,10 +2900,6 @@
   // quic_method is the method table corresponding to the QUIC hooks.
   const SSL_QUIC_METHOD *quic_method = nullptr;
 
-  // tls13_variant is the variant of TLS 1.3 we are using for this
-  // configuration.
-  tls13_variant_t tls13_variant = tls13_rfc;
-
   bssl::UniquePtr<bssl::SSLCipherPreferenceList> cipher_list;
 
   X509_STORE *cert_store = nullptr;
@@ -3163,10 +3225,6 @@
   // second.
   unsigned initial_timeout_duration_ms = 1000;
 
-  // tls13_variant is the variant of TLS 1.3 we are using for this
-  // configuration.
-  tls13_variant_t tls13_variant = tls13_rfc;
-
   // session is the configured session to be offered by the client. This session
   // is immutable.
   bssl::UniquePtr<SSL_SESSION> session;
@@ -3187,6 +3245,9 @@
   uint32_t max_cert_list = 0;
   bssl::UniquePtr<char> hostname;
 
+  // quic_method is the method table corresponding to the QUIC hooks.
+  const SSL_QUIC_METHOD *quic_method = nullptr;
+
   // renegotiate_mode controls how peer renegotiation attempts are handled.
   ssl_renegotiate_mode_t renegotiate_mode = ssl_renegotiate_never;
 
diff --git a/src/ssl/s3_both.cc b/src/ssl/s3_both.cc
index f835dc2..aec6cae 100644
--- a/src/ssl/s3_both.cc
+++ b/src/ssl/s3_both.cc
@@ -188,14 +188,12 @@
   // unnecessary encryption overhead, notably in TLS 1.3 where we send several
   // encrypted messages in a row. For now, we do not do this for the null
   // cipher. The benefit is smaller and there is a risk of breaking buggy
-  // implementations. Additionally, we tie this to draft-28 as a sanity check,
-  // on the off chance middleboxes have fixated on sizes.
+  // implementations.
   //
   // TODO(davidben): See if we can do this uniformly.
   Span<const uint8_t> rest = msg;
-  if (ssl->ctx->quic_method == nullptr &&
-      (ssl->s3->aead_write_ctx->is_null_cipher() ||
-       ssl->version == TLS1_3_DRAFT23_VERSION)) {
+  if (ssl->quic_method == nullptr &&
+      ssl->s3->aead_write_ctx->is_null_cipher()) {
     while (!rest.empty()) {
       Span<const uint8_t> chunk = rest.subspan(0, ssl->max_send_fragment);
       rest = rest.subspan(chunk.size());
@@ -250,9 +248,9 @@
   auto data =
       MakeConstSpan(reinterpret_cast<const uint8_t *>(pending_hs_data->data),
                     pending_hs_data->length);
-  if (ssl->ctx->quic_method) {
-    if (!ssl->ctx->quic_method->add_handshake_data(ssl, ssl->s3->write_level,
-                                                   data.data(), data.size())) {
+  if (ssl->quic_method) {
+    if (!ssl->quic_method->add_handshake_data(ssl, ssl->s3->write_level,
+                                              data.data(), data.size())) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
       return false;
     }
@@ -269,7 +267,7 @@
     return false;
   }
 
-  if (!ssl->ctx->quic_method &&
+  if (!ssl->quic_method &&
       !add_record_to_flight(ssl, SSL3_RT_CHANGE_CIPHER_SPEC,
                             kChangeCipherSpec)) {
     return false;
@@ -285,13 +283,13 @@
     return -1;
   }
 
-  if (ssl->ctx->quic_method) {
+  if (ssl->quic_method) {
     if (ssl->s3->write_shutdown != ssl_shutdown_none) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
       return -1;
     }
 
-    if (!ssl->ctx->quic_method->flush_flight(ssl)) {
+    if (!ssl->quic_method->flush_flight(ssl)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
       return -1;
     }
diff --git a/src/ssl/s3_pkt.cc b/src/ssl/s3_pkt.cc
index f0ae8a2..abc6798 100644
--- a/src/ssl/s3_pkt.cc
+++ b/src/ssl/s3_pkt.cc
@@ -232,25 +232,29 @@
     return -1;
   }
 
-  if (len == 0) {
-    return 0;
-  }
-
   if (!tls_flush_pending_hs_data(ssl)) {
     return -1;
   }
+
   size_t flight_len = 0;
   if (ssl->s3->pending_flight != nullptr) {
     flight_len =
         ssl->s3->pending_flight->length - ssl->s3->pending_flight_offset;
   }
 
-  size_t max_out = len + SSL_max_seal_overhead(ssl);
-  if (max_out < len || max_out + flight_len < max_out) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
-    return -1;
+  size_t max_out = flight_len;
+  if (len > 0) {
+    const size_t max_ciphertext_len = len + SSL_max_seal_overhead(ssl);
+    if (max_ciphertext_len < len || max_out + max_ciphertext_len < max_out) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+      return -1;
+    }
+    max_out += max_ciphertext_len;
   }
-  max_out += flight_len;
+
+  if (max_out == 0) {
+    return 0;
+  }
 
   if (!buf->EnsureCap(flight_len + ssl_seal_align_prefix_len(ssl), max_out)) {
     return -1;
@@ -270,12 +274,14 @@
     buf->DidWrite(flight_len);
   }
 
-  size_t ciphertext_len;
-  if (!tls_seal_record(ssl, buf->remaining().data(), &ciphertext_len,
-                       buf->remaining().size(), type, in, len)) {
-    return -1;
+  if (len > 0) {
+    size_t ciphertext_len;
+    if (!tls_seal_record(ssl, buf->remaining().data(), &ciphertext_len,
+                         buf->remaining().size(), type, in, len)) {
+      return -1;
+    }
+    buf->DidWrite(ciphertext_len);
   }
-  buf->DidWrite(ciphertext_len);
 
   // Now that we've made progress on the connection, uncork KeyUpdate
   // acknowledgments.
@@ -404,9 +410,9 @@
 }
 
 int ssl3_dispatch_alert(SSL *ssl) {
-  if (ssl->ctx->quic_method) {
-    if (!ssl->ctx->quic_method->send_alert(ssl, ssl->s3->write_level,
-                                           ssl->s3->send_alert[1])) {
+  if (ssl->quic_method) {
+    if (!ssl->quic_method->send_alert(ssl, ssl->s3->write_level,
+                                      ssl->s3->send_alert[1])) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
       return 0;
     }
diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc
index f01b57d..0bad266 100644
--- a/src/ssl/ssl_aead_ctx.cc
+++ b/src/ssl/ssl_aead_ctx.cc
@@ -42,7 +42,6 @@
       random_variable_nonce_(false),
       xor_fixed_nonce_(false),
       omit_length_in_ad_(false),
-      omit_ad_(false),
       ad_is_header_(false) {
   OPENSSL_memset(fixed_nonce_, 0, sizeof(fixed_nonce_));
 }
@@ -134,11 +133,7 @@
       aead_ctx->xor_fixed_nonce_ = true;
       aead_ctx->variable_nonce_len_ = 8;
       aead_ctx->variable_nonce_included_in_record_ = false;
-      if (ssl_is_draft28(version)) {
-        aead_ctx->ad_is_header_ = true;
-      } else {
-        aead_ctx->omit_ad_ = true;
-      }
+      aead_ctx->ad_is_header_ = true;
       assert(fixed_iv.size() >= aead_ctx->variable_nonce_len_);
     }
   } else {
@@ -231,10 +226,6 @@
     return header;
   }
 
-  if (omit_ad_) {
-    return {};
-  }
-
   OPENSSL_memcpy(storage, seqnum, 8);
   size_t len = 8;
   storage[len++] = type;
diff --git a/src/ssl/ssl_cert.cc b/src/ssl/ssl_cert.cc
index 37d6501..1b01e7f 100644
--- a/src/ssl/ssl_cert.cc
+++ b/src/ssl/ssl_cert.cc
@@ -180,6 +180,16 @@
   ret->sid_ctx_length = cert->sid_ctx_length;
   OPENSSL_memcpy(ret->sid_ctx, cert->sid_ctx, sizeof(ret->sid_ctx));
 
+  if (cert->dc) {
+    ret->dc = cert->dc->Dup();
+    if (!ret->dc) {
+       return nullptr;
+    }
+  }
+
+  ret->dc_privatekey = UpRef(cert->dc_privatekey);
+  ret->dc_key_method = cert->dc_key_method;
+
   return ret;
 }
 
@@ -194,6 +204,10 @@
   cert->chain.reset();
   cert->privatekey.reset();
   cert->key_method = nullptr;
+
+  cert->dc.reset();
+  cert->dc_privatekey.reset();
+  cert->dc_key_method = nullptr;
 }
 
 static void ssl_cert_set_cert_cb(CERT *cert, int (*cb)(SSL *ssl, void *arg),
@@ -232,7 +246,7 @@
   // An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA
   // certificates, so sanity-check the key usage extension.
   if (pubkey->type == EVP_PKEY_EC &&
-      !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) {
+      !ssl_cert_check_key_usage(&cert_cbs, key_usage_digital_signature)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
     return leaf_cert_and_privkey_error;
   }
@@ -324,10 +338,10 @@
   return true;
 }
 
-bool ssl_has_certificate(const SSL_CONFIG *cfg) {
-  return cfg->cert->chain != nullptr &&
-         sk_CRYPTO_BUFFER_value(cfg->cert->chain.get(), 0) != nullptr &&
-         ssl_has_private_key(cfg);
+bool ssl_has_certificate(const SSL_HANDSHAKE *hs) {
+  return hs->config->cert->chain != nullptr &&
+         sk_CRYPTO_BUFFER_value(hs->config->cert->chain.get(), 0) != nullptr &&
+         ssl_has_private_key(hs);
 }
 
 bool ssl_parse_cert_chain(uint8_t *out_alert,
@@ -395,7 +409,7 @@
 }
 
 bool ssl_add_cert_chain(SSL_HANDSHAKE *hs, CBB *cbb) {
-  if (!ssl_has_certificate(hs->config)) {
+  if (!ssl_has_certificate(hs)) {
     return CBB_add_u24(cbb, 0);
   }
 
@@ -526,7 +540,7 @@
   return ssl_compare_public_and_private_key(pubkey.get(), privkey);
 }
 
-bool ssl_cert_check_digital_signature_key_usage(const CBS *in) {
+bool ssl_cert_check_key_usage(const CBS *in, enum ssl_key_usage_t bit) {
   CBS buf = *in;
 
   CBS tbs_cert, outer_extensions;
@@ -592,8 +606,8 @@
       return false;
     }
 
-    if (!CBS_asn1_bitstring_has_bit(&bit_string, 0)) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+    if (!CBS_asn1_bitstring_has_bit(&bit_string, bit)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_KEY_USAGE_BIT_INCORRECT);
       return false;
     }
 
@@ -696,20 +710,6 @@
     return false;
   }
 
-  // Check key usages for all key types but RSA. This is needed to distinguish
-  // ECDH certificates, which we do not support, from ECDSA certificates. In
-  // principle, we should check RSA key usages based on cipher, but this breaks
-  // buggy antivirus deployments. Other key types are always used for signing.
-  //
-  // TODO(davidben): Get more recent data on RSA key usages.
-  if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
-    CBS leaf_cbs;
-    CBS_init(&leaf_cbs, CRYPTO_BUFFER_data(leaf), CRYPTO_BUFFER_len(leaf));
-    if (!ssl_cert_check_digital_signature_key_usage(&leaf_cbs)) {
-      return false;
-    }
-  }
-
   if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) {
     // Check the key's group and point format are acceptable.
     EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
@@ -728,7 +728,7 @@
 
 bool ssl_on_certificate_selected(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_has_certificate(hs->config)) {
+  if (!ssl_has_certificate(hs)) {
     // Nothing to do.
     return true;
   }
@@ -741,10 +741,143 @@
   CRYPTO_BUFFER_init_CBS(
       sk_CRYPTO_BUFFER_value(hs->config->cert->chain.get(), 0), &leaf);
 
-  hs->local_pubkey = ssl_cert_parse_pubkey(&leaf);
+  if (ssl_signing_with_dc(hs)) {
+    hs->local_pubkey = UpRef(hs->config->cert->dc->pkey);
+  } else {
+    hs->local_pubkey = ssl_cert_parse_pubkey(&leaf);
+  }
   return hs->local_pubkey != NULL;
 }
 
+
+// Delegated credentials.
+
+DC::DC() = default;
+DC::~DC() = default;
+
+UniquePtr<DC> DC::Dup() {
+  bssl::UniquePtr<DC> ret = MakeUnique<DC>();
+  if (!ret) {
+    return nullptr;
+  }
+
+  ret->raw = UpRef(raw);
+  ret->expected_cert_verify_algorithm = expected_cert_verify_algorithm;
+  ret->pkey = UpRef(pkey);
+  return ret;
+}
+
+// static
+UniquePtr<DC> DC::Parse(CRYPTO_BUFFER *in, uint8_t *out_alert) {
+  UniquePtr<DC> dc = MakeUnique<DC>();
+  if (!dc) {
+    *out_alert = SSL_AD_INTERNAL_ERROR;
+    return nullptr;
+  }
+
+  dc->raw = UpRef(in);
+
+  CBS pubkey, deleg, sig;
+  uint32_t valid_time;
+  uint16_t algorithm;
+  CRYPTO_BUFFER_init_CBS(dc->raw.get(), &deleg);
+  if (!CBS_get_u32(&deleg, &valid_time) ||
+      !CBS_get_u16(&deleg, &dc->expected_cert_verify_algorithm) ||
+      !CBS_get_u24_length_prefixed(&deleg, &pubkey) ||
+      !CBS_get_u16(&deleg, &algorithm) ||
+      !CBS_get_u16_length_prefixed(&deleg, &sig) ||
+      CBS_len(&deleg) != 0) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    *out_alert = SSL_AD_DECODE_ERROR;
+    return nullptr;
+  }
+
+  dc->pkey.reset(EVP_parse_public_key(&pubkey));
+  if (dc->pkey == nullptr) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    *out_alert = SSL_AD_DECODE_ERROR;
+    return nullptr;
+  }
+
+  return dc;
+}
+
+// ssl_can_serve_dc returns true if the host has configured a DC that it can
+// serve in the handshake. Specifically, it checks that a DC has been
+// configured, that the DC protocol version is the same as the negotiated
+// protocol version, and that the DC signature algorithm is supported by the
+// peer.
+static bool ssl_can_serve_dc(const SSL_HANDSHAKE *hs) {
+  // Check that a DC has been configured.
+  const CERT *cert = hs->config->cert.get();
+  if (cert->dc == nullptr ||
+      cert->dc->raw == nullptr ||
+      (cert->dc_privatekey == nullptr && cert->dc_key_method == nullptr)) {
+    return false;
+  }
+
+  // Check that 1.3 or higher has been negotiated.
+  const DC *dc = cert->dc.get();
+  assert(hs->ssl->s3->have_version);
+  if (ssl_protocol_version(hs->ssl) < TLS1_3_VERSION) {
+    return false;
+  }
+
+  // Check that the DC signature algorithm is supported by the peer.
+  Span<const uint16_t> peer_sigalgs = tls1_get_peer_verify_algorithms(hs);
+  bool sigalg_found = false;
+  for (uint16_t peer_sigalg : peer_sigalgs) {
+    if (dc->expected_cert_verify_algorithm == peer_sigalg) {
+      sigalg_found = true;
+      break;
+    }
+  }
+
+  return sigalg_found;
+}
+
+bool ssl_signing_with_dc(const SSL_HANDSHAKE *hs) {
+  // As of draft-ietf-tls-subcert-03, only the server may use delegated
+  // credentials to authenticate itself.
+  return hs->ssl->server &&
+         hs->delegated_credential_requested &&
+         ssl_can_serve_dc(hs);
+}
+
+static int cert_set_dc(CERT *cert, CRYPTO_BUFFER *const raw, EVP_PKEY *privkey,
+                       const SSL_PRIVATE_KEY_METHOD *key_method) {
+  if (privkey == nullptr && key_method == nullptr) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+    return 0;
+  }
+
+  if (privkey != nullptr && key_method != nullptr) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD);
+    return 0;
+  }
+
+  uint8_t alert;
+  UniquePtr<DC> dc = DC::Parse(raw, &alert);
+  if (dc == nullptr) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_DELEGATED_CREDENTIAL);
+    return 0;
+  }
+
+  if (privkey) {
+    // Check that the public and private keys match.
+    if (!ssl_compare_public_and_private_key(dc->pkey.get(), privkey)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_AND_PRIVATE_KEY_MISMATCH);
+      return 0;
+    }
+  }
+
+  cert->dc = std::move(dc);
+  cert->dc_privatekey = UpRef(privkey);
+  cert->dc_key_method = key_method;
+
+  return 1;
+}
+
 BSSL_NAMESPACE_END
 
 using namespace bssl;
@@ -870,3 +1003,12 @@
   ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl->config.get());
   ssl->config->client_CA.reset(name_list);
 }
+
+int SSL_set1_delegated_credential(SSL *ssl, CRYPTO_BUFFER *dc, EVP_PKEY *pkey,
+                                  const SSL_PRIVATE_KEY_METHOD *key_method) {
+  if (!ssl->config) {
+    return 0;
+  }
+
+  return cert_set_dc(ssl->config->cert.get(), dc, pkey, key_method);
+}
diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc
index 108ea6a..78d2aa1 100644
--- a/src/ssl/ssl_key_share.cc
+++ b/src/ssl/ssl_key_share.cc
@@ -220,11 +220,12 @@
     X25519_keypair(x25519_public_key, x25519_private_key_);
 
     uint8_t hrss_entropy[HRSS_GENERATE_KEY_BYTES];
+    HRSS_public_key hrss_public_key;
     RAND_bytes(hrss_entropy, sizeof(hrss_entropy));
-    HRSS_generate_key(&hrss_public_key_, &hrss_private_key_, hrss_entropy);
+    HRSS_generate_key(&hrss_public_key, &hrss_private_key_, hrss_entropy);
 
     uint8_t hrss_public_key_bytes[HRSS_PUBLIC_KEY_BYTES];
-    HRSS_marshal_public_key(hrss_public_key_bytes, &hrss_public_key_);
+    HRSS_marshal_public_key(hrss_public_key_bytes, &hrss_public_key);
 
     if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
         !CBB_add_bytes(out, hrss_public_key_bytes,
@@ -233,7 +234,7 @@
     }
 
     return true;
-  };
+  }
 
   bool Accept(CBB *out_public_key, Array<uint8_t> *out_secret,
               uint8_t *out_alert, Span<const uint8_t> peer_key) override {
@@ -287,16 +288,15 @@
       return false;
     }
 
-    HRSS_decap(secret.data() + 32, &hrss_public_key_, &hrss_private_key_,
-               peer_key.data() + 32, peer_key.size() - 32);
+    HRSS_decap(secret.data() + 32, &hrss_private_key_, peer_key.data() + 32,
+               peer_key.size() - 32);
 
     *out_secret = std::move(secret);
     return true;
-  };
+  }
 
  private:
   uint8_t x25519_private_key_[32];
-  HRSS_public_key hrss_public_key_;
   HRSS_private_key hrss_private_key_;
 };
 
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index ceeba89..a4f2044 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -640,7 +640,6 @@
       max_send_fragment(ctx_arg->max_send_fragment),
       msg_callback(ctx_arg->msg_callback),
       msg_callback_arg(ctx_arg->msg_callback_arg),
-      tls13_variant(ctx_arg->tls13_variant),
       ctx(UpRef(ctx_arg)),
       session_ctx(UpRef(ctx_arg)),
       options(ctx->options),
@@ -715,6 +714,7 @@
   ssl->config->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled;
   ssl->config->handoff = ctx->handoff;
   ssl->config->ignore_tls13_downgrade = ctx->ignore_tls13_downgrade;
+  ssl->quic_method = ctx->quic_method;
 
   if (!ssl->method->ssl_new(ssl.get()) ||
       !ssl->ctx->x509_method->ssl_new(ssl->s3->hs.get())) {
@@ -729,6 +729,7 @@
       signed_cert_timestamps_enabled(false),
       ocsp_stapling_enabled(false),
       channel_id_enabled(false),
+      enforce_rsa_key_usage(false),
       retain_only_sha256_of_client_certs(false),
       handoff(false),
       shed_handshake_config(false),
@@ -851,7 +852,7 @@
 
 int SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level,
                           const uint8_t *data, size_t len) {
-  if (ssl->ctx->quic_method == nullptr) {
+  if (ssl->quic_method == nullptr) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
@@ -1078,7 +1079,7 @@
 }
 
 int SSL_peek(SSL *ssl, void *buf, int num) {
-  if (ssl->ctx->quic_method != nullptr) {
+  if (ssl->quic_method != nullptr) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
@@ -1099,7 +1100,7 @@
 int SSL_write(SSL *ssl, const void *buf, int num) {
   ssl_reset_error_state(ssl);
 
-  if (ssl->ctx->quic_method != nullptr) {
+  if (ssl->quic_method != nullptr) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
@@ -1135,6 +1136,37 @@
   return ret;
 }
 
+int SSL_key_update(SSL *ssl, int request_type) {
+  ssl_reset_error_state(ssl);
+
+  if (ssl->do_handshake == NULL) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+    return 0;
+  }
+
+  if (ssl->ctx->quic_method != nullptr) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    return 0;
+  }
+
+  if (!ssl->s3->initial_handshake_complete) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_NOT_COMPLETE);
+    return 0;
+  }
+
+  if (ssl_protocol_version(ssl) < TLS1_3_VERSION) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
+    return 0;
+  }
+
+  if (!ssl->s3->key_update_pending &&
+      !tls13_add_key_update(ssl, request_type)) {
+    return 0;
+  }
+
+  return 1;
+}
+
 int SSL_shutdown(SSL *ssl) {
   ssl_reset_error_state(ssl);
 
@@ -1230,14 +1262,6 @@
   ctx->enable_early_data = !!enabled;
 }
 
-void SSL_CTX_set_tls13_variant(SSL_CTX *ctx, enum tls13_variant_t variant) {
-  ctx->tls13_variant = variant;
-}
-
-void SSL_set_tls13_variant(SSL *ssl, enum tls13_variant_t variant) {
-  ssl->tls13_variant = variant;
-}
-
 void SSL_set_early_data_enabled(SSL *ssl, int enabled) {
   ssl->enable_early_data = !!enabled;
 }
@@ -1320,7 +1344,7 @@
       return SSL_ERROR_HANDBACK;
 
     case SSL_READING: {
-      if (ssl->ctx->quic_method) {
+      if (ssl->quic_method) {
         return SSL_ERROR_WANT_READ;
       }
       BIO *bio = SSL_get_rbio(ssl);
@@ -2437,6 +2461,14 @@
   return 1;
 }
 
+int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) {
+  if (ssl->method->is_dtls) {
+    return 0;
+  }
+  ssl->quic_method = quic_method;
+  return 1;
+}
+
 int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
                          CRYPTO_EX_dup *dup_unused, CRYPTO_EX_free *free_func) {
   int index;
@@ -2666,6 +2698,13 @@
   ctx->reverify_on_resume = !!enabled;
 }
 
+void SSL_set_enforce_rsa_key_usage(SSL *ssl, int enabled) {
+  if (!ssl->config) {
+    return;
+  }
+  ssl->config->enforce_rsa_key_usage = !!enabled;
+}
+
 void SSL_set_renegotiate_mode(SSL *ssl, enum ssl_renegotiate_mode_t mode) {
   ssl->renegotiate_mode = mode;
 
diff --git a/src/ssl/ssl_privkey.cc b/src/ssl/ssl_privkey.cc
index e716c9a..1ddb1b1 100644
--- a/src/ssl/ssl_privkey.cc
+++ b/src/ssl/ssl_privkey.cc
@@ -133,8 +133,14 @@
   return NULL;
 }
 
-bool ssl_has_private_key(const SSL_CONFIG *cfg) {
-  return cfg->cert->privatekey != nullptr || cfg->cert->key_method != nullptr;
+bool ssl_has_private_key(const SSL_HANDSHAKE *hs) {
+  if (hs->config->cert->privatekey != nullptr ||
+      hs->config->cert->key_method != nullptr ||
+      ssl_signing_with_dc(hs)) {
+    return true;
+  }
+
+  return false;
 }
 
 static bool pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey,
@@ -195,13 +201,20 @@
     SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out,
     uint16_t sigalg, Span<const uint8_t> in) {
   SSL *const ssl = hs->ssl;
-  if (hs->config->cert->key_method != NULL) {
+  const SSL_PRIVATE_KEY_METHOD *key_method = hs->config->cert->key_method;
+  EVP_PKEY *privatekey = hs->config->cert->privatekey.get();
+  if (ssl_signing_with_dc(hs)) {
+    key_method = hs->config->cert->dc_key_method;
+    privatekey = hs->config->cert->dc_privatekey.get();
+  }
+
+  if (key_method != NULL) {
     enum ssl_private_key_result_t ret;
     if (hs->pending_private_key_op) {
-      ret = hs->config->cert->key_method->complete(ssl, out, out_len, max_out);
+      ret = key_method->complete(ssl, out, out_len, max_out);
     } else {
-      ret = hs->config->cert->key_method->sign(ssl, out, out_len, max_out,
-                                               sigalg, in.data(), in.size());
+      ret = key_method->sign(ssl, out, out_len, max_out,
+                             sigalg, in.data(), in.size());
     }
     if (ret == ssl_private_key_failure) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_PRIVATE_KEY_OPERATION_FAILED);
@@ -212,8 +225,7 @@
 
   *out_len = max_out;
   ScopedEVP_MD_CTX ctx;
-  if (!setup_ctx(ssl, ctx.get(), hs->config->cert->privatekey.get(), sigalg,
-                 false /* sign */) ||
+  if (!setup_ctx(ssl, ctx.get(), privatekey, sigalg, false /* sign */) ||
       !EVP_DigestSign(ctx.get(), out, out_len, in.data(), in.size())) {
     return ssl_private_key_failure;
   }
@@ -552,6 +564,10 @@
 }
 
 static bool sigalgs_unique(Span<const uint16_t> in_sigalgs) {
+  if (in_sigalgs.size() < 2) {
+    return true;
+  }
+
   Array<uint16_t> sigalgs;
   if (!sigalgs.CopyFrom(in_sigalgs)) {
     return false;
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 8d01c03..f3f7923 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -2628,11 +2628,6 @@
   // SSL 3.0 is not available.
   EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), SSL3_VERSION));
 
-  // TLS1_3_DRAFT_VERSION is not an API-level version.
-  EXPECT_FALSE(
-      SSL_CTX_set_max_proto_version(ctx.get(), TLS1_3_DRAFT23_VERSION));
-  ERR_clear_error();
-
   ctx.reset(SSL_CTX_new(DTLS_method()));
   ASSERT_TRUE(ctx);
 
@@ -4358,6 +4353,35 @@
   EXPECT_EQ(1u, server->config->supported_group_list.size());
 }
 
+TEST(SSLTest, ZeroSizedWiteFlushesHandshakeMessages) {
+  // If there are pending handshake mesages, an |SSL_write| of zero bytes should
+  // flush them.
+  bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+  EXPECT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
+  EXPECT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), TLS1_3_VERSION));
+  bssl::UniquePtr<X509> cert = GetTestCertificate();
+  bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+  ASSERT_TRUE(cert);
+  ASSERT_TRUE(key);
+  ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
+  ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+
+  bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+  EXPECT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
+  EXPECT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), TLS1_3_VERSION));
+
+  bssl::UniquePtr<SSL> client, server;
+  ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
+                                     server_ctx.get()));
+
+  BIO *client_wbio = SSL_get_wbio(client.get());
+  EXPECT_EQ(0u, BIO_wpending(client_wbio));
+  EXPECT_TRUE(SSL_key_update(client.get(), SSL_KEY_UPDATE_NOT_REQUESTED));
+  EXPECT_EQ(0u, BIO_wpending(client_wbio));
+  EXPECT_EQ(0, SSL_write(client.get(), nullptr, 0));
+  EXPECT_NE(0u, BIO_wpending(client_wbio));
+}
+
 TEST_P(SSLVersionTest, VerifyBeforeCertRequest) {
   // Configure the server to request client certificates.
   SSL_CTX_set_custom_verify(
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index 8616967..e6dbc8d 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -34,11 +34,6 @@
       *out = version;
       return true;
 
-    case TLS1_3_DRAFT23_VERSION:
-    case TLS1_3_DRAFT28_VERSION:
-      *out = TLS1_3_VERSION;
-      return true;
-
     case DTLS1_VERSION:
       // DTLS 1.0 is analogous to TLS 1.1, not TLS 1.0.
       *out = TLS1_1_VERSION;
@@ -58,8 +53,6 @@
 
 static const uint16_t kTLSVersions[] = {
     TLS1_3_VERSION,
-    TLS1_3_DRAFT28_VERSION,
-    TLS1_3_DRAFT23_VERSION,
     TLS1_2_VERSION,
     TLS1_1_VERSION,
     TLS1_VERSION,
@@ -95,14 +88,10 @@
 }
 
 // The following functions map between API versions and wire versions. The
-// public API works on wire versions, except that TLS 1.3 draft versions all
-// appear as TLS 1.3. This will get collapsed back down when TLS 1.3 is
-// finalized.
+// public API works on wire versions.
 
 static const char *ssl_version_to_string(uint16_t version) {
   switch (version) {
-    case TLS1_3_DRAFT23_VERSION:
-    case TLS1_3_DRAFT28_VERSION:
     case TLS1_3_VERSION:
       return "TLSv1.3";
 
@@ -127,26 +116,11 @@
 }
 
 static uint16_t wire_version_to_api(uint16_t version) {
-  switch (version) {
-    // Report TLS 1.3 draft versions as TLS 1.3 in the public API.
-    case TLS1_3_DRAFT23_VERSION:
-    case TLS1_3_DRAFT28_VERSION:
-    case TLS1_3_VERSION:
-      return TLS1_3_VERSION;
-    default:
-      return version;
-  }
+  return version;
 }
 
-// api_version_to_wire maps |version| to some representative wire version. In
-// particular, it picks an arbitrary TLS 1.3 representative. This should only be
-// used in context where that does not matter.
+// api_version_to_wire maps |version| to some representative wire version.
 static bool api_version_to_wire(uint16_t *out, uint16_t version) {
-  if (version == TLS1_3_DRAFT23_VERSION ||
-      version == TLS1_3_DRAFT28_VERSION) {
-    return false;
-  }
-
   // Check it is a real protocol version.
   uint16_t unused;
   if (!ssl_protocol_version_from_wire(&unused, version)) {
@@ -218,7 +192,7 @@
   uint16_t max_version = hs->config->conf_max_version;
 
   // QUIC requires TLS 1.3.
-  if (hs->ssl->ctx->quic_method && min_version < TLS1_3_VERSION) {
+  if (hs->ssl->quic_method && min_version < TLS1_3_VERSION) {
     min_version = TLS1_3_VERSION;
   }
 
@@ -299,21 +273,6 @@
     return false;
   }
 
-  // If the TLS 1.3 variant is set to |tls13_default|, all variants are enabled,
-  // otherwise only the matching version is enabled.
-  if (protocol_version == TLS1_3_VERSION) {
-    switch (ssl->tls13_variant) {
-      case tls13_draft23:
-        return version == TLS1_3_DRAFT23_VERSION;
-      case tls13_draft28:
-        return version == TLS1_3_DRAFT28_VERSION;
-      case tls13_rfc:
-        return version == TLS1_3_VERSION;
-      case tls13_all:
-        return true;
-    }
-  }
-
   return true;
 }
 
@@ -373,10 +332,6 @@
   return false;
 }
 
-bool ssl_is_draft28(uint16_t version) {
-  return version == TLS1_3_DRAFT28_VERSION || version == TLS1_3_VERSION;
-}
-
 BSSL_NAMESPACE_END
 
 using namespace bssl;
diff --git a/src/ssl/ssl_x509.cc b/src/ssl/ssl_x509.cc
index eb3a38b..841482f 100644
--- a/src/ssl/ssl_x509.cc
+++ b/src/ssl/ssl_x509.cc
@@ -448,7 +448,7 @@
   // Only build a chain if there are no intermediates configured and the feature
   // isn't disabled.
   if ((hs->ssl->mode & SSL_MODE_NO_AUTO_CHAIN) ||
-      !ssl_has_certificate(hs->config) || hs->config->cert->chain == NULL ||
+      !ssl_has_certificate(hs) || hs->config->cert->chain == NULL ||
       sk_CRYPTO_BUFFER_num(hs->config->cert->chain.get()) > 1) {
     return 1;
   }
@@ -1223,7 +1223,8 @@
     assert(ssl->config);
     return -1;
   }
-  if (ssl_has_certificate(ssl->config.get()) ||
+
+  if (ssl_has_certificate(ssl->s3->hs.get()) ||
       ssl->ctx->client_cert_cb == NULL) {
     return 1;
   }
diff --git a/src/ssl/t1_lib.cc b/src/ssl/t1_lib.cc
index 5e65f81..3a08fe6 100644
--- a/src/ssl/t1_lib.cc
+++ b/src/ssl/t1_lib.cc
@@ -292,23 +292,10 @@
     SSL_CURVE_SECP384R1,
 };
 
-// TLS 1.3 servers will pick CECPQ2 if offered by a client, but it's not enabled
-// by default for clients.
-static const uint16_t kDefaultGroupsServer[] = {
-    // CECPQ2 is not yet enabled by default.
-    // SSL_CURVE_CECPQ2,
-    SSL_CURVE_X25519,
-    SSL_CURVE_SECP256R1,
-    SSL_CURVE_SECP384R1,
-};;
-
 Span<const uint16_t> tls1_get_grouplist(const SSL_HANDSHAKE *hs) {
   if (!hs->config->supported_group_list.empty()) {
     return hs->config->supported_group_list;
   }
-  if (hs->ssl->server) {
-    return Span<const uint16_t>(kDefaultGroupsServer);
-  }
   return Span<const uint16_t>(kDefaultGroups);
 }
 
@@ -2715,6 +2702,36 @@
   return true;
 }
 
+// Delegated credentials.
+//
+// https://tools.ietf.org/html/draft-ietf-tls-subcerts
+
+static bool ext_delegated_credential_add_clienthello(SSL_HANDSHAKE *hs,
+                                                     CBB *out) {
+  return true;
+}
+
+static bool ext_delegated_credential_parse_clienthello(SSL_HANDSHAKE *hs,
+                                                       uint8_t *out_alert,
+                                                       CBS *contents) {
+  assert(TLSEXT_TYPE_delegated_credential == 0xff02);
+  // TODO: Check that the extension is empty.
+  //
+  // As of draft-02, the client sends an empty extension in order indicate
+  // support for delegated credentials. This could change, however, since the
+  // spec is not yet finalized. This assertion is here to remind us to enforce
+  // this check once the extension ID is assigned.
+
+  if (contents == nullptr || ssl_protocol_version(hs->ssl) < TLS1_3_VERSION) {
+    // Don't use delegated credentials unless we're negotiating TLS 1.3 or
+    // higher.
+    return true;
+  }
+
+  hs->delegated_credential_requested = true;
+  return true;
+}
+
 // Certificate compression
 
 static bool cert_compression_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
@@ -3003,6 +3020,14 @@
     cert_compression_parse_clienthello,
     cert_compression_add_serverhello,
   },
+  {
+    TLSEXT_TYPE_delegated_credential,
+    NULL,
+    ext_delegated_credential_add_clienthello,
+    forbid_parse_serverhello,
+    ext_delegated_credential_parse_clienthello,
+    dont_add_serverhello,
+  },
 };
 
 #define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension))
@@ -3629,6 +3654,7 @@
 bool tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out) {
   SSL *const ssl = hs->ssl;
   CERT *cert = hs->config->cert.get();
+  DC *dc = cert->dc.get();
 
   // Before TLS 1.2, the signature algorithm isn't negotiated as part of the
   // handshake.
@@ -3641,19 +3667,13 @@
   }
 
   Span<const uint16_t> sigalgs = kSignSignatureAlgorithms;
-  if (!cert->sigalgs.empty()) {
+  if (ssl_signing_with_dc(hs)) {
+    sigalgs = MakeConstSpan(&dc->expected_cert_verify_algorithm, 1);
+  } else if (!cert->sigalgs.empty()) {
     sigalgs = cert->sigalgs;
   }
 
-  Span<const uint16_t> peer_sigalgs = hs->peer_sigalgs;
-  if (peer_sigalgs.empty() && ssl_protocol_version(ssl) < TLS1_3_VERSION) {
-    // If the client didn't specify any signature_algorithms extension then
-    // we can assume that it supports SHA1. See
-    // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
-    static const uint16_t kDefaultPeerAlgorithms[] = {SSL_SIGN_RSA_PKCS1_SHA1,
-                                                      SSL_SIGN_ECDSA_SHA1};
-    peer_sigalgs = kDefaultPeerAlgorithms;
-  }
+  Span<const uint16_t> peer_sigalgs = tls1_get_peer_verify_algorithms(hs);
 
   for (uint16_t sigalg : sigalgs) {
     // SSL_SIGN_RSA_PKCS1_MD5_SHA1 is an internal value and should never be
@@ -3675,6 +3695,19 @@
   return false;
 }
 
+Span<const uint16_t> tls1_get_peer_verify_algorithms(const SSL_HANDSHAKE *hs) {
+  Span<const uint16_t> peer_sigalgs = hs->peer_sigalgs;
+  if (peer_sigalgs.empty() && ssl_protocol_version(hs->ssl) < TLS1_3_VERSION) {
+    // If the client didn't specify any signature_algorithms extension then
+    // we can assume that it supports SHA1. See
+    // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+    static const uint16_t kDefaultPeerAlgorithms[] = {SSL_SIGN_RSA_PKCS1_SHA1,
+                                                      SSL_SIGN_ECDSA_SHA1};
+    peer_sigalgs = kDefaultPeerAlgorithms;
+  }
+  return peer_sigalgs;
+}
+
 bool tls1_verify_channel_id(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
   SSL *const ssl = hs->ssl;
   // A Channel ID handshake message is structured to contain multiple
diff --git a/src/ssl/test/CMakeLists.txt b/src/ssl/test/CMakeLists.txt
index d86464c..ebc16f1 100644
--- a/src/ssl/test/CMakeLists.txt
+++ b/src/ssl/test/CMakeLists.txt
@@ -10,13 +10,11 @@
   settings_writer.cc
   test_config.cc
   test_state.cc
-
-  $<TARGET_OBJECTS:test_support>
 )
 
 add_dependencies(bssl_shim global_target)
 
-target_link_libraries(bssl_shim ssl crypto)
+target_link_libraries(bssl_shim test_support_lib ssl crypto)
 
 if(UNIX AND NOT APPLE AND NOT ANDROID)
   add_executable(
@@ -29,13 +27,11 @@
     settings_writer.cc
     test_config.cc
     test_state.cc
-
-    $<TARGET_OBJECTS:test_support>
   )
 
   add_dependencies(handshaker global_target)
 
-  target_link_libraries(handshaker ssl crypto)
+  target_link_libraries(handshaker test_support_lib ssl crypto)
 else()
   # Declare a dummy target for run_tests to depend on.
   add_custom_target(handshaker)
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 77ed796..62db076 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -981,6 +981,12 @@
           pending_initial_write = false;
         }
 
+        if (config->key_update &&
+            !SSL_key_update(ssl, SSL_KEY_UPDATE_NOT_REQUESTED)) {
+          fprintf(stderr, "SSL_key_update failed.\n");
+          return false;
+        }
+
         for (int i = 0; i < n; i++) {
           buf[i] ^= 0xff;
         }
diff --git a/src/ssl/test/fuzzer.h b/src/ssl/test/fuzzer.h
index 1ca970d..f714d5d 100644
--- a/src/ssl/test/fuzzer.h
+++ b/src/ssl/test/fuzzer.h
@@ -414,6 +414,13 @@
       return false;
     }
 
+    static const int kCurves[] = {NID_CECPQ2, NID_X25519, NID_X9_62_prime256v1,
+                                  NID_secp384r1, NID_secp521r1};
+    if (!SSL_CTX_set1_curves(ctx_.get(), kCurves,
+                             OPENSSL_ARRAY_SIZE(kCurves))) {
+      return false;
+    }
+
     SSL_CTX_set_early_data_enabled(ctx_.get(), 1);
 
     SSL_CTX_set_next_proto_select_cb(ctx_.get(), NPNSelectCallback, nullptr);
@@ -489,16 +496,6 @@
           SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, nullptr);
           break;
 
-        case kTLS13Variant: {
-          uint8_t variant;
-          if (!CBS_get_u8(cbs, &variant)) {
-            return nullptr;
-          }
-          SSL_set_tls13_variant(ssl.get(),
-                                static_cast<tls13_variant_t>(variant));
-          break;
-        }
-
         case kHandoffTag: {
           CBS handoff;
           if (!CBS_get_u24_length_prefixed(cbs, &handoff)) {
diff --git a/src/ssl/test/fuzzer_tags.h b/src/ssl/test/fuzzer_tags.h
index c21aca3..eb9991d 100644
--- a/src/ssl/test/fuzzer_tags.h
+++ b/src/ssl/test/fuzzer_tags.h
@@ -39,13 +39,10 @@
 // certificates.
 static const uint16_t kRequestClientCert = 2;
 
-// kTLS13Variant is followed by a u8 denoting the TLS 1.3 variant to configure.
-static const uint16_t kTLS13Variant = 3;
-
 // kHandoffTag is followed by the output of |SSL_serialize_handoff|.
-static const uint16_t kHandoffTag = 4;
+static const uint16_t kHandoffTag = 3;
 
 // kHandbackTag is followed by te output of |SSL_serialize_handback|.
-static const uint16_t kHandbackTag = 5;
+static const uint16_t kHandbackTag = 4;
 
 #endif  // HEADER_SSL_TEST_FUZZER_TAGS
diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go
index 3246f0b..e827c52 100644
--- a/src/ssl/test/runner/cipher_suites.go
+++ b/src/ssl/test/runner/cipher_suites.go
@@ -33,7 +33,7 @@
 
 	// This method may not be called if the server doesn't send a
 	// ServerKeyExchange message.
-	processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+	processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, crypto.PublicKey, *serverKeyExchangeMsg) error
 	generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
 
 	// peerSignatureAlgorithm returns the signature algorithm used by the
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index d99518c..bbcacf5 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -32,23 +32,8 @@
 	VersionDTLS12 = 0xfefd
 )
 
-// A draft version of TLS 1.3 that is sent over the wire for the current draft.
-const (
-	tls13Draft23Version = 0x7f17
-	tls13Draft28Version = 0x7f1c
-)
-
-const (
-	TLS13RFC     = 0
-	TLS13Draft23 = 1
-	TLS13Draft28 = 2
-	TLS13All     = 3
-)
-
 var allTLSWireVersions = []uint16{
 	VersionTLS13,
-	tls13Draft28Version,
-	tls13Draft23Version,
 	VersionTLS12,
 	VersionTLS11,
 	VersionTLS10,
@@ -140,6 +125,7 @@
 	extensionRenegotiationInfo          uint16 = 0xff01
 	extensionQUICTransportParams        uint16 = 0xffa5 // draft-ietf-quic-tls-13
 	extensionChannelID                  uint16 = 30032  // not IANA assigned
+	extensionDelegatedCredentials       uint16 = 0xff02 // not IANA assigned
 )
 
 // TLS signaling cipher suite values
@@ -447,9 +433,6 @@
 	// which is currently TLS 1.2.
 	MaxVersion uint16
 
-	// TLS13Variant is the variant of TLS 1.3 to use.
-	TLS13Variant int
-
 	// CurvePreferences contains the elliptic curves that will be used in
 	// an ECDHE handshake, in preference order. If empty, the default will
 	// be used.
@@ -1531,10 +1514,6 @@
 	// specified number of plaintext bytes per record.
 	ExpectPackedEncryptedHandshake int
 
-	// ForbidHandshakePacking, if true, requires the peer place a record
-	// boundary after every handshake message.
-	ForbidHandshakePacking bool
-
 	// SendTicketLifetime, if non-zero, is the ticket lifetime to send in
 	// NewSessionTicket messages.
 	SendTicketLifetime time.Duration
@@ -1658,6 +1637,18 @@
 	// ExpectKeyShares, if not nil, lists (in order) the curves that a ClientHello
 	// should have key shares for.
 	ExpectedKeyShares []CurveID
+
+	// ExpectDelegatedCredentials, if true, requires that the handshake present
+	// delegated credentials.
+	ExpectDelegatedCredentials bool
+
+	// FailIfDelegatedCredentials, if true, causes a handshake failure if the
+	// server returns delegated credentials.
+	FailIfDelegatedCredentials bool
+
+	// DisableDelegatedCredentials, if true, disables client support for delegated
+	// credentials.
+	DisableDelegatedCredentials bool
 }
 
 func (c *Config) serverInit() {
@@ -1770,18 +1761,12 @@
 		switch vers {
 		case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13:
 			return vers, true
-		case tls13Draft23Version, tls13Draft28Version:
-			return VersionTLS13, true
 		}
 	}
 
 	return 0, false
 }
 
-func isDraft28(vers uint16) bool {
-	return vers == tls13Draft28Version || vers == VersionTLS13
-}
-
 // isSupportedVersion checks if the specified wire version is acceptable. If so,
 // it returns true and the corresponding protocol version. Otherwise, it returns
 // false.
@@ -1790,26 +1775,6 @@
 	if !ok || c.minVersion(isDTLS) > vers || vers > c.maxVersion(isDTLS) {
 		return 0, false
 	}
-	if vers == VersionTLS13 {
-		switch c.TLS13Variant {
-		case TLS13Draft23:
-			if wireVers != tls13Draft23Version {
-				return 0, false
-			}
-		case TLS13Draft28:
-			if wireVers != tls13Draft28Version {
-				return 0, false
-			}
-		case TLS13RFC:
-			if wireVers != VersionTLS13 {
-				return 0, false
-			}
-		case TLS13All:
-			// Allow all of them.
-		default:
-			panic(c.TLS13Variant)
-		}
-	}
 	return vers, true
 }
 
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index b6b6ffa..8a3ed5d 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -106,6 +106,7 @@
 	pendingFragments [][]byte // pending outgoing handshake fragments.
 	pendingPacket    []byte   // pending outgoing packet.
 
+	keyUpdateSeen      bool
 	keyUpdateRequested bool
 	seenOneByteRecord  bool
 
@@ -453,7 +454,7 @@
 				n := len(payload) - c.Overhead()
 				additionalData[11] = byte(n >> 8)
 				additionalData[12] = byte(n)
-			} else if isDraft28(hc.wireVersion) {
+			} else {
 				additionalData = b.data[:recordHeaderLen]
 			}
 			var err error
@@ -619,7 +620,7 @@
 				copy(additionalData[8:], b.data[:3])
 				additionalData[11] = byte(payloadLen >> 8)
 				additionalData[12] = byte(payloadLen)
-			} else if isDraft28(hc.wireVersion) {
+			} else {
 				additionalData = make([]byte, 5)
 				copy(additionalData, b.data[:3])
 				n := len(b.data) - recordHeaderLen
@@ -1321,9 +1322,6 @@
 			return nil, err
 		}
 	}
-	if c.hand.Len() > 4+n && c.config.Bugs.ForbidHandshakePacking {
-		return nil, errors.New("tls: forbidden trailing data after a handshake message")
-	}
 	return c.hand.Next(4 + n), nil
 }
 
@@ -1635,6 +1633,8 @@
 	}
 
 	if keyUpdate, ok := msg.(*keyUpdateMsg); ok {
+		c.keyUpdateSeen = true
+
 		if c.config.Bugs.RejectUnsolicitedKeyUpdate {
 			return errors.New("tls: unexpected KeyUpdate message")
 		}
@@ -1665,7 +1665,7 @@
 	keyUpdate, ok := msg.(*keyUpdateMsg)
 	if !ok {
 		c.sendAlert(alertUnexpectedMessage)
-		return errors.New("tls: unexpected message when reading KeyUpdate")
+		return fmt.Errorf("tls: unexpected message (%T) when reading KeyUpdate", msg)
 	}
 
 	if keyUpdate.keyUpdateRequest != keyUpdateNotRequested {
@@ -1708,13 +1708,12 @@
 				// Soft error, like EAGAIN
 				return 0, err
 			}
-			if c.hand.Len() > 0 {
+			for c.hand.Len() > 0 {
 				// We received handshake bytes, indicating a
 				// post-handshake message.
 				if err := c.handlePostHandshakeMessage(); err != nil {
 					return 0, err
 				}
-				continue
 			}
 		}
 		if err := c.in.err; err != nil {
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 5234462..45dc75d 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -32,6 +32,8 @@
 	masterSecret  []byte
 	session       *ClientSessionState
 	finishedBytes []byte
+	peerPublicKey crypto.PublicKey
+	skxAlgo       signatureAlgorithm
 }
 
 func mapClientHelloVersion(vers uint16, isDTLS bool) uint16 {
@@ -126,6 +128,7 @@
 		pskBinderFirst:          c.config.Bugs.PSKBinderFirst,
 		omitExtensions:          c.config.Bugs.OmitExtensions,
 		emptyExtensions:         c.config.Bugs.EmptyExtensions,
+		delegatedCredentials:    !c.config.Bugs.DisableDelegatedCredentials,
 	}
 
 	if maxVersion >= VersionTLS13 {
@@ -424,10 +427,9 @@
 		if len(hello.pskIdentities) > 0 {
 			version := session.wireVersion
 			// We may have a pre-1.3 session if SendBothTickets is
-			// set. Fill in an arbitrary TLS 1.3 version to compute
-			// the binder.
+			// set.
 			if session.vers < VersionTLS13 {
-				version = tls13Draft23Version
+				version = VersionTLS13
 			}
 			generatePSKBinders(version, hello, pskCipherSuite, session.masterSecret, []byte{}, []byte{}, c.config)
 		}
@@ -979,7 +981,6 @@
 		if err := hs.verifyCertificates(certMsg); err != nil {
 			return err
 		}
-		leaf := c.peerCertificates[0]
 		c.ocspResponse = certMsg.certificates[0].ocspResponse
 		c.sctList = certMsg.certificates[0].sctList
 
@@ -995,7 +996,7 @@
 
 		c.peerSignatureAlgorithm = certVerifyMsg.signatureAlgorithm
 		input := hs.finishedHash.certificateVerifyInput(serverCertificateVerifyContextTLS13)
-		err = verifyMessage(c.vers, getCertificatePublicKey(leaf), c.config, certVerifyMsg.signatureAlgorithm, input, certVerifyMsg.signature)
+		err = verifyMessage(c.vers, hs.peerPublicKey, c.config, certVerifyMsg.signatureAlgorithm, input, certVerifyMsg.signature)
 		if err != nil {
 			return err
 		}
@@ -1234,7 +1235,7 @@
 	skx, ok := msg.(*serverKeyExchangeMsg)
 	if ok {
 		hs.writeServerHash(skx.marshal())
-		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, leaf, skx)
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, hs.peerPublicKey, skx)
 		if err != nil {
 			c.sendAlert(alertUnexpectedMessage)
 			return err
@@ -1378,6 +1379,23 @@
 	return nil
 }
 
+// delegatedCredentialSignedMessage returns the bytes that are signed in order
+// to authenticate a delegated credential.
+func delegatedCredentialSignedMessage(credBytes []byte, algorithm signatureAlgorithm, leafDER []byte) []byte {
+	// https://tools.ietf.org/html/draft-ietf-tls-subcerts-03#section-3
+	ret := make([]byte, 64, 128)
+	for i := range ret {
+		ret[i] = 0x20
+	}
+
+	ret = append(ret, []byte("TLS, server delegated credentials\x00")...)
+	ret = append(ret, leafDER...)
+	ret = append(ret, byte(algorithm>>8), byte(algorithm))
+	ret = append(ret, credBytes...)
+
+	return ret
+}
+
 func (hs *clientHandshakeState) verifyCertificates(certMsg *certificateMsg) error {
 	c := hs.c
 
@@ -1386,6 +1404,7 @@
 		return errors.New("tls: no certificates sent")
 	}
 
+	var dc *delegatedCredential
 	certs := make([]*x509.Certificate, len(certMsg.certificates))
 	for i, certEntry := range certMsg.certificates {
 		cert, err := x509.ParseCertificate(certEntry.data)
@@ -1394,6 +1413,22 @@
 			return errors.New("tls: failed to parse certificate from server: " + err.Error())
 		}
 		certs[i] = cert
+
+		if certEntry.delegatedCredential != nil {
+			if c.config.Bugs.FailIfDelegatedCredentials {
+				c.sendAlert(alertIllegalParameter)
+				return errors.New("tls: unexpected delegated credential")
+			}
+			if i != 0 {
+				c.sendAlert(alertIllegalParameter)
+				return errors.New("tls: non-leaf certificate has a delegated credential")
+			}
+			if c.config.Bugs.DisableDelegatedCredentials {
+				c.sendAlert(alertIllegalParameter)
+				return errors.New("tls: server sent delegated credential without it being requested")
+			}
+			dc = certEntry.delegatedCredential
+		}
 	}
 
 	if !c.config.InsecureSkipVerify {
@@ -1418,16 +1453,45 @@
 		}
 	}
 
-	publicKey := getCertificatePublicKey(certs[0])
-	switch publicKey.(type) {
+	leafPublicKey := getCertificatePublicKey(certs[0])
+	switch leafPublicKey.(type) {
 	case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
 		break
 	default:
 		c.sendAlert(alertUnsupportedCertificate)
-		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", publicKey)
+		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", leafPublicKey)
 	}
 
 	c.peerCertificates = certs
+
+	if dc != nil {
+		// Note that this doesn't check a) the delegated credential temporal
+		// validity nor b) that the certificate has the special OID asserted.
+		hs.skxAlgo = dc.expectedCertVerifyAlgo
+
+		var err error
+		if hs.peerPublicKey, err = x509.ParsePKIXPublicKey(dc.pkixPublicKey); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: failed to parse public key from delegated credential: " + err.Error())
+		}
+
+		verifier, err := getSigner(c.vers, hs.peerPublicKey, c.config, dc.algorithm, true)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: failed to get verifier for delegated credential: " + err.Error())
+		}
+
+		if err := verifier.verifyMessage(leafPublicKey, delegatedCredentialSignedMessage(dc.signedBytes, dc.algorithm, certs[0].Raw), dc.signature); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: failed to verify delegated credential: " + err.Error())
+		}
+	} else if c.config.Bugs.ExpectDelegatedCredentials {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: delegated credentials missing")
+	} else {
+		hs.peerPublicKey = leafPublicKey
+	}
+
 	return nil
 }
 
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 823c6c8..f12ca1a 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -297,6 +297,7 @@
 	emptyExtensions         bool
 	pad                     int
 	compressedCertAlgs      []uint16
+	delegatedCredentials    bool
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -350,7 +351,8 @@
 		m.omitExtensions == m1.omitExtensions &&
 		m.emptyExtensions == m1.emptyExtensions &&
 		m.pad == m1.pad &&
-		eqUint16s(m.compressedCertAlgs, m1.compressedCertAlgs)
+		eqUint16s(m.compressedCertAlgs, m1.compressedCertAlgs) &&
+		m.delegatedCredentials == m1.delegatedCredentials
 }
 
 func (m *clientHelloMsg) marshalKeyShares(bb *byteBuilder) {
@@ -592,6 +594,10 @@
 			algIDs.addU16(v)
 		}
 	}
+	if m.delegatedCredentials {
+		extensions.addU16(extensionDelegatedCredentials)
+		extensions.addU16(0) // Length is always 0
+	}
 	// The PSK extension must be last. See https://tools.ietf.org/html/rfc8446#section-4.2.11
 	if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
 		extensions.addU16(extensionPreSharedKey)
@@ -717,6 +723,7 @@
 	m.alpnProtocols = nil
 	m.extendedMasterSecret = false
 	m.customExtension = ""
+	m.delegatedCredentials = false
 
 	if len(reader) == 0 {
 		// ClientHello is optionally followed by extension data
@@ -947,6 +954,11 @@
 					return false
 				}
 			}
+		case extensionDelegatedCredentials:
+			if len(body) != 0 {
+				return false
+			}
+			m.delegatedCredentials = true
 		}
 
 		if isGREASEValue(extension) {
@@ -1602,6 +1614,17 @@
 	sctList             []byte
 	duplicateExtensions bool
 	extraExtension      []byte
+	delegatedCredential *delegatedCredential
+}
+
+type delegatedCredential struct {
+	// https://tools.ietf.org/html/draft-ietf-tls-subcerts-03#section-3
+	signedBytes            []byte
+	lifetimeSecs           uint32
+	expectedCertVerifyAlgo signatureAlgorithm
+	pkixPublicKey          []byte
+	algorithm              signatureAlgorithm
+	signature              []byte
 }
 
 type certificateMsg struct {
@@ -1700,6 +1723,29 @@
 					}
 				case extensionSignedCertificateTimestamp:
 					cert.sctList = []byte(body)
+				case extensionDelegatedCredentials:
+					// https://tools.ietf.org/html/draft-ietf-tls-subcerts-03#section-3
+					if cert.delegatedCredential != nil {
+						return false
+					}
+
+					dc := new(delegatedCredential)
+					origBody := body
+					var expectedCertVerifyAlgo, algorithm uint16
+
+					if !body.readU32(&dc.lifetimeSecs) ||
+						!body.readU16(&expectedCertVerifyAlgo) ||
+						!body.readU24LengthPrefixedBytes(&dc.pkixPublicKey) ||
+						!body.readU16(&algorithm) ||
+						!body.readU16LengthPrefixedBytes(&dc.signature) ||
+						len(body) != 0 {
+						return false
+					}
+
+					dc.expectedCertVerifyAlgo = signatureAlgorithm(expectedCertVerifyAlgo)
+					dc.algorithm = signatureAlgorithm(algorithm)
+					dc.signedBytes = []byte(origBody)[:4+2+3+len(dc.pkixPublicKey)]
+					cert.delegatedCredential = dc
 				default:
 					return false
 				}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 5486342..d2ef9b4 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -881,10 +881,10 @@
 					data: certData,
 				}
 				if i == 0 {
-					if hs.clientHello.ocspStapling {
+					if hs.clientHello.ocspStapling && !c.config.Bugs.NoOCSPStapling {
 						cert.ocspResponse = hs.cert.OCSPStaple
 					}
-					if hs.clientHello.sctListSupported {
+					if hs.clientHello.sctListSupported && !c.config.Bugs.NoSignedCertificateTimestamps {
 						cert.sctList = hs.cert.SignedCertificateTimestampList
 					}
 					cert.duplicateExtensions = config.Bugs.SendDuplicateCertExtensions
@@ -1577,11 +1577,11 @@
 	c := hs.c
 
 	isPSK := hs.suite.flags&suitePSK != 0
-	if !isPSK && hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+	if !isPSK && hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 && !c.config.Bugs.NoOCSPStapling {
 		hs.hello.extensions.ocspStapling = true
 	}
 
-	if hs.clientHello.sctListSupported && len(hs.cert.SignedCertificateTimestampList) > 0 {
+	if hs.clientHello.sctListSupported && len(hs.cert.SignedCertificateTimestampList) > 0 && !c.config.Bugs.NoSignedCertificateTimestamps {
 		hs.hello.extensions.sctList = hs.cert.SignedCertificateTimestampList
 	}
 
diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go
index f40552d..13e78bc 100644
--- a/src/ssl/test/runner/key_agreement.go
+++ b/src/ssl/test/runner/key_agreement.go
@@ -5,6 +5,7 @@
 package runner
 
 import (
+	"crypto"
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rsa"
@@ -133,7 +134,7 @@
 	return preMasterSecret, nil
 }
 
-func (ka *rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+func (ka *rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, key crypto.PublicKey, skx *serverKeyExchangeMsg) error {
 	return errors.New("tls: unexpected ServerKeyExchange")
 }
 
@@ -456,7 +457,7 @@
 // to authenticate the ServerKeyExchange parameters.
 type keyAgreementAuthentication interface {
 	signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error)
-	verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error
+	verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, key crypto.PublicKey, params []byte, sig []byte) error
 }
 
 // nilKeyAgreementAuthentication does not authenticate the key
@@ -469,7 +470,7 @@
 	return skx, nil
 }
 
-func (ka *nilKeyAgreementAuthentication) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error {
+func (ka *nilKeyAgreementAuthentication) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, key crypto.PublicKey, params []byte, sig []byte) error {
 	return nil
 }
 
@@ -529,9 +530,8 @@
 	return skx, nil
 }
 
-func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error {
+func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, publicKey crypto.PublicKey, params []byte, sig []byte) error {
 	// The peer's key must match the cipher type.
-	publicKey := getCertificatePublicKey(cert)
 	switch ka.keyType {
 	case keyTypeECDSA:
 		_, edsaOk := publicKey.(*ecdsa.PublicKey)
@@ -646,7 +646,7 @@
 	return ka.curve.finish(ckx.ciphertext[1:])
 }
 
-func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, key crypto.PublicKey, skx *serverKeyExchangeMsg) error {
 	if len(skx.key) < 4 {
 		return errServerKeyExchange
 	}
@@ -671,7 +671,7 @@
 	// Check the signature.
 	serverECDHParams := skx.key[:4+publicLen]
 	sig := skx.key[4+publicLen:]
-	return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
+	return ka.auth.verifyParameters(config, clientHello, serverHello, key, serverECDHParams, sig)
 }
 
 func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -722,7 +722,7 @@
 	return nil, nil
 }
 
-func (ka *nilKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+func (ka *nilKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, key crypto.PublicKey, skx *serverKeyExchangeMsg) error {
 	if len(skx.key) != 0 {
 		return errServerKeyExchange
 	}
@@ -820,7 +820,7 @@
 	return makePSKPremaster(otherSecret, config.PreSharedKey), nil
 }
 
-func (ka *pskKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+func (ka *pskKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, key crypto.PublicKey, skx *serverKeyExchangeMsg) error {
 	if len(skx.key) < 2 {
 		return errServerKeyExchange
 	}
@@ -833,7 +833,7 @@
 	// Process the remainder of the ServerKeyExchange.
 	newSkx := new(serverKeyExchangeMsg)
 	newSkx.key = skx.key[2+identityLen:]
-	return ka.base.processServerKeyExchange(config, clientHello, serverHello, cert, newSkx)
+	return ka.base.processServerKeyExchange(config, clientHello, serverHello, key, newSkx)
 }
 
 func (ka *pskKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index b5cc0a7..8461bd8 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -16,9 +16,11 @@
 
 import (
 	"bytes"
+	"crypto"
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rand"
+	"crypto/rsa"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"encoding/base64"
@@ -246,6 +248,143 @@
 	garbageCertificate.PrivateKey = rsaCertificate.PrivateKey
 }
 
+// delegatedCredentialConfig specifies the shape of a delegated credential, not
+// including the keys themselves.
+type delegatedCredentialConfig struct {
+	// lifetime is the amount of time, from the notBefore of the parent
+	// certificate, that the delegated credential is valid for. If zero, then 24
+	// hours is assumed.
+	lifetime time.Duration
+	// expectedAlgo is the signature scheme that should be used with this
+	// delegated credential. If zero, ECDSA with P-256 is assumed.
+	expectedAlgo signatureAlgorithm
+	// tlsVersion is the version of TLS that should be used with this delegated
+	// credential. If zero, TLS 1.3 is assumed.
+	tlsVersion uint16
+	// algo is the signature algorithm that the delegated credential itself is
+	// signed with. Cannot be zero.
+	algo signatureAlgorithm
+}
+
+func loadRSAPrivateKey(filename string) (priv *rsa.PrivateKey, privPKCS8 []byte, err error) {
+	pemPath := path.Join(*resourceDir, filename)
+	pemBytes, err := ioutil.ReadFile(pemPath)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	block, _ := pem.Decode(pemBytes)
+	if block == nil {
+		return nil, nil, fmt.Errorf("no PEM block found in %q", pemPath)
+	}
+	privPKCS8 = block.Bytes
+
+	parsed, err := x509.ParsePKCS8PrivateKey(privPKCS8)
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to parse PKCS#8 key from %q", pemPath)
+	}
+
+	priv, ok := parsed.(*rsa.PrivateKey)
+	if !ok {
+		return nil, nil, fmt.Errorf("found %T in %q rather than an RSA private key", parsed, pemPath)
+	}
+
+	return priv, privPKCS8, nil
+}
+
+func createDelegatedCredential(config delegatedCredentialConfig, parentDER []byte, parentPriv crypto.PrivateKey) (dc, privPKCS8 []uint8, err error) {
+	expectedAlgo := config.expectedAlgo
+	if expectedAlgo == signatureAlgorithm(0) {
+		expectedAlgo = signatureECDSAWithP256AndSHA256
+	}
+
+	var pub crypto.PublicKey
+
+	switch expectedAlgo {
+	case signatureRSAPKCS1WithMD5, signatureRSAPKCS1WithSHA1, signatureRSAPKCS1WithSHA256, signatureRSAPKCS1WithSHA384, signatureRSAPKCS1WithSHA512, signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA384, signatureRSAPSSWithSHA512:
+		// RSA keys are expensive to generate so load from disk instead.
+		var priv *rsa.PrivateKey
+		if priv, privPKCS8, err = loadRSAPrivateKey(rsaKeyFile); err != nil {
+			return nil, nil, err
+		}
+
+		pub = &priv.PublicKey
+
+	case signatureECDSAWithSHA1, signatureECDSAWithP256AndSHA256, signatureECDSAWithP384AndSHA384, signatureECDSAWithP521AndSHA512:
+		var curve elliptic.Curve
+		switch expectedAlgo {
+		case signatureECDSAWithSHA1, signatureECDSAWithP256AndSHA256:
+			curve = elliptic.P256()
+		case signatureECDSAWithP384AndSHA384:
+			curve = elliptic.P384()
+		case signatureECDSAWithP521AndSHA512:
+			curve = elliptic.P521()
+		default:
+			panic("internal error")
+		}
+
+		priv, err := ecdsa.GenerateKey(curve, rand.Reader)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		if privPKCS8, err = x509.MarshalPKCS8PrivateKey(priv); err != nil {
+			return nil, nil, err
+		}
+
+		pub = &priv.PublicKey
+
+	default:
+		return nil, nil, fmt.Errorf("unsupported expected signature algorithm: %x", expectedAlgo)
+	}
+
+	lifetime := config.lifetime
+	if lifetime == 0 {
+		lifetime = 24 * time.Hour
+	}
+	lifetimeSecs := int64(lifetime.Seconds())
+	if lifetimeSecs > 1<<32 {
+		return nil, nil, fmt.Errorf("lifetime %s is too long to be expressed", lifetime)
+	}
+	tlsVersion := config.tlsVersion
+	if tlsVersion == 0 {
+		tlsVersion = VersionTLS13
+	}
+
+	if tlsVersion < VersionTLS13 {
+		return nil, nil, fmt.Errorf("delegated credentials require TLS 1.3")
+	}
+
+	// https://tools.ietf.org/html/draft-ietf-tls-subcerts-03#section-3
+	dc = append(dc, byte(lifetimeSecs>>24), byte(lifetimeSecs>>16), byte(lifetimeSecs>>8), byte(lifetimeSecs))
+	dc = append(dc, byte(expectedAlgo>>8), byte(expectedAlgo))
+
+	pubBytes, err := x509.MarshalPKIXPublicKey(pub)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	dc = append(dc, byte(len(pubBytes)>>16), byte(len(pubBytes)>>8), byte(len(pubBytes)))
+	dc = append(dc, pubBytes...)
+
+	var dummyConfig Config
+	parentSigner, err := getSigner(tlsVersion, parentPriv, &dummyConfig, config.algo, false /* not for verification */)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	parentSignature, err := parentSigner.signMessage(parentPriv, &dummyConfig, delegatedCredentialSignedMessage(dc, config.algo, parentDER))
+	if err != nil {
+		return nil, nil, err
+	}
+
+	dc = append(dc, byte(config.algo>>8), byte(config.algo))
+	dc = append(dc, byte(len(parentSignature)>>8), byte(len(parentSignature)))
+	dc = append(dc, parentSignature...)
+
+	return dc, privPKCS8, nil
+}
+
 func getRunnerCertificate(t testCert) Certificate {
 	for _, cert := range testCerts {
 		if cert.id == t {
@@ -473,6 +612,11 @@
 	sendKeyUpdates int
 	// keyUpdateRequest is the KeyUpdateRequest value to send in KeyUpdate messages.
 	keyUpdateRequest byte
+	// expectUnsolicitedKeyUpdate makes the test expect a one or more KeyUpdate
+	// messages while reading data from the shim. Don't use this in combination
+	// with any of the fields that send a KeyUpdate otherwise any received
+	// KeyUpdate might not be as unsolicited as expected.
+	expectUnsolicitedKeyUpdate bool
 	// expectMessageDropped, if true, means the test message is expected to
 	// be dropped by the client rather than echoed back.
 	expectMessageDropped bool
@@ -484,10 +628,6 @@
 	// resumeShimPrefix is the prefix that the shim will send to the server on a
 	// resumption.
 	resumeShimPrefix string
-	// tls13Variant, if non-zero, causes both runner and shim to be
-	// configured with the specified TLS 1.3 variant. This is a convenience
-	// option for configuring both concurrently.
-	tls13Variant int
 	// expectedQUICTransportParams contains the QUIC transport
 	// parameters that are expected to be sent by the peer.
 	expectedQUICTransportParams []byte
@@ -567,9 +707,6 @@
 	if *deterministic {
 		config.Time = func() time.Time { return time.Unix(1234, 1234) }
 	}
-	if test.tls13Variant != 0 {
-		config.TLS13Variant = test.tls13Variant
-	}
 
 	conn = &timeoutConn{conn, *idleTimeout}
 
@@ -951,6 +1088,10 @@
 				return fmt.Errorf("bad reply contents at byte %d; got %q and wanted %q", i, buf, testMessage)
 			}
 		}
+
+		if seen := tlsConn.keyUpdateSeen; seen != test.expectUnsolicitedKeyUpdate {
+			return fmt.Errorf("keyUpdateSeen (%t) != expectUnsolicitedKeyUpdate", seen)
+		}
 	}
 
 	return nil
@@ -1063,20 +1204,6 @@
 		if test.config.MaxVersion == 0 && test.config.MinVersion == 0 && test.expectedVersion == 0 {
 			panic(fmt.Sprintf("The name of test %q suggests that it's version specific, but min/max version in the Config is %x/%x. One of them should probably be %x", test.name, test.config.MinVersion, test.config.MaxVersion, ver.version))
 		}
-
-		if ver.tls13Variant != 0 {
-			var foundFlag bool
-			for _, flag := range test.flags {
-				if flag == "-tls13-variant" {
-					foundFlag = true
-					break
-				}
-			}
-			if !foundFlag && test.config.TLS13Variant != ver.tls13Variant && test.tls13Variant != ver.tls13Variant {
-				panic(fmt.Sprintf("The name of test %q suggests that uses an experimental TLS 1.3 variant, but neither the shim nor the runner configures it", test.name))
-			}
-		}
-
 	}
 
 	listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv6loopback})
@@ -1165,10 +1292,6 @@
 		flags = append(flags, "-tls-unique")
 	}
 
-	if test.tls13Variant != 0 {
-		flags = append(flags, "-tls13-variant", strconv.Itoa(test.tls13Variant))
-	}
-
 	flags = append(flags, "-handshaker-path", *handshakerPath)
 
 	var transcriptPrefix string
@@ -1376,8 +1499,7 @@
 	// versionWire, if non-zero, is the wire representation of the
 	// version. Otherwise the wire version is the protocol version or
 	// versionDTLS.
-	versionWire  uint16
-	tls13Variant int
+	versionWire uint16
 }
 
 func (vers tlsVersion) shimFlag(protocol protocol) string {
@@ -1420,25 +1542,10 @@
 		versionDTLS: VersionDTLS12,
 	},
 	{
-		name:         "TLS13",
-		version:      VersionTLS13,
-		excludeFlag:  "-no-tls13",
-		versionWire:  VersionTLS13,
-		tls13Variant: TLS13RFC,
-	},
-	{
-		name:         "TLS13Draft23",
-		version:      VersionTLS13,
-		excludeFlag:  "-no-tls13",
-		versionWire:  tls13Draft23Version,
-		tls13Variant: TLS13Draft23,
-	},
-	{
-		name:         "TLS13Draft28",
-		version:      VersionTLS13,
-		excludeFlag:  "-no-tls13",
-		versionWire:  tls13Draft28Version,
-		tls13Variant: TLS13Draft28,
+		name:        "TLS13",
+		version:     VersionTLS13,
+		excludeFlag: "-no-tls13",
+		versionWire: VersionTLS13,
 	},
 }
 
@@ -1456,23 +1563,6 @@
 	return ret
 }
 
-func allShimVersions(protocol protocol) []tlsVersion {
-	if protocol == dtls {
-		return allVersions(protocol)
-	}
-	tls13Default := tlsVersion{
-		name:         "TLS13All",
-		version:      VersionTLS13,
-		excludeFlag:  "-no-tls13",
-		versionWire:  0,
-		tls13Variant: TLS13All,
-	}
-
-	var shimVersions []tlsVersion
-	shimVersions = append(shimVersions, allVersions(protocol)...)
-	return append(shimVersions, tls13Default)
-}
-
 type testCipherSuite struct {
 	name string
 	id   uint16
@@ -2826,7 +2916,7 @@
 			expectedError: ":WRONG_VERSION_NUMBER:",
 		},
 		{
-			name: "KeyUpdate-Client",
+			name: "KeyUpdate-ToClient",
 			config: Config{
 				MaxVersion: VersionTLS13,
 			},
@@ -2835,7 +2925,7 @@
 		},
 		{
 			testType: serverTest,
-			name:     "KeyUpdate-Server",
+			name:     "KeyUpdate-ToServer",
 			config: Config{
 				MaxVersion: VersionTLS13,
 			},
@@ -2843,6 +2933,23 @@
 			keyUpdateRequest: keyUpdateNotRequested,
 		},
 		{
+			name: "KeyUpdate-FromClient",
+			config: Config{
+				MaxVersion: VersionTLS13,
+			},
+			expectUnsolicitedKeyUpdate: true,
+			flags:                      []string{"-key-update"},
+		},
+		{
+			testType: serverTest,
+			name:     "KeyUpdate-FromServer",
+			config: Config{
+				MaxVersion: VersionTLS13,
+			},
+			expectUnsolicitedKeyUpdate: true,
+			flags:                      []string{"-key-update"},
+		},
+		{
 			name: "KeyUpdate-InvalidRequestMode",
 			config: Config{
 				MaxVersion: VersionTLS13,
@@ -2959,20 +3066,19 @@
 		},
 		{
 			testType: clientTest,
-			name:     "TLS13Draft23-InvalidCompressionMethod",
+			name:     "TLS13-InvalidCompressionMethod",
 			config: Config{
 				MaxVersion: VersionTLS13,
 				Bugs: ProtocolBugs{
 					SendCompressionMethod: 1,
 				},
 			},
-			tls13Variant:  TLS13Draft23,
 			shouldFail:    true,
 			expectedError: ":DECODE_ERROR:",
 		},
 		{
 			testType: clientTest,
-			name:     "TLS13Draft23-HRR-InvalidCompressionMethod",
+			name:     "TLS13-HRR-InvalidCompressionMethod",
 			config: Config{
 				MaxVersion:       VersionTLS13,
 				CurvePreferences: []CurveID{CurveP384},
@@ -2980,7 +3086,6 @@
 					SendCompressionMethod: 1,
 				},
 			},
-			tls13Variant:       TLS13Draft23,
 			shouldFail:         true,
 			expectedError:      ":DECODE_ERROR:",
 			expectedLocalError: "remote error: error decoding message",
@@ -3069,8 +3174,7 @@
 					ExpectPackedEncryptedHandshake: 512,
 				},
 			},
-			tls13Variant: TLS13Draft28,
-			messageLen:   1024,
+			messageLen: 1024,
 			flags: []string{
 				"-max-send-fragment", "512",
 				"-read-size", "1024",
@@ -3098,30 +3202,15 @@
 			expectedLocalError: "local error: record overflow",
 		},
 		{
-			// Test that handshake data is not packed in TLS 1.3
-			// draft-23.
+			// Test that handshake data is tightly packed in TLS 1.3.
 			testType: serverTest,
-			name:     "ForbidHandshakePacking-TLS13Draft23",
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					ForbidHandshakePacking: true,
-				},
-			},
-			tls13Variant: TLS13Draft23,
-		},
-		{
-			// Test that handshake data is tightly packed in TLS 1.3
-			// draft-28.
-			testType: serverTest,
-			name:     "PackedEncryptedHandshake-TLS13Draft28",
+			name:     "PackedEncryptedHandshake-TLS13",
 			config: Config{
 				MaxVersion: VersionTLS13,
 				Bugs: ProtocolBugs{
 					ExpectPackedEncryptedHandshake: 16384,
 				},
 			},
-			tls13Variant: TLS13Draft28,
 		},
 		{
 			// Test that DTLS can handle multiple application data
@@ -3280,7 +3369,6 @@
 				AdvertiseAllConfiguredCiphers: true,
 			},
 		},
-		tls13Variant:         ver.tls13Variant,
 		certFile:             certFile,
 		keyFile:              keyFile,
 		flags:                flags,
@@ -3306,7 +3394,6 @@
 				SendCipherSuite:             sendCipherSuite,
 			},
 		},
-		tls13Variant:         ver.tls13Variant,
 		flags:                flags,
 		resumeSession:        true,
 		shouldFail:           shouldFail,
@@ -3330,9 +3417,8 @@
 			PreSharedKey:         []byte(psk),
 			PreSharedKeyIdentity: pskIdentity,
 		},
-		tls13Variant: ver.tls13Variant,
-		flags:        flags,
-		messageLen:   maxPlaintext,
+		flags:      flags,
+		messageLen: maxPlaintext,
 	})
 
 	// Test bad records for all ciphers. Bad records are fatal in TLS
@@ -3354,7 +3440,6 @@
 			PreSharedKey:         []byte(psk),
 			PreSharedKeyIdentity: pskIdentity,
 		},
-		tls13Variant:     ver.tls13Variant,
 		flags:            flags,
 		damageFirstWrite: true,
 		messageLen:       maxPlaintext,
@@ -3828,7 +3913,6 @@
 				ClientAuth: RequireAnyClientCert,
 				ClientCAs:  certPool,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
 				"-key-file", path.Join(*resourceDir, rsaKeyFile),
@@ -3842,8 +3926,7 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-require-any-client-certificate"},
+			flags: []string{"-require-any-client-certificate"},
 		})
 		testCases = append(testCases, testCase{
 			testType: serverTest,
@@ -3853,8 +3936,7 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{ecdsaP256Certificate},
 			},
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-require-any-client-certificate"},
+			flags: []string{"-require-any-client-certificate"},
 		})
 		testCases = append(testCases, testCase{
 			testType: clientTest,
@@ -3865,7 +3947,6 @@
 				ClientAuth: RequireAnyClientCert,
 				ClientCAs:  certPool,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
 				"-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
@@ -3879,7 +3960,6 @@
 				MaxVersion: ver.version,
 				ClientAuth: RequireAnyClientCert,
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedLocalError: "client didn't provide a certificate",
 		})
@@ -3893,7 +3973,6 @@
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-expect-verify-result",
 			},
@@ -3909,7 +3988,6 @@
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-expect-verify-result",
 				"-verify-peer",
@@ -3931,7 +4009,6 @@
 				MaxVersion: ver.version,
 			},
 			flags:              []string{"-require-any-client-certificate"},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedError:      ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
 			expectedLocalError: certificateRequired,
@@ -3949,7 +4026,6 @@
 			},
 			// Setting SSL_VERIFY_PEER allows anonymous clients.
 			flags:         []string{"-verify-peer"},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":UNEXPECTED_MESSAGE:",
 		})
@@ -3965,7 +4041,6 @@
 				"-enable-channel-id",
 				"-verify-peer-if-no-obc",
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedError:      ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
 			expectedLocalError: certificateRequired,
@@ -3980,7 +4055,6 @@
 				ChannelID:  channelIDKey,
 			},
 			expectChannelID: true,
-			tls13Variant:    ver.tls13Variant,
 			flags: []string{
 				"-enable-channel-id",
 				"-verify-peer-if-no-obc",
@@ -3998,7 +4072,6 @@
 					ExpectCertificateReqNames: caNames,
 				},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-require-any-client-certificate",
 				"-use-client-ca-list", encodeDERValues(caNames),
@@ -4015,7 +4088,6 @@
 				ClientAuth:   RequireAnyClientCert,
 				ClientCAs:    certPool,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
 				"-key-file", path.Join(*resourceDir, rsaKeyFile),
@@ -4081,7 +4153,7 @@
 	// Test that an empty client CA list doesn't send a CA extension.
 	testCases = append(testCases, testCase{
 		testType: serverTest,
-		name:     "TLS13Draft23-Empty-Client-CA-List",
+		name:     "TLS13-Empty-Client-CA-List",
 		config: Config{
 			MaxVersion:   VersionTLS13,
 			Certificates: []Certificate{rsaCertificate},
@@ -4089,7 +4161,6 @@
 				ExpectNoCertificateAuthoritiesExtension: true,
 			},
 		},
-		tls13Variant: TLS13Draft23,
 		flags: []string{
 			"-require-any-client-certificate",
 			"-use-client-ca-list", "<EMPTY>",
@@ -4134,8 +4205,7 @@
 							RequireExtendedMasterSecret: with,
 						},
 					},
-					tls13Variant: ver.tls13Variant,
-					flags:        flags,
+					flags: flags,
 				})
 			}
 		}
@@ -4442,37 +4512,6 @@
 		})
 
 		tests = append(tests, testCase{
-			name: "TLS13Draft23-HelloRetryRequest-Client",
-			config: Config{
-				MaxVersion: VersionTLS13,
-				MinVersion: VersionTLS13,
-				// P-384 requires a HelloRetryRequest against BoringSSL's default
-				// configuration. Assert this with ExpectMissingKeyShare.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					ExpectMissingKeyShare: true,
-				},
-			},
-			tls13Variant: TLS13Draft23,
-			// Cover HelloRetryRequest during an ECDHE-PSK resumption.
-			resumeSession: true,
-		})
-
-		tests = append(tests, testCase{
-			testType: serverTest,
-			name:     "TLS13Draft23-HelloRetryRequest-Server",
-			config: Config{
-				MaxVersion: VersionTLS13,
-				MinVersion: VersionTLS13,
-				// Require a HelloRetryRequest for every curve.
-				DefaultCurves: []CurveID{},
-			},
-			tls13Variant: TLS13Draft23,
-			// Cover HelloRetryRequest during an ECDHE-PSK resumption.
-			resumeSession: true,
-		})
-
-		tests = append(tests, testCase{
 			testType: clientTest,
 			name:     "TLS13-EarlyData-TooMuchData-Client",
 			config: Config{
@@ -4829,7 +4868,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant: vers.tls13Variant,
 			flags: []string{
 				"-enable-ocsp-stapling",
 				"-expect-ocsp-response",
@@ -4844,7 +4882,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant:         vers.tls13Variant,
 			expectedOCSPResponse: testOCSPResponse,
 			flags: []string{
 				"-ocsp-response",
@@ -4862,7 +4899,6 @@
 				MaxVersion:   vers.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
-			tls13Variant: vers.tls13Variant,
 			flags: []string{
 				"-enable-ocsp-stapling",
 				"-use-ocsp-callback",
@@ -4881,7 +4917,6 @@
 				MaxVersion:   vers.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
-			tls13Variant: vers.tls13Variant,
 			flags: []string{
 				"-enable-ocsp-stapling",
 				"-use-ocsp-callback",
@@ -4902,7 +4937,6 @@
 				MaxVersion:   vers.version,
 				Certificates: []Certificate{certNoStaple},
 			},
-			tls13Variant: vers.tls13Variant,
 			flags: []string{
 				"-enable-ocsp-stapling",
 				"-use-ocsp-callback",
@@ -4921,7 +4955,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant:         vers.tls13Variant,
 			expectedOCSPResponse: testOCSPResponse,
 			flags: []string{
 				"-use-ocsp-callback",
@@ -4941,7 +4974,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant:         vers.tls13Variant,
 			expectedOCSPResponse: []byte{},
 			flags: []string{
 				"-use-ocsp-callback",
@@ -4959,7 +4991,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant: vers.tls13Variant,
 			flags: []string{
 				"-use-ocsp-callback",
 				"-fail-ocsp-callback",
@@ -5002,7 +5033,6 @@
 						MaxVersion:   vers.version,
 						Certificates: []Certificate{rsaCertificate},
 					},
-					tls13Variant:  vers.tls13Variant,
 					flags:         append([]string{"-expect-verify-result"}, flags...),
 					resumeSession: true,
 				})
@@ -5013,7 +5043,6 @@
 						MaxVersion:   vers.version,
 						Certificates: []Certificate{rsaCertificate},
 					},
-					tls13Variant:  vers.tls13Variant,
 					flags:         append([]string{"-verify-fail"}, flags...),
 					shouldFail:    true,
 					expectedError: ":CERTIFICATE_VERIFY_FAILED:",
@@ -5026,7 +5055,6 @@
 						MaxVersion:   vers.version,
 						Certificates: []Certificate{rsaCertificate},
 					},
-					tls13Variant:  vers.tls13Variant,
 					flags:         append([]string{"-on-resume-verify-fail"}, flags...),
 					resumeSession: true,
 				})
@@ -5038,7 +5066,6 @@
 							MaxVersion:   vers.version,
 							Certificates: []Certificate{rsaCertificate},
 						},
-						tls13Variant: vers.tls13Variant,
 						flags: append([]string{
 							"-on-resume-verify-fail",
 							"-reverify-on-resume",
@@ -5054,7 +5081,6 @@
 							MaxVersion:   vers.version,
 							Certificates: []Certificate{rsaCertificate},
 						},
-						tls13Variant: vers.tls13Variant,
 						flags: append([]string{
 							"-reverify-on-resume",
 						}, flags...),
@@ -5073,7 +5099,6 @@
 								MaxEarlyDataSize:       16384,
 								SessionTicketsDisabled: true,
 							},
-							tls13Variant:         vers.tls13Variant,
 							resumeSession:        true,
 							expectResumeRejected: true,
 							flags: append([]string{
@@ -5100,7 +5125,6 @@
 									AlwaysRejectEarlyData: true,
 								},
 							},
-							tls13Variant:         vers.tls13Variant,
 							resumeSession:        true,
 							expectResumeRejected: false,
 							flags: append([]string{
@@ -5123,7 +5147,6 @@
 								MaxEarlyDataSize:       16384,
 								SessionTicketsDisabled: true,
 							},
-							tls13Variant:         vers.tls13Variant,
 							resumeSession:        true,
 							expectResumeRejected: true,
 							shouldFail:           true,
@@ -5153,7 +5176,6 @@
 									AlwaysRejectEarlyData: true,
 								},
 							},
-							tls13Variant:         vers.tls13Variant,
 							resumeSession:        true,
 							expectResumeRejected: false,
 							shouldFail:           true,
@@ -5182,7 +5204,6 @@
 									ExpectEarlyData: [][]byte{[]byte("hello")},
 								},
 							},
-							tls13Variant:         vers.tls13Variant,
 							resumeSession:        true,
 							expectResumeRejected: false,
 							flags: append([]string{
@@ -5206,7 +5227,6 @@
 									ExpectEarlyData: [][]byte{[]byte("hello")},
 								},
 							},
-							tls13Variant:  vers.tls13Variant,
 							resumeSession: true,
 							shouldFail:    true,
 							expectedError: ":CERTIFICATE_VERIFY_FAILED:",
@@ -5232,7 +5252,6 @@
 				MaxVersion:   vers.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
-			tls13Variant: vers.tls13Variant,
 			flags: []string{
 				"-verify-fail",
 				"-expect-verify-result",
@@ -5404,7 +5423,6 @@
 					MaxVersion:       ver.version,
 					RequestChannelID: true,
 				},
-				tls13Variant:    ver.tls13Variant,
 				flags:           []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
 				resumeSession:   true,
 				expectChannelID: true,
@@ -5418,7 +5436,6 @@
 					MaxVersion: ver.version,
 					ChannelID:  channelIDKey,
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-expect-channel-id",
 					base64.StdEncoding.EncodeToString(channelIDBytes),
@@ -5437,7 +5454,6 @@
 						InvalidChannelIDSignature: true,
 					},
 				},
-				tls13Variant:  ver.tls13Variant,
 				flags:         []string{"-enable-channel-id"},
 				shouldFail:    true,
 				expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:",
@@ -5759,7 +5775,7 @@
 
 func addVersionNegotiationTests() {
 	for _, protocol := range []protocol{tls, dtls} {
-		for _, shimVers := range allShimVersions(protocol) {
+		for _, shimVers := range allVersions(protocol) {
 			// Assemble flags to disable all newer versions on the shim.
 			var flags []string
 			for _, vers := range allVersions(protocol) {
@@ -5770,11 +5786,6 @@
 
 			flags2 := []string{"-max-version", shimVers.shimFlag(protocol)}
 
-			if shimVers.tls13Variant != 0 {
-				flags = append(flags, "-tls13-variant", strconv.Itoa(shimVers.tls13Variant))
-				flags2 = append(flags2, "-tls13-variant", strconv.Itoa(shimVers.tls13Variant))
-			}
-
 			// Test configuring the runner's maximum version.
 			for _, runnerVers := range allVersions(protocol) {
 				expectedVersion := shimVers.version
@@ -5782,12 +5793,6 @@
 					expectedVersion = runnerVers.version
 				}
 
-				if expectedVersion == VersionTLS13 && runnerVers.tls13Variant != shimVers.tls13Variant {
-					if shimVers.tls13Variant != TLS13All {
-						expectedVersion = VersionTLS12
-					}
-				}
-
 				suffix := shimVers.name + "-" + runnerVers.name
 				if protocol == dtls {
 					suffix += "-DTLS"
@@ -5810,8 +5815,7 @@
 					testType: clientTest,
 					name:     "VersionNegotiation-Client-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 						Bugs: ProtocolBugs{
 							ExpectInitialRecordVersion: clientVers,
 						},
@@ -5824,8 +5828,7 @@
 					testType: clientTest,
 					name:     "VersionNegotiation-Client2-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 						Bugs: ProtocolBugs{
 							ExpectInitialRecordVersion: clientVers,
 						},
@@ -5839,8 +5842,7 @@
 					testType: serverTest,
 					name:     "VersionNegotiation-Server-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 						Bugs: ProtocolBugs{
 							ExpectInitialRecordVersion: serverVers,
 						},
@@ -5853,8 +5855,7 @@
 					testType: serverTest,
 					name:     "VersionNegotiation-Server2-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 						Bugs: ProtocolBugs{
 							ExpectInitialRecordVersion: serverVers,
 						},
@@ -5883,14 +5884,12 @@
 				testType: serverTest,
 				name:     "VersionNegotiationExtension-" + suffix,
 				config: Config{
-					TLS13Variant: vers.tls13Variant,
 					Bugs: ProtocolBugs{
 						SendSupportedVersions:      []uint16{0x1111, vers.wire(protocol), 0x2222},
 						IgnoreTLS13DowngradeRandom: true,
 					},
 				},
 				expectedVersion: vers.version,
-				flags:           []string{"-tls13-variant", strconv.Itoa(vers.tls13Variant)},
 			})
 		}
 	}
@@ -6114,7 +6113,6 @@
 					NegotiateVersion: test.version,
 				},
 			},
-			tls13Variant:       TLS13RFC,
 			expectedVersion:    test.version,
 			shouldFail:         true,
 			expectedError:      ":TLS13_DOWNGRADE:",
@@ -6130,7 +6128,6 @@
 					NegotiateVersion: test.version,
 				},
 			},
-			tls13Variant:    TLS13RFC,
 			expectedVersion: test.version,
 			flags: []string{
 				"-ignore-tls13-downgrade",
@@ -6147,37 +6144,12 @@
 					SendSupportedVersions: []uint16{test.version},
 				},
 			},
-			tls13Variant:       TLS13RFC,
 			expectedVersion:    test.version,
 			shouldFail:         true,
 			expectedLocalError: test.clientShimError,
 		})
 	}
 
-	// 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",
@@ -6189,7 +6161,6 @@
 				AlertBeforeFalseStartTest: alertAccessDenied,
 			},
 		},
-		tls13Variant:    TLS13RFC,
 		expectedVersion: VersionTLS12,
 		flags: []string{
 			"-false-start",
@@ -6202,29 +6173,6 @@
 		expectedLocalError: "tls: peer did not false start: EOF",
 	})
 
-	// Test that draft TLS 1.3 versions do not trigger disabling False Start.
-	testCases = append(testCases, testCase{
-		name: "Downgrade-FalseStart-Draft",
-		config: Config{
-			MaxVersion:   VersionTLS13,
-			TLS13Variant: TLS13RFC,
-			NextProtos:   []string{"foo"},
-			Bugs: ProtocolBugs{
-				ExpectFalseStart: true,
-			},
-		},
-		expectedVersion: VersionTLS12,
-		flags: []string{
-			"-false-start",
-			"-advertise-alpn", "\x03foo",
-			"-expect-alpn", "foo",
-			"-ignore-tls13-downgrade",
-			"-tls13-variant", strconv.Itoa(TLS13Draft28),
-			"-max-version", strconv.Itoa(VersionTLS13),
-		},
-		shimWritesFirst: true,
-	})
-
 	// SSL 3.0 support has been removed. Test that the shim does not
 	// support it.
 	testCases = append(testCases, testCase{
@@ -6279,22 +6227,7 @@
 
 			flags2 := []string{"-min-version", shimVers.shimFlag(protocol)}
 
-			if shimVers.tls13Variant != 0 {
-				flags = append(flags, "-tls13-variant", strconv.Itoa(shimVers.tls13Variant))
-				flags2 = append(flags2, "-tls13-variant", strconv.Itoa(shimVers.tls13Variant))
-			}
-
 			for _, runnerVers := range allVersions(protocol) {
-				// Different TLS 1.3 variants are incompatible with each other and don't
-				// produce consistent minimum versions.
-				//
-				// TODO(davidben): Fold these tests (the main value is in the
-				// NegotiateVersion bug) into addVersionNegotiationTests and test based
-				// on intended shim behavior, not the shim + runner combination.
-				if shimVers.tls13Variant != runnerVers.tls13Variant {
-					continue
-				}
-
 				suffix := shimVers.name + "-" + runnerVers.name
 				if protocol == dtls {
 					suffix += "-DTLS"
@@ -6316,8 +6249,7 @@
 					testType: clientTest,
 					name:     "MinimumVersion-Client-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 						Bugs: ProtocolBugs{
 							// Ensure the server does not decline to
 							// select a version (versions extension) or
@@ -6337,8 +6269,7 @@
 					testType: clientTest,
 					name:     "MinimumVersion-Client2-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 						Bugs: ProtocolBugs{
 							// Ensure the server does not decline to
 							// select a version (versions extension) or
@@ -6359,8 +6290,7 @@
 					testType: serverTest,
 					name:     "MinimumVersion-Server-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 					},
 					flags:              flags,
 					expectedVersion:    expectedVersion,
@@ -6373,8 +6303,7 @@
 					testType: serverTest,
 					name:     "MinimumVersion-Server2-" + suffix,
 					config: Config{
-						MaxVersion:   runnerVers.version,
-						TLS13Variant: runnerVers.tls13Variant,
+						MaxVersion: runnerVers.version,
 					},
 					flags:              flags2,
 					expectedVersion:    expectedVersion,
@@ -6404,7 +6333,6 @@
 					DuplicateExtension: true,
 				},
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedLocalError: "remote error: error decoding message",
 		})
@@ -6417,7 +6345,6 @@
 					DuplicateExtension: true,
 				},
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedLocalError: "remote error: error decoding message",
 		})
@@ -6432,8 +6359,7 @@
 					ExpectServerName: "example.com",
 				},
 			},
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-host-name", "example.com"},
+			flags: []string{"-host-name", "example.com"},
 		})
 		testCases = append(testCases, testCase{
 			testType: clientTest,
@@ -6445,7 +6371,6 @@
 				},
 			},
 			flags:              []string{"-host-name", "example.com"},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedLocalError: "tls: unexpected server name",
 		})
@@ -6458,7 +6383,6 @@
 					ExpectServerName: "missing.com",
 				},
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedLocalError: "tls: unexpected server name",
 		})
@@ -6471,7 +6395,6 @@
 					SendServerNameAck: true,
 				},
 			},
-			tls13Variant:  ver.tls13Variant,
 			flags:         []string{"-host-name", "example.com"},
 			resumeSession: true,
 		})
@@ -6484,7 +6407,6 @@
 					SendServerNameAck: true,
 				},
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedError:      ":UNEXPECTED_EXTENSION:",
 			expectedLocalError: "remote error: unsupported extension",
@@ -6496,7 +6418,6 @@
 				MaxVersion: ver.version,
 				ServerName: "example.com",
 			},
-			tls13Variant:  ver.tls13Variant,
 			flags:         []string{"-expect-server-name", "example.com"},
 			resumeSession: true,
 		})
@@ -6513,7 +6434,6 @@
 				"-advertise-alpn", "\x03foo\x03bar\x03baz",
 				"-expect-alpn", "foo",
 			},
-			tls13Variant:          ver.tls13Variant,
 			expectedNextProto:     "foo",
 			expectedNextProtoType: alpn,
 			resumeSession:         true,
@@ -6530,7 +6450,6 @@
 			flags: []string{
 				"-advertise-alpn", "\x03foo\x03bar",
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedError:      ":INVALID_ALPN_PROTOCOL:",
 			expectedLocalError: "remote error: illegal parameter",
@@ -6549,7 +6468,6 @@
 				"-allow-unknown-alpn-protos",
 				"-expect-alpn", "baz",
 			},
-			tls13Variant: ver.tls13Variant,
 		})
 		testCases = append(testCases, testCase{
 			testType: serverTest,
@@ -6562,7 +6480,6 @@
 				"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
 				"-select-alpn", "foo",
 			},
-			tls13Variant:          ver.tls13Variant,
 			expectedNextProto:     "foo",
 			expectedNextProtoType: alpn,
 			resumeSession:         true,
@@ -6575,7 +6492,6 @@
 				NextProtos: []string{"foo", "bar", "baz"},
 			},
 			flags:             []string{"-decline-alpn"},
-			tls13Variant:      ver.tls13Variant,
 			expectNoNextProto: true,
 			resumeSession:     true,
 		})
@@ -6592,7 +6508,6 @@
 				"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
 				"-select-empty-alpn",
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedLocalError: "remote error: internal error",
 			expectedError:      ":INVALID_ALPN_PROTOCOL:",
@@ -6614,7 +6529,6 @@
 				"-select-alpn", "foo",
 				"-async",
 			},
-			tls13Variant:          ver.tls13Variant,
 			expectedNextProto:     "foo",
 			expectedNextProtoType: alpn,
 			resumeSession:         true,
@@ -6636,7 +6550,6 @@
 			flags: []string{
 				"-advertise-alpn", "\x03foo",
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":PARSE_TLSEXT:",
 		})
@@ -6652,7 +6565,6 @@
 			flags: []string{
 				"-select-alpn", "foo",
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":PARSE_TLSEXT:",
 		})
@@ -6672,7 +6584,6 @@
 					"-select-alpn", "foo",
 					"-advertise-npn", "\x03foo\x03bar\x03baz",
 				},
-				tls13Variant:          ver.tls13Variant,
 				expectedNextProto:     "foo",
 				expectedNextProtoType: alpn,
 				resumeSession:         true,
@@ -6692,7 +6603,6 @@
 					"-select-alpn", "foo",
 					"-advertise-npn", "\x03foo\x03bar\x03baz",
 				},
-				tls13Variant:          ver.tls13Variant,
 				expectedNextProto:     "foo",
 				expectedNextProtoType: alpn,
 				resumeSession:         true,
@@ -6712,7 +6622,6 @@
 					"-advertise-alpn", "\x03foo",
 					"-select-next-proto", "foo",
 				},
-				tls13Variant:  ver.tls13Variant,
 				shouldFail:    true,
 				expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:",
 			})
@@ -6730,7 +6639,6 @@
 					"-advertise-alpn", "\x03foo",
 					"-select-next-proto", "foo",
 				},
-				tls13Variant:  ver.tls13Variant,
 				shouldFail:    true,
 				expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:",
 			})
@@ -6752,7 +6660,6 @@
 			},
 			expectTokenBinding:        true,
 			expectedTokenBindingParam: 2,
-			tls13Variant:              ver.tls13Variant,
 			flags: []string{
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -6770,7 +6677,6 @@
 				TokenBindingParams:  []byte{3},
 				TokenBindingVersion: maxTokenBindingVersion,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -6786,7 +6692,6 @@
 				TokenBindingParams:  []byte{0, 1, 2},
 				TokenBindingVersion: minTokenBindingVersion - 1,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -6804,7 +6709,6 @@
 			},
 			expectTokenBinding:        true,
 			expectedTokenBindingParam: 2,
-			tls13Variant:              ver.tls13Variant,
 			flags: []string{
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -6822,7 +6726,6 @@
 				TokenBindingParams:  []byte{},
 				TokenBindingVersion: maxTokenBindingVersion,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -6842,7 +6745,6 @@
 			},
 			expectTokenBinding:        true,
 			expectedTokenBindingParam: 2,
-			tls13Variant:              ver.tls13Variant,
 			flags: []string{
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -6861,7 +6763,6 @@
 				TokenBindingVersion:      maxTokenBindingVersion,
 				ExpectTokenBindingParams: []byte{0, 1, 2},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{0, 1, 2}),
@@ -6879,7 +6780,6 @@
 				TokenBindingParams:  []byte{2},
 				TokenBindingVersion: maxTokenBindingVersion,
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":UNEXPECTED_EXTENSION:",
 		})
@@ -6900,7 +6800,6 @@
 				"-expected-token-binding-param",
 				"2",
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":ERROR_PARSING_EXTENSION:",
 		})
@@ -6921,7 +6820,6 @@
 				"-expected-token-binding-param",
 				"2",
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":ERROR_PARSING_EXTENSION:",
 		})
@@ -6942,7 +6840,6 @@
 				"-expected-token-binding-param",
 				"2",
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":ERROR_PARSING_EXTENSION:",
 		})
@@ -6961,7 +6858,6 @@
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{0, 1, 2}),
 			},
-			tls13Variant: ver.tls13Variant,
 		})
 		testCases = append(testCases, testCase{
 			testType: clientTest,
@@ -6980,7 +6876,6 @@
 				"-expected-token-binding-param",
 				"2",
 			},
-			tls13Variant: ver.tls13Variant,
 		})
 		testCases = append(testCases, testCase{
 			testType: clientTest,
@@ -6997,7 +6892,6 @@
 				"-token-binding-params",
 				base64.StdEncoding.EncodeToString([]byte{0, 1, 2}),
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: "ERROR_PARSING_EXTENSION",
 		})
@@ -7016,7 +6910,6 @@
 						NoExtendedMasterSecret: true,
 					},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-token-binding-params",
 					base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -7037,7 +6930,6 @@
 						NoExtendedMasterSecret: true,
 					},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-token-binding-params",
 					base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -7059,7 +6951,6 @@
 						NoRenegotiationInfo: true,
 					},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-token-binding-params",
 					base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -7080,7 +6971,6 @@
 						NoRenegotiationInfo: true,
 					},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-token-binding-params",
 					base64.StdEncoding.EncodeToString([]byte{2, 1, 0}),
@@ -7101,7 +6991,6 @@
 					MaxEarlyDataSize:         16384,
 				},
 				resumeSession: true,
-				tls13Variant:  ver.tls13Variant,
 				flags: []string{
 					"-enable-early-data",
 					"-expect-ticket-supports-early-data",
@@ -7124,7 +7013,6 @@
 				resumeSession:             true,
 				expectTokenBinding:        true,
 				expectedTokenBindingParam: 2,
-				tls13Variant:              ver.tls13Variant,
 				flags: []string{
 					"-enable-early-data",
 					"-expect-ticket-supports-early-data",
@@ -7145,7 +7033,6 @@
 					MaxVersion:          ver.version,
 					QUICTransportParams: []byte{1, 2},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-quic-transport-params",
 					base64.StdEncoding.EncodeToString([]byte{3, 4}),
@@ -7163,7 +7050,6 @@
 					MaxVersion:          ver.version,
 					QUICTransportParams: []byte{1, 2},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-quic-transport-params",
 					base64.StdEncoding.EncodeToString([]byte{3, 4}),
@@ -7180,7 +7066,6 @@
 					MinVersion: ver.version,
 					MaxVersion: ver.version,
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-max-version",
 					strconv.Itoa(int(ver.version)),
@@ -7196,7 +7081,6 @@
 					MaxVersion:          ver.version,
 					QUICTransportParams: []byte{1, 2},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-quic-transport-params",
 					base64.StdEncoding.EncodeToString([]byte{3, 4}),
@@ -7212,7 +7096,6 @@
 					MaxVersion:          ver.version,
 					QUICTransportParams: []byte{1, 2},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-expected-quic-transport-params",
 					base64.StdEncoding.EncodeToString([]byte{1, 2}),
@@ -7249,7 +7132,6 @@
 					},
 				},
 			},
-			tls13Variant:         ver.tls13Variant,
 			resumeSession:        true,
 			expectResumeRejected: true,
 		})
@@ -7260,7 +7142,6 @@
 			config: Config{
 				MaxVersion: ver.version,
 			},
-			tls13Variant:  ver.tls13Variant,
 			resumeSession: true,
 			flags:         []string{"-use-ticket-callback"},
 		})
@@ -7273,7 +7154,6 @@
 					ExpectNewTicket: true,
 				},
 			},
-			tls13Variant:  ver.tls13Variant,
 			flags:         []string{"-use-ticket-callback", "-renew-ticket"},
 			resumeSession: true,
 		})
@@ -7293,7 +7173,6 @@
 					},
 				},
 			},
-			tls13Variant:         ver.tls13Variant,
 			resumeSession:        true,
 			expectResumeRejected: true,
 			flags: []string{
@@ -7449,7 +7328,6 @@
 				"-expect-signed-cert-timestamps",
 				base64.StdEncoding.EncodeToString(testSCTList),
 			},
-			tls13Variant:  ver.tls13Variant,
 			resumeSession: true,
 		})
 
@@ -7472,7 +7350,6 @@
 				"-expect-signed-cert-timestamps",
 				base64.StdEncoding.EncodeToString(testSCTList),
 			},
-			tls13Variant:  ver.tls13Variant,
 			resumeSession: true,
 		})
 
@@ -7486,7 +7363,6 @@
 				"-signed-cert-timestamps",
 				base64.StdEncoding.EncodeToString(testSCTList),
 			},
-			tls13Variant:    ver.tls13Variant,
 			expectedSCTList: testSCTList,
 			resumeSession:   true,
 		})
@@ -7505,7 +7381,6 @@
 			flags: []string{
 				"-enable-signed-cert-timestamps",
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":ERROR_PARSING_EXTENSION:",
 		})
@@ -7524,7 +7399,6 @@
 			flags: []string{
 				"-enable-signed-cert-timestamps",
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":ERROR_PARSING_EXTENSION:",
 		})
@@ -7540,7 +7414,6 @@
 					NoSignedCertificateTimestamps: true,
 				},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-ocsp-response",
 				base64.StdEncoding.EncodeToString(testOCSPResponse),
@@ -7809,29 +7682,19 @@
 					suffix += "-DTLS"
 				}
 
-				// We can't resume across TLS 1.3 variants and error out earlier in the
-				// session resumption.
-				if sessionVers.tls13Variant != resumeVers.tls13Variant {
-					continue
-				}
-
 				if sessionVers.version == resumeVers.version {
 					testCases = append(testCases, testCase{
 						protocol:      protocol,
 						name:          "Resume-Client" + suffix,
 						resumeSession: true,
 						config: Config{
-							MaxVersion:   sessionVers.version,
-							TLS13Variant: sessionVers.tls13Variant,
+							MaxVersion: sessionVers.version,
 							Bugs: ProtocolBugs{
 								ExpectNoTLS13PSK: sessionVers.version < VersionTLS13,
 							},
 						},
 						expectedVersion:       sessionVers.version,
 						expectedResumeVersion: resumeVers.version,
-						flags: []string{
-							"-tls13-variant", strconv.Itoa(sessionVers.tls13Variant),
-						},
 					})
 				} else {
 					testCases = append(testCases, testCase{
@@ -7839,13 +7702,11 @@
 						name:          "Resume-Client-Mismatch" + suffix,
 						resumeSession: true,
 						config: Config{
-							MaxVersion:   sessionVers.version,
-							TLS13Variant: sessionVers.tls13Variant,
+							MaxVersion: sessionVers.version,
 						},
 						expectedVersion: sessionVers.version,
 						resumeConfig: &Config{
-							MaxVersion:   resumeVers.version,
-							TLS13Variant: resumeVers.tls13Variant,
+							MaxVersion: resumeVers.version,
 							Bugs: ProtocolBugs{
 								AcceptAnySession: true,
 							},
@@ -7853,10 +7714,6 @@
 						expectedResumeVersion: resumeVers.version,
 						shouldFail:            true,
 						expectedError:         ":OLD_SESSION_VERSION_NOT_RETURNED:",
-						flags: []string{
-							"-on-initial-tls13-variant", strconv.Itoa(sessionVers.tls13Variant),
-							"-on-resume-tls13-variant", strconv.Itoa(resumeVers.tls13Variant),
-						},
 					})
 				}
 
@@ -7865,21 +7722,15 @@
 					name:          "Resume-Client-NoResume" + suffix,
 					resumeSession: true,
 					config: Config{
-						MaxVersion:   sessionVers.version,
-						TLS13Variant: sessionVers.tls13Variant,
+						MaxVersion: sessionVers.version,
 					},
 					expectedVersion: sessionVers.version,
 					resumeConfig: &Config{
-						MaxVersion:   resumeVers.version,
-						TLS13Variant: resumeVers.tls13Variant,
+						MaxVersion: resumeVers.version,
 					},
 					newSessionsOnResume:   true,
 					expectResumeRejected:  true,
 					expectedResumeVersion: resumeVers.version,
-					flags: []string{
-						"-on-initial-tls13-variant", strconv.Itoa(sessionVers.tls13Variant),
-						"-on-resume-tls13-variant", strconv.Itoa(resumeVers.tls13Variant),
-					},
 				})
 
 				testCases = append(testCases, testCase{
@@ -7888,23 +7739,17 @@
 					name:          "Resume-Server" + suffix,
 					resumeSession: true,
 					config: Config{
-						MaxVersion:   sessionVers.version,
-						TLS13Variant: sessionVers.tls13Variant,
+						MaxVersion: sessionVers.version,
 					},
 					expectedVersion:      sessionVers.version,
 					expectResumeRejected: sessionVers != resumeVers,
 					resumeConfig: &Config{
-						MaxVersion:   resumeVers.version,
-						TLS13Variant: resumeVers.tls13Variant,
+						MaxVersion: resumeVers.version,
 						Bugs: ProtocolBugs{
 							SendBothTickets: true,
 						},
 					},
 					expectedResumeVersion: resumeVers.version,
-					flags: []string{
-						"-on-initial-tls13-variant", strconv.Itoa(sessionVers.tls13Variant),
-						"-on-resume-tls13-variant", strconv.Itoa(resumeVers.tls13Variant),
-					},
 				})
 
 				// Repeat the test using session IDs, rather than tickets.
@@ -8352,15 +8197,14 @@
 		},
 	})
 	testCases = append(testCases, testCase{
-		name: "Renegotiate-Client-TLS13Draft23",
+		name: "Renegotiate-Client-TLS12",
 		config: Config{
 			MaxVersion: VersionTLS12,
 			Bugs: ProtocolBugs{
 				FailIfResumeOnRenego: true,
 			},
 		},
-		tls13Variant: TLS13Draft23,
-		renegotiate:  1,
+		renegotiate: 1,
 		// Test renegotiation after both an initial and resumption
 		// handshake.
 		resumeSession: true,
@@ -8970,7 +8814,6 @@
 					"-enable-all-curves",
 					"-enable-ed25519",
 				},
-				tls13Variant:                   ver.tls13Variant,
 				shouldFail:                     shouldSignFail,
 				expectedError:                  signError,
 				expectedLocalError:             signLocalError,
@@ -8993,7 +8836,6 @@
 						IgnorePeerSignatureAlgorithmPreferences: shouldVerifyFail,
 					},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-require-any-client-certificate",
 					"-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)),
@@ -9020,7 +8862,6 @@
 						fakeSigAlg2,
 					},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
 					"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
@@ -9049,7 +8890,6 @@
 						IgnorePeerSignatureAlgorithmPreferences: shouldVerifyFail,
 					},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)),
 					"-enable-all-curves",
@@ -9077,7 +8917,6 @@
 							InvalidSignature: true,
 						},
 					},
-					tls13Variant: ver.tls13Variant,
 					flags: []string{
 						"-require-any-client-certificate",
 						"-enable-all-curves",
@@ -9100,7 +8939,6 @@
 							InvalidSignature: true,
 						},
 					},
-					tls13Variant: ver.tls13Variant,
 					flags: []string{
 						"-enable-all-curves",
 						"-enable-ed25519",
@@ -9118,7 +8956,6 @@
 						ClientAuth:                RequireAnyClientCert,
 						VerifySignatureAlgorithms: allAlgorithms,
 					},
-					tls13Variant: ver.tls13Variant,
 					flags: []string{
 						"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
 						"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
@@ -9137,7 +8974,6 @@
 						CipherSuites:              signingCiphers,
 						VerifySignatureAlgorithms: allAlgorithms,
 					},
-					tls13Variant: ver.tls13Variant,
 					flags: []string{
 						"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
 						"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
@@ -9167,7 +9003,6 @@
 					signatureECDSAWithP256AndSHA256,
 				},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
 				"-key-file", path.Join(*resourceDir, rsaKeyFile),
@@ -9188,7 +9023,6 @@
 					signatureECDSAWithP256AndSHA256,
 				},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
 				"-key-file", path.Join(*resourceDir, rsaKeyFile),
@@ -10006,7 +9840,6 @@
 						ExpectRSAPSSSupport: expect,
 					},
 				},
-				tls13Variant:       ver.tls13Variant,
 				flags:              flags,
 				shouldFail:         shouldFail,
 				expectedLocalError: localError,
@@ -10025,7 +9858,6 @@
 						ExpectRSAPSSSupport: expect,
 					},
 				},
-				tls13Variant:       ver.tls13Variant,
 				flags:              serverFlags,
 				shouldFail:         shouldFail,
 				expectedLocalError: localError,
@@ -10253,7 +10085,6 @@
 			// Test the exporter in both initial and resumption
 			// handshakes.
 			resumeSession:        true,
-			tls13Variant:         vers.tls13Variant,
 			exportKeyingMaterial: 1024,
 			exportLabel:          "label",
 			exportContext:        "context",
@@ -10264,7 +10095,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant:         vers.tls13Variant,
 			exportKeyingMaterial: 1024,
 		})
 		testCases = append(testCases, testCase{
@@ -10272,7 +10102,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant:         vers.tls13Variant,
 			exportKeyingMaterial: 1024,
 			useExportContext:     true,
 		})
@@ -10281,7 +10110,6 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
-			tls13Variant:         vers.tls13Variant,
 			exportKeyingMaterial: 1,
 			exportLabel:          "label",
 			exportContext:        "context",
@@ -10298,7 +10126,6 @@
 					MaxEarlyDataSize: 16384,
 				},
 				resumeSession: true,
-				tls13Variant:  vers.tls13Variant,
 				flags: []string{
 					"-enable-early-data",
 					"-expect-ticket-supports-early-data",
@@ -10330,7 +10157,6 @@
 					},
 				},
 				resumeSession: true,
-				tls13Variant:  vers.tls13Variant,
 				flags: []string{
 					"-enable-early-data",
 					"-expect-ticket-supports-early-data",
@@ -10355,7 +10181,6 @@
 					MaxEarlyDataSize: 16384,
 				},
 				resumeSession:             true,
-				tls13Variant:              vers.tls13Variant,
 				exportEarlyKeyingMaterial: 1024,
 				exportLabel:               "label",
 				exportContext:             "context",
@@ -10376,7 +10201,6 @@
 				config: Config{
 					MaxVersion: vers.version,
 				},
-				tls13Variant:  vers.tls13Variant,
 				flags:         []string{"-export-early-keying-material", "1024"},
 				shouldFail:    true,
 				expectedError: ":EARLY_DATA_NOT_IN_USE:",
@@ -10387,7 +10211,6 @@
 					MaxVersion: vers.version,
 				},
 				resumeSession: true,
-				tls13Variant:  vers.tls13Variant,
 				flags:         []string{"-on-resume-export-early-keying-material", "1024"},
 				shouldFail:    true,
 				expectedError: ":EARLY_DATA_NOT_IN_USE:",
@@ -10405,7 +10228,6 @@
 					},
 				},
 				resumeSession: true,
-				tls13Variant:  vers.tls13Variant,
 				flags: []string{
 					"-enable-early-data",
 					"-expect-ticket-supports-early-data",
@@ -10427,7 +10249,6 @@
 						ExpectEarlyDataAccepted: true,
 					},
 				},
-				tls13Variant:         vers.tls13Variant,
 				resumeSession:        true,
 				exportKeyingMaterial: 1024,
 				exportLabel:          "label",
@@ -10447,7 +10268,6 @@
 						ExpectEarlyDataAccepted: true,
 					},
 				},
-				tls13Variant:              vers.tls13Variant,
 				resumeSession:             true,
 				exportEarlyKeyingMaterial: 1024,
 				exportLabel:               "label",
@@ -10463,7 +10283,6 @@
 				config: Config{
 					MaxVersion: vers.version,
 				},
-				tls13Variant:  vers.tls13Variant,
 				flags:         []string{"-export-early-keying-material", "1024"},
 				shouldFail:    true,
 				expectedError: ":EARLY_DATA_NOT_IN_USE:",
@@ -10475,7 +10294,6 @@
 					MaxVersion: vers.version,
 				},
 				resumeSession: true,
-				tls13Variant:  vers.tls13Variant,
 				flags:         []string{"-on-resume-export-early-keying-material", "1024"},
 				shouldFail:    true,
 				expectedError: ":EARLY_DATA_NOT_IN_USE:",
@@ -10488,7 +10306,6 @@
 					MaxVersion: vers.version,
 				},
 				resumeSession:             true,
-				tls13Variant:              vers.tls13Variant,
 				exportEarlyKeyingMaterial: 1024,
 				exportLabel:               "label",
 				exportContext:             "context",
@@ -10502,7 +10319,6 @@
 					MaxVersion: vers.version,
 				},
 				resumeSession:             true,
-				tls13Variant:              vers.tls13Variant,
 				exportEarlyKeyingMaterial: 1024,
 				exportLabel:               "label",
 				exportContext:             "context",
@@ -10788,7 +10604,6 @@
 					},
 					CurvePreferences: []CurveID{curve.id},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-enable-all-curves",
 					"-expect-curve-id", strconv.Itoa(int(curve.id)),
@@ -10807,7 +10622,6 @@
 					},
 					CurvePreferences: []CurveID{curve.id},
 				},
-				tls13Variant: ver.tls13Variant,
 				flags: []string{
 					"-enable-all-curves",
 					"-expect-curve-id", strconv.Itoa(int(curve.id)),
@@ -10830,7 +10644,6 @@
 							SendCompressedCoordinates: true,
 						},
 					},
-					tls13Variant:  ver.tls13Variant,
 					flags:         []string{"-enable-all-curves"},
 					shouldFail:    true,
 					expectedError: ":BAD_ECPOINT:",
@@ -10850,7 +10663,6 @@
 							SendCompressedCoordinates: true,
 						},
 					},
-					tls13Variant:  ver.tls13Variant,
 					flags:         []string{"-enable-all-curves"},
 					shouldFail:    true,
 					expectedError: ":BAD_ECPOINT:",
@@ -11613,7 +11425,6 @@
 				},
 			},
 			resumeSession: useStatefulResumption,
-			tls13Variant:  ver.tls13Variant,
 			flags:         []string{"-no-ticket"},
 		})
 
@@ -11625,7 +11436,6 @@
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
 			},
-			tls13Variant:         ver.tls13Variant,
 			resumeSession:        true,
 			expectResumeRejected: true,
 			// Set SSL_OP_NO_TICKET on the second connection, after the first
@@ -12255,7 +12065,7 @@
 		messageType: typeEndOfEarlyData,
 		test: testCase{
 			testType: serverTest,
-			name:     "TLS13Draft23-EndOfEarlyData",
+			name:     "TLS13-EndOfEarlyData",
 			config: Config{
 				MaxVersion: VersionTLS13,
 			},
@@ -12266,7 +12076,6 @@
 					ExpectEarlyDataAccepted: true,
 				},
 			},
-			tls13Variant:  TLS13Draft23,
 			resumeSession: true,
 			flags:         []string{"-enable-early-data"},
 		},
@@ -12345,1637 +12154,1539 @@
 }
 
 func addTLS13HandshakeTests() {
-	for _, version := range allVersions(tls) {
-		if version.version != VersionTLS13 {
-			continue
-		}
-		name := version.name
-		variant := version.tls13Variant
-
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "NegotiatePSKResumption-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					NegotiatePSKResumption: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "NegotiatePSKResumption-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				NegotiatePSKResumption: true,
 			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			shouldFail:    true,
-			expectedError: ":MISSING_KEY_SHARE:",
-		})
+		},
+		resumeSession: true,
+		shouldFail:    true,
+		expectedError: ":MISSING_KEY_SHARE:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "MissingKeyShare-Client-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					MissingKeyShare: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "MissingKeyShare-Client-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				MissingKeyShare: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":MISSING_KEY_SHARE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":MISSING_KEY_SHARE:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "MissingKeyShare-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					MissingKeyShare: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "MissingKeyShare-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				MissingKeyShare: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":MISSING_KEY_SHARE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":MISSING_KEY_SHARE:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "DuplicateKeyShares-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					DuplicateKeyShares: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "DuplicateKeyShares-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				DuplicateKeyShares: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":DUPLICATE_KEY_SHARE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":DUPLICATE_KEY_SHARE:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 4,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 4,
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		// Test that enabling a TLS 1.3 variant does not interfere with
-		// TLS 1.2 session ID resumption.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "ResumeTLS12SessionID-" + name,
-			config: Config{
-				MaxVersion:             VersionTLS12,
-				SessionTicketsDisabled: true,
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-		})
+	// Test that enabling TLS 1.3 does not interfere with TLS 1.2 session ID
+	// resumption.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ResumeTLS12SessionID-TLS13",
+		config: Config{
+			MaxVersion:             VersionTLS12,
+			SessionTicketsDisabled: true,
+		},
+		resumeSession: true,
+	})
 
-		// Test that the client correctly handles a TLS 1.3 ServerHello which echoes
-		// a TLS 1.2 session ID.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "TLS12SessionID-" + name,
-			config: Config{
-				MaxVersion:             VersionTLS12,
-				SessionTicketsDisabled: true,
-			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
+	// Test that the client correctly handles a TLS 1.3 ServerHello which echoes
+	// a TLS 1.2 session ID.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "TLS12SessionID-TLS13",
+		config: Config{
+			MaxVersion:             VersionTLS12,
+			SessionTicketsDisabled: true,
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+		},
+		resumeSession:        true,
+		expectResumeRejected: true,
+	})
+
+	// Test that the server correctly echoes back session IDs of
+	// various lengths. The first test additionally asserts that
+	// BoringSSL always sends the ChangeCipherSpec messages for
+	// compatibility mode, rather than negotiating it based on the
+	// ClientHello.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EmptySessionID-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendClientHelloSessionID: []byte{},
 			},
-			tls13Variant:         variant,
-			resumeSession:        true,
-			expectResumeRejected: true,
-		})
+		},
+	})
 
-		// Test that the server correctly echoes back session IDs of
-		// various lengths. The first test additionally asserts that
-		// BoringSSL always sends the ChangeCipherSpec messages for
-		// compatibility mode, rather than negotiating it based on the
-		// ClientHello.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EmptySessionID-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendClientHelloSessionID: []byte{},
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ShortSessionID-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendClientHelloSessionID: make([]byte, 16),
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "ShortSessionID-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendClientHelloSessionID: make([]byte, 16),
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "FullSessionID-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendClientHelloSessionID: make([]byte, 32),
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "FullSessionID-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendClientHelloSessionID: make([]byte, 32),
-				},
+	// Test that the client sends a fake session ID in TLS 1.3.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "TLS13SessionID-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				ExpectClientHelloSessionID: true,
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		// Test that the client sends a fake session ID in TLS 1.3.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "TLS13SessionID-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					ExpectClientHelloSessionID: true,
-				},
+	// Test that the client omits the fake session ID when the max version is TLS 1.2 and below.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "TLS12NoSessionID-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				ExpectNoTLS12Session: true,
 			},
-			tls13Variant: variant,
-		})
+		},
+		flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+	})
 
-		// Test that the client omits the fake session ID when the max version is TLS 1.2 and below.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "TLS12NoSessionID-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					ExpectNoTLS12Session: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MinVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MinVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}},
 			},
-			tls13Variant: variant,
-			flags:        []string{"-max-version", strconv.Itoa(VersionTLS12)},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-accept-early-data",
+			"-on-resume-shim-writes-first",
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MinVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-Reject-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				AlwaysRejectEarlyData: true,
 			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MinVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}},
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-accept-early-data",
-				"-on-resume-shim-writes-first",
-			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-reject-early-data",
+			"-on-resume-shim-writes-first",
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-Reject-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			MinVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: true,
+				ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
 			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					AlwaysRejectEarlyData: true,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-reject-early-data",
-				"-on-resume-shim-writes-first",
-			},
-		})
+		},
+		messageCount:  2,
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-accept-early-data",
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				MinVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: true,
-					ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
-				},
-			},
-			tls13Variant:  variant,
-			messageCount:  2,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-accept-early-data",
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-FirstTicket-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			MinVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				UseFirstSessionTicket:   true,
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: true,
+				ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
 			},
-		})
+		},
+		messageCount:  2,
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-accept-early-data",
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-FirstTicket-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				MinVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					UseFirstSessionTicket:   true,
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: true,
-					ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
-				},
-			},
-			tls13Variant:  variant,
-			messageCount:  2,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-accept-early-data",
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-OmitEarlyDataExtension-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 4,
+				OmitEarlyDataExtension:  true,
 			},
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-OmitEarlyDataExtension-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 4,
-					OmitEarlyDataExtension:  true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-TooMuchData-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 16384 + 1,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-TooMuchData-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 16384 + 1,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-Interleaved-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 4,
+				InterleaveEarlyData:     true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-Interleaved-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 4,
-					InterleaveEarlyData:     true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-EarlyDataInTLS12-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 4,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_RECORD:",
+		flags:         []string{"-max-version", strconv.Itoa(VersionTLS12)},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-EarlyDataInTLS12-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 4,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-HRR-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 4,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":UNEXPECTED_RECORD:",
-			flags:         []string{"-max-version", strconv.Itoa(VersionTLS12)},
-		})
+			DefaultCurves: []CurveID{},
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-HRR-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 4,
-				},
-				DefaultCurves: []CurveID{},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-HRR-Interleaved-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 4,
+				InterleaveEarlyData:     true,
 			},
-			tls13Variant: variant,
-		})
+			DefaultCurves: []CurveID{},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_RECORD:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-HRR-Interleaved-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 4,
-					InterleaveEarlyData:     true,
-				},
-				DefaultCurves: []CurveID{},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-HRR-TooMuchData-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendFakeEarlyDataLength: 16384 + 1,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":UNEXPECTED_RECORD:",
-		})
+			DefaultCurves: []CurveID{},
+		},
+		shouldFail:    true,
+		expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-HRR-TooMuchData-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendFakeEarlyDataLength: 16384 + 1,
-				},
-				DefaultCurves: []CurveID{},
+	// Test that skipping early data looking for cleartext correctly
+	// processes an alert record.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-HRR-FatalAlert-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyAlert:          true,
+				SendFakeEarlyDataLength: 4,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
-		})
+			DefaultCurves: []CurveID{},
+		},
+		shouldFail:    true,
+		expectedError: ":SSLV3_ALERT_HANDSHAKE_FAILURE:",
+	})
 
-		// Test that skipping early data looking for cleartext correctly
-		// processes an alert record.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-HRR-FatalAlert-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyAlert:          true,
-					SendFakeEarlyDataLength: 4,
-				},
-				DefaultCurves: []CurveID{},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipEarlyData-SecondClientHelloEarlyData-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyDataOnSecondClientHello: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":SSLV3_ALERT_HANDSHAKE_FAILURE:",
-		})
+			DefaultCurves: []CurveID{},
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: bad record MAC",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipEarlyData-SecondClientHelloEarlyData-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyDataOnSecondClientHello: true,
-				},
-				DefaultCurves: []CurveID{},
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EmptyEncryptedExtensions-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				EmptyEncryptedExtensions: true,
 			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedLocalError: "remote error: bad record MAC",
-		})
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: error decoding message",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EmptyEncryptedExtensions-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					EmptyEncryptedExtensions: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EncryptedExtensionsWithKeyShare-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				EncryptedExtensionsWithKeyShare: true,
 			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedLocalError: "remote error: error decoding message",
-		})
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: unsupported extension",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EncryptedExtensionsWithKeyShare-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					EncryptedExtensionsWithKeyShare: true,
-				},
-			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedLocalError: "remote error: unsupported extension",
-		})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SendHelloRetryRequest-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// Require a HelloRetryRequest for every curve.
+			DefaultCurves:    []CurveID{},
+			CurvePreferences: []CurveID{CurveX25519},
+		},
+		expectedCurveID: CurveX25519,
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SendHelloRetryRequest-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// Require a HelloRetryRequest for every curve.
-				DefaultCurves: []CurveID{},
-			},
-			tls13Variant:    variant,
-			expectedCurveID: CurveX25519,
-		})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SendHelloRetryRequest-2-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			DefaultCurves:    []CurveID{CurveP384},
+			CurvePreferences: []CurveID{CurveX25519, CurveP384},
+		},
+		// Although the ClientHello did not predict our preferred curve,
+		// we always select it whether it is predicted or not.
+		expectedCurveID: CurveX25519,
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SendHelloRetryRequest-2-" + name,
-			config: Config{
-				MaxVersion:    VersionTLS13,
-				DefaultCurves: []CurveID{CurveP384},
+	testCases = append(testCases, testCase{
+		name: "UnknownCurve-HelloRetryRequest-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCurve: bogusCurve,
 			},
-			tls13Variant: variant,
-			// Although the ClientHello did not predict our preferred curve,
-			// we always select it whether it is predicted or not.
-			expectedCurveID: CurveX25519,
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "UnknownCurve-HelloRetryRequest-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCurve: bogusCurve,
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-CipherChange-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				SendCipherSuite:                  TLS_AES_128_GCM_SHA256,
+				SendHelloRetryRequestCipherSuite: TLS_CHACHA20_POLY1305_SHA256,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":WRONG_CURVE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CIPHER_RETURNED:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-CipherChange-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					SendCipherSuite:                  TLS_AES_128_GCM_SHA256,
-					SendHelloRetryRequestCipherSuite: TLS_CHACHA20_POLY1305_SHA256,
-				},
+	// Test that the client does not offer a PSK in the second ClientHello if the
+	// HelloRetryRequest is incompatible with it.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "HelloRetryRequest-NonResumableCipher-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			CipherSuites: []uint16{
+				TLS_AES_128_GCM_SHA256,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":WRONG_CIPHER_RETURNED:",
-		})
-
-		// Test that the client does not offer a PSK in the second ClientHello if the
-		// HelloRetryRequest is incompatible with it.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "HelloRetryRequest-NonResumableCipher-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				CipherSuites: []uint16{
-					TLS_AES_128_GCM_SHA256,
-				},
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				ExpectNoTLS13PSKAfterHRR: true,
 			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					ExpectNoTLS13PSKAfterHRR: true,
-				},
-				CipherSuites: []uint16{
-					TLS_AES_256_GCM_SHA384,
-				},
+			CipherSuites: []uint16{
+				TLS_AES_256_GCM_SHA384,
 			},
-			tls13Variant:         variant,
-			resumeSession:        true,
-			expectResumeRejected: true,
-		})
+		},
+		resumeSession:        true,
+		expectResumeRejected: true,
+	})
 
-		testCases = append(testCases, testCase{
-			name: "DisabledCurve-HelloRetryRequest-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				CurvePreferences: []CurveID{CurveP256},
-				Bugs: ProtocolBugs{
-					IgnorePeerCurvePreferences: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "DisabledCurve-HelloRetryRequest-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			CurvePreferences: []CurveID{CurveP256},
+			Bugs: ProtocolBugs{
+				IgnorePeerCurvePreferences: true,
 			},
-			tls13Variant:  variant,
-			flags:         []string{"-curves", strconv.Itoa(int(CurveP384))},
-			shouldFail:    true,
-			expectedError: ":WRONG_CURVE:",
-		})
+		},
+		flags:         []string{"-curves", strconv.Itoa(int(CurveP384))},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "UnnecessaryHelloRetryRequest-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				CurvePreferences: []CurveID{CurveX25519},
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCurve: CurveX25519,
-				},
+	testCases = append(testCases, testCase{
+		name: "UnnecessaryHelloRetryRequest-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			CurvePreferences: []CurveID{CurveX25519},
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCurve: CurveX25519,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":WRONG_CURVE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "SecondHelloRetryRequest-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					SecondHelloRetryRequest: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "SecondHelloRetryRequest-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				SecondHelloRetryRequest: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":UNEXPECTED_MESSAGE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_MESSAGE:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-Empty-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					AlwaysSendHelloRetryRequest: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-Empty-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				AlwaysSendHelloRetryRequest: true,
 			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedError:      ":EMPTY_HELLO_RETRY_REQUEST:",
-			expectedLocalError: "remote error: illegal parameter",
-		})
+		},
+		shouldFail:         true,
+		expectedError:      ":EMPTY_HELLO_RETRY_REQUEST:",
+		expectedLocalError: "remote error: illegal parameter",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-DuplicateCurve-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires a HelloRetryRequest against BoringSSL's default
-				// configuration. Assert this ExpectMissingKeyShare.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					ExpectMissingKeyShare:                true,
-					DuplicateHelloRetryRequestExtensions: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-DuplicateCurve-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires a HelloRetryRequest against BoringSSL's default
+			// configuration. Assert this ExpectMissingKeyShare.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				ExpectMissingKeyShare:                true,
+				DuplicateHelloRetryRequestExtensions: true,
 			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedError:      ":DUPLICATE_EXTENSION:",
-			expectedLocalError: "remote error: illegal parameter",
-		})
+		},
+		shouldFail:         true,
+		expectedError:      ":DUPLICATE_EXTENSION:",
+		expectedLocalError: "remote error: illegal parameter",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-Cookie-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCookie: []byte("cookie"),
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-Cookie-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCookie: []byte("cookie"),
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-DuplicateCookie-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCookie:          []byte("cookie"),
-					DuplicateHelloRetryRequestExtensions: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-DuplicateCookie-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCookie:          []byte("cookie"),
+				DuplicateHelloRetryRequestExtensions: true,
 			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedError:      ":DUPLICATE_EXTENSION:",
-			expectedLocalError: "remote error: illegal parameter",
-		})
+		},
+		shouldFail:         true,
+		expectedError:      ":DUPLICATE_EXTENSION:",
+		expectedLocalError: "remote error: illegal parameter",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-EmptyCookie-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCookie: []byte{},
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-EmptyCookie-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCookie: []byte{},
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":DECODE_ERROR:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":DECODE_ERROR:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-Cookie-Curve-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCookie: []byte("cookie"),
-					ExpectMissingKeyShare:       true,
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-Cookie-Curve-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCookie: []byte("cookie"),
+				ExpectMissingKeyShare:       true,
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequest-Unknown-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					CustomHelloRetryRequestExtension: "extension",
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequest-Unknown-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				CustomHelloRetryRequestExtension: "extension",
 			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedError:      ":UNEXPECTED_EXTENSION:",
-			expectedLocalError: "remote error: unsupported extension",
-		})
+		},
+		shouldFail:         true,
+		expectedError:      ":UNEXPECTED_EXTENSION:",
+		expectedLocalError: "remote error: unsupported extension",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SecondClientHelloMissingKeyShare-" + name,
-			config: Config{
-				MaxVersion:    VersionTLS13,
-				DefaultCurves: []CurveID{},
-				Bugs: ProtocolBugs{
-					SecondClientHelloMissingKeyShare: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SecondClientHelloMissingKeyShare-TLS13",
+		config: Config{
+			MaxVersion:    VersionTLS13,
+			DefaultCurves: []CurveID{},
+			Bugs: ProtocolBugs{
+				SecondClientHelloMissingKeyShare: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":MISSING_KEY_SHARE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":MISSING_KEY_SHARE:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SecondClientHelloWrongCurve-" + name,
-			config: Config{
-				MaxVersion:    VersionTLS13,
-				DefaultCurves: []CurveID{},
-				Bugs: ProtocolBugs{
-					MisinterpretHelloRetryRequestCurve: CurveP521,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SecondClientHelloWrongCurve-TLS13",
+		config: Config{
+			MaxVersion:    VersionTLS13,
+			DefaultCurves: []CurveID{},
+			Bugs: ProtocolBugs{
+				MisinterpretHelloRetryRequestCurve: CurveP521,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":WRONG_CURVE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequestVersionMismatch-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					SendServerHelloVersion: 0x0305,
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequestVersionMismatch-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				SendServerHelloVersion: 0x0305,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":WRONG_VERSION_NUMBER:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_VERSION_NUMBER:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "HelloRetryRequestCurveMismatch-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					// Send P-384 (correct) in the HelloRetryRequest.
-					SendHelloRetryRequestCurve: CurveP384,
-					// But send P-256 in the ServerHello.
-					SendCurve: CurveP256,
-				},
+	testCases = append(testCases, testCase{
+		name: "HelloRetryRequestCurveMismatch-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				// Send P-384 (correct) in the HelloRetryRequest.
+				SendHelloRetryRequestCurve: CurveP384,
+				// But send P-256 in the ServerHello.
+				SendCurve: CurveP256,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":WRONG_CURVE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	})
 
-		// Test the server selecting a curve that requires a HelloRetryRequest
-		// without sending it.
-		testCases = append(testCases, testCase{
-			name: "SkipHelloRetryRequest-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				// P-384 requires HelloRetryRequest in BoringSSL.
-				CurvePreferences: []CurveID{CurveP384},
-				Bugs: ProtocolBugs{
-					SkipHelloRetryRequest: true,
-				},
+	// Test the server selecting a curve that requires a HelloRetryRequest
+	// without sending it.
+	testCases = append(testCases, testCase{
+		name: "SkipHelloRetryRequest-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				SkipHelloRetryRequest: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":WRONG_CURVE:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	})
 
-		// Test that the supported_versions extension is enforced in the
-		// second ServerHello. Note we only enforce this starting draft 28.
-		if isDraft28(version.versionWire) {
-			testCases = append(testCases, testCase{
-				name: "SecondServerHelloNoVersion-" + name,
-				config: Config{
-					MaxVersion: VersionTLS13,
-					// P-384 requires HelloRetryRequest in BoringSSL.
-					CurvePreferences: []CurveID{CurveP384},
-					Bugs: ProtocolBugs{
-						OmitServerSupportedVersionExtension: true,
-					},
-				},
-				tls13Variant:  variant,
-				shouldFail:    true,
-				expectedError: ":SECOND_SERVERHELLO_VERSION_MISMATCH:",
-			})
-			testCases = append(testCases, testCase{
-				name: "SecondServerHelloWrongVersion-" + name,
-				config: Config{
-					MaxVersion: VersionTLS13,
-					// P-384 requires HelloRetryRequest in BoringSSL.
-					CurvePreferences: []CurveID{CurveP384},
-					Bugs: ProtocolBugs{
-						SendServerSupportedVersionExtension: 0x1234,
-					},
-				},
-				tls13Variant:  variant,
-				shouldFail:    true,
-				expectedError: ":SECOND_SERVERHELLO_VERSION_MISMATCH:",
-			})
-		}
-
-		testCases = append(testCases, testCase{
-			name: "RequestContextInHandshake-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				MinVersion: VersionTLS13,
-				ClientAuth: RequireAnyClientCert,
-				Bugs: ProtocolBugs{
-					SendRequestContext: []byte("request context"),
-				},
+	testCases = append(testCases, testCase{
+		name: "SecondServerHelloNoVersion-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				OmitServerSupportedVersionExtension: true,
 			},
-			tls13Variant: variant,
-			flags: []string{
-				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
-				"-key-file", path.Join(*resourceDir, rsaKeyFile),
+		},
+		shouldFail:    true,
+		expectedError: ":SECOND_SERVERHELLO_VERSION_MISMATCH:",
+	})
+	testCases = append(testCases, testCase{
+		name: "SecondServerHelloWrongVersion-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// P-384 requires HelloRetryRequest in BoringSSL.
+			CurvePreferences: []CurveID{CurveP384},
+			Bugs: ProtocolBugs{
+				SendServerSupportedVersionExtension: 0x1234,
 			},
-			shouldFail:    true,
-			expectedError: ":DECODE_ERROR:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":SECOND_SERVERHELLO_VERSION_MISMATCH:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "UnknownExtensionInCertificateRequest-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				MinVersion: VersionTLS13,
-				ClientAuth: RequireAnyClientCert,
-				Bugs: ProtocolBugs{
-					SendCustomCertificateRequest: 0x1212,
-				},
+	testCases = append(testCases, testCase{
+		name: "RequestContextInHandshake-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			MinVersion: VersionTLS13,
+			ClientAuth: RequireAnyClientCert,
+			Bugs: ProtocolBugs{
+				SendRequestContext: []byte("request context"),
 			},
-			tls13Variant: variant,
-			flags: []string{
-				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
-				"-key-file", path.Join(*resourceDir, rsaKeyFile),
+		},
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaKeyFile),
+		},
+		shouldFail:    true,
+		expectedError: ":DECODE_ERROR:",
+	})
+
+	testCases = append(testCases, testCase{
+		name: "UnknownExtensionInCertificateRequest-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			MinVersion: VersionTLS13,
+			ClientAuth: RequireAnyClientCert,
+			Bugs: ProtocolBugs{
+				SendCustomCertificateRequest: 0x1212,
 			},
-		})
+		},
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaKeyFile),
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			name: "MissingSignatureAlgorithmsInCertificateRequest-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				MinVersion: VersionTLS13,
-				ClientAuth: RequireAnyClientCert,
-				Bugs: ProtocolBugs{
-					OmitCertificateRequestAlgorithms: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "MissingSignatureAlgorithmsInCertificateRequest-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			MinVersion: VersionTLS13,
+			ClientAuth: RequireAnyClientCert,
+			Bugs: ProtocolBugs{
+				OmitCertificateRequestAlgorithms: true,
 			},
-			tls13Variant: variant,
-			flags: []string{
-				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
-				"-key-file", path.Join(*resourceDir, rsaKeyFile),
-			},
-			shouldFail:    true,
-			expectedError: ":DECODE_ERROR:",
-		})
+		},
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaKeyFile),
+		},
+		shouldFail:    true,
+		expectedError: ":DECODE_ERROR:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "TrailingKeyShareData-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					TrailingKeyShareData: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TrailingKeyShareData-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				TrailingKeyShareData: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":DECODE_ERROR:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":DECODE_ERROR:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "AlwaysSelectPSKIdentity-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					AlwaysSelectPSKIdentity: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "AlwaysSelectPSKIdentity-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				AlwaysSelectPSKIdentity: true,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":UNEXPECTED_EXTENSION:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "InvalidPSKIdentity-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SelectPSKIdentityOnResume: 1,
-				},
+	testCases = append(testCases, testCase{
+		name: "InvalidPSKIdentity-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SelectPSKIdentityOnResume: 1,
 			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			shouldFail:    true,
-			expectedError: ":PSK_IDENTITY_NOT_FOUND:",
-		})
+		},
+		resumeSession: true,
+		shouldFail:    true,
+		expectedError: ":PSK_IDENTITY_NOT_FOUND:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "ExtraPSKIdentity-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					ExtraPSKIdentity:   true,
-					SendExtraPSKBinder: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ExtraPSKIdentity-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				ExtraPSKIdentity:   true,
+				SendExtraPSKBinder: true,
 			},
-			tls13Variant:  variant,
-			resumeSession: true,
-		})
+		},
+		resumeSession: true,
+	})
 
-		// Test that unknown NewSessionTicket extensions are tolerated.
-		testCases = append(testCases, testCase{
-			name: "CustomTicketExtension-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					CustomTicketExtension: "1234",
-				},
+	// Test that unknown NewSessionTicket extensions are tolerated.
+	testCases = append(testCases, testCase{
+		name: "CustomTicketExtension-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				CustomTicketExtension: "1234",
 			},
-			tls13Variant: variant,
-		})
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-RejectTicket-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Certificates:     []Certificate{rsaCertificate},
-			},
-			resumeConfig: &Config{
-				MaxVersion:             VersionTLS13,
-				MaxEarlyDataSize:       16384,
-				Certificates:           []Certificate{ecdsaP256Certificate},
-				SessionTicketsDisabled: true,
-			},
-			tls13Variant:         variant,
-			resumeSession:        true,
-			expectResumeRejected: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-reject-early-data",
-				"-on-resume-shim-writes-first",
-				"-on-initial-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile),
-				"-on-resume-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile),
-				"-on-retry-expect-peer-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
-				// Session tickets are disabled, so the runner will not send a ticket.
-				"-on-retry-expect-no-session",
-			},
-		})
+		},
+	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-RejectTicket-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Certificates:     []Certificate{rsaCertificate},
+		},
+		resumeConfig: &Config{
+			MaxVersion:             VersionTLS13,
+			MaxEarlyDataSize:       16384,
+			Certificates:           []Certificate{ecdsaP256Certificate},
+			SessionTicketsDisabled: true,
+		},
+		resumeSession:        true,
+		expectResumeRejected: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-reject-early-data",
+			"-on-resume-shim-writes-first",
+			"-on-initial-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+			"-on-resume-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+			"-on-retry-expect-peer-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+			// Session tickets are disabled, so the runner will not send a ticket.
+			"-on-retry-expect-no-session",
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-HRR-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-HRR-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
 			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-reject-early-data",
-			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-reject-early-data",
+		},
+	})
 
-		// The client must check the server does not send the early_data
-		// extension while rejecting the session.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyDataWithoutResume-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
+	// The client must check the server does not send the early_data
+	// extension while rejecting the session.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyDataWithoutResume-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:             VersionTLS13,
+			SessionTicketsDisabled: true,
+			Bugs: ProtocolBugs{
+				SendEarlyDataExtension: true,
 			},
-			resumeConfig: &Config{
-				MaxVersion:             VersionTLS13,
-				SessionTicketsDisabled: true,
-				Bugs: ProtocolBugs{
-					SendEarlyDataExtension: true,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-			},
-			shouldFail:    true,
-			expectedError: ":UNEXPECTED_EXTENSION:",
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
 
-		// The client must fail with a dedicated error code if the server
-		// responds with TLS 1.2 when offering 0-RTT.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyDataVersionDowngrade-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS12,
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-			},
-			shouldFail:    true,
-			expectedError: ":WRONG_VERSION_ON_EARLY_DATA:",
-		})
+	// The client must fail with a dedicated error code if the server
+	// responds with TLS 1.2 when offering 0-RTT.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyDataVersionDowngrade-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS12,
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_VERSION_ON_EARLY_DATA:",
+	})
 
-		// Test that the client rejects an (unsolicited) early_data extension if
-		// the server sent an HRR.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "ServerAcceptsEarlyDataOnHRR-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
+	// Test that the client rejects an (unsolicited) early_data extension if
+	// the server sent an HRR.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ServerAcceptsEarlyDataOnHRR-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
+				SendEarlyDataExtension:      true,
 			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
-					SendEarlyDataExtension:      true,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-reject-early-data",
-			},
-			shouldFail:    true,
-			expectedError: ":UNEXPECTED_EXTENSION:",
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-reject-early-data",
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "SkipChangeCipherSpec-Client-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SkipChangeCipherSpec: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "SkipChangeCipherSpec-Client-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SkipChangeCipherSpec: true,
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "SkipChangeCipherSpec-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SkipChangeCipherSpec: true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SkipChangeCipherSpec-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SkipChangeCipherSpec: true,
 			},
-			tls13Variant: variant,
-		})
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "TooManyChangeCipherSpec-Client-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendExtraChangeCipherSpec: 33,
-				},
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "TooManyChangeCipherSpec-Client-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendExtraChangeCipherSpec: 33,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "TooManyChangeCipherSpec-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendExtraChangeCipherSpec: 33,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TooManyChangeCipherSpec-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendExtraChangeCipherSpec: 33,
 			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
-		})
+		},
+		shouldFail:    true,
+		expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+	})
 
-		testCases = append(testCases, testCase{
-			name: "SendPostHandshakeChangeCipherSpec-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendPostHandshakeChangeCipherSpec: true,
-				},
+	testCases = append(testCases, testCase{
+		name: "SendPostHandshakeChangeCipherSpec-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendPostHandshakeChangeCipherSpec: true,
 			},
-			tls13Variant:       variant,
-			shouldFail:         true,
-			expectedError:      ":UNEXPECTED_RECORD:",
-			expectedLocalError: "remote error: unexpected message",
-		})
+		},
+		shouldFail:         true,
+		expectedError:      ":UNEXPECTED_RECORD:",
+		expectedLocalError: "remote error: unexpected message",
+	})
 
-		fooString := "foo"
-		barString := "bar"
+	fooString := "foo"
+	barString := "bar"
 
-		// Test that the client reports the correct ALPN after a 0-RTT reject
-		// that changed it.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-ALPNMismatch-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					ALPNProtocol: &fooString,
-				},
+	// Test that the client reports the correct ALPN after a 0-RTT reject
+	// that changed it.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-ALPNMismatch-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				ALPNProtocol: &fooString,
 			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					ALPNProtocol: &barString,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-advertise-alpn", "\x03foo\x03bar",
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-reject-early-data",
-				"-on-initial-expect-alpn", "foo",
-				"-on-resume-expect-alpn", "foo",
-				"-on-retry-expect-alpn", "bar",
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				ALPNProtocol: &barString,
 			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-advertise-alpn", "\x03foo\x03bar",
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-reject-early-data",
+			"-on-initial-expect-alpn", "foo",
+			"-on-resume-expect-alpn", "foo",
+			"-on-retry-expect-alpn", "bar",
+		},
+	})
 
-		// Test that the client reports the correct ALPN after a 0-RTT reject if
-		// ALPN was omitted from the first connection.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-ALPNOmitted1-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				NextProtos:       []string{"foo"},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-advertise-alpn", "\x03foo\x03bar",
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-reject-early-data",
-				"-on-initial-expect-alpn", "",
-				"-on-resume-expect-alpn", "",
-				"-on-retry-expect-alpn", "foo",
-				"-on-resume-shim-writes-first",
-			},
-		})
+	// Test that the client reports the correct ALPN after a 0-RTT reject if
+	// ALPN was omitted from the first connection.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-ALPNOmitted1-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			NextProtos:       []string{"foo"},
+		},
+		resumeSession: true,
+		flags: []string{
+			"-advertise-alpn", "\x03foo\x03bar",
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-reject-early-data",
+			"-on-initial-expect-alpn", "",
+			"-on-resume-expect-alpn", "",
+			"-on-retry-expect-alpn", "foo",
+			"-on-resume-shim-writes-first",
+		},
+	})
+
+	// Test that the client reports the correct ALPN after a 0-RTT reject if
+	// ALPN was omitted from the second connection.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-ALPNOmitted2-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			NextProtos:       []string{"foo"},
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeSession: true,
+		flags: []string{
+			"-advertise-alpn", "\x03foo\x03bar",
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-reject-early-data",
+			"-on-initial-expect-alpn", "foo",
+			"-on-resume-expect-alpn", "foo",
+			"-on-retry-expect-alpn", "",
+			"-on-resume-shim-writes-first",
+		},
+	})
 
-		// Test that the client reports the correct ALPN after a 0-RTT reject if
-		// ALPN was omitted from the second connection.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-ALPNOmitted2-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				NextProtos:       []string{"foo"},
+	// Test that the client enforces ALPN match on 0-RTT accept.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-BadALPNMismatch-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				ALPNProtocol: &fooString,
 			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-advertise-alpn", "\x03foo\x03bar",
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-reject-early-data",
-				"-on-initial-expect-alpn", "foo",
-				"-on-resume-expect-alpn", "foo",
-				"-on-retry-expect-alpn", "",
-				"-on-resume-shim-writes-first",
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				AlwaysAcceptEarlyData: true,
+				ALPNProtocol:          &barString,
 			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-advertise-alpn", "\x03foo\x03bar",
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-on-initial-expect-alpn", "foo",
+			"-on-resume-expect-alpn", "foo",
+			"-on-retry-expect-alpn", "bar",
+		},
+		shouldFail:    true,
+		expectedError: ":ALPN_MISMATCH_ON_EARLY_DATA:",
+	})
 
-		// Test that the client enforces ALPN match on 0-RTT accept.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-BadALPNMismatch-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					ALPNProtocol: &fooString,
-				},
-			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					AlwaysAcceptEarlyData: true,
-					ALPNProtocol:          &barString,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-advertise-alpn", "\x03foo\x03bar",
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-on-initial-expect-alpn", "foo",
-				"-on-resume-expect-alpn", "foo",
-				"-on-retry-expect-alpn", "bar",
-			},
-			shouldFail:    true,
-			expectedError: ":ALPN_MISMATCH_ON_EARLY_DATA:",
-		})
+	// Test that the client does not offer early data if it is incompatible
+	// with ALPN preferences.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-ALPNPreferenceChanged-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			NextProtos:       []string{"foo", "bar"},
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-no-offer-early-data",
+			"-on-initial-advertise-alpn", "\x03foo",
+			"-on-resume-advertise-alpn", "\x03bar",
+			"-on-initial-expect-alpn", "foo",
+			"-on-resume-expect-alpn", "bar",
+		},
+	})
 
-		// Test that the client does not offer early data if it is incompatible
-		// with ALPN preferences.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-ALPNPreferenceChanged-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				NextProtos:       []string{"foo", "bar"},
+	// Test that the server correctly rejects 0-RTT when the previous
+	// session did not allow early data on resumption.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-NonZeroRTTSession-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: false,
 			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-no-offer-early-data",
-				"-on-initial-advertise-alpn", "\x03foo",
-				"-on-resume-advertise-alpn", "\x03bar",
-				"-on-initial-expect-alpn", "foo",
-				"-on-resume-expect-alpn", "bar",
-			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-on-resume-enable-early-data",
+			"-expect-reject-early-data",
+		},
+	})
 
-		// Test that the server correctly rejects 0-RTT when the previous
-		// session did not allow early data on resumption.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-NonZeroRTTSession-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
+	// Test that we reject early data where ALPN is omitted from the first
+	// connection.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-ALPNOmitted1-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			NextProtos: []string{},
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			NextProtos: []string{"foo"},
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: false,
 			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: false,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-on-resume-enable-early-data",
-				"-expect-reject-early-data",
-			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-on-initial-select-alpn", "",
+			"-on-resume-select-alpn", "foo",
+		},
+	})
 
-		// Test that we reject early data where ALPN is omitted from the first
-		// connection.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-ALPNOmitted1-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				NextProtos: []string{},
+	// Test that we reject early data where ALPN is omitted from the second
+	// connection.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-ALPNOmitted2-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			NextProtos: []string{"foo"},
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			NextProtos: []string{},
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: false,
 			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				NextProtos: []string{"foo"},
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: false,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-on-initial-select-alpn", "",
-				"-on-resume-select-alpn", "foo",
-			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-on-initial-select-alpn", "foo",
+			"-on-resume-select-alpn", "",
+		},
+	})
 
-		// Test that we reject early data where ALPN is omitted from the second
-		// connection.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-ALPNOmitted2-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				NextProtos: []string{"foo"},
+	// Test that we reject early data with mismatched ALPN.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-ALPNMismatch-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			NextProtos: []string{"foo"},
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			NextProtos: []string{"bar"},
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: false,
 			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				NextProtos: []string{},
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: false,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-on-initial-select-alpn", "foo",
-				"-on-resume-select-alpn", "",
-			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-on-initial-select-alpn", "foo",
+			"-on-resume-select-alpn", "bar",
+		},
+	})
 
-		// Test that we reject early data with mismatched ALPN.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-ALPNMismatch-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				NextProtos: []string{"foo"},
-			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				NextProtos: []string{"bar"},
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: false,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-on-initial-select-alpn", "foo",
-				"-on-resume-select-alpn", "bar",
-			},
-		})
+	// Test that the client offering 0-RTT and Channel ID forbids the server
+	// from accepting both.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyDataChannelID-AcceptBoth-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			RequestChannelID: true,
+		},
+		resumeSession:   true,
+		expectChannelID: true,
+		shouldFail:      true,
+		expectedError:   ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:",
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
+		},
+	})
 
-		// Test that the client offering 0-RTT and Channel ID forbids the server
-		// from accepting both.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyDataChannelID-AcceptBoth-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				RequestChannelID: true,
+	// Test that the client offering Channel ID and 0-RTT allows the server
+	// to decline 0-RTT.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyDataChannelID-AcceptChannelID-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			RequestChannelID: true,
+			Bugs: ProtocolBugs{
+				AlwaysRejectEarlyData: true,
 			},
-			tls13Variant:    variant,
-			resumeSession:   true,
-			expectChannelID: true,
-			shouldFail:      true,
-			expectedError:   ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:",
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
-			},
-		})
+		},
+		resumeSession:   true,
+		expectChannelID: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
+			"-expect-reject-early-data",
+		},
+	})
 
-		// Test that the client offering Channel ID and 0-RTT allows the server
-		// to decline 0-RTT.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyDataChannelID-AcceptChannelID-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				RequestChannelID: true,
-				Bugs: ProtocolBugs{
-					AlwaysRejectEarlyData: true,
-				},
-			},
-			tls13Variant:    variant,
-			resumeSession:   true,
-			expectChannelID: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
-				"-expect-reject-early-data",
-			},
-		})
+	// Test that the client offering Channel ID and 0-RTT allows the server
+	// to decline Channel ID.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyDataChannelID-AcceptEarlyData-Client-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
+			"-expect-accept-early-data",
+		},
+	})
 
-		// Test that the client offering Channel ID and 0-RTT allows the server
-		// to decline Channel ID.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyDataChannelID-AcceptEarlyData-Client-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
-				"-expect-accept-early-data",
+	// Test that the server supporting Channel ID and 0-RTT declines 0-RTT
+	// if it would negotiate Channel ID.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyDataChannelID-OfferBoth-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			ChannelID:  channelIDKey,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: false,
 			},
-		})
+		},
+		resumeSession:   true,
+		expectChannelID: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-reject-early-data",
+			"-expect-channel-id",
+			base64.StdEncoding.EncodeToString(channelIDBytes),
+		},
+	})
 
-		// Test that the server supporting Channel ID and 0-RTT declines 0-RTT
-		// if it would negotiate Channel ID.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyDataChannelID-OfferBoth-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				ChannelID:  channelIDKey,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: false,
-				},
-			},
-			tls13Variant:    variant,
-			resumeSession:   true,
-			expectChannelID: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-reject-early-data",
-				"-expect-channel-id",
-				base64.StdEncoding.EncodeToString(channelIDBytes),
+	// Test that the server supporting Channel ID and 0-RTT accepts 0-RTT
+	// if not offered Channel ID.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyDataChannelID-OfferEarlyData-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: true,
+				ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
 			},
-		})
+		},
+		resumeSession:   true,
+		expectChannelID: false,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-accept-early-data",
+			"-enable-channel-id",
+		},
+	})
 
-		// Test that the server supporting Channel ID and 0-RTT accepts 0-RTT
-		// if not offered Channel ID.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyDataChannelID-OfferEarlyData-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: true,
-					ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
-				},
-			},
-			tls13Variant:    variant,
-			resumeSession:   true,
-			expectChannelID: false,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-accept-early-data",
-				"-enable-channel-id",
+	// Test that the server rejects 0-RTT streams without end_of_early_data.
+	// The subsequent records should fail to decrypt.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-SkipEndOfEarlyData-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: true,
+				SkipEndOfEarlyData:      true,
 			},
-		})
+		},
+		resumeSession:      true,
+		flags:              []string{"-enable-early-data"},
+		shouldFail:         true,
+		expectedLocalError: "remote error: bad record MAC",
+		expectedError:      ":BAD_DECRYPT:",
+	})
 
-		// Test that the server rejects 0-RTT streams without end_of_early_data.
-		// The subsequent records should fail to decrypt.
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-SkipEndOfEarlyData-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: true,
-					SkipEndOfEarlyData:      true,
-				},
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-UnexpectedHandshake-Server-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				SendStrayEarlyHandshake: true,
+				ExpectEarlyDataAccepted: true,
 			},
-			tls13Variant:       variant,
-			resumeSession:      true,
-			flags:              []string{"-enable-early-data"},
-			shouldFail:         true,
-			expectedLocalError: "remote error: bad record MAC",
-			expectedError:      ":BAD_DECRYPT:",
-		})
+		},
+		resumeSession:      true,
+		shouldFail:         true,
+		expectedError:      ":UNEXPECTED_MESSAGE:",
+		expectedLocalError: "remote error: unexpected message",
+		flags: []string{
+			"-enable-early-data",
+		},
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-UnexpectedHandshake-Server-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					SendStrayEarlyHandshake: true,
-					ExpectEarlyDataAccepted: true,
-				},
-			},
-			tls13Variant:       variant,
-			resumeSession:      true,
-			shouldFail:         true,
-			expectedError:      ":UNEXPECTED_MESSAGE:",
-			expectedLocalError: "remote error: unexpected message",
-			flags: []string{
-				"-enable-early-data",
-			},
-		})
+	// Test that the client reports TLS 1.3 as the version while sending
+	// early data.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-Client-VersionAPI-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-accept-early-data",
+			"-expect-version", strconv.Itoa(VersionTLS13),
+		},
+	})
 
-		// Test that the client reports TLS 1.3 as the version while sending
-		// early data.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-Client-VersionAPI-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
+	// Test that client and server both notice handshake errors after data
+	// has started flowing.
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "EarlyData-Client-BadFinished-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				BadFinished: true,
 			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-accept-early-data",
-				"-expect-version", strconv.Itoa(VersionTLS13),
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-accept-early-data",
+		},
+		shouldFail:         true,
+		expectedError:      ":DIGEST_CHECK_FAILED:",
+		expectedLocalError: "remote error: error decrypting message",
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "EarlyData-Server-BadFinished-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: true,
+				ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
+				BadFinished:             true,
 			},
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-accept-early-data",
+		},
+		shouldFail:         true,
+		expectedError:      ":DIGEST_CHECK_FAILED:",
+		expectedLocalError: "remote error: error decrypting message",
+	})
 
-		// Test that client and server both notice handshake errors after data
-		// has started flowing.
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "EarlyData-Client-BadFinished-" + name,
-			config: Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-			},
-			resumeConfig: &Config{
-				MaxVersion:       VersionTLS13,
-				MaxEarlyDataSize: 16384,
-				Bugs: ProtocolBugs{
-					BadFinished: true,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-accept-early-data",
-			},
-			shouldFail:         true,
-			expectedError:      ":DIGEST_CHECK_FAILED:",
-			expectedLocalError: "remote error: error decrypting message",
-		})
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "EarlyData-Server-BadFinished-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
-			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: true,
-					ExpectHalfRTTData:       [][]byte{{254, 253, 252, 251}},
-					BadFinished:             true,
-				},
-			},
-			tls13Variant:  variant,
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-accept-early-data",
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "Server-NonEmptyEndOfEarlyData-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: true,
+				NonEmptyEndOfEarlyData:  true,
 			},
-			shouldFail:         true,
-			expectedError:      ":DIGEST_CHECK_FAILED:",
-			expectedLocalError: "remote error: error decrypting message",
-		})
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-accept-early-data",
+		},
+		shouldFail:    true,
+		expectedError: ":DECODE_ERROR:",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "Server-NonEmptyEndOfEarlyData-" + name,
-			config: Config{
-				MaxVersion: VersionTLS13,
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ServerSkipCertificateVerify-TLS13",
+		config: Config{
+			MinVersion:   VersionTLS13,
+			MaxVersion:   VersionTLS13,
+			Certificates: []Certificate{rsaChainCertificate},
+			Bugs: ProtocolBugs{
+				SkipCertificateVerify: true,
 			},
-			resumeConfig: &Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-					ExpectEarlyDataAccepted: true,
-					NonEmptyEndOfEarlyData:  true,
-				},
+		},
+		expectPeerCertificate: &rsaChainCertificate,
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+			"-require-any-client-certificate",
+		},
+		shouldFail:         true,
+		expectedError:      ":UNEXPECTED_MESSAGE:",
+		expectedLocalError: "remote error: unexpected message",
+	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ClientSkipCertificateVerify-TLS13",
+		config: Config{
+			MinVersion:   VersionTLS13,
+			MaxVersion:   VersionTLS13,
+			Certificates: []Certificate{rsaChainCertificate},
+			Bugs: ProtocolBugs{
+				SkipCertificateVerify: true,
 			},
-			resumeSession: true,
-			flags: []string{
-				"-enable-early-data",
-				"-expect-ticket-supports-early-data",
-				"-expect-accept-early-data",
-			},
-			tls13Variant:  variant,
-			shouldFail:    true,
-			expectedError: ":DECODE_ERROR:",
-		})
+		},
+		expectPeerCertificate: &rsaChainCertificate,
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+		},
+		shouldFail:         true,
+		expectedError:      ":UNEXPECTED_MESSAGE:",
+		expectedLocalError: "remote error: unexpected message",
+	})
 
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     "ServerSkipCertificateVerify-" + name,
-			config: Config{
-				MinVersion:   VersionTLS13,
-				MaxVersion:   VersionTLS13,
-				Certificates: []Certificate{rsaChainCertificate},
-				Bugs: ProtocolBugs{
-					SkipCertificateVerify: true,
-				},
-			},
-			tls13Variant:          variant,
-			expectPeerCertificate: &rsaChainCertificate,
-			flags: []string{
-				"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
-				"-key-file", path.Join(*resourceDir, rsaChainKeyFile),
-				"-require-any-client-certificate",
-			},
-			shouldFail:         true,
-			expectedError:      ":UNEXPECTED_MESSAGE:",
-			expectedLocalError: "remote error: unexpected message",
-		})
-		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     "ClientSkipCertificateVerify-" + name,
-			config: Config{
-				MinVersion:   VersionTLS13,
-				MaxVersion:   VersionTLS13,
-				Certificates: []Certificate{rsaChainCertificate},
-				Bugs: ProtocolBugs{
-					SkipCertificateVerify: true,
-				},
-			},
-			tls13Variant:          variant,
-			expectPeerCertificate: &rsaChainCertificate,
-			flags: []string{
-				"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
-				"-key-file", path.Join(*resourceDir, rsaChainKeyFile),
-			},
-			shouldFail:         true,
-			expectedError:      ":UNEXPECTED_MESSAGE:",
-			expectedLocalError: "remote error: unexpected message",
-		})
-	}
 }
 
 func addTLS13CipherPreferenceTests() {
@@ -13990,6 +13701,7 @@
 				TLS_CHACHA20_POLY1305_SHA256,
 				TLS_AES_128_GCM_SHA256,
 			},
+			CurvePreferences: []CurveID{CurveX25519},
 		},
 		flags: []string{
 			"-expect-cipher-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
@@ -14006,6 +13718,7 @@
 				TLS_AES_128_GCM_SHA256,
 				TLS_CHACHA20_POLY1305_SHA256,
 			},
+			CurvePreferences: []CurveID{CurveX25519},
 		},
 		flags: []string{
 			"-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
@@ -14029,7 +13742,7 @@
 		},
 	})
 
-	// Test that CECPQ2 cannot be used with TLS_AES_128_GCM_SHA256.
+	// CECPQ2 prefers 256-bit ciphers but will use AES-128 if there's nothing else.
 	testCases = append(testCases, testCase{
 		testType: serverTest,
 		name:     "TLS13-CipherPreference-CECPQ2-AES128Only",
@@ -14042,9 +13755,39 @@
 		flags: []string{
 			"-curves", strconv.Itoa(int(CurveCECPQ2)),
 		},
-		shouldFail:         true,
-		expectedError:      ":NO_SHARED_CIPHER:",
-		expectedLocalError: "remote error: handshake failure",
+	})
+	// When a 256-bit cipher is offered, even if not in first place, it should be
+	// picked.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13-CipherPreference-CECPQ2-AES256Preferred",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			CipherSuites: []uint16{
+				TLS_AES_128_GCM_SHA256,
+				TLS_AES_256_GCM_SHA384,
+			},
+		},
+		flags: []string{
+			"-curves", strconv.Itoa(int(CurveCECPQ2)),
+		},
+		expectedCipher: TLS_AES_256_GCM_SHA384,
+	})
+	// ... but when CECPQ2 isn't being used, the client's preference controls.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13-CipherPreference-CECPQ2-AES128PreferredOtherwise",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			CipherSuites: []uint16{
+				TLS_AES_128_GCM_SHA256,
+				TLS_AES_256_GCM_SHA384,
+			},
+		},
+		flags: []string{
+			"-curves", strconv.Itoa(int(CurveX25519)),
+		},
+		expectedCipher: TLS_AES_128_GCM_SHA256,
 	})
 
 	// Test that CECPQ2 continues to honor AES vs ChaCha20 logic.
@@ -14166,7 +13909,6 @@
 					SendRecordVersion: 0x03ff,
 				},
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":WRONG_VERSION_NUMBER:",
 		})
@@ -14183,7 +13925,6 @@
 					SendInitialRecordVersion: 0x03ff,
 				},
 			},
-			tls13Variant: ver.tls13Variant,
 		})
 
 		// Test that garbage ClientHello record versions are rejected.
@@ -14197,7 +13938,6 @@
 					SendInitialRecordVersion: 0xffff,
 				},
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
 			expectedError: ":WRONG_VERSION_NUMBER:",
 		})
@@ -14217,7 +13957,6 @@
 				Certificates: []Certificate{rsaChainCertificate},
 				ClientAuth:   RequireAnyClientCert,
 			},
-			tls13Variant:          ver.tls13Variant,
 			expectPeerCertificate: &rsaChainCertificate,
 			flags: []string{
 				"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
@@ -14234,7 +13973,6 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{rsaChainCertificate},
 			},
-			tls13Variant:          ver.tls13Variant,
 			expectPeerCertificate: &rsaChainCertificate,
 			flags: []string{
 				"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
@@ -14253,7 +13991,6 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{garbageCertificate},
 			},
-			tls13Variant:       ver.tls13Variant,
 			shouldFail:         true,
 			expectedError:      ":CANNOT_PARSE_LEAF_CERT:",
 			expectedLocalError: "remote error: error decoding message",
@@ -14267,7 +14004,6 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{garbageCertificate},
 			},
-			tls13Variant:       ver.tls13Variant,
 			flags:              []string{"-require-any-client-certificate"},
 			shouldFail:         true,
 			expectedError:      ":CANNOT_PARSE_LEAF_CERT:",
@@ -14288,7 +14024,6 @@
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-on-initial-retain-only-sha256-client-cert",
 				"-on-resume-retain-only-sha256-client-cert",
@@ -14306,7 +14041,6 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-verify-peer",
 				"-on-initial-retain-only-sha256-client-cert",
@@ -14328,7 +14062,6 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-verify-peer",
 				"-on-initial-retain-only-sha256-client-cert",
@@ -14349,7 +14082,6 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
-			tls13Variant: ver.tls13Variant,
 			flags: []string{
 				"-verify-peer",
 				"-on-resume-retain-only-sha256-client-cert",
@@ -14412,13 +14144,182 @@
 				MaxVersion:   ver.version,
 				Certificates: []Certificate{cert},
 			},
-			tls13Variant:  ver.tls13Variant,
 			shouldFail:    true,
-			expectedError: ":ECC_CERT_NOT_FOR_SIGNING:",
+			expectedError: ":KEY_USAGE_BIT_INCORRECT:",
 		})
 	}
 }
 
+func addRSAKeyUsageTests() {
+	priv := rsaCertificate.PrivateKey.(*rsa.PrivateKey)
+
+	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+	if err != nil {
+		panic(err)
+	}
+
+	dsTemplate := x509.Certificate{
+		SerialNumber: serialNumber,
+		Subject: pkix.Name{
+			Organization: []string{"Acme Co"},
+		},
+		NotBefore: time.Now(),
+		NotAfter:  time.Now(),
+
+		KeyUsage:              x509.KeyUsageDigitalSignature,
+		BasicConstraintsValid: true,
+	}
+
+	encTemplate := x509.Certificate{
+		SerialNumber: serialNumber,
+		Subject: pkix.Name{
+			Organization: []string{"Acme Co"},
+		},
+		NotBefore: time.Now(),
+		NotAfter:  time.Now(),
+
+		KeyUsage:              x509.KeyUsageKeyEncipherment,
+		BasicConstraintsValid: true,
+	}
+
+	dsDerBytes, err := x509.CreateCertificate(rand.Reader, &dsTemplate, &dsTemplate, &priv.PublicKey, priv)
+	if err != nil {
+		panic(err)
+	}
+
+	encDerBytes, err := x509.CreateCertificate(rand.Reader, &encTemplate, &encTemplate, &priv.PublicKey, priv)
+	if err != nil {
+		panic(err)
+	}
+
+	dsCert := Certificate{
+		Certificate: [][]byte{dsDerBytes},
+		PrivateKey:  priv,
+	}
+
+	encCert := Certificate{
+		Certificate: [][]byte{encDerBytes},
+		PrivateKey:  priv,
+	}
+
+	dsSuites := []uint16{
+		TLS_AES_128_GCM_SHA256,
+		TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+		TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+	}
+	encSuites := []uint16{
+		TLS_RSA_WITH_AES_128_GCM_SHA256,
+		TLS_RSA_WITH_AES_128_CBC_SHA,
+	}
+
+	for _, ver := range tlsVersions {
+		testCases = append(testCases, testCase{
+			testType: clientTest,
+			name:     "RSAKeyUsage-WantSignature-GotEncipherment-" + ver.name,
+			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{encCert},
+				CipherSuites: dsSuites,
+			},
+			shouldFail:    true,
+			expectedError: ":KEY_USAGE_BIT_INCORRECT:",
+			flags: []string{
+				"-enforce-rsa-key-usage",
+			},
+		})
+
+		testCases = append(testCases, testCase{
+			testType: clientTest,
+			name:     "RSAKeyUsage-WantSignature-GotSignature-" + ver.name,
+			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{dsCert},
+				CipherSuites: dsSuites,
+			},
+			flags: []string{
+				"-enforce-rsa-key-usage",
+			},
+		})
+
+		// TLS 1.3 removes the encipherment suites.
+		if ver.version < VersionTLS13 {
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				name:     "RSAKeyUsage-WantEncipherment-GotEncipherment" + ver.name,
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					Certificates: []Certificate{encCert},
+					CipherSuites: encSuites,
+				},
+				flags: []string{
+					"-enforce-rsa-key-usage",
+				},
+			})
+
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				name:     "RSAKeyUsage-WantEncipherment-GotSignature-" + ver.name,
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					Certificates: []Certificate{dsCert},
+					CipherSuites: encSuites,
+				},
+				shouldFail:    true,
+				expectedError: ":KEY_USAGE_BIT_INCORRECT:",
+				flags: []string{
+					"-enforce-rsa-key-usage",
+				},
+			})
+
+			// In 1.2 and below, we should not enforce without the enforce-rsa-key-usage flag.
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				name:     "RSAKeyUsage-WantSignature-GotEncipherment-Unenforced" + ver.name,
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					Certificates: []Certificate{dsCert},
+					CipherSuites: encSuites,
+				},
+			})
+
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				name:     "RSAKeyUsage-WantEncipherment-GotSignature-Unenforced" + ver.name,
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					Certificates: []Certificate{encCert},
+					CipherSuites: dsSuites,
+				},
+			})
+
+		}
+
+		if ver.version >= VersionTLS13 {
+			// In 1.3 and above, we enforce keyUsage even without the flag.
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				name:     "RSAKeyUsage-WantSignature-GotEncipherment-Enforced" + ver.name,
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					Certificates: []Certificate{encCert},
+					CipherSuites: dsSuites,
+				},
+				shouldFail:    true,
+				expectedError: ":KEY_USAGE_BIT_INCORRECT:",
+			})
+
+		}
+	}
+}
+
 func addExtraHandshakeTests() {
 	// An extra SSL_do_handshake is normally a no-op. These tests use -async
 	// to ensure there is no transport I/O.
@@ -14588,8 +14489,10 @@
 					OmitExtensions: true,
 					// Disable all ServerHello extensions so
 					// OmitExtensions works.
-					NoExtendedMasterSecret: true,
-					NoRenegotiationInfo:    true,
+					NoExtendedMasterSecret:        true,
+					NoRenegotiationInfo:           true,
+					NoOCSPStapling:                true,
+					NoSignedCertificateTimestamps: true,
 				},
 			},
 		})
@@ -14605,8 +14508,10 @@
 					EmptyExtensions: true,
 					// Disable all ServerHello extensions so
 					// EmptyExtensions works.
-					NoExtendedMasterSecret: true,
-					NoRenegotiationInfo:    true,
+					NoExtendedMasterSecret:        true,
+					NoRenegotiationInfo:           true,
+					NoOCSPStapling:                true,
+					NoSignedCertificateTimestamps: true,
 				},
 			},
 		})
@@ -14666,9 +14571,8 @@
 		// Duplicate compression algorithms is an error, even if nothing is
 		// configured.
 		testCases = append(testCases, testCase{
-			testType:     serverTest,
-			name:         "DuplicateCertCompressionExt-" + ver.name,
-			tls13Variant: ver.tls13Variant,
+			testType: serverTest,
+			name:     "DuplicateCertCompressionExt-" + ver.name,
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -14683,10 +14587,9 @@
 		// With compression algorithms configured, an duplicate values should still
 		// be an error.
 		testCases = append(testCases, testCase{
-			testType:     serverTest,
-			name:         "DuplicateCertCompressionExt2-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: serverTest,
+			name:     "DuplicateCertCompressionExt2-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -14714,10 +14617,9 @@
 		}
 
 		testCases = append(testCases, testCase{
-			testType:     serverTest,
-			name:         "CertCompressionExpands-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: serverTest,
+			name:     "CertCompressionExpands-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion:          ver.version,
 				MaxVersion:          ver.version,
@@ -14729,10 +14631,9 @@
 		})
 
 		testCases = append(testCases, testCase{
-			testType:     serverTest,
-			name:         "CertCompressionShrinks-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: serverTest,
+			name:     "CertCompressionShrinks-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion:          ver.version,
 				MaxVersion:          ver.version,
@@ -14746,10 +14647,9 @@
 		// With both algorithms configured, the server should pick its most
 		// preferable. (Which is expandingAlgId.)
 		testCases = append(testCases, testCase{
-			testType:     serverTest,
-			name:         "CertCompressionPriority-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: serverTest,
+			name:     "CertCompressionPriority-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -14764,10 +14664,9 @@
 		})
 
 		testCases = append(testCases, testCase{
-			testType:     clientTest,
-			name:         "CertCompressionExpandsClient-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: clientTest,
+			name:     "CertCompressionExpandsClient-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -14781,10 +14680,9 @@
 		})
 
 		testCases = append(testCases, testCase{
-			testType:     clientTest,
-			name:         "CertCompressionShrinksClient-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: clientTest,
+			name:     "CertCompressionShrinksClient-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -14798,10 +14696,9 @@
 		})
 
 		testCases = append(testCases, testCase{
-			testType:     clientTest,
-			name:         "CertCompressionBadAlgIdClient-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: clientTest,
+			name:     "CertCompressionBadAlgIdClient-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -14818,10 +14715,9 @@
 		})
 
 		testCases = append(testCases, testCase{
-			testType:     clientTest,
-			name:         "CertCompressionTooSmallClient-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: clientTest,
+			name:     "CertCompressionTooSmallClient-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -14838,10 +14734,9 @@
 		})
 
 		testCases = append(testCases, testCase{
-			testType:     clientTest,
-			name:         "CertCompressionTooLargeClient-" + ver.name,
-			tls13Variant: ver.tls13Variant,
-			flags:        []string{"-install-cert-compression-algs"},
+			testType: clientTest,
+			name:     "CertCompressionTooLargeClient-" + ver.name,
+			flags:    []string{"-install-cert-compression-algs"},
 			config: Config{
 				MinVersion: ver.version,
 				MaxVersion: ver.version,
@@ -15015,6 +14910,109 @@
 	}
 }
 
+func addDelegatedCredentialTests() {
+	certPath := path.Join(*resourceDir, rsaCertificateFile)
+	pemBytes, err := ioutil.ReadFile(certPath)
+	if err != nil {
+		panic(err)
+	}
+
+	block, _ := pem.Decode(pemBytes)
+	if block == nil {
+		panic(fmt.Sprintf("no PEM block found in %q", certPath))
+	}
+	parentDER := block.Bytes
+
+	rsaPriv, _, err := loadRSAPrivateKey(rsaKeyFile)
+	if err != nil {
+		panic(err)
+	}
+
+	ecdsaDC, ecdsaPKCS8, err := createDelegatedCredential(delegatedCredentialConfig{
+		algo: signatureRSAPSSWithSHA256,
+	}, parentDER, rsaPriv)
+	if err != nil {
+		panic(err)
+	}
+	ecdsaFlagValue := fmt.Sprintf("%x,%x", ecdsaDC, ecdsaPKCS8)
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "DelegatedCredentials-NoClientSupport",
+		config: Config{
+			MinVersion: VersionTLS13,
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				DisableDelegatedCredentials: true,
+			},
+		},
+		flags: []string{
+			"-delegated-credential", ecdsaFlagValue,
+		},
+	})
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "DelegatedCredentials-Basic",
+		config: Config{
+			MinVersion: VersionTLS13,
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				ExpectDelegatedCredentials: true,
+			},
+		},
+		flags: []string{
+			"-delegated-credential", ecdsaFlagValue,
+		},
+	})
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "DelegatedCredentials-SigAlgoMissing",
+		config: Config{
+			MinVersion: VersionTLS13,
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				FailIfDelegatedCredentials: true,
+			},
+			// If the client doesn't support the delegated credential signature
+			// algorithm then the handshake should complete without using delegated
+			// credentials.
+			VerifySignatureAlgorithms: []signatureAlgorithm{signatureRSAPSSWithSHA256},
+		},
+		flags: []string{
+			"-delegated-credential", ecdsaFlagValue,
+		},
+	})
+
+	// This flag value has mismatched public and private keys which should cause a
+	// configuration error in the shim.
+	_, badTLSVersionPKCS8, err := createDelegatedCredential(delegatedCredentialConfig{
+		algo:       signatureRSAPSSWithSHA256,
+		tlsVersion: 0x1234,
+	}, parentDER, rsaPriv)
+	if err != nil {
+		panic(err)
+	}
+	mismatchFlagValue := fmt.Sprintf("%x,%x", ecdsaDC, badTLSVersionPKCS8)
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "DelegatedCredentials-KeyMismatch",
+		config: Config{
+			MinVersion: VersionTLS13,
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				FailIfDelegatedCredentials: true,
+			},
+		},
+		flags: []string{
+			"-delegated-credential", mismatchFlagValue,
+		},
+		shouldFail:    true,
+		expectedError: ":KEY_VALUES_MISMATCH:",
+	})
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -15146,10 +15144,12 @@
 	addCertificateTests()
 	addRetainOnlySHA256ClientCertTests()
 	addECDSAKeyUsageTests()
+	addRSAKeyUsageTests()
 	addExtraHandshakeTests()
 	addOmitExtensionsTests()
 	addCertCompressionTests()
 	addJDK11WorkaroundTests()
+	addDelegatedCredentialTests()
 
 	testCases = append(testCases, convertToSplitHandshakeTests(testCases)...)
 
diff --git a/src/ssl/test/settings_writer.cc b/src/ssl/test/settings_writer.cc
index 66025f6..fe8d42e 100644
--- a/src/ssl/test/settings_writer.cc
+++ b/src/ssl/test/settings_writer.cc
@@ -59,12 +59,6 @@
     return false;
   }
 
-  if (config->tls13_variant != 0 &&
-      (!CBB_add_u16(cbb_.get(), kTLS13Variant) ||
-       !CBB_add_u8(cbb_.get(), static_cast<uint8_t>(config->tls13_variant)))) {
-    return false;
-  }
-
   return true;
 }
 
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index bed0501..70e061b 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -145,9 +145,11 @@
   { "-is-handshaker-supported", &TestConfig::is_handshaker_supported },
   { "-handshaker-resume", &TestConfig::handshaker_resume },
   { "-reverify-on-resume", &TestConfig::reverify_on_resume },
+  { "-enforce-rsa-key-usage", &TestConfig::enforce_rsa_key_usage },
   { "-jdk11-workaround", &TestConfig::jdk11_workaround },
   { "-server-preference", &TestConfig::server_preference },
   { "-export-traffic-secrets", &TestConfig::export_traffic_secrets },
+  { "-key-update", &TestConfig::key_update },
 };
 
 const Flag<std::string> kStringFlags[] = {
@@ -176,6 +178,7 @@
   { "-expect-client-ca-list", &TestConfig::expected_client_ca_list },
   { "-expect-msg-callback", &TestConfig::expect_msg_callback },
   { "-handshaker-path", &TestConfig::handshaker_path },
+  { "-delegated-credential", &TestConfig::delegated_credential },
 };
 
 const Flag<std::string> kBase64Flags[] = {
@@ -217,7 +220,6 @@
   { "-max-send-fragment", &TestConfig::max_send_fragment },
   { "-read-size", &TestConfig::read_size },
   { "-expect-ticket-age-skew", &TestConfig::expect_ticket_age_skew },
-  { "-tls13-variant", &TestConfig::tls13_variant },
 };
 
 const Flag<std::vector<int>> kIntVectorFlags[] = {
@@ -1246,9 +1248,6 @@
     SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
   }
 
-  SSL_CTX_set_tls13_variant(ssl_ctx.get(),
-                            static_cast<enum tls13_variant_t>(tls13_variant));
-
   if (allow_unknown_alpn_protos) {
     SSL_CTX_set_allow_unknown_alpn_protos(ssl_ctx.get(), 1);
   }
@@ -1503,6 +1502,9 @@
   if (reverify_on_resume) {
     SSL_CTX_set_reverify_on_resume(ssl_ctx, 1);
   }
+  if (enforce_rsa_key_usage) {
+    SSL_set_enforce_rsa_key_usage(ssl.get(), 1);
+  }
   if (no_tls13) {
     SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_3);
   }
@@ -1673,5 +1675,40 @@
     }
   }
 
+  if (!delegated_credential.empty()) {
+    std::string::size_type comma = delegated_credential.find(',');
+    if (comma == std::string::npos) {
+      fprintf(stderr, "failed to find comma in delegated credential argument");
+      return nullptr;
+    }
+
+    const std::string dc_hex = delegated_credential.substr(0, comma);
+    const std::string pkcs8_hex = delegated_credential.substr(comma + 1);
+    std::string dc, pkcs8;
+    if (!HexDecode(&dc, dc_hex) || !HexDecode(&pkcs8, pkcs8_hex)) {
+      fprintf(stderr, "failed to hex decode delegated credential argument");
+      return nullptr;
+    }
+
+    CBS dc_cbs(bssl::Span<const uint8_t>(
+        reinterpret_cast<const uint8_t *>(dc.data()), dc.size()));
+    CBS pkcs8_cbs(bssl::Span<const uint8_t>(
+        reinterpret_cast<const uint8_t *>(pkcs8.data()), pkcs8.size()));
+
+    bssl::UniquePtr<EVP_PKEY> priv(EVP_parse_private_key(&pkcs8_cbs));
+    if (!priv) {
+      fprintf(stderr, "failed to parse delegated credential private key");
+      return nullptr;
+    }
+
+    bssl::UniquePtr<CRYPTO_BUFFER> dc_buf(
+        CRYPTO_BUFFER_new_from_CBS(&dc_cbs, nullptr));
+    if (!SSL_set1_delegated_credential(ssl.get(), dc_buf.get(),
+                                      priv.get(), nullptr)) {
+      fprintf(stderr, "SSL_set1_delegated_credential failed.\n");
+      return nullptr;
+    }
+  }
+
   return ssl;
 }
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 0d0753e..9221d6f 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -104,7 +104,6 @@
   bool use_ticket_callback = false;
   bool renew_ticket = false;
   bool enable_early_data = false;
-  int tls13_variant = 0;
   bool enable_client_custom_extension = false;
   bool enable_server_custom_extension = false;
   bool custom_extension_skip = false;
@@ -166,12 +165,15 @@
   bool fail_ocsp_callback = false;
   bool install_cert_compression_algs = false;
   bool reverify_on_resume = false;
+  bool enforce_rsa_key_usage = false;
   bool is_handshaker_supported = false;
   bool handshaker_resume = false;
   std::string handshaker_path;
   bool jdk11_workaround = false;
   bool server_preference = false;
   bool export_traffic_secrets = false;
+  bool key_update = false;
+  std::string delegated_credential;
 
   int argc;
   char **argv;
diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc
index 6baeaf7..ba5719f 100644
--- a/src/ssl/tls13_both.cc
+++ b/src/ssl/tls13_both.cc
@@ -212,7 +212,8 @@
       }
       // TLS 1.3 always uses certificate keys for signing thus the correct
       // keyUsage is enforced.
-      if (!ssl_cert_check_digital_signature_key_usage(&certificate)) {
+      if (!ssl_cert_check_key_usage(&certificate,
+                                    key_usage_digital_signature)) {
         ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
         return false;
       }
@@ -418,6 +419,7 @@
 bool tls13_add_certificate(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   CERT *const cert = hs->config->cert.get();
+  DC *const dc = cert->dc.get();
 
   ScopedCBB cbb;
   CBB *body, body_storage, certificate_list;
@@ -441,7 +443,7 @@
     return false;
   }
 
-  if (!ssl_has_certificate(hs->config)) {
+  if (!ssl_has_certificate(hs)) {
     return ssl_add_message_cbb(ssl, cbb.get());
   }
 
@@ -484,6 +486,19 @@
     }
   }
 
+  if (ssl_signing_with_dc(hs)) {
+    const CRYPTO_BUFFER *raw = dc->raw.get();
+    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_delegated_credential) ||
+        !CBB_add_u16(&extensions, CRYPTO_BUFFER_len(raw)) ||
+        !CBB_add_bytes(&extensions,
+                       CRYPTO_BUFFER_data(raw),
+                       CRYPTO_BUFFER_len(raw)) ||
+        !CBB_flush(&extensions)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      return 0;
+    }
+  }
+
   for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain.get()); i++) {
     CRYPTO_BUFFER *cert_buf = sk_CRYPTO_BUFFER_value(cert->chain.get(), i);
     CBB child;
@@ -607,6 +622,25 @@
   return true;
 }
 
+bool tls13_add_key_update(SSL *ssl, int update_requested) {
+  ScopedCBB cbb;
+  CBB body_cbb;
+  if (!ssl->method->init_message(ssl, cbb.get(), &body_cbb,
+                                 SSL3_MT_KEY_UPDATE) ||
+      !CBB_add_u8(&body_cbb, update_requested) ||
+      !ssl_add_message_cbb(ssl, cbb.get()) ||
+      !tls13_rotate_traffic_key(ssl, evp_aead_seal)) {
+    return false;
+  }
+
+  // Suppress KeyUpdate acknowledgments until this change is written to the
+  // wire. This prevents us from accumulating write obligations when read and
+  // write progress at different rates. See RFC 8446, section 4.6.3.
+  ssl->s3->key_update_pending = true;
+
+  return true;
+}
+
 static bool tls13_receive_key_update(SSL *ssl, const SSLMessage &msg) {
   CBS body = msg.body;
   uint8_t key_update_request;
@@ -625,21 +659,9 @@
 
   // Acknowledge the KeyUpdate
   if (key_update_request == SSL_KEY_UPDATE_REQUESTED &&
-      !ssl->s3->key_update_pending) {
-    ScopedCBB cbb;
-    CBB body_cbb;
-    if (!ssl->method->init_message(ssl, cbb.get(), &body_cbb,
-                                   SSL3_MT_KEY_UPDATE) ||
-        !CBB_add_u8(&body_cbb, SSL_KEY_UPDATE_NOT_REQUESTED) ||
-        !ssl_add_message_cbb(ssl, cbb.get()) ||
-        !tls13_rotate_traffic_key(ssl, evp_aead_seal)) {
-      return false;
-    }
-
-    // Suppress KeyUpdate acknowledgments until this change is written to the
-    // wire. This prevents us from accumulating write obligations when read and
-    // write progress at different rates. See RFC 8446, section 4.6.3.
-    ssl->s3->key_update_pending = true;
+      !ssl->s3->key_update_pending &&
+      !tls13_add_key_update(ssl, SSL_KEY_UPDATE_NOT_REQUESTED)) {
+    return false;
   }
 
   return true;
@@ -648,7 +670,7 @@
 bool tls13_post_handshake(SSL *ssl, const SSLMessage &msg) {
   if (msg.type == SSL3_MT_KEY_UPDATE) {
     ssl->s3->key_update_count++;
-    if (ssl->ctx->quic_method != nullptr ||
+    if (ssl->quic_method != nullptr ||
         ssl->s3->key_update_count > kMaxKeyUpdates) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_KEY_UPDATES);
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc
index 40913dc..ac97165 100644
--- a/src/ssl/tls13_client.cc
+++ b/src/ssl/tls13_client.cc
@@ -294,16 +294,14 @@
     return ssl_hs_error;
   }
 
-  if (ssl_is_draft28(ssl->version)) {
-    // Recheck supported_versions, in case this is the second ServerHello.
-    uint16_t version;
-    if (!have_supported_versions ||
-        !CBS_get_u16(&supported_versions, &version) ||
-        version != ssl->version) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_SECOND_SERVERHELLO_VERSION_MISMATCH);
-      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-      return ssl_hs_error;
-    }
+  // Recheck supported_versions, in case this is the second ServerHello.
+  uint16_t version;
+  if (!have_supported_versions ||
+      !CBS_get_u16(&supported_versions, &version) ||
+      version != ssl->version) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_SECOND_SERVERHELLO_VERSION_MISMATCH);
+    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+    return ssl_hs_error;
   }
 
   alert = SSL_AD_DECODE_ERROR;
@@ -685,7 +683,7 @@
 
 static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) {
   // Don't send CertificateVerify if there is no certificate.
-  if (!ssl_has_certificate(hs->config)) {
+  if (!ssl_has_certificate(hs)) {
     hs->tls13_state = state_complete_second_flight;
     return ssl_hs_ok;
   }
@@ -883,8 +881,7 @@
     session->timeout = server_timeout;
   }
 
-  if (!tls13_derive_session_psk(session.get(), ticket_nonce,
-                                ssl->ctx->quic_method != nullptr)) {
+  if (!tls13_derive_session_psk(session.get(), ticket_nonce)) {
     return false;
   }
 
diff --git a/src/ssl/tls13_enc.cc b/src/ssl/tls13_enc.cc
index f18084e..7353561 100644
--- a/src/ssl/tls13_enc.cc
+++ b/src/ssl/tls13_enc.cc
@@ -69,27 +69,19 @@
 static bool hkdf_expand_label(uint8_t *out, const EVP_MD *digest,
                               const uint8_t *secret, size_t secret_len,
                               const char *label, size_t label_len,
-                              const uint8_t *hash, size_t hash_len, size_t len,
-                              bool use_quic_label) {
+                              const uint8_t *hash, size_t hash_len,
+                              size_t len) {
   static const char kTLS13ProtocolLabel[] = "tls13 ";
-  static const char kQUICProtocolLabel[] = "quic ";
-
-  const char *protocol_label;
-  if (use_quic_label) {
-    protocol_label = kQUICProtocolLabel;
-  } else {
-    protocol_label = kTLS13ProtocolLabel;
-  }
 
   ScopedCBB cbb;
   CBB child;
   Array<uint8_t> hkdf_label;
-  if (!CBB_init(cbb.get(),
-                2 + 1 + strlen(protocol_label) + label_len + 1 + hash_len) ||
+  if (!CBB_init(cbb.get(), 2 + 1 + strlen(kTLS13ProtocolLabel) + label_len + 1 +
+                               hash_len) ||
       !CBB_add_u16(cbb.get(), len) ||
       !CBB_add_u8_length_prefixed(cbb.get(), &child) ||
-      !CBB_add_bytes(&child, (const uint8_t *)protocol_label,
-                     strlen(protocol_label)) ||
+      !CBB_add_bytes(&child, (const uint8_t *)kTLS13ProtocolLabel,
+                     strlen(kTLS13ProtocolLabel)) ||
       !CBB_add_bytes(&child, (const uint8_t *)label, label_len) ||
       !CBB_add_u8_length_prefixed(cbb.get(), &child) ||
       !CBB_add_bytes(&child, hash, hash_len) ||
@@ -115,8 +107,7 @@
   if (!hkdf_expand_label(hs->secret, hs->transcript.Digest(), hs->secret,
                          hs->hash_len, kTLS13LabelDerived,
                          strlen(kTLS13LabelDerived), derive_context,
-                         derive_context_len, hs->hash_len,
-                         hs->ssl->ctx->quic_method != nullptr)) {
+                         derive_context_len, hs->hash_len)) {
     return false;
   }
 
@@ -137,8 +128,7 @@
 
   return hkdf_expand_label(out, hs->transcript.Digest(), hs->secret,
                            hs->hash_len, label, label_len, context_hash,
-                           context_hash_len, len,
-                           hs->ssl->ctx->quic_method != nullptr);
+                           context_hash_len, len);
 }
 
 bool tls13_set_traffic_key(SSL *ssl, enum ssl_encryption_level_t level,
@@ -154,7 +144,7 @@
   }
 
   UniquePtr<SSLAEADContext> traffic_aead;
-  if (ssl->ctx->quic_method == nullptr) {
+  if (ssl->quic_method == nullptr) {
     // Look up cipher suite properties.
     const EVP_AEAD *aead;
     size_t discard;
@@ -169,8 +159,7 @@
     size_t key_len = EVP_AEAD_key_length(aead);
     uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
     if (!hkdf_expand_label(key, digest, traffic_secret, traffic_secret_len,
-                           "key", 3, NULL, 0, key_len,
-                           ssl->ctx->quic_method != nullptr)) {
+                           "key", 3, NULL, 0, key_len)) {
       return false;
     }
 
@@ -178,8 +167,7 @@
     size_t iv_len = EVP_AEAD_nonce_length(aead);
     uint8_t iv[EVP_AEAD_MAX_NONCE_LENGTH];
     if (!hkdf_expand_label(iv, digest, traffic_secret, traffic_secret_len, "iv",
-                           2, NULL, 0, iv_len,
-                           ssl->ctx->quic_method != nullptr)) {
+                           2, NULL, 0, iv_len)) {
       return false;
     }
 
@@ -249,16 +237,16 @@
   }
   ssl->s3->early_exporter_secret_len = hs->hash_len;
 
-  if (ssl->ctx->quic_method != nullptr) {
+  if (ssl->quic_method != nullptr) {
     if (ssl->server) {
-      if (!ssl->ctx->quic_method->set_encryption_secrets(
+      if (!ssl->quic_method->set_encryption_secrets(
               ssl, ssl_encryption_early_data, nullptr, hs->early_traffic_secret,
               hs->hash_len)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
         return false;
       }
     } else {
-      if (!ssl->ctx->quic_method->set_encryption_secrets(
+      if (!ssl->quic_method->set_encryption_secrets(
               ssl, ssl_encryption_early_data, hs->early_traffic_secret, nullptr,
               hs->hash_len)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
@@ -285,16 +273,16 @@
     return false;
   }
 
-  if (ssl->ctx->quic_method != nullptr) {
+  if (ssl->quic_method != nullptr) {
     if (ssl->server) {
-      if (!ssl->ctx->quic_method->set_encryption_secrets(
+      if (!ssl->quic_method->set_encryption_secrets(
               ssl, ssl_encryption_handshake, hs->client_handshake_secret,
               hs->server_handshake_secret, hs->hash_len)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
         return false;
       }
     } else {
-      if (!ssl->ctx->quic_method->set_encryption_secrets(
+      if (!ssl->quic_method->set_encryption_secrets(
               ssl, ssl_encryption_handshake, hs->server_handshake_secret,
               hs->client_handshake_secret, hs->hash_len)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
@@ -326,16 +314,16 @@
     return false;
   }
 
-  if (ssl->ctx->quic_method != nullptr) {
+  if (ssl->quic_method != nullptr) {
     if (ssl->server) {
-      if (!ssl->ctx->quic_method->set_encryption_secrets(
+      if (!ssl->quic_method->set_encryption_secrets(
               ssl, ssl_encryption_application, hs->client_traffic_secret_0,
               hs->server_traffic_secret_0, hs->hash_len)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
         return false;
       }
     } else {
-      if (!ssl->ctx->quic_method->set_encryption_secrets(
+      if (!ssl->quic_method->set_encryption_secrets(
               ssl, ssl_encryption_application, hs->server_traffic_secret_0,
               hs->client_traffic_secret_0, hs->hash_len)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
@@ -364,7 +352,7 @@
   if (!hkdf_expand_label(secret, digest, secret, secret_len,
                          kTLS13LabelApplicationTraffic,
                          strlen(kTLS13LabelApplicationTraffic), NULL, 0,
-                         secret_len, ssl->ctx->quic_method != nullptr)) {
+                         secret_len)) {
     return false;
   }
 
@@ -392,13 +380,11 @@
 static bool tls13_verify_data(const EVP_MD *digest, uint16_t version,
                               uint8_t *out, size_t *out_len,
                               const uint8_t *secret, size_t hash_len,
-                              uint8_t *context, size_t context_len,
-                              bool use_quic) {
+                              uint8_t *context, size_t context_len) {
   uint8_t key[EVP_MAX_MD_SIZE];
   unsigned len;
   if (!hkdf_expand_label(key, digest, secret, hash_len, kTLS13LabelFinished,
-                         strlen(kTLS13LabelFinished), NULL, 0, hash_len,
-                         use_quic) ||
+                         strlen(kTLS13LabelFinished), NULL, 0, hash_len) ||
       HMAC(digest, key, hash_len, context, context_len, out, &len) == NULL) {
     return false;
   }
@@ -420,8 +406,7 @@
   if (!hs->transcript.GetHash(context_hash, &context_hash_len) ||
       !tls13_verify_data(hs->transcript.Digest(), hs->ssl->version, out,
                          out_len, traffic_secret, hs->hash_len, context_hash,
-                         context_hash_len,
-                         hs->ssl->ctx->quic_method != nullptr)) {
+                         context_hash_len)) {
     return 0;
   }
   return 1;
@@ -429,13 +414,12 @@
 
 static const char kTLS13LabelResumptionPSK[] = "resumption";
 
-bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce,
-                              bool use_quic) {
+bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce) {
   const EVP_MD *digest = ssl_session_get_digest(session);
   return hkdf_expand_label(session->master_key, digest, session->master_key,
                            session->master_key_length, kTLS13LabelResumptionPSK,
                            strlen(kTLS13LabelResumptionPSK), nonce.data(),
-                           nonce.size(), session->master_key_length, use_quic);
+                           nonce.size(), session->master_key_length);
 }
 
 static const char kTLS13LabelExportKeying[] = "exporter";
@@ -464,12 +448,11 @@
                     nullptr) &&
          hkdf_expand_label(derived_secret, digest, secret.data(), secret.size(),
                            label.data(), label.size(), export_context,
-                           export_context_len, derived_secret_len,
-                           ssl->ctx->quic_method != nullptr) &&
+                           export_context_len, derived_secret_len) &&
          hkdf_expand_label(out.data(), digest, derived_secret,
                            derived_secret_len, kTLS13LabelExportKeying,
                            strlen(kTLS13LabelExportKeying), hash, hash_len,
-                           out.size(), ssl->ctx->quic_method != nullptr);
+                           out.size());
 }
 
 static const char kTLS13LabelPSKBinder[] = "res binder";
@@ -477,7 +460,7 @@
 static bool tls13_psk_binder(uint8_t *out, uint16_t version,
                              const EVP_MD *digest, uint8_t *psk, size_t psk_len,
                              uint8_t *context, size_t context_len,
-                             size_t hash_len, bool use_quic) {
+                             size_t hash_len) {
   uint8_t binder_context[EVP_MAX_MD_SIZE];
   unsigned binder_context_len;
   if (!EVP_Digest(NULL, 0, binder_context, &binder_context_len, digest, NULL)) {
@@ -495,10 +478,9 @@
   size_t len;
   if (!hkdf_expand_label(binder_key, digest, early_secret, hash_len,
                          kTLS13LabelPSKBinder, strlen(kTLS13LabelPSKBinder),
-                         binder_context, binder_context_len, hash_len,
-                         use_quic) ||
+                         binder_context, binder_context_len, hash_len) ||
       !tls13_verify_data(digest, version, out, &len, binder_key, hash_len,
-                         context, context_len, use_quic)) {
+                         context, context_len)) {
     return false;
   }
 
@@ -531,7 +513,7 @@
   if (!tls13_psk_binder(verify_data, ssl->session->ssl_version, digest,
                         ssl->session->master_key,
                         ssl->session->master_key_length, context, context_len,
-                        hash_len, ssl->ctx->quic_method != nullptr)) {
+                        hash_len)) {
     return false;
   }
 
@@ -563,8 +545,7 @@
   CBS binder;
   if (!tls13_psk_binder(verify_data, hs->ssl->version, hs->transcript.Digest(),
                         session->master_key, session->master_key_length,
-                        context, context_len, hash_len,
-                        hs->ssl->ctx->quic_method != nullptr) ||
+                        context, context_len, hash_len) ||
       // We only consider the first PSK, so compare against the first binder.
       !CBS_get_u8_length_prefixed(binders, &binder)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc
index 7073b57..caaf0c7 100644
--- a/src/ssl/tls13_server.cc
+++ b/src/ssl/tls13_server.cc
@@ -17,6 +17,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include <tuple>
+
 #include <openssl/aead.h>
 #include <openssl/bytestring.h>
 #include <openssl/digest.h>
@@ -95,6 +97,37 @@
   return 1;
 }
 
+// CipherScorer produces a "score" for each possible cipher suite offered by
+// the client.
+class CipherScorer {
+ public:
+  CipherScorer(uint16_t group_id)
+      : aes_is_fine_(EVP_has_aes_hardware()),
+        security_128_is_fine_(group_id != SSL_CURVE_CECPQ2) {}
+
+  typedef std::tuple<bool, bool, bool> Score;
+
+  // MinScore returns a |Score| that will compare less than the score of all
+  // cipher suites.
+  Score MinScore() const {
+    return Score(false, false, false);
+  }
+
+  Score Evaluate(const SSL_CIPHER *a) const {
+    return Score(
+        // Something is always preferable to nothing.
+        true,
+        // Either 128-bit is fine, or 256-bit is preferred.
+        security_128_is_fine_ || a->algorithm_enc != SSL_AES128GCM,
+        // Either AES is fine, or else ChaCha20 is preferred.
+        aes_is_fine_ || a->algorithm_enc == SSL_CHACHA20POLY1305);
+  }
+
+ private:
+  const bool aes_is_fine_;
+  const bool security_128_is_fine_;
+};
+
 static const SSL_CIPHER *choose_tls13_cipher(
     const SSL *ssl, const SSL_CLIENT_HELLO *client_hello, uint16_t group_id) {
   if (client_hello->cipher_suites_len % 2 != 0) {
@@ -105,11 +138,12 @@
   CBS_init(&cipher_suites, client_hello->cipher_suites,
            client_hello->cipher_suites_len);
 
-  const bool aes_is_fine = EVP_has_aes_hardware();
-  const bool require_256_bit = group_id == SSL_CURVE_CECPQ2;
   const uint16_t version = ssl_protocol_version(ssl);
 
   const SSL_CIPHER *best = nullptr;
+  CipherScorer scorer(group_id);
+  CipherScorer::Score best_score = scorer.MinScore();
+
   while (CBS_len(&cipher_suites) > 0) {
     uint16_t cipher_suite;
     if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
@@ -124,23 +158,12 @@
       continue;
     }
 
-    // Post-quantum key exchanges should be paired with 256-bit ciphers.
-    if (require_256_bit && candidate->algorithm_enc == SSL_AES128GCM) {
-      continue;
-    }
-
-    // TLS 1.3 removes legacy ciphers, so honor the client order, but prefer
-    // ChaCha20 if we do not have AES hardware.
-    if (aes_is_fine) {
-      return candidate;
-    }
-
-    if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) {
-      return candidate;
-    }
-
-    if (best == nullptr) {
+    const CipherScorer::Score candidate_score = scorer.Evaluate(candidate);
+    // |candidate_score| must be larger to displace the current choice. That way
+    // the client's order controls between ciphers with an equal score.
+    if (candidate_score > best_score) {
       best = candidate;
+      best_score = candidate_score;
     }
   }
 
@@ -194,8 +217,7 @@
         !CBB_add_u8_length_prefixed(&body, &nonce_cbb) ||
         !CBB_add_bytes(&nonce_cbb, nonce, sizeof(nonce)) ||
         !CBB_add_u16_length_prefixed(&body, &ticket) ||
-        !tls13_derive_session_psk(session.get(), nonce,
-                                  ssl->ctx->quic_method != nullptr) ||
+        !tls13_derive_session_psk(session.get(), nonce) ||
         !ssl_encrypt_ticket(hs, &ticket, session.get()) ||
         !CBB_add_u16_length_prefixed(&body, &extensions)) {
       return false;
@@ -663,7 +685,7 @@
 
   // Send the server Certificate message, if necessary.
   if (!ssl->s3->session_reused) {
-    if (!ssl_has_certificate(hs->config)) {
+    if (!ssl_has_certificate(hs)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
       return ssl_hs_error;
     }