Adding support for draft 21 as a TLS 1.3 variant.

Change-Id: I46686aea9b68105cfe70a11db0e88052781e179c
Reviewed-on: https://boringssl-review.googlesource.com/22164
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index a2d3ce7..2dd278c 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -592,6 +592,7 @@
 #define DTLS1_2_VERSION 0xfefd
 
 #define TLS1_3_DRAFT_VERSION 0x7f12
+#define TLS1_3_DRAFT21_VERSION 0x7f15
 #define TLS1_3_EXPERIMENT_VERSION 0x7e01
 #define TLS1_3_EXPERIMENT2_VERSION 0x7e02
 #define TLS1_3_EXPERIMENT3_VERSION 0x7e03
@@ -3234,6 +3235,7 @@
   tls13_experiment = 1,
   tls13_experiment2 = 2,
   tls13_experiment3 = 3,
+  tls13_draft21 = 4,
 };
 
 // SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 6754cec..ae0be88 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -299,6 +299,7 @@
 #define SSL3_MT_CLIENT_HELLO 1
 #define SSL3_MT_SERVER_HELLO 2
 #define SSL3_MT_NEW_SESSION_TICKET 4
+#define SSL3_MT_END_OF_EARLY_DATA 5
 #define SSL3_MT_HELLO_RETRY_REQUEST 6
 #define SSL3_MT_ENCRYPTED_EXTENSIONS 8
 #define SSL3_MT_CERTIFICATE 11
@@ -313,6 +314,7 @@
 #define SSL3_MT_KEY_UPDATE 24
 #define SSL3_MT_NEXT_PROTO 67
 #define SSL3_MT_CHANNEL_ID 203
+#define SSL3_MT_MESSAGE_HASH 254
 #define DTLS1_MT_HELLO_VERIFY_REQUEST 3
 
 // The following are legacy aliases for consumers which use
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 0237e32..f62ee1f 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -214,6 +214,7 @@
 #define TLSEXT_TYPE_cookie 44
 #define TLSEXT_TYPE_psk_key_exchange_modes 45
 #define TLSEXT_TYPE_ticket_early_data_info 46
+#define TLSEXT_TYPE_certificate_authorities 47
 
 // ExtensionType value from RFC5746
 #define TLSEXT_TYPE_renegotiate 0xff01
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index 48466fb..f907939 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -500,9 +500,8 @@
     return ssl_hs_ok;
   }
 
-  if (!tls13_init_early_key_schedule(hs) ||
-      !tls13_advance_key_schedule(hs, ssl->session->master_key,
-                                  ssl->session->master_key_length) ||
+  if (!tls13_init_early_key_schedule(hs, ssl->session->master_key,
+                                     ssl->session->master_key_length) ||
       !tls13_derive_early_secrets(hs) ||
       !tls13_set_traffic_key(ssl, evp_aead_seal, hs->early_traffic_secret,
                              hs->hash_len)) {
diff --git a/ssl/internal.h b/ssl/internal.h
index 2b3335b..55bece9 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -392,6 +392,10 @@
 // call this function before the version is determined.
 uint16_t ssl_protocol_version(const SSL *ssl);
 
+// ssl_is_draft21 returns whether the version corresponds to a draft21 TLS 1.3
+// variant.
+bool ssl_is_draft21(uint16_t version);
+
 // ssl_is_resumption_experiment returns whether the version corresponds to a
 // TLS 1.3 resumption experiment.
 bool ssl_is_resumption_experiment(uint16_t version);
@@ -543,6 +547,16 @@
   // to call this function after the handshake buffer is released.
   bool InitHash(uint16_t version, const SSL_CIPHER *cipher);
 
+  // UpdateForHelloRetryRequest resets the rolling hash with the
+  // HelloRetryRequest construction. It returns true on success and false on
+  // failure. It is an error to call this function before the handshake buffer
+  // is released.
+  bool UpdateForHelloRetryRequest();
+
+  // CopyHashContext copies the hash context into |ctx| and returns true on
+  // success.
+  bool CopyHashContext(EVP_MD_CTX *ctx);
+
   Span<const uint8_t> buffer() {
     return MakeConstSpan(reinterpret_cast<const uint8_t *>(buffer_->data),
                          buffer_->length);
@@ -1157,6 +1171,9 @@
                                                             uint8_t *out_alert,
                                                             CBS *cbs);
 
+// ssl_has_client_CAs returns there are configured CAs.
+bool ssl_has_client_CAs(SSL *ssl);
+
 // ssl_add_client_CA_list adds the configured CA list to |cbb| in the format
 // used by a TLS CertificateRequest message. It returns one on success and zero
 // on error.
@@ -1177,14 +1194,16 @@
 // TLS 1.3 key derivation.
 
 // tls13_init_key_schedule initializes the handshake hash and key derivation
-// state. The cipher suite and PRF hash must have been selected at this point.
-// It returns one on success and zero on error.
-int tls13_init_key_schedule(SSL_HANDSHAKE *hs);
+// state, and incorporates the PSK. The cipher suite and PRF hash must have been
+// selected at this point. It returns one on success and zero on error.
+int tls13_init_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *psk,
+                            size_t psk_len);
 
 // tls13_init_early_key_schedule initializes the handshake hash and key
-// derivation state from the resumption secret to derive the early secrets. It
-// returns one on success and zero on error.
-int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs);
+// derivation state from the resumption secret and incorporates the PSK to
+// derive the early secrets. It returns one on success and zero on error.
+int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *psk,
+                                  size_t psk_len);
 
 // tls13_advance_key_schedule incorporates |in| into the key schedule with
 // HKDF-Extract. It returns one on success and zero on error.
@@ -1231,6 +1250,11 @@
 int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out,
                        size_t *out_len, int is_server);
 
+// 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);
+
 // tls13_write_psk_binder calculates the PSK binder value and replaces the last
 // bytes of |msg| with the resulting value. It returns 1 on success, and 0 on
 // failure.
diff --git a/ssl/s3_pkt.cc b/ssl/s3_pkt.cc
index 285abb3..e6518ba 100644
--- a/ssl/s3_pkt.cc
+++ b/ssl/s3_pkt.cc
@@ -306,7 +306,7 @@
   if (type == SSL3_RT_HANDSHAKE) {
     // If reading 0-RTT data, reject handshake data. 0-RTT data is terminated
     // by an alert.
-    if (is_early_data_read) {
+    if (!ssl_is_draft21(ssl->version) && is_early_data_read) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
       *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
       return ssl_open_record_error;
@@ -335,7 +335,8 @@
   // Handle the end_of_early_data alert.
   static const uint8_t kEndOfEarlyData[2] = {SSL3_AL_WARNING,
                                              TLS1_AD_END_OF_EARLY_DATA};
-  if (is_early_data_read && type == SSL3_RT_ALERT && body == kEndOfEarlyData) {
+  if (!ssl_is_draft21(ssl->version) && is_early_data_read &&
+      type == SSL3_RT_ALERT && body == kEndOfEarlyData) {
     // Stop accepting early data.
     ssl->s3->hs->can_early_read = false;
     return ssl_open_record_discard;
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc
index cd586a0..9a3eef3 100644
--- a/ssl/ssl_cert.cc
+++ b/ssl/ssl_cert.cc
@@ -704,6 +704,17 @@
   return ret;
 }
 
+bool ssl_has_client_CAs(SSL *ssl) {
+  STACK_OF(CRYPTO_BUFFER) *names = ssl->client_CA;
+  if (names == NULL) {
+    names = ssl->ctx->client_CA;
+  }
+  if (names == NULL) {
+    return false;
+  }
+  return sk_CRYPTO_BUFFER_num(names) > 0;
+}
+
 int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) {
   CBB child, name_cbb;
   if (!CBB_add_u16_length_prefixed(cbb, &child)) {
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index ab88134..122313f 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -986,6 +986,13 @@
     // Process any buffered post-handshake messages.
     SSLMessage msg;
     if (ssl->method->get_message(ssl, &msg)) {
+      // If we received an interrupt in early read (EndOfEarlyData), loop again
+      // for the handshake to process it.
+      if (SSL_in_init(ssl)) {
+        ssl->s3->hs->can_early_read = false;
+        continue;
+      }
+
       // Handle the post-handshake message and try again.
       if (!ssl_do_post_handshake(ssl, msg)) {
         ssl_set_read_error(ssl);
diff --git a/ssl/ssl_transcript.cc b/ssl/ssl_transcript.cc
index 8486e5f..2033dfd 100644
--- a/ssl/ssl_transcript.cc
+++ b/ssl/ssl_transcript.cc
@@ -209,6 +209,30 @@
   return EVP_MD_CTX_md(hash_.get());
 }
 
+bool SSLTranscript::UpdateForHelloRetryRequest() {
+  if (buffer_) {
+    buffer_->length = 0;
+  }
+
+  uint8_t old_hash[EVP_MAX_MD_SIZE];
+  size_t hash_len;
+  if (!GetHash(old_hash, &hash_len)) {
+    return false;
+  }
+  const uint8_t header[4] = {SSL3_MT_MESSAGE_HASH, 0, 0,
+                             static_cast<uint8_t>(hash_len)};
+  if (!EVP_DigestInit_ex(hash_.get(), Digest(), nullptr) ||
+      !Update(header) ||
+      !Update(MakeConstSpan(old_hash, hash_len))) {
+    return false;
+  }
+  return true;
+}
+
+bool SSLTranscript::CopyHashContext(EVP_MD_CTX *ctx) {
+  return EVP_MD_CTX_copy_ex(ctx, hash_.get());
+}
+
 bool SSLTranscript::Update(Span<const uint8_t> in) {
   // Depending on the state of the handshake, either the handshake buffer may be
   // active, the rolling hash, or both.
diff --git a/ssl/ssl_versions.cc b/ssl/ssl_versions.cc
index ccae6ef..1f30b41 100644
--- a/ssl/ssl_versions.cc
+++ b/ssl/ssl_versions.cc
@@ -35,6 +35,7 @@
       return true;
 
     case TLS1_3_DRAFT_VERSION:
+    case TLS1_3_DRAFT21_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
@@ -63,6 +64,7 @@
     TLS1_3_EXPERIMENT2_VERSION,
     TLS1_3_EXPERIMENT_VERSION,
     TLS1_3_DRAFT_VERSION,
+    TLS1_3_DRAFT21_VERSION,
     TLS1_2_VERSION,
     TLS1_1_VERSION,
     TLS1_VERSION,
@@ -106,6 +108,7 @@
 static const char *ssl_version_to_string(uint16_t version) {
   switch (version) {
     case TLS1_3_DRAFT_VERSION:
+    case TLS1_3_DRAFT21_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
@@ -138,6 +141,7 @@
   switch (version) {
     // Report TLS 1.3 draft versions as TLS 1.3 in the public API.
     case TLS1_3_DRAFT_VERSION:
+    case TLS1_3_DRAFT21_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
@@ -152,6 +156,7 @@
 // used in context where that does not matter.
 static bool api_version_to_wire(uint16_t *out, uint16_t version) {
   if (version == TLS1_3_DRAFT_VERSION ||
+      version == TLS1_3_DRAFT21_VERSION ||
       version == TLS1_3_EXPERIMENT_VERSION ||
       version == TLS1_3_EXPERIMENT2_VERSION ||
       version == TLS1_3_EXPERIMENT3_VERSION) {
@@ -301,34 +306,42 @@
 
 bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
   SSL *const ssl = hs->ssl;
-  // As a client, only allow the configured TLS 1.3 variant. As a server,
-  // support all TLS 1.3 variants as long as tls13_variant is set to a
-  // non-default value.
-  if (ssl->server) {
-    if (ssl->tls13_variant == tls13_default &&
-        (version == TLS1_3_EXPERIMENT_VERSION ||
-         version == TLS1_3_EXPERIMENT2_VERSION ||
-         version == TLS1_3_EXPERIMENT3_VERSION)) {
-      return false;
-    }
-  } else {
-    if ((ssl->tls13_variant != tls13_experiment &&
-         version == TLS1_3_EXPERIMENT_VERSION) ||
-        (ssl->tls13_variant != tls13_experiment2 &&
-         version == TLS1_3_EXPERIMENT2_VERSION) ||
-        (ssl->tls13_variant != tls13_experiment3 &&
-         version == TLS1_3_EXPERIMENT3_VERSION) ||
-        (ssl->tls13_variant != tls13_default &&
-         version == TLS1_3_DRAFT_VERSION)) {
-      return false;
-    }
+  uint16_t protocol_version;
+  if (!method_supports_version(ssl->method, version) ||
+      !ssl_protocol_version_from_wire(&protocol_version, version) ||
+      hs->min_version > protocol_version ||
+      protocol_version > hs->max_version) {
+    return false;
   }
 
-  uint16_t protocol_version;
-  return method_supports_version(ssl->method, version) &&
-         ssl_protocol_version_from_wire(&protocol_version, version) &&
-         hs->min_version <= protocol_version &&
-         protocol_version <= hs->max_version;
+  // TLS 1.3 variants must additionally match |tls13_variant|.
+  if (protocol_version != TLS1_3_VERSION ||
+      (ssl->tls13_variant == tls13_experiment &&
+       version == TLS1_3_EXPERIMENT_VERSION) ||
+      (ssl->tls13_variant == tls13_experiment2 &&
+       version == TLS1_3_EXPERIMENT2_VERSION) ||
+      (ssl->tls13_variant == tls13_experiment3 &&
+       version == TLS1_3_EXPERIMENT3_VERSION) ||
+      (ssl->tls13_variant == tls13_draft21 &&
+       version == TLS1_3_DRAFT21_VERSION) ||
+      (ssl->tls13_variant == tls13_default &&
+       version == TLS1_3_DRAFT_VERSION)) {
+    return true;
+  }
+
+  // The server, when not configured at |tls13_default|, should additionally
+  // enable all variants, except draft-21 which is implemented solely for QUIC
+  // interop testing and will not be deployed. Currently, this is to implement
+  // the draft-18 vs. experiments field trials. In the future, this will be to
+  // transition cleanly to a future draft-22 which hopefully includes the
+  // deployability fixes.
+  if (ssl->server &&
+      ssl->tls13_variant != tls13_default &&
+      version != TLS1_3_DRAFT21_VERSION) {
+    return true;
+  }
+
+  return false;
 }
 
 bool ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb) {
@@ -375,6 +388,10 @@
   return false;
 }
 
+bool ssl_is_draft21(uint16_t version) {
+  return version == TLS1_3_DRAFT21_VERSION;
+}
+
 bool ssl_is_resumption_experiment(uint16_t version) {
   return version == TLS1_3_EXPERIMENT_VERSION ||
          version == TLS1_3_EXPERIMENT2_VERSION ||
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 47224ea..a7bfec4 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -1800,11 +1800,21 @@
 
 static bool ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
   SSL *const ssl = hs->ssl;
+  hs->needs_psk_binder = false;
   if (hs->max_version < TLS1_3_VERSION || ssl->session == NULL ||
       ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION) {
     return true;
   }
 
+  // Per draft-ietf-tls-tls13-21 section 4.1.4, skip offering the session if the
+  // selected cipher in HelloRetryRequest does not match. This avoids performing
+  // the transcript hash transformation for multiple hashes.
+  if (hs->received_hello_retry_request &&
+      ssl_is_draft21(ssl->version) &&
+      ssl->session->cipher->algorithm_prf != hs->new_cipher->algorithm_prf) {
+    return true;
+  }
+
   struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
   uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time);
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index d439cb5..7eca21d 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1278,6 +1278,9 @@
   if (!config->use_client_ca_list.empty()) {
     if (config->use_client_ca_list == "<NULL>") {
       SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
+    } else if (config->use_client_ca_list == "<EMPTY>") {
+      bssl::UniquePtr<STACK_OF(X509_NAME)> names;
+      SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
     } else {
       bssl::UniquePtr<STACK_OF(X509_NAME)> names =
           DecodeHexX509Names(config->use_client_ca_list);
@@ -2396,14 +2399,13 @@
     }
 
     if (expect_new_session) {
-      bool got_early_data_info =
+      bool got_early_data =
           GetTestState(ssl)->new_session->ticket_max_early_data != 0;
-      if (config->expect_early_data_info != got_early_data_info) {
-        fprintf(
-            stderr,
-            "new session did%s include ticket_early_data_info, but we expected "
-            "the opposite\n",
-            got_early_data_info ? "" : " not");
+      if (config->expect_ticket_supports_early_data != got_early_data) {
+        fprintf(stderr,
+                "new session did%s support early data, but we expected the "
+                "opposite\n",
+                got_early_data ? "" : " not");
         return false;
       }
     }
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index eee1337..9e0deef 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -34,6 +34,7 @@
 // A draft version of TLS 1.3 that is sent over the wire for the current draft.
 const (
 	tls13DraftVersion       = 0x7f12
+	tls13Draft21Version     = 0x7f15
 	tls13ExperimentVersion  = 0x7e01
 	tls13Experiment2Version = 0x7e02
 	tls13Experiment3Version = 0x7e03
@@ -44,10 +45,12 @@
 	TLS13Experiment  = 1
 	TLS13Experiment2 = 2
 	TLS13Experiment3 = 3
+	TLS13Draft21     = 4
 )
 
 var allTLSWireVersions = []uint16{
 	tls13DraftVersion,
+	tls13Draft21Version,
 	tls13Experiment3Version,
 	tls13Experiment2Version,
 	tls13ExperimentVersion,
@@ -91,6 +94,7 @@
 	typeServerHello         uint8 = 2
 	typeHelloVerifyRequest  uint8 = 3
 	typeNewSessionTicket    uint8 = 4
+	typeEndOfEarlyData      uint8 = 5 // draft-ietf-tls-tls13-21
 	typeHelloRetryRequest   uint8 = 6 // draft-ietf-tls-tls13-16
 	typeEncryptedExtensions uint8 = 8 // draft-ietf-tls-tls13-16
 	typeCertificate         uint8 = 11
@@ -104,6 +108,7 @@
 	typeKeyUpdate           uint8 = 24  // draft-ietf-tls-tls13-16
 	typeNextProtocol        uint8 = 67  // Not IANA assigned
 	typeChannelID           uint8 = 203 // Not IANA assigned
+	typeMessageHash         uint8 = 254 // draft-ietf-tls-tls13-21
 )
 
 // TLS compression types.
@@ -131,6 +136,7 @@
 	extensionCookie                     uint16 = 44    // draft-ietf-tls-tls13-16
 	extensionPSKKeyExchangeModes        uint16 = 45    // draft-ietf-tls-tls13-18
 	extensionTicketEarlyDataInfo        uint16 = 46    // draft-ietf-tls-tls13-18
+	extensionCertificateAuthorities     uint16 = 47    // draft-ietf-tls-tls13-21
 	extensionCustom                     uint16 = 1234  // not IANA assigned
 	extensionNextProtoNeg               uint16 = 13172 // not IANA assigned
 	extensionRenegotiationInfo          uint16 = 0xff01
@@ -456,8 +462,7 @@
 	// MaxEarlyDataSize controls the maximum number of bytes that the
 	// server will accept in early data and advertise in a
 	// NewSessionTicketMsg. If 0, no early data will be accepted and
-	// the TicketEarlyDataInfo extension in the NewSessionTicketMsg
-	// will be omitted.
+	// the early_data extension in the NewSessionTicketMsg will be omitted.
 	MaxEarlyDataSize uint32
 
 	// SRTPProtectionProfiles, if not nil, is the list of SRTP
@@ -581,10 +586,14 @@
 	// message.
 	SkipFinished bool
 
-	// SkipEndOfEarlyData causes the implementation to skip the
-	// end_of_early_data alert.
+	// SkipEndOfEarlyData causes the implementation to skip
+	// end_of_early_data.
 	SkipEndOfEarlyData bool
 
+	// NonEmptyEndOfEarlyData causes the implementation to end an extra byte in the
+	// EndOfEarlyData.
+	NonEmptyEndOfEarlyData bool
+
 	// SkipCertificateVerify, if true causes peer to skip sending a
 	// CertificateVerify message after the Certificate message.
 	SkipCertificateVerify bool
@@ -755,6 +764,10 @@
 	// if a TLS 1.3 PSK is offered.
 	ExpectNoTLS13PSK bool
 
+	// ExpectNoTLS13PSKAfterHRR, if true, causes the server to fail the connection
+	// if a TLS 1.3 PSK is offered after HRR.
+	ExpectNoTLS13PSKAfterHRR bool
+
 	// RequireExtendedMasterSecret, if true, requires that the peer support
 	// the extended master secret option.
 	RequireExtendedMasterSecret bool
@@ -1054,13 +1067,13 @@
 	// receipt of a NewSessionTicket message.
 	ExpectNoNewSessionTicket bool
 
-	// DuplicateTicketEarlyDataInfo causes an extra empty extension of
-	// ticket_early_data_info to be sent in NewSessionTicket.
-	DuplicateTicketEarlyDataInfo bool
+	// DuplicateTicketEarlyData causes an extra empty extension of early_data to
+	// be sent in NewSessionTicket.
+	DuplicateTicketEarlyData bool
 
-	// ExpectTicketEarlyDataInfo, if true, means that the client will fail upon
-	// absence of the ticket_early_data_info extension.
-	ExpectTicketEarlyDataInfo bool
+	// ExpectTicketEarlyData, if true, means that the client will fail upon
+	// absence of the early_data extension.
+	ExpectTicketEarlyData bool
 
 	// ExpectTicketAge, if non-zero, is the expected age of the ticket that the
 	// server receives from the client.
@@ -1308,6 +1321,10 @@
 	// the specified curve in a HelloRetryRequest.
 	SendHelloRetryRequestCurve CurveID
 
+	// SendHelloRetryRequestCipherSuite, if non-zero, causes the server to send
+	// the specified cipher suite in a HelloRetryRequest.
+	SendHelloRetryRequestCipherSuite uint16
+
 	// SendHelloRetryRequestCookie, if not nil, contains a cookie to be
 	// sent by the server in HelloRetryRequest.
 	SendHelloRetryRequestCookie []byte
@@ -1345,6 +1362,14 @@
 	// a TLS 1.3 CertificateRequest.
 	SendRequestContext []byte
 
+	// OmitCertificateRequestAlgorithms, if true, omits the signature_algorithm
+	// extension in a TLS 1.3 CertificateRequest.
+	OmitCertificateRequestAlgorithms bool
+
+	// SendCustomCertificateRequest, if non-zero, send an additional custom
+	// extension in a TLS 1.3 CertificateRequest.
+	SendCustomCertificateRequest uint16
+
 	// SendSNIWarningAlert, if true, causes the server to send an
 	// unrecognized_name alert before the ServerHello.
 	SendSNIWarningAlert bool
@@ -1432,6 +1457,10 @@
 	// renegotiation handshakes.
 	RenegotiationCertificate *Certificate
 
+	// ExpectNoCertificateAuthoritiesExtension, if true, causes the client to
+	// reject CertificateRequest with the CertificateAuthorities extension.
+	ExpectNoCertificateAuthoritiesExtension bool
+
 	// UseLegacySigningAlgorithm, if non-zero, is the signature algorithm
 	// to use when signing in TLS 1.1 and earlier where algorithms are not
 	// negotiated.
@@ -1576,7 +1605,7 @@
 		switch vers {
 		case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
 			return vers, true
-		case tls13DraftVersion, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version:
+		case tls13DraftVersion, tls13Draft21Version, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version:
 			return VersionTLS13, true
 		}
 	}
@@ -1584,6 +1613,10 @@
 	return 0, false
 }
 
+func isDraft21(vers uint16) bool {
+	return vers == tls13Draft21Version
+}
+
 func isResumptionExperiment(vers uint16) bool {
 	return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Experiment3Version
 }
@@ -1603,6 +1636,7 @@
 	if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) ||
 		(c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) ||
 		(c.TLS13Variant != TLS13Experiment3 && wireVers == tls13Experiment3Version) ||
+		(c.TLS13Variant != TLS13Draft21 && wireVers == tls13Draft21Version) ||
 		(c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) {
 		return 0, false
 	}
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 71b52f2..6a2c59c 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -1274,7 +1274,8 @@
 		m = new(helloRetryRequestMsg)
 	case typeNewSessionTicket:
 		m = &newSessionTicketMsg{
-			version: c.vers,
+			vers:   c.wireVersion,
+			isDTLS: c.isDTLS,
 		}
 	case typeEncryptedExtensions:
 		m = new(encryptedExtensionsMsg)
@@ -1284,6 +1285,7 @@
 		}
 	case typeCertificateRequest:
 		m = &certificateRequestMsg{
+			vers: c.wireVersion,
 			hasSignatureAlgorithm: c.vers >= VersionTLS12,
 			hasRequestContext:     c.vers >= VersionTLS13,
 		}
@@ -1309,6 +1311,8 @@
 		m = new(channelIDMsg)
 	case typeKeyUpdate:
 		m = new(keyUpdateMsg)
+	case typeEndOfEarlyData:
+		m = new(endOfEarlyDataMsg)
 	default:
 		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 	}
@@ -1469,8 +1473,8 @@
 		return errors.New("tls: no GREASE ticket extension found")
 	}
 
-	if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
-		return errors.New("tls: no ticket_early_data_info extension found")
+	if c.config.Bugs.ExpectTicketEarlyData && newSessionTicket.maxEarlyDataSize == 0 {
+		return errors.New("tls: no early_data ticket extension found")
 	}
 
 	if c.config.Bugs.ExpectNoNewSessionTicket {
@@ -1497,6 +1501,10 @@
 		earlyALPN:          c.clientProtocol,
 	}
 
+	if isDraft21(c.wireVersion) {
+		session.masterSecret = deriveSessionPSK(cipherSuite, c.wireVersion, c.resumptionSecret, newSessionTicket.ticketNonce)
+	}
+
 	cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
 	_, ok := c.config.ClientSessionCache.Get(cacheKey)
 	if !ok || !c.config.Bugs.UseFirstSessionTicket {
@@ -1537,7 +1545,7 @@
 		if c.config.Bugs.RejectUnsolicitedKeyUpdate {
 			return errors.New("tls: unexpected KeyUpdate message")
 		}
-		if err := c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.in.trafficSecret)); err != nil {
+		if err := c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.wireVersion, c.in.trafficSecret)); err != nil {
 			return err
 		}
 		if keyUpdate.keyUpdateRequest == keyUpdateRequested {
@@ -1571,7 +1579,7 @@
 		return errors.New("tls: received invalid KeyUpdate message")
 	}
 
-	return c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.in.trafficSecret))
+	return c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.wireVersion, c.in.trafficSecret))
 }
 
 func (c *Conn) Renegotiate() error {
@@ -1789,9 +1797,16 @@
 	}
 
 	if c.vers >= VersionTLS13 {
-		// TODO(davidben): What should we do with useContext? See
-		// https://github.com/tlswg/tls13-spec/issues/546
-		return hkdfExpandLabel(c.cipherSuite.hash(), c.exporterSecret, label, context, length), nil
+		if isDraft21(c.wireVersion) {
+			hash := c.cipherSuite.hash()
+			exporterKeyingLabel := []byte("exporter")
+			contextHash := hash.New()
+			contextHash.Write(context)
+			exporterContext := hash.New().Sum(nil)
+			derivedSecret := hkdfExpandLabel(c.cipherSuite.hash(), c.wireVersion, c.exporterSecret, label, exporterContext, hash.Size())
+			return hkdfExpandLabel(c.cipherSuite.hash(), c.wireVersion, derivedSecret, exporterKeyingLabel, contextHash.Sum(nil), length), nil
+		}
+		return hkdfExpandLabel(c.cipherSuite.hash(), c.wireVersion, c.exporterSecret, label, context, length), nil
 	}
 
 	seedLen := len(c.clientRandom) + len(c.serverRandom)
@@ -1825,7 +1840,7 @@
 	return false
 }
 
-func (c *Conn) SendNewSessionTicket() error {
+func (c *Conn) SendNewSessionTicket(nonce []byte) error {
 	if c.isClient || c.vers < VersionTLS13 {
 		return errors.New("tls: cannot send post-handshake NewSessionTicket")
 	}
@@ -1845,12 +1860,17 @@
 
 	// TODO(davidben): Allow configuring these values.
 	m := &newSessionTicketMsg{
-		version:                c.vers,
-		ticketLifetime:         uint32(24 * time.Hour / time.Second),
-		duplicateEarlyDataInfo: c.config.Bugs.DuplicateTicketEarlyDataInfo,
-		customExtension:        c.config.Bugs.CustomTicketExtension,
-		ticketAgeAdd:           ticketAgeAdd,
-		maxEarlyDataSize:       c.config.MaxEarlyDataSize,
+		vers:                        c.wireVersion,
+		isDTLS:                      c.isDTLS,
+		ticketLifetime:              uint32(24 * time.Hour / time.Second),
+		duplicateEarlyDataExtension: c.config.Bugs.DuplicateTicketEarlyData,
+		customExtension:             c.config.Bugs.CustomTicketExtension,
+		ticketAgeAdd:                ticketAgeAdd,
+		maxEarlyDataSize:            c.config.MaxEarlyDataSize,
+	}
+
+	if isDraft21(c.wireVersion) {
+		m.ticketNonce = nonce
 	}
 
 	if c.config.Bugs.SendTicketLifetime != 0 {
@@ -1868,6 +1888,10 @@
 		earlyALPN:          []byte(c.clientProtocol),
 	}
 
+	if isDraft21(c.wireVersion) {
+		state.masterSecret = deriveSessionPSK(c.cipherSuite, c.wireVersion, c.resumptionSecret, nonce)
+	}
+
 	if !c.config.Bugs.SendEmptySessionTicket {
 		var err error
 		m.ticket, err = c.encryptTicket(&state)
@@ -1901,7 +1925,7 @@
 	if err := c.flushHandshake(); err != nil {
 		return err
 	}
-	c.useOutTrafficSecret(c.out.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.out.trafficSecret))
+	c.useOutTrafficSecret(c.out.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.wireVersion, c.out.trafficSecret))
 	return nil
 }
 
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index a07a815..ba34647 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -372,7 +372,14 @@
 		c.writeV2Record(helloBytes)
 	} else {
 		if len(hello.pskIdentities) > 0 {
-			generatePSKBinders(hello, pskCipherSuite, session.masterSecret, []byte{}, c.config)
+			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.
+			if session.vers < VersionTLS13 {
+				version = tls13DraftVersion
+			}
+			generatePSKBinders(version, hello, pskCipherSuite, session.masterSecret, []byte{}, []byte{}, c.config)
 		}
 		helloBytes = hello.marshal()
 
@@ -403,10 +410,16 @@
 
 	// Derive early write keys and set Conn state to allow early writes.
 	if sendEarlyData {
-		finishedHash := newFinishedHash(session.vers, pskCipherSuite)
+		finishedHash := newFinishedHash(session.wireVersion, c.isDTLS, pskCipherSuite)
 		finishedHash.addEntropy(session.masterSecret)
 		finishedHash.Write(helloBytes)
-		earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel)
+
+		earlyLabel := earlyTrafficLabel
+		if isDraft21(session.wireVersion) {
+			earlyLabel = earlyTrafficLabelDraft21
+		}
+
+		earlyTrafficSecret := finishedHash.deriveSecret(earlyLabel)
 		c.useOutTrafficSecret(session.wireVersion, pskCipherSuite, earlyTrafficSecret)
 		for _, earlyData := range c.config.Bugs.SendEarlyData {
 			if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil {
@@ -514,7 +527,7 @@
 		hello.raw = nil
 
 		if len(hello.pskIdentities) > 0 {
-			generatePSKBinders(hello, pskCipherSuite, session.masterSecret, append(helloBytes, helloRetryRequest.marshal()...), c.config)
+			generatePSKBinders(c.wireVersion, hello, pskCipherSuite, session.masterSecret, helloBytes, helloRetryRequest.marshal(), c.config)
 		}
 		secondHelloBytes = hello.marshal()
 
@@ -584,13 +597,19 @@
 		serverHello:  serverHello,
 		hello:        hello,
 		suite:        suite,
-		finishedHash: newFinishedHash(c.vers, suite),
+		finishedHash: newFinishedHash(c.wireVersion, c.isDTLS, suite),
 		keyShares:    keyShares,
 		session:      session,
 	}
 
 	hs.writeHash(helloBytes, hs.c.sendHandshakeSeq-1)
 	if haveHelloRetryRequest {
+		if isDraft21(c.wireVersion) {
+			err = hs.finishedHash.UpdateForHelloRetryRequest()
+			if err != nil {
+				return err
+			}
+		}
 		hs.writeServerHash(helloRetryRequest.marshal())
 		hs.writeClientHash(secondHelloBytes)
 	}
@@ -735,8 +754,10 @@
 		if err != nil {
 			return err
 		}
+		hs.finishedHash.nextSecret()
 		hs.finishedHash.addEntropy(ecdheSecret)
 	} else {
+		hs.finishedHash.nextSecret()
 		hs.finishedHash.addEntropy(zeroSecret)
 	}
 
@@ -746,10 +767,17 @@
 		}
 	}
 
+	clientLabel := clientHandshakeTrafficLabel
+	serverLabel := serverHandshakeTrafficLabel
+	if isDraft21(c.wireVersion) {
+		clientLabel = clientHandshakeTrafficLabelDraft21
+		serverLabel = serverHandshakeTrafficLabelDraft21
+	}
+
 	// Derive handshake traffic keys and switch read key to handshake
 	// traffic key.
-	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
-	serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel)
+	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
+	serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
 	if err := c.useInTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret); err != nil {
 		return err
 	}
@@ -791,6 +819,10 @@
 				return errors.New("tls: non-empty certificate request context sent in handshake")
 			}
 
+			if c.config.Bugs.ExpectNoCertificateAuthoritiesExtension && certReq.hasCAExtension {
+				return errors.New("tls: expected no certificate_authorities extension")
+			}
+
 			if c.config.Bugs.IgnorePeerSignatureAlgorithmPreferences {
 				certReq.signatureAlgorithms = c.config.signSignatureAlgorithms()
 			}
@@ -879,10 +911,21 @@
 
 	// The various secrets do not incorporate the client's final leg, so
 	// derive them now before updating the handshake context.
+	hs.finishedHash.nextSecret()
 	hs.finishedHash.addEntropy(zeroSecret)
-	clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
-	serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel)
-	c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel)
+
+	clientLabel = clientApplicationTrafficLabel
+	serverLabel = serverApplicationTrafficLabel
+	exportLabel := exporterLabel
+	if isDraft21(c.wireVersion) {
+		clientLabel = clientApplicationTrafficLabelDraft21
+		serverLabel = serverApplicationTrafficLabelDraft21
+		exportLabel = exporterLabelDraft21
+	}
+
+	clientTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
+	serverTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
+	c.exporterSecret = hs.finishedHash.deriveSecret(exportLabel)
 
 	// Switch to application data keys on read. In particular, any alerts
 	// from the client certificate are read over these keys.
@@ -890,8 +933,8 @@
 		return err
 	}
 
-	// If we're expecting 0.5-RTT messages from the server, read them
-	// now.
+	// If we're expecting 0.5-RTT messages from the server, read them now.
+	var deferredTickets []*newSessionTicketMsg
 	if encryptedExtensions.extensions.hasEarlyData {
 		// BoringSSL will always send two tickets half-RTT when
 		// negotiating 0-RTT.
@@ -904,9 +947,8 @@
 			if !ok {
 				return errors.New("tls: expected half-RTT ticket")
 			}
-			if err := c.processTLS13NewSessionTicket(newSessionTicket, hs.suite); err != nil {
-				return err
-			}
+			// Defer processing until the resumption secret is computed.
+			deferredTickets = append(deferredTickets, newSessionTicket)
 		}
 		for _, expectedMsg := range c.config.Bugs.ExpectHalfRTTData {
 			if err := c.readRecord(recordTypeApplicationData); err != nil {
@@ -922,12 +964,19 @@
 
 	// Send EndOfEarlyData and then switch write key to handshake
 	// traffic key.
-	if c.out.cipher != nil && !c.config.Bugs.SkipEndOfEarlyData {
+	if encryptedExtensions.extensions.hasEarlyData && c.out.cipher != nil && !c.config.Bugs.SkipEndOfEarlyData {
 		if c.config.Bugs.SendStrayEarlyHandshake {
 			helloRequest := new(helloRequestMsg)
 			c.writeRecord(recordTypeHandshake, helloRequest.marshal())
 		}
-		c.sendAlert(alertEndOfEarlyData)
+		if isDraft21(c.wireVersion) {
+			endOfEarlyData := new(endOfEarlyDataMsg)
+			endOfEarlyData.nonEmpty = c.config.Bugs.NonEmptyEndOfEarlyData
+			c.writeRecord(recordTypeHandshake, endOfEarlyData.marshal())
+			hs.writeClientHash(endOfEarlyData.marshal())
+		} else {
+			c.sendAlert(alertEndOfEarlyData)
+		}
 	}
 
 	if isResumptionClientCCSExperiment(c.wireVersion) {
@@ -1022,7 +1071,18 @@
 	// Switch to application data keys.
 	c.useOutTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret)
 
-	c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel)
+	resumeLabel := resumptionLabel
+	if isDraft21(c.wireVersion) {
+		resumeLabel = resumptionLabelDraft21
+	}
+
+	c.resumptionSecret = hs.finishedHash.deriveSecret(resumeLabel)
+	for _, ticket := range deferredTickets {
+		if err := c.processTLS13NewSessionTicket(ticket, hs.suite); err != nil {
+			return err
+		}
+	}
+
 	return nil
 }
 
@@ -1498,6 +1558,7 @@
 	// session ID or session ticket will be attached.
 	session := &ClientSessionState{
 		vers:               c.vers,
+		wireVersion:        c.wireVersion,
 		cipherSuite:        hs.suite.id,
 		masterSecret:       hs.masterSecret,
 		handshakeHash:      hs.finishedHash.Sum(),
@@ -1731,7 +1792,7 @@
 	copy(b[len(b)-len(xb):], xb)
 }
 
-func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, transcript []byte, config *Config) {
+func generatePSKBinders(version uint16, hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, firstClientHello, helloRetryRequest []byte, config *Config) {
 	if config.Bugs.SendNoPSKBinder {
 		return
 	}
@@ -1757,7 +1818,11 @@
 	helloBytes := hello.marshal()
 	binderSize := len(hello.pskBinders)*(binderLen+1) + 2
 	truncatedHello := helloBytes[:len(helloBytes)-binderSize]
-	binder := computePSKBinder(psk, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+	binderLabel := resumptionPSKBinderLabel
+	if isDraft21(version) {
+		binderLabel = resumptionPSKBinderLabelDraft21
+	}
+	binder := computePSKBinder(psk, version, binderLabel, pskCipherSuite, firstClientHello, helloRetryRequest, truncatedHello)
 	if config.Bugs.SendShortPSKBinder {
 		binder = binder[:binderLen]
 	}
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index bf9cb7f..aa6b463 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -1406,6 +1406,7 @@
 type helloRetryRequestMsg struct {
 	raw                 []byte
 	vers                uint16
+	cipherSuite         uint16
 	hasSelectedGroup    bool
 	selectedGroup       CurveID
 	cookie              []byte
@@ -1422,6 +1423,9 @@
 	retryRequestMsg.addU8(typeHelloRetryRequest)
 	retryRequest := retryRequestMsg.addU24LengthPrefixed()
 	retryRequest.addU16(m.vers)
+	if isDraft21(m.vers) {
+		retryRequest.addU16(m.cipherSuite)
+	}
 	extensions := retryRequest.addU16LengthPrefixed()
 
 	count := 1
@@ -1456,8 +1460,13 @@
 		return false
 	}
 	m.vers = uint16(data[4])<<8 | uint16(data[5])
-	extLen := int(data[6])<<8 | int(data[7])
-	data = data[8:]
+	data = data[6:]
+	if isDraft21(m.vers) {
+		m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+		data = data[2:]
+	}
+	extLen := int(data[0])<<8 | int(data[1])
+	data = data[2:]
 	if len(data) != extLen || len(data) == 0 {
 		return false
 	}
@@ -1870,7 +1879,8 @@
 }
 
 type certificateRequestMsg struct {
-	raw []byte
+	raw  []byte
+	vers uint16
 	// hasSignatureAlgorithm indicates whether this message includes a list
 	// of signature and hash functions. This change was introduced with TLS
 	// 1.2.
@@ -1884,6 +1894,8 @@
 	requestContext         []byte
 	signatureAlgorithms    []signatureAlgorithm
 	certificateAuthorities [][]byte
+	hasCAExtension         bool
+	customExtension        uint16
 }
 
 func (m *certificateRequestMsg) marshal() []byte {
@@ -1899,33 +1911,119 @@
 	if m.hasRequestContext {
 		requestContext := body.addU8LengthPrefixed()
 		requestContext.addBytes(m.requestContext)
+		extensions := newByteBuilder()
+		if isDraft21(m.vers) {
+			extensions = body.addU16LengthPrefixed()
+			if m.hasSignatureAlgorithm {
+				extensions.addU16(extensionSignatureAlgorithms)
+				signatureAlgorithms := extensions.addU16LengthPrefixed().addU16LengthPrefixed()
+				for _, sigAlg := range m.signatureAlgorithms {
+					signatureAlgorithms.addU16(uint16(sigAlg))
+				}
+			}
+			if len(m.certificateAuthorities) > 0 {
+				extensions.addU16(extensionCertificateAuthorities)
+				certificateAuthorities := extensions.addU16LengthPrefixed().addU16LengthPrefixed()
+				for _, ca := range m.certificateAuthorities {
+					caEntry := certificateAuthorities.addU16LengthPrefixed()
+					caEntry.addBytes(ca)
+				}
+			}
+		} else {
+			if m.hasSignatureAlgorithm {
+				signatureAlgorithms := body.addU16LengthPrefixed()
+				for _, sigAlg := range m.signatureAlgorithms {
+					signatureAlgorithms.addU16(uint16(sigAlg))
+				}
+			}
+
+			certificateAuthorities := body.addU16LengthPrefixed()
+			for _, ca := range m.certificateAuthorities {
+				caEntry := certificateAuthorities.addU16LengthPrefixed()
+				caEntry.addBytes(ca)
+			}
+			extensions = body.addU16LengthPrefixed()
+		}
+
+		if m.customExtension > 0 {
+			extensions.addU16(m.customExtension)
+			extensions.addU16LengthPrefixed()
+		}
 	} else {
 		certificateTypes := body.addU8LengthPrefixed()
 		certificateTypes.addBytes(m.certificateTypes)
-	}
 
-	if m.hasSignatureAlgorithm {
-		signatureAlgorithms := body.addU16LengthPrefixed()
-		for _, sigAlg := range m.signatureAlgorithms {
-			signatureAlgorithms.addU16(uint16(sigAlg))
+		if m.hasSignatureAlgorithm {
+			signatureAlgorithms := body.addU16LengthPrefixed()
+			for _, sigAlg := range m.signatureAlgorithms {
+				signatureAlgorithms.addU16(uint16(sigAlg))
+			}
 		}
-	}
 
-	certificateAuthorities := body.addU16LengthPrefixed()
-	for _, ca := range m.certificateAuthorities {
-		caEntry := certificateAuthorities.addU16LengthPrefixed()
-		caEntry.addBytes(ca)
-	}
-
-	if m.hasRequestContext {
-		// Emit no certificate extensions.
-		body.addU16(0)
+		certificateAuthorities := body.addU16LengthPrefixed()
+		for _, ca := range m.certificateAuthorities {
+			caEntry := certificateAuthorities.addU16LengthPrefixed()
+			caEntry.addBytes(ca)
+		}
 	}
 
 	m.raw = builder.finish()
 	return m.raw
 }
 
+func parseSignatureAlgorithms(data []byte) ([]signatureAlgorithm, []byte, bool) {
+	if len(data) < 2 {
+		return nil, nil, false
+	}
+	sigAlgsLen := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+	if sigAlgsLen&1 != 0 {
+		return nil, nil, false
+	}
+	if len(data) < int(sigAlgsLen) {
+		return nil, nil, false
+	}
+	numSigAlgs := sigAlgsLen / 2
+	signatureAlgorithms := make([]signatureAlgorithm, numSigAlgs)
+	for i := range signatureAlgorithms {
+		signatureAlgorithms[i] = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(data[1])
+		data = data[2:]
+	}
+
+	return signatureAlgorithms, data, true
+}
+
+func parseCAs(data []byte) ([][]byte, []byte, bool) {
+	if len(data) < 2 {
+		return nil, nil, false
+	}
+	casLength := uint16(data[0])<<8 | uint16(data[1])
+	data = data[2:]
+	if len(data) < int(casLength) {
+		return nil, nil, false
+	}
+
+	cas := data[:casLength]
+	data = data[casLength:]
+
+	var certificateAuthorities [][]byte
+	for len(cas) > 0 {
+		if len(cas) < 2 {
+			return nil, nil, false
+		}
+		caLen := uint16(cas[0])<<8 | uint16(cas[1])
+		cas = cas[2:]
+
+		if len(cas) < int(caLen) {
+			return nil, nil, false
+		}
+
+		certificateAuthorities = append(certificateAuthorities, cas[:caLen])
+		cas = cas[caLen:]
+	}
+	return certificateAuthorities, data, true
+}
+
 func (m *certificateRequestMsg) unmarshal(data []byte) bool {
 	m.raw = data
 
@@ -1942,6 +2040,70 @@
 		m.requestContext = make([]byte, contextLen)
 		copy(m.requestContext, data[1:])
 		data = data[1+contextLen:]
+		if isDraft21(m.vers) {
+			if len(data) < 2 {
+				return false
+			}
+			extensionsLen := int(data[0])<<8 | int(data[1])
+			if len(data) < 2+extensionsLen {
+				return false
+			}
+			extensions := data[2 : 2+extensionsLen]
+			data = data[2+extensionsLen:]
+			for len(extensions) != 0 {
+				if len(extensions) < 4 {
+					return false
+				}
+				extension := uint16(extensions[0])<<8 | uint16(extensions[1])
+				length := int(extensions[2])<<8 | int(extensions[3])
+				if len(extensions) < 4+length {
+					return false
+				}
+				contents := extensions[4 : 4+length]
+				extensions = extensions[4+length:]
+				switch extension {
+				case extensionSignatureAlgorithms:
+					sigAlgs, rest, ok := parseSignatureAlgorithms(contents)
+					if !ok || len(rest) != 0 {
+						return false
+					}
+					m.signatureAlgorithms = sigAlgs
+				case extensionCertificateAuthorities:
+					cas, rest, ok := parseCAs(contents)
+					if !ok || len(rest) != 0 {
+						return false
+					}
+					m.hasCAExtension = true
+					m.certificateAuthorities = cas
+				}
+			}
+		} else {
+			if m.hasSignatureAlgorithm {
+				sigAlgs, rest, ok := parseSignatureAlgorithms(data)
+				if !ok {
+					return false
+				}
+				m.signatureAlgorithms = sigAlgs
+				data = rest
+			}
+
+			cas, rest, ok := parseCAs(data)
+			if !ok {
+				return false
+			}
+			m.certificateAuthorities = cas
+			data = rest
+
+			// Ignore certificate extensions.
+			if len(data) < 2 {
+				return false
+			}
+			extsLength := int(data[0])<<8 | int(data[1])
+			if len(data) < 2+extsLength {
+				return false
+			}
+			data = data[2+extsLength:]
+		}
 	} else {
 		numCertTypes := int(data[0])
 		if len(data) < 1+numCertTypes {
@@ -1950,66 +2112,22 @@
 		m.certificateTypes = make([]byte, numCertTypes)
 		copy(m.certificateTypes, data[1:])
 		data = data[1+numCertTypes:]
-	}
 
-	if m.hasSignatureAlgorithm {
-		if len(data) < 2 {
-			return false
-		}
-		sigAlgsLen := uint16(data[0])<<8 | uint16(data[1])
-		data = data[2:]
-		if sigAlgsLen&1 != 0 {
-			return false
-		}
-		if len(data) < int(sigAlgsLen) {
-			return false
-		}
-		numSigAlgs := sigAlgsLen / 2
-		m.signatureAlgorithms = make([]signatureAlgorithm, numSigAlgs)
-		for i := range m.signatureAlgorithms {
-			m.signatureAlgorithms[i] = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(data[1])
-			data = data[2:]
-		}
-	}
-
-	if len(data) < 2 {
-		return false
-	}
-	casLength := uint16(data[0])<<8 | uint16(data[1])
-	data = data[2:]
-	if len(data) < int(casLength) {
-		return false
-	}
-	cas := make([]byte, casLength)
-	copy(cas, data)
-	data = data[casLength:]
-
-	m.certificateAuthorities = nil
-	for len(cas) > 0 {
-		if len(cas) < 2 {
-			return false
-		}
-		caLen := uint16(cas[0])<<8 | uint16(cas[1])
-		cas = cas[2:]
-
-		if len(cas) < int(caLen) {
-			return false
+		if m.hasSignatureAlgorithm {
+			sigAlgs, rest, ok := parseSignatureAlgorithms(data)
+			if !ok {
+				return false
+			}
+			m.signatureAlgorithms = sigAlgs
+			data = rest
 		}
 
-		m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
-		cas = cas[caLen:]
-	}
-
-	if m.hasRequestContext {
-		// Ignore certificate extensions.
-		if len(data) < 2 {
+		cas, rest, ok := parseCAs(data)
+		if !ok {
 			return false
 		}
-		extsLength := int(data[0])<<8 | int(data[1])
-		if len(data) < 2+extsLength {
-			return false
-		}
-		data = data[2+extsLength:]
+		m.certificateAuthorities = cas
+		data = rest
 	}
 
 	if len(data) > 0 {
@@ -2090,15 +2208,17 @@
 }
 
 type newSessionTicketMsg struct {
-	raw                    []byte
-	version                uint16
-	ticketLifetime         uint32
-	ticketAgeAdd           uint32
-	ticket                 []byte
-	maxEarlyDataSize       uint32
-	customExtension        string
-	duplicateEarlyDataInfo bool
-	hasGREASEExtension     bool
+	raw                         []byte
+	vers                        uint16
+	isDTLS                      bool
+	ticketLifetime              uint32
+	ticketAgeAdd                uint32
+	ticketNonce                 []byte
+	ticket                      []byte
+	maxEarlyDataSize            uint32
+	customExtension             string
+	duplicateEarlyDataExtension bool
+	hasGREASEExtension          bool
 }
 
 func (m *newSessionTicketMsg) marshal() []byte {
@@ -2106,25 +2226,37 @@
 		return m.raw
 	}
 
+	version, ok := wireToVersion(m.vers, m.isDTLS)
+	if !ok {
+		panic("unknown version")
+	}
+
 	// See http://tools.ietf.org/html/rfc5077#section-3.3
 	ticketMsg := newByteBuilder()
 	ticketMsg.addU8(typeNewSessionTicket)
 	body := ticketMsg.addU24LengthPrefixed()
 	body.addU32(m.ticketLifetime)
-	if m.version >= VersionTLS13 {
+	if version >= VersionTLS13 {
 		body.addU32(m.ticketAgeAdd)
+		if isDraft21(m.vers) {
+			body.addU8LengthPrefixed().addBytes(m.ticketNonce)
+		}
 	}
 
 	ticket := body.addU16LengthPrefixed()
 	ticket.addBytes(m.ticket)
 
-	if m.version >= VersionTLS13 {
+	if version >= VersionTLS13 {
 		extensions := body.addU16LengthPrefixed()
 		if m.maxEarlyDataSize > 0 {
-			extensions.addU16(extensionTicketEarlyDataInfo)
+			extID := extensionTicketEarlyDataInfo
+			if isDraft21(m.vers) {
+				extID = extensionEarlyData
+			}
+			extensions.addU16(extID)
 			extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
-			if m.duplicateEarlyDataInfo {
-				extensions.addU16(extensionTicketEarlyDataInfo)
+			if m.duplicateEarlyDataExtension {
+				extensions.addU16(extID)
 				extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
 			}
 		}
@@ -2141,18 +2273,32 @@
 func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
 	m.raw = data
 
+	version, ok := wireToVersion(m.vers, m.isDTLS)
+	if !ok {
+		panic("unknown version")
+	}
+
 	if len(data) < 8 {
 		return false
 	}
 	m.ticketLifetime = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
 	data = data[8:]
 
-	if m.version >= VersionTLS13 {
+	if version >= VersionTLS13 {
 		if len(data) < 4 {
 			return false
 		}
 		m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
 		data = data[4:]
+		if isDraft21(m.vers) {
+			nonceLen := int(data[0])
+			data = data[1:]
+			if len(data) < nonceLen {
+				return false
+			}
+			m.ticketNonce = data[:nonceLen]
+			data = data[nonceLen:]
+		}
 	}
 
 	if len(data) < 2 {
@@ -2164,14 +2310,14 @@
 		return false
 	}
 
-	if m.version >= VersionTLS13 && ticketLen == 0 {
+	if version >= VersionTLS13 && ticketLen == 0 {
 		return false
 	}
 
 	m.ticket = data[:ticketLen]
 	data = data[ticketLen:]
 
-	if m.version >= VersionTLS13 {
+	if version >= VersionTLS13 {
 		if len(data) < 2 {
 			return false
 		}
@@ -2182,6 +2328,11 @@
 			return false
 		}
 
+		extID := extensionTicketEarlyDataInfo
+		if isDraft21(m.vers) {
+			extID = extensionEarlyData
+		}
+
 		for len(data) != 0 {
 			if len(data) < 4 {
 				return false
@@ -2194,7 +2345,7 @@
 			}
 
 			switch extension {
-			case extensionTicketEarlyDataInfo:
+			case extID:
 				if length != 4 {
 					return false
 				}
@@ -2381,6 +2532,21 @@
 	return m.keyUpdateRequest == keyUpdateNotRequested || m.keyUpdateRequest == keyUpdateRequested
 }
 
+type endOfEarlyDataMsg struct {
+	nonEmpty bool
+}
+
+func (m *endOfEarlyDataMsg) marshal() []byte {
+	if m.nonEmpty {
+		return []byte{typeEndOfEarlyData, 0, 0, 1, 42}
+	}
+	return []byte{typeEndOfEarlyData, 0, 0, 0}
+}
+
+func (*endOfEarlyDataMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
 // ssl3NoCertificateMsg is a dummy message to handle SSL 3.0 using a warning
 // alert in the handshake.
 type ssl3NoCertificateMsg struct{}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 0bf14eb..dd6f48f 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -412,7 +412,7 @@
 		hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
 	}
 
-	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash = newFinishedHash(c.wireVersion, c.isDTLS, hs.suite)
 	hs.finishedHash.discardHandshakeBuffer()
 	hs.writeClientHash(hs.clientHello.marshal())
 
@@ -496,7 +496,7 @@
 	// AcceptAnyBinder is set. See https://crbug.com/boringssl/115.
 	if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
 		binderToVerify := hs.clientHello.pskBinders[pskIndex]
-		if err := verifyPSKBinder(hs.clientHello, hs.sessionState, binderToVerify, []byte{}); err != nil {
+		if err := verifyPSKBinder(c.wireVersion, hs.clientHello, hs.sessionState, binderToVerify, []byte{}, []byte{}); err != nil {
 			return err
 		}
 	}
@@ -520,8 +520,13 @@
 
 ResendHelloRetryRequest:
 	var sendHelloRetryRequest bool
+	cipherSuite := hs.suite.id
+	if config.Bugs.SendHelloRetryRequestCipherSuite != 0 {
+		cipherSuite = config.Bugs.SendHelloRetryRequestCipherSuite
+	}
 	helloRetryRequest := &helloRetryRequestMsg{
 		vers:                c.wireVersion,
+		cipherSuite:         cipherSuite,
 		duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions,
 	}
 
@@ -571,6 +576,12 @@
 	}
 
 	if sendHelloRetryRequest {
+		if isDraft21(c.wireVersion) {
+			if err := hs.finishedHash.UpdateForHelloRetryRequest(); err != nil {
+				return err
+			}
+		}
+
 		oldClientHelloBytes := hs.clientHello.marshal()
 		hs.writeServerHash(helloRetryRequest.marshal())
 		c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
@@ -592,6 +603,10 @@
 		}
 		hs.writeClientHash(newClientHello.marshal())
 
+		if config.Bugs.ExpectNoTLS13PSKAfterHRR && len(newClientHello.pskIdentities) > 0 {
+			return fmt.Errorf("tls: client offered unexpected PSK identities after HelloRetryRequest")
+		}
+
 		if newClientHello.hasEarlyData {
 			return errors.New("tls: EarlyData sent in new ClientHello")
 		}
@@ -626,11 +641,15 @@
 
 		// PSK binders and obfuscated ticket age are both updated in the
 		// second ClientHello.
-		if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
-			return errors.New("tls: PSK identity count from old and new ClientHello do not match")
-		}
-		for i, identity := range oldClientHelloCopy.pskIdentities {
-			newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
+		if isDraft21(c.wireVersion) && len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
+			newClientHelloCopy.pskIdentities = oldClientHelloCopy.pskIdentities
+		} else {
+			if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
+				return errors.New("tls: PSK identity count from old and new ClientHello do not match")
+			}
+			for i, identity := range oldClientHelloCopy.pskIdentities {
+				newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
+			}
 		}
 		newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders
 		newClientHelloCopy.hasEarlyData = oldClientHelloCopy.hasEarlyData
@@ -648,7 +667,7 @@
 		// AcceptAnyBinder is set. See https://crbug.com/115.
 		if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
 			binderToVerify := newClientHello.pskBinders[pskIndex]
-			if err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...)); err != nil {
+			if err := verifyPSKBinder(c.wireVersion, newClientHello, hs.sessionState, binderToVerify, oldClientHelloBytes, helloRetryRequest.marshal()); err != nil {
 				return err
 			}
 		}
@@ -662,7 +681,12 @@
 			}
 		}
 		if encryptedExtensions.extensions.hasEarlyData {
-			earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel)
+			earlyLabel := earlyTrafficLabel
+			if isDraft21(c.wireVersion) {
+				earlyLabel = earlyTrafficLabelDraft21
+			}
+
+			earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyLabel)
 			if err := c.useInTrafficSecret(c.wireVersion, hs.suite, earlyTrafficSecret); err != nil {
 				return err
 			}
@@ -716,6 +740,7 @@
 			c.sendAlert(alertHandshakeFailure)
 			return err
 		}
+		hs.finishedHash.nextSecret()
 		hs.finishedHash.addEntropy(ecdheSecret)
 		hs.hello.hasKeyShare = true
 
@@ -740,6 +765,7 @@
 			}
 		}
 	} else {
+		hs.finishedHash.nextSecret()
 		hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
 	}
 
@@ -760,11 +786,18 @@
 		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
 	}
 
+	clientLabel := clientHandshakeTrafficLabel
+	serverLabel := serverHandshakeTrafficLabel
+	if isDraft21(c.wireVersion) {
+		clientLabel = clientHandshakeTrafficLabelDraft21
+		serverLabel = serverHandshakeTrafficLabelDraft21
+	}
+
 	// Switch to handshake traffic keys.
-	serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel)
+	serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
 	c.useOutTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret)
 	// Derive handshake traffic read key, but don't switch yet.
-	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
+	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
 
 	// Send EncryptedExtensions.
 	hs.writeServerHash(encryptedExtensions.marshal())
@@ -779,9 +812,11 @@
 		if config.ClientAuth >= RequestClientCert {
 			// Request a client certificate
 			certReq := &certificateRequestMsg{
-				hasSignatureAlgorithm: true,
+				vers: c.wireVersion,
+				hasSignatureAlgorithm: !config.Bugs.OmitCertificateRequestAlgorithms,
 				hasRequestContext:     true,
 				requestContext:        config.Bugs.SendRequestContext,
+				customExtension:       config.Bugs.SendCustomCertificateRequest,
 			}
 			if !config.Bugs.NoSignatureAlgorithms {
 				certReq.signatureAlgorithms = config.verifySignatureAlgorithms()
@@ -896,10 +931,21 @@
 
 	// The various secrets do not incorporate the client's final leg, so
 	// derive them now before updating the handshake context.
+	hs.finishedHash.nextSecret()
 	hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
-	clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
-	serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel)
-	c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel)
+
+	clientLabel = clientApplicationTrafficLabel
+	serverLabel = serverApplicationTrafficLabel
+	exportLabel := exporterLabel
+	if isDraft21(c.wireVersion) {
+		clientLabel = clientApplicationTrafficLabelDraft21
+		serverLabel = serverApplicationTrafficLabelDraft21
+		exportLabel = exporterLabelDraft21
+	}
+
+	clientTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
+	serverTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
+	c.exporterSecret = hs.finishedHash.deriveSecret(exportLabel)
 
 	// Switch to application data keys on write. In particular, any alerts
 	// from the client certificate are sent over these keys.
@@ -912,13 +958,27 @@
 		}
 	}
 
-	// Read end_of_early_data alert.
+	// Read end_of_early_data.
 	if encryptedExtensions.extensions.hasEarlyData {
-		if err := c.readRecord(recordTypeAlert); err != errEndOfEarlyDataAlert {
-			if err == nil {
-				panic("readRecord(recordTypeAlert) returned nil")
+		if isDraft21(c.wireVersion) {
+			msg, err := c.readHandshake()
+			if err != nil {
+				return err
 			}
-			return err
+
+			endOfEarlyData, ok := msg.(*endOfEarlyDataMsg)
+			if !ok {
+				c.sendAlert(alertUnexpectedMessage)
+				return unexpectedMessageError(endOfEarlyData, msg)
+			}
+			hs.writeClientHash(endOfEarlyData.marshal())
+		} else {
+			if err := c.readRecord(recordTypeAlert); err != errEndOfEarlyDataAlert {
+				if err == nil {
+					panic("readRecord(recordTypeAlert) returned nil")
+				}
+				return err
+			}
 		}
 	}
 
@@ -1040,14 +1100,20 @@
 	}
 
 	c.cipherSuite = hs.suite
-	c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel)
+
+	resumeLabel := resumptionLabel
+	if isDraft21(c.wireVersion) {
+		resumeLabel = resumptionLabelDraft21
+	}
+
+	c.resumptionSecret = hs.finishedHash.deriveSecret(resumeLabel)
 
 	// TODO(davidben): Allow configuring the number of tickets sent for
 	// testing.
 	if !c.config.SessionTicketsDisabled && foundKEMode {
 		ticketCount := 2
 		for i := 0; i < ticketCount; i++ {
-			c.SendNewSessionTicket()
+			c.SendNewSessionTicket([]byte{byte(i)})
 		}
 	}
 	return nil
@@ -1408,7 +1474,7 @@
 		hs.hello.extensions.ocspStapling = true
 	}
 
-	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash = newFinishedHash(c.wireVersion, c.isDTLS, hs.suite)
 	hs.finishedHash.discardHandshakeBuffer()
 	hs.writeClientHash(hs.clientHello.marshal())
 	hs.writeServerHash(hs.hello.marshal())
@@ -1460,7 +1526,7 @@
 		}
 	}
 
-	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash = newFinishedHash(c.wireVersion, c.isDTLS, hs.suite)
 	hs.writeClientHash(hs.clientHello.marshal())
 	hs.writeServerHash(hs.hello.marshal())
 
@@ -1514,6 +1580,7 @@
 	if config.ClientAuth >= RequestClientCert {
 		// Request a client certificate
 		certReq := &certificateRequestMsg{
+			vers:             c.wireVersion,
 			certificateTypes: config.ClientCertificateTypes,
 		}
 		if certReq.certificateTypes == nil {
@@ -1787,6 +1854,8 @@
 	}
 
 	m := new(newSessionTicketMsg)
+	m.vers = c.wireVersion
+	m.isDTLS = c.isDTLS
 	if c.config.Bugs.SendTicketLifetime != 0 {
 		m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second)
 	}
@@ -2022,7 +2091,7 @@
 	return val&0x0f0f == 0x0a0a && val&0xff == val>>8
 }
 
-func verifyPSKBinder(clientHello *clientHelloMsg, sessionState *sessionState, binderToVerify, transcript []byte) error {
+func verifyPSKBinder(version uint16, clientHello *clientHelloMsg, sessionState *sessionState, binderToVerify, firstClientHello, helloRetryRequest []byte) error {
 	binderLen := 2
 	for _, binder := range clientHello.pskBinders {
 		binderLen += 1 + len(binder)
@@ -2035,7 +2104,11 @@
 		return errors.New("tls: Unknown cipher suite for PSK in session")
 	}
 
-	binder := computePSKBinder(sessionState.masterSecret, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+	binderLabel := resumptionPSKBinderLabel
+	if isDraft21(version) {
+		binderLabel = resumptionPSKBinderLabelDraft21
+	}
+	binder := computePSKBinder(sessionState.masterSecret, version, binderLabel, pskCipherSuite, firstClientHello, helloRetryRequest, truncatedHello)
 	if !bytes.Equal(binder, binderToVerify) {
 		return errors.New("tls: PSK binder does not verify")
 	}
diff --git a/ssl/test/runner/prf.go b/ssl/test/runner/prf.go
index cfc383d..6fa3c4c 100644
--- a/ssl/test/runner/prf.go
+++ b/ssl/test/runner/prf.go
@@ -180,9 +180,14 @@
 	return
 }
 
-func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+func newFinishedHash(wireVersion uint16, isDTLS bool, cipherSuite *cipherSuite) finishedHash {
 	var ret finishedHash
 
+	version, ok := wireToVersion(wireVersion, isDTLS)
+	if !ok {
+		panic("unknown version")
+	}
+
 	if version >= VersionTLS12 {
 		ret.hash = cipherSuite.hash()
 
@@ -207,6 +212,7 @@
 
 	ret.buffer = []byte{}
 	ret.version = version
+	ret.wireVersion = wireVersion
 	return ret
 }
 
@@ -226,13 +232,28 @@
 	// full buffer is required.
 	buffer []byte
 
-	version uint16
-	prf     func(result, secret, label, seed []byte)
+	version     uint16
+	wireVersion uint16
+	prf         func(result, secret, label, seed []byte)
 
 	// secret, in TLS 1.3, is the running input secret.
 	secret []byte
 }
 
+func (h *finishedHash) UpdateForHelloRetryRequest() (err error) {
+	data := newByteBuilder()
+	data.addU8(typeMessageHash)
+	data.addU24(h.hash.Size())
+	data.addBytes(h.Sum())
+	h.client = h.hash.New()
+	h.server = h.hash.New()
+	if h.buffer != nil {
+		h.buffer = []byte{}
+	}
+	h.Write(data.finish())
+	return nil
+}
+
 func (h *finishedHash) Write(msg []byte) (n int, err error) {
 	h.client.Write(msg)
 	h.server.Write(msg)
@@ -307,7 +328,7 @@
 		return out
 	}
 
-	clientFinishedKey := hkdfExpandLabel(h.hash, baseKey, finishedLabel, nil, h.hash.Size())
+	clientFinishedKey := hkdfExpandLabel(h.hash, h.wireVersion, baseKey, finishedLabel, nil, h.hash.Size())
 	finishedHMAC := hmac.New(h.hash.New, clientFinishedKey)
 	finishedHMAC.Write(h.appendContextHashes(nil))
 	return finishedHMAC.Sum(nil)
@@ -326,7 +347,7 @@
 		return out
 	}
 
-	serverFinishedKey := hkdfExpandLabel(h.hash, baseKey, finishedLabel, nil, h.hash.Size())
+	serverFinishedKey := hkdfExpandLabel(h.hash, h.wireVersion, baseKey, finishedLabel, nil, h.hash.Size())
 	finishedHMAC := hmac.New(h.hash.New, serverFinishedKey)
 	finishedHMAC.Write(h.appendContextHashes(nil))
 	return finishedHMAC.Sum(nil)
@@ -374,20 +395,33 @@
 	h.secret = hkdfExtract(h.hash.New, h.secret, ikm)
 }
 
+func (h *finishedHash) nextSecret() {
+	if isDraft21(h.wireVersion) {
+		derivedLabel := []byte("derived")
+		h.secret = hkdfExpandLabel(h.hash, h.wireVersion, h.secret, derivedLabel, h.hash.New().Sum(nil), h.hash.Size())
+	}
+}
+
 // hkdfExpandLabel implements TLS 1.3's HKDF-Expand-Label function, as defined
 // in section 7.1 of draft-ietf-tls-tls13-16.
-func hkdfExpandLabel(hash crypto.Hash, secret, label, hashValue []byte, length int) []byte {
+func hkdfExpandLabel(hash crypto.Hash, version uint16, secret, label, hashValue []byte, length int) []byte {
 	if len(label) > 255 || len(hashValue) > 255 {
 		panic("hkdfExpandLabel: label or hashValue too long")
 	}
-	hkdfLabel := make([]byte, 3+9+len(label)+1+len(hashValue))
+
+	versionLabel := []byte("TLS 1.3, ")
+	if isDraft21(version) {
+		versionLabel = []byte("tls13 ")
+	}
+
+	hkdfLabel := make([]byte, 3+len(versionLabel)+len(label)+1+len(hashValue))
 	x := hkdfLabel
 	x[0] = byte(length >> 8)
 	x[1] = byte(length)
-	x[2] = byte(9 + len(label))
+	x[2] = byte(len(versionLabel) + len(label))
 	x = x[3:]
-	copy(x, []byte("TLS 1.3, "))
-	x = x[9:]
+	copy(x, versionLabel)
+	x = x[len(versionLabel):]
 	copy(x, label)
 	x = x[len(label):]
 	x[0] = byte(len(hashValue))
@@ -414,12 +448,25 @@
 	applicationTrafficLabel       = []byte("application traffic secret")
 	exporterLabel                 = []byte("exporter master secret")
 	resumptionLabel               = []byte("resumption master secret")
+
+	externalPSKBinderLabelDraft21        = []byte("ext binder")
+	resumptionPSKBinderLabelDraft21      = []byte("res binder")
+	earlyTrafficLabelDraft21             = []byte("c e traffic")
+	clientHandshakeTrafficLabelDraft21   = []byte("c hs traffic")
+	serverHandshakeTrafficLabelDraft21   = []byte("s hs traffic")
+	clientApplicationTrafficLabelDraft21 = []byte("c ap traffic")
+	serverApplicationTrafficLabelDraft21 = []byte("s ap traffic")
+	applicationTrafficLabelDraft21       = []byte("traffic upd")
+	exporterLabelDraft21                 = []byte("exp master")
+	resumptionLabelDraft21               = []byte("res master")
+
+	resumptionPSKLabel = []byte("resumption")
 )
 
 // deriveSecret implements TLS 1.3's Derive-Secret function, as defined in
 // section 7.1 of draft ietf-tls-tls13-16.
 func (h *finishedHash) deriveSecret(label []byte) []byte {
-	return hkdfExpandLabel(h.hash, h.secret, label, h.appendContextHashes(nil), h.hash.Size())
+	return hkdfExpandLabel(h.hash, h.wireVersion, h.secret, label, h.appendContextHashes(nil), h.hash.Size())
 }
 
 // The following are context strings for CertificateVerify in TLS 1.3.
@@ -458,21 +505,34 @@
 // deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic
 // secret.
 func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) interface{} {
-	key := hkdfExpandLabel(suite.hash(), secret, keyTLS13, nil, suite.keyLen)
-	iv := hkdfExpandLabel(suite.hash(), secret, ivTLS13, nil, suite.ivLen(version))
+	key := hkdfExpandLabel(suite.hash(), version, secret, keyTLS13, nil, suite.keyLen)
+	iv := hkdfExpandLabel(suite.hash(), version, secret, ivTLS13, nil, suite.ivLen(version))
 
 	return suite.aead(version, key, iv)
 }
 
-func updateTrafficSecret(hash crypto.Hash, secret []byte) []byte {
-	return hkdfExpandLabel(hash, secret, applicationTrafficLabel, nil, hash.Size())
+func updateTrafficSecret(hash crypto.Hash, version uint16, secret []byte) []byte {
+	trafficLabel := applicationTrafficLabel
+	if isDraft21(version) {
+		trafficLabel = applicationTrafficLabelDraft21
+	}
+	return hkdfExpandLabel(hash, version, secret, trafficLabel, nil, hash.Size())
 }
 
-func computePSKBinder(psk, label []byte, cipherSuite *cipherSuite, transcript, truncatedHello []byte) []byte {
-	finishedHash := newFinishedHash(VersionTLS13, cipherSuite)
+func computePSKBinder(psk []byte, version uint16, label []byte, cipherSuite *cipherSuite, clientHello, helloRetryRequest, truncatedHello []byte) []byte {
+	finishedHash := newFinishedHash(version, false, cipherSuite)
 	finishedHash.addEntropy(psk)
 	binderKey := finishedHash.deriveSecret(label)
-	finishedHash.Write(transcript)
+	finishedHash.Write(clientHello)
+	if isDraft21(version) && len(helloRetryRequest) != 0 {
+		finishedHash.UpdateForHelloRetryRequest()
+	}
+	finishedHash.Write(helloRetryRequest)
 	finishedHash.Write(truncatedHello)
 	return finishedHash.clientSum(binderKey)
 }
+
+func deriveSessionPSK(suite *cipherSuite, version uint16, masterSecret []byte, nonce []byte) []byte {
+	hash := suite.hash()
+	return hkdfExpandLabel(hash, version, masterSecret, resumptionPSKLabel, nonce, hash.Size())
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 0ce50bc..ce50fa8 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -1305,6 +1305,13 @@
 		tls13Variant: TLS13Default,
 	},
 	{
+		name:         "TLS13Draft21",
+		version:      VersionTLS13,
+		excludeFlag:  "-no-tls13",
+		versionWire:  tls13Draft21Version,
+		tls13Variant: TLS13Draft21,
+	},
+	{
 		name:         "TLS13Experiment",
 		version:      VersionTLS13,
 		excludeFlag:  "-no-tls13",
@@ -3130,7 +3137,7 @@
 			},
 		},
 		shouldFail:    true,
-		expectedError: ":UNKNOWN_CIPHER_RETURNED:",
+		expectedError: ":WRONG_CIPHER_RETURNED:",
 	})
 
 	// The server must be tolerant to bogus ciphers.
@@ -3783,6 +3790,25 @@
 			"-use-client-ca-list", "<NULL>",
 		},
 	})
+
+	// Test that an empty client CA list doesn't send a CA extension.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13Draft21-Empty-Client-CA-List",
+		config: Config{
+			MaxVersion:   VersionTLS13,
+			Certificates: []Certificate{rsaCertificate},
+			Bugs: ProtocolBugs{
+				ExpectNoCertificateAuthoritiesExtension: true,
+			},
+		},
+		tls13Variant: TLS13Draft21,
+		flags: []string{
+			"-require-any-client-certificate",
+			"-use-client-ca-list", "<EMPTY>",
+		},
+	})
+
 }
 
 func addExtendedMasterSecretTests() {
@@ -4153,7 +4179,7 @@
 			resumeSession:    true,
 			flags: []string{
 				"-enable-early-data",
-				"-expect-early-data-info",
+				"-expect-ticket-supports-early-data",
 				"-expect-accept-early-data",
 				"-on-resume-shim-writes-first",
 			},
@@ -4182,7 +4208,7 @@
 				resumeSession: true,
 				flags: []string{
 					"-enable-early-data",
-					"-expect-early-data-info",
+					"-expect-ticket-supports-early-data",
 					"-expect-accept-early-data",
 					"-on-resume-read-with-unfinished-write",
 					"-on-resume-shim-writes-first",
@@ -4211,7 +4237,7 @@
 				resumeSession: true,
 				flags: []string{
 					"-enable-early-data",
-					"-expect-early-data-info",
+					"-expect-ticket-supports-early-data",
 					"-expect-reject-early-data",
 					"-on-resume-read-with-unfinished-write",
 					"-on-resume-shim-writes-first",
@@ -5145,14 +5171,13 @@
 				}
 				// When running and shim have different TLS 1.3 variants enabled,
 				// shim clients are expected to fall back to TLS 1.2, while shim
-				// servers support both variants when enabled when the experiment is
-				// enabled.
+				// servers support multiple variants.
 				expectedServerVersion := expectedVersion
 				expectedClientVersion := expectedVersion
 				if expectedVersion == VersionTLS13 && runnerVers.tls13Variant != shimVers.tls13Variant {
 					expectedClientVersion = VersionTLS12
 					expectedServerVersion = VersionTLS12
-					if shimVers.tls13Variant != TLS13Default {
+					if shimVers.tls13Variant != TLS13Default && runnerVers.tls13Variant != TLS13Draft21 {
 						expectedServerVersion = VersionTLS13
 					}
 				}
@@ -9181,7 +9206,7 @@
 		flags: []string{
 			"-enable-client-custom-extension",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 		},
 	})
@@ -9200,7 +9225,7 @@
 		flags: []string{
 			"-enable-client-custom-extension",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-accept-early-data",
 		},
 	})
@@ -9221,7 +9246,7 @@
 		flags: []string{
 			"-enable-client-custom-extension",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 		},
 	})
@@ -9252,7 +9277,7 @@
 		flags: []string{
 			"-enable-client-custom-extension",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 		},
 	})
 
@@ -9274,7 +9299,7 @@
 		flags: []string{
 			"-enable-server-custom-extension",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 		},
 	})
 
@@ -10036,7 +10061,7 @@
 		},
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 		},
 	})
 
@@ -10057,7 +10082,7 @@
 			MaxVersion:       VersionTLS13,
 			MaxEarlyDataSize: 16384,
 			Bugs: ProtocolBugs{
-				DuplicateTicketEarlyDataInfo: true,
+				DuplicateTicketEarlyData: true,
 			},
 		},
 		shouldFail:         true,
@@ -10071,7 +10096,7 @@
 		config: Config{
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
-				ExpectTicketEarlyDataInfo: true,
+				ExpectTicketEarlyData: true,
 			},
 		},
 		flags: []string{
@@ -10956,7 +10981,7 @@
 			resumeSession: true,
 			flags: []string{
 				"-enable-early-data",
-				"-expect-early-data-info",
+				"-expect-ticket-supports-early-data",
 				"-expect-accept-early-data",
 				"-on-resume-shim-writes-first",
 			},
@@ -10980,7 +11005,7 @@
 			resumeSession: true,
 			flags: []string{
 				"-enable-early-data",
-				"-expect-early-data-info",
+				"-expect-ticket-supports-early-data",
 				"-expect-reject-early-data",
 				"-on-resume-shim-writes-first",
 			},
@@ -11221,6 +11246,49 @@
 	})
 
 	testCases = append(testCases, testCase{
+		name: "TLS13Draft21-HelloRetryRequest-CipherChange",
+		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:  TLS13Draft21,
+		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:     "TLS13Draft21-HelloRetryRequest-NonResumableCipher",
+		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,
+			},
+			CipherSuites: []uint16{
+				TLS_AES_256_GCM_SHA384,
+			},
+		},
+		tls13Variant:         TLS13Draft21,
+		resumeSession:        true,
+		expectResumeRejected: true,
+	})
+
+	testCases = append(testCases, testCase{
 		name: "DisabledCurve-HelloRetryRequest",
 		config: Config{
 			MaxVersion:       VersionTLS13,
@@ -11446,6 +11514,42 @@
 	})
 
 	testCases = append(testCases, testCase{
+		name: "TLS13-UnknownInCertificateRequest",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			MinVersion: VersionTLS13,
+			ClientAuth: RequireAnyClientCert,
+			Bugs: ProtocolBugs{
+				SendCustomCertificateRequest: 0x1212,
+			},
+		},
+		tls13Variant: TLS13Draft21,
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaKeyFile),
+		},
+	})
+
+	testCases = append(testCases, testCase{
+		name: "TLS13-MissingSignatureAlgorithmsInCertificateRequest",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			MinVersion: VersionTLS13,
+			ClientAuth: RequireAnyClientCert,
+			Bugs: ProtocolBugs{
+				OmitCertificateRequestAlgorithms: true,
+			},
+		},
+		tls13Variant: TLS13Draft21,
+		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:     "TLS13-TrailingKeyShareData",
 		config: Config{
@@ -11524,7 +11628,7 @@
 		expectResumeRejected: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 			"-on-resume-shim-writes-first",
 			"-on-initial-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile),
@@ -11552,7 +11656,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 		},
 	})
@@ -11576,7 +11680,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 		},
 		shouldFail:    true,
 		expectedError: ":UNEXPECTED_EXTENSION:",
@@ -11597,7 +11701,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 		},
 		shouldFail:    true,
 		expectedError: ":WRONG_VERSION_ON_EARLY_DATA:",
@@ -11623,7 +11727,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 		},
 		shouldFail:    true,
@@ -11656,7 +11760,7 @@
 		flags: []string{
 			"-advertise-alpn", "\x03foo\x03bar",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 			"-on-initial-expect-alpn", "foo",
 			"-on-resume-expect-alpn", "foo",
@@ -11682,7 +11786,7 @@
 		flags: []string{
 			"-advertise-alpn", "\x03foo\x03bar",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 			"-on-initial-expect-alpn", "",
 			"-on-resume-expect-alpn", "",
@@ -11709,7 +11813,7 @@
 		flags: []string{
 			"-advertise-alpn", "\x03foo\x03bar",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-reject-early-data",
 			"-on-initial-expect-alpn", "foo",
 			"-on-resume-expect-alpn", "foo",
@@ -11741,7 +11845,7 @@
 		flags: []string{
 			"-advertise-alpn", "\x03foo\x03bar",
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-on-initial-expect-alpn", "foo",
 			"-on-resume-expect-alpn", "foo",
 			"-on-retry-expect-alpn", "bar",
@@ -11763,7 +11867,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-no-offer-early-data",
 			"-on-initial-advertise-alpn", "\x03foo",
 			"-on-resume-advertise-alpn", "\x03bar",
@@ -11884,7 +11988,7 @@
 		expectedError:   ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:",
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
 		},
 	})
@@ -11906,7 +12010,7 @@
 		expectChannelID: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
 			"-expect-reject-early-data",
 		},
@@ -11924,7 +12028,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
 			"-expect-accept-early-data",
 		},
@@ -12030,7 +12134,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-accept-early-data",
 			"-expect-version", strconv.Itoa(VersionTLS13),
 		},
@@ -12055,7 +12159,7 @@
 		resumeSession: true,
 		flags: []string{
 			"-enable-early-data",
-			"-expect-early-data-info",
+			"-expect-ticket-supports-early-data",
 			"-expect-accept-early-data",
 		},
 		shouldFail:         true,
@@ -12088,6 +12192,34 @@
 		expectedError:      ":DIGEST_CHECK_FAILED:",
 		expectedLocalError: "remote error: error decrypting message",
 	})
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13Draft21-Server-NonEmptyEndOfEarlyData",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+		},
+		resumeConfig: &Config{
+			MaxVersion:       VersionTLS13,
+			MaxEarlyDataSize: 16384,
+			Bugs: ProtocolBugs{
+				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
+				ExpectEarlyDataAccepted: true,
+				NonEmptyEndOfEarlyData:  true,
+			},
+		},
+		resumeSession: true,
+		flags: []string{
+			"-enable-early-data",
+			"-expect-ticket-supports-early-data",
+			"-expect-accept-early-data",
+		},
+		tls13Variant:  TLS13Draft21,
+		shouldFail:    true,
+		expectedError: ":DECODE_ERROR:",
+	})
+
 	testCases = append(testCases, testCase{
 		testType: serverTest,
 		name:     "TLS13-ServerSkipCertificateVerify",
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 3354851..2d9f725 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -81,7 +81,8 @@
   { "-tls-unique", &TestConfig::tls_unique },
   { "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal },
   { "-expect-no-session", &TestConfig::expect_no_session },
-  { "-expect-early-data-info", &TestConfig::expect_early_data_info },
+  { "-expect-ticket-supports-early-data",
+    &TestConfig::expect_ticket_supports_early_data },
   { "-use-ticket-callback", &TestConfig::use_ticket_callback },
   { "-renew-ticket", &TestConfig::renew_ticket },
   { "-enable-early-data", &TestConfig::enable_early_data },
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index b96d9e5..b742f94 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -87,7 +87,7 @@
   bool tls_unique = false;
   bool expect_ticket_renewal = false;
   bool expect_no_session = false;
-  bool expect_early_data_info = false;
+  bool expect_ticket_supports_early_data = false;
   bool expect_accept_early_data = false;
   bool expect_reject_early_data = false;
   bool expect_no_offer_early_data = false;
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index b6307ee..9c09309 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -63,8 +63,10 @@
   }
 
   CBS body = msg.body, extensions;
-  uint16_t server_version;
+  uint16_t server_version, cipher_suite = 0;
   if (!CBS_get_u16(&body, &server_version) ||
+      (ssl_is_draft21(ssl->version) &&
+       !CBS_get_u16(&body, &cipher_suite)) ||
       !CBS_get_u16_length_prefixed(&body, &extensions) ||
       // HelloRetryRequest may not be empty.
       CBS_len(&extensions) == 0 ||
@@ -74,6 +76,26 @@
     return ssl_hs_error;
   }
 
+  if (ssl_is_draft21(ssl->version)) {
+    const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
+    // Check if the cipher is a TLS 1.3 cipher.
+    if (cipher == NULL ||
+        SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
+        SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
+      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+      return ssl_hs_error;
+    }
+
+    hs->new_cipher = cipher;
+
+    if (!hs->transcript.InitHash(ssl_protocol_version(ssl), hs->new_cipher) ||
+        !hs->transcript.UpdateForHelloRetryRequest()) {
+      return ssl_hs_error;
+    }
+  }
+
+
   bool have_cookie, have_key_share;
   CBS cookie, key_share;
   const SSL_EXTENSION_TYPE ext_types[] = {
@@ -206,16 +228,20 @@
   OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
                  SSL3_RANDOM_SIZE);
 
+  // Check if the cipher is a TLS 1.3 cipher.
   const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
-  if (cipher == NULL) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
+  if (cipher == nullptr ||
+      SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
+      SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
   }
 
-  // Check if the cipher is a TLS 1.3 cipher.
-  if (SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
-      SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl)) {
+  // Check that the cipher matches the one in the HelloRetryRequest.
+  if (ssl_is_draft21(ssl->version) &&
+      hs->received_hello_retry_request &&
+      hs->new_cipher != cipher) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
@@ -302,18 +328,16 @@
   hs->new_session->cipher = cipher;
   hs->new_cipher = cipher;
 
-  // The PRF hash is now known. Set up the key schedule.
-  if (!tls13_init_key_schedule(hs)) {
-    return ssl_hs_error;
-  }
+  size_t hash_len =
+      EVP_MD_size(ssl_get_handshake_digest(ssl_protocol_version(ssl), cipher));
 
-  // Incorporate the PSK into the running secret.
+  // Set up the key schedule and incorporate the PSK into the running secret.
   if (ssl->s3->session_reused) {
-    if (!tls13_advance_key_schedule(hs, hs->new_session->master_key,
-                                    hs->new_session->master_key_length)) {
+    if (!tls13_init_key_schedule(hs, hs->new_session->master_key,
+                                 hs->new_session->master_key_length)) {
       return ssl_hs_error;
     }
-  } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
+  } else if (!tls13_init_key_schedule(hs, kZeroes, hash_len)) {
     return ssl_hs_error;
   }
 
@@ -445,37 +469,81 @@
     return ssl_hs_ok;
   }
 
-  CBS body = msg.body, context, supported_signature_algorithms;
-  if (!CBS_get_u8_length_prefixed(&body, &context) ||
-      // The request context is always empty during the handshake.
-      CBS_len(&context) != 0 ||
-      !CBS_get_u16_length_prefixed(&body, &supported_signature_algorithms) ||
-      CBS_len(&supported_signature_algorithms) == 0 ||
-      !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
-    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    return ssl_hs_error;
-  }
 
-  uint8_t alert = SSL_AD_DECODE_ERROR;
-  UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names =
-      ssl_parse_client_CA_list(ssl, &alert, &body);
-  if (!ca_names) {
-    ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
-    return ssl_hs_error;
-  }
+  if (ssl_is_draft21(ssl->version)) {
+    bool have_sigalgs = false, have_ca = false;
+    CBS sigalgs, ca;
+    const SSL_EXTENSION_TYPE ext_types[] = {
+      {TLSEXT_TYPE_signature_algorithms, &have_sigalgs, &sigalgs},
+      {TLSEXT_TYPE_certificate_authorities, &have_ca, &ca},
+    };
 
-  // Ignore extensions.
-  CBS extensions;
-  if (!CBS_get_u16_length_prefixed(&body, &extensions) ||
-      CBS_len(&body) != 0) {
-    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    return ssl_hs_error;
+    CBS body = msg.body, context, extensions, supported_signature_algorithms;
+    uint8_t alert = SSL_AD_DECODE_ERROR;
+    if (!CBS_get_u8_length_prefixed(&body, &context) ||
+        // The request context is always empty during the handshake.
+        CBS_len(&context) != 0 ||
+        !CBS_get_u16_length_prefixed(&body, &extensions) ||
+        CBS_len(&body) != 0 ||
+        !ssl_parse_extensions(&extensions, &alert, ext_types,
+                              OPENSSL_ARRAY_SIZE(ext_types),
+                              1 /* accept unknown */) ||
+        (have_ca && CBS_len(&ca) == 0) ||
+        !have_sigalgs ||
+        !CBS_get_u16_length_prefixed(&sigalgs,
+                                     &supported_signature_algorithms) ||
+        CBS_len(&supported_signature_algorithms) == 0 ||
+        !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
+      ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      return ssl_hs_error;
+    }
+
+    if (have_ca) {
+      hs->ca_names = ssl_parse_client_CA_list(ssl, &alert, &ca);
+      if (!hs->ca_names) {
+        ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+        return ssl_hs_error;
+      }
+    } else {
+      hs->ca_names.reset(sk_CRYPTO_BUFFER_new_null());
+      if (!hs->ca_names) {
+        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+        ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        return ssl_hs_error;
+      }
+    }
+  } else {
+    CBS body = msg.body, context, supported_signature_algorithms;
+    if (!CBS_get_u8_length_prefixed(&body, &context) ||
+        // The request context is always empty during the handshake.
+        CBS_len(&context) != 0 ||
+        !CBS_get_u16_length_prefixed(&body, &supported_signature_algorithms) ||
+        CBS_len(&supported_signature_algorithms) == 0 ||
+        !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
+      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      return ssl_hs_error;
+    }
+
+    uint8_t alert = SSL_AD_DECODE_ERROR;
+    hs->ca_names = ssl_parse_client_CA_list(ssl, &alert, &body);
+    if (!hs->ca_names) {
+      ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+      return ssl_hs_error;
+    }
+
+    // Ignore extensions.
+    CBS extensions;
+    if (!CBS_get_u16_length_prefixed(&body, &extensions) ||
+        CBS_len(&body) != 0) {
+      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      return ssl_hs_error;
+    }
   }
 
   hs->cert_request = true;
-  hs->ca_names = std::move(ca_names);
   ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
 
   if (!ssl_hash_message(hs, msg)) {
@@ -557,9 +625,19 @@
 
   if (ssl->early_data_accepted) {
     hs->can_early_write = false;
-    if (!ssl->method->add_alert(ssl, SSL3_AL_WARNING,
-                                TLS1_AD_END_OF_EARLY_DATA)) {
-      return ssl_hs_error;
+    if (ssl_is_draft21(ssl->version)) {
+      ScopedCBB cbb;
+      CBB body;
+      if (!ssl->method->init_message(ssl, cbb.get(), &body,
+                                     SSL3_MT_END_OF_EARLY_DATA) ||
+          !ssl_add_message_cbb(ssl, cbb.get())) {
+        return ssl_hs_error;
+      }
+    } else {
+      if (!ssl->method->add_alert(ssl, SSL3_AL_WARNING,
+                                  TLS1_AD_END_OF_EARLY_DATA)) {
+        return ssl_hs_error;
+      }
     }
   }
 
@@ -790,9 +868,11 @@
   ssl_session_rebase_time(ssl, session.get());
 
   uint32_t server_timeout;
-  CBS body = msg.body, ticket, extensions;
+  CBS body = msg.body, ticket_nonce, ticket, extensions;
   if (!CBS_get_u32(&body, &server_timeout) ||
       !CBS_get_u32(&body, &session->ticket_age_add) ||
+      (ssl_is_draft21(ssl->version) &&
+       !CBS_get_u8_length_prefixed(&body, &ticket_nonce)) ||
       !CBS_get_u16_length_prefixed(&body, &ticket) ||
       !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
       !CBS_get_u16_length_prefixed(&body, &extensions) ||
@@ -808,12 +888,18 @@
     session->timeout = server_timeout;
   }
 
+  if (!tls13_derive_session_psk(session.get(), ticket_nonce)) {
+    return 0;
+  }
+
   // Parse out the extensions.
   bool have_early_data_info = false;
   CBS early_data_info;
+  uint16_t ext_id = ssl_is_draft21(ssl->version)
+                        ? TLSEXT_TYPE_early_data
+                        : TLSEXT_TYPE_ticket_early_data_info;
   const SSL_EXTENSION_TYPE ext_types[] = {
-      {TLSEXT_TYPE_ticket_early_data_info, &have_early_data_info,
-       &early_data_info},
+      {ext_id, &have_early_data_info, &early_data_info},
   };
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc
index 6c7e1da..14f4a78 100644
--- a/ssl/tls13_enc.cc
+++ b/ssl/tls13_enc.cc
@@ -46,32 +46,33 @@
   return 1;
 }
 
-int tls13_init_key_schedule(SSL_HANDSHAKE *hs) {
+int tls13_init_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *psk,
+                            size_t psk_len) {
   if (!init_key_schedule(hs, ssl_protocol_version(hs->ssl), hs->new_cipher)) {
     return 0;
   }
 
   hs->transcript.FreeBuffer();
-  return 1;
+  return HKDF_extract(hs->secret, &hs->hash_len, hs->transcript.Digest(), psk,
+                      psk_len, hs->secret, hs->hash_len);
 }
 
-int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs) {
+int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *psk,
+                                  size_t psk_len) {
   SSL *const ssl = hs->ssl;
   return init_key_schedule(hs, ssl_session_protocol_version(ssl->session),
-                           ssl->session->cipher);
+                           ssl->session->cipher) &&
+         HKDF_extract(hs->secret, &hs->hash_len, hs->transcript.Digest(), psk,
+                      psk_len, hs->secret, hs->hash_len);
 }
 
-int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
-                               size_t len) {
-  return HKDF_extract(hs->secret, &hs->hash_len, hs->transcript.Digest(), in,
-                      len, hs->secret, hs->hash_len);
-}
-
-static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest,
-                             const uint8_t *secret, size_t secret_len,
-                             const uint8_t *label, size_t label_len,
-                             const uint8_t *hash, size_t hash_len, size_t len) {
-  static const char kTLS13LabelVersion[] = "TLS 1.3, ";
+static int hkdf_expand_label(uint8_t *out, uint16_t version,
+                             const EVP_MD *digest, const uint8_t *secret,
+                             size_t secret_len, const uint8_t *label,
+                             size_t label_len, const uint8_t *hash,
+                             size_t hash_len, size_t len) {
+  const char *kTLS13LabelVersion =
+      ssl_is_draft21(version) ? "tls13 " : "TLS 1.3, ";
 
   ScopedCBB cbb;
   CBB child;
@@ -96,6 +97,34 @@
   return ret;
 }
 
+static const char kTLS13LabelDerived[] = "derived";
+
+int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
+                               size_t len) {
+  SSL *const ssl = hs->ssl;
+
+  // Draft 18 does not include the extra Derive-Secret step.
+  if (ssl_is_draft21(ssl->version)) {
+    uint8_t derive_context[EVP_MAX_MD_SIZE];
+    unsigned derive_context_len;
+    if (!EVP_Digest(nullptr, 0, derive_context, &derive_context_len,
+                    hs->transcript.Digest(), nullptr)) {
+      return 0;
+    }
+
+    if (!hkdf_expand_label(hs->secret, ssl->version, hs->transcript.Digest(),
+                           hs->secret, hs->hash_len,
+                           (const uint8_t *)kTLS13LabelDerived,
+                           strlen(kTLS13LabelDerived), derive_context,
+                           derive_context_len, hs->hash_len)) {
+      return 0;
+    }
+  }
+
+  return HKDF_extract(hs->secret, &hs->hash_len, hs->transcript.Digest(), in,
+                      len, hs->secret, hs->hash_len);
+}
+
 // derive_secret derives a secret of length |len| and writes the result in |out|
 // with the given label and the current base secret and most recently-saved
 // handshake context. It returns one on success and zero on error.
@@ -107,9 +136,10 @@
     return 0;
   }
 
-  return hkdf_expand_label(out, hs->transcript.Digest(), hs->secret,
-                           hs->hash_len, label, label_len, context_hash,
-                           context_hash_len, len);
+  return hkdf_expand_label(out, SSL_get_session(hs->ssl)->ssl_version,
+                           hs->transcript.Digest(), hs->secret, hs->hash_len,
+                           label, label_len, context_hash, context_hash_len,
+                           len);
 }
 
 int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
@@ -136,16 +166,18 @@
   // Derive the key.
   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,
-                         (const uint8_t *)"key", 3, NULL, 0, key_len)) {
+  if (!hkdf_expand_label(key, session->ssl_version, digest, traffic_secret,
+                         traffic_secret_len, (const uint8_t *)"key", 3, NULL, 0,
+                         key_len)) {
     return 0;
   }
 
   // Derive the IV.
   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,
-                         (const uint8_t *)"iv", 2, NULL, 0, iv_len)) {
+  if (!hkdf_expand_label(iv, session->ssl_version, digest, traffic_secret,
+                         traffic_secret_len, (const uint8_t *)"iv", 2, NULL, 0,
+                         iv_len)) {
     return 0;
   }
 
@@ -195,28 +227,49 @@
 static const char kTLS13LabelServerApplicationTraffic[] =
     "server application traffic secret";
 
+static const char kTLS13Draft21LabelExporter[] = "exp master";
+static const char kTLS13Draft21LabelEarlyExporter[] = "e exp master";
+
+static const char kTLS13Draft21LabelClientEarlyTraffic[] = "c e traffic";
+static const char kTLS13Draft21LabelClientHandshakeTraffic[] = "c hs traffic";
+static const char kTLS13Draft21LabelServerHandshakeTraffic[] = "s hs traffic";
+static const char kTLS13Draft21LabelClientApplicationTraffic[] = "c ap traffic";
+static const char kTLS13Draft21LabelServerApplicationTraffic[] = "s ap traffic";
+
 int tls13_derive_early_secrets(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
+  uint16_t version = SSL_get_session(ssl)->ssl_version;
+
+  const char *early_traffic_label = ssl_is_draft21(version)
+                                        ? kTLS13Draft21LabelClientEarlyTraffic
+                                        : kTLS13LabelClientEarlyTraffic;
+  const char *early_exporter_label = ssl_is_draft21(version)
+                                         ? kTLS13Draft21LabelEarlyExporter
+                                         : kTLS13LabelEarlyExporter;
   return derive_secret(hs, hs->early_traffic_secret, hs->hash_len,
-                       (const uint8_t *)kTLS13LabelClientEarlyTraffic,
-                       strlen(kTLS13LabelClientEarlyTraffic)) &&
+                       (const uint8_t *)early_traffic_label,
+                       strlen(early_traffic_label)) &&
          ssl_log_secret(ssl, "CLIENT_EARLY_TRAFFIC_SECRET",
                         hs->early_traffic_secret, hs->hash_len) &&
          derive_secret(hs, ssl->s3->early_exporter_secret, hs->hash_len,
-                       (const uint8_t *)kTLS13LabelEarlyExporter,
-                       strlen(kTLS13LabelEarlyExporter));
+                       (const uint8_t *)early_exporter_label,
+                       strlen(early_exporter_label));
 }
 
 int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
+  const char *client_label = ssl_is_draft21(ssl->version)
+                                 ? kTLS13Draft21LabelClientHandshakeTraffic
+                                 : kTLS13LabelClientHandshakeTraffic;
+  const char *server_label = ssl_is_draft21(ssl->version)
+                                 ? kTLS13Draft21LabelServerHandshakeTraffic
+                                 : kTLS13LabelServerHandshakeTraffic;
   return derive_secret(hs, hs->client_handshake_secret, hs->hash_len,
-                       (const uint8_t *)kTLS13LabelClientHandshakeTraffic,
-                       strlen(kTLS13LabelClientHandshakeTraffic)) &&
+                       (const uint8_t *)client_label, strlen(client_label)) &&
          ssl_log_secret(ssl, "CLIENT_HANDSHAKE_TRAFFIC_SECRET",
                         hs->client_handshake_secret, hs->hash_len) &&
          derive_secret(hs, hs->server_handshake_secret, hs->hash_len,
-                       (const uint8_t *)kTLS13LabelServerHandshakeTraffic,
-                       strlen(kTLS13LabelServerHandshakeTraffic)) &&
+                       (const uint8_t *)server_label, strlen(server_label)) &&
          ssl_log_secret(ssl, "SERVER_HANDSHAKE_TRAFFIC_SECRET",
                         hs->server_handshake_secret, hs->hash_len);
 }
@@ -224,25 +277,33 @@
 int tls13_derive_application_secrets(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   ssl->s3->exporter_secret_len = hs->hash_len;
+  const char *client_label = ssl_is_draft21(ssl->version)
+                                 ? kTLS13Draft21LabelClientApplicationTraffic
+                                 : kTLS13LabelClientApplicationTraffic;
+  const char *server_label = ssl_is_draft21(ssl->version)
+                                 ? kTLS13Draft21LabelServerApplicationTraffic
+                                 : kTLS13LabelServerApplicationTraffic;
+  const char *exporter_label = ssl_is_draft21(ssl->version)
+                                   ? kTLS13Draft21LabelExporter
+                                   : kTLS13LabelExporter;
   return derive_secret(hs, hs->client_traffic_secret_0, hs->hash_len,
-                       (const uint8_t *)kTLS13LabelClientApplicationTraffic,
-                       strlen(kTLS13LabelClientApplicationTraffic)) &&
+                       (const uint8_t *)client_label, strlen(client_label)) &&
          ssl_log_secret(ssl, "CLIENT_TRAFFIC_SECRET_0",
                         hs->client_traffic_secret_0, hs->hash_len) &&
          derive_secret(hs, hs->server_traffic_secret_0, hs->hash_len,
-                       (const uint8_t *)kTLS13LabelServerApplicationTraffic,
-                       strlen(kTLS13LabelServerApplicationTraffic)) &&
+                       (const uint8_t *)server_label, strlen(server_label)) &&
          ssl_log_secret(ssl, "SERVER_TRAFFIC_SECRET_0",
                         hs->server_traffic_secret_0, hs->hash_len) &&
          derive_secret(hs, ssl->s3->exporter_secret, hs->hash_len,
-                       (const uint8_t *)kTLS13LabelExporter,
-                       strlen(kTLS13LabelExporter)) &&
+                       (const uint8_t *)exporter_label,
+                       strlen(exporter_label)) &&
          ssl_log_secret(ssl, "EXPORTER_SECRET", ssl->s3->exporter_secret,
                         hs->hash_len);
 }
 
 static const char kTLS13LabelApplicationTraffic[] =
     "application traffic secret";
+static const char kTLS13Draft21LabelApplicationTraffic[] = "traffic upd";
 
 int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) {
   uint8_t *secret;
@@ -255,11 +316,14 @@
     secret_len = ssl->s3->write_traffic_secret_len;
   }
 
+  const char *traffic_label = ssl_is_draft21(ssl->version)
+                                  ? kTLS13Draft21LabelApplicationTraffic
+                                  : kTLS13LabelApplicationTraffic;
+
   const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl));
-  if (!hkdf_expand_label(secret, digest, secret, secret_len,
-                         (const uint8_t *)kTLS13LabelApplicationTraffic,
-                         strlen(kTLS13LabelApplicationTraffic), NULL, 0,
-                         secret_len)) {
+  if (!hkdf_expand_label(secret, ssl->version, digest, secret, secret_len,
+                         (const uint8_t *)traffic_label, strlen(traffic_label),
+                         NULL, 0, secret_len)) {
     return 0;
   }
 
@@ -267,30 +331,33 @@
 }
 
 static const char kTLS13LabelResumption[] = "resumption master secret";
+static const char kTLS13Draft21LabelResumption[] = "res master";
 
 int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs) {
   if (hs->hash_len > SSL_MAX_MASTER_KEY_LENGTH) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
-
+  const char *resumption_label = ssl_is_draft21(hs->ssl->version)
+                                     ? kTLS13Draft21LabelResumption
+                                     : kTLS13LabelResumption;
   hs->new_session->master_key_length = hs->hash_len;
   return derive_secret(
       hs, hs->new_session->master_key, hs->new_session->master_key_length,
-      (const uint8_t *)kTLS13LabelResumption, strlen(kTLS13LabelResumption));
+      (const uint8_t *)resumption_label, strlen(resumption_label));
 }
 
 static const char kTLS13LabelFinished[] = "finished";
 
 // tls13_verify_data sets |out| to be the HMAC of |context| using a derived
 // Finished key for both Finished messages and the PSK binder.
-static int tls13_verify_data(const EVP_MD *digest, uint8_t *out,
-                             size_t *out_len, const uint8_t *secret,
-                             size_t hash_len, uint8_t *context,
-                             size_t context_len) {
+static int 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) {
   uint8_t key[EVP_MAX_MD_SIZE];
   unsigned len;
-  if (!hkdf_expand_label(key, digest, secret, hash_len,
+  if (!hkdf_expand_label(key, version, digest, secret, hash_len,
                          (const uint8_t *)kTLS13LabelFinished,
                          strlen(kTLS13LabelFinished), NULL, 0, hash_len) ||
       HMAC(digest, key, hash_len, context, context_len, out, &len) == NULL) {
@@ -312,35 +379,79 @@
   uint8_t context_hash[EVP_MAX_MD_SIZE];
   size_t context_hash_len;
   if (!hs->transcript.GetHash(context_hash, &context_hash_len) ||
-      !tls13_verify_data(hs->transcript.Digest(), out, out_len, traffic_secret,
-                         hs->hash_len, 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)) {
     return 0;
   }
   return 1;
 }
 
+static const char kTLS13LabelResumptionPSK[] = "resumption";
+
+bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce) {
+  if (!ssl_is_draft21(session->ssl_version)) {
+    return true;
+  }
+
+  const EVP_MD *digest = ssl_session_get_digest(session);
+  return hkdf_expand_label(session->master_key, session->ssl_version, digest,
+                           session->master_key, session->master_key_length,
+                           (const uint8_t *)kTLS13LabelResumptionPSK,
+                           strlen(kTLS13LabelResumptionPSK), nonce.data(),
+                           nonce.size(), session->master_key_length);
+}
+
+static const char kTLS13LabelExportKeying[] = "exporter";
+
 int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
                                  const char *label, size_t label_len,
-                                 const uint8_t *context, size_t context_len,
-                                 int use_context) {
-  const uint8_t *hash = NULL;
-  size_t hash_len = 0;
+                                 const uint8_t *context_in,
+                                 size_t context_in_len, int use_context) {
+  const uint8_t *context = NULL;
+  size_t context_len = 0;
   if (use_context) {
-    hash = context;
-    hash_len = context_len;
+    context = context_in;
+    context_len = context_in_len;
+  }
+
+  if (!ssl_is_draft21(ssl->version)) {
+    const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl));
+    return hkdf_expand_label(
+        out, ssl->version, digest, ssl->s3->exporter_secret,
+        ssl->s3->exporter_secret_len, (const uint8_t *)label, label_len,
+        context, context_len, out_len);
   }
 
   const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl));
-  return hkdf_expand_label(out, digest, ssl->s3->exporter_secret,
-                           ssl->s3->exporter_secret_len, (const uint8_t *)label,
-                           label_len, hash, hash_len, out_len);
+
+  uint8_t hash[EVP_MAX_MD_SIZE];
+  uint8_t export_context[EVP_MAX_MD_SIZE];
+  uint8_t derived_secret[EVP_MAX_MD_SIZE];
+  unsigned hash_len;
+  unsigned export_context_len;
+  unsigned derived_secret_len = EVP_MD_size(digest);
+  if (!EVP_Digest(context, context_len, hash, &hash_len, digest, NULL) ||
+      !EVP_Digest(NULL, 0, export_context, &export_context_len, digest, NULL)) {
+    return 0;
+  }
+  return hkdf_expand_label(
+             derived_secret, ssl->version, digest, ssl->s3->exporter_secret,
+             ssl->s3->exporter_secret_len, (const uint8_t *)label, label_len,
+             export_context, export_context_len, derived_secret_len) &&
+         hkdf_expand_label(
+             out, ssl->version, digest, derived_secret, derived_secret_len,
+             (const uint8_t *)kTLS13LabelExportKeying,
+             strlen(kTLS13LabelExportKeying), hash, hash_len, out_len);
 }
 
 static const char kTLS13LabelPSKBinder[] = "resumption psk binder key";
+static const char kTLS13Draft21LabelPSKBinder[] = "res binder";
 
-static int tls13_psk_binder(uint8_t *out, const EVP_MD *digest, uint8_t *psk,
-                            size_t psk_len, uint8_t *context,
-                            size_t context_len, size_t hash_len) {
+static int 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) {
   uint8_t binder_context[EVP_MAX_MD_SIZE];
   unsigned binder_context_len;
   if (!EVP_Digest(NULL, 0, binder_context, &binder_context_len, digest, NULL)) {
@@ -353,15 +464,17 @@
                     NULL, 0)) {
     return 0;
   }
+  const char *binder_label = ssl_is_draft21(version)
+                                 ? kTLS13Draft21LabelPSKBinder
+                                 : kTLS13LabelPSKBinder;
 
   uint8_t binder_key[EVP_MAX_MD_SIZE] = {0};
   size_t len;
-  if (!hkdf_expand_label(binder_key, digest, early_secret, hash_len,
-                         (const uint8_t *)kTLS13LabelPSKBinder,
-                         strlen(kTLS13LabelPSKBinder), binder_context,
-                         binder_context_len, hash_len) ||
-      !tls13_verify_data(digest, out, &len, binder_key, hash_len, context,
-                         context_len)) {
+  if (!hkdf_expand_label(binder_key, version, digest, early_secret, hash_len,
+                         (const uint8_t *)binder_label, strlen(binder_label),
+                         binder_context, binder_context_len, hash_len) ||
+      !tls13_verify_data(digest, version, out, &len, binder_key, hash_len,
+                         context, context_len)) {
     return 0;
   }
 
@@ -381,6 +494,7 @@
   ScopedEVP_MD_CTX ctx;
   uint8_t context[EVP_MAX_MD_SIZE];
   unsigned context_len;
+
   if (!EVP_DigestInit_ex(ctx.get(), digest, NULL) ||
       !EVP_DigestUpdate(ctx.get(), hs->transcript.buffer().data(),
                         hs->transcript.buffer().size()) ||
@@ -390,7 +504,8 @@
   }
 
   uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
-  if (!tls13_psk_binder(verify_data, digest, ssl->session->master_key,
+  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)) {
     return 0;
@@ -422,7 +537,7 @@
 
   uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
   CBS binder;
-  if (!tls13_psk_binder(verify_data, hs->transcript.Digest(),
+  if (!tls13_psk_binder(verify_data, hs->ssl->version, hs->transcript.Digest(),
                         session->master_key, session->master_key_length,
                         context, context_len, hash_len) ||
       // We only consider the first PSK, so compare against the first binder.
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 89c9d46..9afd0d4 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -160,33 +160,46 @@
   ssl_session_rebase_time(ssl, hs->new_session.get());
 
   for (int i = 0; i < kNumTickets; i++) {
-    if (!RAND_bytes((uint8_t *)&hs->new_session->ticket_age_add, 4)) {
+    UniquePtr<SSL_SESSION> session(
+        SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_INCLUDE_NONAUTH));
+    if (!session) {
       return 0;
     }
-    hs->new_session->ticket_age_add_valid = 1;
 
+    if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
+      return 0;
+    }
+    session->ticket_age_add_valid = 1;
     if (ssl->cert->enable_early_data) {
-      hs->new_session->ticket_max_early_data = kMaxEarlyDataAccepted;
+      session->ticket_max_early_data = kMaxEarlyDataAccepted;
     }
 
+    static_assert(kNumTickets < 256, "Too many tickets");
+    uint8_t nonce[] = {static_cast<uint8_t>(i)};
+
     ScopedCBB cbb;
-    CBB body, ticket, extensions;
+    CBB body, nonce_cbb, ticket, extensions;
     if (!ssl->method->init_message(ssl, cbb.get(), &body,
                                    SSL3_MT_NEW_SESSION_TICKET) ||
-        !CBB_add_u32(&body, hs->new_session->timeout) ||
-        !CBB_add_u32(&body, hs->new_session->ticket_age_add) ||
+        !CBB_add_u32(&body, session->timeout) ||
+        !CBB_add_u32(&body, session->ticket_age_add) ||
+        (ssl_is_draft21(ssl->version) &&
+         (!CBB_add_u8_length_prefixed(&body, &nonce_cbb) ||
+          !CBB_add_bytes(&nonce_cbb, nonce, sizeof(nonce)))) ||
         !CBB_add_u16_length_prefixed(&body, &ticket) ||
-        !ssl_encrypt_ticket(ssl, &ticket, hs->new_session.get()) ||
+        !tls13_derive_session_psk(session.get(), nonce) ||
+        !ssl_encrypt_ticket(ssl, &ticket, session.get()) ||
         !CBB_add_u16_length_prefixed(&body, &extensions)) {
       return 0;
     }
 
     if (ssl->cert->enable_early_data) {
       CBB early_data_info;
-      if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
+      if (!CBB_add_u16(&extensions, ssl_is_draft21(ssl->version)
+                                        ? TLSEXT_TYPE_early_data
+                                        : TLSEXT_TYPE_ticket_early_data_info) ||
           !CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
-          !CBB_add_u32(&early_data_info,
-                       hs->new_session->ticket_max_early_data) ||
+          !CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
           !CBB_flush(&extensions)) {
         return 0;
       }
@@ -244,8 +257,11 @@
 
   // The PRF hash is now known. Set up the key schedule and hash the
   // ClientHello.
-  if (!tls13_init_key_schedule(hs) ||
-      !ssl_hash_message(hs, msg)) {
+  if (!hs->transcript.InitHash(ssl_protocol_version(ssl), hs->new_cipher)) {
+    return ssl_hs_error;
+  }
+
+  if (!ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
@@ -429,13 +445,16 @@
     return ssl_hs_error;
   }
 
-  // Incorporate the PSK into the running secret.
+  size_t hash_len = EVP_MD_size(
+      ssl_get_handshake_digest(ssl_protocol_version(ssl), hs->new_cipher));
+
+  // Set up the key schedule and incorporate the PSK into the running secret.
   if (ssl->s3->session_reused) {
-    if (!tls13_advance_key_schedule(hs, hs->new_session->master_key,
+    if (!tls13_init_key_schedule(hs, hs->new_session->master_key,
                                     hs->new_session->master_key_length)) {
       return ssl_hs_error;
     }
-  } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
+  } else if (!tls13_init_key_schedule(hs, kZeroes, hash_len)) {
     return ssl_hs_error;
   }
 
@@ -454,6 +473,10 @@
       ssl->early_data_accepted = false;
       ssl->s3->skip_early_data = true;
       ssl->method->next_message(ssl);
+      if (ssl_is_draft21(ssl->version) &&
+          !hs->transcript.UpdateForHelloRetryRequest()) {
+        return ssl_hs_error;
+      }
       hs->tls13_state = state_send_hello_retry_request;
       return ssl_hs_ok;
     }
@@ -473,6 +496,8 @@
   if (!ssl->method->init_message(ssl, cbb.get(), &body,
                                  SSL3_MT_HELLO_RETRY_REQUEST) ||
       !CBB_add_u16(&body, ssl->version) ||
+      (ssl_is_draft21(ssl->version) &&
+       !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher))) ||
       !tls1_get_shared_group(hs, &group_id) ||
       !CBB_add_u16_length_prefixed(&body, &extensions) ||
       !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
@@ -582,16 +607,48 @@
 
   // Send a CertificateRequest, if necessary.
   if (hs->cert_request) {
-    CBB sigalgs_cbb;
-    if (!ssl->method->init_message(ssl, cbb.get(), &body,
-                                   SSL3_MT_CERTIFICATE_REQUEST) ||
-        !CBB_add_u8(&body, 0 /* no certificate_request_context. */) ||
-        !CBB_add_u16_length_prefixed(&body, &sigalgs_cbb) ||
-        !tls12_add_verify_sigalgs(ssl, &sigalgs_cbb) ||
-        !ssl_add_client_CA_list(ssl, &body) ||
-        !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) ||
-        !ssl_add_message_cbb(ssl, cbb.get())) {
-      return ssl_hs_error;
+    if (ssl_is_draft21(ssl->version)) {
+      CBB cert_request_extensions, sigalg_contents, sigalgs_cbb;
+      if (!ssl->method->init_message(ssl, cbb.get(), &body,
+                                     SSL3_MT_CERTIFICATE_REQUEST) ||
+          !CBB_add_u8(&body, 0 /* no certificate_request_context. */) ||
+          !CBB_add_u16_length_prefixed(&body, &cert_request_extensions) ||
+          !CBB_add_u16(&cert_request_extensions,
+                       TLSEXT_TYPE_signature_algorithms) ||
+          !CBB_add_u16_length_prefixed(&cert_request_extensions,
+                                       &sigalg_contents) ||
+          !CBB_add_u16_length_prefixed(&sigalg_contents, &sigalgs_cbb) ||
+          !tls12_add_verify_sigalgs(ssl, &sigalgs_cbb)) {
+        return ssl_hs_error;
+      }
+
+      if (ssl_has_client_CAs(ssl)) {
+        CBB ca_contents;
+        if (!CBB_add_u16(&cert_request_extensions,
+                         TLSEXT_TYPE_certificate_authorities) ||
+            !CBB_add_u16_length_prefixed(&cert_request_extensions,
+                                         &ca_contents) ||
+            !ssl_add_client_CA_list(ssl, &ca_contents) ||
+            !CBB_flush(&cert_request_extensions)) {
+          return ssl_hs_error;
+        }
+      }
+
+      if (!ssl_add_message_cbb(ssl, cbb.get())) {
+        return ssl_hs_error;
+      }
+    } else {
+      CBB sigalgs_cbb;
+      if (!ssl->method->init_message(ssl, cbb.get(), &body,
+                                     SSL3_MT_CERTIFICATE_REQUEST) ||
+          !CBB_add_u8(&body, 0 /* no certificate_request_context. */) ||
+          !CBB_add_u16_length_prefixed(&body, &sigalgs_cbb) ||
+          !tls12_add_verify_sigalgs(ssl, &sigalgs_cbb) ||
+          !ssl_add_client_CA_list(ssl, &body) ||
+          !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) ||
+          !ssl_add_message_cbb(ssl, cbb.get())) {
+        return ssl_hs_error;
+      }
     }
   }
 
@@ -648,6 +705,15 @@
     // the wire sooner and also avoids triggering a write on |SSL_read| when
     // processing the client Finished. This requires computing the client
     // Finished early. See draft-ietf-tls-tls13-18, section 4.5.1.
+    if (ssl_is_draft21(ssl->version)) {
+      static const uint8_t kEndOfEarlyData[4] = {SSL3_MT_END_OF_EARLY_DATA, 0,
+                                                 0, 0};
+      if (!hs->transcript.Update(kEndOfEarlyData)) {
+        OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+        return ssl_hs_error;
+      }
+    }
+
     size_t finished_len;
     if (!tls13_finished_mac(hs, hs->expected_client_finished, &finished_len,
                             0 /* client */)) {
@@ -698,11 +764,30 @@
 }
 
 static enum ssl_hs_wait_t do_process_end_of_early_data(SSL_HANDSHAKE *hs) {
+  SSL *const ssl = hs->ssl;
   hs->tls13_state = state_process_change_cipher_spec;
-  // If early data was accepted, the ChangeCipherSpec message will be in the
-  // discarded early data.
-  if (hs->early_data_offered && !hs->ssl->early_data_accepted) {
-    return ssl_hs_ok;
+  if (hs->early_data_offered) {
+    // If early data was not accepted, the EndOfEarlyData and ChangeCipherSpec
+    // message will be in the discarded early data.
+    if (!hs->ssl->early_data_accepted) {
+      return ssl_hs_ok;
+    }
+    if (ssl_is_draft21(ssl->version)) {
+      SSLMessage msg;
+      if (!ssl->method->get_message(ssl, &msg)) {
+        return ssl_hs_read_message;
+      }
+
+      if (!ssl_check_message_type(ssl, msg, SSL3_MT_END_OF_EARLY_DATA)) {
+        return ssl_hs_error;
+      }
+      if (CBS_len(&msg.body) != 0) {
+        ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+        return ssl_hs_error;
+      }
+      ssl->method->next_message(ssl);
+    }
   }
   return ssl_is_resumption_client_ccs_experiment(hs->ssl->version)
              ? ssl_hs_read_change_cipher_spec
diff --git a/ssl/tls_record.cc b/ssl/tls_record.cc
index bc641fa..a062012 100644
--- a/ssl/tls_record.cc
+++ b/ssl/tls_record.cc
@@ -320,7 +320,8 @@
 
   if (type == SSL3_RT_ALERT) {
     // Return end_of_early_data alerts as-is for the caller to process.
-    if (out->size() == 2 &&
+    if (!ssl_is_draft21(ssl->version) &&
+        out->size() == 2 &&
         (*out)[0] == SSL3_AL_WARNING &&
         (*out)[1] == TLS1_AD_END_OF_EARLY_DATA) {
       *out_type = type;
diff --git a/tool/client.cc b/tool/client.cc
index 2ec381f..873cea0 100644
--- a/tool/client.cc
+++ b/tool/client.cc
@@ -323,6 +323,10 @@
     *out = tls13_default;
     return true;
   }
+  if (in == "draft21") {
+    *out = tls13_draft21;
+    return true;
+  }
   if (in == "experiment") {
     *out = tls13_experiment;
     return true;