external/boringssl: Sync to f11ea19043f2b3ee42e4a76d0645914347e1a36e.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/ba9da449a4bf5b90cd020807f2c4176e3ab6fe3e..f11ea19043f2b3ee42e4a76d0645914347e1a36e

Test: BoringSSL CTS Presubmits.
Change-Id: Ifb6e46262349afd7cd7a23d59a684e25fb723208
diff --git a/src/ssl/handoff.cc b/src/ssl/handoff.cc
index b19d443..dd73c83 100644
--- a/src/ssl/handoff.cc
+++ b/src/ssl/handoff.cc
@@ -93,17 +93,17 @@
   if (CBS_len(&transcript) != 0) {
     s3->hs->transcript.Update(transcript);
     s3->is_v2_hello = true;
-    ssl_do_msg_callback(ssl, 0 /* read */, 0 /* V2ClientHello */, transcript);
   }
+  ssl->handback = true;
 
   return true;
 }
 
 bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
   if (!ssl->server ||
-      !ssl->s3->initial_handshake_complete ||
-      ssl->method->is_dtls ||
-      ssl->version < TLS1_VERSION) {
+      (ssl->s3->hs->state != state12_finish_server_handshake &&
+       ssl->s3->hs->state != state12_read_client_certificate) ||
+      ssl->method->is_dtls || ssl->version < TLS1_VERSION) {
     return false;
   }
 
@@ -115,14 +115,22 @@
 
   size_t iv_len = 0;
   const uint8_t *read_iv = nullptr, *write_iv = nullptr;
-  if (ssl->version == TLS1_VERSION &&
-      SSL_CIPHER_is_block_cipher(s3->aead_read_ctx->cipher()) &&
-      (!s3->aead_read_ctx->GetIV(&read_iv, &iv_len) ||
-       !s3->aead_write_ctx->GetIV(&write_iv, &iv_len))) {
-    return false;
+  Span<const uint8_t> transcript;
+  if (ssl->s3->hs->state == state12_finish_server_handshake) {
+    if (ssl->version == TLS1_VERSION &&
+        SSL_CIPHER_is_block_cipher(s3->aead_read_ctx->cipher()) &&
+        (!s3->aead_read_ctx->GetIV(&read_iv, &iv_len) ||
+         !s3->aead_write_ctx->GetIV(&write_iv, &iv_len))) {
+      return false;
+    }
+  } else {
+    transcript = s3->hs->transcript.buffer();
   }
 
-  CBB seq;
+  // TODO(mab): make sure everything is serialized.
+  CBB seq, key_share;
+  SSL_SESSION *session =
+      s3->session_reused ? ssl->session : s3->hs->new_session.get();
   if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
       !CBB_add_asn1_uint64(&seq, kHandbackVersion) ||
       !CBB_add_asn1_uint64(&seq, ssl->version) ||
@@ -142,7 +150,7 @@
       !CBB_add_asn1_bool(&seq, s3->session_reused) ||
       !CBB_add_asn1_bool(&seq, s3->send_connection_binding) ||
       !CBB_add_asn1_bool(&seq, s3->tlsext_channel_id_valid) ||
-      !ssl_session_serialize(s3->established_session.get(), &seq) ||
+      !ssl_session_serialize(session, &seq) ||
       !CBB_add_asn1_octet_string(&seq, s3->next_proto_negotiated.data(),
                                  s3->next_proto_negotiated.size()) ||
       !CBB_add_asn1_octet_string(&seq, s3->alpn_selected.data(),
@@ -158,11 +166,22 @@
       !CBB_add_asn1_bool(&seq, ssl->quiet_shutdown) ||
       !CBB_add_asn1_bool(&seq, ssl->tlsext_channel_id_enabled) ||
       !CBB_add_asn1_bool(&seq, ssl->retain_only_sha256_of_client_certs) ||
-      !CBB_flush(out)) {
+      !CBB_add_asn1_bool(&seq, ssl->token_binding_negotiated) ||
+      !CBB_add_asn1_uint64(&seq, ssl->negotiated_token_binding_param) ||
+      !CBB_add_asn1_bool(&seq, s3->hs->next_proto_neg_seen) ||
+      !CBB_add_asn1_bool(&seq, s3->hs->cert_request) ||
+      !CBB_add_asn1_bool(&seq, s3->hs->extended_master_secret) ||
+      !CBB_add_asn1_bool(&seq, s3->hs->ticket_expected) ||
+      !CBB_add_asn1_uint64(&seq, SSL_CIPHER_get_id(s3->hs->new_cipher)) ||
+      !CBB_add_asn1_octet_string(&seq, transcript.data(), transcript.size()) ||
+      !CBB_add_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
     return false;
   }
-
-  return true;
+  if (ssl->s3->hs->state == state12_read_client_certificate &&
+      !s3->hs->key_share->Serialize(&key_share)) {
+    return false;
+  }
+  return CBB_flush(out);
 }
 
 bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
@@ -173,11 +192,16 @@
 
   SSL3_STATE *const s3 = ssl->s3;
   uint64_t handback_version, version, conf_max_version, conf_min_version,
-      max_send_fragment, options, mode, max_cert_list;
+      max_send_fragment, options, mode, max_cert_list,
+      negotiated_token_binding_param, cipher;
+
   CBS seq, read_seq, write_seq, server_rand, client_rand, read_iv, write_iv,
-      next_proto, alpn, hostname, channel_id;
-  int session_reused, send_connection_binding, channel_id_valid,
-      quiet_shutdown, channel_id_enabled, retain_only_sha256;
+      next_proto, alpn, hostname, channel_id, transcript, key_share;
+  int session_reused, send_connection_binding, channel_id_valid, quiet_shutdown,
+      channel_id_enabled, retain_only_sha256, cert_request,
+      extended_master_secret, ticket_expected, token_binding_negotiated,
+      next_proto_neg_seen;
+  SSL_SESSION *session = nullptr;
 
   CBS handback_cbs(handback);
   if (!CBS_get_asn1(&handback_cbs, &seq, CBS_ASN1_SEQUENCE) ||
@@ -210,11 +234,19 @@
     return false;
   }
 
-  s3->established_session =
-      SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
+  s3->hs = ssl_handshake_new(ssl);
+  if (session_reused) {
+    ssl->session =
+        SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool)
+            .release();
+    session = ssl->session;
+  } else {
+    s3->hs->new_session =
+        SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
+    session = s3->hs->new_session.get();
+  }
 
-  if (!s3->established_session ||
-      !CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
+  if (!session || !CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
       !CBS_get_asn1(&seq, &alpn, CBS_ASN1_OCTETSTRING) ||
       !CBS_get_asn1(&seq, &hostname, CBS_ASN1_OCTETSTRING) ||
       !CBS_get_asn1(&seq, &channel_id, CBS_ASN1_OCTETSTRING) ||
@@ -226,7 +258,22 @@
       !CBS_get_asn1_uint64(&seq, &max_cert_list) ||
       !CBS_get_asn1_bool(&seq, &quiet_shutdown) ||
       !CBS_get_asn1_bool(&seq, &channel_id_enabled) ||
-      !CBS_get_asn1_bool(&seq, &retain_only_sha256)) {
+      !CBS_get_asn1_bool(&seq, &retain_only_sha256) ||
+      !CBS_get_asn1_bool(&seq, &token_binding_negotiated) ||
+      !CBS_get_asn1_uint64(&seq, &negotiated_token_binding_param) ||
+      !CBS_get_asn1_bool(&seq, &next_proto_neg_seen) ||
+      !CBS_get_asn1_bool(&seq, &cert_request) ||
+      !CBS_get_asn1_bool(&seq, &extended_master_secret) ||
+      !CBS_get_asn1_bool(&seq, &ticket_expected) ||
+      !CBS_get_asn1_uint64(&seq, &cipher)) {
+    return false;
+  }
+  if ((s3->hs->new_cipher =
+           SSL_get_cipher_by_value(static_cast<uint16_t>(cipher))) == nullptr) {
+    return false;
+  }
+  if (!CBS_get_asn1(&seq, &transcript, CBS_ASN1_OCTETSTRING) ||
+      !CBS_get_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
     return false;
   }
 
@@ -240,9 +287,9 @@
   ssl->mode = mode;
   ssl->max_cert_list = max_cert_list;
 
-  s3->hs.reset();
   s3->have_version = true;
-  s3->initial_handshake_complete = true;
+  s3->hs->state = CBS_len(&transcript) == 0 ? state12_finish_server_handshake
+                                            : state12_read_client_certificate;
   s3->session_reused = session_reused;
   s3->send_connection_binding = send_connection_binding;
   s3->tlsext_channel_id_valid = channel_id_valid;
@@ -263,23 +310,44 @@
   ssl->quiet_shutdown = quiet_shutdown;
   ssl->tlsext_channel_id_enabled = channel_id_enabled;
   ssl->retain_only_sha256_of_client_certs = retain_only_sha256;
+  ssl->token_binding_negotiated = token_binding_negotiated;
+  ssl->negotiated_token_binding_param =
+      static_cast<uint8_t>(negotiated_token_binding_param);
+  s3->hs->next_proto_neg_seen = next_proto_neg_seen;
+  s3->hs->wait = ssl_hs_flush;
+  s3->hs->extended_master_secret = extended_master_secret;
+  s3->hs->ticket_expected = ticket_expected;
+  s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version);
+  s3->hs->cert_request = cert_request;
 
-  Array<uint8_t> key_block;
-  if (!tls1_configure_aead(ssl, evp_aead_open, &key_block,
-                           s3->established_session->cipher, read_iv) ||
-      !tls1_configure_aead(ssl, evp_aead_seal, &key_block,
-                           s3->established_session->cipher, write_iv)) {
-    return false;
+  if (s3->hs->state == state12_finish_server_handshake) {
+    Array<uint8_t> key_block;
+    if (!tls1_configure_aead(ssl, evp_aead_open, &key_block, session->cipher,
+                             read_iv) ||
+        !tls1_configure_aead(ssl, evp_aead_seal, &key_block, session->cipher,
+                             write_iv)) {
+      return false;
+    }
+
+    if (!CBS_copy_bytes(&read_seq, s3->read_sequence,
+                        sizeof(s3->read_sequence)) ||
+        !CBS_copy_bytes(&write_seq, s3->write_sequence,
+                        sizeof(s3->write_sequence))) {
+      return false;
+    }
+  } else {
+    if (!s3->hs->transcript.Init() ||
+        !s3->hs->transcript.InitHash(ssl_protocol_version(ssl),
+                                     s3->hs->new_cipher) ||
+        !s3->hs->transcript.Update(transcript)) {
+      return false;
+    }
+    if ((s3->hs->key_share = SSLKeyShare::Create(&key_share)) == nullptr) {
+      return false;
+    }
   }
 
-  if (!CBS_copy_bytes(&read_seq, s3->read_sequence,
-                      sizeof(s3->read_sequence)) ||
-      !CBS_copy_bytes(&write_seq, s3->write_sequence,
-                      sizeof(s3->write_sequence))) {
-    return false;
-  }
-
-  return true;
+  return CBS_len(&seq) == 0;
 }
 
 }  // namespace bssl
diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc
index 6432424..00a2cc5 100644
--- a/src/ssl/handshake.cc
+++ b/src/ssl/handshake.cc
@@ -565,6 +565,11 @@
         hs->wait = ssl_hs_ok;
         return -1;
 
+      case ssl_hs_handback:
+        ssl->s3->rwstate = SSL_HANDBACK;
+        hs->wait = ssl_hs_handback;
+        return -1;
+
       case ssl_hs_x509_lookup:
         ssl->s3->rwstate = SSL_X509_LOOKUP;
         hs->wait = ssl_hs_ok;
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index fa8a241..5f2f41f 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -172,30 +172,6 @@
 
 namespace bssl {
 
-enum ssl_server_hs_state_t {
-  state_start_accept = 0,
-  state_read_client_hello,
-  state_select_certificate,
-  state_tls13,
-  state_select_parameters,
-  state_send_server_hello,
-  state_send_server_certificate,
-  state_send_server_key_exchange,
-  state_send_server_hello_done,
-  state_read_client_certificate,
-  state_verify_client_certificate,
-  state_read_client_key_exchange,
-  state_read_client_certificate_verify,
-  state_read_change_cipher_spec,
-  state_process_change_cipher_spec,
-  state_read_next_proto,
-  state_read_channel_id,
-  state_read_client_finished,
-  state_send_server_finished,
-  state_finish_server_handshake,
-  state_done,
-};
-
 int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello,
                                            uint16_t id) {
   CBS cipher_suites;
@@ -425,7 +401,7 @@
 
 static enum ssl_hs_wait_t do_start_accept(SSL_HANDSHAKE *hs) {
   ssl_do_info_callback(hs->ssl, SSL_CB_HANDSHAKE_START, 1);
-  hs->state = state_read_client_hello;
+  hs->state = state12_read_client_hello;
   return ssl_hs_ok;
 }
 
@@ -505,7 +481,7 @@
     return ssl_hs_error;
   }
 
-  hs->state = state_select_certificate;
+  hs->state = state12_select_certificate;
   return ssl_hs_ok;
 }
 
@@ -536,7 +512,7 @@
 
   if (ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
     // Jump to the TLS 1.3 state machine.
-    hs->state = state_tls13;
+    hs->state = state12_tls13;
     return ssl_hs_ok;
   }
 
@@ -555,14 +531,14 @@
     return ssl_hs_error;
   }
 
-  hs->state = state_select_parameters;
+  hs->state = state12_select_parameters;
   return ssl_hs_ok;
 }
 
 static enum ssl_hs_wait_t do_tls13(SSL_HANDSHAKE *hs) {
   enum ssl_hs_wait_t wait = tls13_server_handshake(hs);
   if (wait == ssl_hs_ok) {
-    hs->state = state_finish_server_handshake;
+    hs->state = state12_finish_server_handshake;
     return ssl_hs_ok;
   }
 
@@ -672,14 +648,15 @@
     return ssl_hs_error;
   }
 
-  // Release the handshake buffer if client authentication isn't required.
-  if (!hs->cert_request) {
+  // Handback includes the whole handshake transcript, so we cannot free the
+  // transcript buffer in the handback case.
+  if (!hs->cert_request && !hs->ssl->handback) {
     hs->transcript.FreeBuffer();
   }
 
   ssl->method->next_message(ssl);
 
-  hs->state = state_send_server_hello;
+  hs->state = state12_send_server_hello;
   return ssl_hs_ok;
 }
 
@@ -744,9 +721,9 @@
   }
 
   if (ssl->session != NULL) {
-    hs->state = state_send_server_finished;
+    hs->state = state12_send_server_finished;
   } else {
-    hs->state = state_send_server_certificate;
+    hs->state = state12_send_server_certificate;
   }
   return ssl_hs_ok;
 }
@@ -835,7 +812,7 @@
     }
   }
 
-  hs->state = state_send_server_key_exchange;
+  hs->state = state12_send_server_key_exchange;
   return ssl_hs_ok;
 }
 
@@ -843,7 +820,7 @@
   SSL *const ssl = hs->ssl;
 
   if (hs->server_params.size() == 0) {
-    hs->state = state_send_server_hello_done;
+    hs->state = state12_send_server_hello_done;
     return ssl_hs_ok;
   }
 
@@ -907,7 +884,7 @@
 
   hs->server_params.Reset();
 
-  hs->state = state_send_server_hello_done;
+  hs->state = state12_send_server_hello_done;
   return ssl_hs_ok;
 }
 
@@ -942,15 +919,18 @@
     return ssl_hs_error;
   }
 
-  hs->state = state_read_client_certificate;
+  hs->state = state12_read_client_certificate;
   return ssl_hs_flush;
 }
 
 static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
+  if (ssl->handback && hs->new_cipher->algorithm_mkey == SSL_kECDHE) {
+     return ssl_hs_handback;
+  }
   if (!hs->cert_request) {
-    hs->state = state_verify_client_certificate;
+    hs->state = state12_verify_client_certificate;
     return ssl_hs_ok;
   }
 
@@ -973,7 +953,7 @@
       // OpenSSL returns X509_V_OK when no certificates are received. This is
       // classed by them as a bug, but it's assumed by at least NGINX.
       hs->new_session->verify_result = X509_V_OK;
-      hs->state = state_verify_client_certificate;
+      hs->state = state12_verify_client_certificate;
       return ssl_hs_ok;
     }
 
@@ -1035,7 +1015,7 @@
   }
 
   ssl->method->next_message(ssl);
-  hs->state = state_verify_client_certificate;
+  hs->state = state12_verify_client_certificate;
   return ssl_hs_ok;
 }
 
@@ -1051,7 +1031,7 @@
     }
   }
 
-  hs->state = state_read_client_key_exchange;
+  hs->state = state12_read_client_key_exchange;
   return ssl_hs_ok;
 }
 
@@ -1262,7 +1242,7 @@
   hs->new_session->extended_master_secret = hs->extended_master_secret;
 
   ssl->method->next_message(ssl);
-  hs->state = state_read_client_certificate_verify;
+  hs->state = state12_read_client_certificate_verify;
   return ssl_hs_ok;
 }
 
@@ -1273,7 +1253,7 @@
   // CertificateVerify is required if and only if there's a client certificate.
   if (!hs->peer_pubkey) {
     hs->transcript.FreeBuffer();
-    hs->state = state_read_change_cipher_spec;
+    hs->state = state12_read_change_cipher_spec;
     return ssl_hs_ok;
   }
 
@@ -1358,12 +1338,12 @@
   }
 
   ssl->method->next_message(ssl);
-  hs->state = state_read_change_cipher_spec;
+  hs->state = state12_read_change_cipher_spec;
   return ssl_hs_ok;
 }
 
 static enum ssl_hs_wait_t do_read_change_cipher_spec(SSL_HANDSHAKE *hs) {
-  hs->state = state_process_change_cipher_spec;
+  hs->state = state12_process_change_cipher_spec;
   return ssl_hs_read_change_cipher_spec;
 }
 
@@ -1372,7 +1352,7 @@
     return ssl_hs_error;
   }
 
-  hs->state = state_read_next_proto;
+  hs->state = state12_read_next_proto;
   return ssl_hs_ok;
 }
 
@@ -1380,7 +1360,7 @@
   SSL *const ssl = hs->ssl;
 
   if (!hs->next_proto_neg_seen) {
-    hs->state = state_read_channel_id;
+    hs->state = state12_read_channel_id;
     return ssl_hs_ok;
   }
 
@@ -1408,7 +1388,7 @@
   }
 
   ssl->method->next_message(ssl);
-  hs->state = state_read_channel_id;
+  hs->state = state12_read_channel_id;
   return ssl_hs_ok;
 }
 
@@ -1416,7 +1396,7 @@
   SSL *const ssl = hs->ssl;
 
   if (!ssl->s3->tlsext_channel_id_valid) {
-    hs->state = state_read_client_finished;
+    hs->state = state12_read_client_finished;
     return ssl_hs_ok;
   }
 
@@ -1432,7 +1412,7 @@
   }
 
   ssl->method->next_message(ssl);
-  hs->state = state_read_client_finished;
+  hs->state = state12_read_client_finished;
   return ssl_hs_ok;
 }
 
@@ -1444,9 +1424,9 @@
   }
 
   if (ssl->session != NULL) {
-    hs->state = state_finish_server_handshake;
+    hs->state = state12_finish_server_handshake;
   } else {
-    hs->state = state_send_server_finished;
+    hs->state = state12_send_server_finished;
   }
 
   // If this is a full handshake with ChannelID then record the handshake
@@ -1501,9 +1481,9 @@
   }
 
   if (ssl->session != NULL) {
-    hs->state = state_read_change_cipher_spec;
+    hs->state = state12_read_change_cipher_spec;
   } else {
-    hs->state = state_finish_server_handshake;
+    hs->state = state12_finish_server_handshake;
   }
   return ssl_hs_flush;
 }
@@ -1511,6 +1491,10 @@
 static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
+  if (ssl->handback) {
+    return ssl_hs_handback;
+  }
+
   ssl->method->on_handshake_complete(ssl);
 
   // If we aren't retaining peer certificates then we can discard it now.
@@ -1532,77 +1516,77 @@
   ssl->s3->initial_handshake_complete = true;
   ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);
 
-  hs->state = state_done;
+  hs->state = state12_done;
   return ssl_hs_ok;
 }
 
 enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs) {
-  while (hs->state != state_done) {
+  while (hs->state != state12_done) {
     enum ssl_hs_wait_t ret = ssl_hs_error;
-    enum ssl_server_hs_state_t state =
-        static_cast<enum ssl_server_hs_state_t>(hs->state);
+    enum tls12_server_hs_state_t state =
+        static_cast<enum tls12_server_hs_state_t>(hs->state);
     switch (state) {
-      case state_start_accept:
+      case state12_start_accept:
         ret = do_start_accept(hs);
         break;
-      case state_read_client_hello:
+      case state12_read_client_hello:
         ret = do_read_client_hello(hs);
         break;
-      case state_select_certificate:
+      case state12_select_certificate:
         ret = do_select_certificate(hs);
         break;
-      case state_tls13:
+      case state12_tls13:
         ret = do_tls13(hs);
         break;
-      case state_select_parameters:
+      case state12_select_parameters:
         ret = do_select_parameters(hs);
         break;
-      case state_send_server_hello:
+      case state12_send_server_hello:
         ret = do_send_server_hello(hs);
         break;
-      case state_send_server_certificate:
+      case state12_send_server_certificate:
         ret = do_send_server_certificate(hs);
         break;
-      case state_send_server_key_exchange:
+      case state12_send_server_key_exchange:
         ret = do_send_server_key_exchange(hs);
         break;
-      case state_send_server_hello_done:
+      case state12_send_server_hello_done:
         ret = do_send_server_hello_done(hs);
         break;
-      case state_read_client_certificate:
+      case state12_read_client_certificate:
         ret = do_read_client_certificate(hs);
         break;
-      case state_verify_client_certificate:
+      case state12_verify_client_certificate:
         ret = do_verify_client_certificate(hs);
         break;
-      case state_read_client_key_exchange:
+      case state12_read_client_key_exchange:
         ret = do_read_client_key_exchange(hs);
         break;
-      case state_read_client_certificate_verify:
+      case state12_read_client_certificate_verify:
         ret = do_read_client_certificate_verify(hs);
         break;
-      case state_read_change_cipher_spec:
+      case state12_read_change_cipher_spec:
         ret = do_read_change_cipher_spec(hs);
         break;
-      case state_process_change_cipher_spec:
+      case state12_process_change_cipher_spec:
         ret = do_process_change_cipher_spec(hs);
         break;
-      case state_read_next_proto:
+      case state12_read_next_proto:
         ret = do_read_next_proto(hs);
         break;
-      case state_read_channel_id:
+      case state12_read_channel_id:
         ret = do_read_channel_id(hs);
         break;
-      case state_read_client_finished:
+      case state12_read_client_finished:
         ret = do_read_client_finished(hs);
         break;
-      case state_send_server_finished:
+      case state12_send_server_finished:
         ret = do_send_server_finished(hs);
         break;
-      case state_finish_server_handshake:
+      case state12_finish_server_handshake:
         ret = do_finish_server_handshake(hs);
         break;
-      case state_done:
+      case state12_done:
         ret = ssl_hs_ok;
         break;
     }
@@ -1621,50 +1605,50 @@
 }
 
 const char *ssl_server_handshake_state(SSL_HANDSHAKE *hs) {
-  enum ssl_server_hs_state_t state =
-      static_cast<enum ssl_server_hs_state_t>(hs->state);
+  enum tls12_server_hs_state_t state =
+      static_cast<enum tls12_server_hs_state_t>(hs->state);
   switch (state) {
-    case state_start_accept:
+    case state12_start_accept:
       return "TLS server start_accept";
-    case state_read_client_hello:
+    case state12_read_client_hello:
       return "TLS server read_client_hello";
-    case state_select_certificate:
+    case state12_select_certificate:
       return "TLS server select_certificate";
-    case state_tls13:
+    case state12_tls13:
       return tls13_server_handshake_state(hs);
-    case state_select_parameters:
+    case state12_select_parameters:
       return "TLS server select_parameters";
-    case state_send_server_hello:
+    case state12_send_server_hello:
       return "TLS server send_server_hello";
-    case state_send_server_certificate:
+    case state12_send_server_certificate:
       return "TLS server send_server_certificate";
-    case state_send_server_key_exchange:
+    case state12_send_server_key_exchange:
       return "TLS server send_server_key_exchange";
-    case state_send_server_hello_done:
+    case state12_send_server_hello_done:
       return "TLS server send_server_hello_done";
-    case state_read_client_certificate:
+    case state12_read_client_certificate:
       return "TLS server read_client_certificate";
-    case state_verify_client_certificate:
+    case state12_verify_client_certificate:
       return "TLS server verify_client_certificate";
-    case state_read_client_key_exchange:
+    case state12_read_client_key_exchange:
       return "TLS server read_client_key_exchange";
-    case state_read_client_certificate_verify:
+    case state12_read_client_certificate_verify:
       return "TLS server read_client_certificate_verify";
-    case state_read_change_cipher_spec:
+    case state12_read_change_cipher_spec:
       return "TLS server read_change_cipher_spec";
-    case state_process_change_cipher_spec:
+    case state12_process_change_cipher_spec:
       return "TLS server process_change_cipher_spec";
-    case state_read_next_proto:
+    case state12_read_next_proto:
       return "TLS server read_next_proto";
-    case state_read_channel_id:
+    case state12_read_channel_id:
       return "TLS server read_channel_id";
-    case state_read_client_finished:
+    case state12_read_client_finished:
       return "TLS server read_client_finished";
-    case state_send_server_finished:
+    case state12_send_server_finished:
       return "TLS server send_server_finished";
-    case state_finish_server_handshake:
+    case state12_finish_server_handshake:
       return "TLS server finish_server_handshake";
-    case state_done:
+    case state12_done:
       return "TLS server done";
   }
 
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index d13d5f2..e884b63 100644
--- a/src/ssl/internal.h
+++ b/src/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_draft28 returns whether the version corresponds to a draft28 TLS 1.3
+// variant.
+bool ssl_is_draft28(uint16_t version);
+
 // Cipher suites.
 
 }  // namespace bssl
@@ -694,7 +698,7 @@
   // number of bytes written.
   size_t GetAdditionalData(uint8_t out[13], uint8_t type,
                            uint16_t record_version, const uint8_t seqnum[8],
-                           size_t plaintext_len);
+                           size_t plaintext_len, size_t ciphertext_len);
 
   const SSL_CIPHER *cipher_;
   ScopedEVP_AEAD_CTX ctx_;
@@ -721,6 +725,9 @@
   bool omit_version_in_ad_ : 1;
   // omit_ad_ is true if the AEAD's ad parameter should be omitted.
   bool omit_ad_ : 1;
+  // tls13_ad_ is true if the AEAD's ad parameter should be based on the
+  // TLS 1.3 format.
+  bool tls13_ad_ : 1;
   // xor_fixed_nonce_ is true if the fixed nonce should be XOR'd into the
   // variable nonce rather than prepended.
   bool xor_fixed_nonce_ : 1;
@@ -929,6 +936,10 @@
   // nullptr on error.
   static UniquePtr<SSLKeyShare> Create(uint16_t group_id);
 
+  // Create deserializes an SSLKeyShare instance previously serialized by
+  // |Serialize|.
+  static UniquePtr<SSLKeyShare> Create(CBS *in);
+
   // GroupID returns the group ID.
   virtual uint16_t GroupID() const PURE_VIRTUAL;
 
@@ -952,6 +963,14 @@
   // send to the peer.
   virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert,
                       Span<const uint8_t> peer_key) PURE_VIRTUAL;
+
+  // Serialize writes the state of the key exchange to |out|, returning true if
+  // successful and false otherwise.
+  virtual bool Serialize(CBB *out) { return false; }
+
+  // Deserialize initializes the state of the key exchange from |in|, returning
+  // true if successful and false otherwise.  It is called by |Create|.
+  virtual bool Deserialize(CBS *in) { return false; }
 };
 
 // ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
@@ -1258,6 +1277,7 @@
   ssl_hs_flush,
   ssl_hs_certificate_selection_pending,
   ssl_hs_handoff,
+  ssl_hs_handback,
   ssl_hs_x509_lookup,
   ssl_hs_channel_id_lookup,
   ssl_hs_private_key_operation,
@@ -1280,6 +1300,30 @@
   ssl_grease_last_index = ssl_grease_ticket_extension,
 };
 
+enum tls12_server_hs_state_t {
+  state12_start_accept = 0,
+  state12_read_client_hello,
+  state12_select_certificate,
+  state12_tls13,
+  state12_select_parameters,
+  state12_send_server_hello,
+  state12_send_server_certificate,
+  state12_send_server_key_exchange,
+  state12_send_server_hello_done,
+  state12_read_client_certificate,
+  state12_verify_client_certificate,
+  state12_read_client_key_exchange,
+  state12_read_client_certificate_verify,
+  state12_read_change_cipher_spec,
+  state12_process_change_cipher_spec,
+  state12_read_next_proto,
+  state12_read_channel_id,
+  state12_read_client_finished,
+  state12_send_server_finished,
+  state12_finish_server_handshake,
+  state12_done,
+};
+
 struct SSL_HANDSHAKE {
   explicit SSL_HANDSHAKE(SSL *ssl);
   ~SSL_HANDSHAKE();
@@ -2676,6 +2720,11 @@
   // element of the same name and may be cleared if the handoff is declined.
   bool handoff:1;
 
+  // handback indicates that a server should pause the handshake after
+  // finishing operations that require private key material, in such a way that
+  // |SSL_get_error| returns |SSL_HANDBACK|.  It is set by |SSL_apply_handoff|.
+  bool handback : 1;
+
   // did_dummy_pq_padding is only valid for a client. In that context, it is
   // true iff the client observed the server echoing a dummy PQ padding
   // extension.
diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc
index 247e889..e6b3ee9 100644
--- a/src/ssl/ssl_aead_ctx.cc
+++ b/src/ssl/ssl_aead_ctx.cc
@@ -43,6 +43,7 @@
       omit_length_in_ad_(false),
       omit_version_in_ad_(false),
       omit_ad_(false),
+      tls13_ad_(false),
       xor_fixed_nonce_(false) {
   OPENSSL_memset(fixed_nonce_, 0, sizeof(fixed_nonce_));
 }
@@ -134,7 +135,11 @@
       aead_ctx->xor_fixed_nonce_ = true;
       aead_ctx->variable_nonce_len_ = 8;
       aead_ctx->variable_nonce_included_in_record_ = false;
-      aead_ctx->omit_ad_ = true;
+      if (ssl_is_draft28(version)) {
+        aead_ctx->tls13_ad_ = true;
+      } else {
+        aead_ctx->omit_ad_ = true;
+      }
       assert(fixed_iv.size() >= aead_ctx->variable_nonce_len_);
     }
   } else {
@@ -203,19 +208,26 @@
 size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type,
                                          uint16_t record_version,
                                          const uint8_t seqnum[8],
-                                         size_t plaintext_len) {
+                                         size_t plaintext_len,
+                                         size_t ciphertext_len) {
   if (omit_ad_) {
     return 0;
   }
 
-  OPENSSL_memcpy(out, seqnum, 8);
-  size_t len = 8;
+  size_t len = 0;
+  if (!tls13_ad_) {
+    OPENSSL_memcpy(out, seqnum, 8);
+    len += 8;
+  }
   out[len++] = type;
   if (!omit_version_in_ad_) {
     out[len++] = static_cast<uint8_t>((record_version >> 8));
     out[len++] = static_cast<uint8_t>(record_version);
   }
-  if (!omit_length_in_ad_) {
+  if (tls13_ad_) {
+    out[len++] = static_cast<uint8_t>((ciphertext_len >> 8));
+    out[len++] = static_cast<uint8_t>(ciphertext_len);
+  } else if (!omit_length_in_ad_) {
     out[len++] = static_cast<uint8_t>((plaintext_len >> 8));
     out[len++] = static_cast<uint8_t>(plaintext_len);
   }
@@ -244,8 +256,8 @@
     plaintext_len = in.size() - overhead;
   }
   uint8_t ad[13];
-  size_t ad_len =
-      GetAdditionalData(ad, type, record_version, seqnum, plaintext_len);
+  size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum,
+                                    plaintext_len, in.size());
 
   // Assemble the nonce.
   uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
@@ -320,7 +332,8 @@
   }
 
   uint8_t ad[13];
-  size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum, in_len);
+  size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum, in_len,
+                                    in_len + suffix_len);
 
   // Assemble the nonce.
   uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc
index 4d76bb2..2a076c3 100644
--- a/src/ssl/ssl_key_share.cc
+++ b/src/ssl/ssl_key_share.cc
@@ -124,6 +124,32 @@
     return true;
   }
 
+  bool Serialize(CBB *out) override {
+    assert(private_key_);
+    CBB cbb;
+    UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_));
+    // Padding is added to avoid leaking the length.
+    size_t len = BN_num_bytes(EC_GROUP_get0_order(group.get()));
+    if (!CBB_add_asn1_uint64(out, group_id_) ||
+        !CBB_add_asn1(out, &cbb, CBS_ASN1_OCTETSTRING) ||
+        !BN_bn2cbb_padded(&cbb, len, private_key_.get()) ||
+        !CBB_flush(out)) {
+      return false;
+    }
+    return true;
+  }
+
+  bool Deserialize(CBS *in) override {
+    assert(!private_key_);
+    CBS private_key;
+    if (!CBS_get_asn1(in, &private_key, CBS_ASN1_OCTETSTRING)) {
+      return false;
+    }
+    private_key_.reset(BN_bin2bn(CBS_data(&private_key),
+                                 CBS_len(&private_key), nullptr));
+    return private_key_ != nullptr;
+  }
+
  private:
   UniquePtr<BIGNUM> private_key_;
   int nid_;
@@ -166,6 +192,21 @@
     return true;
   }
 
+  bool Serialize(CBB *out) override {
+    return (CBB_add_asn1_uint64(out, GroupID()) &&
+            CBB_add_asn1_octet_string(out, private_key_, sizeof(private_key_)));
+  }
+
+  bool Deserialize(CBS *in) override {
+    CBS key;
+    if (!CBS_get_asn1(in, &key, CBS_ASN1_OCTETSTRING) ||
+        CBS_len(&key) != sizeof(private_key_) ||
+        !CBS_copy_bytes(&key, private_key_, sizeof(private_key_))) {
+      return false;
+    }
+    return true;
+  }
+
  private:
   uint8_t private_key_[32];
 };
@@ -205,6 +246,19 @@
   }
 }
 
+UniquePtr<SSLKeyShare> SSLKeyShare::Create(CBS *in) {
+  uint64_t group;
+  if (!CBS_get_asn1_uint64(in, &group)) {
+    return nullptr;
+  }
+  UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint64_t>(group));
+  if (!key_share->Deserialize(in)) {
+    return nullptr;
+  }
+  return key_share;
+}
+
+
 bool SSLKeyShare::Accept(CBB *out_public_key, Array<uint8_t> *out_secret,
                          uint8_t *out_alert, Span<const uint8_t> peer_key) {
   *out_alert = SSL_AD_INTERNAL_ERROR;
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index ef79831..6312504 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -1274,6 +1274,9 @@
     case SSL_HANDOFF:
       return SSL_ERROR_HANDOFF;
 
+    case SSL_HANDBACK:
+      return SSL_ERROR_HANDBACK;
+
     case SSL_READING: {
       BIO *bio = SSL_get_rbio(ssl);
       if (BIO_should_read(bio)) {
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 9f77f14..12f044c 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -3949,9 +3949,13 @@
 
   int handshake_ret = SSL_do_handshake(handshaker.get());
   int handshake_err = SSL_get_error(handshaker.get(), handshake_ret);
-  ASSERT_EQ(handshake_err, SSL_ERROR_WANT_READ);
+  ASSERT_EQ(handshake_err, SSL_ERROR_HANDBACK);
 
-  ASSERT_TRUE(CompleteHandshakes(client.get(), handshaker.get()));
+  // Double-check that additional calls to |SSL_do_handshake| continue
+  // to get |SSL_ERRROR_HANDBACK|.
+  handshake_ret = SSL_do_handshake(handshaker.get());
+  handshake_err = SSL_get_error(handshaker.get(), handshake_ret);
+  ASSERT_EQ(handshake_err, SSL_ERROR_HANDBACK);
 
   ScopedCBB cbb_handback;
   Array<uint8_t> handback;
@@ -3963,6 +3967,7 @@
   ASSERT_TRUE(SSL_apply_handback(server2.get(), handback));
 
   MoveBIOs(server2.get(), handshaker.get());
+  ASSERT_TRUE(CompleteHandshakes(client.get(), server2.get()));
 
   uint8_t byte = 42;
   EXPECT_EQ(SSL_write(client.get(), &byte, 1), 1);
diff --git a/src/ssl/ssl_transcript.cc b/src/ssl/ssl_transcript.cc
index 2033dfd..345f9d3 100644
--- a/src/ssl/ssl_transcript.cc
+++ b/src/ssl/ssl_transcript.cc
@@ -368,10 +368,6 @@
     return true;
   }
 
-  // At this point, the handshake should have released the handshake buffer on
-  // its own.
-  assert(!buffer_);
-
   static const char kClientLabel[] = "client finished";
   static const char kServerLabel[] = "server finished";
   auto label = from_server
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index aeb41d3..73ea26f 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -35,6 +35,7 @@
       return true;
 
     case TLS1_3_DRAFT23_VERSION:
+    case TLS1_3_DRAFT28_VERSION:
       *out = TLS1_3_VERSION;
       return true;
 
@@ -57,6 +58,7 @@
 
 static const uint16_t kTLSVersions[] = {
     TLS1_3_DRAFT23_VERSION,
+    TLS1_3_DRAFT28_VERSION,
     TLS1_2_VERSION,
     TLS1_1_VERSION,
     TLS1_VERSION,
@@ -100,6 +102,7 @@
 static const char *ssl_version_to_string(uint16_t version) {
   switch (version) {
     case TLS1_3_DRAFT23_VERSION:
+    case TLS1_3_DRAFT28_VERSION:
       return "TLSv1.3";
 
     case TLS1_2_VERSION:
@@ -129,6 +132,7 @@
   switch (version) {
     // Report TLS 1.3 draft versions as TLS 1.3 in the public API.
     case TLS1_3_DRAFT23_VERSION:
+    case TLS1_3_DRAFT28_VERSION:
       return TLS1_3_VERSION;
     default:
       return version;
@@ -139,7 +143,8 @@
 // particular, it picks an arbitrary TLS 1.3 representative. This should only be
 // used in context where that does not matter.
 static bool api_version_to_wire(uint16_t *out, uint16_t version) {
-  if (version == TLS1_3_DRAFT23_VERSION) {
+  if (version == TLS1_3_DRAFT23_VERSION ||
+      version == TLS1_3_DRAFT28_VERSION) {
     return false;
   }
   if (version == TLS1_3_VERSION) {
@@ -295,20 +300,15 @@
   }
 
   // This logic is part of the TLS 1.3 variants mechanism used in TLS 1.3
-  // experimentation. Although we currently only have one variant, TLS 1.3 does
-  // not a final stable deployment yet, so leave the logic in place for now.
+  // experimentation. TLS 1.3 variants must match the enabled |tls13_variant|.
   if (protocol_version != TLS1_3_VERSION ||
+      (ssl->tls13_variant == tls13_draft28 &&
+       version == TLS1_3_DRAFT28_VERSION) ||
       (ssl->tls13_variant == tls13_default &&
        version == TLS1_3_DRAFT23_VERSION)) {
     return true;
   }
 
-  // The server, when not configured at |tls13_default|, should additionally
-  // enable all variants.
-  if (ssl->server && ssl->tls13_variant != tls13_default) {
-    return true;
-  }
-
   return false;
 }
 
@@ -356,6 +356,10 @@
   return false;
 }
 
+bool ssl_is_draft28(uint16_t version) {
+  return version == TLS1_3_DRAFT28_VERSION;
+}
+
 }  // namespace bssl
 
 using namespace bssl;
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index ae26ded..107de52 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -1937,40 +1937,34 @@
   return fwrite(settings, settings_len, 1, file.get()) == 1;
 }
 
-static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
-                       bssl::UniquePtr<SSL> *ssl_uniqueptr,
-                       const TestConfig *config, bool is_resume, bool is_retry);
-
-// DoConnection tests an SSL connection against the peer. On success, it returns
-// true and sets |*out_session| to the negotiated SSL session. If the test is a
-// resumption attempt, |is_resume| is true and |session| is the session from the
-// previous exchange.
-static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
-                         SSL_CTX *ssl_ctx, const TestConfig *config,
-                         const TestConfig *retry_config, bool is_resume,
-                         SSL_SESSION *session) {
+static bssl::UniquePtr<SSL> NewSSL(SSL_CTX *ssl_ctx, const TestConfig *config,
+                                   SSL_SESSION *session, bool is_resume,
+                                   std::unique_ptr<TestState> test_state) {
   bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
   if (!ssl) {
-    return false;
+    return nullptr;
   }
 
-  if (!SetTestConfig(ssl.get(), config) ||
-      !SetTestState(ssl.get(), std::unique_ptr<TestState>(new TestState))) {
-    return false;
+  if (!SetTestConfig(ssl.get(), config)) {
+    return nullptr;
   }
-
-  GetTestState(ssl.get())->is_resume = is_resume;
+  if (test_state != nullptr) {
+    if (!SetTestState(ssl.get(), std::move(test_state))) {
+      return nullptr;
+    }
+    GetTestState(ssl.get())->is_resume = is_resume;
+  }
 
   if (config->fallback_scsv &&
       !SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
-    return false;
+    return nullptr;
   }
   // Install the certificate synchronously if nothing else will handle it.
   if (!config->use_early_callback &&
       !config->use_old_client_cert_callback &&
       !config->async &&
       !InstallCertificate(ssl.get())) {
-    return false;
+    return nullptr;
   }
   if (!config->use_old_client_cert_callback) {
     SSL_set_cert_cb(ssl.get(), CertCallback, nullptr);
@@ -2027,7 +2021,7 @@
       // The async case will be supplied by |ChannelIdCallback|.
       bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(config->send_channel_id);
       if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
-        return false;
+        return nullptr;
       }
     }
   }
@@ -2039,13 +2033,13 @@
   }
   if (!config->host_name.empty() &&
       !SSL_set_tlsext_host_name(ssl.get(), config->host_name.c_str())) {
-    return false;
+    return nullptr;
   }
   if (!config->advertise_alpn.empty() &&
       SSL_set_alpn_protos(ssl.get(),
                           (const uint8_t *)config->advertise_alpn.data(),
                           config->advertise_alpn.size()) != 0) {
-    return false;
+    return nullptr;
   }
   if (!config->psk.empty()) {
     SSL_set_psk_client_callback(ssl.get(), PskClientCallback);
@@ -2053,11 +2047,11 @@
   }
   if (!config->psk_identity.empty() &&
       !SSL_use_psk_identity_hint(ssl.get(), config->psk_identity.c_str())) {
-    return false;
+    return nullptr;
   }
   if (!config->srtp_profiles.empty() &&
       !SSL_set_srtp_profiles(ssl.get(), config->srtp_profiles.c_str())) {
-    return false;
+    return nullptr;
   }
   if (config->enable_ocsp_stapling) {
     SSL_enable_ocsp_stapling(ssl.get());
@@ -2067,11 +2061,11 @@
   }
   if (config->min_version != 0 &&
       !SSL_set_min_proto_version(ssl.get(), (uint16_t)config->min_version)) {
-    return false;
+    return nullptr;
   }
   if (config->max_version != 0 &&
       !SSL_set_max_proto_version(ssl.get(), (uint16_t)config->max_version)) {
-    return false;
+    return nullptr;
   }
   if (config->mtu != 0) {
     SSL_set_options(ssl.get(), SSL_OP_NO_QUERY_MTU);
@@ -2095,7 +2089,7 @@
   if (config->p384_only) {
     int nid = NID_secp384r1;
     if (!SSL_set1_curves(ssl.get(), &nid, 1)) {
-      return false;
+      return nullptr;
     }
   }
   if (config->enable_all_curves) {
@@ -2105,7 +2099,7 @@
     };
     if (!SSL_set1_curves(ssl.get(), kAllCurves,
                          OPENSSL_ARRAY_SIZE(kAllCurves))) {
-      return false;
+      return nullptr;
     }
   }
   if (config->initial_timeout_duration_ms > 0) {
@@ -2123,7 +2117,7 @@
   }
   if (config->dummy_pq_padding_len > 0 &&
       !SSL_set_dummy_pq_padding_size(ssl.get(), config->dummy_pq_padding_len)) {
-    return false;
+    return nullptr;
   }
   if (!config->quic_transport_params.empty()) {
     if (!SSL_set_quic_transport_params(
@@ -2131,10 +2125,55 @@
             reinterpret_cast<const uint8_t *>(
                 config->quic_transport_params.data()),
             config->quic_transport_params.size())) {
-      return false;
+      return nullptr;
     }
   }
 
+  if (session != NULL) {
+    if (!config->is_server) {
+      if (SSL_set_session(ssl.get(), session) != 1) {
+        return nullptr;
+      }
+    } else if (config->async) {
+      // The internal session cache is disabled, so install the session
+      // manually.
+      SSL_SESSION_up_ref(session);
+      GetTestState(ssl.get())->pending_session.reset(session);
+    }
+  }
+
+  if (SSL_get_current_cipher(ssl.get()) != nullptr) {
+    fprintf(stderr, "non-null cipher before handshake\n");
+    return nullptr;
+  }
+
+  return ssl;
+}
+
+static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
+                       bssl::UniquePtr<SSL> *ssl_uniqueptr,
+                       const TestConfig *config, bool is_resume, bool is_retry);
+
+// DoConnection tests an SSL connection against the peer. On success, it returns
+// true and sets |*out_session| to the negotiated SSL session. If the test is a
+// resumption attempt, |is_resume| is true and |session| is the session from the
+// previous exchange.
+static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
+                         SSL_CTX *ssl_ctx, const TestConfig *config,
+                         const TestConfig *retry_config, bool is_resume,
+                         SSL_SESSION *session) {
+  bssl::UniquePtr<SSL> ssl = NewSSL(ssl_ctx, config, session, is_resume,
+                                    std::unique_ptr<TestState>(new TestState));
+  if (!ssl) {
+    return false;
+  }
+  if (config->is_server) {
+    SSL_set_accept_state(ssl.get());
+  } else {
+    SSL_set_connect_state(ssl.get());
+  }
+
+
   int sock = Connect(config->port);
   if (sock == -1) {
     return false;
@@ -2167,30 +2206,6 @@
   SSL_set_bio(ssl.get(), bio.get(), bio.get());
   bio.release();  // SSL_set_bio takes ownership.
 
-  if (session != NULL) {
-    if (!config->is_server) {
-      if (SSL_set_session(ssl.get(), session) != 1) {
-        return false;
-      }
-    } else if (config->async) {
-      // The internal session cache is disabled, so install the session
-      // manually.
-      SSL_SESSION_up_ref(session);
-      GetTestState(ssl.get())->pending_session.reset(session);
-    }
-  }
-
-  if (SSL_get_current_cipher(ssl.get()) != nullptr) {
-    fprintf(stderr, "non-null cipher before handshake\n");
-    return false;
-  }
-
-  if (config->is_server) {
-    SSL_set_accept_state(ssl.get());
-  } else {
-    SSL_set_connect_state(ssl.get());
-  }
-
   bool ret = DoExchange(out_session, &ssl, config, is_resume, false);
   if (!config->is_server && is_resume && config->expect_reject_early_data) {
     // We must have failed due to an early data rejection.
@@ -2253,22 +2268,28 @@
   return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDOFF;
 }
 
+static bool HandbackReady(SSL *ssl, int ret) {
+  return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDBACK;
+}
+
 static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
                        bssl::UniquePtr<SSL> *ssl_uniqueptr,
                        const TestConfig *config, bool is_resume,
                        bool is_retry) {
   int ret;
   SSL *ssl = ssl_uniqueptr->get();
+  SSL_CTX *session_ctx = ssl->ctx;
 
   if (!config->implicit_handshake) {
     if (config->handoff) {
-      bssl::UniquePtr<SSL_CTX> ctx_handoff(SSL_CTX_new(TLSv1_method()));
+      bssl::UniquePtr<SSL_CTX> ctx_handoff = SetupCtx(ssl->ctx, config);
       if (!ctx_handoff) {
         return false;
       }
       SSL_CTX_set_handoff_mode(ctx_handoff.get(), 1);
 
-      bssl::UniquePtr<SSL> ssl_handoff(SSL_new(ctx_handoff.get()));
+      bssl::UniquePtr<SSL> ssl_handoff =
+          NewSSL(ctx_handoff.get(), config, nullptr, false, nullptr);
       if (!ssl_handoff) {
         return false;
       }
@@ -2318,12 +2339,12 @@
       });
     } while (config->async && RetryAsync(ssl, ret));
 
-    if (ret != 1 ||
-        !CheckHandshakeProperties(ssl, is_resume, config)) {
-      return false;
-    }
-
     if (config->handoff) {
+      if (!HandbackReady(ssl, ret)) {
+        fprintf(stderr, "Connection failed to handback.\n");
+        return false;
+      }
+
       bssl::ScopedCBB cbb;
       bssl::Array<uint8_t> handback;
       if (!CBB_init(cbb.get(), 512) ||
@@ -2333,26 +2354,42 @@
         return false;
       }
 
-      bssl::UniquePtr<SSL_CTX> ctx_handback(SSL_CTX_new(TLSv1_method()));
-      SSL_CTX_set_msg_callback(ctx_handback.get(), MessageCallback);
-      bssl::UniquePtr<SSL> ssl_handback(SSL_new(ctx_handback.get()));
+      bssl::UniquePtr<SSL_CTX> ctx_handback = SetupCtx(ssl->ctx, config);
+      if (!ctx_handback) {
+        return false;
+      }
+      bssl::UniquePtr<SSL> ssl_handback =
+          NewSSL(ctx_handback.get(), config, nullptr, false, nullptr);
       if (!ssl_handback) {
         return false;
       }
-      if (!SSL_apply_handback(ssl_handback.get(), handback)) {
-        fprintf(stderr, "Applying handback failed.\n");
-        return false;
-      }
-
       MoveBIOs(ssl_handback.get(), ssl);
       if (!MoveExData(ssl_handback.get(), ssl)) {
         return false;
       }
 
+      if (!SSL_apply_handback(ssl_handback.get(), handback)) {
+        fprintf(stderr, "Applying handback failed.\n");
+        return false;
+      }
+
       *ssl_uniqueptr = std::move(ssl_handback);
       ssl = ssl_uniqueptr->get();
+
+      do {
+        ret = CheckIdempotentError("SSL_do_handshake", ssl, [&]() -> int {
+          return SSL_do_handshake(ssl);
+        });
+      } while (config->async && RetryAsync(ssl, ret));
     }
 
+    if (ret != 1 || !CheckHandshakeProperties(ssl, is_resume, config)) {
+      return false;
+    }
+
+    lh_SSL_SESSION_doall_arg(ssl->ctx->sessions, ssl_ctx_add_session,
+                             session_ctx);
+
     if (is_resume && !is_retry && !config->is_server &&
         config->expect_no_offer_early_data && SSL_in_early_data(ssl)) {
       fprintf(stderr, "Client unexpectedly offered early data.\n");
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 16f4dd7..8f354e9 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -34,13 +34,16 @@
 // A draft version of TLS 1.3 that is sent over the wire for the current draft.
 const (
 	tls13Draft23Version = 0x7f17
+	tls13Draft28Version = 0x7f1c
 )
 
 const (
 	TLS13Draft23 = 0
+	TLS13Draft28 = 1
 )
 
 var allTLSWireVersions = []uint16{
+	tls13Draft28Version,
 	tls13Draft23Version,
 	VersionTLS12,
 	VersionTLS11,
@@ -1671,7 +1674,7 @@
 		switch vers {
 		case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
 			return vers, true
-		case tls13Draft23Version:
+		case tls13Draft23Version, tls13Draft28Version:
 			return VersionTLS13, true
 		}
 	}
@@ -1679,11 +1682,16 @@
 	return 0, false
 }
 
+func isDraft28(vers uint16) bool {
+	return vers == tls13Draft28Version
+}
+
 // isSupportedVersion checks if the specified wire version is acceptable. If so,
 // it returns true and the corresponding protocol version. Otherwise, it returns
 // false.
 func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) {
-	if c.TLS13Variant != TLS13Draft23 && wireVers == tls13Draft23Version {
+	if (c.TLS13Variant != TLS13Draft23 && wireVers == tls13Draft23Version) ||
+		(c.TLS13Variant != TLS13Draft28 && wireVers == tls13Draft28Version) {
 		return 0, false
 	}
 
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 79cd06a..9cd61eb 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -448,6 +448,8 @@
 				n := len(payload) - c.Overhead()
 				additionalData[11] = byte(n >> 8)
 				additionalData[12] = byte(n)
+			} else if isDraft28(hc.wireVersion) {
+				additionalData = b.data[:recordHeaderLen]
 			}
 			var err error
 			payload, err = c.Open(payload[:0], nonce, payload, additionalData)
@@ -612,6 +614,12 @@
 				copy(additionalData[8:], b.data[:3])
 				additionalData[11] = byte(payloadLen >> 8)
 				additionalData[12] = byte(payloadLen)
+			} else if isDraft28(hc.wireVersion) {
+				additionalData = make([]byte, 5)
+				copy(additionalData, b.data[:3])
+				n := len(b.data) - recordHeaderLen
+				additionalData[3] = byte(n >> 8)
+				additionalData[4] = byte(n)
 			}
 
 			c.Seal(payload[:0], nonce, payload, additionalData)
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 308f3c6..683fd3a 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -1378,6 +1378,13 @@
 		versionWire:  tls13Draft23Version,
 		tls13Variant: TLS13Draft23,
 	},
+	{
+		name:         "TLS13Draft28",
+		version:      VersionTLS13,
+		excludeFlag:  "-no-tls13",
+		versionWire:  tls13Draft28Version,
+		tls13Variant: TLS13Draft28,
+	},
 }
 
 func allVersions(protocol protocol) []tlsVersion {
@@ -5389,16 +5396,12 @@
 					expectedVersion = runnerVers.version
 				}
 				// 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 multiple variants.
-				expectedServerVersion := expectedVersion
-				expectedClientVersion := expectedVersion
+				// shim peers are expected to fall back to TLS 1.2.
 				if expectedVersion == VersionTLS13 && runnerVers.tls13Variant != shimVers.tls13Variant {
-					expectedClientVersion = VersionTLS12
-					if shimVers.tls13Variant == TLS13Draft23 {
-						expectedServerVersion = VersionTLS12
-					}
+					expectedVersion = VersionTLS12
 				}
+				expectedClientVersion := expectedVersion
+				expectedServerVersion := expectedVersion
 
 				suffix := shimVers.name + "-" + runnerVers.name
 				if protocol == dtls {
diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc
index 05a3d56..3152e7a 100644
--- a/src/ssl/tls_record.cc
+++ b/src/ssl/tls_record.cc
@@ -416,7 +416,7 @@
   out_prefix[4] = ciphertext_len & 0xff;
 
   if (!ssl->s3->aead_write_ctx->SealScatter(
-          out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, type,
+          out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, out_prefix[0],
           record_version, ssl->s3->write_sequence, in, in_len, extra_in,
           extra_in_len) ||
       !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) {