external/boringssl: Sync to 9c33ae85621ef8e00a42309b5101e0bedd02b816.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/629db8cd0c84628e37aa81242b5b07fec7602f55..9c33ae85621ef8e00a42309b5101e0bedd02b816

Bug: 33622440
Test: BoringSSL tests
Change-Id: I20da15ad995a620b6b2f08db20c77ebd0f05ca10
diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c
index f9bb8f4..d3e4a92 100644
--- a/src/ssl/d1_both.c
+++ b/src/ssl/d1_both.c
@@ -124,6 +124,7 @@
 #include <openssl/rand.h>
 #include <openssl/x509.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -157,7 +158,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
-  memset(frag, 0, sizeof(hm_fragment));
+  OPENSSL_memset(frag, 0, sizeof(hm_fragment));
   frag->type = msg_hdr->type;
   frag->seq = msg_hdr->seq;
   frag->msg_len = msg_hdr->msg_len;
@@ -195,7 +196,7 @@
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    memset(frag->reassembly, 0, bitmask_len);
+    OPENSSL_memset(frag->reassembly, 0, bitmask_len);
   }
 
   return frag;
@@ -383,7 +384,7 @@
     assert(msg_len > 0);
 
     /* Copy the body into the fragment. */
-    memcpy(frag->data + DTLS1_HM_HEADER_LENGTH + frag_off, CBS_data(&body),
+    OPENSSL_memcpy(frag->data + DTLS1_HM_HEADER_LENGTH + frag_off, CBS_data(&body),
            CBS_len(&body));
     dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
   }
@@ -489,7 +490,7 @@
 
 int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
                          CBS *out_body) {
-  memset(out_hdr, 0x00, sizeof(struct hm_header_st));
+  OPENSSL_memset(out_hdr, 0x00, sizeof(struct hm_header_st));
 
   if (!CBS_get_u8(cbs, &out_hdr->type) ||
       !CBS_get_u24(cbs, &out_hdr->msg_len) ||
@@ -747,7 +748,7 @@
 
   /* Fix up the header. Copy the fragment length into the total message
    * length. */
-  memcpy(*out_msg + 1, *out_msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+  OPENSSL_memcpy(*out_msg + 1, *out_msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
   return 1;
 }
 
diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c
index cafb4c2..258e9ab 100644
--- a/src/ssl/d1_lib.c
+++ b/src/ssl/d1_lib.c
@@ -64,9 +64,11 @@
 #include <openssl/mem.h>
 #include <openssl/nid.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
+
 /* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire
  * before starting to decrease the MTU. */
 #define DTLS1_MTU_TIMEOUTS                     2
@@ -86,7 +88,7 @@
     ssl3_free(ssl);
     return 0;
   }
-  memset(d1, 0, sizeof *d1);
+  OPENSSL_memset(d1, 0, sizeof *d1);
 
   ssl->d1 = d1;
 
@@ -154,12 +156,12 @@
   if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec ||
       (ssl->d1->next_timeout.tv_sec == timenow.tv_sec &&
        ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
-    memset(out, 0, sizeof(struct timeval));
+    OPENSSL_memset(out, 0, sizeof(struct timeval));
     return 1;
   }
 
   /* Calculate time left until timer expires */
-  memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval));
+  OPENSSL_memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval));
   out->tv_sec -= timenow.tv_sec;
   out->tv_usec -= timenow.tv_usec;
   if (out->tv_usec < 0) {
@@ -170,7 +172,7 @@
   /* If remaining time is less than 15 ms, set it to 0 to prevent issues
    * because of small devergences with socket timeouts. */
   if (out->tv_sec == 0 && out->tv_usec < 15000) {
-    memset(out, 0, sizeof(struct timeval));
+    OPENSSL_memset(out, 0, sizeof(struct timeval));
   }
 
   return 1;
@@ -204,7 +206,7 @@
 void dtls1_stop_timer(SSL *ssl) {
   /* Reset everything */
   ssl->d1->num_timeouts = 0;
-  memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval));
+  OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval));
   ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
   BIO_ctrl(ssl->rbio, BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
            &ssl->d1->next_timeout);
@@ -234,9 +236,7 @@
 }
 
 int DTLSv1_handle_timeout(SSL *ssl) {
-  ssl->rwstate = SSL_NOTHING;
-  /* Functions which use SSL_get_error must clear the error queue on entry. */
-  ERR_clear_error();
+  ssl_reset_error_state(ssl);
 
   if (!SSL_is_dtls(ssl)) {
     return -1;
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 155359c..c6950d5 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -122,6 +122,7 @@
 #include <openssl/err.h>
 #include <openssl/rand.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -265,7 +266,7 @@
     len = rr->length;
   }
 
-  memcpy(buf, rr->data, len);
+  OPENSSL_memcpy(buf, rr->data, len);
   if (!peek) {
     /* TODO(davidben): Should the record be truncated instead? This is a
      * datagram transport. See https://crbug.com/boringssl/65. */
diff --git a/src/ssl/dtls_method.c b/src/ssl/dtls_method.c
index 89b5491..6576686 100644
--- a/src/ssl/dtls_method.c
+++ b/src/ssl/dtls_method.c
@@ -62,6 +62,7 @@
 #include <openssl/buf.h>
 #include <openssl/err.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -112,8 +113,8 @@
   }
 
   ssl->d1->r_epoch++;
-  memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
-  memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
+  OPENSSL_memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
+  OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
 
   SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
   ssl->s3->aead_read_ctx = aead_ctx;
@@ -122,9 +123,9 @@
 
 static int dtls1_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
   ssl->d1->w_epoch++;
-  memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence,
-         sizeof(ssl->s3->write_sequence));
-  memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
+  OPENSSL_memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence,
+                 sizeof(ssl->s3->write_sequence));
+  OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
 
   SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
   ssl->s3->aead_write_ctx = aead_ctx;
diff --git a/src/ssl/dtls_record.c b/src/ssl/dtls_record.c
index ffe4053..e507f5c 100644
--- a/src/ssl/dtls_record.c
+++ b/src/ssl/dtls_record.c
@@ -283,7 +283,7 @@
 
   out[3] = epoch >> 8;
   out[4] = epoch & 0xff;
-  memcpy(&out[5], &seq[2], 6);
+  OPENSSL_memcpy(&out[5], &seq[2], 6);
 
   size_t ciphertext_len;
   if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len,
diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c
index 8c21818..720c215 100644
--- a/src/ssl/handshake_client.c
+++ b/src/ssl/handshake_client.c
@@ -167,6 +167,7 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -349,7 +350,7 @@
       case SSL3_ST_CW_CERT_VRFY_A:
       case SSL3_ST_CW_CERT_VRFY_B:
       case SSL3_ST_CW_CERT_VRFY_C:
-        if (hs->cert_request) {
+        if (hs->cert_request && ssl_has_certificate(ssl)) {
           ret = ssl3_send_cert_verify(hs);
           if (ret <= 0) {
             goto end;
@@ -815,7 +816,7 @@
     goto f_err;
   }
 
-  memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
+  OPENSSL_memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
   ssl->d1->cookie_len = CBS_len(&cookie);
 
   ssl->d1->send_cookie = 1;
@@ -913,7 +914,7 @@
   }
 
   /* Copy over the server random. */
-  memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE);
+  OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE);
 
   /* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS
    * 1.3 is finalized and we are not implementing a draft version. */
@@ -932,7 +933,7 @@
     }
     /* Note: session_id could be empty. */
     ssl->s3->new_session->session_id_length = CBS_len(&session_id);
-    memcpy(ssl->s3->new_session->session_id, CBS_data(&session_id),
+    OPENSSL_memcpy(ssl->s3->new_session->session_id, CBS_data(&session_id),
            CBS_len(&session_id));
   }
 
@@ -1466,7 +1467,6 @@
   }
 
   if (!ssl_has_certificate(ssl)) {
-    hs->cert_request = 0;
     /* Without a client certificate, the handshake buffer may be released. */
     ssl3_free_handshake_buffer(ssl);
 
@@ -1477,7 +1477,8 @@
     }
   }
 
-  if (!ssl3_output_cert_chain(ssl)) {
+  if (!ssl_auto_chain_if_needed(ssl) ||
+      !ssl3_output_cert_chain(ssl)) {
     return -1;
   }
   hs->state = SSL3_ST_CW_CERT_B;
@@ -1515,7 +1516,7 @@
     }
 
     char identity[PSK_MAX_IDENTITY_LEN + 1];
-    memset(identity, 0, sizeof(identity));
+    OPENSSL_memset(identity, 0, sizeof(identity));
     psk_len =
         ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint, identity,
                                  sizeof(identity), psk, sizeof(psk));
@@ -1616,7 +1617,7 @@
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    memset(pms, 0, pms_len);
+    OPENSSL_memset(pms, 0, pms_len);
   } else {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c
index d41685e..6ce49f5 100644
--- a/src/ssl/handshake_server.c
+++ b/src/ssl/handshake_server.c
@@ -881,12 +881,12 @@
       OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
       return -1;
     }
-    memcpy(ssl->s3->client_random, client_hello.random,
-           client_hello.random_len);
+    OPENSSL_memcpy(ssl->s3->client_random, client_hello.random,
+                   client_hello.random_len);
 
     /* Only null compression is supported. */
-    if (memchr(client_hello.compression_methods, 0,
-               client_hello.compression_methods_len) == NULL) {
+    if (OPENSSL_memchr(client_hello.compression_methods, 0,
+                       client_hello.compression_methods_len) == NULL) {
       al = SSL_AD_ILLEGAL_PARAMETER;
       OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMPRESSION_SPECIFIED);
       goto f_err;
@@ -916,6 +916,10 @@
       }
     }
 
+    if (!ssl_auto_chain_if_needed(ssl)) {
+      goto err;
+    }
+
     /* Negotiate the cipher suite. This must be done after |cert_cb| so the
      * certificate is finalized. */
     ssl->s3->tmp.new_cipher =
@@ -1736,7 +1740,7 @@
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    memset(premaster_secret, 0, premaster_secret_len);
+    OPENSSL_memset(premaster_secret, 0, premaster_secret_len);
   } else {
     al = SSL_AD_HANDSHAKE_FAILURE;
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE);
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 2688bc7..919f5aa 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -779,6 +779,11 @@
  * empty certificate list. It returns one on success and zero on error. */
 int ssl_add_cert_chain(SSL *ssl, CBB *cbb);
 
+/* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if
+ * necessary. On success, it updates |ssl|'s certificate configuration as needed
+ * and returns one. Otherwise, it returns zero. */
+int ssl_auto_chain_if_needed(SSL *ssl);
+
 /* ssl_cert_check_digital_signature_key_usage parses the DER-encoded, X.509
  * certificate in |in| and returns one if doesn't specify a key usage or, if it
  * does, if it includes digitalSignature. Otherwise it pushes to the error
@@ -833,10 +838,9 @@
                           const uint8_t *traffic_secret,
                           size_t traffic_secret_len);
 
-/* tls13_set_handshake_traffic derives the handshake traffic secret and
- * switches both read and write traffic to it. It returns one on success and
- * zero on error. */
-int tls13_set_handshake_traffic(SSL_HANDSHAKE *hs);
+/* tls13_derive_handshake_secrets derives the handshake traffic secret. It
+ * returns one on success and zero on error. */
+int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs);
 
 /* tls13_rotate_traffic_key derives the next read or write traffic secret. It
  * returns one on success and zero on error. */
@@ -914,6 +918,8 @@
 
   size_t hash_len;
   uint8_t secret[EVP_MAX_MD_SIZE];
+  uint8_t client_handshake_secret[EVP_MAX_MD_SIZE];
+  uint8_t server_handshake_secret[EVP_MAX_MD_SIZE];
   uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE];
   uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE];
 
@@ -1142,10 +1148,10 @@
  * it. It writes the parsed extensions to pointers denoted by |ext_types|. On
  * success, it fills in the |out_present| and |out_data| fields and returns one.
  * Otherwise, it sets |*out_alert| to an alert to send and returns zero. Unknown
- * extensions are rejected. */
+ * extensions are rejected unless |ignore_unknown| is 1. */
 int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
                          const SSL_EXTENSION_TYPE *ext_types,
-                         size_t num_ext_types);
+                         size_t num_ext_types, int ignore_unknown);
 
 
 /* SSLKEYLOGFILE functions. */
@@ -1482,6 +1488,10 @@
    * handshake. */
   unsigned tlsext_channel_id_valid:1;
 
+  /* short_header is one if https://github.com/tlswg/tls13-spec/pull/762 has
+   * been negotiated. */
+  unsigned short_header:1;
+
   uint8_t send_alert[2];
 
   /* pending_message is the current outgoing handshake message. */
@@ -1936,6 +1946,9 @@
 
 void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock);
 
+/* ssl_reset_error_state resets state for |SSL_get_error|. */
+void ssl_reset_error_state(SSL *ssl);
+
 
 #if defined(__cplusplus)
 } /* extern C */
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 4800f92..492884f 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -127,6 +127,7 @@
 #include <openssl/sha.h>
 #include <openssl/x509.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -136,7 +137,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
-  memset(hs, 0, sizeof(SSL_HANDSHAKE));
+  OPENSSL_memset(hs, 0, sizeof(SSL_HANDSHAKE));
   hs->ssl = ssl;
   hs->wait = ssl_hs_ok;
   hs->state = SSL_ST_INIT;
@@ -149,6 +150,10 @@
   }
 
   OPENSSL_cleanse(hs->secret, sizeof(hs->secret));
+  OPENSSL_cleanse(hs->client_handshake_secret,
+                  sizeof(hs->client_handshake_secret));
+  OPENSSL_cleanse(hs->server_handshake_secret,
+                  sizeof(hs->server_handshake_secret));
   OPENSSL_cleanse(hs->client_traffic_secret_0,
                   sizeof(hs->client_traffic_secret_0));
   OPENSSL_cleanse(hs->server_traffic_secret_0,
@@ -291,10 +296,10 @@
     }
 
     if (ssl->server) {
-      memcpy(ssl->s3->previous_server_finished, finished, finished_len);
+      OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len);
       ssl->s3->previous_server_finished_len = finished_len;
     } else {
-      memcpy(ssl->s3->previous_client_finished, finished, finished_len);
+      OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len);
       ssl->s3->previous_client_finished_len = finished_len;
     }
   }
@@ -349,10 +354,10 @@
     }
 
     if (ssl->server) {
-      memcpy(ssl->s3->previous_client_finished, finished, finished_len);
+      OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len);
       ssl->s3->previous_client_finished_len = finished_len;
     } else {
-      memcpy(ssl->s3->previous_server_finished, finished, finished_len);
+      OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len);
       ssl->s3->previous_server_finished_len = finished_len;
     }
   }
@@ -517,9 +522,9 @@
     rand_len = SSL3_RANDOM_SIZE;
   }
   uint8_t random[SSL3_RANDOM_SIZE];
-  memset(random, 0, SSL3_RANDOM_SIZE);
-  memcpy(random + (SSL3_RANDOM_SIZE - rand_len), CBS_data(&challenge),
-         rand_len);
+  OPENSSL_memset(random, 0, SSL3_RANDOM_SIZE);
+  OPENSSL_memcpy(random + (SSL3_RANDOM_SIZE - rand_len), CBS_data(&challenge),
+                 rand_len);
 
   /* Write out an equivalent SSLv3 ClientHello. */
   size_t max_v3_client_hello = SSL3_HM_HEADER_LENGTH + 2 /* version */ +
@@ -775,7 +780,7 @@
 
 int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
                          const SSL_EXTENSION_TYPE *ext_types,
-                         size_t num_ext_types) {
+                         size_t num_ext_types, int ignore_unknown) {
   /* Reset everything. */
   for (size_t i = 0; i < num_ext_types; i++) {
     *ext_types[i].out_present = 0;
@@ -802,6 +807,9 @@
     }
 
     if (ext_type == NULL) {
+      if (ignore_unknown) {
+        continue;
+      }
       OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
       *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
       return 0;
diff --git a/src/ssl/s3_enc.c b/src/ssl/s3_enc.c
index 7cdc294..bf82e08 100644
--- a/src/ssl/s3_enc.c
+++ b/src/ssl/s3_enc.c
@@ -144,8 +144,10 @@
 #include <openssl/md5.h>
 #include <openssl/nid.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
+
 static int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len,
                     const uint8_t *secret, size_t secret_len, const char *label,
                     size_t label_len, const uint8_t *seed1, size_t seed1_len,
@@ -194,7 +196,7 @@
     EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH);
     if (i + MD5_DIGEST_LENGTH > out_len) {
       EVP_DigestFinal_ex(&md5, smd, NULL);
-      memcpy(out, smd, out_len - i);
+      OPENSSL_memcpy(out, smd, out_len - i);
     } else {
       EVP_DigestFinal_ex(&md5, out, NULL);
     }
@@ -269,7 +271,8 @@
     if (!BUF_MEM_grow(ssl->s3->handshake_buffer, new_len)) {
       return 0;
     }
-    memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in, in_len);
+    OPENSSL_memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in,
+                   in_len);
   }
 
   if (EVP_MD_CTX_md(&ssl->s3->handshake_hash) != NULL) {
diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c
index 859cb9b..7039418 100644
--- a/src/ssl/s3_lib.c
+++ b/src/ssl/s3_lib.c
@@ -159,6 +159,7 @@
 #include <openssl/mem.h>
 #include <openssl/nid.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -169,7 +170,7 @@
   if (s3 == NULL) {
     return 0;
   }
-  memset(s3, 0, sizeof *s3);
+  OPENSSL_memset(s3, 0, sizeof *s3);
 
   s3->hs = ssl_handshake_new(ssl);
   if (s3->hs == NULL) {
@@ -221,19 +222,7 @@
     return ssl->cipher_list;
   }
 
-  if (ssl->version >= TLS1_1_VERSION && ssl->ctx->cipher_list_tls11 != NULL) {
-    return ssl->ctx->cipher_list_tls11;
-  }
-
-  if (ssl->version >= TLS1_VERSION && ssl->ctx->cipher_list_tls10 != NULL) {
-    return ssl->ctx->cipher_list_tls10;
-  }
-
-  if (ssl->ctx->cipher_list != NULL) {
-    return ssl->ctx->cipher_list;
-  }
-
-  return NULL;
+  return ssl->ctx->cipher_list;
 }
 
 /* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index e4116fb..9bd9f1f 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -118,6 +118,7 @@
 #include <openssl/mem.h>
 #include <openssl/rand.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -319,7 +320,7 @@
     len = (int)rr->length;
   }
 
-  memcpy(out, rr->data, len);
+  OPENSSL_memcpy(out, rr->data, len);
   if (!peek) {
     rr->length -= len;
     rr->data += len;
diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c
index b05df0b..1b95150 100644
--- a/src/ssl/ssl_aead_ctx.c
+++ b/src/ssl/ssl_aead_ctx.c
@@ -22,6 +22,7 @@
 #include <openssl/rand.h>
 #include <openssl/type_check.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -52,9 +53,10 @@
       OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
       return 0;
     }
-    memcpy(merged_key, mac_key, mac_key_len);
-    memcpy(merged_key + mac_key_len, enc_key, enc_key_len);
-    memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv, fixed_iv_len);
+    OPENSSL_memcpy(merged_key, mac_key, mac_key_len);
+    OPENSSL_memcpy(merged_key + mac_key_len, enc_key, enc_key_len);
+    OPENSSL_memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv,
+                   fixed_iv_len);
     enc_key = merged_key;
     enc_key_len += mac_key_len;
     enc_key_len += fixed_iv_len;
@@ -65,7 +67,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
-  memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX));
+  OPENSSL_memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX));
   aead_ctx->cipher = cipher;
 
   if (!EVP_AEAD_CTX_init_with_direction(
@@ -79,7 +81,7 @@
   aead_ctx->variable_nonce_len = (uint8_t)EVP_AEAD_nonce_length(aead);
   if (mac_key_len == 0) {
     assert(fixed_iv_len <= sizeof(aead_ctx->fixed_nonce));
-    memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len);
+    OPENSSL_memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len);
     aead_ctx->fixed_nonce_len = fixed_iv_len;
 
     if (cipher->algorithm_enc & SSL_CHACHA20POLY1305) {
@@ -158,7 +160,7 @@
     return 0;
   }
 
-  memcpy(out, seqnum, 8);
+  OPENSSL_memcpy(out, seqnum, 8);
   size_t len = 8;
   out[len++] = type;
   if (!aead->omit_version_in_ad) {
@@ -208,9 +210,9 @@
   /* Prepend the fixed nonce, or left-pad with zeros if XORing. */
   if (aead->xor_fixed_nonce) {
     nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len;
-    memset(nonce, 0, nonce_len);
+    OPENSSL_memset(nonce, 0, nonce_len);
   } else {
-    memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
+    OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
     nonce_len += aead->fixed_nonce_len;
   }
 
@@ -221,12 +223,12 @@
       OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
       return 0;
     }
-    memcpy(nonce + nonce_len, in, aead->variable_nonce_len);
+    OPENSSL_memcpy(nonce + nonce_len, in, aead->variable_nonce_len);
     in += aead->variable_nonce_len;
     in_len -= aead->variable_nonce_len;
   } else {
     assert(aead->variable_nonce_len == 8);
-    memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
+    OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
   }
   nonce_len += aead->variable_nonce_len;
 
@@ -262,7 +264,7 @@
       OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
       return 0;
     }
-    memmove(out, in, in_len);
+    OPENSSL_memmove(out, in, in_len);
     *out_len = in_len;
     return 1;
   }
@@ -278,9 +280,9 @@
   /* Prepend the fixed nonce, or left-pad with zeros if XORing. */
   if (aead->xor_fixed_nonce) {
     nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len;
-    memset(nonce, 0, nonce_len);
+    OPENSSL_memset(nonce, 0, nonce_len);
   } else {
-    memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
+    OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
     nonce_len += aead->fixed_nonce_len;
   }
 
@@ -294,7 +296,7 @@
     /* When sending we use the sequence number as the variable part of the
      * nonce. */
     assert(aead->variable_nonce_len == 8);
-    memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
+    OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
   }
   nonce_len += aead->variable_nonce_len;
 
@@ -310,7 +312,8 @@
       OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
       return 0;
     }
-    memcpy(out, nonce + aead->fixed_nonce_len, aead->variable_nonce_len);
+    OPENSSL_memcpy(out, nonce + aead->fixed_nonce_len,
+                   aead->variable_nonce_len);
     extra_len = aead->variable_nonce_len;
     out += aead->variable_nonce_len;
     max_out -= aead->variable_nonce_len;
diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c
index 902b580..c9dfdcc 100644
--- a/src/ssl/ssl_asn1.c
+++ b/src/ssl/ssl_asn1.c
@@ -91,6 +91,7 @@
 #include <openssl/mem.h>
 #include <openssl/x509.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -127,6 +128,7 @@
  *     ticketAgeAdd            [21] OCTET STRING OPTIONAL,
  *     isServer                [22] BOOLEAN DEFAULT TRUE,
  *     peerSignatureAlgorithm  [23] INTEGER OPTIONAL,
+ *     ticketMaxEarlyData      [24] INTEGER OPTIONAL,
  * }
  *
  * Note: historically this serialization has included other optional
@@ -179,6 +181,8 @@
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22;
 static const int kPeerSignatureAlgorithmTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 23;
+static const int kTicketMaxEarlyDataTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 24;
 
 static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
                                      size_t *out_len, int for_ticket) {
@@ -391,6 +395,13 @@
     goto err;
   }
 
+  if (in->ticket_max_early_data != 0 &&
+      (!CBB_add_asn1(&session, &child, kTicketMaxEarlyDataTag) ||
+       !CBB_add_asn1_uint64(&child, in->ticket_max_early_data))) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+
   if (!CBB_finish(&cbb, out_data, out_len)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -443,7 +454,7 @@
   }
 
   if (pp) {
-    memcpy(*pp, out, len);
+    OPENSSL_memcpy(*pp, out, len);
     *pp += len;
   }
   OPENSSL_free(out);
@@ -510,7 +521,7 @@
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     return 0;
   }
-  memcpy(out, CBS_data(&value), CBS_len(&value));
+  OPENSSL_memcpy(out, CBS_data(&value), CBS_len(&value));
   *out_len = (uint8_t)CBS_len(&value);
   return 1;
 }
@@ -593,9 +604,9 @@
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
-  memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
+  OPENSSL_memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
   ret->session_id_length = CBS_len(&session_id);
-  memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
+  OPENSSL_memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
   ret->master_key_length = CBS_len(&master_key);
 
   CBS child;
@@ -647,7 +658,8 @@
       OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
       goto err;
     }
-    memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256));
+    OPENSSL_memcpy(ret->peer_sha256, CBS_data(&peer_sha256),
+                   sizeof(ret->peer_sha256));
     ret->peer_sha256_valid = 1;
   } else {
     ret->peer_sha256_valid = 0;
@@ -773,6 +785,8 @@
 
   if (!SSL_SESSION_parse_u16(&session, &ret->peer_signature_algorithm,
                              kPeerSignatureAlgorithmTag, 0) ||
+      !SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data,
+                             kTicketMaxEarlyDataTag, 0) ||
       CBS_len(&session) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
diff --git a/src/ssl/ssl_buffer.c b/src/ssl/ssl_buffer.c
index 7feb161..c27db8b 100644
--- a/src/ssl/ssl_buffer.c
+++ b/src/ssl/ssl_buffer.c
@@ -24,6 +24,7 @@
 #include <openssl/mem.h>
 #include <openssl/type_check.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -67,7 +68,7 @@
 
 static void clear_buffer(SSL3_BUFFER *buf) {
   OPENSSL_free(buf->buf);
-  memset(buf, 0, sizeof(SSL3_BUFFER));
+  OPENSSL_memset(buf, 0, sizeof(SSL3_BUFFER));
 }
 
 OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH <=
diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c
index 277ee4d..397fbf0 100644
--- a/src/ssl/ssl_cert.c
+++ b/src/ssl/ssl_cert.c
@@ -147,7 +147,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
-  memset(ret, 0, sizeof(CERT));
+  OPENSSL_memset(ret, 0, sizeof(CERT));
 
   return ret;
 }
@@ -158,7 +158,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
-  memset(ret, 0, sizeof(CERT));
+  OPENSSL_memset(ret, 0, sizeof(CERT));
 
   if (cert->x509_leaf != NULL) {
     X509_up_ref(cert->x509_leaf);
@@ -557,56 +557,55 @@
     return CBB_add_u24(cbb, 0);
   }
 
-  CERT *cert = ssl->cert;
-  X509 *x = cert->x509_leaf;
-
   CBB child;
-  if (!CBB_add_u24_length_prefixed(cbb, &child)) {
+  if (!CBB_add_u24_length_prefixed(cbb, &child) ||
+      !ssl_add_cert_with_length(&child, ssl->cert->x509_leaf)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
-  int no_chain = 0;
-  STACK_OF(X509) *chain = cert->x509_chain;
-  if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || chain != NULL) {
-    no_chain = 1;
-  }
-
-  if (no_chain) {
-    if (!ssl_add_cert_with_length(&child, x)) {
+  STACK_OF(X509) *chain = ssl->cert->x509_chain;
+  for (size_t i = 0; i < sk_X509_num(chain); i++) {
+    if (!ssl_add_cert_with_length(&child, sk_X509_value(chain, i))) {
       return 0;
     }
-
-    for (size_t i = 0; i < sk_X509_num(chain); i++) {
-      x = sk_X509_value(chain, i);
-      if (!ssl_add_cert_with_length(&child, x)) {
-        return 0;
-      }
-    }
-  } else {
-    X509_STORE_CTX xs_ctx;
-
-    if (!X509_STORE_CTX_init(&xs_ctx, ssl->ctx->cert_store, x, NULL)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
-      return 0;
-    }
-    X509_verify_cert(&xs_ctx);
-    /* Don't leave errors in the queue */
-    ERR_clear_error();
-
-    for (size_t i = 0; i < sk_X509_num(xs_ctx.chain); i++) {
-      x = sk_X509_value(xs_ctx.chain, i);
-      if (!ssl_add_cert_with_length(&child, x)) {
-        X509_STORE_CTX_cleanup(&xs_ctx);
-        return 0;
-      }
-    }
-    X509_STORE_CTX_cleanup(&xs_ctx);
   }
 
   return CBB_flush(cbb);
 }
 
+int ssl_auto_chain_if_needed(SSL *ssl) {
+  /* Only build a chain if there are no intermediates configured and the feature
+   * isn't disabled. */
+  if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) ||
+      !ssl_has_certificate(ssl) ||
+      ssl->cert->x509_chain != NULL) {
+    return 1;
+  }
+
+  X509_STORE_CTX ctx;
+  if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, ssl->cert->x509_leaf,
+                           NULL)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
+    return 0;
+  }
+
+  /* Attempt to build a chain, ignoring the result. */
+  X509_verify_cert(&ctx);
+  ERR_clear_error();
+
+  /* Configure the intermediates from any partial chain we managed to build. */
+  for (size_t i = 1; i < sk_X509_num(ctx.chain); i++) {
+    if (!SSL_add1_chain_cert(ssl, sk_X509_value(ctx.chain, i))) {
+      X509_STORE_CTX_cleanup(&ctx);
+      return 0;
+    }
+  }
+
+  X509_STORE_CTX_cleanup(&ctx);
+  return 1;
+}
+
 /* ssl_cert_skip_to_spki parses a DER-encoded, X.509 certificate from |in| and
  * positions |*out_tbs_cert| to cover the TBSCertificate, starting at the
  * subjectPublicKeyInfo. */
@@ -707,7 +706,8 @@
 
     static const uint8_t kKeyUsageOID[3] = {0x55, 0x1d, 0x0f};
     if (CBS_len(&oid) != sizeof(kKeyUsageOID) ||
-        memcmp(CBS_data(&oid), kKeyUsageOID, sizeof(kKeyUsageOID)) != 0) {
+        OPENSSL_memcmp(CBS_data(&oid), kKeyUsageOID, sizeof(kKeyUsageOID)) !=
+            0) {
       continue;
     }
 
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 5223721..20b075e 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -1073,7 +1073,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return 0;
   }
-  memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int));
+  OPENSSL_memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int));
 
   /* Now find the strength_bits values actually used. */
   curr = *head_p;
@@ -1437,7 +1437,7 @@
   if (!pref_list->in_group_flags) {
     goto err;
   }
-  memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags);
+  OPENSSL_memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags);
   OPENSSL_free(in_group_flags);
   in_group_flags = NULL;
   if (*out_cipher_list != NULL) {
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 77e86a8..a60bf81 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -196,8 +196,8 @@
 
   uint8_t tmp_storage[sizeof(uint32_t)];
   if (sess->session_id_length < sizeof(tmp_storage)) {
-    memset(tmp_storage, 0, sizeof(tmp_storage));
-    memcpy(tmp_storage, sess->session_id, sess->session_id_length);
+    OPENSSL_memset(tmp_storage, 0, sizeof(tmp_storage));
+    OPENSSL_memcpy(tmp_storage, sess->session_id, sess->session_id_length);
     session_id = tmp_storage;
   }
 
@@ -224,7 +224,7 @@
     return 1;
   }
 
-  return memcmp(a->session_id, b->session_id, a->session_id_length);
+  return OPENSSL_memcmp(a->session_id, b->session_id, a->session_id_length);
 }
 
 SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
@@ -245,7 +245,7 @@
     goto err;
   }
 
-  memset(ret, 0, sizeof(SSL_CTX));
+  OPENSSL_memset(ret, 0, sizeof(SSL_CTX));
 
   ret->method = method->method;
 
@@ -352,8 +352,6 @@
   lh_SSL_SESSION_free(ctx->sessions);
   X509_STORE_free(ctx->cert_store);
   ssl_cipher_preference_list_free(ctx->cipher_list);
-  ssl_cipher_preference_list_free(ctx->cipher_list_tls10);
-  ssl_cipher_preference_list_free(ctx->cipher_list_tls11);
   ssl_cert_free(ctx->cert);
   sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions,
                                    SSL_CUSTOM_EXTENSION_free);
@@ -385,7 +383,7 @@
   if (ssl == NULL) {
     goto err;
   }
-  memset(ssl, 0, sizeof(SSL));
+  OPENSSL_memset(ssl, 0, sizeof(SSL));
 
   ssl->min_version = ctx->min_version;
   ssl->max_version = ctx->max_version;
@@ -408,7 +406,7 @@
   ssl->verify_mode = ctx->verify_mode;
   ssl->sid_ctx_length = ctx->sid_ctx_length;
   assert(ssl->sid_ctx_length <= sizeof ssl->sid_ctx);
-  memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx));
+  OPENSSL_memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx));
   ssl->verify_callback = ctx->default_verify_callback;
   ssl->retain_only_sha256_of_client_certs =
       ctx->retain_only_sha256_of_client_certs;
@@ -421,9 +419,9 @@
   ssl->quiet_shutdown = ctx->quiet_shutdown;
   ssl->max_send_fragment = ctx->max_send_fragment;
 
-  CRYPTO_refcount_inc(&ctx->references);
+  SSL_CTX_up_ref(ctx);
   ssl->ctx = ctx;
-  CRYPTO_refcount_inc(&ctx->references);
+  SSL_CTX_up_ref(ctx);
   ssl->initial_ctx = ctx;
 
   if (ctx->supported_group_list) {
@@ -614,11 +612,16 @@
   return ssl->wbio;
 }
 
-int SSL_do_handshake(SSL *ssl) {
+void ssl_reset_error_state(SSL *ssl) {
+  /* Functions which use |SSL_get_error| must reset I/O and error state on
+   * entry. */
   ssl->rwstate = SSL_NOTHING;
-  /* Functions which use SSL_get_error must clear the error queue on entry. */
   ERR_clear_error();
   ERR_clear_system_error();
+}
+
+int SSL_do_handshake(SSL *ssl) {
+  ssl_reset_error_state(ssl);
 
   if (ssl->handshake_func == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
@@ -737,10 +740,7 @@
 }
 
 static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
-  ssl->rwstate = SSL_NOTHING;
-  /* Functions which use SSL_get_error must clear the error queue on entry. */
-  ERR_clear_error();
-  ERR_clear_system_error();
+  ssl_reset_error_state(ssl);
 
   if (ssl->handshake_func == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
@@ -786,10 +786,7 @@
 }
 
 int SSL_write(SSL *ssl, const void *buf, int num) {
-  ssl->rwstate = SSL_NOTHING;
-  /* Functions which use SSL_get_error must clear the error queue on entry. */
-  ERR_clear_error();
-  ERR_clear_system_error();
+  ssl_reset_error_state(ssl);
 
   if (ssl->handshake_func == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
@@ -817,10 +814,7 @@
 }
 
 int SSL_shutdown(SSL *ssl) {
-  ssl->rwstate = SSL_NOTHING;
-  /* Functions which use SSL_get_error must clear the error queue on entry. */
-  ERR_clear_error();
-  ERR_clear_system_error();
+  ssl_reset_error_state(ssl);
 
   if (ssl->handshake_func == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
@@ -880,6 +874,10 @@
   return ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
 }
 
+void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled) {
+  ctx->enable_early_data = !!enabled;
+}
+
 static int bio_retry_reason_to_error(int reason) {
   switch (reason) {
     case BIO_RR_CONNECT:
@@ -1159,12 +1157,12 @@
     *out_len = max_out;
   }
 
-  memcpy(out, finished, *out_len);
+  OPENSSL_memcpy(out, finished, *out_len);
   return 1;
 
 err:
   *out_len = 0;
-  memset(out, 0, max_out);
+  OPENSSL_memset(out, 0, max_out);
   return 0;
 }
 
@@ -1177,7 +1175,7 @@
 
   assert(sizeof(ctx->sid_ctx) < 256);
   ctx->sid_ctx_length = (uint8_t)sid_ctx_len;
-  memcpy(ctx->sid_ctx, sid_ctx, sid_ctx_len);
+  OPENSSL_memcpy(ctx->sid_ctx, sid_ctx, sid_ctx_len);
 
   return 1;
 }
@@ -1191,7 +1189,7 @@
 
   assert(sizeof(ssl->sid_ctx) < 256);
   ssl->sid_ctx_length = (uint8_t)sid_ctx_len;
-  memcpy(ssl->sid_ctx, sid_ctx, sid_ctx_len);
+  OPENSSL_memcpy(ssl->sid_ctx, sid_ctx, sid_ctx_len);
 
   return 1;
 }
@@ -1311,7 +1309,7 @@
   if (out_len > in_len) {
     out_len = in_len;
   }
-  memcpy(out, in, out_len);
+  OPENSSL_memcpy(out, in, out_len);
   return in_len;
 }
 
@@ -1547,9 +1545,9 @@
     return 0;
   }
   uint8_t *out_bytes = out;
-  memcpy(out_bytes, ctx->tlsext_tick_key_name, 16);
-  memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16);
-  memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16);
+  OPENSSL_memcpy(out_bytes, ctx->tlsext_tick_key_name, 16);
+  OPENSSL_memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16);
+  OPENSSL_memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16);
   return 1;
 }
 
@@ -1562,9 +1560,9 @@
     return 0;
   }
   const uint8_t *in_bytes = in;
-  memcpy(ctx->tlsext_tick_key_name, in_bytes, 16);
-  memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16);
-  memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16);
+  OPENSSL_memcpy(ctx->tlsext_tick_key_name, in_bytes, 16);
+  OPENSSL_memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16);
+  OPENSSL_memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16);
   return 1;
 }
 
@@ -1680,38 +1678,6 @@
   return 1;
 }
 
-int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) {
-  STACK_OF(SSL_CIPHER) *cipher_list =
-      ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls10, str);
-  if (cipher_list == NULL) {
-    return 0;
-  }
-
-  /* |ssl_create_cipher_list| may succeed but return an empty cipher list. */
-  if (sk_SSL_CIPHER_num(cipher_list) == 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
-    return 0;
-  }
-
-  return 1;
-}
-
-int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) {
-  STACK_OF(SSL_CIPHER) *cipher_list =
-      ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls11, str);
-  if (cipher_list == NULL) {
-    return 0;
-  }
-
-  /* |ssl_create_cipher_list| may succeed but return an empty cipher list. */
-  if (sk_SSL_CIPHER_num(cipher_list) == 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
-    return 0;
-  }
-
-  return 1;
-}
-
 int SSL_set_cipher_list(SSL *ssl, const char *str) {
   STACK_OF(SSL_CIPHER) *cipher_list =
       ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str);
@@ -1878,7 +1844,7 @@
   for (i = 0; i < server_len;) {
     for (j = 0; j < client_len;) {
       if (server[i] == client[j] &&
-          memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) {
+          OPENSSL_memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) {
         /* We found a match */
         result = &server[i];
         status = OPENSSL_NPN_NEGOTIATED;
@@ -2030,7 +1996,8 @@
   if (!ssl->s3->tlsext_channel_id_valid) {
     return 0;
   }
-  memcpy(out, ssl->s3->tlsext_channel_id, (max_out < 64) ? max_out : 64);
+  OPENSSL_memcpy(out, ssl->s3->tlsext_channel_id,
+                 (max_out < 64) ? max_out : 64);
   return 64;
 }
 
@@ -2299,13 +2266,13 @@
   ssl_cert_free(ssl->cert);
   ssl->cert = ssl_cert_dup(ctx->cert);
 
-  CRYPTO_refcount_inc(&ctx->references);
-  SSL_CTX_free(ssl->ctx); /* decrement reference count */
+  SSL_CTX_up_ref(ctx);
+  SSL_CTX_free(ssl->ctx);
   ssl->ctx = ctx;
 
   ssl->sid_ctx_length = ctx->sid_ctx_length;
   assert(ssl->sid_ctx_length <= sizeof(ssl->sid_ctx));
-  memcpy(ssl->sid_ctx, ctx->sid_ctx, sizeof(ssl->sid_ctx));
+  OPENSSL_memcpy(ssl->sid_ctx, ctx->sid_ctx, sizeof(ssl->sid_ctx));
 
   return ssl->ctx;
 }
@@ -2869,7 +2836,7 @@
   if (max_out > sizeof(ssl->s3->client_random)) {
     max_out = sizeof(ssl->s3->client_random);
   }
-  memcpy(out, ssl->s3->client_random, max_out);
+  OPENSSL_memcpy(out, ssl->s3->client_random, max_out);
   return max_out;
 }
 
@@ -2880,7 +2847,7 @@
   if (max_out > sizeof(ssl->s3->server_random)) {
     max_out = sizeof(ssl->s3->server_random);
   }
-  memcpy(out, ssl->s3->server_random, max_out);
+  OPENSSL_memcpy(out, ssl->s3->server_random, max_out);
   return max_out;
 }
 
@@ -2903,6 +2870,10 @@
   ctx->grease_enabled = !!enabled;
 }
 
+void SSL_CTX_set_short_header_enabled(SSL_CTX *ctx, int enabled) {
+  ctx->short_header_enabled = !!enabled;
+}
+
 int SSL_clear(SSL *ssl) {
   /* In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously
    * established session to be offered the next time around. wpa_supplicant
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index d6d7dab..7adef1a 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -166,7 +166,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return 0;
   }
-  memset(session, 0, sizeof(SSL_SESSION));
+  OPENSSL_memset(session, 0, sizeof(SSL_SESSION));
 
   session->verify_result = X509_V_ERR_INVALID_CALL;
   session->references = 1;
@@ -185,11 +185,11 @@
   new_session->is_server = session->is_server;
   new_session->ssl_version = session->ssl_version;
   new_session->sid_ctx_length = session->sid_ctx_length;
-  memcpy(new_session->sid_ctx, session->sid_ctx, session->sid_ctx_length);
+  OPENSSL_memcpy(new_session->sid_ctx, session->sid_ctx, session->sid_ctx_length);
 
   /* Copy the key material. */
   new_session->master_key_length = session->master_key_length;
-  memcpy(new_session->master_key, session->master_key,
+  OPENSSL_memcpy(new_session->master_key, session->master_key,
          session->master_key_length);
   new_session->cipher = session->cipher;
 
@@ -245,7 +245,8 @@
     }
   }
 
-  memcpy(new_session->peer_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH);
+  OPENSSL_memcpy(new_session->peer_sha256, session->peer_sha256,
+                 SHA256_DIGEST_LENGTH);
   new_session->peer_sha256_valid = session->peer_sha256_valid;
 
   if (session->tlsext_hostname != NULL) {
@@ -263,18 +264,19 @@
   /* Copy non-authentication connection properties. */
   if (dup_flags & SSL_SESSION_INCLUDE_NONAUTH) {
     new_session->session_id_length = session->session_id_length;
-    memcpy(new_session->session_id, session->session_id,
-           session->session_id_length);
+    OPENSSL_memcpy(new_session->session_id, session->session_id,
+                   session->session_id_length);
 
     new_session->group_id = session->group_id;
 
-    memcpy(new_session->original_handshake_hash,
-           session->original_handshake_hash,
-           session->original_handshake_hash_len);
+    OPENSSL_memcpy(new_session->original_handshake_hash,
+                   session->original_handshake_hash,
+                   session->original_handshake_hash_len);
     new_session->original_handshake_hash_len =
         session->original_handshake_hash_len;
     new_session->tlsext_tick_lifetime_hint = session->tlsext_tick_lifetime_hint;
     new_session->ticket_age_add = session->ticket_age_add;
+    new_session->ticket_max_early_data = session->ticket_max_early_data;
     new_session->extended_master_secret = session->extended_master_secret;
   }
 
@@ -387,7 +389,7 @@
   if (max_out > (size_t)session->master_key_length) {
     max_out = (size_t)session->master_key_length;
   }
-  memcpy(out, session->master_key, max_out);
+  OPENSSL_memcpy(out, session->master_key, max_out);
   return max_out;
 }
 
@@ -418,7 +420,7 @@
 
   assert(sizeof(session->sid_ctx) < 256);
   session->sid_ctx_length = (uint8_t)sid_ctx_len;
-  memcpy(session->sid_ctx, sid_ctx, sid_ctx_len);
+  OPENSSL_memcpy(session->sid_ctx, sid_ctx, sid_ctx_len);
 
   return 1;
 }
@@ -517,7 +519,7 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     goto err;
   }
-  memcpy(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length);
+  OPENSSL_memcpy(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length);
   session->sid_ctx_length = ssl->sid_ctx_length;
 
   /* The session is marked not resumable until it is completely filled in. */
@@ -627,7 +629,7 @@
                       NULL)) {
       goto err;
     }
-    memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+    OPENSSL_memcpy(key_name, tctx->tlsext_tick_key_name, 16);
   }
 
   uint8_t *ptr;
@@ -639,7 +641,7 @@
 
   size_t total = 0;
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
-  memcpy(ptr, session_buf, session_len);
+  OPENSSL_memcpy(ptr, session_buf, session_len);
   total = session_len;
 #else
   int len;
@@ -679,7 +681,8 @@
   }
 
   return session->sid_ctx_length == ssl->sid_ctx_length &&
-         memcmp(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length) == 0;
+         OPENSSL_memcmp(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length) ==
+             0;
 }
 
 int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session) {
@@ -737,7 +740,7 @@
     SSL_SESSION data;
     data.ssl_version = ssl->version;
     data.session_id_length = session_id_len;
-    memcpy(data.session_id, session_id, session_id_len);
+    OPENSSL_memcpy(data.session_id, session_id, session_id_len);
 
     CRYPTO_MUTEX_lock_read(&ssl->initial_ctx->lock);
     session = lh_SSL_SESSION_retrieve(ssl->initial_ctx->sessions, &data);
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index b74e51e..952ac11 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -673,7 +673,7 @@
   }
   encoded.reset(encoded_raw);
   if (encoded_len != input.size() ||
-      memcmp(input.data(), encoded.get(), input.size()) != 0) {
+      OPENSSL_memcmp(input.data(), encoded.get(), input.size()) != 0) {
     fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n");
     hexdump(stderr, "Before: ", input.data(), input.size());
     hexdump(stderr, "After:  ", encoded_raw, encoded_len);
@@ -711,7 +711,7 @@
     fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n");
     return false;
   }
-  if (memcmp(input.data(), encoded.get(), input.size()) != 0) {
+  if (OPENSSL_memcmp(input.data(), encoded.get(), input.size()) != 0) {
     fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n");
     return false;
   }
@@ -838,7 +838,7 @@
   if (session->tlsext_tick == nullptr) {
     return nullptr;
   }
-  memset(session->tlsext_tick, 'a', ticket_len);
+  OPENSSL_memset(session->tlsext_tick, 'a', ticket_len);
   session->tlsext_ticklen = ticket_len;
 
   // Fix up the timeout.
@@ -1030,8 +1030,8 @@
   }
 
   ret->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-  memset(ret->session_id, 0, ret->session_id_length);
-  memcpy(ret->session_id, &number, sizeof(number));
+  OPENSSL_memset(ret->session_id, 0, ret->session_id_length);
+  OPENSSL_memcpy(ret->session_id, &number, sizeof(number));
   return ret;
 }
 
@@ -1142,7 +1142,8 @@
       "j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==\n"
       "-----END CERTIFICATE-----\n";
   bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
-  return bssl::UniquePtr<X509>(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+  return bssl::UniquePtr<X509>(
+      PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
 }
 
 static bssl::UniquePtr<EVP_PKEY> GetTestKey() {
@@ -1197,6 +1198,90 @@
       PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
 }
 
+static bssl::UniquePtr<X509> GetChainTestCertificate() {
+  static const char kCertPEM[] =
+      "-----BEGIN CERTIFICATE-----\n"
+      "MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD\n"
+      "QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs\n"
+      "aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8\n"
+      "CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/\n"
+      "kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3\n"
+      "tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c\n"
+      "IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1\n"
+      "z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V\n"
+      "iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI\n"
+      "KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw\n"
+      "rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7\n"
+      "AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w\n"
+      "giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW\n"
+      "ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK\n"
+      "MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC\n"
+      "1ngWZ7Ih\n"
+      "-----END CERTIFICATE-----\n";
+  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
+  return bssl::UniquePtr<X509>(
+      PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bssl::UniquePtr<X509> GetChainTestIntermediate() {
+  static const char kCertPEM[] =
+      "-----BEGIN CERTIFICATE-----\n"
+      "MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS\n"
+      "b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE\n"
+      "AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D\n"
+      "GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ\n"
+      "3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l\n"
+      "HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF\n"
+      "Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7\n"
+      "6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM\n"
+      "cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n"
+      "AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ\n"
+      "BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1\n"
+      "QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye\n"
+      "NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b\n"
+      "WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv\n"
+      "XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4=\n"
+      "-----END CERTIFICATE-----\n";
+  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
+  return bssl::UniquePtr<X509>(
+      PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bssl::UniquePtr<EVP_PKEY> GetChainTestKey() {
+  static const char kKeyPEM[] =
+      "-----BEGIN PRIVATE KEY-----\n"
+      "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRvaz8CC/cshpC\n"
+      "afJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/kLRcH89M\n"
+      "/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3tHb+xs2P\n"
+      "Ss8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+cIDs2rQ+l\n"
+      "P7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1z7C8jU50\n"
+      "Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9ViLeXANgZ\n"
+      "i+Xx9KgfAgMBAAECggEBAK0VjSJzkyPaamcyTVSWjo7GdaBGcK60lk657RjR+lK0\n"
+      "YJ7pkej4oM2hdsVZFsP8Cs4E33nXLa/0pDsRov/qrp0WQm2skwqGMC1I/bZ0WRPk\n"
+      "wHaDrBBfESWnJDX/AGpVtlyOjPmgmK6J2usMPihQUDkKdAYrVWJePrMIxt1q6BMe\n"
+      "iczs3qriMmtY3bUc4UyUwJ5fhDLjshHvfuIpYQyI6EXZM6dZksn9LylXJnigY6QJ\n"
+      "HxOYO0BDwOsZ8yQ8J8afLk88i0GizEkgE1z3REtQUwgWfxr1WV/ud+T6/ZhSAgH9\n"
+      "042mQvSFZnIUSEsmCvjhWuAunfxHKCTcAoYISWfzWpkCgYEA7gpf3HHU5Tn+CgUn\n"
+      "1X5uGpG3DmcMgfeGgs2r2f/IIg/5Ac1dfYILiybL1tN9zbyLCJfcbFpWBc9hJL6f\n"
+      "CPc5hUiwWFJqBJewxQkC1Ae/HakHbip+IZ+Jr0842O4BAArvixk4Lb7/N2Ct9sTE\n"
+      "NJO6RtK9lbEZ5uK61DglHy8CS2UCgYEA4ZC1o36kPAMQBggajgnucb2yuUEelk0f\n"
+      "AEr+GI32MGE+93xMr7rAhBoqLg4AITyIfEnOSQ5HwagnIHonBbv1LV/Gf9ursx8Z\n"
+      "YOGbvT8zzzC+SU1bkDzdjAYnFQVGIjMtKOBJ3K07++ypwX1fr4QsQ8uKL8WSOWwt\n"
+      "Z3Bym6XiZzMCgYADnhy+2OwHX85AkLt+PyGlPbmuelpyTzS4IDAQbBa6jcuW/2wA\n"
+      "UE2km75VUXmD+u2R/9zVuLm99NzhFhSMqlUxdV1YukfqMfP5yp1EY6m/5aW7QuIP\n"
+      "2MDa7TVL9rIFMiVZ09RKvbBbQxjhuzPQKL6X/PPspnhiTefQ+dl2k9xREQKBgHDS\n"
+      "fMfGNEeAEKezrfSVqxphE9/tXms3L+ZpnCaT+yu/uEr5dTIAawKoQ6i9f/sf1/Sy\n"
+      "xedsqR+IB+oKrzIDDWMgoJybN4pkZ8E5lzhVQIjFjKgFdWLzzqyW9z1gYfABQPlN\n"
+      "FiS20WX0vgP1vcKAjdNrHzc9zyHBpgQzDmAj3NZZAoGBAI8vKCKdH7w3aL5CNkZQ\n"
+      "2buIeWNA2HZazVwAGG5F2TU/LmXfRKnG6dX5bkU+AkBZh56jNZy//hfFSewJB4Kk\n"
+      "buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi\n"
+      "SxpiPQ8d/hmSGwn4ksrWUsJD\n"
+      "-----END PRIVATE KEY-----\n";
+  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
+  return bssl::UniquePtr<EVP_PKEY>(
+      PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
 static bool CompleteHandshakes(SSL *client, SSL *server) {
   // Drive both their handshakes to completion.
   for (;;) {
@@ -1442,7 +1527,7 @@
   }
   bssl::UniquePtr<uint8_t> free_s1(s1_bytes);
 
-  return s0_len == s1_len && memcmp(s0_bytes, s1_bytes, s0_len) == 0;
+  return s0_len == s1_len && OPENSSL_memcmp(s0_bytes, s1_bytes, s0_len) == 0;
 }
 
 static bool ExpectFDs(const SSL *ssl, int rfd, int wfd) {
@@ -1711,7 +1796,8 @@
     return false;
   }
 
-  if (memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) != 0) {
+  if (OPENSSL_memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) !=
+      0) {
     fprintf(stderr, "peer_sha256 did not match.\n");
     return false;
   }
@@ -1747,10 +1833,10 @@
     fprintf(stderr, "ClientHello for version %04x too short.\n", version);
     return false;
   }
-  memset(client_hello.data() + kRandomOffset, 0, SSL3_RANDOM_SIZE);
+  OPENSSL_memset(client_hello.data() + kRandomOffset, 0, SSL3_RANDOM_SIZE);
 
   if (client_hello.size() != expected_len ||
-      memcmp(client_hello.data(), expected, expected_len) != 0) {
+      OPENSSL_memcmp(client_hello.data(), expected, expected_len) != 0) {
     fprintf(stderr, "ClientHello for version %04x did not match:\n", version);
     fprintf(stderr, "Got:\n\t");
     for (size_t i = 0; i < client_hello.size(); i++) {
@@ -2097,9 +2183,9 @@
   static const uint8_t kZeros[16] = {0};
 
   if (encrypt) {
-    memcpy(key_name, kZeros, sizeof(kZeros));
+    OPENSSL_memcpy(key_name, kZeros, sizeof(kZeros));
     RAND_bytes(iv, 16);
-  } else if (memcmp(key_name, kZeros, 16) != 0) {
+  } else if (OPENSSL_memcmp(key_name, kZeros, 16) != 0) {
     return 0;
   }
 
@@ -2124,7 +2210,7 @@
 
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   // Fuzzer-mode tickets are unencrypted.
-  memcpy(plaintext.get(), ciphertext, len);
+  OPENSSL_memcpy(plaintext.get(), ciphertext, len);
 #else
   static const uint8_t kZeros[16] = {0};
   const uint8_t *iv = session->tlsext_tick + 16;
@@ -2588,6 +2674,27 @@
   return true;
 }
 
+static const char *GetVersionName(uint16_t version) {
+  switch (version) {
+    case SSL3_VERSION:
+      return "SSLv3";
+    case TLS1_VERSION:
+      return "TLSv1";
+    case TLS1_1_VERSION:
+      return "TLSv1.1";
+    case TLS1_2_VERSION:
+      return "TLSv1.2";
+    case TLS1_3_VERSION:
+      return "TLSv1.3";
+    case DTLS1_VERSION:
+      return "DTLSv1";
+    case DTLS1_2_VERSION:
+      return "DTLSv1.2";
+    default:
+      return "???";
+  }
+}
+
 static bool TestVersion(bool is_dtls, const SSL_METHOD *method,
                         uint16_t version) {
   bssl::UniquePtr<X509> cert = GetTestCertificate();
@@ -2619,6 +2726,29 @@
     return false;
   }
 
+  // Test the version name is reported as expected.
+  const char *version_name = GetVersionName(version);
+  if (strcmp(version_name, SSL_get_version(client.get())) != 0 ||
+      strcmp(version_name, SSL_get_version(server.get())) != 0) {
+    fprintf(stderr, "Version name mismatch. Got '%s' and '%s', wanted '%s'.\n",
+            SSL_get_version(client.get()), SSL_get_version(server.get()),
+            version_name);
+    return false;
+  }
+
+  // Test SSL_SESSION reports the same name.
+  const char *client_name =
+      SSL_SESSION_get_version(SSL_get_session(client.get()));
+  const char *server_name =
+      SSL_SESSION_get_version(SSL_get_session(server.get()));
+  if (strcmp(version_name, client_name) != 0 ||
+      strcmp(version_name, server_name) != 0) {
+    fprintf(stderr,
+            "Session version name mismatch. Got '%s' and '%s', wanted '%s'.\n",
+            client_name, server_name, version_name);
+    return false;
+  }
+
   return true;
 }
 
@@ -2738,6 +2868,268 @@
   return true;
 }
 
+static bool ChainsEqual(STACK_OF(X509) *chain,
+                         const std::vector<X509 *> &expected) {
+  if (sk_X509_num(chain) != expected.size()) {
+    return false;
+  }
+
+  for (size_t i = 0; i < expected.size(); i++) {
+    if (X509_cmp(sk_X509_value(chain, i), expected[i]) != 0) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool TestAutoChain(bool is_dtls, const SSL_METHOD *method,
+                          uint16_t version) {
+  bssl::UniquePtr<X509> cert = GetChainTestCertificate();
+  bssl::UniquePtr<X509> intermediate = GetChainTestIntermediate();
+  bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
+  if (!cert || !intermediate || !key) {
+    return false;
+  }
+
+  // Configure both client and server to accept any certificate. Add
+  // |intermediate| to the cert store.
+  bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+  if (!ctx ||
+      !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+      !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+      !X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx.get()),
+                           intermediate.get())) {
+    return false;
+  }
+  SSL_CTX_set_verify(
+      ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+  SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+
+  // By default, the client and server should each only send the leaf.
+  bssl::UniquePtr<SSL> client, server;
+  if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+                              nullptr /* no session */)) {
+    return false;
+  }
+
+  if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()), {cert.get()})) {
+    fprintf(stderr, "Client-received chain did not match.\n");
+    return false;
+  }
+
+  if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()), {cert.get()})) {
+    fprintf(stderr, "Server-received chain did not match.\n");
+    return false;
+  }
+
+  // If auto-chaining is enabled, then the intermediate is sent.
+  SSL_CTX_clear_mode(ctx.get(), SSL_MODE_NO_AUTO_CHAIN);
+  if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+                              nullptr /* no session */)) {
+    return false;
+  }
+
+  if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()),
+                   {cert.get(), intermediate.get()})) {
+    fprintf(stderr, "Client-received chain did not match (auto-chaining).\n");
+    return false;
+  }
+
+  if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()),
+                   {cert.get(), intermediate.get()})) {
+    fprintf(stderr, "Server-received chain did not match (auto-chaining).\n");
+    return false;
+  }
+
+  // Auto-chaining does not override explicitly-configured intermediates.
+  if (!SSL_CTX_add1_chain_cert(ctx.get(), cert.get()) ||
+      !ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+                              nullptr /* no session */)) {
+    return false;
+  }
+
+  if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()),
+                   {cert.get(), cert.get()})) {
+    fprintf(stderr,
+            "Client-received chain did not match (auto-chaining, explicit "
+            "intermediate).\n");
+    return false;
+  }
+
+  if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()),
+                   {cert.get(), cert.get()})) {
+    fprintf(stderr,
+            "Server-received chain did not match (auto-chaining, explicit "
+            "intermediate).\n");
+    return false;
+  }
+
+  return true;
+}
+
+static bool ExpectBadWriteRetry() {
+  int err = ERR_get_error();
+  if (ERR_GET_LIB(err) != ERR_LIB_SSL ||
+      ERR_GET_REASON(err) != SSL_R_BAD_WRITE_RETRY) {
+    char buf[ERR_ERROR_STRING_BUF_LEN];
+    ERR_error_string_n(err, buf, sizeof(buf));
+    fprintf(stderr, "Wanted SSL_R_BAD_WRITE_RETRY, got: %s.\n", buf);
+    return false;
+  }
+
+  if (ERR_peek_error() != 0) {
+    fprintf(stderr, "Unexpected error following SSL_R_BAD_WRITE_RETRY.\n");
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestSSLWriteRetry(bool is_dtls, const SSL_METHOD *method,
+                              uint16_t version) {
+  if (is_dtls) {
+    return true;
+  }
+
+  for (bool enable_partial_write : std::vector<bool>{false, true}) {
+    // Connect a client and server.
+    bssl::UniquePtr<X509> cert = GetTestCertificate();
+    bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+    bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+    bssl::UniquePtr<SSL> client, server;
+    if (!cert || !key || !ctx ||
+        !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+        !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+        !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+        !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+        !ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+                                nullptr /* no session */)) {
+      return false;
+    }
+
+    if (enable_partial_write) {
+      SSL_set_mode(client.get(), SSL_MODE_ENABLE_PARTIAL_WRITE);
+    }
+
+    // Write without reading until the buffer is full and we have an unfinished
+    // write. Keep a count so we may reread it again later. "hello!" will be
+    // written in two chunks, "hello" and "!".
+    char data[] = "hello!";
+    static const int kChunkLen = 5;  // The length of "hello".
+    unsigned count = 0;
+    for (;;) {
+      int ret = SSL_write(client.get(), data, kChunkLen);
+      if (ret <= 0) {
+        int err = SSL_get_error(client.get(), ret);
+        if (SSL_get_error(client.get(), ret) == SSL_ERROR_WANT_WRITE) {
+          break;
+        }
+        fprintf(stderr, "SSL_write failed in unexpected way: %d\n", err);
+        return false;
+      }
+
+      if (ret != 5) {
+        fprintf(stderr, "SSL_write wrote %d bytes, expected 5.\n", ret);
+        return false;
+      }
+
+      count++;
+    }
+
+    // Retrying with the same parameters is legal.
+    if (SSL_get_error(client.get(), SSL_write(client.get(), data, kChunkLen)) !=
+        SSL_ERROR_WANT_WRITE) {
+      fprintf(stderr, "SSL_write retry unexpectedly failed.\n");
+      return false;
+    }
+
+    // Retrying with the same buffer but shorter length is not legal.
+    if (SSL_get_error(client.get(),
+                      SSL_write(client.get(), data, kChunkLen - 1)) !=
+            SSL_ERROR_SSL ||
+        !ExpectBadWriteRetry()) {
+      fprintf(stderr, "SSL_write retry did not fail as expected.\n");
+      return false;
+    }
+
+    // Retrying with a different buffer pointer is not legal.
+    char data2[] = "hello";
+    if (SSL_get_error(client.get(), SSL_write(client.get(), data2,
+                                              kChunkLen)) != SSL_ERROR_SSL ||
+        !ExpectBadWriteRetry()) {
+      fprintf(stderr, "SSL_write retry did not fail as expected.\n");
+      return false;
+    }
+
+    // With |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|, the buffer may move.
+    SSL_set_mode(client.get(), SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+    if (SSL_get_error(client.get(),
+                      SSL_write(client.get(), data2, kChunkLen)) !=
+        SSL_ERROR_WANT_WRITE) {
+      fprintf(stderr, "SSL_write retry unexpectedly failed.\n");
+      return false;
+    }
+
+    // |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER| does not disable length checks.
+    if (SSL_get_error(client.get(),
+                      SSL_write(client.get(), data2, kChunkLen - 1)) !=
+            SSL_ERROR_SSL ||
+        !ExpectBadWriteRetry()) {
+      fprintf(stderr, "SSL_write retry did not fail as expected.\n");
+      return false;
+    }
+
+    // Retrying with a larger buffer is legal.
+    if (SSL_get_error(client.get(),
+                      SSL_write(client.get(), data, kChunkLen + 1)) !=
+        SSL_ERROR_WANT_WRITE) {
+      fprintf(stderr, "SSL_write retry unexpectedly failed.\n");
+      return false;
+    }
+
+    // Drain the buffer.
+    char buf[20];
+    for (unsigned i = 0; i < count; i++) {
+      if (SSL_read(server.get(), buf, sizeof(buf)) != kChunkLen ||
+          OPENSSL_memcmp(buf, "hello", kChunkLen) != 0) {
+        fprintf(stderr, "Failed to read initial records.\n");
+        return false;
+      }
+    }
+
+    // Now that there is space, a retry with a larger buffer should flush the
+    // pending record, skip over that many bytes of input (on assumption they
+    // are the same), and write the remainder. If SSL_MODE_ENABLE_PARTIAL_WRITE
+    // is set, this will complete in two steps.
+    char data3[] = "_____!";
+    if (enable_partial_write) {
+      if (SSL_write(client.get(), data3, kChunkLen + 1) != kChunkLen ||
+          SSL_write(client.get(), data3 + kChunkLen, 1) != 1) {
+        fprintf(stderr, "SSL_write retry failed.\n");
+        return false;
+      }
+    } else if (SSL_write(client.get(), data3, kChunkLen + 1) != kChunkLen + 1) {
+      fprintf(stderr, "SSL_write retry failed.\n");
+      return false;
+    }
+
+    // Check the last write was correct. The data will be spread over two
+    // records, so SSL_read returns twice.
+    if (SSL_read(server.get(), buf, sizeof(buf)) != kChunkLen ||
+        OPENSSL_memcmp(buf, "hello", kChunkLen) != 0 ||
+        SSL_read(server.get(), buf, sizeof(buf)) != 1 ||
+        buf[0] != '!') {
+      fprintf(stderr, "Failed to read write retry.\n");
+      return false;
+    }
+  }
+
+  return true;
+}
+
 static bool ForEachVersion(bool (*test_func)(bool is_dtls,
                                              const SSL_METHOD *method,
                                              uint16_t version)) {
@@ -2814,7 +3206,9 @@
       !TestSetVersion() ||
       !ForEachVersion(TestVersion) ||
       !ForEachVersion(TestALPNCipherAvailable) ||
-      !ForEachVersion(TestSSLClearSessionResumption)) {
+      !ForEachVersion(TestSSLClearSessionResumption) ||
+      !ForEachVersion(TestAutoChain) ||
+      !ForEachVersion(TestSSLWriteRetry)) {
     ERR_print_errors_fp(stderr);
     return 1;
   }
diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c
index 70907e1..5e5c348 100644
--- a/src/ssl/t1_enc.c
+++ b/src/ssl/t1_enc.c
@@ -146,6 +146,7 @@
 #include <openssl/nid.h>
 #include <openssl/rand.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -231,7 +232,7 @@
     return 1;
   }
 
-  memset(out, 0, out_len);
+  OPENSSL_memset(out, 0, out_len);
 
   uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl);
   if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) {
@@ -528,12 +529,13 @@
     return 0;
   }
 
-  memcpy(seed, ssl->s3->client_random, SSL3_RANDOM_SIZE);
-  memcpy(seed + SSL3_RANDOM_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+  OPENSSL_memcpy(seed, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+  OPENSSL_memcpy(seed + SSL3_RANDOM_SIZE, ssl->s3->server_random,
+                 SSL3_RANDOM_SIZE);
   if (use_context) {
     seed[2 * SSL3_RANDOM_SIZE] = (uint8_t)(context_len >> 8);
     seed[2 * SSL3_RANDOM_SIZE + 1] = (uint8_t)context_len;
-    memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len);
+    OPENSSL_memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len);
   }
 
   int ret =
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index 4549fe2..0681919 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -205,7 +205,7 @@
 
 int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in,
                           size_t in_len) {
-  memset(out, 0, sizeof(*out));
+  OPENSSL_memset(out, 0, sizeof(*out));
   out->ssl = ssl;
   out->client_hello = in;
   out->client_hello_len = in_len;
@@ -308,9 +308,6 @@
     SSL_CURVE_X25519,
     SSL_CURVE_SECP256R1,
     SSL_CURVE_SECP384R1,
-#if defined(BORINGSSL_ANDROID_SYSTEM)
-    SSL_CURVE_SECP521R1,
-#endif
 };
 
 void tls1_get_grouplist(SSL *ssl, const uint16_t **out_group_ids,
@@ -464,8 +461,7 @@
 #endif
     SSL_SIGN_RSA_PKCS1_SHA384,
 
-    /* TODO(davidben): Remove this entry and SSL_CURVE_SECP521R1 from
-     * kDefaultGroups. */
+    /* TODO(davidben): Remove this. */
 #if defined(BORINGSSL_ANDROID_SYSTEM)
     SSL_SIGN_ECDSA_SECP521R1_SHA512,
 #endif
@@ -1510,8 +1506,9 @@
     }
 
     if (CBS_len(&client_protocol_name) == CBS_len(&protocol_name) &&
-        memcmp(CBS_data(&client_protocol_name), CBS_data(&protocol_name),
-               CBS_len(&protocol_name)) == 0) {
+        OPENSSL_memcmp(CBS_data(&client_protocol_name),
+                       CBS_data(&protocol_name),
+                       CBS_len(&protocol_name)) == 0) {
       protocol_ok = 1;
       break;
     }
@@ -1885,8 +1882,9 @@
 
   /* Per RFC 4492, section 5.1.2, implementations MUST support the uncompressed
    * point format. */
-  if (memchr(CBS_data(&ec_point_format_list), TLSEXT_ECPOINTFORMAT_uncompressed,
-             CBS_len(&ec_point_format_list)) == NULL) {
+  if (OPENSSL_memchr(CBS_data(&ec_point_format_list),
+                     TLSEXT_ECPOINTFORMAT_uncompressed,
+                     CBS_len(&ec_point_format_list)) == NULL) {
     *out_alert = SSL_AD_ILLEGAL_PARAMETER;
     return 0;
   }
@@ -2145,8 +2143,8 @@
   }
 
   /* We only support tickets with PSK_DHE_KE. */
-  hs->accept_psk_mode =
-      memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) != NULL;
+  hs->accept_psk_mode = OPENSSL_memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE,
+                                       CBS_len(&ke_modes)) != NULL;
 
   return 1;
 }
@@ -2347,7 +2345,7 @@
   uint8_t *secret = NULL;
   size_t secret_len;
   SSL_ECDH_CTX group;
-  memset(&group, 0, sizeof(SSL_ECDH_CTX));
+  OPENSSL_memset(&group, 0, sizeof(SSL_ECDH_CTX));
   CBB public_key;
   if (!CBB_init(&public_key, 32) ||
       !SSL_ECDH_CTX_init(&group, group_id) ||
@@ -2460,6 +2458,46 @@
 }
 
 
+/* Short record headers
+ *
+ * This is a non-standard extension which negotiates
+ * https://github.com/tlswg/tls13-spec/pull/762 for experimenting. */
+
+static int ext_short_header_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+  SSL *const ssl = hs->ssl;
+  uint16_t min_version, max_version;
+  if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+    return 0;
+  }
+
+  if (max_version < TLS1_3_VERSION ||
+      !ssl->ctx->short_header_enabled) {
+    return 1;
+  }
+
+  return CBB_add_u16(out, TLSEXT_TYPE_short_header) &&
+         CBB_add_u16(out, 0 /* empty extension */);
+}
+
+static int ext_short_header_parse_clienthello(SSL_HANDSHAKE *hs,
+                                              uint8_t *out_alert,
+                                              CBS *contents) {
+  SSL *const ssl = hs->ssl;
+  if (contents == NULL ||
+      !ssl->ctx->short_header_enabled ||
+      ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+    return 1;
+  }
+
+  if (CBS_len(contents) != 0) {
+    return 0;
+  }
+
+  ssl->s3->short_header = 1;
+  return 1;
+}
+
+
 /* Negotiated Groups
  *
  * https://tools.ietf.org/html/rfc4492#section-5.1.2
@@ -2690,6 +2728,14 @@
     ignore_parse_clienthello,
     dont_add_serverhello,
   },
+  {
+    TLSEXT_TYPE_short_header,
+    NULL,
+    ext_short_header_add_clienthello,
+    forbid_parse_serverhello,
+    ext_short_header_parse_clienthello,
+    dont_add_serverhello,
+  },
   /* The final extension must be non-empty. WebSphere Application Server 7.0 is
    * intolerant to the last extension being zero-length. See
    * https://crbug.com/363583. */
@@ -2824,7 +2870,7 @@
         goto err;
       }
 
-      memset(padding_bytes, 0, padding_len);
+      OPENSSL_memset(padding_bytes, 0, padding_len);
     }
   }
 
@@ -3187,8 +3233,8 @@
     }
   } else {
     /* Check the key name matches. */
-    if (memcmp(ticket, ssl_ctx->tlsext_tick_key_name,
-               SSL_TICKET_KEY_NAME_LEN) != 0) {
+    if (OPENSSL_memcmp(ticket, ssl_ctx->tlsext_tick_key_name,
+                       SSL_TICKET_KEY_NAME_LEN) != 0) {
       goto done;
     }
     if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key,
@@ -3231,7 +3277,7 @@
   }
   size_t plaintext_len;
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
-  memcpy(plaintext, ciphertext, ciphertext_len);
+  OPENSSL_memcpy(plaintext, ciphertext, ciphertext_len);
   plaintext_len = ciphertext_len;
 #else
   if (ciphertext_len >= INT_MAX) {
@@ -3256,7 +3302,7 @@
 
   /* Copy the client's session ID into the new session, to denote the ticket has
    * been accepted. */
-  memcpy(session->session_id, session_id, session_id_len);
+  OPENSSL_memcpy(session->session_id, session_id, session_id_len);
   session->session_id_length = session_id_len;
 
   *out_session = session;
@@ -3443,7 +3489,7 @@
     goto err;
   }
 
-  memcpy(ssl->s3->tlsext_channel_id, p, 64);
+  OPENSSL_memcpy(ssl->s3->tlsext_channel_id, p, 64);
   ret = 1;
 
 err:
diff --git a/src/ssl/test/async_bio.cc b/src/ssl/test/async_bio.cc
index 605b33a..fd35176 100644
--- a/src/ssl/test/async_bio.cc
+++ b/src/ssl/test/async_bio.cc
@@ -20,6 +20,8 @@
 #include <openssl/bio.h>
 #include <openssl/mem.h>
 
+#include "../../crypto/internal.h"
+
 
 namespace {
 
@@ -110,7 +112,7 @@
   if (a == NULL) {
     return 0;
   }
-  memset(a, 0, sizeof(*a));
+  OPENSSL_memset(a, 0, sizeof(*a));
   a->enforce_write_quota = true;
   bio->init = 1;
   bio->ptr = (char *)a;
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index a3903e2..a98ff43 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -330,8 +330,8 @@
     fprintf(stderr, "Output buffer too small.\n");
     return ssl_private_key_failure;
   }
-  memcpy(out, test_state->private_key_result.data(),
-         test_state->private_key_result.size());
+  OPENSSL_memcpy(out, test_state->private_key_result.data(),
+                 test_state->private_key_result.size());
   *out_len = test_state->private_key_result.size();
 
   test_state->private_key_result.clear();
@@ -498,9 +498,9 @@
     size_t certificate_types_len =
         SSL_get0_certificate_types(ssl, &certificate_types);
     if (certificate_types_len != config->expected_certificate_types.size() ||
-        memcmp(certificate_types,
-               config->expected_certificate_types.data(),
-               certificate_types_len) != 0) {
+        OPENSSL_memcmp(certificate_types,
+                       config->expected_certificate_types.data(),
+                       certificate_types_len) != 0) {
       fprintf(stderr, "certificate types mismatch\n");
       return false;
     }
@@ -626,8 +626,8 @@
 
   if (!config->expected_advertised_alpn.empty() &&
       (config->expected_advertised_alpn.size() != inlen ||
-       memcmp(config->expected_advertised_alpn.data(),
-              in, inlen) != 0)) {
+       OPENSSL_memcmp(config->expected_advertised_alpn.data(), in, inlen) !=
+           0)) {
     fprintf(stderr, "bad ALPN select callback inputs\n");
     exit(1);
   }
@@ -663,7 +663,7 @@
 
   BUF_strlcpy(out_identity, config->psk_identity.c_str(),
               max_identity_len);
-  memcpy(out_psk, config->psk.data(), config->psk.size());
+  OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
   return config->psk.size();
 }
 
@@ -681,7 +681,7 @@
     return 0;
   }
 
-  memcpy(out_psk, config->psk.data(), config->psk.size());
+  OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
   return config->psk.size();
 }
 
@@ -758,9 +758,9 @@
   static const uint8_t kZeros[16] = {0};
 
   if (encrypt) {
-    memcpy(key_name, kZeros, sizeof(kZeros));
+    OPENSSL_memcpy(key_name, kZeros, sizeof(kZeros));
     RAND_bytes(iv, 16);
-  } else if (memcmp(key_name, kZeros, 16) != 0) {
+  } else if (OPENSSL_memcmp(key_name, kZeros, 16) != 0) {
     return 0;
   }
 
@@ -824,7 +824,7 @@
   }
 
   if (contents_len != sizeof(kCustomExtensionContents) - 1 ||
-      memcmp(contents, kCustomExtensionContents, contents_len) != 0) {
+      OPENSSL_memcmp(contents, kCustomExtensionContents, contents_len) != 0) {
     *out_alert_value = SSL_AD_DECODE_ERROR;
     return 0;
   }
@@ -862,7 +862,7 @@
     return -1;
   }
   sockaddr_in sin;
-  memset(&sin, 0, sizeof(sin));
+  OPENSSL_memset(&sin, 0, sizeof(sin));
   sin.sin_family = AF_INET;
   sin.sin_port = htons(port);
   if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) {
@@ -928,17 +928,6 @@
     return nullptr;
   }
 
-  if (!config->cipher_tls10.empty() &&
-      !SSL_CTX_set_cipher_list_tls10(ssl_ctx.get(),
-                                     config->cipher_tls10.c_str())) {
-    return nullptr;
-  }
-  if (!config->cipher_tls11.empty() &&
-      !SSL_CTX_set_cipher_list_tls11(ssl_ctx.get(),
-                                     config->cipher_tls11.c_str())) {
-    return nullptr;
-  }
-
   bssl::UniquePtr<DH> dh(DH_get_2048_256(NULL));
   if (!dh) {
     return nullptr;
@@ -994,7 +983,6 @@
     SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
   }
 
-  SSL_CTX_set_tls_channel_id_enabled(ssl_ctx.get(), 1);
   SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
 
   SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
@@ -1053,6 +1041,14 @@
     return nullptr;
   }
 
+  if (config->enable_short_header) {
+    SSL_CTX_set_short_header_enabled(ssl_ctx.get(), 1);
+  }
+
+  if (config->enable_early_data) {
+    SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
+  }
+
   return ssl_ctx;
 }
 
@@ -1154,7 +1150,7 @@
     // SSL_peek should synchronously return the same data.
     int ret2 = SSL_peek(ssl, buf.get(), ret);
     if (ret2 != ret ||
-        memcmp(buf.get(), out, ret) != 0) {
+        OPENSSL_memcmp(buf.get(), out, ret) != 0) {
       fprintf(stderr, "First and second SSL_peek did not match.\n");
       return -1;
     }
@@ -1162,7 +1158,7 @@
     // SSL_read should synchronously return the same data and consume it.
     ret2 = SSL_read(ssl, buf.get(), ret);
     if (ret2 != ret ||
-        memcmp(buf.get(), out, ret) != 0) {
+        OPENSSL_memcmp(buf.get(), out, ret) != 0) {
       fprintf(stderr, "SSL_peek and SSL_read did not match.\n");
       return -1;
     }
@@ -1276,8 +1272,8 @@
     unsigned next_proto_len;
     SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
     if (next_proto_len != config->expected_next_proto.size() ||
-        memcmp(next_proto, config->expected_next_proto.data(),
-               next_proto_len) != 0) {
+        OPENSSL_memcmp(next_proto, config->expected_next_proto.data(),
+                       next_proto_len) != 0) {
       fprintf(stderr, "negotiated next proto mismatch\n");
       return false;
     }
@@ -1288,8 +1284,8 @@
     unsigned alpn_proto_len;
     SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len);
     if (alpn_proto_len != config->expected_alpn.size() ||
-        memcmp(alpn_proto, config->expected_alpn.data(),
-               alpn_proto_len) != 0) {
+        OPENSSL_memcmp(alpn_proto, config->expected_alpn.data(),
+                       alpn_proto_len) != 0) {
       fprintf(stderr, "negotiated alpn proto mismatch\n");
       return false;
     }
@@ -1302,8 +1298,8 @@
       return false;
     }
     if (config->expected_channel_id.size() != 64 ||
-        memcmp(config->expected_channel_id.data(),
-               channel_id, 64) != 0) {
+        OPENSSL_memcmp(config->expected_channel_id.data(), channel_id, 64) !=
+            0) {
       fprintf(stderr, "channel id mismatch\n");
       return false;
     }
@@ -1321,7 +1317,7 @@
     size_t len;
     SSL_get0_ocsp_response(ssl, &data, &len);
     if (config->expected_ocsp_response.size() != len ||
-        memcmp(config->expected_ocsp_response.data(), data, len) != 0) {
+        OPENSSL_memcmp(config->expected_ocsp_response.data(), data, len) != 0) {
       fprintf(stderr, "OCSP response mismatch\n");
       return false;
     }
@@ -1332,8 +1328,8 @@
     size_t len;
     SSL_get0_signed_cert_timestamp_list(ssl, &data, &len);
     if (config->expected_signed_cert_timestamps.size() != len ||
-        memcmp(config->expected_signed_cert_timestamps.data(),
-               data, len) != 0) {
+        OPENSSL_memcmp(config->expected_signed_cert_timestamps.data(), data,
+                       len) != 0) {
       fprintf(stderr, "SCT list mismatch\n");
       return false;
     }
@@ -1754,7 +1750,7 @@
     // trip up the CBC record splitting code.
     static const size_t kBufLen = 32769;
     std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufLen]);
-    memset(buf.get(), 0x42, kBufLen);
+    OPENSSL_memset(buf.get(), 0x42, kBufLen);
     static const size_t kRecordSizes[] = {
         0, 1, 255, 256, 257, 16383, 16384, 16385, 32767, 32768, 32769};
     for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kRecordSizes); i++) {
@@ -1768,6 +1764,19 @@
       }
     }
   } else {
+    if (config->read_with_unfinished_write) {
+      if (!config->async) {
+        fprintf(stderr, "-read-with-unfinished-write requires -async.\n");
+        return false;
+      }
+
+      int write_ret = SSL_write(ssl.get(),
+                          reinterpret_cast<const uint8_t *>("unfinished"), 10);
+      if (SSL_get_error(ssl.get(), write_ret) != SSL_ERROR_WANT_WRITE) {
+        fprintf(stderr, "Failed to leave unfinished write.\n");
+        return false;
+      }
+    }
     if (config->shim_writes_first) {
       if (WriteAll(ssl.get(), reinterpret_cast<const uint8_t *>("hello"),
                    5) < 0) {
@@ -1839,6 +1848,19 @@
               GetTestState(ssl.get())->got_new_session ? "" : " not");
       return false;
     }
+
+    if (expect_new_session) {
+      bool got_early_data_info =
+          GetTestState(ssl.get())->new_session->ticket_max_early_data != 0;
+      if (config->expect_early_data_info != got_early_data_info) {
+        fprintf(
+            stderr,
+            "new session did%s include ticket_early_data_info, but we expected "
+            "the opposite\n",
+            got_early_data_info ? "" : " not");
+        return false;
+      }
+    }
   }
 
   if (out_session) {
diff --git a/src/ssl/test/packeted_bio.cc b/src/ssl/test/packeted_bio.cc
index 8331b4b..835df0e 100644
--- a/src/ssl/test/packeted_bio.cc
+++ b/src/ssl/test/packeted_bio.cc
@@ -21,6 +21,8 @@
 
 #include <openssl/mem.h>
 
+#include "../../crypto/internal.h"
+
 
 namespace {
 
@@ -33,8 +35,8 @@
 struct PacketedBio {
   PacketedBio(timeval *clock_arg, bool advance_clock_arg)
       : clock(clock_arg), advance_clock(advance_clock_arg) {
-    memset(&timeout, 0, sizeof(timeout));
-    memset(&read_deadline, 0, sizeof(read_deadline));
+    OPENSSL_memset(&timeout, 0, sizeof(timeout));
+    OPENSSL_memset(&read_deadline, 0, sizeof(read_deadline));
   }
 
   bool HasTimeout() const {
@@ -209,7 +211,7 @@
     if (outl > (int)len) {
       outl = len;
     }
-    memcpy(out, buf, outl);
+    OPENSSL_memcpy(out, buf, outl);
     OPENSSL_free(buf);
     return outl;
   }
@@ -217,7 +219,7 @@
 
 static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) {
   if (cmd == BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT) {
-    memcpy(&GetData(bio)->read_deadline, ptr, sizeof(timeval));
+    OPENSSL_memcpy(&GetData(bio)->read_deadline, ptr, sizeof(timeval));
     return 1;
   }
 
@@ -290,6 +292,6 @@
   data->clock->tv_sec += data->clock->tv_usec / 1000000;
   data->clock->tv_usec %= 1000000;
   data->clock->tv_sec += data->timeout.tv_sec;
-  memset(&data->timeout, 0, sizeof(data->timeout));
+  OPENSSL_memset(&data->timeout, 0, sizeof(data->timeout));
   return true;
 }
diff --git a/src/ssl/test/runner/alert.go b/src/ssl/test/runner/alert.go
index 8320b7e..652e9ee 100644
--- a/src/ssl/test/runner/alert.go
+++ b/src/ssl/test/runner/alert.go
@@ -23,7 +23,7 @@
 	alertRecordOverflow         alert = 22
 	alertDecompressionFailure   alert = 30
 	alertHandshakeFailure       alert = 40
-	alertNoCertficate           alert = 41
+	alertNoCertificate          alert = 41
 	alertBadCertificate         alert = 42
 	alertUnsupportedCertificate alert = 43
 	alertCertificateRevoked     alert = 44
@@ -37,6 +37,7 @@
 	alertProtocolVersion        alert = 70
 	alertInsufficientSecurity   alert = 71
 	alertInternalError          alert = 80
+	alertInappropriateFallback  alert = 86
 	alertUserCanceled           alert = 90
 	alertNoRenegotiation        alert = 100
 	alertMissingExtension       alert = 109
@@ -55,6 +56,7 @@
 	alertRecordOverflow:         "record overflow",
 	alertDecompressionFailure:   "decompression failure",
 	alertHandshakeFailure:       "handshake failure",
+	alertNoCertificate:          "no certificate",
 	alertBadCertificate:         "bad certificate",
 	alertUnsupportedCertificate: "unsupported certificate",
 	alertCertificateRevoked:     "revoked certificate",
@@ -68,6 +70,7 @@
 	alertProtocolVersion:        "protocol version not supported",
 	alertInsufficientSecurity:   "insufficient security level",
 	alertInternalError:          "internal error",
+	alertInappropriateFallback:  "inappropriate fallback",
 	alertUserCanceled:           "user canceled",
 	alertNoRenegotiation:        "no renegotiation",
 	alertMissingExtension:       "missing extension",
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index f5fedb0..96bc39a 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -95,15 +95,12 @@
 	extensionSupportedVersions          uint16 = 43    // draft-ietf-tls-tls13-16
 	extensionCookie                     uint16 = 44    // draft-ietf-tls-tls13-16
 	extensionPSKKeyExchangeModes        uint16 = 45    // draft-ietf-tls-tls13-18
+	extensionTicketEarlyDataInfo        uint16 = 46    // draft-ietf-tls-tls13-18
 	extensionCustom                     uint16 = 1234  // not IANA assigned
 	extensionNextProtoNeg               uint16 = 13172 // not IANA assigned
 	extensionRenegotiationInfo          uint16 = 0xff01
 	extensionChannelID                  uint16 = 30032 // not IANA assigned
-)
-
-// TLS ticket extension numbers
-const (
-	ticketExtensionCustom uint16 = 1234 // not IANA assigned
+	extensionShortHeader                uint16 = 27463 // not IANA assigned
 )
 
 // TLS signaling cipher suite values
@@ -126,7 +123,8 @@
 // TLS Elliptic Curve Point Formats
 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
 const (
-	pointFormatUncompressed uint8 = 0
+	pointFormatUncompressed    uint8 = 0
+	pointFormatCompressedPrime uint8 = 1
 )
 
 // TLS CertificateStatusType (RFC 3546)
@@ -225,6 +223,7 @@
 	SCTList                    []byte                // signed certificate timestamp list
 	PeerSignatureAlgorithm     signatureAlgorithm    // algorithm used by the peer in the handshake
 	CurveID                    CurveID               // the curve used in ECDHE
+	ShortHeader                bool                  // whether the short header extension was negotiated
 }
 
 // ClientAuthType declares the policy the server will follow for
@@ -956,6 +955,19 @@
 	// receipt of a NewSessionTicket message.
 	ExpectNoNewSessionTicket bool
 
+	// SendTicketEarlyDataInfo, if non-zero, is the maximum amount of data that we
+	// will accept as early data, and gets sent in the ticket_early_data_info
+	// extension of the NewSessionTicket message.
+	SendTicketEarlyDataInfo uint32
+
+	// DuplicateTicketEarlyDataInfo causes an extra empty extension of
+	// ticket_early_data_info to be sent in NewSessionTicket.
+	DuplicateTicketEarlyDataInfo bool
+
+	// ExpectTicketEarlyDataInfo, if true, means that the client will fail upon
+	// absence of the ticket_early_data_info extension.
+	ExpectTicketEarlyDataInfo bool
+
 	// ExpectTicketAge, if non-zero, is the expected age of the ticket that the
 	// server receives from the client.
 	ExpectTicketAge time.Duration
@@ -1224,6 +1236,23 @@
 	// NoSignedCertificateTimestamps, if true, causes the client to not
 	// request signed certificate timestamps.
 	NoSignedCertificateTimestamps bool
+
+	// EnableShortHeader, if true, causes the TLS 1.3 short header extension
+	// to be enabled.
+	EnableShortHeader bool
+
+	// AlwaysNegotiateShortHeader, if true, causes the server to always
+	// negotiate the short header extension in ServerHello.
+	AlwaysNegotiateShortHeader bool
+
+	// ClearShortHeaderBit, if true, causes the server to send short headers
+	// without the high bit set.
+	ClearShortHeaderBit bool
+
+	// SendSupportedPointFormats, if not nil, is the list of supported point
+	// formats to send in ClientHello or ServerHello. If set to a non-nil
+	// empty slice, no extension will be sent.
+	SendSupportedPointFormats []byte
 }
 
 func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 80a5b06..ee342fa 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -21,6 +21,8 @@
 	"time"
 )
 
+var errNoCertificateAlert = errors.New("tls: no certificate alert")
+
 // A Conn represents a secured connection.
 // It implements the net.Conn interface.
 type Conn struct {
@@ -163,6 +165,8 @@
 
 	trafficSecret []byte
 
+	shortHeader bool
+
 	config *Config
 }
 
@@ -301,10 +305,17 @@
 	copy(hc.outSeq[:], hc.seq[:])
 }
 
+func (hc *halfConn) isShortHeader() bool {
+	return hc.shortHeader && hc.cipher != nil
+}
+
 func (hc *halfConn) recordHeaderLen() int {
 	if hc.isDTLS {
 		return dtlsRecordHeaderLen
 	}
+	if hc.isShortHeader() {
+		return 2
+	}
 	return tlsRecordHeaderLen
 }
 
@@ -608,6 +619,9 @@
 	n := len(b.data) - recordHeaderLen
 	b.data[recordHeaderLen-2] = byte(n >> 8)
 	b.data[recordHeaderLen-1] = byte(n)
+	if hc.isShortHeader() && !hc.config.Bugs.ClearShortHeaderBit {
+		b.data[0] |= 0x80
+	}
 	hc.incSeq(true)
 
 	return true, 0
@@ -716,7 +730,7 @@
 		return c.dtlsDoReadRecord(want)
 	}
 
-	recordHeaderLen := tlsRecordHeaderLen
+	recordHeaderLen := c.in.recordHeaderLen()
 
 	if c.rawInput == nil {
 		c.rawInput = c.in.newBlock()
@@ -736,19 +750,36 @@
 		}
 		return 0, nil, err
 	}
-	typ := recordType(b.data[0])
 
-	// No valid TLS record has a type of 0x80, however SSLv2 handshakes
-	// start with a uint16 length where the MSB is set and the first record
-	// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
-	// an SSLv2 client.
-	if want == recordTypeHandshake && typ == 0x80 {
-		c.sendAlert(alertProtocolVersion)
-		return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
+	var typ recordType
+	var vers uint16
+	var n int
+	if c.in.isShortHeader() {
+		typ = recordTypeApplicationData
+		vers = VersionTLS10
+		n = int(b.data[0])<<8 | int(b.data[1])
+		if n&0x8000 == 0 {
+			c.sendAlert(alertDecodeError)
+			return 0, nil, c.in.setErrorLocked(errors.New("tls: length did not have high bit set"))
+		}
+
+		n = n & 0x7fff
+	} else {
+		typ = recordType(b.data[0])
+
+		// No valid TLS record has a type of 0x80, however SSLv2 handshakes
+		// start with a uint16 length where the MSB is set and the first record
+		// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+		// an SSLv2 client.
+		if want == recordTypeHandshake && typ == 0x80 {
+			c.sendAlert(alertProtocolVersion)
+			return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
+		}
+
+		vers = uint16(b.data[1])<<8 | uint16(b.data[2])
+		n = int(b.data[3])<<8 | int(b.data[4])
 	}
 
-	vers := uint16(b.data[1])<<8 | uint16(b.data[2])
-	n := int(b.data[3])<<8 | int(b.data[4])
 	// Alerts sent near version negotiation do not have a well-defined
 	// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
 	// version is irrelevant.)
@@ -866,6 +897,11 @@
 		}
 		switch data[0] {
 		case alertLevelWarning:
+			if alert(data[1]) == alertNoCertificate {
+				c.in.freeBlock(b)
+				return errNoCertificateAlert
+			}
+
 			// drop on the floor
 			c.in.freeBlock(b)
 			goto Again
@@ -934,7 +970,7 @@
 // L < c.out.Mutex.
 func (c *Conn) sendAlert(err alert) error {
 	level := byte(alertLevelError)
-	if err == alertNoRenegotiation || err == alertCloseNotify || err == alertNoCertficate {
+	if err == alertNoRenegotiation || err == alertCloseNotify || err == alertNoCertificate {
 		level = alertLevelWarning
 	}
 	return c.SendAlert(level, err)
@@ -1007,7 +1043,7 @@
 }
 
 func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
-	recordHeaderLen := tlsRecordHeaderLen
+	recordHeaderLen := c.out.recordHeaderLen()
 	b := c.out.newBlock()
 	first := true
 	isClientHello := typ == recordTypeHandshake && len(data) > 0 && data[0] == typeClientHello
@@ -1049,32 +1085,36 @@
 			}
 		}
 		b.resize(recordHeaderLen + explicitIVLen + m)
-		b.data[0] = byte(typ)
-		if c.vers >= VersionTLS13 && c.out.cipher != nil {
-			b.data[0] = byte(recordTypeApplicationData)
-			if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
-				b.data[0] = byte(outerType)
+		// If using a short record header, the length will be filled in
+		// by encrypt.
+		if !c.out.isShortHeader() {
+			b.data[0] = byte(typ)
+			if c.vers >= VersionTLS13 && c.out.cipher != nil {
+				b.data[0] = byte(recordTypeApplicationData)
+				if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
+					b.data[0] = byte(outerType)
+				}
 			}
+			vers := c.vers
+			if vers == 0 || vers >= VersionTLS13 {
+				// Some TLS servers fail if the record version is
+				// greater than TLS 1.0 for the initial ClientHello.
+				//
+				// TLS 1.3 fixes the version number in the record
+				// layer to {3, 1}.
+				vers = VersionTLS10
+			}
+			if c.config.Bugs.SendRecordVersion != 0 {
+				vers = c.config.Bugs.SendRecordVersion
+			}
+			if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
+				vers = c.config.Bugs.SendInitialRecordVersion
+			}
+			b.data[1] = byte(vers >> 8)
+			b.data[2] = byte(vers)
+			b.data[3] = byte(m >> 8)
+			b.data[4] = byte(m)
 		}
-		vers := c.vers
-		if vers == 0 || vers >= VersionTLS13 {
-			// Some TLS servers fail if the record version is
-			// greater than TLS 1.0 for the initial ClientHello.
-			//
-			// TLS 1.3 fixes the version number in the record
-			// layer to {3, 1}.
-			vers = VersionTLS10
-		}
-		if c.config.Bugs.SendRecordVersion != 0 {
-			vers = c.config.Bugs.SendRecordVersion
-		}
-		if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
-			vers = c.config.Bugs.SendInitialRecordVersion
-		}
-		b.data[1] = byte(vers >> 8)
-		b.data[2] = byte(vers)
-		b.data[3] = byte(m >> 8)
-		b.data[4] = byte(m)
 		if explicitIVLen > 0 {
 			explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
 			if explicitIVIsSeq {
@@ -1162,6 +1202,13 @@
 // c.in.Mutex < L; c.out.Mutex < L.
 func (c *Conn) readHandshake() (interface{}, error) {
 	data, err := c.doReadHandshake()
+	if err == errNoCertificateAlert {
+		if c.hand.Len() != 0 {
+			// The warning alert may not interleave with a handshake message.
+			return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		return new(ssl3NoCertificateMsg), nil
+	}
 	if err != nil {
 		return nil, err
 	}
@@ -1404,6 +1451,10 @@
 				return errors.New("tls: no GREASE ticket extension found")
 			}
 
+			if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.earlyDataInfo == 0 {
+				return errors.New("tls: no ticket_early_data_info extension found")
+			}
+
 			if c.config.Bugs.ExpectNoNewSessionTicket {
 				return errors.New("tls: received unexpected NewSessionTicket")
 			}
@@ -1620,6 +1671,7 @@
 		state.SCTList = c.sctList
 		state.PeerSignatureAlgorithm = c.peerSignatureAlgorithm
 		state.CurveID = c.curveID
+		state.ShortHeader = c.in.shortHeader
 	}
 
 	return state
@@ -1715,10 +1767,12 @@
 
 	// TODO(davidben): Allow configuring these values.
 	m := &newSessionTicketMsg{
-		version:         c.vers,
-		ticketLifetime:  uint32(24 * time.Hour / time.Second),
-		customExtension: c.config.Bugs.CustomTicketExtension,
-		ticketAgeAdd:    ticketAgeAdd,
+		version:                c.vers,
+		ticketLifetime:         uint32(24 * time.Hour / time.Second),
+		earlyDataInfo:          c.config.Bugs.SendTicketEarlyDataInfo,
+		duplicateEarlyDataInfo: c.config.Bugs.DuplicateTicketEarlyDataInfo,
+		customExtension:        c.config.Bugs.CustomTicketExtension,
+		ticketAgeAdd:           ticketAgeAdd,
 	}
 
 	state := sessionState{
@@ -1781,3 +1835,8 @@
 	_, err := c.conn.Write(payload)
 	return err
 }
+
+func (c *Conn) setShortHeader() {
+	c.in.shortHeader = true
+	c.out.shortHeader = true
+}
diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json
index cb2befa..80a9bf1 100644
--- a/src/ssl/test/runner/fuzzer_mode.json
+++ b/src/ssl/test/runner/fuzzer_mode.json
@@ -25,12 +25,15 @@
     "ECDSACurveMismatch-Verify-TLS13": "Fuzzer mode always accepts a signature.",
     "InvalidChannelIDSignature-*": "Fuzzer mode always accepts a signature.",
 
+    "Resume-Server-CipherNotPreferred*": "Fuzzer mode does not encrypt tickets.",
     "Resume-Server-DeclineBadCipher*": "Fuzzer mode does not encrypt tickets.",
     "Resume-Server-DeclineCrossVersion*": "Fuzzer mode does not encrypt tickets.",
     "TicketCallback-SingleCall-*": "Fuzzer mode does not encrypt tickets.",
     "CorruptTicket-*": "Fuzzer mode does not encrypt tickets.",
     "ShimTicketRewritable": "Fuzzer mode does not encrypt tickets.",
 
-    "Resume-Server-*Binder*": "Fuzzer mode does not check binders."
+    "Resume-Server-*Binder*": "Fuzzer mode does not check binders.",
+
+    "SkipEarlyData*": "Trial decryption does not work with the NULL cipher."
   }
 }
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 7fa7ea2..507ea40 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -81,6 +81,7 @@
 		srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
 		customExtension:         c.config.Bugs.CustomExtension,
 		pskBinderFirst:          c.config.Bugs.PSKBinderFirst,
+		shortHeaderSupported:    c.config.Bugs.EnableShortHeader,
 	}
 
 	disableEMS := c.config.Bugs.NoExtendedMasterSecret
@@ -104,6 +105,10 @@
 		hello.compressionMethods = c.config.Bugs.SendCompressionMethods
 	}
 
+	if c.config.Bugs.SendSupportedPointFormats != nil {
+		hello.supportedPoints = c.config.Bugs.SendSupportedPointFormats
+	}
+
 	if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo {
 		if c.config.Bugs.BadRenegotiationInfo {
 			hello.secureRenegotiation = append(hello.secureRenegotiation, c.clientVerify...)
@@ -684,6 +689,18 @@
 		hs.finishedHash.addEntropy(zeroSecret)
 	}
 
+	if hs.serverHello.shortHeader && !hs.hello.shortHeaderSupported {
+		return errors.New("tls: server sent unsolicited short header extension")
+	}
+
+	if hs.serverHello.shortHeader && hs.hello.hasEarlyData {
+		return errors.New("tls: server sent short header extension in response to early data")
+	}
+
+	if hs.serverHello.shortHeader {
+		c.setShortHeader()
+	}
+
 	// Switch to handshake traffic keys.
 	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
 	c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
@@ -1011,7 +1028,7 @@
 	// no_certificate warning alert.
 	if certRequested {
 		if c.vers == VersionSSL30 && chainToSend == nil {
-			c.sendAlert(alertNoCertficate)
+			c.sendAlert(alertNoCertificate)
 		} else if !c.config.Bugs.SkipClientCertificate {
 			certMsg := new(certificateMsg)
 			if chainToSend != nil {
@@ -1291,6 +1308,10 @@
 func (hs *clientHandshakeState) processServerHello() (bool, error) {
 	c := hs.c
 
+	if hs.serverHello.shortHeader {
+		return false, errors.New("tls: short header extension sent before TLS 1.3")
+	}
+
 	if hs.serverResumedSession() {
 		// For test purposes, assert that the server never accepts the
 		// resumption offer on renegotiation.
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 8a338f0..62309b8 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -167,6 +167,7 @@
 	customExtension         string
 	hasGREASEExtension      bool
 	pskBinderFirst          bool
+	shortHeaderSupported    bool
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -212,7 +213,8 @@
 		m.sctListSupported == m1.sctListSupported &&
 		m.customExtension == m1.customExtension &&
 		m.hasGREASEExtension == m1.hasGREASEExtension &&
-		m.pskBinderFirst == m1.pskBinderFirst
+		m.pskBinderFirst == m1.pskBinderFirst &&
+		m.shortHeaderSupported == m1.shortHeaderSupported
 }
 
 func (m *clientHelloMsg) marshal() []byte {
@@ -314,9 +316,7 @@
 		extensions.addU16(extensionSupportedPoints)
 		supportedPointsList := extensions.addU16LengthPrefixed()
 		supportedPoints := supportedPointsList.addU8LengthPrefixed()
-		for _, pointFormat := range m.supportedPoints {
-			supportedPoints.addU8(pointFormat)
-		}
+		supportedPoints.addBytes(m.supportedPoints)
 	}
 	if m.hasKeyShares {
 		extensions.addU16(extensionKeyShare)
@@ -430,6 +430,10 @@
 		customExt := extensions.addU16LengthPrefixed()
 		customExt.addBytes([]byte(m.customExtension))
 	}
+	if m.shortHeaderSupported {
+		extensions.addU16(extensionShortHeader)
+		extensions.addU16(0) // Length is always 0
+	}
 	// The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
 	if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
 		extensions.addU16(extensionPreSharedKey)
@@ -601,8 +605,7 @@
 			if length != l+1 {
 				return false
 			}
-			m.supportedPoints = make([]uint8, l)
-			copy(m.supportedPoints, data[1:])
+			m.supportedPoints = data[1 : 1+l]
 		case extensionSessionTicket:
 			// http://tools.ietf.org/html/rfc5077#section-3.2
 			m.ticketSupported = true
@@ -802,6 +805,11 @@
 				return false
 			}
 			m.sctListSupported = true
+		case extensionShortHeader:
+			if length != 0 {
+				return false
+			}
+			m.shortHeaderSupported = true
 		case extensionCustom:
 			m.customExtension = string(data[:length])
 		}
@@ -831,6 +839,7 @@
 	compressionMethod   uint8
 	customExtension     string
 	unencryptedALPN     string
+	shortHeader         bool
 	extensions          serverExtensions
 }
 
@@ -868,6 +877,11 @@
 
 	extensions := hello.addU16LengthPrefixed()
 
+	if m.shortHeader {
+		extensions.addU16(extensionShortHeader)
+		extensions.addU16(0) // Length
+	}
+
 	if vers >= VersionTLS13 {
 		if m.hasKeyShare {
 			extensions.addU16(extensionKeyShare)
@@ -996,6 +1010,11 @@
 					return false
 				}
 				m.earlyDataIndication = true
+			case extensionShortHeader:
+				if len(d) != 0 {
+					return false
+				}
+				m.shortHeader = true
 			default:
 				// Only allow the 3 extensions that are sent in
 				// the clear in TLS 1.3.
@@ -1071,6 +1090,7 @@
 	npnAfterAlpn            bool
 	hasKeyShare             bool
 	keyShare                keyShareEntry
+	supportedPoints         []uint8
 }
 
 func (m *serverExtensions) marshal(extensions *byteBuilder) {
@@ -1165,6 +1185,13 @@
 		keyExchange := keyShare.addU16LengthPrefixed()
 		keyExchange.addBytes(m.keyShare.keyExchange)
 	}
+	if len(m.supportedPoints) > 0 {
+		// http://tools.ietf.org/html/rfc4492#section-5.1.2
+		extensions.addU16(extensionSupportedPoints)
+		supportedPointsList := extensions.addU16LengthPrefixed()
+		supportedPoints := supportedPointsList.addU8LengthPrefixed()
+		supportedPoints.addBytes(m.supportedPoints)
+	}
 }
 
 func (m *serverExtensions) unmarshal(data []byte, version uint16) bool {
@@ -1265,7 +1292,15 @@
 			if version >= VersionTLS13 {
 				return false
 			}
-			// Ignore this extension from the server.
+			// http://tools.ietf.org/html/rfc4492#section-5.5.2
+			if length < 1 {
+				return false
+			}
+			l := int(data[0])
+			if length != l+1 {
+				return false
+			}
+			m.supportedPoints = data[1 : 1+l]
 		case extensionSupportedCurves:
 			// The server can only send supported_curves in TLS 1.3.
 			if version < VersionTLS13 {
@@ -1968,13 +2003,15 @@
 }
 
 type newSessionTicketMsg struct {
-	raw                []byte
-	version            uint16
-	ticketLifetime     uint32
-	ticketAgeAdd       uint32
-	ticket             []byte
-	customExtension    string
-	hasGREASEExtension bool
+	raw                    []byte
+	version                uint16
+	ticketLifetime         uint32
+	ticketAgeAdd           uint32
+	ticket                 []byte
+	earlyDataInfo          uint32
+	customExtension        string
+	duplicateEarlyDataInfo bool
+	hasGREASEExtension     bool
 }
 
 func (m *newSessionTicketMsg) marshal() []byte {
@@ -1996,8 +2033,16 @@
 
 	if m.version >= VersionTLS13 {
 		extensions := body.addU16LengthPrefixed()
+		if m.earlyDataInfo > 0 {
+			extensions.addU16(extensionTicketEarlyDataInfo)
+			extensions.addU16LengthPrefixed().addU32(m.earlyDataInfo)
+			if m.duplicateEarlyDataInfo {
+				extensions.addU16(extensionTicketEarlyDataInfo)
+				extensions.addU16LengthPrefixed().addU32(m.earlyDataInfo)
+			}
+		}
 		if len(m.customExtension) > 0 {
-			extensions.addU16(ticketExtensionCustom)
+			extensions.addU16(extensionCustom)
 			extensions.addU16LengthPrefixed().addBytes([]byte(m.customExtension))
 		}
 	}
@@ -2043,28 +2088,37 @@
 		if len(data) < 2 {
 			return false
 		}
-		extsLength := int(data[0])<<8 + int(data[1])
+
+		extensionsLength := int(data[0])<<8 | int(data[1])
 		data = data[2:]
-		if len(data) < extsLength {
+		if extensionsLength != len(data) {
 			return false
 		}
-		extensions := data[:extsLength]
-		data = data[extsLength:]
 
-		for len(extensions) > 0 {
-			if len(extensions) < 4 {
+		for len(data) != 0 {
+			if len(data) < 4 {
 				return false
 			}
-			extValue := uint16(extensions[0])<<8 | uint16(extensions[1])
-			extLength := int(extensions[2])<<8 | int(extensions[3])
-			if len(extensions) < 4+extLength {
+			extension := uint16(data[0])<<8 | uint16(data[1])
+			length := int(data[2])<<8 | int(data[3])
+			data = data[4:]
+			if len(data) < length {
 				return false
 			}
-			extensions = extensions[4+extLength:]
 
-			if isGREASEValue(extValue) {
-				m.hasGREASEExtension = true
+			switch extension {
+			case extensionTicketEarlyDataInfo:
+				if length != 4 {
+					return false
+				}
+				m.earlyDataInfo = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+			default:
+				if isGREASEValue(extension) {
+					m.hasGREASEExtension = true
+				}
 			}
+
+			data = data[length:]
 		}
 	}
 
@@ -2240,6 +2294,10 @@
 	return m.keyUpdateRequest == keyUpdateNotRequested || m.keyUpdateRequest == keyUpdateRequested
 }
 
+// ssl3NoCertificateMsg is a dummy message to handle SSL 3.0 using a warning
+// alert in the handshake.
+type ssl3NoCertificateMsg struct{}
+
 func eqUint16s(x, y []uint16) bool {
 	if len(x) != len(y) {
 		return false
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 57566c5..1116d6c 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -365,6 +365,15 @@
 		versOverride:    config.Bugs.SendServerHelloVersion,
 		customExtension: config.Bugs.CustomUnencryptedExtension,
 		unencryptedALPN: config.Bugs.SendUnencryptedALPN,
+		shortHeader:     hs.clientHello.shortHeaderSupported && config.Bugs.EnableShortHeader,
+	}
+
+	if config.Bugs.AlwaysNegotiateShortHeader {
+		hs.hello.shortHeader = true
+	}
+
+	if hs.hello.shortHeader {
+		c.setShortHeader()
 	}
 
 	hs.hello.random = make([]byte, 32)
@@ -972,6 +981,7 @@
 		vers:              versionToWire(c.vers, c.isDTLS),
 		versOverride:      config.Bugs.SendServerHelloVersion,
 		compressionMethod: compressionNone,
+		shortHeader:       config.Bugs.AlwaysNegotiateShortHeader,
 	}
 
 	hs.hello.random = make([]byte, 32)
@@ -1182,6 +1192,10 @@
 		serverExtensions.ticketSupported = true
 	}
 
+	if c.config.Bugs.SendSupportedPointFormats != nil {
+		serverExtensions.supportedPoints = c.config.Bugs.SendSupportedPointFormats
+	}
+
 	if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE {
 		return errors.New("tls: no GREASE extension found")
 	}
@@ -1438,7 +1452,13 @@
 			for _, cert := range certMsg.certificates {
 				certificates = append(certificates, cert.data)
 			}
-		} else if c.vers != VersionSSL30 {
+		} else if c.vers == VersionSSL30 {
+			// In SSL 3.0, no certificate is signaled by a warning
+			// alert which we translate to ssl3NoCertificateMsg.
+			if _, ok := msg.(*ssl3NoCertificateMsg); !ok {
+				return errors.New("tls: client provided neither a certificate nor no_certificate warning alert")
+			}
+		} else {
 			// In TLS, the Certificate message is required. In SSL
 			// 3.0, the peer skips it when sending no certificates.
 			c.sendAlert(alertUnexpectedMessage)
@@ -1459,11 +1479,9 @@
 			return err
 		}
 
-		if ok {
-			msg, err = c.readHandshake()
-			if err != nil {
-				return err
-			}
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
 		}
 	}
 
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index fc66cf6..ba78fce 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -383,6 +383,8 @@
 	// expectPeerCertificate, if not nil, is the certificate chain the peer
 	// is expected to send.
 	expectPeerCertificate *Certificate
+	// expectShortHeader is whether the short header extension should be negotiated.
+	expectShortHeader bool
 }
 
 var testCases []testCase
@@ -611,6 +613,10 @@
 		}
 	}
 
+	if test.expectShortHeader != connState.ShortHeader {
+		return fmt.Errorf("ShortHeader is %t, but we expected the opposite", connState.ShortHeader)
+	}
+
 	if test.exportKeyingMaterial > 0 {
 		actual := make([]byte, test.exportKeyingMaterial)
 		if _, err := io.ReadFull(tlsConn, actual); err != nil {
@@ -1315,13 +1321,15 @@
 					SendFallbackSCSV: true,
 				},
 			},
-			shouldFail:    true,
-			expectedError: ":INAPPROPRIATE_FALLBACK:",
+			shouldFail:         true,
+			expectedError:      ":INAPPROPRIATE_FALLBACK:",
+			expectedLocalError: "remote error: inappropriate fallback",
 		},
 		{
 			testType: serverTest,
-			name:     "FallbackSCSV-VersionMatch",
+			name:     "FallbackSCSV-VersionMatch-TLS13",
 			config: Config{
+				MaxVersion: VersionTLS13,
 				Bugs: ProtocolBugs{
 					SendFallbackSCSV: true,
 				},
@@ -2561,11 +2569,57 @@
 		expectedError: expectedClientError,
 	})
 
-	if !shouldClientFail {
-		// Ensure the maximum record size is accepted.
+	if shouldClientFail {
+		return
+	}
+
+	// Ensure the maximum record size is accepted.
+	testCases = append(testCases, testCase{
+		protocol: protocol,
+		name:     prefix + ver.name + "-" + suite.name + "-LargeRecord",
+		config: Config{
+			MinVersion:           ver.version,
+			MaxVersion:           ver.version,
+			CipherSuites:         []uint16{suite.id},
+			Certificates:         []Certificate{cert},
+			PreSharedKey:         []byte(psk),
+			PreSharedKeyIdentity: pskIdentity,
+		},
+		flags:      flags,
+		messageLen: maxPlaintext,
+	})
+
+	// Test bad records for all ciphers. Bad records are fatal in TLS
+	// and ignored in DTLS.
+	var shouldFail bool
+	var expectedError string
+	if protocol == tls {
+		shouldFail = true
+		expectedError = ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:"
+	}
+
+	testCases = append(testCases, testCase{
+		protocol: protocol,
+		name:     prefix + ver.name + "-" + suite.name + "-BadRecord",
+		config: Config{
+			MinVersion:           ver.version,
+			MaxVersion:           ver.version,
+			CipherSuites:         []uint16{suite.id},
+			Certificates:         []Certificate{cert},
+			PreSharedKey:         []byte(psk),
+			PreSharedKeyIdentity: pskIdentity,
+		},
+		flags:            flags,
+		damageFirstWrite: true,
+		messageLen:       maxPlaintext,
+		shouldFail:       shouldFail,
+		expectedError:    expectedError,
+	})
+
+	if ver.version >= VersionTLS13 {
 		testCases = append(testCases, testCase{
 			protocol: protocol,
-			name:     prefix + ver.name + "-" + suite.name + "-LargeRecord",
+			name:     prefix + ver.name + "-" + suite.name + "-ShortHeader",
 			config: Config{
 				MinVersion:           ver.version,
 				MaxVersion:           ver.version,
@@ -2573,36 +2627,13 @@
 				Certificates:         []Certificate{cert},
 				PreSharedKey:         []byte(psk),
 				PreSharedKeyIdentity: pskIdentity,
+				Bugs: ProtocolBugs{
+					EnableShortHeader: true,
+				},
 			},
-			flags:      flags,
-			messageLen: maxPlaintext,
-		})
-
-		// Test bad records for all ciphers. Bad records are fatal in TLS
-		// and ignored in DTLS.
-		var shouldFail bool
-		var expectedError string
-		if protocol == tls {
-			shouldFail = true
-			expectedError = ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:"
-		}
-
-		testCases = append(testCases, testCase{
-			protocol: protocol,
-			name:     prefix + ver.name + "-" + suite.name + "-BadRecord",
-			config: Config{
-				MinVersion:           ver.version,
-				MaxVersion:           ver.version,
-				CipherSuites:         []uint16{suite.id},
-				Certificates:         []Certificate{cert},
-				PreSharedKey:         []byte(psk),
-				PreSharedKeyIdentity: pskIdentity,
-			},
-			flags:            flags,
-			damageFirstWrite: true,
-			messageLen:       maxPlaintext,
-			shouldFail:       shouldFail,
-			expectedError:    expectedError,
+			flags:             append([]string{"-enable-short-header"}, flags...),
+			resumeSession:     true,
+			expectShortHeader: true,
 		})
 	}
 }
@@ -2774,94 +2805,6 @@
 		},
 		flags: []string{"-psk", "secret"},
 	})
-
-	// versionSpecificCiphersTest specifies a test for the TLS 1.0 and TLS
-	// 1.1 specific cipher suite settings. A server is setup with the given
-	// cipher lists and then a connection is made for each member of
-	// expectations. The cipher suite that the server selects must match
-	// the specified one.
-	var versionSpecificCiphersTest = []struct {
-		ciphersDefault, ciphersTLS10, ciphersTLS11 string
-		// expectations is a map from TLS version to cipher suite id.
-		expectations map[uint16]uint16
-	}{
-		{
-			// Test that the null case (where no version-specific ciphers are set)
-			// works as expected.
-			"DES-CBC3-SHA:AES128-SHA", // default ciphers
-			"", // no ciphers specifically for TLS ≥ 1.0
-			"", // no ciphers specifically for TLS ≥ 1.1
-			map[uint16]uint16{
-				VersionSSL30: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-				VersionTLS10: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-				VersionTLS11: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-				VersionTLS12: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-			},
-		},
-		{
-			// With ciphers_tls10 set, TLS 1.0, 1.1 and 1.2 should get a different
-			// cipher.
-			"DES-CBC3-SHA:AES128-SHA", // default
-			"AES128-SHA",              // these ciphers for TLS ≥ 1.0
-			"",                        // no ciphers specifically for TLS ≥ 1.1
-			map[uint16]uint16{
-				VersionSSL30: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-				VersionTLS10: TLS_RSA_WITH_AES_128_CBC_SHA,
-				VersionTLS11: TLS_RSA_WITH_AES_128_CBC_SHA,
-				VersionTLS12: TLS_RSA_WITH_AES_128_CBC_SHA,
-			},
-		},
-		{
-			// With ciphers_tls11 set, TLS 1.1 and 1.2 should get a different
-			// cipher.
-			"DES-CBC3-SHA:AES128-SHA", // default
-			"",           // no ciphers specifically for TLS ≥ 1.0
-			"AES128-SHA", // these ciphers for TLS ≥ 1.1
-			map[uint16]uint16{
-				VersionSSL30: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-				VersionTLS10: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-				VersionTLS11: TLS_RSA_WITH_AES_128_CBC_SHA,
-				VersionTLS12: TLS_RSA_WITH_AES_128_CBC_SHA,
-			},
-		},
-		{
-			// With both ciphers_tls10 and ciphers_tls11 set, ciphers_tls11 should
-			// mask ciphers_tls10 for TLS 1.1 and 1.2.
-			"DES-CBC3-SHA:AES128-SHA", // default
-			"AES128-SHA",              // these ciphers for TLS ≥ 1.0
-			"AES256-SHA",              // these ciphers for TLS ≥ 1.1
-			map[uint16]uint16{
-				VersionSSL30: TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-				VersionTLS10: TLS_RSA_WITH_AES_128_CBC_SHA,
-				VersionTLS11: TLS_RSA_WITH_AES_256_CBC_SHA,
-				VersionTLS12: TLS_RSA_WITH_AES_256_CBC_SHA,
-			},
-		},
-	}
-
-	for i, test := range versionSpecificCiphersTest {
-		for version, expectedCipherSuite := range test.expectations {
-			flags := []string{"-cipher", test.ciphersDefault}
-			if len(test.ciphersTLS10) > 0 {
-				flags = append(flags, "-cipher-tls10", test.ciphersTLS10)
-			}
-			if len(test.ciphersTLS11) > 0 {
-				flags = append(flags, "-cipher-tls11", test.ciphersTLS11)
-			}
-
-			testCases = append(testCases, testCase{
-				testType: serverTest,
-				name:     fmt.Sprintf("VersionSpecificCiphersTest-%d-%x", i, version),
-				config: Config{
-					MaxVersion:   version,
-					MinVersion:   version,
-					CipherSuites: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA},
-				},
-				flags:          flags,
-				expectedCipher: expectedCipherSuite,
-			})
-		}
-	}
 }
 
 func addBadECDSASignatureTests() {
@@ -6319,6 +6262,24 @@
 		expectedLocalError: "remote error: no renegotiation",
 	})
 
+	// Renegotiation is not allowed when there is an unfinished write.
+	testCases = append(testCases, testCase{
+		name: "Renegotiate-Client-UnfinishedWrite",
+		config: Config{
+			MaxVersion: VersionTLS12,
+		},
+		renegotiate: 1,
+		flags: []string{
+			"-async",
+			"-renegotiate-freely",
+			"-read-with-unfinished-write",
+		},
+		shouldFail:    true,
+		expectedError: ":NO_RENEGOTIATION:",
+		// We do not successfully send the no_renegotiation alert in
+		// this case. https://crbug.com/boringssl/130
+	})
+
 	// Stray HelloRequests during the handshake are ignored in TLS 1.2.
 	testCases = append(testCases, testCase{
 		name: "StrayHelloRequest",
@@ -8178,6 +8139,102 @@
 		},
 		resumeSession: true,
 	})
+
+	// Server-sent point formats are legal in TLS 1.2, but not in TLS 1.3.
+	testCases = append(testCases, testCase{
+		name: "PointFormat-ServerHello-TLS12",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{pointFormatUncompressed},
+			},
+		},
+	})
+	testCases = append(testCases, testCase{
+		name: "PointFormat-EncryptedExtensions-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{pointFormatUncompressed},
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":ERROR_PARSING_EXTENSION:",
+	})
+
+	// Test that we tolerate unknown point formats, as long as
+	// pointFormatUncompressed is present. Limit ciphers to ECDHE ciphers to
+	// check they are still functional.
+	testCases = append(testCases, testCase{
+		name: "PointFormat-Client-Tolerance",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime},
+			},
+		},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "PointFormat-Server-Tolerance",
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime},
+			},
+		},
+	})
+
+	// Test TLS 1.2 does not require the point format extension to be
+	// present.
+	testCases = append(testCases, testCase{
+		name: "PointFormat-Client-Missing",
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{},
+			},
+		},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "PointFormat-Server-Missing",
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{},
+			},
+		},
+	})
+
+	// If the point format extension is present, uncompressed points must be
+	// offered. BoringSSL requires this whether or not ECDHE is used.
+	testCases = append(testCases, testCase{
+		name: "PointFormat-Client-MissingUncompressed",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{pointFormatCompressedPrime},
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":ERROR_PARSING_EXTENSION:",
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "PointFormat-Server-MissingUncompressed",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				SendSupportedPointFormats: []byte{pointFormatCompressedPrime},
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":ERROR_PARSING_EXTENSION:",
+	})
 }
 
 func addTLS13RecordTests() {
@@ -8322,6 +8379,48 @@
 		expectedLocalError: "tls: invalid ticket age",
 	})
 
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "TLS13-SendTicketEarlyDataInfo",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendTicketEarlyDataInfo: 16384,
+			},
+		},
+		flags: []string{
+			"-expect-early-data-info",
+		},
+	})
+
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "TLS13-DuplicateTicketEarlyDataInfo",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendTicketEarlyDataInfo:      16384,
+				DuplicateTicketEarlyDataInfo: true,
+			},
+		},
+		shouldFail:         true,
+		expectedError:      ":DUPLICATE_EXTENSION:",
+		expectedLocalError: "remote error: illegal parameter",
+	})
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13-ExpectTicketEarlyDataInfo",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				ExpectTicketEarlyDataInfo: true,
+			},
+		},
+		flags: []string{
+			"-enable-early-data",
+		},
+	})
 }
 
 func addChangeCipherSpecTests() {
@@ -9853,6 +9952,150 @@
 	}
 }
 
+func addShortHeaderTests() {
+	// The short header extension may be negotiated as either client or
+	// server.
+	testCases = append(testCases, testCase{
+		name: "ShortHeader-Client",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				EnableShortHeader: true,
+			},
+		},
+		flags:             []string{"-enable-short-header"},
+		expectShortHeader: true,
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ShortHeader-Server",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				EnableShortHeader: true,
+			},
+		},
+		flags:             []string{"-enable-short-header"},
+		expectShortHeader: true,
+	})
+
+	// If the peer doesn't support it, it will not be negotiated.
+	testCases = append(testCases, testCase{
+		name: "ShortHeader-No-Yes-Client",
+		config: Config{
+			MaxVersion: VersionTLS13,
+		},
+		flags: []string{"-enable-short-header"},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ShortHeader-No-Yes-Server",
+		config: Config{
+			MaxVersion: VersionTLS13,
+		},
+		flags: []string{"-enable-short-header"},
+	})
+
+	// If we don't support it, it will not be negotiated.
+	testCases = append(testCases, testCase{
+		name: "ShortHeader-Yes-No-Client",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				EnableShortHeader: true,
+			},
+		},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ShortHeader-Yes-No-Server",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				EnableShortHeader: true,
+			},
+		},
+	})
+
+	// It will not be negotiated at TLS 1.2.
+	testCases = append(testCases, testCase{
+		name: "ShortHeader-TLS12-Client",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				EnableShortHeader: true,
+			},
+		},
+		flags: []string{"-enable-short-header"},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ShortHeader-TLS12-Server",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				EnableShortHeader: true,
+			},
+		},
+		flags: []string{"-enable-short-header"},
+	})
+
+	// Servers reject early data and short header sent together.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ShortHeader-EarlyData",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				EnableShortHeader:   true,
+				SendEarlyDataLength: 1,
+			},
+		},
+		flags:         []string{"-enable-short-header"},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	// Clients reject unsolicited short header extensions.
+	testCases = append(testCases, testCase{
+		name: "ShortHeader-Unsolicited",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				AlwaysNegotiateShortHeader: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+	testCases = append(testCases, testCase{
+		name: "ShortHeader-Unsolicited-TLS12",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				AlwaysNegotiateShortHeader: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	// The high bit must be checked in short headers.
+	testCases = append(testCases, testCase{
+		name: "ShortHeader-ClearShortHeaderBit",
+		config: Config{
+			Bugs: ProtocolBugs{
+				EnableShortHeader:   true,
+				ClearShortHeaderBit: true,
+			},
+		},
+		flags:              []string{"-enable-short-header"},
+		shouldFail:         true,
+		expectedError:      ":DECODE_ERROR:",
+		expectedLocalError: "remote error: error decoding message",
+	})
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -9979,6 +10222,7 @@
 	addCertificateTests()
 	addRetainOnlySHA256ClientCertTests()
 	addECDSAKeyUsageTests()
+	addShortHeaderTests()
 
 	var wg sync.WaitGroup
 
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 492dd73..a06b5e5 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -81,8 +81,10 @@
   { "-tls-unique", &TestConfig::tls_unique },
   { "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal },
   { "-expect-no-session", &TestConfig::expect_no_session },
+  { "-expect-early-data-info", &TestConfig::expect_early_data_info },
   { "-use-ticket-callback", &TestConfig::use_ticket_callback },
   { "-renew-ticket", &TestConfig::renew_ticket },
+  { "-enable-early-data", &TestConfig::enable_early_data },
   { "-enable-client-custom-extension",
     &TestConfig::enable_client_custom_extension },
   { "-enable-server-custom-extension",
@@ -115,6 +117,8 @@
     &TestConfig::expect_sha256_client_cert_initial },
   { "-expect-sha256-client-cert-resume",
     &TestConfig::expect_sha256_client_cert_resume },
+  { "-enable-short-header", &TestConfig::enable_short_header },
+  { "-read-with-unfinished-write", &TestConfig::read_with_unfinished_write },
 };
 
 const Flag<std::string> kStringFlags[] = {
@@ -135,8 +139,6 @@
   { "-psk-identity", &TestConfig::psk_identity },
   { "-srtp-profiles", &TestConfig::srtp_profiles },
   { "-cipher", &TestConfig::cipher },
-  { "-cipher-tls10", &TestConfig::cipher_tls10 },
-  { "-cipher-tls11", &TestConfig::cipher_tls11 },
   { "-export-label", &TestConfig::export_label },
   { "-export-context", &TestConfig::export_context },
   { "-expect-peer-cert-file", &TestConfig::expect_peer_cert_file },
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 4d6a336..1307d56 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -75,8 +75,6 @@
   bool fail_second_ddos_callback = false;
   bool fail_cert_callback = false;
   std::string cipher;
-  std::string cipher_tls10;
-  std::string cipher_tls11;
   bool handshake_never_done = false;
   int export_keying_material = 0;
   std::string export_label;
@@ -85,8 +83,10 @@
   bool tls_unique = false;
   bool expect_ticket_renewal = false;
   bool expect_no_session = false;
+  bool expect_early_data_info = false;
   bool use_ticket_callback = false;
   bool renew_ticket = false;
+  bool enable_early_data = false;
   bool enable_client_custom_extension = false;
   bool enable_server_custom_extension = false;
   bool custom_extension_skip = false;
@@ -125,6 +125,8 @@
   bool retain_only_sha256_client_cert_resume = false;
   bool expect_sha256_client_cert_initial = false;
   bool expect_sha256_client_cert_resume = false;
+  bool enable_short_header = false;
+  bool read_with_unfinished_write = false;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c
index 5a058b1..7347fc4 100644
--- a/src/ssl/tls13_both.c
+++ b/src/ssl/tls13_both.c
@@ -243,7 +243,8 @@
 
     uint8_t alert;
     if (!ssl_parse_extensions(&extensions, &alert, ext_types,
-                              OPENSSL_ARRAY_SIZE(ext_types))) {
+                              OPENSSL_ARRAY_SIZE(ext_types),
+                              0 /* reject unknown */)) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
       goto err;
     }
diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c
index 4a202d7..6f2bb21 100644
--- a/src/ssl/tls13_client.c
+++ b/src/ssl/tls13_client.c
@@ -78,7 +78,8 @@
 
   uint8_t alert;
   if (!ssl_parse_extensions(&extensions, &alert, ext_types,
-                            OPENSSL_ARRAY_SIZE(ext_types))) {
+                            OPENSSL_ARRAY_SIZE(ext_types),
+                            0 /* reject unknown */)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
   }
@@ -182,7 +183,8 @@
   }
 
   assert(ssl->s3->have_version);
-  memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE);
+  OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
+                 SSL3_RANDOM_SIZE);
 
   const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
   if (cipher == NULL) {
@@ -200,16 +202,18 @@
   }
 
   /* Parse out the extensions. */
-  int have_key_share = 0, have_pre_shared_key = 0;
-  CBS key_share, pre_shared_key;
+  int have_key_share = 0, have_pre_shared_key = 0, have_short_header = 0;
+  CBS key_share, pre_shared_key, short_header;
   const SSL_EXTENSION_TYPE ext_types[] = {
       {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
       {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
+      {TLSEXT_TYPE_short_header, &have_short_header, &short_header},
   };
 
   uint8_t alert;
   if (!ssl_parse_extensions(&extensions, &alert, ext_types,
-                            OPENSSL_ARRAY_SIZE(ext_types))) {
+                            OPENSSL_ARRAY_SIZE(ext_types),
+                            0 /* reject unknown */)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
   }
@@ -304,6 +308,23 @@
   }
   OPENSSL_free(dhe_secret);
 
+  /* Negotiate short record headers. */
+  if (have_short_header) {
+    if (CBS_len(&short_header) != 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      return ssl_hs_error;
+    }
+
+    if (!ssl->ctx->short_header_enabled) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+      return ssl_hs_error;
+    }
+
+    ssl->s3->short_header = 1;
+  }
+
   /* If there was no HelloRetryRequest, the version negotiation logic has
    * already hashed the message. */
   if (hs->received_hello_retry_request &&
@@ -311,7 +332,11 @@
     return ssl_hs_error;
   }
 
-  if (!tls13_set_handshake_traffic(hs)) {
+  if (!tls13_derive_handshake_secrets(hs) ||
+      !tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
+                             hs->hash_len) ||
+      !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret,
+                             hs->hash_len)) {
     return ssl_hs_error;
   }
 
@@ -464,7 +489,8 @@
     }
   }
 
-  if (!tls13_prepare_certificate(hs)) {
+  if (!ssl_auto_chain_if_needed(ssl) ||
+      !tls13_prepare_certificate(hs)) {
     return ssl_hs_error;
   }
 
@@ -612,6 +638,7 @@
 }
 
 int tls13_process_new_session_ticket(SSL *ssl) {
+  int ret = 0;
   SSL_SESSION *session =
       SSL_SESSION_dup(ssl->s3->established_session,
                       SSL_SESSION_INCLUDE_NONAUTH);
@@ -629,10 +656,34 @@
       !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
       !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
       CBS_len(&cbs) != 0) {
-    SSL_SESSION_free(session);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    return 0;
+    goto err;
+  }
+
+  /* Parse out the extensions. */
+  int have_early_data_info = 0;
+  CBS early_data_info;
+  const SSL_EXTENSION_TYPE ext_types[] = {
+      {TLSEXT_TYPE_ticket_early_data_info, &have_early_data_info,
+       &early_data_info},
+  };
+
+  uint8_t alert;
+  if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+                            OPENSSL_ARRAY_SIZE(ext_types),
+                            1 /* ignore unknown */)) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+    goto err;
+  }
+
+  if (have_early_data_info) {
+    if (!CBS_get_u32(&early_data_info, &session->ticket_max_early_data) ||
+        CBS_len(&early_data_info) != 0) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      goto err;
+    }
   }
 
   session->ticket_age_add_valid = 1;
@@ -641,11 +692,14 @@
   if (ssl->ctx->new_session_cb != NULL &&
       ssl->ctx->new_session_cb(ssl, session)) {
     /* |new_session_cb|'s return value signals that it took ownership. */
-    return 1;
+    session = NULL;
   }
 
+  ret = 1;
+
+err:
   SSL_SESSION_free(session);
-  return 1;
+  return ret;
 }
 
 void ssl_clear_tls13_state(SSL_HANDSHAKE *hs) {
diff --git a/src/ssl/tls13_enc.c b/src/ssl/tls13_enc.c
index 4fca65b..ea9dce8 100644
--- a/src/ssl/tls13_enc.c
+++ b/src/ssl/tls13_enc.c
@@ -24,6 +24,7 @@
 #include <openssl/hmac.h>
 #include <openssl/mem.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -34,7 +35,7 @@
   hs->hash_len = EVP_MD_size(digest);
 
   /* Initialize the secret to the zero key. */
-  memset(hs->secret, 0, hs->hash_len);
+  OPENSSL_memset(hs->secret, 0, hs->hash_len);
 
   /* Initialize the rolling hashes and release the handshake buffer. */
   if (!ssl3_init_handshake_hash(ssl)) {
@@ -166,10 +167,12 @@
 
   /* Save the traffic secret. */
   if (direction == evp_aead_open) {
-    memmove(ssl->s3->read_traffic_secret, traffic_secret, traffic_secret_len);
+    OPENSSL_memmove(ssl->s3->read_traffic_secret, traffic_secret,
+                    traffic_secret_len);
     ssl->s3->read_traffic_secret_len = traffic_secret_len;
   } else {
-    memmove(ssl->s3->write_traffic_secret, traffic_secret, traffic_secret_len);
+    OPENSSL_memmove(ssl->s3->write_traffic_secret, traffic_secret,
+                    traffic_secret_len);
     ssl->s3->write_traffic_secret_len = traffic_secret_len;
   }
 
@@ -185,39 +188,18 @@
 static const char kTLS13LabelServerApplicationTraffic[] =
     "server application traffic secret";
 
-int tls13_set_handshake_traffic(SSL_HANDSHAKE *hs) {
+int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  uint8_t client_traffic_secret[EVP_MAX_MD_SIZE];
-  uint8_t server_traffic_secret[EVP_MAX_MD_SIZE];
-  if (!derive_secret(hs, client_traffic_secret, hs->hash_len,
-                     (const uint8_t *)kTLS13LabelClientHandshakeTraffic,
-                     strlen(kTLS13LabelClientHandshakeTraffic)) ||
-      !ssl_log_secret(ssl, "CLIENT_HANDSHAKE_TRAFFIC_SECRET",
-                      client_traffic_secret, hs->hash_len) ||
-      !derive_secret(hs, server_traffic_secret, hs->hash_len,
-                     (const uint8_t *)kTLS13LabelServerHandshakeTraffic,
-                     strlen(kTLS13LabelServerHandshakeTraffic)) ||
-      !ssl_log_secret(ssl, "SERVER_HANDSHAKE_TRAFFIC_SECRET",
-                      server_traffic_secret, hs->hash_len)) {
-    return 0;
-  }
-
-  if (ssl->server) {
-    if (!tls13_set_traffic_key(ssl, evp_aead_open, client_traffic_secret,
-                               hs->hash_len) ||
-        !tls13_set_traffic_key(ssl, evp_aead_seal, server_traffic_secret,
-                               hs->hash_len)) {
-      return 0;
-    }
-  } else {
-    if (!tls13_set_traffic_key(ssl, evp_aead_open, server_traffic_secret,
-                               hs->hash_len) ||
-        !tls13_set_traffic_key(ssl, evp_aead_seal, client_traffic_secret,
-                               hs->hash_len)) {
-      return 0;
-    }
-  }
-  return 1;
+  return derive_secret(hs, hs->client_handshake_secret, hs->hash_len,
+                       (const uint8_t *)kTLS13LabelClientHandshakeTraffic,
+                       strlen(kTLS13LabelClientHandshakeTraffic)) &&
+         ssl_log_secret(ssl, "CLIENT_HANDSHAKE_TRAFFIC_SECRET",
+                        hs->client_handshake_secret, hs->hash_len) &&
+         derive_secret(hs, hs->server_handshake_secret, hs->hash_len,
+                       (const uint8_t *)kTLS13LabelServerHandshakeTraffic,
+                       strlen(kTLS13LabelServerHandshakeTraffic)) &&
+         ssl_log_secret(ssl, "SERVER_HANDSHAKE_TRAFFIC_SECRET",
+                        hs->server_handshake_secret, hs->hash_len);
 }
 
 static const char kTLS13LabelExporter[] = "exporter master secret";
@@ -405,7 +387,7 @@
     return 0;
   }
 
-  memcpy(msg + len - hash_len, verify_data, hash_len);
+  OPENSSL_memcpy(msg + len - hash_len, verify_data, hash_len);
   return 1;
 }
 
diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c
index 1aca634..750e47f 100644
--- a/src/ssl/tls13_server.c
+++ b/src/ssl/tls13_server.c
@@ -25,9 +25,15 @@
 #include <openssl/rand.h>
 #include <openssl/stack.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
+/* kMaxEarlyDataAccepted is the advertised number of plaintext bytes of early
+ * data that will be accepted. This value should be slightly below
+ * kMaxEarlyDataSkipped in tls_record.c, which is measured in ciphertext. */
+static const size_t kMaxEarlyDataAccepted = 14336;
+
 enum server_hs_state_t {
   state_process_client_hello = 0,
   state_select_parameters,
@@ -109,7 +115,8 @@
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return ssl_hs_error;
   }
-  memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
+  OPENSSL_memcpy(ssl->s3->client_random, client_hello.random,
+                 client_hello.random_len);
 
   /* TLS 1.3 requires the peer only advertise the null compression. */
   if (client_hello.compression_methods_len != 1 ||
@@ -125,6 +132,12 @@
     return ssl_hs_error;
   }
 
+  /* The short record header extension is incompatible with early data. */
+  if (ssl->s3->skip_early_data && ssl->s3->short_header) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+    return ssl_hs_error;
+  }
+
   hs->tls13_state = state_select_parameters;
   return ssl_hs_ok;
 }
@@ -191,6 +204,10 @@
     }
   }
 
+  if (!ssl_auto_chain_if_needed(ssl)) {
+    return ssl_hs_error;
+  }
+
   SSL_CLIENT_HELLO client_hello;
   if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
                              ssl->init_num)) {
@@ -389,8 +406,18 @@
       !CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
       !CBB_add_u16_length_prefixed(&body, &extensions) ||
       !ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
-      !ssl_ext_key_share_add_serverhello(hs, &extensions) ||
-      !ssl_complete_message(ssl, &cbb)) {
+      !ssl_ext_key_share_add_serverhello(hs, &extensions)) {
+    goto err;
+  }
+
+  if (ssl->s3->short_header) {
+    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_short_header) ||
+        !CBB_add_u16(&extensions, 0 /* empty extension */)) {
+      goto err;
+    }
+  }
+
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -404,7 +431,11 @@
 
 static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!tls13_set_handshake_traffic(hs)) {
+  if (!tls13_derive_handshake_secrets(hs) ||
+      !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
+                             hs->hash_len) ||
+      !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret,
+                             hs->hash_len)) {
     return ssl_hs_error;
   }
 
@@ -631,9 +662,6 @@
     goto err;
   }
 
-  /* TODO(svaldez): Add support for sending 0RTT through TicketEarlyDataInfo
-   * extension. */
-
   CBB cbb, body, ticket, extensions;
   if (!ssl->method->init_message(ssl, &cbb, &body,
                                  SSL3_MT_NEW_SESSION_TICKET) ||
@@ -645,6 +673,18 @@
     goto err;
   }
 
+  if (ssl->ctx->enable_early_data) {
+    session->ticket_max_early_data = kMaxEarlyDataAccepted;
+
+    CBB early_data_info;
+    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
+        !CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
+        !CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
+        !CBB_flush(&extensions)) {
+      goto err;
+    }
+  }
+
   /* Add a fake extension. See draft-davidben-tls-grease-01. */
   if (!CBB_add_u16(&extensions,
                    ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c
index 9effb36..4efed3f 100644
--- a/src/ssl/tls_method.c
+++ b/src/ssl/tls_method.c
@@ -61,6 +61,7 @@
 
 #include <openssl/buf.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -112,7 +113,7 @@
     return 0;
   }
 
-  memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
+  OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
 
   SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
   ssl->s3->aead_read_ctx = aead_ctx;
@@ -120,7 +121,7 @@
 }
 
 static int ssl3_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
-  memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
+  OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
 
   SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
   ssl->s3->aead_write_ctx = aead_ctx;
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index c52909c..362b0c2 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -125,10 +125,11 @@
  * forever. */
 static const uint8_t kMaxEmptyRecords = 32;
 
-/* kMaxEarlyDataSkipped is the maximum amount of data processed when skipping
- * over early data. Without this limit an attacker could send records at a
- * faster rate than we can process and cause trial decryption to loop
- * forever. */
+/* kMaxEarlyDataSkipped is the maximum number of rejected early data bytes that
+ * will be skipped. Without this limit an attacker could send records at a
+ * faster rate than we can process and cause trial decryption to loop forever.
+ * This value should be slightly above kMaxEarlyDataAccepted in tls13_server.c,
+ * which is measured in plaintext. */
 static const size_t kMaxEarlyDataSkipped = 16384;
 
 /* kMaxWarningAlerts is the number of consecutive warning alerts that will be
@@ -144,6 +145,19 @@
          SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher);
 }
 
+static int ssl_uses_short_header(const SSL *ssl,
+                                 enum evp_aead_direction_t dir) {
+  if (!ssl->s3->short_header) {
+    return 0;
+  }
+
+  if (dir == evp_aead_open) {
+    return ssl->s3->aead_read_ctx != NULL;
+  }
+
+  return ssl->s3->aead_write_ctx != NULL;
+}
+
 int ssl_record_sequence_update(uint8_t *seq, size_t seq_len) {
   for (size_t i = seq_len - 1; i < seq_len; i--) {
     ++seq[i];
@@ -156,34 +170,46 @@
 }
 
 size_t ssl_record_prefix_len(const SSL *ssl) {
+  size_t header_len;
   if (SSL_is_dtls(ssl)) {
-    return DTLS1_RT_HEADER_LENGTH +
-           SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx);
+    header_len = DTLS1_RT_HEADER_LENGTH;
+  } else if (ssl_uses_short_header(ssl, evp_aead_open)) {
+    header_len = 2;
   } else {
-    return SSL3_RT_HEADER_LENGTH +
-           SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx);
+    header_len = SSL3_RT_HEADER_LENGTH;
   }
+
+  return header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx);
 }
 
 size_t ssl_seal_align_prefix_len(const SSL *ssl) {
   if (SSL_is_dtls(ssl)) {
     return DTLS1_RT_HEADER_LENGTH +
            SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
-  } else {
-    size_t ret = SSL3_RT_HEADER_LENGTH +
-                 SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
-    if (ssl_needs_record_splitting(ssl)) {
-      ret += SSL3_RT_HEADER_LENGTH;
-      ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher);
-    }
-    return ret;
   }
+
+  size_t header_len;
+  if (ssl_uses_short_header(ssl, evp_aead_seal)) {
+    header_len = 2;
+  } else {
+    header_len = SSL3_RT_HEADER_LENGTH;
+  }
+
+  size_t ret =
+      header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
+  if (ssl_needs_record_splitting(ssl)) {
+    ret += header_len;
+    ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher);
+  }
+  return ret;
 }
 
 size_t SSL_max_seal_overhead(const SSL *ssl) {
   size_t ret = SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
   if (SSL_is_dtls(ssl)) {
     ret += DTLS1_RT_HEADER_LENGTH;
+  } else if (ssl_uses_short_header(ssl, evp_aead_seal)) {
+    ret += 2;
   } else {
     ret += SSL3_RT_HEADER_LENGTH;
   }
@@ -209,11 +235,31 @@
   /* Decode the record header. */
   uint8_t type;
   uint16_t version, ciphertext_len;
-  if (!CBS_get_u8(&cbs, &type) ||
-      !CBS_get_u16(&cbs, &version) ||
-      !CBS_get_u16(&cbs, &ciphertext_len)) {
-    *out_consumed = SSL3_RT_HEADER_LENGTH;
-    return ssl_open_record_partial;
+  size_t header_len;
+  if (ssl_uses_short_header(ssl, evp_aead_open)) {
+    if (!CBS_get_u16(&cbs, &ciphertext_len)) {
+      *out_consumed = 2;
+      return ssl_open_record_partial;
+    }
+
+    if ((ciphertext_len & 0x8000) == 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      *out_alert = SSL_AD_DECODE_ERROR;
+      return ssl_open_record_error;
+    }
+
+    ciphertext_len &= 0x7fff;
+    type = SSL3_RT_APPLICATION_DATA;
+    version = TLS1_VERSION;
+    header_len = 2;
+  } else {
+    if (!CBS_get_u8(&cbs, &type) ||
+        !CBS_get_u16(&cbs, &version) ||
+        !CBS_get_u16(&cbs, &ciphertext_len)) {
+      *out_consumed = SSL3_RT_HEADER_LENGTH;
+      return ssl_open_record_partial;
+    }
+    header_len = SSL3_RT_HEADER_LENGTH;
   }
 
   int version_ok;
@@ -245,12 +291,11 @@
   /* Extract the body. */
   CBS body;
   if (!CBS_get_bytes(&cbs, &body, ciphertext_len)) {
-    *out_consumed = SSL3_RT_HEADER_LENGTH + (size_t)ciphertext_len;
+    *out_consumed = header_len + (size_t)ciphertext_len;
     return ssl_open_record_partial;
   }
 
-  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in,
-                      SSL3_RT_HEADER_LENGTH);
+  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, header_len);
 
   *out_consumed = in_len - CBS_len(&cbs);
 
@@ -352,21 +397,32 @@
 static int do_seal_record(SSL *ssl, uint8_t *out, size_t *out_len,
                           size_t max_out, uint8_t type, const uint8_t *in,
                           size_t in_len) {
-  if (max_out < SSL3_RT_HEADER_LENGTH) {
+  assert(!buffers_alias(in, in_len, out, max_out));
+
+  const int short_header = ssl_uses_short_header(ssl, evp_aead_seal);
+  size_t header_len = short_header ? 2 : SSL3_RT_HEADER_LENGTH;
+
+  /* TLS 1.3 hides the actual record type inside the encrypted data. */
+  if (ssl->s3->have_version &&
+      ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
+      ssl->s3->aead_write_ctx != NULL) {
+    if (in_len > in_len + header_len + 1 || max_out < in_len + header_len + 1) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+      return 0;
+    }
+
+    OPENSSL_memcpy(out + header_len, in, in_len);
+    out[header_len + in_len] = type;
+    in = out + header_len;
+    type = SSL3_RT_APPLICATION_DATA;
+    in_len++;
+  }
+
+  if (max_out < header_len) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
-  /* Either |in| and |out| don't alias or |in| aligns with the
-   * ciphertext. |tls_seal_record| forbids aliasing, but TLS 1.3 aliases them
-   * internally. */
-  assert(!buffers_alias(in, in_len, out, max_out) ||
-         in ==
-             out + SSL3_RT_HEADER_LENGTH +
-                 SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx));
-
-  out[0] = type;
-
   /* The TLS record-layer version number is meaningless and, starting in
    * TLS 1.3, is frozen at TLS 1.0. But for historical reasons, SSL 3.0
    * ClientHellos should use SSL 3.0 and pre-TLS-1.3 expects the version
@@ -376,29 +432,39 @@
       (ssl->s3->have_version && ssl3_protocol_version(ssl) < TLS1_3_VERSION)) {
     wire_version = ssl->version;
   }
-  out[1] = wire_version >> 8;
-  out[2] = wire_version & 0xff;
 
+  /* Write the non-length portions of the header. */
+  if (!short_header) {
+    out[0] = type;
+    out[1] = wire_version >> 8;
+    out[2] = wire_version & 0xff;
+    out += 3;
+    max_out -= 3;
+  }
+
+  /* Write the ciphertext, leaving two bytes for the length. */
   size_t ciphertext_len;
-  if (!SSL_AEAD_CTX_seal(ssl->s3->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH,
-                         &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH,
-                         type, wire_version, ssl->s3->write_sequence, in,
-                         in_len) ||
+  if (!SSL_AEAD_CTX_seal(ssl->s3->aead_write_ctx, out + 2, &ciphertext_len,
+                         max_out - 2, type, wire_version,
+                         ssl->s3->write_sequence, in, in_len) ||
       !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) {
     return 0;
   }
 
-  if (ciphertext_len >= 1 << 16) {
+  /* Fill in the length. */
+  if (ciphertext_len >= 1 << 15) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
     return 0;
   }
-  out[3] = ciphertext_len >> 8;
-  out[4] = ciphertext_len & 0xff;
+  out[0] = ciphertext_len >> 8;
+  out[1] = ciphertext_len & 0xff;
+  if (short_header) {
+    out[0] |= 0x80;
+  }
 
-  *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
+  *out_len = header_len + ciphertext_len;
 
-  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out,
-                      SSL3_RT_HEADER_LENGTH);
+  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out, header_len);
   return 1;
 }
 
@@ -410,25 +476,6 @@
   }
 
   size_t frag_len = 0;
-
-  /* TLS 1.3 hides the actual record type inside the encrypted data. */
-  if (ssl->s3->have_version &&
-      ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
-      ssl->s3->aead_write_ctx != NULL) {
-    size_t padding = SSL3_RT_HEADER_LENGTH + 1;
-
-    if (in_len > in_len + padding || max_out < in_len + padding) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
-      return 0;
-    }
-
-    memmove(out + SSL3_RT_HEADER_LENGTH, in, in_len);
-    out[SSL3_RT_HEADER_LENGTH + in_len] = type;
-    in = out + SSL3_RT_HEADER_LENGTH;
-    type = SSL3_RT_APPLICATION_DATA;
-    in_len++;
-  }
-
   if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 &&
       ssl_needs_record_splitting(ssl)) {
     if (!do_seal_record(ssl, out, &frag_len, max_out, type, in, 1)) {
@@ -439,6 +486,7 @@
     out += frag_len;
     max_out -= frag_len;
 
+    assert(!ssl_uses_short_header(ssl, evp_aead_seal));
 #if !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
     assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len(
                                        ssl->s3->aead_write_ctx->cipher) ==