external/boringssl: Sync to 392cedd0a28f15b693c81c8b877ee3d74c122d42.
am: ae1abf960b

Change-Id: Ia4835872c131299a4a5cb70c9b1dcb045bfa577a
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index 7112211..0bc058b 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-575334657fcb66a4861c9d125430b2aef60476a6
+392cedd0a28f15b693c81c8b877ee3d74c122d42
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0b95a81..43277f9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -85,8 +85,6 @@
               # possible loss of data
       "C4244" # 'function' : conversion from 'int' to 'uint8_t',
               # possible loss of data
-      "C4245" # 'initializing' : conversion from 'long' to
-              # 'unsigned long', signed/unsigned mismatch
       "C4267" # conversion from 'size_t' to 'int', possible loss of data
       "C4371" # layout of class may have changed from a previous version of the
               # compiler due to better packing of member '...'
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 8541bbb..1cd8458 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -40,7 +40,7 @@
     # CMake does not add -isysroot and -arch flags to assembly.
     if (APPLE)
       if (CMAKE_OSX_SYSROOT)
-        set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT}")
+        set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"")
       endif()
       foreach(arch ${CMAKE_OSX_ARCHITECTURES})
         set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}")
diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc
index 3d78635..eb54f7e 100644
--- a/src/crypto/bio/bio_test.cc
+++ b/src/crypto/bio/bio_test.cc
@@ -12,10 +12,6 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-#if !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 201410L
-#endif
-
 #include <algorithm>
 #include <string>
 
diff --git a/src/crypto/bio/printf.c b/src/crypto/bio/printf.c
index 28162e6..4f9d8a1 100644
--- a/src/crypto/bio/printf.c
+++ b/src/crypto/bio/printf.c
@@ -54,10 +54,6 @@
  * copied and put under another distribution licence
  * [including the GNU Public Licence.] */
 
-#if !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 201410L  // for snprintf, vprintf etc
-#endif
-
 #include <openssl/bio.h>
 
 #include <assert.h>
diff --git a/src/crypto/dh/dh.c b/src/crypto/dh/dh.c
index 04e245e..7b7b833 100644
--- a/src/crypto/dh/dh.c
+++ b/src/crypto/dh/dh.c
@@ -167,7 +167,7 @@
     dh->q = q;
   }
 
-  if (g == NULL) {
+  if (g != NULL) {
     BN_free(dh->g);
     dh->g = g;
   }
diff --git a/src/crypto/err/err.c b/src/crypto/err/err.c
index 2c567ce..a620fc7 100644
--- a/src/crypto/err/err.c
+++ b/src/crypto/err/err.c
@@ -129,18 +129,9 @@
 extern const size_t kOpenSSLReasonValuesLen;
 extern const char kOpenSSLReasonStringData[];
 
-// err_clear_data frees the optional |data| member of the given error.
-static void err_clear_data(struct err_error_st *error) {
-  if ((error->flags & ERR_FLAG_MALLOCED) != 0) {
-    OPENSSL_free(error->data);
-  }
-  error->data = NULL;
-  error->flags &= ~ERR_FLAG_MALLOCED;
-}
-
 // err_clear clears the given queued error.
 static void err_clear(struct err_error_st *error) {
-  err_clear_data(error);
+  OPENSSL_free(error->data);
   OPENSSL_memset(error, 0, sizeof(struct err_error_st));
 }
 
@@ -227,7 +218,7 @@
     } else {
       *data = error->data;
       if (flags != NULL) {
-        *flags = error->flags & ERR_FLAG_PUBLIC_MASK;
+        *flags = ERR_FLAG_STRING;
       }
       // If this error is being removed, take ownership of data from
       // the error. The semantics are such that the caller doesn't
@@ -235,12 +226,11 @@
       // ownership and retains it until the next call that affects the
       // error queue.
       if (inc) {
-        if (error->flags & ERR_FLAG_MALLOCED) {
+        if (error->data != NULL) {
           OPENSSL_free(state->to_free);
           state->to_free = error->data;
         }
         error->data = NULL;
-        error->flags = 0;
       }
     }
   }
@@ -585,24 +575,20 @@
   ERR_print_errors_cb(print_errors_to_file, file);
 }
 
-// err_set_error_data sets the data on the most recent error. The |flags|
-// argument is a combination of the |ERR_FLAG_*| values.
-static void err_set_error_data(char *data, int flags) {
+// err_set_error_data sets the data on the most recent error.
+static void err_set_error_data(char *data) {
   ERR_STATE *const state = err_get_state();
   struct err_error_st *error;
 
   if (state == NULL || state->top == state->bottom) {
-    if (flags & ERR_FLAG_MALLOCED) {
-      OPENSSL_free(data);
-    }
+    OPENSSL_free(data);
     return;
   }
 
   error = &state->errors[state->top];
 
-  err_clear_data(error);
+  OPENSSL_free(error->data);
   error->data = data;
-  error->flags = flags;
 }
 
 void ERR_put_error(int library, int unused, int reason, const char *file,
@@ -680,7 +666,7 @@
   }
 
   buf[len] = 0;
-  err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING);
+  err_set_error_data(buf);
 }
 
 void ERR_add_error_data(unsigned count, ...) {
@@ -708,7 +694,7 @@
   buf[buf_len] = 0;
   va_end(ap);
 
-  err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING);
+  err_set_error_data(buf);
 }
 
 int ERR_set_mark(void) {
@@ -717,7 +703,7 @@
   if (state == NULL || state->bottom == state->top) {
     return 0;
   }
-  state->errors[state->top].flags |= ERR_FLAG_MARK;
+  state->errors[state->top].mark = 1;
   return 1;
 }
 
@@ -731,8 +717,8 @@
   while (state->bottom != state->top) {
     struct err_error_st *error = &state->errors[state->top];
 
-    if ((error->flags & ERR_FLAG_MARK) != 0) {
-      error->flags &= ~ERR_FLAG_MARK;
+    if (error->mark) {
+      error->mark = 0;
       return 1;
     }
 
diff --git a/src/crypto/fipsmodule/sha/sha1.c b/src/crypto/fipsmodule/sha/sha1.c
index 7ce0193..e5b4ba6 100644
--- a/src/crypto/fipsmodule/sha/sha1.c
+++ b/src/crypto/fipsmodule/sha/sha1.c
@@ -63,10 +63,10 @@
 #include "../../internal.h"
 
 
-#if !defined(OPENSSL_NO_ASM) &&                         \
-    (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
-     defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \
-     defined(OPENSSL_PPC64LE))
+#if (!defined(OPENSSL_NO_ASM) &&                            \
+     (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) ||    \
+      defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))) || \
+    defined(OPENSSL_PPC64LE)
 #define SHA1_ASM
 #endif
 
diff --git a/src/crypto/lhash/lhash_test.cc b/src/crypto/lhash/lhash_test.cc
index cc146e8..0859eeb 100644
--- a/src/crypto/lhash/lhash_test.cc
+++ b/src/crypto/lhash/lhash_test.cc
@@ -12,10 +12,6 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-#if !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 201410L
-#endif
-
 #include <openssl/lhash.h>
 
 #include <stdio.h>
diff --git a/src/crypto/mem.c b/src/crypto/mem.c
index 09f3159..67f74b7 100644
--- a/src/crypto/mem.c
+++ b/src/crypto/mem.c
@@ -54,10 +54,6 @@
  * copied and put under another distribution licence
  * [including the GNU Public Licence.] */
 
-#if !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 201410L  // needed for strdup, snprintf, vprintf etc
-#endif
-
 #include <openssl/mem.h>
 
 #include <assert.h>
diff --git a/src/crypto/x509/x_name.c b/src/crypto/x509/x_name.c
index 0980463..f132e6b 100644
--- a/src/crypto/x509/x_name.c
+++ b/src/crypto/x509/x_name.c
@@ -244,7 +244,7 @@
             entry->set = i;
             if (!sk_X509_NAME_ENTRY_push(nm.x->entries, entry))
                 goto err;
-            sk_X509_NAME_ENTRY_set(entries, j, NULL);
+            (void)sk_X509_NAME_ENTRY_set(entries, j, NULL);
         }
     }
     ret = x509_name_canon(nm.x);
diff --git a/src/include/openssl/err.h b/src/include/openssl/err.h
index 0a64925..5de3cbd 100644
--- a/src/include/openssl/err.h
+++ b/src/include/openssl/err.h
@@ -158,6 +158,15 @@
 
 // Reading and formatting errors.
 
+// ERR_GET_LIB returns the library code for the error. This is one of
+// the |ERR_LIB_*| values.
+#define ERR_GET_LIB(packed_error) ((int)(((packed_error) >> 24) & 0xff))
+
+// ERR_GET_REASON returns the reason code for the error. This is one of
+// library-specific |LIB_R_*| values where |LIB| is the library (see
+// |ERR_GET_LIB|). Note that reason codes are specific to the library.
+#define ERR_GET_REASON(packed_error) ((int)((packed_error) & 0xfff))
+
 // ERR_get_error gets the packed error code for the least recent error and
 // removes that error from the queue. If there are no errors in the queue then
 // it returns zero.
@@ -167,6 +176,10 @@
 // number of the call that added the error are also returned.
 OPENSSL_EXPORT uint32_t ERR_get_error_line(const char **file, int *line);
 
+// ERR_FLAG_STRING means that the |data| member is a NUL-terminated string that
+// can be printed. This is always set if |data| is non-NULL.
+#define ERR_FLAG_STRING 1
+
 // ERR_get_error_line_data acts like |ERR_get_error_line|, but also returns the
 // error-specific data pointer and flags. The flags are a bitwise-OR of
 // |ERR_FLAG_*| values. The error-specific data is owned by the error queue
@@ -257,67 +270,6 @@
 // need to call this function. Use |ERR_clear_error|.
 OPENSSL_EXPORT void ERR_remove_thread_state(const CRYPTO_THREADID *tid);
 
-
-// Custom errors.
-
-// ERR_get_next_error_library returns a value suitable for passing as the
-// |library| argument to |ERR_put_error|. This is intended for code that wishes
-// to push its own, non-standard errors to the error queue.
-OPENSSL_EXPORT int ERR_get_next_error_library(void);
-
-
-// Deprecated functions.
-
-// ERR_remove_state calls |ERR_clear_error|.
-OPENSSL_EXPORT void ERR_remove_state(unsigned long pid);
-
-// ERR_func_error_string returns the string "OPENSSL_internal".
-OPENSSL_EXPORT const char *ERR_func_error_string(uint32_t packed_error);
-
-// ERR_error_string behaves like |ERR_error_string_n| but |len| is implicitly
-// |ERR_ERROR_STRING_BUF_LEN| and it returns |buf|. If |buf| is NULL, the error
-// string is placed in a static buffer which is returned. (The static buffer may
-// be overridden by concurrent calls in other threads so this form should not be
-// used.)
-//
-// Use |ERR_error_string_n| instead.
-//
-// TODO(fork): remove this function.
-OPENSSL_EXPORT char *ERR_error_string(uint32_t packed_error, char *buf);
-#define ERR_ERROR_STRING_BUF_LEN 256
-
-
-// Private functions.
-
-// ERR_clear_system_error clears the system's error value (i.e. errno).
-OPENSSL_EXPORT void ERR_clear_system_error(void);
-
-// OPENSSL_PUT_ERROR is used by OpenSSL code to add an error to the error
-// queue.
-#define OPENSSL_PUT_ERROR(library, reason) \
-  ERR_put_error(ERR_LIB_##library, 0, reason, __FILE__, __LINE__)
-
-// OPENSSL_PUT_SYSTEM_ERROR is used by OpenSSL code to add an error from the
-// operating system to the error queue.
-// TODO(fork): include errno.
-#define OPENSSL_PUT_SYSTEM_ERROR() \
-  ERR_put_error(ERR_LIB_SYS, 0, 0, __FILE__, __LINE__);
-
-// ERR_put_error adds an error to the error queue, dropping the least recent
-// error if necessary for space reasons.
-OPENSSL_EXPORT void ERR_put_error(int library, int unused, int reason,
-                                  const char *file, unsigned line);
-
-// ERR_add_error_data takes a variable number (|count|) of const char*
-// pointers, concatenates them and sets the result as the data on the most
-// recent error.
-OPENSSL_EXPORT void ERR_add_error_data(unsigned count, ...);
-
-// ERR_add_error_dataf takes a printf-style format and arguments, and sets the
-// result as the data on the most recent error.
-OPENSSL_EXPORT void ERR_add_error_dataf(const char *format, ...)
-    OPENSSL_PRINTF_FORMAT_FUNC(1, 2);
-
 // ERR_set_mark "marks" the most recent error for use with |ERR_pop_to_mark|.
 // It returns one if an error was marked and zero if there are no errors.
 OPENSSL_EXPORT int ERR_set_mark(void);
@@ -328,60 +280,18 @@
 // are marked using |ERR_set_mark|.
 OPENSSL_EXPORT int ERR_pop_to_mark(void);
 
-struct err_error_st {
-  // file contains the filename where the error occurred.
-  const char *file;
-  // data contains optional data. It must be freed with |OPENSSL_free| if
-  // |flags&ERR_FLAG_MALLOCED|.
-  char *data;
-  // packed contains the error library and reason, as packed by ERR_PACK.
-  uint32_t packed;
-  // line contains the line number where the error occurred.
-  uint16_t line;
-  // flags contains a bitwise-OR of ERR_FLAG_* values.
-  uint8_t flags;
-};
 
-// ERR_FLAG_STRING means that the |data| member is a NUL-terminated string that
-// can be printed.
-#define ERR_FLAG_STRING 1
-// ERR_TXT_STRING is provided for compatibility with code that assumes that
-// it's using OpenSSL.
-#define ERR_TXT_STRING ERR_FLAG_STRING
+// Custom errors.
 
-// ERR_FLAG_PUBLIC_MASK is applied to the flags field before it is returned
-// from functions like |ERR_get_error_line_data|.
-#define ERR_FLAG_PUBLIC_MASK 0xf
+// ERR_get_next_error_library returns a value suitable for passing as the
+// |library| argument to |ERR_put_error|. This is intended for code that wishes
+// to push its own, non-standard errors to the error queue.
+OPENSSL_EXPORT int ERR_get_next_error_library(void);
 
-// The following flag values are internal and are masked when flags are
-// returned from functions like |ERR_get_error_line_data|.
 
-// ERR_FLAG_MALLOCED means the the |data| member must be freed when no longer
-// needed.
-#define ERR_FLAG_MALLOCED 16
-// ERR_FLAG_MARK is used to indicate a reversion point in the queue. See
-// |ERR_pop_to_mark|.
-#define ERR_FLAG_MARK 32
+// Built-in library and reason codes.
 
-// ERR_NUM_ERRORS is the limit of the number of errors in the queue.
-#define ERR_NUM_ERRORS 16
-
-// err_state_st (aka |ERR_STATE|) contains the per-thread, error queue.
-typedef struct err_state_st {
-  // errors contains the ERR_NUM_ERRORS most recent errors, organised as a ring
-  // buffer.
-  struct err_error_st errors[ERR_NUM_ERRORS];
-  // top contains the index one past the most recent error. If |top| equals
-  // |bottom| then the queue is empty.
-  unsigned top;
-  // bottom contains the index of the last error in the queue.
-  unsigned bottom;
-
-  // to_free, if not NULL, contains a pointer owned by this structure that was
-  // previously a |data| pointer of one of the elements of |errors|.
-  void *to_free;
-} ERR_STATE;
-
+// The following values are built-in library codes.
 enum {
   ERR_LIB_NONE = 1,
   ERR_LIB_SYS,
@@ -418,6 +328,8 @@
   ERR_NUM_LIBS
 };
 
+// The following reason codes used to denote an error occuring in another
+// library. They are sometimes used for a stack trace.
 #define ERR_R_SYS_LIB ERR_LIB_SYS
 #define ERR_R_BN_LIB ERR_LIB_BN
 #define ERR_R_RSA_LIB ERR_LIB_RSA
@@ -456,7 +368,7 @@
 #define ERR_R_CIPHER_LIB ERR_LIB_CIPHER
 #define ERR_R_HKDF_LIB ERR_LIB_HKDF
 
-// Global reasons.
+// The following values are global reason codes. They may occur in any library.
 #define ERR_R_FATAL 64
 #define ERR_R_MALLOC_FAILURE (1 | ERR_R_FATAL)
 #define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2 | ERR_R_FATAL)
@@ -464,13 +376,102 @@
 #define ERR_R_INTERNAL_ERROR (4 | ERR_R_FATAL)
 #define ERR_R_OVERFLOW (5 | ERR_R_FATAL)
 
+
+// Deprecated functions.
+
+// ERR_remove_state calls |ERR_clear_error|.
+OPENSSL_EXPORT void ERR_remove_state(unsigned long pid);
+
+// ERR_func_error_string returns the string "OPENSSL_internal".
+OPENSSL_EXPORT const char *ERR_func_error_string(uint32_t packed_error);
+
+// ERR_error_string behaves like |ERR_error_string_n| but |len| is implicitly
+// |ERR_ERROR_STRING_BUF_LEN| and it returns |buf|. If |buf| is NULL, the error
+// string is placed in a static buffer which is returned. (The static buffer may
+// be overridden by concurrent calls in other threads so this form should not be
+// used.)
+//
+// Use |ERR_error_string_n| instead.
+//
+// TODO(fork): remove this function.
+OPENSSL_EXPORT char *ERR_error_string(uint32_t packed_error, char *buf);
+#define ERR_ERROR_STRING_BUF_LEN 256
+
+// ERR_GET_FUNC returns zero. BoringSSL errors do not report a function code.
+#define ERR_GET_FUNC(packed_error) 0
+
+// ERR_TXT_STRING is provided for compatibility with code that assumes that
+// it's using OpenSSL.
+#define ERR_TXT_STRING ERR_FLAG_STRING
+
+
+// Private functions.
+
+// ERR_clear_system_error clears the system's error value (i.e. errno).
+OPENSSL_EXPORT void ERR_clear_system_error(void);
+
+// OPENSSL_PUT_ERROR is used by OpenSSL code to add an error to the error
+// queue.
+#define OPENSSL_PUT_ERROR(library, reason) \
+  ERR_put_error(ERR_LIB_##library, 0, reason, __FILE__, __LINE__)
+
+// OPENSSL_PUT_SYSTEM_ERROR is used by OpenSSL code to add an error from the
+// operating system to the error queue.
+// TODO(fork): include errno.
+#define OPENSSL_PUT_SYSTEM_ERROR() \
+  ERR_put_error(ERR_LIB_SYS, 0, 0, __FILE__, __LINE__);
+
+// ERR_put_error adds an error to the error queue, dropping the least recent
+// error if necessary for space reasons.
+OPENSSL_EXPORT void ERR_put_error(int library, int unused, int reason,
+                                  const char *file, unsigned line);
+
+// ERR_add_error_data takes a variable number (|count|) of const char*
+// pointers, concatenates them and sets the result as the data on the most
+// recent error.
+OPENSSL_EXPORT void ERR_add_error_data(unsigned count, ...);
+
+// ERR_add_error_dataf takes a printf-style format and arguments, and sets the
+// result as the data on the most recent error.
+OPENSSL_EXPORT void ERR_add_error_dataf(const char *format, ...)
+    OPENSSL_PRINTF_FORMAT_FUNC(1, 2);
+
+struct err_error_st {
+  // file contains the filename where the error occurred.
+  const char *file;
+  // data contains a NUL-terminated string with optional data. It must be freed
+  // with |OPENSSL_free|.
+  char *data;
+  // packed contains the error library and reason, as packed by ERR_PACK.
+  uint32_t packed;
+  // line contains the line number where the error occurred.
+  uint16_t line;
+  // mark indicates a reversion point in the queue. See |ERR_pop_to_mark|.
+  unsigned mark : 1;
+};
+
+// ERR_NUM_ERRORS is the limit of the number of errors in the queue.
+#define ERR_NUM_ERRORS 16
+
+// err_state_st (aka |ERR_STATE|) contains the per-thread, error queue.
+typedef struct err_state_st {
+  // errors contains the ERR_NUM_ERRORS most recent errors, organised as a ring
+  // buffer.
+  struct err_error_st errors[ERR_NUM_ERRORS];
+  // top contains the index one past the most recent error. If |top| equals
+  // |bottom| then the queue is empty.
+  unsigned top;
+  // bottom contains the index of the last error in the queue.
+  unsigned bottom;
+
+  // to_free, if not NULL, contains a pointer owned by this structure that was
+  // previously a |data| pointer of one of the elements of |errors|.
+  void *to_free;
+} ERR_STATE;
+
 #define ERR_PACK(lib, reason)                                              \
   (((((uint32_t)(lib)) & 0xff) << 24) | ((((uint32_t)(reason)) & 0xfff)))
 
-#define ERR_GET_LIB(packed_error) ((int)(((packed_error) >> 24) & 0xff))
-#define ERR_GET_FUNC(packed_error) 0
-#define ERR_GET_REASON(packed_error) ((int)((packed_error) & 0xfff))
-
 // OPENSSL_DECLARE_ERROR_REASON is used by util/make_errors.h (which generates
 // the error defines) to recognise that an additional reason value is needed.
 // This is needed when the reason value is used outside of an
diff --git a/src/include/openssl/span.h b/src/include/openssl/span.h
index d447314..3109036 100644
--- a/src/include/openssl/span.h
+++ b/src/include/openssl/span.h
@@ -22,6 +22,7 @@
 extern "C++" {
 
 #include <algorithm>
+#include <cstdlib>
 #include <type_traits>
 
 namespace bssl {
@@ -104,6 +105,8 @@
       std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
       std::is_integral<decltype(std::declval<C>().size())>::value>;
 
+  static const size_t npos = static_cast<size_t>(-1);
+
  public:
   constexpr Span() : Span(nullptr, 0) {}
   constexpr Span(T *ptr, size_t len) : data_(ptr), size_(len) {}
@@ -124,6 +127,7 @@
 
   T *data() const { return data_; }
   size_t size() const { return size_; }
+  bool empty() const { return size_ == 0; }
 
   T *begin() const { return data_; }
   const T *cbegin() const { return data_; }
@@ -133,12 +137,22 @@
   T &operator[](size_t i) const { return data_[i]; }
   T &at(size_t i) const { return data_[i]; }
 
+  Span subspan(size_t pos = 0, size_t len = npos) const {
+    if (pos > size_) {
+      abort();  // absl::Span throws an exception here.
+    }
+    return Span(data_ + pos, std::min(size_ - pos, len));
+  }
+
  private:
   T *data_;
   size_t size_;
 };
 
 template <typename T>
+const size_t Span<T>::npos;
+
+template <typename T>
 Span<T> MakeSpan(T *ptr, size_t size) {
   return Span<T>(ptr, size);
 }
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index a85fc9c..6b4bf81 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -591,7 +591,6 @@
 #define TLS1_3_EXPERIMENT_VERSION 0x7e01
 #define TLS1_3_EXPERIMENT2_VERSION 0x7e02
 #define TLS1_3_EXPERIMENT3_VERSION 0x7e03
-#define TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION 0x7a12
 
 // SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to
 // |version|. If |version| is zero, the default minimum version is used. It
@@ -1670,10 +1669,21 @@
 OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes(
     const uint8_t *in, size_t in_len, const SSL_CTX *ctx);
 
-// SSL_SESSION_get_version returns a string describing the TLS version |session|
-// was established at. For example, "TLSv1.2" or "SSLv3".
+// SSL_SESSION_get_version returns a string describing the TLS or DTLS version
+// |session| was established at. For example, "TLSv1.2" or "SSLv3".
 OPENSSL_EXPORT const char *SSL_SESSION_get_version(const SSL_SESSION *session);
 
+// SSL_SESSION_get_protocol_version returns the TLS or DTLS version |session|
+// was established at.
+OPENSSL_EXPORT uint16_t
+SSL_SESSION_get_protocol_version(const SSL_SESSION *session);
+
+// SSL_SESSION_set_protocol_version sets |session|'s TLS or DTLS version to
+// |version|. This may be useful when writing tests but should otherwise not be
+// used. It returns one on success and zero on error.
+OPENSSL_EXPORT int SSL_SESSION_set_protocol_version(SSL_SESSION *session,
+                                                    uint16_t version);
+
 // SSL_SESSION_get_id returns a pointer to a buffer containing |session|'s
 // session ID and sets |*out_len| to its length.
 OPENSSL_EXPORT const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session,
@@ -3219,10 +3229,8 @@
 enum tls13_variant_t {
   tls13_default = 0,
   tls13_experiment = 1,
-  tls13_record_type_experiment = 2,
-  tls13_no_session_id_experiment = 3,
-  tls13_experiment2 = 4,
-  tls13_experiment3 = 5,
+  tls13_experiment2 = 2,
+  tls13_experiment3 = 3,
 };
 
 // SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the
@@ -4047,7 +4055,7 @@
 
 struct ssl_session_st {
   CRYPTO_refcount_t references;
-  int ssl_version;  // what ssl version session info is being kept in here?
+  uint16_t ssl_version;  // what ssl version session info is being kept in here?
 
   // group_id is the ID of the ECDH group used to establish this session or zero
   // if not applicable or unknown.
diff --git a/src/include/openssl/ssl3.h b/src/include/openssl/ssl3.h
index 719a52d..6754cec 100644
--- a/src/include/openssl/ssl3.h
+++ b/src/include/openssl/ssl3.h
@@ -272,7 +272,6 @@
 #define SSL3_RT_ALERT 21
 #define SSL3_RT_HANDSHAKE 22
 #define SSL3_RT_APPLICATION_DATA 23
-#define SSL3_RT_PLAINTEXT_HANDSHAKE 24
 
 // Pseudo content type for SSL/TLS header info
 #define SSL3_RT_HEADER 0x100
diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc
index c10c40f..a03b140 100644
--- a/src/ssl/handshake.cc
+++ b/src/ssl/handshake.cc
@@ -147,7 +147,6 @@
 
 SSL_HANDSHAKE::~SSL_HANDSHAKE() {
   ssl->ctx->x509_method->hs_flush_cached_ca_names(this);
-  OPENSSL_free(key_block);
 }
 
 SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) {
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 13e6655..4247425 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -258,6 +258,7 @@
   const T *data() const { return data_; }
   T *data() { return data_; }
   size_t size() const { return size_; }
+  bool empty() const { return size_ == 0; }
 
   const T &operator[](size_t i) const { return data_[i]; }
   T &operator[](size_t i) { return data_[i]; }
@@ -352,32 +353,31 @@
 // compared numerically.
 
 // ssl_protocol_version_from_wire sets |*out| to the protocol version
-// corresponding to wire version |version| and returns one. If |version| is not
-// a valid TLS or DTLS version, it returns zero.
+// corresponding to wire version |version| and returns true. If |version| is not
+// a valid TLS or DTLS version, it returns false.
 //
 // Note this simultaneously handles both DTLS and TLS. Use one of the
 // higher-level functions below for most operations.
-int ssl_protocol_version_from_wire(uint16_t *out, uint16_t version);
+bool ssl_protocol_version_from_wire(uint16_t *out, uint16_t version);
 
 // ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the
 // minimum and maximum enabled protocol versions, respectively.
-int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
-                          uint16_t *out_max_version);
+bool ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
+                           uint16_t *out_max_version);
 
-// ssl_supports_version returns one if |hs| supports |version| and zero
-// otherwise.
-int ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version);
+// ssl_supports_version returns whether |hs| supports |version|.
+bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version);
 
 // ssl_add_supported_versions writes the supported versions of |hs| to |cbb|, in
 // decreasing preference order.
-int ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb);
+bool ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb);
 
 // ssl_negotiate_version negotiates a common version based on |hs|'s preferences
-// and the peer preference list in |peer_versions|. On success, it returns one
-// and sets |*out_version| to the selected version. Otherwise, it returns zero
+// and the peer preference list in |peer_versions|. On success, it returns true
+// and sets |*out_version| to the selected version. Otherwise, it returns false
 // and sets |*out_alert| to an alert to send.
-int ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
-                          uint16_t *out_version, const CBS *peer_versions);
+bool ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+                           uint16_t *out_version, const CBS *peer_versions);
 
 // ssl3_protocol_version returns |ssl|'s protocol version. It is an error to
 // call this function before the version is determined.
@@ -470,11 +470,11 @@
 // object for |cipher| protocol version |version|. It sets |*out_mac_secret_len|
 // and |*out_fixed_iv_len| to the MAC key length and fixed IV length,
 // respectively. The MAC key length is zero except for legacy block and stream
-// ciphers. It returns 1 on success and 0 on error.
-int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
-                            size_t *out_mac_secret_len,
-                            size_t *out_fixed_iv_len, const SSL_CIPHER *cipher,
-                            uint16_t version, int is_dtls);
+// ciphers. It returns true on success and false on error.
+bool ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
+                             size_t *out_mac_secret_len,
+                             size_t *out_fixed_iv_len, const SSL_CIPHER *cipher,
+                             uint16_t version, int is_dtls);
 
 // ssl_get_handshake_digest returns the |EVP_MD| corresponding to |version| and
 // |cipher|.
@@ -483,14 +483,14 @@
 
 // ssl_create_cipher_list evaluates |rule_str| according to the ciphers in
 // |ssl_method|. It sets |*out_cipher_list| to a newly-allocated
-// |ssl_cipher_preference_list_st| containing the result. It returns 1 on
-// success and 0 on failure. If |strict| is true, nonsense will be rejected. If
-// false, nonsense will be silently ignored. An empty result is considered an
-// error regardless of |strict|.
-int ssl_create_cipher_list(
+// |ssl_cipher_preference_list_st| containing the result. It returns true on
+// success and false on failure. If |strict| is true, nonsense will be
+// rejected. If false, nonsense will be silently ignored. An empty result is
+// considered an error regardless of |strict|.
+bool ssl_create_cipher_list(
     const SSL_PROTOCOL_METHOD *ssl_method,
     struct ssl_cipher_preference_list_st **out_cipher_list,
-    const char *rule_str, int strict);
+    const char *rule_str, bool strict);
 
 // ssl_cipher_get_value returns the cipher suite id of |cipher|.
 uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher);
@@ -499,17 +499,16 @@
 // values suitable for use with |key| in TLS 1.2 and below.
 uint32_t ssl_cipher_auth_mask_for_key(const EVP_PKEY *key);
 
-// ssl_cipher_uses_certificate_auth returns one if |cipher| authenticates the
-// server and, optionally, the client with a certificate. Otherwise it returns
-// zero.
-int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher);
+// ssl_cipher_uses_certificate_auth returns whether |cipher| authenticates the
+// server and, optionally, the client with a certificate.
+bool ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher);
 
-// ssl_cipher_requires_server_key_exchange returns 1 if |cipher| requires a
-// ServerKeyExchange message. Otherwise it returns 0.
+// ssl_cipher_requires_server_key_exchange returns whether |cipher| requires a
+// ServerKeyExchange message.
 //
-// This function may return zero while still allowing |cipher| an optional
+// This function may return false while still allowing |cipher| an optional
 // ServerKeyExchange. This is the case for plain PSK ciphers.
-int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher);
+bool ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher);
 
 // ssl_cipher_get_record_split_len, for TLS 1.0 CBC mode ciphers, returns the
 // length of an encrypted 1-byte record, for use in record-splitting. Otherwise
@@ -618,11 +617,12 @@
   // returns nullptr on error. Only one of |Open| or |Seal| may be used with the
   // resulting object, depending on |direction|. |version| is the normalized
   // protocol version, so DTLS 1.0 is represented as 0x0301, not 0xffef.
-  static UniquePtr<SSLAEADContext> Create(
-      enum evp_aead_direction_t direction, uint16_t version, int is_dtls,
-      const SSL_CIPHER *cipher, const uint8_t *enc_key, size_t enc_key_len,
-      const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv,
-      size_t fixed_iv_len);
+  static UniquePtr<SSLAEADContext> Create(enum evp_aead_direction_t direction,
+                                          uint16_t version, int is_dtls,
+                                          const SSL_CIPHER *cipher,
+                                          Span<const uint8_t> enc_key,
+                                          Span<const uint8_t> mac_key,
+                                          Span<const uint8_t> fixed_iv);
 
   // SetVersionIfNullCipher sets the version the SSLAEADContext for the null
   // cipher, to make version-specific determinations in the record layer prior
@@ -1335,8 +1335,9 @@
   // CertificateRequest message.
   UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names;
 
-  // cached_x509_ca_names contains a cache of parsed versions of the elements
-  // of |ca_names|.
+  // cached_x509_ca_names contains a cache of parsed versions of the elements of
+  // |ca_names|. This pointer is left non-owning so only
+  // |ssl_crypto_x509_method| needs to link against crypto/x509.
   STACK_OF(X509_NAME) *cached_x509_ca_names = nullptr;
 
   // certificate_types, on the client, contains the set of certificate types
@@ -1361,8 +1362,7 @@
   const SSL_CIPHER *new_cipher = nullptr;
 
   // key_block is the record-layer key block for TLS 1.2 and earlier.
-  uint8_t *key_block = nullptr;
-  uint8_t key_block_len = 0;
+  Array<uint8_t> key_block;
 
   // scts_requested is true if the SCT extension is in the ClientHello.
   bool scts_requested:1;
@@ -2229,12 +2229,13 @@
 int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
                              const SSL_SESSION *session);
 
-// SSL_SESSION_protocol_version returns the protocol version associated with
-// |session|.
-uint16_t SSL_SESSION_protocol_version(const SSL_SESSION *session);
+// ssl_session_protocol_version returns the protocol version associated with
+// |session|. Note that despite the name, this is not the same as
+// |SSL_SESSION_get_protocol_version|. The latter is based on upstream's name.
+uint16_t ssl_session_protocol_version(const SSL_SESSION *session);
 
-// SSL_SESSION_get_digest returns the digest used in |session|.
-const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session);
+// ssl_session_get_digest returns the digest used in |session|.
+const EVP_MD *ssl_session_get_digest(const SSL_SESSION *session);
 
 void ssl_set_session(SSL *ssl, SSL_SESSION *session);
 
diff --git a/src/ssl/s3_both.cc b/src/ssl/s3_both.cc
index f63ed26..65e2089 100644
--- a/src/ssl/s3_both.cc
+++ b/src/ssl/s3_both.cc
@@ -132,8 +132,8 @@
 
 namespace bssl {
 
-static int add_record_to_flight(SSL *ssl, uint8_t type, const uint8_t *in,
-                                size_t in_len) {
+static int add_record_to_flight(SSL *ssl, uint8_t type,
+                                Span<const uint8_t> in) {
   // We'll never add a flight while in the process of writing it out.
   assert(ssl->s3->pending_flight_offset == 0);
 
@@ -144,18 +144,19 @@
     }
   }
 
-  size_t max_out = in_len + SSL_max_seal_overhead(ssl);
+  size_t max_out = in.size() + SSL_max_seal_overhead(ssl);
   size_t new_cap = ssl->s3->pending_flight->length + max_out;
-  if (max_out < in_len || new_cap < max_out) {
+  if (max_out < in.size() || new_cap < max_out) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
     return 0;
   }
 
   size_t len;
   if (!BUF_MEM_reserve(ssl->s3->pending_flight, new_cap) ||
-      !tls_seal_record(ssl, (uint8_t *)ssl->s3->pending_flight->data +
-                                ssl->s3->pending_flight->length,
-                       &len, max_out, type, in, in_len)) {
+      !tls_seal_record(ssl,
+                       (uint8_t *)ssl->s3->pending_flight->data +
+                           ssl->s3->pending_flight->length,
+                       &len, max_out, type, in.data(), in.size())) {
     return 0;
   }
 
@@ -183,26 +184,15 @@
 int ssl3_add_message(SSL *ssl, Array<uint8_t> msg) {
   // Add the message to the current flight, splitting into several records if
   // needed.
-  size_t added = 0;
+  Span<const uint8_t> rest = msg;
   do {
-    size_t todo = msg.size() - added;
-    if (todo > ssl->max_send_fragment) {
-      todo = ssl->max_send_fragment;
-    }
+    Span<const uint8_t> chunk = rest.subspan(0, ssl->max_send_fragment);
+    rest = rest.subspan(chunk.size());
 
-    uint8_t type = SSL3_RT_HANDSHAKE;
-    if (ssl->server &&
-        ssl->s3->have_version &&
-        ssl->version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION &&
-        ssl->s3->aead_write_ctx->is_null_cipher()) {
-      type = SSL3_RT_PLAINTEXT_HANDSHAKE;
-    }
-
-    if (!add_record_to_flight(ssl, type, msg.data() + added, todo)) {
+    if (!add_record_to_flight(ssl, SSL3_RT_HANDSHAKE, chunk)) {
       return 0;
     }
-    added += todo;
-  } while (added < msg.size());
+  } while (!rest.empty());
 
   ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, msg.data(),
                       msg.size());
@@ -218,8 +208,8 @@
 int ssl3_add_change_cipher_spec(SSL *ssl) {
   static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS};
 
-  if (!add_record_to_flight(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
-                            sizeof(kChangeCipherSpec))) {
+  if (!add_record_to_flight(ssl, SSL3_RT_CHANGE_CIPHER_SPEC,
+                            kChangeCipherSpec)) {
     return 0;
   }
 
@@ -230,7 +220,7 @@
 
 int ssl3_add_alert(SSL *ssl, uint8_t level, uint8_t desc) {
   uint8_t alert[2] = {level, desc};
-  if (!add_record_to_flight(ssl, SSL3_RT_ALERT, alert, sizeof(alert))) {
+  if (!add_record_to_flight(ssl, SSL3_RT_ALERT, alert)) {
     return 0;
   }
 
diff --git a/src/ssl/s3_pkt.cc b/src/ssl/s3_pkt.cc
index b9eebf3..f7470ae 100644
--- a/src/ssl/s3_pkt.cc
+++ b/src/ssl/s3_pkt.cc
@@ -522,13 +522,7 @@
       return -1;
     }
 
-    // Accept server_plaintext_handshake records when the content type TLS 1.3
-    // variant is enabled.
-    if (rr->type != SSL3_RT_HANDSHAKE &&
-        !(!ssl->server &&
-          ssl->tls13_variant == tls13_record_type_experiment &&
-          ssl->s3->aead_read_ctx->is_null_cipher() &&
-          rr->type == SSL3_RT_PLAINTEXT_HANDSHAKE)) {
+    if (rr->type != SSL3_RT_HANDSHAKE) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
       return -1;
diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc
index d03a4a0..8856f74 100644
--- a/src/ssl/ssl_aead_ctx.cc
+++ b/src/ssl/ssl_aead_ctx.cc
@@ -56,10 +56,8 @@
 
 UniquePtr<SSLAEADContext> SSLAEADContext::Create(
     enum evp_aead_direction_t direction, uint16_t version, int is_dtls,
-    const SSL_CIPHER *cipher, const uint8_t *enc_key, size_t enc_key_len,
-    const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv,
-    size_t fixed_iv_len) {
-
+    const SSL_CIPHER *cipher, Span<const uint8_t> enc_key,
+    Span<const uint8_t> mac_key, Span<const uint8_t> fixed_iv) {
   const EVP_AEAD *aead;
   uint16_t protocol_version;
   size_t expected_mac_key_len, expected_fixed_iv_len;
@@ -68,27 +66,27 @@
                                &expected_fixed_iv_len, cipher, protocol_version,
                                is_dtls) ||
       // Ensure the caller returned correct key sizes.
-      expected_fixed_iv_len != fixed_iv_len ||
-      expected_mac_key_len != mac_key_len) {
+      expected_fixed_iv_len != fixed_iv.size() ||
+      expected_mac_key_len != mac_key.size()) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return nullptr;
   }
 
   uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH];
-  if (mac_key_len > 0) {
+  if (!mac_key.empty()) {
     // This is a "stateful" AEAD (for compatibility with pre-AEAD cipher
     // suites).
-    if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) {
+    if (mac_key.size() + enc_key.size() + fixed_iv.size() >
+        sizeof(merged_key)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
       return nullptr;
     }
-    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;
+    OPENSSL_memcpy(merged_key, mac_key.data(), mac_key.size());
+    OPENSSL_memcpy(merged_key + mac_key.size(), enc_key.data(), enc_key.size());
+    OPENSSL_memcpy(merged_key + mac_key.size() + enc_key.size(),
+                   fixed_iv.data(), fixed_iv.size());
+    enc_key = MakeConstSpan(merged_key,
+                            enc_key.size() + mac_key.size() + fixed_iv.size());
   }
 
   UniquePtr<SSLAEADContext> aead_ctx =
@@ -101,7 +99,7 @@
   assert(aead_ctx->ProtocolVersion() == protocol_version);
 
   if (!EVP_AEAD_CTX_init_with_direction(
-          aead_ctx->ctx_.get(), aead, enc_key, enc_key_len,
+          aead_ctx->ctx_.get(), aead, enc_key.data(), enc_key.size(),
           EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) {
     return nullptr;
   }
@@ -110,10 +108,10 @@
   static_assert(EVP_AEAD_MAX_NONCE_LENGTH < 256,
                 "variable_nonce_len doesn't fit in uint8_t");
   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_));
-    OPENSSL_memcpy(aead_ctx->fixed_nonce_, fixed_iv, fixed_iv_len);
-    aead_ctx->fixed_nonce_len_ = fixed_iv_len;
+  if (mac_key.empty()) {
+    assert(fixed_iv.size() <= sizeof(aead_ctx->fixed_nonce_));
+    OPENSSL_memcpy(aead_ctx->fixed_nonce_, fixed_iv.data(), fixed_iv.size());
+    aead_ctx->fixed_nonce_len_ = fixed_iv.size();
 
     if (cipher->algorithm_enc & SSL_CHACHA20POLY1305) {
       // The fixed nonce into the actual nonce (the sequence number).
@@ -121,8 +119,8 @@
       aead_ctx->variable_nonce_len_ = 8;
     } else {
       // The fixed IV is prepended to the nonce.
-      assert(fixed_iv_len <= aead_ctx->variable_nonce_len_);
-      aead_ctx->variable_nonce_len_ -= fixed_iv_len;
+      assert(fixed_iv.size() <= aead_ctx->variable_nonce_len_);
+      aead_ctx->variable_nonce_len_ -= fixed_iv.size();
     }
 
     // AES-GCM uses an explicit nonce.
@@ -137,7 +135,7 @@
       aead_ctx->variable_nonce_len_ = 8;
       aead_ctx->variable_nonce_included_in_record_ = false;
       aead_ctx->omit_ad_ = true;
-      assert(fixed_iv_len >= aead_ctx->variable_nonce_len_);
+      assert(fixed_iv.size() >= aead_ctx->variable_nonce_len_);
     }
   } else {
     assert(protocol_version < TLS1_3_VERSION);
diff --git a/src/ssl/ssl_cipher.cc b/src/ssl/ssl_cipher.cc
index 435441d..0c02389 100644
--- a/src/ssl/ssl_cipher.cc
+++ b/src/ssl/ssl_cipher.cc
@@ -553,8 +553,8 @@
 
 typedef struct cipher_order_st {
   const SSL_CIPHER *cipher;
-  int active;
-  int in_group;
+  bool active;
+  bool in_group;
   struct cipher_order_st *next, *prev;
 } CIPHER_ORDER;
 
@@ -645,10 +645,10 @@
   }
 }
 
-int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
-                            size_t *out_mac_secret_len,
-                            size_t *out_fixed_iv_len,
-                            const SSL_CIPHER *cipher, uint16_t version, int is_dtls) {
+bool ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
+                             size_t *out_mac_secret_len,
+                             size_t *out_fixed_iv_len, const SSL_CIPHER *cipher,
+                             uint16_t version, int is_dtls) {
   *out_aead = NULL;
   *out_mac_secret_len = 0;
   *out_fixed_iv_len = 0;
@@ -668,7 +668,7 @@
       *out_aead = EVP_aead_chacha20_poly1305();
       *out_fixed_iv_len = 12;
     } else {
-      return 0;
+      return false;
     }
 
     // In TLS 1.3, the iv_len is equal to the AEAD nonce length whereas the code
@@ -714,7 +714,7 @@
         *out_aead = EVP_aead_aes_256_cbc_sha1_tls();
       }
     } else {
-      return 0;
+      return false;
     }
 
     *out_mac_secret_len = SHA_DIGEST_LENGTH;
@@ -724,22 +724,22 @@
     } else if (cipher->algorithm_enc == SSL_AES256) {
       *out_aead = EVP_aead_aes_256_cbc_sha256_tls();
     } else {
-      return 0;
+      return false;
     }
 
     *out_mac_secret_len = SHA256_DIGEST_LENGTH;
   } else if (cipher->algorithm_mac == SSL_SHA384) {
       if (cipher->algorithm_enc != SSL_AES256) {
-        return 0;
+        return false;
       }
 
       *out_aead = EVP_aead_aes_256_cbc_sha384_tls();
       *out_mac_secret_len = SHA384_DIGEST_LENGTH;
   } else {
-    return 0;
+    return false;
   }
 
-  return 1;
+  return true;
 }
 
 const EVP_MD *ssl_get_handshake_digest(uint16_t version,
@@ -764,9 +764,9 @@
   return !is_strict && (c == ' ' || c == ';' || c == ',');
 }
 
-// rule_equals returns one iff the NUL-terminated string |rule| is equal to the
+// rule_equals returns whether the NUL-terminated string |rule| is equal to the
 // |buf_len| bytes at |buf|.
-static int rule_equals(const char *rule, const char *buf, size_t buf_len) {
+static bool rule_equals(const char *rule, const char *buf, size_t buf_len) {
   // |strncmp| alone only checks that |buf| is a prefix of |rule|.
   return strncmp(rule, buf, buf_len) == 0 && rule[buf_len] == '\0';
 }
@@ -826,8 +826,8 @@
       co_list[co_list_num].cipher = cipher;
       co_list[co_list_num].next = NULL;
       co_list[co_list_num].prev = NULL;
-      co_list[co_list_num].active = 0;
-      co_list[co_list_num].in_group = 0;
+      co_list[co_list_num].active = false;
+      co_list[co_list_num].in_group = false;
       co_list_num++;
     }
   }
@@ -866,11 +866,11 @@
 static void ssl_cipher_apply_rule(
     uint32_t cipher_id, uint32_t alg_mkey, uint32_t alg_auth,
     uint32_t alg_enc, uint32_t alg_mac, uint16_t min_version, int rule,
-    int strength_bits, int in_group, CIPHER_ORDER **head_p,
+    int strength_bits, bool in_group, CIPHER_ORDER **head_p,
     CIPHER_ORDER **tail_p) {
   CIPHER_ORDER *head, *tail, *curr, *next, *last;
   const SSL_CIPHER *cp;
-  int reverse = 0;
+  bool reverse = false;
 
   if (cipher_id == 0 && strength_bits == -1 && min_version == 0 &&
       (alg_mkey == 0 || alg_auth == 0 || alg_enc == 0 || alg_mac == 0)) {
@@ -880,7 +880,7 @@
 
   if (rule == CIPHER_DEL) {
     // needed to maintain sorting between currently deleted ciphers
-    reverse = 1;
+    reverse = true;
   }
 
   head = *head_p;
@@ -930,33 +930,33 @@
 
     // add the cipher if it has not been added yet.
     if (rule == CIPHER_ADD) {
-      // reverse == 0
+      // reverse == false
       if (!curr->active) {
         ll_append_tail(&head, curr, &tail);
-        curr->active = 1;
+        curr->active = true;
         curr->in_group = in_group;
       }
     }
 
     // Move the added cipher to this location
     else if (rule == CIPHER_ORD) {
-      // reverse == 0
+      // reverse == false
       if (curr->active) {
         ll_append_tail(&head, curr, &tail);
-        curr->in_group = 0;
+        curr->in_group = false;
       }
     } else if (rule == CIPHER_DEL) {
-      // reverse == 1
+      // reverse == true
       if (curr->active) {
         // most recently deleted ciphersuites get best positions
         // for any future CIPHER_ADD (note that the CIPHER_DEL loop
         // works in reverse to maintain the order)
         ll_append_head(&head, curr, &tail);
-        curr->active = 0;
-        curr->in_group = 0;
+        curr->active = false;
+        curr->in_group = false;
       }
     } else if (rule == CIPHER_KILL) {
-      // reverse == 0
+      // reverse == false
       if (head == curr) {
         head = curr->next;
       } else {
@@ -966,7 +966,7 @@
       if (tail == curr) {
         tail = curr->prev;
       }
-      curr->active = 0;
+      curr->active = false;
       if (curr->next != NULL) {
         curr->next->prev = curr->prev;
       }
@@ -982,16 +982,13 @@
   *tail_p = tail;
 }
 
-static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
-                                    CIPHER_ORDER **tail_p) {
-  int max_strength_bits, i, *number_uses;
-  CIPHER_ORDER *curr;
-
+static bool ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
+                                     CIPHER_ORDER **tail_p) {
   // This routine sorts the ciphers with descending strength. The sorting must
   // keep the pre-sorted sequence, so we apply the normal sorting routine as
   // '+' movement to the end of the list.
-  max_strength_bits = 0;
-  curr = *head_p;
+  int max_strength_bits = 0;
+  CIPHER_ORDER *curr = *head_p;
   while (curr != NULL) {
     if (curr->active &&
         SSL_CIPHER_get_bits(curr->cipher, NULL) > max_strength_bits) {
@@ -1000,12 +997,11 @@
     curr = curr->next;
   }
 
-  number_uses = (int *)OPENSSL_malloc((max_strength_bits + 1) * sizeof(int));
-  if (!number_uses) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return 0;
+  Array<int> number_uses;
+  if (!number_uses.Init(max_strength_bits + 1)) {
+    return false;
   }
-  OPENSSL_memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int));
+  OPENSSL_memset(number_uses.data(), 0, (max_strength_bits + 1) * sizeof(int));
 
   // Now find the strength_bits values actually used.
   curr = *head_p;
@@ -1017,24 +1013,25 @@
   }
 
   // Go through the list of used strength_bits values in descending order.
-  for (i = max_strength_bits; i >= 0; i--) {
+  for (int i = max_strength_bits; i >= 0; i--) {
     if (number_uses[i] > 0) {
-      ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, CIPHER_ORD, i, 0, head_p, tail_p);
+      ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, CIPHER_ORD, i, false, head_p,
+                            tail_p);
     }
   }
 
-  OPENSSL_free(number_uses);
-  return 1;
+  return true;
 }
 
-static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
-                                      const char *rule_str,
-                                      CIPHER_ORDER **head_p,
-                                      CIPHER_ORDER **tail_p, int strict) {
+static bool ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
+                                       const char *rule_str,
+                                       CIPHER_ORDER **head_p,
+                                       CIPHER_ORDER **tail_p, bool strict) {
   uint32_t alg_mkey, alg_auth, alg_enc, alg_mac;
   uint16_t min_version;
   const char *l, *buf;
-  int multi, skip_rule, rule, in_group = 0, has_group = 0;
+  int rule;
+  bool multi, skip_rule, in_group = false, has_group = false;
   size_t j, buf_len;
   uint32_t cipher_id;
   char ch;
@@ -1050,9 +1047,9 @@
     if (in_group) {
       if (ch == ']') {
         if (*tail_p) {
-          (*tail_p)->in_group = 0;
+          (*tail_p)->in_group = false;
         }
-        in_group = 0;
+        in_group = false;
         l++;
         continue;
       }
@@ -1064,7 +1061,7 @@
       } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') &&
                  !(ch >= '0' && ch <= '9')) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP);
-        return 0;
+        return false;
       } else {
         rule = CIPHER_ADD;
       }
@@ -1082,8 +1079,8 @@
       l++;
     } else if (ch == '[') {
       assert(!in_group);
-      in_group = 1;
-      has_group = 1;
+      in_group = true;
+      has_group = true;
       l++;
       continue;
     } else {
@@ -1094,7 +1091,7 @@
     // Otherwise the in_group bits will get mixed up.
     if (has_group && rule != CIPHER_ADD) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
-      return 0;
+      return false;
     }
 
     if (is_cipher_list_separator(ch, strict)) {
@@ -1102,14 +1099,14 @@
       continue;
     }
 
-    multi = 0;
+    multi = false;
     cipher_id = 0;
     alg_mkey = ~0u;
     alg_auth = ~0u;
     alg_enc = ~0u;
     alg_mac = ~0u;
     min_version = 0;
-    skip_rule = 0;
+    skip_rule = false;
 
     for (;;) {
       ch = *l;
@@ -1125,7 +1122,7 @@
         // We hit something we cannot deal with, it is no command or separator
         // nor alphanumeric, so we call this an error.
         OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
-        return 0;
+        return false;
       }
 
       if (rule == CIPHER_SPECIAL) {
@@ -1155,7 +1152,7 @@
 
             if (min_version != 0 &&
                 min_version != kCipherAliases[j].min_version) {
-              skip_rule = 1;
+              skip_rule = true;
             } else {
               min_version = kCipherAliases[j].min_version;
             }
@@ -1163,10 +1160,10 @@
           }
         }
         if (j == kCipherAliasesLen) {
-          skip_rule = 1;
+          skip_rule = true;
           if (strict) {
             OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
-            return 0;
+            return false;
           }
         }
       }
@@ -1176,17 +1173,17 @@
         break;
       }
       l++;
-      multi = 1;
+      multi = true;
     }
 
     // Ok, we have the rule, now apply it.
     if (rule == CIPHER_SPECIAL) {
       if (buf_len != 8 || strncmp(buf, "STRENGTH", 8) != 0) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
-        return 0;
+        return false;
       }
       if (!ssl_cipher_strength_sort(head_p, tail_p)) {
-        return 0;
+        return false;
       }
 
       // We do not support any "multi" options together with "@", so throw away
@@ -1202,16 +1199,16 @@
 
   if (in_group) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
-    return 0;
+    return false;
   }
 
-  return 1;
+  return true;
 }
 
-int ssl_create_cipher_list(
+bool ssl_create_cipher_list(
     const SSL_PROTOCOL_METHOD *ssl_method,
     struct ssl_cipher_preference_list_st **out_cipher_list,
-    const char *rule_str, int strict) {
+    const char *rule_str, bool strict) {
   STACK_OF(SSL_CIPHER) *cipherstack = NULL;
   CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
   uint8_t *in_group_flags = NULL;
@@ -1220,7 +1217,7 @@
 
   // Return with error if nothing to do.
   if (rule_str == NULL || out_cipher_list == NULL) {
-    return 0;
+    return false;
   }
 
   // Now we have to collect the available ciphers from the compiled in ciphers.
@@ -1229,7 +1226,7 @@
   co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen);
   if (co_list == NULL) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return 0;
+    return false;
   }
 
   ssl_cipher_collect_ciphers(ssl_method, co_list, &head, &tail);
@@ -1240,10 +1237,10 @@
   // Everything else being equal, prefer ECDHE_ECDSA and ECDHE_RSA over other
   // key exchange mechanisms
   ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1,
-                        0, &head, &tail);
-  ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0,
+                        false, &head, &tail);
+  ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, false,
                         &head, &tail);
-  ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, &head,
+  ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, false, &head,
                         &tail);
 
   // Order the bulk ciphers. First the preferred AEAD ciphers. We prefer
@@ -1251,40 +1248,40 @@
   // AES_GCM. Of the two CHACHA20 variants, the new one is preferred over the
   // old one.
   if (EVP_has_aes_hardware()) {
-    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0,
-                          &head, &tail);
-    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
-                          &head, &tail);
+    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1,
+                          false, &head, &tail);
+    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1,
+                          false, &head, &tail);
     ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0, CIPHER_ADD,
-                          -1, 0, &head, &tail);
+                          -1, false, &head, &tail);
   } else {
     ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0, CIPHER_ADD,
-                          -1, 0, &head, &tail);
-    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0,
-                          &head, &tail);
-    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
-                          &head, &tail);
+                          -1, false, &head, &tail);
+    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1,
+                          false, &head, &tail);
+    ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1,
+                          false, &head, &tail);
   }
 
   // Then the legacy non-AEAD ciphers: AES_128_CBC, AES_256_CBC,
   // 3DES_EDE_CBC_SHA.
-  ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128, ~0u, 0, CIPHER_ADD, -1, 0,
+  ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128, ~0u, 0, CIPHER_ADD, -1, false,
                         &head, &tail);
-  ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, 0, CIPHER_ADD, -1, 0,
+  ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, 0, CIPHER_ADD, -1, false,
                         &head, &tail);
-  ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_3DES, ~0u, 0, CIPHER_ADD, -1, 0, &head,
-                        &tail);
+  ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_3DES, ~0u, 0, CIPHER_ADD, -1, false,
+                        &head, &tail);
 
   // Temporarily enable everything else for sorting
-  ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0, &head,
+  ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, false, &head,
                         &tail);
 
   // Move ciphers without forward secrecy to the end.
-  ssl_cipher_apply_rule(0, (SSL_kRSA | SSL_kPSK), ~0u, ~0u, ~0u, 0,
-                        CIPHER_ORD, -1, 0, &head, &tail);
+  ssl_cipher_apply_rule(0, (SSL_kRSA | SSL_kPSK), ~0u, ~0u, ~0u, 0, CIPHER_ORD,
+                        -1, false, &head, &tail);
 
   // Now disable everything (maintaining the ordering!)
-  ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, &head,
+  ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, false, &head,
                         &tail);
 
   // If the rule_string begins with DEFAULT, apply the default rule before
@@ -1358,10 +1355,10 @@
   // output.
   if (sk_SSL_CIPHER_num((*out_cipher_list)->ciphers) == 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
-    return 0;
+    return false;
   }
 
-  return 1;
+  return true;
 
 err:
   OPENSSL_free(co_list);
@@ -1371,7 +1368,7 @@
     OPENSSL_free(pref_list->in_group_flags);
   }
   OPENSSL_free(pref_list);
-  return 0;
+  return false;
 }
 
 uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) {
@@ -1394,18 +1391,14 @@
   }
 }
 
-int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) {
+bool ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) {
   return (cipher->algorithm_auth & SSL_aCERT) != 0;
 }
 
-int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) {
-  // Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange.
-  if (cipher->algorithm_mkey & SSL_kECDHE) {
-    return 1;
-  }
-
-  // It is optional in all others.
-  return 0;
+bool ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) {
+  // Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. It is
+  // optional or omitted in all others.
+  return (cipher->algorithm_mkey & SSL_kECDHE) != 0;
 }
 
 size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher) {
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index b864f8d..f62d155 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -1741,22 +1741,22 @@
 
 int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
   return ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str,
-                                0 /* not strict */);
+                                false /* not strict */);
 }
 
 int SSL_CTX_set_strict_cipher_list(SSL_CTX *ctx, const char *str) {
   return ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str,
-                                1 /* strict */);
+                                true /* strict */);
 }
 
 int SSL_set_cipher_list(SSL *ssl, const char *str) {
   return ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str,
-                                0 /* not strict */);
+                                false /* not strict */);
 }
 
 int SSL_set_strict_cipher_list(SSL *ssl, const char *str) {
   return ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str,
-                                1 /* strict */);
+                                true /* strict */);
 }
 
 const char *SSL_get_servername(const SSL *ssl, const int type) {
diff --git a/src/ssl/ssl_session.cc b/src/ssl/ssl_session.cc
index ed4c779..aff9c0f 100644
--- a/src/ssl/ssl_session.cc
+++ b/src/ssl/ssl_session.cc
@@ -340,7 +340,7 @@
   }
 }
 
-uint16_t SSL_SESSION_protocol_version(const SSL_SESSION *session) {
+uint16_t ssl_session_protocol_version(const SSL_SESSION *session) {
   uint16_t ret;
   if (!ssl_protocol_version_from_wire(&ret, session->ssl_version)) {
     // An |SSL_SESSION| will never have an invalid version. This is enforced by
@@ -352,8 +352,8 @@
   return ret;
 }
 
-const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session) {
-  return ssl_get_handshake_digest(SSL_SESSION_protocol_version(session),
+const EVP_MD *ssl_session_get_digest(const SSL_SESSION *session) {
+  return ssl_get_handshake_digest(ssl_session_protocol_version(session),
                                   session->cipher);
 }
 
@@ -967,7 +967,7 @@
 }
 
 int SSL_SESSION_should_be_single_use(const SSL_SESSION *session) {
-  return SSL_SESSION_protocol_version(session) >= TLS1_3_VERSION;
+  return ssl_session_protocol_version(session) >= TLS1_3_VERSION;
 }
 
 int SSL_SESSION_is_resumable(const SSL_SESSION *session) {
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 4653f73..f9cf83c 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -3740,6 +3740,26 @@
   EXPECT_EQ(SSL_R_NO_CIPHERS_AVAILABLE, ERR_GET_REASON(err));
 }
 
+TEST_P(SSLVersionTest, SessionVersion) {
+  SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH);
+  SSL_CTX_set_session_cache_mode(server_ctx_.get(), SSL_SESS_CACHE_BOTH);
+
+  bssl::UniquePtr<SSL_SESSION> session =
+      CreateClientSession(client_ctx_.get(), server_ctx_.get());
+  ASSERT_TRUE(session);
+  EXPECT_EQ(version(), SSL_SESSION_get_protocol_version(session.get()));
+
+  // Sessions in TLS 1.3 and later should be single-use.
+  EXPECT_EQ(version() == TLS1_3_VERSION,
+            !!SSL_SESSION_should_be_single_use(session.get()));
+
+  // Making fake sessions for testing works.
+  session.reset(SSL_SESSION_new(client_ctx_.get()));
+  ASSERT_TRUE(session);
+  ASSERT_TRUE(SSL_SESSION_set_protocol_version(session.get(), version()));
+  EXPECT_EQ(version(), SSL_SESSION_get_protocol_version(session.get()));
+}
+
 // TODO(davidben): Convert this file to GTest properly.
 TEST(SSLTest, AllTests) {
   if (!TestSSL_SESSIONEncoding(kOpenSSLSession) ||
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index 560d0cf..56653b1 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -25,34 +25,33 @@
 
 namespace bssl {
 
-int ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) {
+bool ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) {
   switch (version) {
     case SSL3_VERSION:
     case TLS1_VERSION:
     case TLS1_1_VERSION:
     case TLS1_2_VERSION:
       *out = version;
-      return 1;
+      return true;
 
     case TLS1_3_DRAFT_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
-    case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION:
       *out = TLS1_3_VERSION;
-      return 1;
+      return true;
 
     case DTLS1_VERSION:
       // DTLS 1.0 is analogous to TLS 1.1, not TLS 1.0.
       *out = TLS1_1_VERSION;
-      return 1;
+      return true;
 
     case DTLS1_2_VERSION:
       *out = TLS1_2_VERSION;
-      return 1;
+      return true;
 
     default:
-      return 0;
+      return false;
   }
 }
 
@@ -63,7 +62,6 @@
     TLS1_3_EXPERIMENT3_VERSION,
     TLS1_3_EXPERIMENT2_VERSION,
     TLS1_3_EXPERIMENT_VERSION,
-    TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION,
     TLS1_3_DRAFT_VERSION,
     TLS1_2_VERSION,
     TLS1_1_VERSION,
@@ -87,157 +85,30 @@
   }
 }
 
-static int method_supports_version(const SSL_PROTOCOL_METHOD *method,
-                                   uint16_t version) {
+static bool method_supports_version(const SSL_PROTOCOL_METHOD *method,
+                                    uint16_t version) {
   const uint16_t *versions;
   size_t num_versions;
   get_method_versions(method, &versions, &num_versions);
   for (size_t i = 0; i < num_versions; i++) {
     if (versions[i] == version) {
-      return 1;
+      return true;
     }
   }
-  return 0;
+  return false;
 }
 
-static int set_version_bound(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
-                             uint16_t version) {
-  // The public API uses wire versions, except we use |TLS1_3_VERSION|
-  // everywhere to refer to any draft TLS 1.3 versions. In this direction, we
-  // map it to some representative TLS 1.3 draft version.
-  if (version == TLS1_3_DRAFT_VERSION ||
-      version == TLS1_3_EXPERIMENT_VERSION ||
-      version == TLS1_3_EXPERIMENT2_VERSION ||
-      version == TLS1_3_EXPERIMENT3_VERSION ||
-      version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
-    return 0;
-  }
-  if (version == TLS1_3_VERSION) {
-    version = TLS1_3_DRAFT_VERSION;
-  }
-
-  if (!method_supports_version(method, version) ||
-      !ssl_protocol_version_from_wire(out, version)) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
-    return 0;
-  }
-
-  return 1;
-}
-
-static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
-                           uint16_t version) {
-  // Zero is interpreted as the default minimum version.
-  if (version == 0) {
-    // SSL 3.0 is disabled by default and TLS 1.0 does not exist in DTLS.
-    *out = method->is_dtls ? TLS1_1_VERSION : TLS1_VERSION;
-    return 1;
-  }
-
-  return set_version_bound(method, out, version);
-}
-
-static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
-                           uint16_t version) {
-  // Zero is interpreted as the default maximum version.
-  if (version == 0) {
-    *out = TLS1_2_VERSION;
-    return 1;
-  }
-
-  return set_version_bound(method, out, version);
-}
-
-const struct {
-  uint16_t version;
-  uint32_t flag;
-} kProtocolVersions[] = {
-    {SSL3_VERSION, SSL_OP_NO_SSLv3},
-    {TLS1_VERSION, SSL_OP_NO_TLSv1},
-    {TLS1_1_VERSION, SSL_OP_NO_TLSv1_1},
-    {TLS1_2_VERSION, SSL_OP_NO_TLSv1_2},
-    {TLS1_3_VERSION, SSL_OP_NO_TLSv1_3},
-};
-
-int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
-                          uint16_t *out_max_version) {
-  // For historical reasons, |SSL_OP_NO_DTLSv1| aliases |SSL_OP_NO_TLSv1|, but
-  // DTLS 1.0 should be mapped to TLS 1.1.
-  uint32_t options = ssl->options;
-  if (SSL_is_dtls(ssl)) {
-    options &= ~SSL_OP_NO_TLSv1_1;
-    if (options & SSL_OP_NO_DTLSv1) {
-      options |= SSL_OP_NO_TLSv1_1;
-    }
-  }
-
-  uint16_t min_version = ssl->conf_min_version;
-  uint16_t max_version = ssl->conf_max_version;
-
-  // OpenSSL's API for controlling versions entails blacklisting individual
-  // protocols. This has two problems. First, on the client, the protocol can
-  // only express a contiguous range of versions. Second, a library consumer
-  // trying to set a maximum version cannot disable protocol versions that get
-  // added in a future version of the library.
-  //
-  // To account for both of these, OpenSSL interprets the client-side bitmask
-  // as a min/max range by picking the lowest contiguous non-empty range of
-  // enabled protocols. Note that this means it is impossible to set a maximum
-  // version of the higest supported TLS version in a future-proof way.
-  int any_enabled = 0;
-  for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kProtocolVersions); i++) {
-    // Only look at the versions already enabled.
-    if (min_version > kProtocolVersions[i].version) {
-      continue;
-    }
-    if (max_version < kProtocolVersions[i].version) {
-      break;
-    }
-
-    if (!(options & kProtocolVersions[i].flag)) {
-      // The minimum version is the first enabled version.
-      if (!any_enabled) {
-        any_enabled = 1;
-        min_version = kProtocolVersions[i].version;
-      }
-      continue;
-    }
-
-    // If there is a disabled version after the first enabled one, all versions
-    // after it are implicitly disabled.
-    if (any_enabled) {
-      max_version = kProtocolVersions[i-1].version;
-      break;
-    }
-  }
-
-  if (!any_enabled) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SUPPORTED_VERSIONS_ENABLED);
-    return 0;
-  }
-
-  *out_min_version = min_version;
-  *out_max_version = max_version;
-  return 1;
-}
-
-static uint16_t ssl_version(const SSL *ssl) {
-  // In early data, we report the predicted version.
-  if (SSL_in_early_data(ssl) && !ssl->server) {
-    return ssl->s3->hs->early_session->ssl_version;
-  }
-  return ssl->version;
-}
+// The following functions map between API versions and wire versions. The
+// public API works on wire versions, except that TLS 1.3 draft versions all
+// appear as TLS 1.3. This will get collapsed back down when TLS 1.3 is
+// finalized.
 
 static const char *ssl_version_to_string(uint16_t version) {
   switch (version) {
-    // Report TLS 1.3 draft version as TLS 1.3 in the public API.
     case TLS1_3_DRAFT_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
-    case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION:
       return "TLSv1.3";
 
     case TLS1_2_VERSION:
@@ -263,6 +134,159 @@
   }
 }
 
+static uint16_t wire_version_to_api(uint16_t version) {
+  switch (version) {
+    // Report TLS 1.3 draft versions as TLS 1.3 in the public API.
+    case TLS1_3_DRAFT_VERSION:
+    case TLS1_3_EXPERIMENT_VERSION:
+    case TLS1_3_EXPERIMENT2_VERSION:
+    case TLS1_3_EXPERIMENT3_VERSION:
+      return TLS1_3_VERSION;
+    default:
+      return version;
+  }
+}
+
+// api_version_to_wire maps |version| to some representative wire version. In
+// particular, it picks an arbitrary TLS 1.3 representative. This should only be
+// used in context where that does not matter.
+static bool api_version_to_wire(uint16_t *out, uint16_t version) {
+  if (version == TLS1_3_DRAFT_VERSION ||
+      version == TLS1_3_EXPERIMENT_VERSION ||
+      version == TLS1_3_EXPERIMENT2_VERSION ||
+      version == TLS1_3_EXPERIMENT3_VERSION) {
+    return false;
+  }
+  if (version == TLS1_3_VERSION) {
+    version = TLS1_3_DRAFT_VERSION;
+  }
+
+  // Check it is a real protocol version.
+  uint16_t unused;
+  if (!ssl_protocol_version_from_wire(&unused, version)) {
+    return false;
+  }
+
+  *out = version;
+  return true;
+}
+
+static bool set_version_bound(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+                              uint16_t version) {
+  if (!api_version_to_wire(&version, version) ||
+      !method_supports_version(method, version) ||
+      !ssl_protocol_version_from_wire(out, version)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
+    return false;
+  }
+
+  return true;
+}
+
+static bool set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+                            uint16_t version) {
+  // Zero is interpreted as the default minimum version.
+  if (version == 0) {
+    // SSL 3.0 is disabled by default and TLS 1.0 does not exist in DTLS.
+    *out = method->is_dtls ? TLS1_1_VERSION : TLS1_VERSION;
+    return true;
+  }
+
+  return set_version_bound(method, out, version);
+}
+
+static bool set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+                            uint16_t version) {
+  // Zero is interpreted as the default maximum version.
+  if (version == 0) {
+    *out = TLS1_2_VERSION;
+    return true;
+  }
+
+  return set_version_bound(method, out, version);
+}
+
+const struct {
+  uint16_t version;
+  uint32_t flag;
+} kProtocolVersions[] = {
+    {SSL3_VERSION, SSL_OP_NO_SSLv3},
+    {TLS1_VERSION, SSL_OP_NO_TLSv1},
+    {TLS1_1_VERSION, SSL_OP_NO_TLSv1_1},
+    {TLS1_2_VERSION, SSL_OP_NO_TLSv1_2},
+    {TLS1_3_VERSION, SSL_OP_NO_TLSv1_3},
+};
+
+bool ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
+                           uint16_t *out_max_version) {
+  // For historical reasons, |SSL_OP_NO_DTLSv1| aliases |SSL_OP_NO_TLSv1|, but
+  // DTLS 1.0 should be mapped to TLS 1.1.
+  uint32_t options = ssl->options;
+  if (SSL_is_dtls(ssl)) {
+    options &= ~SSL_OP_NO_TLSv1_1;
+    if (options & SSL_OP_NO_DTLSv1) {
+      options |= SSL_OP_NO_TLSv1_1;
+    }
+  }
+
+  uint16_t min_version = ssl->conf_min_version;
+  uint16_t max_version = ssl->conf_max_version;
+
+  // OpenSSL's API for controlling versions entails blacklisting individual
+  // protocols. This has two problems. First, on the client, the protocol can
+  // only express a contiguous range of versions. Second, a library consumer
+  // trying to set a maximum version cannot disable protocol versions that get
+  // added in a future version of the library.
+  //
+  // To account for both of these, OpenSSL interprets the client-side bitmask
+  // as a min/max range by picking the lowest contiguous non-empty range of
+  // enabled protocols. Note that this means it is impossible to set a maximum
+  // version of the higest supported TLS version in a future-proof way.
+  bool any_enabled = false;
+  for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kProtocolVersions); i++) {
+    // Only look at the versions already enabled.
+    if (min_version > kProtocolVersions[i].version) {
+      continue;
+    }
+    if (max_version < kProtocolVersions[i].version) {
+      break;
+    }
+
+    if (!(options & kProtocolVersions[i].flag)) {
+      // The minimum version is the first enabled version.
+      if (!any_enabled) {
+        any_enabled = true;
+        min_version = kProtocolVersions[i].version;
+      }
+      continue;
+    }
+
+    // If there is a disabled version after the first enabled one, all versions
+    // after it are implicitly disabled.
+    if (any_enabled) {
+      max_version = kProtocolVersions[i-1].version;
+      break;
+    }
+  }
+
+  if (!any_enabled) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SUPPORTED_VERSIONS_ENABLED);
+    return false;
+  }
+
+  *out_min_version = min_version;
+  *out_max_version = max_version;
+  return true;
+}
+
+static uint16_t ssl_version(const SSL *ssl) {
+  // In early data, we report the predicted version.
+  if (SSL_in_early_data(ssl) && !ssl->server) {
+    return ssl->s3->hs->early_session->ssl_version;
+  }
+  return ssl->version;
+}
+
 uint16_t ssl3_protocol_version(const SSL *ssl) {
   assert(ssl->s3->have_version);
   uint16_t version;
@@ -275,7 +299,7 @@
   return version;
 }
 
-int ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
+bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
   SSL *const ssl = hs->ssl;
   // As a client, only allow the configured TLS 1.3 variant. As a server,
   // support all TLS 1.3 variants as long as tls13_variant is set to a
@@ -284,23 +308,19 @@
     if (ssl->tls13_variant == tls13_default &&
         (version == TLS1_3_EXPERIMENT_VERSION ||
          version == TLS1_3_EXPERIMENT2_VERSION ||
-         version == TLS1_3_EXPERIMENT3_VERSION ||
-         version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION)) {
-      return 0;
+         version == TLS1_3_EXPERIMENT3_VERSION)) {
+      return false;
     }
   } else {
     if ((ssl->tls13_variant != tls13_experiment &&
-         ssl->tls13_variant != tls13_no_session_id_experiment &&
          version == TLS1_3_EXPERIMENT_VERSION) ||
         (ssl->tls13_variant != tls13_experiment2 &&
          version == TLS1_3_EXPERIMENT2_VERSION) ||
         (ssl->tls13_variant != tls13_experiment3 &&
          version == TLS1_3_EXPERIMENT3_VERSION) ||
-        (ssl->tls13_variant != tls13_record_type_experiment &&
-         version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) ||
         (ssl->tls13_variant != tls13_default &&
          version == TLS1_3_DRAFT_VERSION)) {
-      return 0;
+      return false;
     }
   }
 
@@ -311,21 +331,21 @@
          protocol_version <= hs->max_version;
 }
 
-int ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb) {
+bool ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb) {
   const uint16_t *versions;
   size_t num_versions;
   get_method_versions(hs->ssl->method, &versions, &num_versions);
   for (size_t i = 0; i < num_versions; i++) {
     if (ssl_supports_version(hs, versions[i]) &&
         !CBB_add_u16(cbb, versions[i])) {
-      return 0;
+      return false;
     }
   }
-  return 1;
+  return true;
 }
 
-int ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
-                          uint16_t *out_version, const CBS *peer_versions) {
+bool ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+                           uint16_t *out_version, const CBS *peer_versions) {
   const uint16_t *versions;
   size_t num_versions;
   get_method_versions(hs->ssl->method, &versions, &num_versions);
@@ -340,19 +360,19 @@
       if (!CBS_get_u16(&copy, &version)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
         *out_alert = SSL_AD_DECODE_ERROR;
-        return 0;
+        return false;
       }
 
       if (version == versions[i]) {
         *out_version = version;
-        return 1;
+        return true;
       }
     }
   }
 
   OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
   *out_alert = SSL_AD_PROTOCOL_VERSION;
-  return 0;
+  return false;
 }
 
 bool ssl_is_resumption_experiment(uint16_t version) {
@@ -397,16 +417,7 @@
 }
 
 int SSL_version(const SSL *ssl) {
-  uint16_t ret = ssl_version(ssl);
-  // Report TLS 1.3 draft version as TLS 1.3 in the public API.
-  if (ret == TLS1_3_DRAFT_VERSION ||
-      ret == TLS1_3_EXPERIMENT_VERSION ||
-      ret == TLS1_3_EXPERIMENT2_VERSION ||
-      ret == TLS1_3_EXPERIMENT3_VERSION ||
-      ret == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) {
-    return TLS1_3_VERSION;
-  }
-  return ret;
+  return wire_version_to_api(ssl_version(ssl));
 }
 
 const char *SSL_get_version(const SSL *ssl) {
@@ -416,3 +427,13 @@
 const char *SSL_SESSION_get_version(const SSL_SESSION *session) {
   return ssl_version_to_string(session->ssl_version);
 }
+
+uint16_t SSL_SESSION_get_protocol_version(const SSL_SESSION *session) {
+  return wire_version_to_api(session->ssl_version);
+}
+
+int SSL_SESSION_set_protocol_version(SSL_SESSION *session, uint16_t version) {
+  // This picks a representative TLS 1.3 version, but this API should only be
+  // used on unit test sessions anyway.
+  return api_version_to_wire(&session->ssl_version, version);
+}
diff --git a/src/ssl/t1_enc.cc b/src/ssl/t1_enc.cc
index d693007..85c368c 100644
--- a/src/ssl/t1_enc.cc
+++ b/src/ssl/t1_enc.cc
@@ -318,7 +318,7 @@
 
 static int tls1_setup_key_block(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (hs->key_block_len != 0) {
+  if (!hs->key_block.empty()) {
     return 1;
   }
 
@@ -356,22 +356,13 @@
   ssl->s3->tmp.new_key_len = (uint8_t)key_len;
   ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
 
-  size_t key_block_len = SSL_get_key_block_len(ssl);
-
-  uint8_t *keyblock = (uint8_t *)OPENSSL_malloc(key_block_len);
-  if (keyblock == NULL) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+  Array<uint8_t> key_block;
+  if (!key_block.Init(SSL_get_key_block_len(ssl)) ||
+      !SSL_generate_key_block(ssl, key_block.data(), key_block.size())) {
     return 0;
   }
 
-  if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
-    OPENSSL_free(keyblock);
-    return 0;
-  }
-
-  assert(key_block_len < 256);
-  hs->key_block_len = (uint8_t)key_block_len;
-  hs->key_block = keyblock;
+  hs->key_block = std::move(key_block);
   return 1;
 }
 
@@ -383,45 +374,28 @@
     return 0;
   }
 
-  // use_client_keys is true if we wish to use the keys for the "client write"
-  // direction. This is the case if we're a client sending a ChangeCipherSpec,
-  // or a server reading a client's ChangeCipherSpec.
-  const bool use_client_keys =
-      direction == (ssl->server ? evp_aead_open : evp_aead_seal);
-
   size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len;
   size_t key_len = ssl->s3->tmp.new_key_len;
   size_t iv_len = ssl->s3->tmp.new_fixed_iv_len;
-  assert((mac_secret_len + key_len + iv_len) * 2 == hs->key_block_len);
+  assert((mac_secret_len + key_len + iv_len) * 2 == hs->key_block.size());
 
-  const uint8_t *key_data = hs->key_block;
-  const uint8_t *client_write_mac_secret = key_data;
-  key_data += mac_secret_len;
-  const uint8_t *server_write_mac_secret = key_data;
-  key_data += mac_secret_len;
-  const uint8_t *client_write_key = key_data;
-  key_data += key_len;
-  const uint8_t *server_write_key = key_data;
-  key_data += key_len;
-  const uint8_t *client_write_iv = key_data;
-  key_data += iv_len;
-  const uint8_t *server_write_iv = key_data;
-  key_data += iv_len;
-
-  const uint8_t *mac_secret, *key, *iv;
-  if (use_client_keys) {
-    mac_secret = client_write_mac_secret;
-    key = client_write_key;
-    iv = client_write_iv;
+  Span<const uint8_t> key_block = hs->key_block;
+  Span<const uint8_t> mac_secret, key, iv;
+  if (direction == (ssl->server ? evp_aead_open : evp_aead_seal)) {
+    // Use the client write (server read) keys.
+    mac_secret = key_block.subspan(0, mac_secret_len);
+    key = key_block.subspan(2 * mac_secret_len, key_len);
+    iv = key_block.subspan(2 * mac_secret_len + 2 * key_len, iv_len);
   } else {
-    mac_secret = server_write_mac_secret;
-    key = server_write_key;
-    iv = server_write_iv;
+    // Use the server write (client read) keys.
+    mac_secret = key_block.subspan(mac_secret_len, mac_secret_len);
+    key = key_block.subspan(2 * mac_secret_len + key_len, key_len);
+    iv = key_block.subspan(2 * mac_secret_len + 2 * key_len + iv_len, iv_len);
   }
 
-  UniquePtr<SSLAEADContext> aead_ctx = SSLAEADContext::Create(
-      direction, ssl->version, SSL_is_dtls(ssl), hs->new_cipher, key, key_len,
-      mac_secret, mac_secret_len, iv, iv_len);
+  UniquePtr<SSLAEADContext> aead_ctx =
+      SSLAEADContext::Create(direction, ssl->version, SSL_is_dtls(ssl),
+                             hs->new_cipher, key, mac_secret, iv);
   if (!aead_ctx) {
     return 0;
   }
@@ -488,7 +462,7 @@
                     SSL3_RANDOM_SIZE, ssl->s3->client_random, SSL3_RANDOM_SIZE);
   }
 
-  const EVP_MD *digest = SSL_SESSION_get_digest(session);
+  const EVP_MD *digest = ssl_session_get_digest(session);
   return tls1_prf(digest, out, out_len, session->master_key,
                   session->master_key_length, TLS_MD_KEY_EXPANSION_CONST,
                   TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random,
@@ -537,7 +511,7 @@
   }
 
   const SSL_SESSION *session = SSL_get_session(ssl);
-  const EVP_MD *digest = SSL_SESSION_get_digest(session);
+  const EVP_MD *digest = ssl_session_get_digest(session);
   int ret = tls1_prf(digest, out, out_len, session->master_key,
                      session->master_key_length, label, label_len, seed,
                      seed_len, NULL, 0);
diff --git a/src/ssl/t1_lib.cc b/src/ssl/t1_lib.cc
index 1fe360b..9c4231d 100644
--- a/src/ssl/t1_lib.cc
+++ b/src/ssl/t1_lib.cc
@@ -930,7 +930,7 @@
       ssl->session != NULL &&
       ssl->session->tlsext_tick != NULL &&
       // Don't send TLS 1.3 session tickets in the ticket extension.
-      SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION) {
+      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION) {
     ticket_data = ssl->session->tlsext_tick;
     ticket_len = ssl->session->tlsext_ticklen;
   }
@@ -1808,18 +1808,18 @@
 static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   if (hs->max_version < TLS1_3_VERSION || ssl->session == NULL ||
-      SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION) {
+      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION) {
     return 0;
   }
 
-  size_t binder_len = EVP_MD_size(SSL_SESSION_get_digest(ssl->session));
+  size_t binder_len = EVP_MD_size(ssl_session_get_digest(ssl->session));
   return 15 + ssl->session->tlsext_ticklen + binder_len;
 }
 
 static int ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
   SSL *const ssl = hs->ssl;
   if (hs->max_version < TLS1_3_VERSION || ssl->session == NULL ||
-      SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION) {
+      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION) {
     return 1;
   }
 
@@ -1831,7 +1831,7 @@
   // Fill in a placeholder zero binder of the appropriate length. It will be
   // computed and filled in later after length prefixes are computed.
   uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
-  size_t binder_len = EVP_MD_size(SSL_SESSION_get_digest(ssl->session));
+  size_t binder_len = EVP_MD_size(ssl_session_get_digest(ssl->session));
 
   CBB contents, identity, ticket, binders, binder;
   if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) ||
@@ -1997,7 +1997,7 @@
 static int ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
   SSL *const ssl = hs->ssl;
   if (ssl->session == NULL ||
-      SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION ||
+      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION ||
       ssl->session->ticket_max_early_data == 0 ||
       hs->received_hello_retry_request ||
       !ssl->cert->enable_early_data) {
@@ -2111,7 +2111,7 @@
 
     // Predict the most preferred group.
     Span<const uint16_t> groups = tls1_get_grouplist(ssl);
-    if (groups.size() == 0) {
+    if (groups.empty()) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_NO_GROUPS_SPECIFIED);
       return 0;
     }
@@ -2290,7 +2290,7 @@
 // https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.2
 
 static int ext_cookie_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
-  if (hs->cookie.size() == 0) {
+  if (hs->cookie.empty()) {
     return 1;
   }
 
@@ -3184,7 +3184,7 @@
   }
 
   Span<const uint16_t> peer_sigalgs = hs->peer_sigalgs;
-  if (peer_sigalgs.size() == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+  if (peer_sigalgs.empty() && ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
     // If the client didn't specify any signature_algorithms extension then
     // we can assume that it supports SHA1. See
     // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 8404d52..3991870 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -33,20 +33,17 @@
 
 // A draft version of TLS 1.3 that is sent over the wire for the current draft.
 const (
-	tls13DraftVersion                = 0x7f12
-	tls13ExperimentVersion           = 0x7e01
-	tls13Experiment2Version          = 0x7e02
-	tls13Experiment3Version          = 0x7e03
-	tls13RecordTypeExperimentVersion = 0x7a12
+	tls13DraftVersion       = 0x7f12
+	tls13ExperimentVersion  = 0x7e01
+	tls13Experiment2Version = 0x7e02
+	tls13Experiment3Version = 0x7e03
 )
 
 const (
-	TLS13Default               = 0
-	TLS13Experiment            = 1
-	TLS13RecordTypeExperiment  = 2
-	TLS13NoSessionIDExperiment = 3
-	TLS13Experiment2           = 4
-	TLS13Experiment3           = 5
+	TLS13Default     = 0
+	TLS13Experiment  = 1
+	TLS13Experiment2 = 2
+	TLS13Experiment3 = 3
 )
 
 var allTLSWireVersions = []uint16{
@@ -54,7 +51,6 @@
 	tls13Experiment3Version,
 	tls13Experiment2Version,
 	tls13ExperimentVersion,
-	tls13RecordTypeExperimentVersion,
 	VersionTLS12,
 	VersionTLS11,
 	VersionTLS10,
@@ -743,10 +739,6 @@
 	// connection if there is not a SessionID in the ClientHello.
 	ExpectClientHelloSessionID bool
 
-	// ExpectEmptyClientHelloSessionID, if true, causes the server to fail the
-	// connection if there is a SessionID in the ClientHello.
-	ExpectEmptyClientHelloSessionID bool
-
 	// ExpectNoTLS12Session, if true, causes the server to fail the
 	// connection if either a session ID or TLS 1.2 ticket is offered.
 	ExpectNoTLS12Session bool
@@ -1394,6 +1386,12 @@
 	// empty slice, no extension will be sent.
 	SendSupportedPointFormats []byte
 
+	// SendServerSupportedCurves, if true, causes the server to send its
+	// supported curves list in the ServerHello (TLS 1.2) or
+	// EncryptedExtensions (TLS 1.3) message. This is invalid in TLS 1.2 and
+	// valid in TLS 1.3.
+	SendServerSupportedCurves bool
+
 	// MaxReceivePlaintext, if non-zero, is the maximum plaintext record
 	// length accepted from the peer.
 	MaxReceivePlaintext int
@@ -1558,7 +1556,7 @@
 		switch vers {
 		case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
 			return vers, true
-		case tls13DraftVersion, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version, tls13RecordTypeExperimentVersion:
+		case tls13DraftVersion, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version:
 			return VersionTLS13, true
 		}
 	}
@@ -1582,10 +1580,9 @@
 // it returns true and the corresponding protocol version. Otherwise, it returns
 // false.
 func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) {
-	if (c.TLS13Variant != TLS13Experiment && c.TLS13Variant != TLS13NoSessionIDExperiment && wireVers == tls13ExperimentVersion) ||
+	if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) ||
 		(c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) ||
 		(c.TLS13Variant != TLS13Experiment3 && wireVers == tls13Experiment3Version) ||
-		(c.TLS13Variant != TLS13RecordTypeExperiment && wireVers == tls13RecordTypeExperimentVersion) ||
 		(c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) {
 		return 0, false
 	}
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 25123b1..a80e3c8 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -774,11 +774,6 @@
 		return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
 	}
 
-	// Accept server_plaintext_handshake records when the content type TLS 1.3 variant is enabled.
-	if c.isClient && c.in.cipher == nil && c.config.TLS13Variant == TLS13RecordTypeExperiment && want == recordTypeHandshake && typ == recordTypePlaintextHandshake {
-		typ = recordTypeHandshake
-	}
-
 	vers := uint16(b.data[1])<<8 | uint16(b.data[2])
 	n := int(b.data[3])<<8 | int(b.data[4])
 
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 5dbcab9..bf9cb7f 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -1149,6 +1149,7 @@
 	keyShare                keyShareEntry
 	supportedVersion        uint16
 	supportedPoints         []uint8
+	supportedCurves         []CurveID
 	serverNameAck           bool
 }
 
@@ -1256,6 +1257,15 @@
 		supportedPoints := supportedPointsList.addU8LengthPrefixed()
 		supportedPoints.addBytes(m.supportedPoints)
 	}
+	if len(m.supportedCurves) > 0 {
+		// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
+		extensions.addU16(extensionSupportedCurves)
+		supportedCurvesList := extensions.addU16LengthPrefixed()
+		supportedCurves := supportedCurvesList.addU16LengthPrefixed()
+		for _, curve := range m.supportedCurves {
+			supportedCurves.addU16(uint16(curve))
+		}
+	}
 	if m.hasEarlyData {
 		extensions.addU16(extensionEarlyData)
 		extensions.addBytes([]byte{0, 0})
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 0a67a80..f67cc94 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -573,11 +573,7 @@
 	if sendHelloRetryRequest {
 		oldClientHelloBytes := hs.clientHello.marshal()
 		hs.writeServerHash(helloRetryRequest.marshal())
-		if c.vers == tls13RecordTypeExperimentVersion {
-			c.writeRecord(recordTypePlaintextHandshake, helloRetryRequest.marshal())
-		} else {
-			c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
-		}
+		c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
 		c.flushHandshake()
 
 		if hs.clientHello.hasEarlyData {
@@ -755,11 +751,7 @@
 		toWrite = append(toWrite, typeEncryptedExtensions)
 		c.writeRecord(recordTypeHandshake, toWrite)
 	} else {
-		if c.vers == tls13RecordTypeExperimentVersion {
-			c.writeRecord(recordTypePlaintextHandshake, hs.hello.marshal())
-		} else {
-			c.writeRecord(recordTypeHandshake, hs.hello.marshal())
-		}
+		c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 	}
 	c.flushHandshake()
 
@@ -1089,9 +1081,6 @@
 		copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
 	}
 
-	if len(hs.clientHello.sessionId) > 0 && c.config.Bugs.ExpectEmptyClientHelloSessionID {
-		return false, errors.New("tls: expected empty session ID from client")
-	}
 	if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID {
 		return false, errors.New("tls: expected non-empty session ID from client")
 	}
@@ -1308,6 +1297,10 @@
 		serverExtensions.supportedPoints = c.config.Bugs.SendSupportedPointFormats
 	}
 
+	if c.config.Bugs.SendServerSupportedCurves {
+		serverExtensions.supportedCurves = c.config.curvePreferences()
+	}
+
 	if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE {
 		return errors.New("tls: no GREASE extension found")
 	}
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 5415aa5..39a3765 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -1316,13 +1316,6 @@
 		versionWire:  tls13Experiment3Version,
 		tls13Variant: TLS13Experiment3,
 	},
-	{
-		name:         "TLS13RecordTypeExperiment",
-		version:      VersionTLS13,
-		excludeFlag:  "-no-tls13",
-		versionWire:  tls13RecordTypeExperimentVersion,
-		tls13Variant: TLS13RecordTypeExperiment,
-	},
 }
 
 func allVersions(protocol protocol) []tlsVersion {
@@ -9619,6 +9612,28 @@
 		expectedError: ":ERROR_PARSING_EXTENSION:",
 	})
 
+	// Server-sent supported groups/curves are legal in TLS 1.3. They are
+	// illegal in TLS 1.2, but some servers send them anyway, so we must
+	// tolerate them.
+	testCases = append(testCases, testCase{
+		name: "SupportedCurves-ServerHello-TLS12",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				SendServerSupportedCurves: true,
+			},
+		},
+	})
+	testCases = append(testCases, testCase{
+		name: "SupportedCurves-EncryptedExtensions-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendServerSupportedCurves: true,
+			},
+		},
+	})
+
 	// Test that we tolerate unknown point formats, as long as
 	// pointFormatUncompressed is present. Limit ciphers to ECDHE ciphers to
 	// check they are still functional.
@@ -10762,10 +10777,7 @@
 		})
 
 		hasSessionID := false
-		hasEmptySessionID := false
-		if variant == TLS13NoSessionIDExperiment {
-			hasEmptySessionID = true
-		} else if variant != TLS13Default && variant != TLS13RecordTypeExperiment {
+		if variant != TLS13Default {
 			hasSessionID = true
 		}
 
@@ -10776,8 +10788,7 @@
 			config: Config{
 				MaxVersion: VersionTLS13,
 				Bugs: ProtocolBugs{
-					ExpectClientHelloSessionID:      hasSessionID,
-					ExpectEmptyClientHelloSessionID: hasEmptySessionID,
+					ExpectClientHelloSessionID: hasSessionID,
 				},
 			},
 			tls13Variant: variant,
diff --git a/src/ssl/tls13_enc.cc b/src/ssl/tls13_enc.cc
index 6ff9972..0a36aab 100644
--- a/src/ssl/tls13_enc.cc
+++ b/src/ssl/tls13_enc.cc
@@ -57,7 +57,7 @@
 
 int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  return init_key_schedule(hs, SSL_SESSION_protocol_version(ssl->session),
+  return init_key_schedule(hs, ssl_session_protocol_version(ssl->session),
                            ssl->session->cipher);
 }
 
@@ -116,7 +116,7 @@
                           const uint8_t *traffic_secret,
                           size_t traffic_secret_len) {
   const SSL_SESSION *session = SSL_get_session(ssl);
-  uint16_t version = SSL_SESSION_protocol_version(session);
+  uint16_t version = ssl_session_protocol_version(session);
 
   if (traffic_secret_len > 0xff) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
@@ -131,7 +131,7 @@
     return 0;
   }
 
-  const EVP_MD *digest = SSL_SESSION_get_digest(session);
+  const EVP_MD *digest = ssl_session_get_digest(session);
 
   // Derive the key.
   size_t key_len = EVP_AEAD_key_length(aead);
@@ -149,9 +149,10 @@
     return 0;
   }
 
-  UniquePtr<SSLAEADContext> traffic_aead = SSLAEADContext::Create(
-      direction, session->ssl_version, SSL_is_dtls(ssl), session->cipher, key,
-      key_len, NULL, 0, iv, iv_len);
+  UniquePtr<SSLAEADContext> traffic_aead =
+      SSLAEADContext::Create(direction, session->ssl_version, SSL_is_dtls(ssl),
+                             session->cipher, MakeConstSpan(key, key_len),
+                             Span<const uint8_t>(), MakeConstSpan(iv, iv_len));
   if (!traffic_aead) {
     return 0;
   }
@@ -235,7 +236,9 @@
                         hs->server_traffic_secret_0, hs->hash_len) &&
          derive_secret(hs, ssl->s3->exporter_secret, hs->hash_len,
                        (const uint8_t *)kTLS13LabelExporter,
-                       strlen(kTLS13LabelExporter));
+                       strlen(kTLS13LabelExporter)) &&
+         ssl_log_secret(ssl, "EXPORTER_SECRET", ssl->s3->exporter_secret,
+                        hs->hash_len);
 }
 
 static const char kTLS13LabelApplicationTraffic[] =
@@ -252,7 +255,7 @@
     secret_len = ssl->s3->write_traffic_secret_len;
   }
 
-  const EVP_MD *digest = SSL_SESSION_get_digest(SSL_get_session(ssl));
+  const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl));
   if (!hkdf_expand_label(secret, digest, secret, secret_len,
                          (const uint8_t *)kTLS13LabelApplicationTraffic,
                          strlen(kTLS13LabelApplicationTraffic), NULL, 0,
@@ -327,7 +330,7 @@
     hash_len = context_len;
   }
 
-  const EVP_MD *digest = SSL_SESSION_get_digest(SSL_get_session(ssl));
+  const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl));
   return hkdf_expand_label(out, digest, ssl->s3->exporter_secret,
                            ssl->s3->exporter_secret_len, (const uint8_t *)label,
                            label_len, hash, hash_len, out_len);
@@ -367,7 +370,7 @@
 
 int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) {
   SSL *const ssl = hs->ssl;
-  const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session);
+  const EVP_MD *digest = ssl_session_get_digest(ssl->session);
   size_t hash_len = EVP_MD_size(digest);
 
   if (len < hash_len + 3) {
diff --git a/src/tool/client.cc b/src/tool/client.cc
index e1d9a26..d439860 100644
--- a/src/tool/client.cc
+++ b/src/tool/client.cc
@@ -327,14 +327,6 @@
     *out = tls13_experiment3;
     return true;
   }
-  if (in == "record-type") {
-    *out = tls13_record_type_experiment;
-    return true;
-  }
-  if (in == "no-session-id") {
-    *out = tls13_no_session_id_experiment;
-    return true;
-  }
   return false;
 }