external/boringssl: Sync to 9f0e7cb314ae64234b928fd379381ae9760a9a5f.
am: 15c0b3594b

Change-Id: I4f257eb27607e953e4d5a4e049dfd37592cab4c4
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index a472103..6346331 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-f11ea19043f2b3ee42e4a76d0645914347e1a36e
+9f0e7cb314ae64234b928fd379381ae9760a9a5f
diff --git a/src/crypto/asn1/a_strnid.c b/src/crypto/asn1/a_strnid.c
index 379a79f..efbf0fa 100644
--- a/src/crypto/asn1/a_strnid.c
+++ b/src/crypto/asn1/a_strnid.c
@@ -223,6 +223,7 @@
         return ttmp;
     if (!stable)
         return NULL;
+    sk_ASN1_STRING_TABLE_sort(stable);
     found = sk_ASN1_STRING_TABLE_find(stable, &idx, &fnd);
     if (!found)
         return NULL;
diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c
index 9f4639f..5752712 100644
--- a/src/crypto/crypto.c
+++ b/src/crypto/crypto.c
@@ -164,31 +164,21 @@
 #endif
 }
 
-const char *SSLeay_version(int unused) {
-  return "BoringSSL";
-}
+const char *SSLeay_version(int unused) { return "BoringSSL"; }
 
-const char *OpenSSL_version(int unused) {
-  return "BoringSSL";
-}
+const char *OpenSSL_version(int unused) { return "BoringSSL"; }
 
-unsigned long SSLeay(void) {
-  return OPENSSL_VERSION_NUMBER;
-}
+unsigned long SSLeay(void) { return OPENSSL_VERSION_NUMBER; }
 
-unsigned long OpenSSL_version_num(void) {
-  return OPENSSL_VERSION_NUMBER;
-}
+unsigned long OpenSSL_version_num(void) { return OPENSSL_VERSION_NUMBER; }
 
-int CRYPTO_malloc_init(void) {
-  return 1;
-}
+int CRYPTO_malloc_init(void) { return 1; }
+
+int OPENSSL_malloc_init(void) { return 1; }
 
 void ENGINE_load_builtin_engines(void) {}
 
-int ENGINE_register_all_complete(void) {
-  return 1;
-}
+int ENGINE_register_all_complete(void) { return 1; }
 
 void OPENSSL_load_builtin_modules(void) {}
 
diff --git a/src/crypto/stack/stack.c b/src/crypto/stack/stack.c
index f6b4412..7aa3218 100644
--- a/src/crypto/stack/stack.c
+++ b/src/crypto/stack/stack.c
@@ -223,7 +223,7 @@
   return NULL;
 }
 
-int sk_find(_STACK *sk, size_t *out_index, void *p) {
+int sk_find(const _STACK *sk, size_t *out_index, void *p) {
   if (sk == NULL) {
     return 0;
   }
@@ -245,7 +245,17 @@
     return 0;
   }
 
-  sk_sort(sk);
+  if (!sk_is_sorted(sk)) {
+    for (size_t i = 0; i < sk->num; i++) {
+      if (sk->comp((const void **)&p, (const void **)&sk->data[i]) == 0) {
+        if (out_index) {
+          *out_index = i;
+        }
+        return 1;
+      }
+    }
+    return 0;
+  }
 
   // sk->comp is a function that takes pointers to pointers to elements, but
   // qsort and bsearch take a comparison function that just takes pointers to
diff --git a/src/crypto/x509/by_dir.c b/src/crypto/x509/by_dir.c
index 635b851..b3bfffe 100644
--- a/src/crypto/x509/by_dir.c
+++ b/src/crypto/x509/by_dir.c
@@ -387,6 +387,7 @@
              */
             CRYPTO_MUTEX_lock_write(&xl->store_ctx->objs_lock);
             tmp = NULL;
+            sk_X509_OBJECT_sort(xl->store_ctx->objs);
             if (sk_X509_OBJECT_find(xl->store_ctx->objs, &idx, &stmp)) {
                 tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, idx);
             }
@@ -404,6 +405,7 @@
                  */
                 if (!hent) {
                     htmp.hash = h;
+                    sk_BY_DIR_HASH_sort(ent->hashes);
                     if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp))
                         hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
                 }
@@ -422,6 +424,7 @@
                         ok = 0;
                         goto finish;
                     }
+                    sk_BY_DIR_HASH_sort(ent->hashes);
                 } else if (hent->suffix < k)
                     hent->suffix = k;
 
diff --git a/src/crypto/x509/x509_lu.c b/src/crypto/x509/x509_lu.c
index 1a841db..ea01427 100644
--- a/src/crypto/x509/x509_lu.c
+++ b/src/crypto/x509/x509_lu.c
@@ -473,6 +473,7 @@
     }
 
     size_t idx;
+    sk_X509_OBJECT_sort(h);
     if (!sk_X509_OBJECT_find(h, &idx, &stmp))
         return -1;
 
@@ -604,6 +605,7 @@
     size_t idx, i;
     X509_OBJECT *obj;
 
+    sk_X509_OBJECT_sort(h);
     if (!sk_X509_OBJECT_find(h, &idx, x)) {
         return NULL;
     }
diff --git a/src/crypto/x509/x509_trs.c b/src/crypto/x509/x509_trs.c
index c7dfcad..f899424 100644
--- a/src/crypto/x509/x509_trs.c
+++ b/src/crypto/x509/x509_trs.c
@@ -158,6 +158,7 @@
     tmp.trust = id;
     if (!trtable)
         return -1;
+    sk_X509_TRUST_sort(trtable);
     if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) {
         return -1;
     }
diff --git a/src/crypto/x509/x509_vpm.c b/src/crypto/x509/x509_vpm.c
index 43353c6..84ec838 100644
--- a/src/crypto/x509/x509_vpm.c
+++ b/src/crypto/x509/x509_vpm.c
@@ -614,6 +614,7 @@
     } else {
         size_t idx;
 
+        sk_X509_VERIFY_PARAM_sort(param_table);
         if (sk_X509_VERIFY_PARAM_find(param_table, &idx, param)) {
             ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx);
             X509_VERIFY_PARAM_free(ptmp);
@@ -649,6 +650,7 @@
     pm.name = (char *)name;
     if (param_table) {
         size_t idx;
+        sk_X509_VERIFY_PARAM_sort(param_table);
         if (sk_X509_VERIFY_PARAM_find(param_table, &idx, &pm))
             return sk_X509_VERIFY_PARAM_value(param_table, idx);
     }
diff --git a/src/crypto/x509v3/pcy_cache.c b/src/crypto/x509v3/pcy_cache.c
index b8a4be2..755c079 100644
--- a/src/crypto/x509v3/pcy_cache.c
+++ b/src/crypto/x509v3/pcy_cache.c
@@ -93,6 +93,7 @@
         /*
          * Duplicate policy OIDs are illegal: reject if matches found.
          */
+        sk_X509_POLICY_DATA_sort(cache->data);
         if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
             if (cache->anyPolicy) {
                 ret = -1;
@@ -262,6 +263,7 @@
     X509_POLICY_DATA tmp;
 
     tmp.valid_policy = (ASN1_OBJECT *)id;
+    sk_X509_POLICY_DATA_sort(cache->data);
     if (!sk_X509_POLICY_DATA_find(cache->data, &idx, &tmp))
         return NULL;
     return sk_X509_POLICY_DATA_value(cache->data, idx);
diff --git a/src/crypto/x509v3/pcy_node.c b/src/crypto/x509v3/pcy_node.c
index b3edfe4..6682282 100644
--- a/src/crypto/x509v3/pcy_node.c
+++ b/src/crypto/x509v3/pcy_node.c
@@ -83,6 +83,7 @@
     n.valid_policy = (ASN1_OBJECT *)id;
     l.data = &n;
 
+    sk_X509_POLICY_NODE_sort(nodes);
     if (!sk_X509_POLICY_NODE_find(nodes, &idx, &l))
         return NULL;
 
diff --git a/src/crypto/x509v3/pcy_tree.c b/src/crypto/x509v3/pcy_tree.c
index 256fe88..136b45f 100644
--- a/src/crypto/x509v3/pcy_tree.c
+++ b/src/crypto/x509v3/pcy_tree.c
@@ -543,9 +543,11 @@
         *pnodes = policy_node_cmp_new();
         if (!*pnodes)
             return 0;
-    } else if (sk_X509_POLICY_NODE_find(*pnodes, NULL, pcy))
+    } else {
+      sk_X509_POLICY_NODE_sort(*pnodes);
+      if (sk_X509_POLICY_NODE_find(*pnodes, NULL, pcy))
         return 1;
-
+    }
     if (!sk_X509_POLICY_NODE_push(*pnodes, pcy))
         return 0;
 
diff --git a/src/crypto/x509v3/v3_lib.c b/src/crypto/x509v3/v3_lib.c
index 8f5435d..d5eda3d 100644
--- a/src/crypto/x509v3/v3_lib.c
+++ b/src/crypto/x509v3/v3_lib.c
@@ -116,6 +116,7 @@
     if (!ext_list)
         return NULL;
 
+    sk_X509V3_EXT_METHOD_sort(ext_list);
     if (!sk_X509V3_EXT_METHOD_find(ext_list, &idx, &tmp))
         return NULL;
     return sk_X509V3_EXT_METHOD_value(ext_list, idx);
diff --git a/src/crypto/x509v3/v3_purp.c b/src/crypto/x509v3/v3_purp.c
index 324de85..f70a804 100644
--- a/src/crypto/x509v3/v3_purp.c
+++ b/src/crypto/x509v3/v3_purp.c
@@ -205,6 +205,7 @@
     if (!xptable)
         return -1;
 
+    sk_X509_PURPOSE_sort(xptable);
     if (!sk_X509_PURPOSE_find(xptable, &idx, &tmp))
         return -1;
     return idx + X509_PURPOSE_COUNT;
diff --git a/src/crypto/x509v3/v3_utl.c b/src/crypto/x509v3/v3_utl.c
index 7d109ee..589e296 100644
--- a/src/crypto/x509v3/v3_utl.c
+++ b/src/crypto/x509v3/v3_utl.c
@@ -650,6 +650,7 @@
     if (!*sk)
         return 0;
     /* Don't add duplicates */
+    sk_OPENSSL_STRING_sort(*sk);
     if (sk_OPENSSL_STRING_find(*sk, NULL, (char *)email->data))
         return 1;
     emtmp = BUF_strdup((char *)email->data);
diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h
index bd41d11..e2d15fa 100644
--- a/src/include/openssl/base.h
+++ b/src/include/openssl/base.h
@@ -155,7 +155,7 @@
 // A consumer may use this symbol in the preprocessor to temporarily build
 // against multiple revisions of BoringSSL at the same time. It is not
 // recommended to do so for longer than is necessary.
-#define BORINGSSL_API_VERSION 7
+#define BORINGSSL_API_VERSION 8
 
 #if defined(BORINGSSL_SHARED_LIBRARY)
 
diff --git a/src/include/openssl/crypto.h b/src/include/openssl/crypto.h
index ccf5012..cc6fc3c 100644
--- a/src/include/openssl/crypto.h
+++ b/src/include/openssl/crypto.h
@@ -92,6 +92,9 @@
 // CRYPTO_malloc_init returns one.
 OPENSSL_EXPORT int CRYPTO_malloc_init(void);
 
+// OPENSSL_malloc_init returns one.
+OPENSSL_EXPORT int OPENSSL_malloc_init(void);
+
 // ENGINE_load_builtin_engines does nothing.
 OPENSSL_EXPORT void ENGINE_load_builtin_engines(void);
 
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index d22d396..2922473 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -1749,6 +1749,15 @@
 OPENSSL_EXPORT uint32_t
 SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session);
 
+// SSL_SESSION_get0_cipher returns the cipher negotiated by the connection which
+// established |session|.
+//
+// Note that, in TLS 1.3, there is no guarantee that resumptions with |session|
+// will use that cipher. Prefer calling |SSL_get_current_cipher| on the |SSL|
+// instead.
+OPENSSL_EXPORT const SSL_CIPHER *SSL_SESSION_get0_cipher(
+    const SSL_SESSION *session);
+
 
 // Session caching.
 //
diff --git a/src/include/openssl/stack.h b/src/include/openssl/stack.h
index 625f66e..6975db6 100644
--- a/src/include/openssl/stack.h
+++ b/src/include/openssl/stack.h
@@ -163,12 +163,17 @@
 OPENSSL_EXPORT void *sk_delete_ptr(_STACK *sk, void *p);
 
 // sk_find returns the first value in the stack equal to |p|. If a comparison
-// function has been set on the stack, then equality is defined by it and the
-// stack will be sorted if need be so that a binary search can be used.
-// Otherwise pointer equality is used. If a matching element is found, its
-// index is written to |*out_index| (if |out_index| is not NULL) and one is
-// returned. Otherwise zero is returned.
-OPENSSL_EXPORT int sk_find(_STACK *sk, size_t *out_index, void *p);
+// function has been set on the stack, equality is defined by it, otherwise
+// pointer equality is used. If the stack is sorted, then a binary search is
+// used, otherwise a linear search is performed. If a matching element is found,
+// its index is written to
+// |*out_index| (if |out_index| is not NULL) and one is returned. Otherwise zero
+// is returned.
+//
+// Note this differs from OpenSSL. The type signature is slightly different, and
+// OpenSSL's sk_find will implicitly sort |sk| if it has a comparison function
+// defined.
+OPENSSL_EXPORT int sk_find(const _STACK *sk, size_t *out_index, void *p);
 
 // sk_shift removes and returns the first element in the stack, or returns NULL
 // if the stack is empty.
@@ -302,8 +307,8 @@
   }                                                                            \
                                                                                \
   static inline OPENSSL_UNUSED int sk_##name##_find(                           \
-      STACK_OF(name) *sk, size_t *out_index, ptrtype p) {                      \
-    return sk_find((_STACK *)sk, out_index, (void *)p);                        \
+      const STACK_OF(name) *sk, size_t *out_index, ptrtype p) {                \
+    return sk_find((const _STACK *)sk, out_index, (void *)p);                  \
   }                                                                            \
                                                                                \
   static inline OPENSSL_UNUSED ptrtype sk_##name##_shift(STACK_OF(name) *sk) { \
diff --git a/src/ssl/dtls_record.cc b/src/ssl/dtls_record.cc
index 5e795fa..d348601 100644
--- a/src/ssl/dtls_record.cc
+++ b/src/ssl/dtls_record.cc
@@ -219,8 +219,8 @@
     return ssl_open_record_discard;
   }
 
-  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER,
-                      in.subspan(0, DTLS1_RT_HEADER_LENGTH));
+  Span<const uint8_t> header = in.subspan(0, DTLS1_RT_HEADER_LENGTH);
+  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, header);
 
   uint16_t epoch = (((uint16_t)sequence[0]) << 8) | sequence[1];
   if (epoch != ssl->d1->r_epoch ||
@@ -235,7 +235,7 @@
 
   // discard the body in-place.
   if (!ssl->s3->aead_read_ctx->Open(
-          out, type, version, sequence,
+          out, type, version, sequence, header,
           MakeSpan(const_cast<uint8_t *>(CBS_data(&body)), CBS_len(&body)))) {
     // Bad packets are silently dropped in DTLS. See section 4.2.1 of RFC 6347.
     // Clear the error queue of any errors decryption may have added. Drop the
@@ -328,25 +328,25 @@
   OPENSSL_memcpy(&out[5], &seq[2], 6);
 
   size_t ciphertext_len;
-  if (!aead->Seal(out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len,
-                  max_out - DTLS1_RT_HEADER_LENGTH, type, record_version,
-                  &out[3] /* seq */, in, in_len) ||
-      !ssl_record_sequence_update(&seq[2], 6)) {
-    return 0;
-  }
-
-  if (ciphertext_len >= 1 << 16) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+  if (!aead->CiphertextLen(&ciphertext_len, in_len, 0)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
     return 0;
   }
   out[11] = ciphertext_len >> 8;
   out[12] = ciphertext_len & 0xff;
+  Span<const uint8_t> header = MakeConstSpan(out, DTLS1_RT_HEADER_LENGTH);
+
+  size_t len_copy;
+  if (!aead->Seal(out + DTLS1_RT_HEADER_LENGTH, &len_copy,
+                  max_out - DTLS1_RT_HEADER_LENGTH, type, record_version,
+                  &out[3] /* seq */, header, in, in_len) ||
+      !ssl_record_sequence_update(&seq[2], 6)) {
+    return 0;
+  }
+  assert(ciphertext_len == len_copy);
 
   *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len;
-
-  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER,
-                      MakeSpan(out, DTLS1_RT_HEADER_LENGTH));
-
+  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, header);
   return 1;
 }
 
diff --git a/src/ssl/handoff.cc b/src/ssl/handoff.cc
index dd73c83..2cbbaeb 100644
--- a/src/ssl/handoff.cc
+++ b/src/ssl/handoff.cc
@@ -133,10 +133,6 @@
       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) ||
-      !CBB_add_asn1_uint64(&seq, ssl->conf_max_version) ||
-      !CBB_add_asn1_uint64(&seq, ssl->conf_min_version) ||
-      !CBB_add_asn1_uint64(&seq, ssl->max_send_fragment) ||
       !CBB_add_asn1_octet_string(&seq, s3->read_sequence,
                                  sizeof(s3->read_sequence)) ||
       !CBB_add_asn1_octet_string(&seq, s3->write_sequence,
@@ -148,7 +144,6 @@
       !CBB_add_asn1_octet_string(&seq, read_iv, iv_len) ||
       !CBB_add_asn1_octet_string(&seq, write_iv, iv_len) ||
       !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(session, &seq) ||
       !CBB_add_asn1_octet_string(&seq, s3->next_proto_negotiated.data(),
@@ -160,14 +155,8 @@
           hostname_len) ||
       !CBB_add_asn1_octet_string(&seq, s3->tlsext_channel_id,
                                  sizeof(s3->tlsext_channel_id)) ||
-      !CBB_add_asn1_uint64(&seq, ssl->options) ||
-      !CBB_add_asn1_uint64(&seq, ssl->mode) ||
-      !CBB_add_asn1_uint64(&seq, ssl->max_cert_list) ||
-      !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_add_asn1_bool(&seq, ssl->token_binding_negotiated) ||
-      !CBB_add_asn1_uint64(&seq, ssl->negotiated_token_binding_param) ||
+      !CBB_add_asn1_bool(&seq, ssl->s3->token_binding_negotiated) ||
+      !CBB_add_asn1_uint64(&seq, ssl->s3->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) ||
@@ -191,16 +180,12 @@
   }
 
   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,
-      negotiated_token_binding_param, cipher;
+  uint64_t handback_version, 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, 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;
+  int session_reused, channel_id_valid, cert_request, extended_master_secret,
+      ticket_expected, token_binding_negotiated, next_proto_neg_seen;
   SSL_SESSION *session = nullptr;
 
   CBS handback_cbs(handback);
@@ -210,11 +195,7 @@
     return false;
   }
 
-  if (!CBS_get_asn1_uint64(&seq, &version) ||
-      !CBS_get_asn1_uint64(&seq, &conf_max_version) ||
-      !CBS_get_asn1_uint64(&seq, &conf_min_version) ||
-      !CBS_get_asn1_uint64(&seq, &max_send_fragment) ||
-      !CBS_get_asn1(&seq, &read_seq, CBS_ASN1_OCTETSTRING) ||
+  if (!CBS_get_asn1(&seq, &read_seq, CBS_ASN1_OCTETSTRING) ||
       CBS_len(&read_seq) != sizeof(s3->read_sequence) ||
       !CBS_get_asn1(&seq, &write_seq, CBS_ASN1_OCTETSTRING) ||
       CBS_len(&write_seq) != sizeof(s3->write_sequence) ||
@@ -229,7 +210,6 @@
       !CBS_get_asn1(&seq, &read_iv, CBS_ASN1_OCTETSTRING) ||
       !CBS_get_asn1(&seq, &write_iv, CBS_ASN1_OCTETSTRING) ||
       !CBS_get_asn1_bool(&seq, &session_reused) ||
-      !CBS_get_asn1_bool(&seq, &send_connection_binding) ||
       !CBS_get_asn1_bool(&seq, &channel_id_valid)) {
     return false;
   }
@@ -253,12 +233,6 @@
       CBS_len(&channel_id) != sizeof(s3->tlsext_channel_id) ||
       !CBS_copy_bytes(&channel_id, s3->tlsext_channel_id,
                       sizeof(s3->tlsext_channel_id)) ||
-      !CBS_get_asn1_uint64(&seq, &options) ||
-      !CBS_get_asn1_uint64(&seq, &mode) ||
-      !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, &token_binding_negotiated) ||
       !CBS_get_asn1_uint64(&seq, &negotiated_token_binding_param) ||
       !CBS_get_asn1_bool(&seq, &next_proto_neg_seen) ||
@@ -277,21 +251,14 @@
     return false;
   }
 
-  ssl->version = version;
-  ssl->conf_max_version = conf_max_version;
-  ssl->conf_min_version = conf_min_version;
-  ssl->max_send_fragment = max_send_fragment;
+  ssl->version = session->ssl_version;
   ssl->do_handshake = ssl_server_handshake;
   ssl->server = true;
-  ssl->options = options;
-  ssl->mode = mode;
-  ssl->max_cert_list = max_cert_list;
 
   s3->have_version = 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;
   s3->next_proto_negotiated.CopyFrom(next_proto);
   s3->alpn_selected.CopyFrom(alpn);
@@ -307,11 +274,8 @@
     s3->hostname.reset(hostname_str);
   }
 
-  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 =
+  s3->token_binding_negotiated = token_binding_negotiated;
+  s3->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;
diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc
index 0b352c2..087645d 100644
--- a/src/ssl/handshake_client.cc
+++ b/src/ssl/handshake_client.cc
@@ -740,7 +740,7 @@
     return ssl_hs_error;
   }
 
-  if (ssl->token_binding_negotiated &&
+  if (ssl->s3->token_binding_negotiated &&
       (!hs->extended_master_secret || !ssl->s3->send_connection_binding)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_TB_WITHOUT_EMS_OR_RI);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index 5f2f41f..7ade8fc 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -334,7 +334,7 @@
     SSL_HANDSHAKE *hs, const SSL_CLIENT_HELLO *client_hello,
     const struct ssl_cipher_preference_list_st *server_pref) {
   SSL *const ssl = hs->ssl;
-  STACK_OF(SSL_CIPHER) *prio, *allow;
+  const STACK_OF(SSL_CIPHER) *prio, *allow;
   // in_group_flags will either be NULL, or will point to an array of bytes
   // which indicate equal-preference groups in the |prio| stack. See the
   // comment about |in_group_flags| in the |ssl_cipher_preference_list_st|
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index e884b63..f4dc96f 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -657,19 +657,26 @@
   bool SuffixLen(size_t *out_suffix_len, size_t in_len,
                  size_t extra_in_len) const;
 
+  // CiphertextLen calculates the total ciphertext length written by
+  // |SealScatter| and writes it to |*out_len|. It returns true on success and
+  // false on error. |in_len| and |extra_in_len| should equal the argument of
+  // the same names passed to |SealScatter|.
+  bool CiphertextLen(size_t *out_len, size_t in_len, size_t extra_in_len) const;
+
   // Open authenticates and decrypts |in| in-place. On success, it sets |*out|
   // to the plaintext in |in| and returns true.  Otherwise, it returns
   // false. The output will always be |ExplicitNonceLen| bytes ahead of |in|.
   bool Open(Span<uint8_t> *out, uint8_t type, uint16_t record_version,
-            const uint8_t seqnum[8], Span<uint8_t> in);
+            const uint8_t seqnum[8], Span<const uint8_t> header,
+            Span<uint8_t> in);
 
   // Seal encrypts and authenticates |in_len| bytes from |in| and writes the
   // result to |out|. It returns true on success and false on error.
   //
   // If |in| and |out| alias then |out| + |ExplicitNonceLen| must be == |in|.
   bool Seal(uint8_t *out, size_t *out_len, size_t max_out, uint8_t type,
-            uint16_t record_version, const uint8_t seqnum[8], const uint8_t *in,
-            size_t in_len);
+            uint16_t record_version, const uint8_t seqnum[8],
+            Span<const uint8_t> header, const uint8_t *in, size_t in_len);
 
   // SealScatter encrypts and authenticates |in_len| bytes from |in| and splits
   // the result between |out_prefix|, |out| and |out_suffix|. It returns one on
@@ -688,17 +695,20 @@
   // alias anything.
   bool SealScatter(uint8_t *out_prefix, uint8_t *out, uint8_t *out_suffix,
                    uint8_t type, uint16_t record_version,
-                   const uint8_t seqnum[8], const uint8_t *in, size_t in_len,
-                   const uint8_t *extra_in, size_t extra_in_len);
+                   const uint8_t seqnum[8], Span<const uint8_t> header,
+                   const uint8_t *in, size_t in_len, const uint8_t *extra_in,
+                   size_t extra_in_len);
 
   bool GetIV(const uint8_t **out_iv, size_t *out_iv_len) const;
 
  private:
-  // GetAdditionalData writes the additional data into |out| and returns the
-  // 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 ciphertext_len);
+  // GetAdditionalData returns the additional data, writing into |storage| if
+  // necessary.
+  Span<const uint8_t> GetAdditionalData(uint8_t storage[13], uint8_t type,
+                                        uint16_t record_version,
+                                        const uint8_t seqnum[8],
+                                        size_t plaintext_len,
+                                        Span<const uint8_t> header);
 
   const SSL_CIPHER *cipher_;
   ScopedEVP_AEAD_CTX ctx_;
@@ -717,6 +727,9 @@
   // randomly generated, rather than derived from the sequence
   // number.
   bool random_variable_nonce_ : 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;
   // omit_length_in_ad_ is true if the length should be omitted in the
   // AEAD's ad parameter.
   bool omit_length_in_ad_ : 1;
@@ -725,12 +738,8 @@
   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;
+  // ad_is_header_ is true if the AEAD's ad parameter is the record header.
+  bool ad_is_header_ : 1;
 };
 
 
@@ -2299,6 +2308,10 @@
   // key_update_count is the number of consecutive KeyUpdates received.
   uint8_t key_update_count = 0;
 
+  // The negotiated Token Binding key parameter. Only valid if
+  // |token_binding_negotiated| is set.
+  uint8_t negotiated_token_binding_param = 0;
+
   // skip_early_data instructs the record layer to skip unexpected early data
   // messages when 0RTT is rejected.
   bool skip_early_data:1;
@@ -2348,6 +2361,9 @@
   // fired, were it not a draft.
   bool draft_downgrade:1;
 
+  // token_binding_negotiated is set if Token Binding was negotiated.
+  bool token_binding_negotiated:1;
+
   // hs_buf is the buffer of handshake data to process.
   UniquePtr<BUF_MEM> hs_buf;
 
@@ -2671,10 +2687,6 @@
   uint8_t *token_binding_params;
   size_t token_binding_params_len;
 
-  // The negotiated Token Binding key parameter. Only valid if
-  // |token_binding_negotiated| is set.
-  uint8_t negotiated_token_binding_param;
-
   // Contains the QUIC transport params that this endpoint will send.
   uint8_t *quic_transport_params;
   size_t quic_transport_params_len;
@@ -2706,9 +2718,6 @@
   // we'll advertise support.
   bool tlsext_channel_id_enabled:1;
 
-  // token_binding_negotiated is set if Token Binding was negotiated.
-  bool token_binding_negotiated:1;
-
   // retain_only_sha256_of_client_certs is true if we should compute the SHA256
   // hash of the peer's certificate and then discard it to save memory and
   // session space. Only effective on the server side.
diff --git a/src/ssl/s3_lib.cc b/src/ssl/s3_lib.cc
index a3fc8d7..baa5a17 100644
--- a/src/ssl/s3_lib.cc
+++ b/src/ssl/s3_lib.cc
@@ -177,7 +177,8 @@
       key_update_pending(false),
       wpend_pending(false),
       early_data_accepted(false),
-      draft_downgrade(false) {}
+      draft_downgrade(false),
+      token_binding_negotiated(false) {}
 
 SSL3_STATE::~SSL3_STATE() {}
 
diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc
index e6b3ee9..363c959 100644
--- a/src/ssl/ssl_aead_ctx.cc
+++ b/src/ssl/ssl_aead_ctx.cc
@@ -40,11 +40,11 @@
       is_dtls_(is_dtls_arg),
       variable_nonce_included_in_record_(false),
       random_variable_nonce_(false),
+      xor_fixed_nonce_(false),
       omit_length_in_ad_(false),
       omit_version_in_ad_(false),
       omit_ad_(false),
-      tls13_ad_(false),
-      xor_fixed_nonce_(false) {
+      ad_is_header_(false) {
   OPENSSL_memset(fixed_nonce_, 0, sizeof(fixed_nonce_));
 }
 
@@ -136,7 +136,7 @@
       aead_ctx->variable_nonce_len_ = 8;
       aead_ctx->variable_nonce_included_in_record_ = false;
       if (ssl_is_draft28(version)) {
-        aead_ctx->tls13_ad_ = true;
+        aead_ctx->ad_is_header_ = true;
       } else {
         aead_ctx->omit_ad_ = true;
       }
@@ -198,6 +198,22 @@
                                 extra_in_len);
 }
 
+bool SSLAEADContext::CiphertextLen(size_t *out_len, const size_t in_len,
+                                   const size_t extra_in_len) const {
+  size_t len;
+  if (!SuffixLen(&len, in_len, extra_in_len)) {
+    return false;
+  }
+  len += ExplicitNonceLen();
+  len += in_len;
+  if (len < in_len || len >= 0xffff) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+    return false;
+  }
+  *out_len = len;
+  return true;
+}
+
 size_t SSLAEADContext::MaxOverhead() const {
   return ExplicitNonceLen() +
          (is_null_cipher() || FUZZER_MODE
@@ -205,38 +221,34 @@
               : EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(ctx_.get())));
 }
 
-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 ciphertext_len) {
-  if (omit_ad_) {
-    return 0;
+Span<const uint8_t> SSLAEADContext::GetAdditionalData(
+    uint8_t storage[13], uint8_t type, uint16_t record_version,
+    const uint8_t seqnum[8], size_t plaintext_len, Span<const uint8_t> header) {
+  if (ad_is_header_) {
+    return header;
   }
 
-  size_t len = 0;
-  if (!tls13_ad_) {
-    OPENSSL_memcpy(out, seqnum, 8);
-    len += 8;
+  if (omit_ad_) {
+    return {};
   }
-  out[len++] = type;
+
+  OPENSSL_memcpy(storage, seqnum, 8);
+  size_t len = 8;
+  storage[len++] = type;
   if (!omit_version_in_ad_) {
-    out[len++] = static_cast<uint8_t>((record_version >> 8));
-    out[len++] = static_cast<uint8_t>(record_version);
+    storage[len++] = static_cast<uint8_t>((record_version >> 8));
+    storage[len++] = static_cast<uint8_t>(record_version);
   }
-  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);
+  if (!omit_length_in_ad_) {
+    storage[len++] = static_cast<uint8_t>((plaintext_len >> 8));
+    storage[len++] = static_cast<uint8_t>(plaintext_len);
   }
-  return len;
+  return MakeConstSpan(storage, len);
 }
 
 bool SSLAEADContext::Open(Span<uint8_t> *out, uint8_t type,
                           uint16_t record_version, const uint8_t seqnum[8],
-                          Span<uint8_t> in) {
+                          Span<const uint8_t> header, Span<uint8_t> in) {
   if (is_null_cipher() || FUZZER_MODE) {
     // Handle the initial NULL cipher.
     *out = in;
@@ -255,9 +267,10 @@
     }
     plaintext_len = in.size() - overhead;
   }
-  uint8_t ad[13];
-  size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum,
-                                    plaintext_len, in.size());
+
+  uint8_t ad_storage[13];
+  Span<const uint8_t> ad = GetAdditionalData(ad_storage, type, record_version,
+                                             seqnum, plaintext_len, header);
 
   // Assemble the nonce.
   uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
@@ -298,7 +311,8 @@
   // Decrypt in-place.
   size_t len;
   if (!EVP_AEAD_CTX_open(ctx_.get(), in.data(), &len, in.size(), nonce,
-                         nonce_len, in.data(), in.size(), ad, ad_len)) {
+                         nonce_len, in.data(), in.size(), ad.data(),
+                         ad.size())) {
     return false;
   }
   *out = in.subspan(0, len);
@@ -308,7 +322,8 @@
 bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out,
                                  uint8_t *out_suffix, uint8_t type,
                                  uint16_t record_version,
-                                 const uint8_t seqnum[8], const uint8_t *in,
+                                 const uint8_t seqnum[8],
+                                 Span<const uint8_t> header, const uint8_t *in,
                                  size_t in_len, const uint8_t *extra_in,
                                  size_t extra_in_len) {
   const size_t prefix_len = ExplicitNonceLen();
@@ -331,9 +346,9 @@
     return true;
   }
 
-  uint8_t ad[13];
-  size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum, in_len,
-                                    in_len + suffix_len);
+  uint8_t ad_storage[13];
+  Span<const uint8_t> ad = GetAdditionalData(ad_storage, type, record_version,
+                                             seqnum, in_len, header);
 
   // Assemble the nonce.
   uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
@@ -384,15 +399,15 @@
   size_t written_suffix_len;
   bool result = !!EVP_AEAD_CTX_seal_scatter(
       ctx_.get(), out, out_suffix, &written_suffix_len, suffix_len, nonce,
-      nonce_len, in, in_len, extra_in, extra_in_len, ad, ad_len);
+      nonce_len, in, in_len, extra_in, extra_in_len, ad.data(), ad.size());
   assert(!result || written_suffix_len == suffix_len);
   return result;
 }
 
 bool SSLAEADContext::Seal(uint8_t *out, size_t *out_len, size_t max_out_len,
                           uint8_t type, uint16_t record_version,
-                          const uint8_t seqnum[8], const uint8_t *in,
-                          size_t in_len) {
+                          const uint8_t seqnum[8], Span<const uint8_t> header,
+                          const uint8_t *in, size_t in_len) {
   const size_t prefix_len = ExplicitNonceLen();
   size_t suffix_len;
   if (!SuffixLen(&suffix_len, in_len, 0)) {
@@ -410,7 +425,7 @@
   }
 
   if (!SealScatter(out, out + prefix_len, out + prefix_len + in_len, type,
-                   record_version, seqnum, in, in_len, 0, 0)) {
+                   record_version, seqnum, header, in, in_len, 0, 0)) {
     return false;
   }
   *out_len = prefix_len + in_len + suffix_len;
diff --git a/src/ssl/ssl_file.cc b/src/ssl/ssl_file.cc
index bafa64a..ca4b0be 100644
--- a/src/ssl/ssl_file.cc
+++ b/src/ssl/ssl_file.cc
@@ -165,6 +165,7 @@
     }
 
     // Check for duplicates.
+    sk_X509_NAME_sort(sk);
     if (sk_X509_NAME_find(sk, NULL, xn)) {
       continue;
     }
@@ -223,6 +224,7 @@
     }
 
     // Check for duplicates.
+    sk_X509_NAME_sort(stack);
     if (sk_X509_NAME_find(stack, NULL, xn)) {
       continue;
     }
diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc
index 2a076c3..c7f6f88 100644
--- a/src/ssl/ssl_key_share.cc
+++ b/src/ssl/ssl_key_share.cc
@@ -248,11 +248,11 @@
 
 UniquePtr<SSLKeyShare> SSLKeyShare::Create(CBS *in) {
   uint64_t group;
-  if (!CBS_get_asn1_uint64(in, &group)) {
+  if (!CBS_get_asn1_uint64(in, &group) || group > 0xffff) {
     return nullptr;
   }
-  UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint64_t>(group));
-  if (!key_share->Deserialize(in)) {
+  UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint16_t>(group));
+  if (!key_share || !key_share->Deserialize(in)) {
     return nullptr;
   }
   return key_share;
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index 6312504..14fb0ff 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -2164,11 +2164,11 @@
 }
 
 int SSL_is_token_binding_negotiated(const SSL *ssl) {
-  return ssl->token_binding_negotiated;
+  return ssl->s3->token_binding_negotiated;
 }
 
 uint8_t SSL_get_negotiated_token_binding_param(const SSL *ssl) {
-  return ssl->negotiated_token_binding_param;
+  return ssl->s3->negotiated_token_binding_param;
 }
 
 size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) {
diff --git a/src/ssl/ssl_session.cc b/src/ssl/ssl_session.cc
index 34e7b31..bc2c14c 100644
--- a/src/ssl/ssl_session.cc
+++ b/src/ssl/ssl_session.cc
@@ -990,6 +990,10 @@
   return session->tlsext_tick_lifetime_hint;
 }
 
+const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *session) {
+  return session->cipher;
+}
+
 SSL_SESSION *SSL_magic_pending_session_ptr(void) {
   return (SSL_SESSION *)&g_pending_session_magic;
 }
diff --git a/src/ssl/t1_lib.cc b/src/ssl/t1_lib.cc
index 97c0c4b..2d3a664 100644
--- a/src/ssl/t1_lib.cc
+++ b/src/ssl/t1_lib.cc
@@ -2528,8 +2528,8 @@
 
   for (size_t i = 0; i < ssl->token_binding_params_len; ++i) {
     if (param == ssl->token_binding_params[i]) {
-      ssl->negotiated_token_binding_param = param;
-      ssl->token_binding_negotiated = true;
+      ssl->s3->negotiated_token_binding_param = param;
+      ssl->s3->token_binding_negotiated = true;
       return true;
     }
   }
@@ -2547,7 +2547,7 @@
     uint8_t tb_param = ssl->token_binding_params[i];
     for (uint8_t peer_param : peer_params) {
       if (tb_param == peer_param) {
-        ssl->negotiated_token_binding_param = tb_param;
+        ssl->s3->negotiated_token_binding_param = tb_param;
         return true;
       }
     }
@@ -2587,14 +2587,14 @@
     return true;
   }
 
-  ssl->token_binding_negotiated = true;
+  ssl->s3->token_binding_negotiated = true;
   return true;
 }
 
 static bool ext_token_binding_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
   SSL *const ssl = hs->ssl;
 
-  if (!ssl->token_binding_negotiated) {
+  if (!ssl->s3->token_binding_negotiated) {
     return true;
   }
 
@@ -2603,7 +2603,7 @@
       !CBB_add_u16_length_prefixed(out, &contents) ||
       !CBB_add_u16(&contents, hs->negotiated_token_binding_version) ||
       !CBB_add_u8_length_prefixed(&contents, &params) ||
-      !CBB_add_u8(&params, ssl->negotiated_token_binding_param) ||
+      !CBB_add_u8(&params, ssl->s3->negotiated_token_binding_param) ||
       !CBB_flush(out)) {
     return false;
   }
@@ -3220,7 +3220,7 @@
 static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
-  if (ssl->token_binding_negotiated &&
+  if (ssl->s3->token_binding_negotiated &&
       !(SSL_get_secure_renegotiation_support(ssl) &&
         SSL_get_extms_support(ssl))) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_TB_WITHOUT_EMS_OR_RI);
diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc
index aa05456..6e328b8 100644
--- a/src/ssl/tls13_client.cc
+++ b/src/ssl/tls13_client.cc
@@ -436,7 +436,7 @@
       return ssl_hs_error;
     }
     if (ssl->s3->tlsext_channel_id_valid || hs->received_custom_extension ||
-        ssl->token_binding_negotiated) {
+        ssl->s3->token_binding_negotiated) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION_ON_EARLY_DATA);
       return ssl_hs_error;
     }
diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc
index 3bd6786..9d7f5e0 100644
--- a/src/ssl/tls13_server.cc
+++ b/src/ssl/tls13_server.cc
@@ -391,7 +391,7 @@
           // Channel ID is incompatible with 0-RTT.
           !ssl->s3->tlsext_channel_id_valid &&
           // If Token Binding is negotiated, reject 0-RTT.
-          !ssl->token_binding_negotiated &&
+          !ssl->s3->token_binding_negotiated &&
           // Custom extensions is incompatible with 0-RTT.
           hs->custom_extensions.received == 0 &&
           // The negotiated ALPN must match the one in the ticket.
diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc
index 3152e7a..a2e4a20 100644
--- a/src/ssl/tls_record.cc
+++ b/src/ssl/tls_record.cc
@@ -258,8 +258,8 @@
     return ssl_open_record_partial;
   }
 
-  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER,
-                      in.subspan(0, SSL3_RT_HEADER_LENGTH));
+  Span<const uint8_t> header = in.subspan(0, SSL3_RT_HEADER_LENGTH);
+  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, header);
 
   *out_consumed = in.size() - CBS_len(&cbs);
 
@@ -288,7 +288,7 @@
 
   // Decrypt the body in-place.
   if (!ssl->s3->aead_read_ctx->Open(
-          out, type, version, ssl->s3->read_sequence,
+          out, type, version, ssl->s3->read_sequence, header,
           MakeSpan(const_cast<uint8_t *>(CBS_data(&body)), CBS_len(&body)))) {
     if (ssl->s3->skip_early_data && !ssl->s3->aead_read_ctx->is_null_cipher()) {
       ERR_clear_error();
@@ -376,27 +376,22 @@
 static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
                           uint8_t *out_suffix, uint8_t type, const uint8_t *in,
                           const size_t in_len) {
+  SSLAEADContext *aead = ssl->s3->aead_write_ctx.get();
   uint8_t *extra_in = NULL;
   size_t extra_in_len = 0;
-  if (!ssl->s3->aead_write_ctx->is_null_cipher() &&
-      ssl->s3->aead_write_ctx->ProtocolVersion() >= TLS1_3_VERSION) {
+  if (!aead->is_null_cipher() &&
+      aead->ProtocolVersion() >= TLS1_3_VERSION) {
     // TLS 1.3 hides the actual record type inside the encrypted data.
     extra_in = &type;
     extra_in_len = 1;
   }
 
-  size_t suffix_len;
-  if (!ssl->s3->aead_write_ctx->SuffixLen(&suffix_len, in_len, extra_in_len)) {
+  size_t suffix_len, ciphertext_len;
+  if (!aead->SuffixLen(&suffix_len, in_len, extra_in_len) ||
+      !aead->CiphertextLen(&ciphertext_len, in_len, extra_in_len)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
     return 0;
   }
-  size_t ciphertext_len =
-      ssl->s3->aead_write_ctx->ExplicitNonceLen() + suffix_len;
-  if (ciphertext_len + in_len < ciphertext_len) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
-    return 0;
-  }
-  ciphertext_len += in_len;
 
   assert(in == out || !buffers_alias(in, in_len, out, in_len));
   assert(!buffers_alias(in, in_len, out_prefix, ssl_record_prefix_len(ssl)));
@@ -408,28 +403,27 @@
     out_prefix[0] = type;
   }
 
-  uint16_t record_version = ssl->s3->aead_write_ctx->RecordVersion();
+  uint16_t record_version = aead->RecordVersion();
 
   out_prefix[1] = record_version >> 8;
   out_prefix[2] = record_version & 0xff;
   out_prefix[3] = ciphertext_len >> 8;
   out_prefix[4] = ciphertext_len & 0xff;
+  Span<const uint8_t> header = MakeSpan(out_prefix, SSL3_RT_HEADER_LENGTH);
 
-  if (!ssl->s3->aead_write_ctx->SealScatter(
-          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) ||
+  if (!aead->SealScatter(out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix,
+                         out_prefix[0], record_version, ssl->s3->write_sequence,
+                         header, in, in_len, extra_in, extra_in_len) ||
       !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) {
     return 0;
   }
 
-  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER,
-                      MakeSpan(out_prefix, SSL3_RT_HEADER_LENGTH));
+  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, header);
   return 1;
 }
 
 static size_t tls_seal_scatter_prefix_len(const SSL *ssl, uint8_t type,
-                                   size_t in_len) {
+                                          size_t in_len) {
   size_t ret = SSL3_RT_HEADER_LENGTH;
   if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 &&
       ssl_needs_record_splitting(ssl)) {
diff --git a/src/tool/speed.cc b/src/tool/speed.cc
index d95fa9e..ed3484a 100644
--- a/src/tool/speed.cc
+++ b/src/tool/speed.cc
@@ -142,68 +142,89 @@
   return true;
 }
 
-static bool SpeedRSA(const std::string &key_name, RSA *key,
-                     const std::string &selected) {
-  if (!selected.empty() && key_name.find(selected) == std::string::npos) {
+static bool SpeedRSA(const std::string &selected) {
+  if (!selected.empty() && selected.find("RSA") == std::string::npos) {
     return true;
   }
 
-  std::unique_ptr<uint8_t[]> sig(new uint8_t[RSA_size(key)]);
-  const uint8_t fake_sha256_hash[32] = {0};
-  unsigned sig_len;
+  static const struct {
+    const char *name;
+    const uint8_t *key;
+    const size_t key_len;
+  } kRSAKeys[] = {
+    {"RSA 2048", kDERRSAPrivate2048, kDERRSAPrivate2048Len},
+    {"RSA 4096", kDERRSAPrivate4096, kDERRSAPrivate4096Len},
+  };
 
-  TimeResults results;
-  if (!TimeFunction(&results,
-                    [key, &sig, &fake_sha256_hash, &sig_len]() -> bool {
-        // Usually during RSA signing we're using a long-lived |RSA| that has
-        // already had all of its |BN_MONT_CTX|s constructed, so it makes
-        // sense to use |key| directly here.
-        return RSA_sign(NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
-                        sig.get(), &sig_len, key);
-      })) {
-    fprintf(stderr, "RSA_sign failed.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
-  results.Print(key_name + " signing");
+  for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kRSAKeys); i++) {
+    const std::string name = kRSAKeys[i].name;
 
-  if (!TimeFunction(&results,
-                    [key, &fake_sha256_hash, &sig, sig_len]() -> bool {
-        return RSA_verify(NID_sha256, fake_sha256_hash,
-                          sizeof(fake_sha256_hash), sig.get(), sig_len, key);
-      })) {
-    fprintf(stderr, "RSA_verify failed.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
-  results.Print(key_name + " verify (same key)");
+    bssl::UniquePtr<RSA> key(
+        RSA_private_key_from_bytes(kRSAKeys[i].key, kRSAKeys[i].key_len));
+    if (key == nullptr) {
+      fprintf(stderr, "Failed to parse %s key.\n", name.c_str());
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
 
-  if (!TimeFunction(&results,
-                    [key, &fake_sha256_hash, &sig, sig_len]() -> bool {
-        // Usually during RSA verification we have to parse an RSA key from a
-        // certificate or similar, in which case we'd need to construct a new
-        // RSA key, with a new |BN_MONT_CTX| for the public modulus. If we were
-        // to use |key| directly instead, then these costs wouldn't be
-        // accounted for.
-        bssl::UniquePtr<RSA> verify_key(RSA_new());
-        if (!verify_key) {
-          return false;
-        }
-        verify_key->n = BN_dup(key->n);
-        verify_key->e = BN_dup(key->e);
-        if (!verify_key->n ||
-            !verify_key->e) {
-          return false;
-        }
-        return RSA_verify(NID_sha256, fake_sha256_hash,
-                          sizeof(fake_sha256_hash), sig.get(), sig_len,
-                          verify_key.get());
-      })) {
-    fprintf(stderr, "RSA_verify failed.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
+    std::unique_ptr<uint8_t[]> sig(new uint8_t[RSA_size(key.get())]);
+    const uint8_t fake_sha256_hash[32] = {0};
+    unsigned sig_len;
+
+    TimeResults results;
+    if (!TimeFunction(&results,
+                      [&key, &sig, &fake_sha256_hash, &sig_len]() -> bool {
+          // Usually during RSA signing we're using a long-lived |RSA| that has
+          // already had all of its |BN_MONT_CTX|s constructed, so it makes
+          // sense to use |key| directly here.
+          return RSA_sign(NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
+                          sig.get(), &sig_len, key.get());
+        })) {
+      fprintf(stderr, "RSA_sign failed.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+    results.Print(name + " signing");
+
+    if (!TimeFunction(&results,
+                      [&key, &fake_sha256_hash, &sig, sig_len]() -> bool {
+          return RSA_verify(
+              NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
+              sig.get(), sig_len, key.get());
+        })) {
+      fprintf(stderr, "RSA_verify failed.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+    results.Print(name + " verify (same key)");
+
+    if (!TimeFunction(&results,
+                      [&key, &fake_sha256_hash, &sig, sig_len]() -> bool {
+          // Usually during RSA verification we have to parse an RSA key from a
+          // certificate or similar, in which case we'd need to construct a new
+          // RSA key, with a new |BN_MONT_CTX| for the public modulus. If we
+          // were to use |key| directly instead, then these costs wouldn't be
+          // accounted for.
+          bssl::UniquePtr<RSA> verify_key(RSA_new());
+          if (!verify_key) {
+            return false;
+          }
+          verify_key->n = BN_dup(key->n);
+          verify_key->e = BN_dup(key->e);
+          if (!verify_key->n ||
+              !verify_key->e) {
+            return false;
+          }
+          return RSA_verify(NID_sha256, fake_sha256_hash,
+                            sizeof(fake_sha256_hash), sig.get(), sig_len,
+                            verify_key.get());
+        })) {
+      fprintf(stderr, "RSA_verify failed.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+    results.Print(name + " verify (fresh key)");
   }
-  results.Print(key_name + " verify (fresh key)");
 
   return true;
 }
@@ -381,7 +402,7 @@
 
 static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
                            size_t chunk_len) {
-  EVP_MD_CTX *ctx = EVP_MD_CTX_create();
+  bssl::ScopedEVP_MD_CTX ctx;
   uint8_t scratch[8192];
 
   if (chunk_len > sizeof(scratch)) {
@@ -389,13 +410,13 @@
   }
 
   TimeResults results;
-  if (!TimeFunction(&results, [ctx, md, chunk_len, &scratch]() -> bool {
+  if (!TimeFunction(&results, [&ctx, md, chunk_len, &scratch]() -> bool {
         uint8_t digest[EVP_MAX_MD_SIZE];
         unsigned int md_len;
 
-        return EVP_DigestInit_ex(ctx, md, NULL /* ENGINE */) &&
-               EVP_DigestUpdate(ctx, scratch, chunk_len) &&
-               EVP_DigestFinal_ex(ctx, digest, &md_len);
+        return EVP_DigestInit_ex(ctx.get(), md, NULL /* ENGINE */) &&
+               EVP_DigestUpdate(ctx.get(), scratch, chunk_len) &&
+               EVP_DigestFinal_ex(ctx.get(), digest, &md_len);
       })) {
     fprintf(stderr, "EVP_DigestInit_ex failed.\n");
     ERR_print_errors_fp(stderr);
@@ -403,9 +424,6 @@
   }
 
   results.PrintWithBytes(name, chunk_len);
-
-  EVP_MD_CTX_destroy(ctx);
-
   return true;
 }
 static bool SpeedHash(const EVP_MD *md, const std::string &name,
@@ -745,32 +763,6 @@
     g_timeout_seconds = atoi(args_map["-timeout"].c_str());
   }
 
-  bssl::UniquePtr<RSA> key(
-      RSA_private_key_from_bytes(kDERRSAPrivate2048, kDERRSAPrivate2048Len));
-  if (key == nullptr) {
-    fprintf(stderr, "Failed to parse RSA key.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
-
-  if (!SpeedRSA("RSA 2048", key.get(), selected)) {
-    return false;
-  }
-
-  key.reset(
-      RSA_private_key_from_bytes(kDERRSAPrivate4096, kDERRSAPrivate4096Len));
-  if (key == nullptr) {
-    fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  if (!SpeedRSA("RSA 4096", key.get(), selected)) {
-    return false;
-  }
-
-  key.reset();
-
   // kTLSADLen is the number of bytes of additional data that TLS passes to
   // AEADs.
   static const size_t kTLSADLen = 13;
@@ -780,7 +772,8 @@
   // knowledge in them and construct a couple of the AD bytes internally.
   static const size_t kLegacyADLen = kTLSADLen - 2;
 
-  if (!SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
+  if (!SpeedRSA(selected) ||
+      !SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
       !SpeedAEAD(EVP_aead_aes_256_gcm(), "AES-256-GCM", kTLSADLen, selected) ||
       !SpeedAEAD(EVP_aead_chacha20_poly1305(), "ChaCha20-Poly1305", kTLSADLen,
                  selected) ||
diff --git a/src/util/generate_build_files.py b/src/util/generate_build_files.py
index f2b10de..caed812 100644
--- a/src/util/generate_build_files.py
+++ b/src/util/generate_build_files.py
@@ -294,11 +294,13 @@
       out.write(self.header)
 
       self.PrintVariableSection(out, 'crypto_sources',
-                                files['crypto'] + files['crypto_headers'] +
+                                files['crypto'] +
                                 files['crypto_internal_headers'])
+      self.PrintVariableSection(out, 'crypto_headers',
+                                files['crypto_headers'])
       self.PrintVariableSection(out, 'ssl_sources',
-                                files['ssl'] + files['ssl_headers'] +
-                                files['ssl_internal_headers'])
+                                files['ssl'] + files['ssl_internal_headers'])
+      self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers'])
 
       for ((osname, arch), asm_files) in asm_outputs:
         self.PrintVariableSection(