external/boringssl: Sync to 8ebeabf0e2e01b331e56d0a491c12539baa55d3d.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/be2ee342d3781ddb954f91f8a7e660c6f59e87e5..8ebeabf0e2e01b331e56d0a491c12539baa55d3d

Test: Libcore CTS presubmits.
Change-Id: I2fefc3e2bc2bbc3e3083668bd2a56d491520bc24
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index 29493a8..e2360e6 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-be2ee342d3781ddb954f91f8a7e660c6f59e87e5
+8ebeabf0e2e01b331e56d0a491c12539baa55d3d
diff --git a/err_data.c b/err_data.c
index 88462d1..79e8753 100644
--- a/err_data.c
+++ b/err_data.c
@@ -178,42 +178,42 @@
     0x28340c19,
     0x283480ac,
     0x283500ea,
-    0x2c3229b1,
-    0x2c32a9bf,
-    0x2c3329d1,
-    0x2c33a9e3,
-    0x2c3429f7,
-    0x2c34aa09,
-    0x2c352a24,
-    0x2c35aa36,
-    0x2c362a49,
+    0x2c3229c5,
+    0x2c32a9d3,
+    0x2c3329e5,
+    0x2c33a9f7,
+    0x2c342a0b,
+    0x2c34aa1d,
+    0x2c352a38,
+    0x2c35aa4a,
+    0x2c362a5d,
     0x2c36832d,
-    0x2c372a56,
-    0x2c37aa68,
-    0x2c382a7b,
-    0x2c38aa92,
-    0x2c392aa0,
-    0x2c39aab0,
-    0x2c3a2ac2,
-    0x2c3aaad6,
-    0x2c3b2ae7,
-    0x2c3bab06,
-    0x2c3c2b1a,
-    0x2c3cab30,
-    0x2c3d2b49,
-    0x2c3dab66,
-    0x2c3e2b77,
-    0x2c3eab85,
-    0x2c3f2b9d,
-    0x2c3fabb5,
-    0x2c402bc2,
+    0x2c372a6a,
+    0x2c37aa7c,
+    0x2c382a8f,
+    0x2c38aaa6,
+    0x2c392ab4,
+    0x2c39aac4,
+    0x2c3a2ad6,
+    0x2c3aaaea,
+    0x2c3b2afb,
+    0x2c3bab1a,
+    0x2c3c2b2e,
+    0x2c3cab44,
+    0x2c3d2b5d,
+    0x2c3dab7a,
+    0x2c3e2b8b,
+    0x2c3eab99,
+    0x2c3f2bb1,
+    0x2c3fabc9,
+    0x2c402bd6,
     0x2c4090e7,
-    0x2c412bd3,
-    0x2c41abe6,
+    0x2c412be7,
+    0x2c41abfa,
     0x2c4210c0,
-    0x2c42abf7,
+    0x2c42ac0b,
     0x2c430720,
-    0x2c43aaf8,
+    0x2c43ab0c,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -452,51 +452,51 @@
     0x4066a14c,
     0x40672177,
     0x4067a198,
-    0x406821ab,
-    0x4068a1cc,
-    0x406921fe,
-    0x4069a22c,
-    0x406a224d,
-    0x406aa26d,
-    0x406b23f5,
-    0x406ba418,
-    0x406c242e,
-    0x406ca690,
-    0x406d26bf,
-    0x406da6e7,
-    0x406e2715,
-    0x406ea749,
-    0x406f2768,
-    0x406fa77d,
-    0x40702790,
-    0x4070a7ad,
+    0x406821bf,
+    0x4068a1e0,
+    0x40692212,
+    0x4069a240,
+    0x406a2261,
+    0x406aa281,
+    0x406b2409,
+    0x406ba42c,
+    0x406c2442,
+    0x406ca6a4,
+    0x406d26d3,
+    0x406da6fb,
+    0x406e2729,
+    0x406ea75d,
+    0x406f277c,
+    0x406fa791,
+    0x407027a4,
+    0x4070a7c1,
     0x40710800,
-    0x4071a7bf,
-    0x407227d2,
-    0x4072a7eb,
-    0x40732803,
+    0x4071a7d3,
+    0x407227e6,
+    0x4072a7ff,
+    0x40732817,
     0x4073936d,
-    0x40742817,
-    0x4074a831,
-    0x40752842,
-    0x4075a856,
-    0x40762864,
+    0x4074282b,
+    0x4074a845,
+    0x40752856,
+    0x4075a86a,
+    0x40762878,
     0x407691aa,
-    0x40772889,
-    0x4077a8ab,
-    0x407828c6,
-    0x4078a8ff,
-    0x40792916,
-    0x4079a92c,
-    0x407a2938,
-    0x407aa94b,
-    0x407b2960,
-    0x407ba972,
-    0x407c2987,
-    0x407ca990,
-    0x407d21e7,
+    0x4077289d,
+    0x4077a8bf,
+    0x407828da,
+    0x4078a913,
+    0x4079292a,
+    0x4079a940,
+    0x407a294c,
+    0x407aa95f,
+    0x407b2974,
+    0x407ba986,
+    0x407c299b,
+    0x407ca9a4,
+    0x407d21fb,
     0x407d9c6e,
-    0x407e28db,
+    0x407e28ef,
     0x407e9e3e,
     0x407f1a7e,
     0x407f9887,
@@ -504,7 +504,7 @@
     0x40809aa6,
     0x40811d01,
     0x40819c1f,
-    0x40822700,
+    0x40822714,
     0x4082986d,
     0x40831e19,
     0x4083a0bd,
@@ -514,41 +514,42 @@
     0x40859ff3,
     0x40861f4f,
     0x40869c88,
-    0x4087272d,
+    0x40872741,
     0x4087a024,
     0x408818aa,
-    0x41f42320,
-    0x41f923b2,
-    0x41fe22a5,
-    0x41fea481,
-    0x41ff2572,
-    0x42032339,
-    0x4208235b,
-    0x4208a397,
-    0x42092289,
-    0x4209a3d1,
-    0x420a22e0,
-    0x420aa2c0,
-    0x420b2300,
-    0x420ba379,
-    0x420c258e,
-    0x420ca44e,
-    0x420d2468,
-    0x420da49f,
-    0x421224b9,
-    0x42172555,
-    0x4217a4fb,
-    0x421c251d,
-    0x421f24d8,
-    0x422125a5,
-    0x42262538,
-    0x422b2674,
-    0x422ba622,
-    0x422c265c,
-    0x422ca5e1,
-    0x422d25c0,
-    0x422da641,
-    0x422e2607,
+    0x4088a1ab,
+    0x41f42334,
+    0x41f923c6,
+    0x41fe22b9,
+    0x41fea495,
+    0x41ff2586,
+    0x4203234d,
+    0x4208236f,
+    0x4208a3ab,
+    0x4209229d,
+    0x4209a3e5,
+    0x420a22f4,
+    0x420aa2d4,
+    0x420b2314,
+    0x420ba38d,
+    0x420c25a2,
+    0x420ca462,
+    0x420d247c,
+    0x420da4b3,
+    0x421224cd,
+    0x42172569,
+    0x4217a50f,
+    0x421c2531,
+    0x421f24ec,
+    0x422125b9,
+    0x4226254c,
+    0x422b2688,
+    0x422ba636,
+    0x422c2670,
+    0x422ca5f5,
+    0x422d25d4,
+    0x422da655,
+    0x422e261b,
     0x4432072b,
     0x4432873a,
     0x44330746,
@@ -591,69 +592,69 @@
     0x4c3d136d,
     0x4c3d937c,
     0x4c3e1389,
-    0x50322c09,
-    0x5032ac18,
-    0x50332c23,
-    0x5033ac33,
-    0x50342c4c,
-    0x5034ac66,
-    0x50352c74,
-    0x5035ac8a,
-    0x50362c9c,
-    0x5036acb2,
-    0x50372ccb,
-    0x5037acde,
-    0x50382cf6,
-    0x5038ad07,
-    0x50392d1c,
-    0x5039ad30,
-    0x503a2d50,
-    0x503aad66,
-    0x503b2d7e,
-    0x503bad90,
-    0x503c2dac,
-    0x503cadc3,
-    0x503d2ddc,
-    0x503dadf2,
-    0x503e2dff,
-    0x503eae15,
-    0x503f2e27,
+    0x50322c1d,
+    0x5032ac2c,
+    0x50332c37,
+    0x5033ac47,
+    0x50342c60,
+    0x5034ac7a,
+    0x50352c88,
+    0x5035ac9e,
+    0x50362cb0,
+    0x5036acc6,
+    0x50372cdf,
+    0x5037acf2,
+    0x50382d0a,
+    0x5038ad1b,
+    0x50392d30,
+    0x5039ad44,
+    0x503a2d64,
+    0x503aad7a,
+    0x503b2d92,
+    0x503bada4,
+    0x503c2dc0,
+    0x503cadd7,
+    0x503d2df0,
+    0x503dae06,
+    0x503e2e13,
+    0x503eae29,
+    0x503f2e3b,
     0x503f8382,
-    0x50402e3a,
-    0x5040ae4a,
-    0x50412e64,
-    0x5041ae73,
-    0x50422e8d,
-    0x5042aeaa,
-    0x50432eba,
-    0x5043aeca,
-    0x50442ed9,
+    0x50402e4e,
+    0x5040ae5e,
+    0x50412e78,
+    0x5041ae87,
+    0x50422ea1,
+    0x5042aebe,
+    0x50432ece,
+    0x5043aede,
+    0x50442eed,
     0x5044843f,
-    0x50452eed,
-    0x5045af0b,
-    0x50462f1e,
-    0x5046af34,
-    0x50472f46,
-    0x5047af5b,
-    0x50482f81,
-    0x5048af8f,
-    0x50492fa2,
-    0x5049afb7,
-    0x504a2fcd,
-    0x504aafdd,
-    0x504b2ffd,
-    0x504bb010,
-    0x504c3033,
-    0x504cb061,
-    0x504d3073,
-    0x504db090,
-    0x504e30ab,
-    0x504eb0c7,
-    0x504f30d9,
-    0x504fb0f0,
-    0x505030ff,
+    0x50452f01,
+    0x5045af1f,
+    0x50462f32,
+    0x5046af48,
+    0x50472f5a,
+    0x5047af6f,
+    0x50482f95,
+    0x5048afa3,
+    0x50492fb6,
+    0x5049afcb,
+    0x504a2fe1,
+    0x504aaff1,
+    0x504b3011,
+    0x504bb024,
+    0x504c3047,
+    0x504cb075,
+    0x504d3087,
+    0x504db0a4,
+    0x504e30bf,
+    0x504eb0db,
+    0x504f30ed,
+    0x504fb104,
+    0x50503113,
     0x505086ef,
-    0x50513112,
+    0x50513126,
     0x58320ec9,
     0x68320e8b,
     0x68328c25,
@@ -1117,6 +1118,7 @@
     "RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION\0"
     "SCSV_RECEIVED_WHEN_RENEGOTIATING\0"
     "SERVERHELLO_TLSEXT\0"
+    "SERVER_CERT_CHANGED\0"
     "SESSION_ID_CONTEXT_UNINITIALIZED\0"
     "SESSION_MAY_NOT_BE_CREATED\0"
     "SHUTDOWN_WHILE_IN_INIT\0"
diff --git a/sources.bp b/sources.bp
index 6da6257..b49daae 100644
--- a/sources.bp
+++ b/sources.bp
@@ -467,10 +467,12 @@
     name: "boringssl_crypto_test_sources",
     srcs: [
         "src/crypto/chacha/chacha_test.cc",
+        "src/crypto/curve25519/x25519_test.cc",
         "src/crypto/dh/dh_test.cc",
         "src/crypto/dsa/dsa_test.cc",
         "src/crypto/ec/ec_test.cc",
         "src/crypto/err/err_test.cc",
+        "src/crypto/evp/evp_extra_test.cc",
         "src/crypto/rsa/rsa_test.cc",
         "src/crypto/test/gtest_main.cc",
     ],
@@ -499,7 +501,6 @@
         "src/crypto/constant_time_test.cc",
         "src/crypto/curve25519/ed25519_test.cc",
         "src/crypto/curve25519/spake25519_test.cc",
-        "src/crypto/curve25519/x25519_test.cc",
         "src/crypto/digest/digest_test.cc",
         "src/crypto/ec/example_mul.c",
         "src/crypto/ec/p256-x86_64_test.cc",
@@ -507,7 +508,6 @@
         "src/crypto/ecdsa/ecdsa_sign_test.cc",
         "src/crypto/ecdsa/ecdsa_test.cc",
         "src/crypto/ecdsa/ecdsa_verify_test.cc",
-        "src/crypto/evp/evp_extra_test.cc",
         "src/crypto/evp/evp_test.cc",
         "src/crypto/evp/pbkdf_test.cc",
         "src/crypto/hkdf/hkdf_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2abf616..844a140 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -221,8 +221,8 @@
     message(FATAL_ERROR "Cannot enable ASAN unless using Clang")
   endif()
 
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
   set(OPENSSL_NO_ASM "1")
 endif()
 
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index fbfc4b2..6bb05cc 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -212,10 +212,12 @@
   crypto_test
 
   chacha/chacha_test.cc
+  curve25519/x25519_test.cc
   dh/dh_test.cc
   dsa/dsa_test.cc
   ec/ec_test.cc
   err/err_test.cc
+  evp/evp_extra_test.cc
   rsa/rsa_test.cc
 
   $<TARGET_OBJECTS:gtest_main>
diff --git a/src/crypto/bn/sqrt.c b/src/crypto/bn/sqrt.c
index fb962a9..f806ea2 100644
--- a/src/crypto/bn/sqrt.c
+++ b/src/crypto/bn/sqrt.c
@@ -148,7 +148,7 @@
     }
     q->neg = 0;
     if (!BN_add_word(q, 1) ||
-        !BN_mod_exp(ret, A, q, p, ctx)) {
+        !BN_mod_exp_mont(ret, A, q, p, ctx, NULL)) {
       goto end;
     }
     err = 0;
@@ -193,7 +193,7 @@
       goto end;
     }
     q->neg = 0;
-    if (!BN_mod_exp(b, t, q, p, ctx)) {
+    if (!BN_mod_exp_mont(b, t, q, p, ctx, NULL)) {
       goto end;
     }
 
@@ -281,7 +281,7 @@
 
   /* Now that we have some non-square, we can find an element
    * of order  2^e  by computing its q'th power. */
-  if (!BN_mod_exp(y, y, q, p, ctx)) {
+  if (!BN_mod_exp_mont(y, y, q, p, ctx, NULL)) {
     goto end;
   }
   if (BN_is_one(y)) {
@@ -327,7 +327,7 @@
       goto end;
     }
   } else {
-    if (!BN_mod_exp(x, A, t, p, ctx)) {
+    if (!BN_mod_exp_mont(x, A, t, p, ctx, NULL)) {
       goto end;
     }
     if (BN_is_zero(x)) {
diff --git a/src/crypto/curve25519/CMakeLists.txt b/src/crypto/curve25519/CMakeLists.txt
index 195b1e6..198d6af 100644
--- a/src/crypto/curve25519/CMakeLists.txt
+++ b/src/crypto/curve25519/CMakeLists.txt
@@ -39,15 +39,6 @@
 add_dependencies(all_tests ed25519_test)
 
 add_executable(
-  x25519_test
-
-  x25519_test.cc
-)
-
-target_link_libraries(x25519_test crypto)
-add_dependencies(all_tests x25519_test)
-
-add_executable(
   spake25519_test
 
   spake25519_test.cc
diff --git a/src/crypto/curve25519/x25519_test.cc b/src/crypto/curve25519/x25519_test.cc
index b1a37d4..903892f 100644
--- a/src/crypto/curve25519/x25519_test.cc
+++ b/src/crypto/curve25519/x25519_test.cc
@@ -16,13 +16,16 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <gtest/gtest.h>
+
 #include <openssl/curve25519.h>
 
 #include "../internal.h"
+#include "../test/test_util.h"
 
 
-static bool TestX25519() {
-  /* Taken from https://tools.ietf.org/html/rfc7748#section-5.2 */
+TEST(X25519Test, TestVector) {
+  // Taken from https://tools.ietf.org/html/rfc7748#section-5.2
   static const uint8_t kScalar1[32] = {
       0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
       0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
@@ -35,17 +38,14 @@
   };
 
   uint8_t out[32];
-  X25519(out, kScalar1, kPoint1);
+  EXPECT_TRUE(X25519(out, kScalar1, kPoint1));
 
   static const uint8_t kExpected1[32] = {
       0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea,
       0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c,
       0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52,
   };
-  if (OPENSSL_memcmp(kExpected1, out, sizeof(out)) != 0) {
-    fprintf(stderr, "X25519 test one failed.\n");
-    return false;
-  }
+  EXPECT_EQ(Bytes(kExpected1), Bytes(out));
 
   static const uint8_t kScalar2[32] = {
       0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26,
@@ -58,22 +58,17 @@
       0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93,
   };
 
-  X25519(out, kScalar2, kPoint2);
+  EXPECT_TRUE(X25519(out, kScalar2, kPoint2));
 
   static const uint8_t kExpected2[32] = {
       0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4,
       0x5c, 0xb4, 0xb8, 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f,
       0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57,
   };
-  if (OPENSSL_memcmp(kExpected2, out, sizeof(out)) != 0) {
-    fprintf(stderr, "X25519 test two failed.\n");
-    return false;
-  }
-
-  return true;
+  EXPECT_EQ(Bytes(kExpected2), Bytes(out));
 }
 
-static bool TestX25519SmallOrder() {
+TEST(X25519Test, SmallOrder) {
   static const uint8_t kSmallOrderPoint[32] = {
       0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3,
       0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32,
@@ -83,21 +78,21 @@
   uint8_t out[32], private_key[32];
   OPENSSL_memset(private_key, 0x11, sizeof(private_key));
 
-  if (X25519(out, private_key, kSmallOrderPoint)) {
-    fprintf(stderr, "X25519 returned success with a small-order input.\n");
-    return false;
-  }
+  OPENSSL_memset(out, 0xff, sizeof(out));
+  EXPECT_FALSE(X25519(out, private_key, kSmallOrderPoint))
+      << "X25519 returned success with a small-order input.";
 
-  return true;
+  // For callers which don't check, |out| should still be filled with zeros.
+  static const uint8_t kZeros[32] = {0};
+  EXPECT_EQ(Bytes(kZeros), Bytes(out));
 }
 
-static bool TestX25519Iterated() {
-  /* Taken from https://tools.ietf.org/html/rfc7748#section-5.2 */
+TEST(X25519Test, Iterated) {
+  // Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
   uint8_t scalar[32] = {9}, point[32] = {9}, out[32];
 
-  unsigned i;
-  for (i = 0; i < 1000; i++) {
-    X25519(out, scalar, point);
+  for (unsigned i = 0; i < 1000; i++) {
+    EXPECT_TRUE(X25519(out, scalar, point));
     OPENSSL_memcpy(point, scalar, sizeof(point));
     OPENSSL_memcpy(scalar, out, sizeof(scalar));
   }
@@ -108,21 +103,5 @@
       0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51,
   };
 
-  if (OPENSSL_memcmp(kExpected, scalar, sizeof(kExpected)) != 0) {
-    fprintf(stderr, "Iterated X25519 test failed\n");
-    return false;
-  }
-
-  return true;
-}
-
-int main(int argc, char **argv) {
-  if (!TestX25519() ||
-      !TestX25519Iterated() ||
-      !TestX25519SmallOrder()) {
-    return 1;
-  }
-
-  printf("PASS\n");
-  return 0;
+  EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
 }
diff --git a/src/crypto/dh/check.c b/src/crypto/dh/check.c
index f40e034..e3c111b 100644
--- a/src/crypto/dh/check.c
+++ b/src/crypto/dh/check.c
@@ -93,7 +93,7 @@
     /* Check |pub_key|^|dh->q| is 1 mod |dh->p|. This is necessary for RFC 5114
      * groups which are not safe primes but pick a generator on a prime-order
      * subgroup of size |dh->q|. */
-    if (!BN_mod_exp(tmp, pub_key, dh->q, dh->p, ctx)) {
+    if (!BN_mod_exp_mont(tmp, pub_key, dh->q, dh->p, ctx, NULL)) {
       goto err;
     }
     if (!BN_is_one(tmp)) {
@@ -145,7 +145,7 @@
       *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
     } else {
       /* Check g^q == 1 mod p */
-      if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) {
+      if (!BN_mod_exp_mont(t1, dh->g, dh->q, dh->p, ctx, NULL)) {
         goto err;
       }
       if (!BN_is_one(t1)) {
diff --git a/src/crypto/err/ssl.errordata b/src/crypto/err/ssl.errordata
index bac2f39..106c4c4 100644
--- a/src/crypto/err/ssl.errordata
+++ b/src/crypto/err/ssl.errordata
@@ -125,6 +125,7 @@
 SSL,205,RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION
 SSL,206,SCSV_RECEIVED_WHEN_RENEGOTIATING
 SSL,207,SERVERHELLO_TLSEXT
+SSL,273,SERVER_CERT_CHANGED
 SSL,208,SESSION_ID_CONTEXT_UNINITIALIZED
 SSL,209,SESSION_MAY_NOT_BE_CREATED
 SSL,250,SHUTDOWN_WHILE_IN_INIT
diff --git a/src/crypto/evp/CMakeLists.txt b/src/crypto/evp/CMakeLists.txt
index ca1b511..188c580 100644
--- a/src/crypto/evp/CMakeLists.txt
+++ b/src/crypto/evp/CMakeLists.txt
@@ -21,14 +21,6 @@
 
 
 add_executable(
-  evp_extra_test
-
-  evp_extra_test.cc
-
-  $<TARGET_OBJECTS:test_support>
-)
-
-add_executable(
   evp_test
 
   evp_test.cc
@@ -44,7 +36,6 @@
   $<TARGET_OBJECTS:test_support>
 )
 
-target_link_libraries(evp_extra_test crypto)
 target_link_libraries(evp_test crypto)
 target_link_libraries(pbkdf_test crypto)
-add_dependencies(all_tests evp_extra_test evp_test pbkdf_test)
+add_dependencies(all_tests evp_test pbkdf_test)
diff --git a/src/crypto/evp/evp_extra_test.cc b/src/crypto/evp/evp_extra_test.cc
index 2758917..0f8bb3b 100644
--- a/src/crypto/evp/evp_extra_test.cc
+++ b/src/crypto/evp/evp_extra_test.cc
@@ -20,6 +20,8 @@
 #include <utility>
 #include <vector>
 
+#include <gtest/gtest.h>
+
 #include <openssl/bytestring.h>
 #include <openssl/crypto.h>
 #include <openssl/digest.h>
@@ -28,6 +30,7 @@
 #include <openssl/rsa.h>
 
 #include "../internal.h"
+#include "../test/test_util.h"
 
 
 // kExampleRSAKeyDER is an RSA private key in ASN.1, DER format. Of course, you
@@ -370,352 +373,170 @@
   return pkey;
 }
 
-static bool TestEVP_DigestSignInit(void) {
+TEST(EVPExtraTest, DigestSignInit) {
   bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
+  ASSERT_TRUE(pkey);
   bssl::ScopedEVP_MD_CTX md_ctx;
-  if (!pkey ||
-      !EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()) ||
-      !EVP_DigestSignUpdate(md_ctx.get(), kMsg, sizeof(kMsg))) {
-    return false;
-  }
+  ASSERT_TRUE(
+      EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()));
+  ASSERT_TRUE(EVP_DigestSignUpdate(md_ctx.get(), kMsg, sizeof(kMsg)));
+
   // Determine the size of the signature.
   size_t sig_len = 0;
-  if (!EVP_DigestSignFinal(md_ctx.get(), NULL, &sig_len)) {
-    return false;
-  }
+  ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), NULL, &sig_len));
+
   // Sanity check for testing.
-  if (sig_len != (size_t)EVP_PKEY_size(pkey.get())) {
-    fprintf(stderr, "sig_len mismatch\n");
-    return false;
-  }
+  EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(pkey.get())), sig_len);
 
   std::vector<uint8_t> sig;
   sig.resize(sig_len);
-  if (!EVP_DigestSignFinal(md_ctx.get(), sig.data(), &sig_len)) {
-    return false;
-  }
+  ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), sig.data(), &sig_len));
   sig.resize(sig_len);
 
   // Ensure that the signature round-trips.
   md_ctx.Reset();
-  if (!EVP_DigestVerifyInit(md_ctx.get(), NULL, EVP_sha256(), NULL,
-                            pkey.get()) ||
-      !EVP_DigestVerifyUpdate(md_ctx.get(), kMsg, sizeof(kMsg)) ||
-      !EVP_DigestVerifyFinal(md_ctx.get(), sig.data(), sig_len)) {
-    return false;
-  }
-
-  return true;
+  ASSERT_TRUE(
+      EVP_DigestVerifyInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()));
+  ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), kMsg, sizeof(kMsg)));
+  ASSERT_TRUE(EVP_DigestVerifyFinal(md_ctx.get(), sig.data(), sig_len));
 }
 
-static bool TestEVP_DigestVerifyInit(void) {
+TEST(EVPExtraTest, DigestVerifyInit) {
   bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
   bssl::ScopedEVP_MD_CTX md_ctx;
-  if (!pkey ||
-      !EVP_DigestVerifyInit(md_ctx.get(), NULL, EVP_sha256(), NULL,
-                            pkey.get()) ||
-      !EVP_DigestVerifyUpdate(md_ctx.get(), kMsg, sizeof(kMsg)) ||
-      !EVP_DigestVerifyFinal(md_ctx.get(), kSignature, sizeof(kSignature))) {
-    return false;
-  }
-  return true;
+  ASSERT_TRUE(pkey);
+  ASSERT_TRUE(
+      EVP_DigestVerifyInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()));
+  ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), kMsg, sizeof(kMsg)));
+  ASSERT_TRUE(
+      EVP_DigestVerifyFinal(md_ctx.get(), kSignature, sizeof(kSignature)));
 }
 
-static bool TestVerifyRecover() {
+TEST(EVPExtraTest, VerifyRecover) {
   bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
-  if (!pkey) {
-    return false;
-  }
-
+  ASSERT_TRUE(pkey);
   bssl::UniquePtr<RSA> rsa(EVP_PKEY_get1_RSA(pkey.get()));
-  if (!rsa) {
-    return false;
-  }
+  ASSERT_TRUE(rsa);
 
   const uint8_t kDummyHash[32] = {0};
   uint8_t sig[2048/8];
   unsigned sig_len = sizeof(sig);
-
-  if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), sig, &sig_len,
-                rsa.get())) {
-    fprintf(stderr, "RSA_sign failed.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
+  ASSERT_TRUE(RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), sig,
+                       &sig_len, rsa.get()));
 
   size_t out_len;
   bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
-  if (!EVP_PKEY_verify_recover_init(ctx.get()) ||
-      !EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING) ||
-      !EVP_PKEY_CTX_set_signature_md(ctx.get(), EVP_sha256()) ||
-      !EVP_PKEY_verify_recover(ctx.get(), nullptr, &out_len, sig, sig_len)) {
-    fprintf(stderr, "verify_recover failed will nullptr buffer.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
+  ASSERT_TRUE(EVP_PKEY_verify_recover_init(ctx.get()));
+  ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING));
+  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(ctx.get(), EVP_sha256()));
+  ASSERT_TRUE(
+      EVP_PKEY_verify_recover(ctx.get(), nullptr, &out_len, sig, sig_len));
 
   std::vector<uint8_t> recovered;
   recovered.resize(out_len);
 
-  if (!EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len, sig,
-                               sig_len)) {
-    fprintf(stderr, "verify_recover failed.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
-
-  if (out_len != sizeof(kDummyHash)) {
-    fprintf(stderr, "verify_recover length is %u, expected %u.\n",
-            static_cast<unsigned>(out_len),
-            static_cast<unsigned>(sizeof(kDummyHash)));
-    return false;
-  }
-
-  if (OPENSSL_memcmp(recovered.data(), kDummyHash, sizeof(kDummyHash)) != 0) {
-    fprintf(stderr, "verify_recover got wrong value.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
+  ASSERT_TRUE(EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len,
+                                      sig, sig_len));
+  EXPECT_EQ(Bytes(kDummyHash), Bytes(recovered.data(), out_len));
 
   out_len = recovered.size();
-  if (!EVP_PKEY_CTX_set_signature_md(ctx.get(), nullptr) ||
-      !EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len, sig,
-                               sig_len)) {
-    fprintf(stderr, "verify_recover failed with NULL MD.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
-  }
+  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(ctx.get(), nullptr));
+  ASSERT_TRUE(EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len,
+                                      sig, sig_len));
 
-  /* The size of a SHA-256 hash plus PKCS#1 v1.5 ASN.1 stuff happens to be 51
-   * bytes. */
-  static const size_t kExpectedASN1Size = 51;
-  if (out_len != kExpectedASN1Size) {
-    fprintf(stderr, "verify_recover length without MD is %u, expected %u.\n",
-            static_cast<unsigned>(out_len),
-            static_cast<unsigned>(kExpectedASN1Size));
-    return false;
-  }
-
-  return true;
+  // The size of a SHA-256 hash plus PKCS#1 v1.5 ASN.1 stuff happens to be 51
+  // bytes.
+  EXPECT_EQ(51u, out_len);
 }
 
-static bool TestValidPrivateKey(const uint8_t *input, size_t input_len,
+static void TestValidPrivateKey(const uint8_t *input, size_t input_len,
                                 int expected_id) {
   const uint8_t *p = input;
   bssl::UniquePtr<EVP_PKEY> pkey(d2i_AutoPrivateKey(NULL, &p, input_len));
-  if (!pkey || p != input + input_len) {
-    fprintf(stderr, "d2i_AutoPrivateKey failed\n");
-    return false;
-  }
-
-  if (EVP_PKEY_id(pkey.get()) != expected_id) {
-    fprintf(stderr, "Did not decode expected type\n");
-    return false;
-  }
-
-  return true;
+  ASSERT_TRUE(pkey);
+  EXPECT_EQ(input + input_len, p);
+  EXPECT_EQ(expected_id, EVP_PKEY_id(pkey.get()));
 }
 
-static bool Testd2i_AutoPrivateKey() {
-  if (!TestValidPrivateKey(kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER),
-                           EVP_PKEY_RSA)) {
-    fprintf(stderr, "d2i_AutoPrivateKey(kExampleRSAKeyDER) failed\n");
-    return false;
-  }
-
-  if (!TestValidPrivateKey(kExampleRSAKeyPKCS8, sizeof(kExampleRSAKeyPKCS8),
-                           EVP_PKEY_RSA)) {
-    fprintf(stderr, "d2i_AutoPrivateKey(kExampleRSAKeyPKCS8) failed\n");
-    return false;
-  }
-
-  if (!TestValidPrivateKey(kExampleECKeyDER, sizeof(kExampleECKeyDER),
-                           EVP_PKEY_EC)) {
-    fprintf(stderr, "d2i_AutoPrivateKey(kExampleECKeyDER) failed\n");
-    return false;
-  }
-
-  if (!TestValidPrivateKey(kExampleECKeyPKCS8, sizeof(kExampleECKeyPKCS8),
-                           EVP_PKEY_EC)) {
-    fprintf(stderr, "d2i_AutoPrivateKey(kExampleECKeyPKCS8) failed\n");
-    return false;
-  }
-
-  if (!TestValidPrivateKey(kExampleECKeySpecifiedCurvePKCS8,
-                           sizeof(kExampleECKeySpecifiedCurvePKCS8),
-                           EVP_PKEY_EC)) {
-    fprintf(stderr,
-            "d2i_AutoPrivateKey(kExampleECKeySpecifiedCurvePKCS8) failed\n");
-    return false;
-  }
-
-  if (!TestValidPrivateKey(kExampleDSAKeyDER, sizeof(kExampleDSAKeyDER),
-                           EVP_PKEY_DSA)) {
-    fprintf(stderr, "d2i_AutoPrivateKey(kExampleDSAKeyDER) failed\n");
-    return false;
-  }
+TEST(EVPExtraTest, d2i_AutoPrivateKey) {
+  TestValidPrivateKey(kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER),
+                      EVP_PKEY_RSA);
+  TestValidPrivateKey(kExampleRSAKeyPKCS8, sizeof(kExampleRSAKeyPKCS8),
+                      EVP_PKEY_RSA);
+  TestValidPrivateKey(kExampleECKeyDER, sizeof(kExampleECKeyDER), EVP_PKEY_EC);
+  TestValidPrivateKey(kExampleECKeyPKCS8, sizeof(kExampleECKeyPKCS8),
+                      EVP_PKEY_EC);
+  TestValidPrivateKey(kExampleECKeySpecifiedCurvePKCS8,
+                      sizeof(kExampleECKeySpecifiedCurvePKCS8), EVP_PKEY_EC);
+  TestValidPrivateKey(kExampleDSAKeyDER, sizeof(kExampleDSAKeyDER),
+                      EVP_PKEY_DSA);
 
   const uint8_t *p = kInvalidPrivateKey;
-  bssl::UniquePtr<EVP_PKEY> pkey(d2i_AutoPrivateKey(NULL, &p, sizeof(kInvalidPrivateKey)));
-  if (pkey) {
-    fprintf(stderr, "Parsed invalid private key\n");
-    return false;
-  }
+  bssl::UniquePtr<EVP_PKEY> pkey(
+      d2i_AutoPrivateKey(NULL, &p, sizeof(kInvalidPrivateKey)));
+  EXPECT_FALSE(pkey) << "Parsed invalid private key";
   ERR_clear_error();
-
-  return true;
 }
 
-// TestEVP_PKCS82PKEY tests loading a bad key in PKCS8 format.
-static bool TestEVP_PKCS82PKEY(void) {
+// Tests loading a bad key in PKCS8 format.
+TEST(EVPExtraTest, BadECKey) {
   const uint8_t *derp = kExampleBadECKeyDER;
   bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> p8inf(
       d2i_PKCS8_PRIV_KEY_INFO(NULL, &derp, sizeof(kExampleBadECKeyDER)));
-  if (!p8inf || derp != kExampleBadECKeyDER + sizeof(kExampleBadECKeyDER)) {
-    fprintf(stderr, "Failed to parse key\n");
-    return false;
-  }
+  ASSERT_TRUE(p8inf);
+  EXPECT_EQ(kExampleBadECKeyDER + sizeof(kExampleBadECKeyDER), derp);
 
   bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKCS82PKEY(p8inf.get()));
-  if (pkey) {
-    fprintf(stderr, "Imported invalid EC key\n");
-    return false;
-  }
+  ASSERT_FALSE(pkey) << "Imported invalid EC key";
   ERR_clear_error();
-
-  return true;
 }
 
-// TestEVPMarshalEmptyPublicKey tests |EVP_marshal_public_key| on an empty key.
-static bool TestEVPMarshalEmptyPublicKey(void) {
+// Tests |EVP_marshal_public_key| on an empty key.
+TEST(EVPExtraTest, MarshalEmptyPublicKey) {
   bssl::UniquePtr<EVP_PKEY> empty(EVP_PKEY_new());
-  if (!empty) {
-    return false;
-  }
+  ASSERT_TRUE(empty);
+
   bssl::ScopedCBB cbb;
-  if (EVP_marshal_public_key(cbb.get(), empty.get())) {
-    fprintf(stderr, "Marshalled empty public key.\n");
-    return false;
-  }
-  if (ERR_GET_REASON(ERR_peek_last_error()) != EVP_R_UNSUPPORTED_ALGORITHM) {
-    fprintf(stderr, "Marshalling an empty public key gave wrong error.\n");
-    return false;
-  }
-  ERR_clear_error();
-  return true;
+  EXPECT_FALSE(EVP_marshal_public_key(cbb.get(), empty.get()))
+      << "Marshalled empty public key.";
+  EXPECT_EQ(EVP_R_UNSUPPORTED_ALGORITHM, ERR_GET_REASON(ERR_peek_last_error()));
 }
 
-// Testd2i_PrivateKey tests |d2i_PrivateKey|.
-static bool Testd2i_PrivateKey(void) {
-  const uint8_t *derp = kExampleRSAKeyDER;
-  bssl::UniquePtr<EVP_PKEY> pkey(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &derp,
-                                     sizeof(kExampleRSAKeyDER)));
-  if (!pkey || derp != kExampleRSAKeyDER + sizeof(kExampleRSAKeyDER)) {
-    fprintf(stderr, "Failed to import raw RSA key.\n");
-    return false;
+static bssl::UniquePtr<EVP_PKEY> ParsePrivateKey(int type, const uint8_t *in,
+                                                 size_t len) {
+  const uint8_t *ptr = in;
+  bssl::UniquePtr<EVP_PKEY> pkey(d2i_PrivateKey(type, nullptr, &ptr, len));
+  if (!pkey) {
+    return nullptr;
   }
 
-  derp = kExampleDSAKeyDER;
-  pkey.reset(d2i_PrivateKey(EVP_PKEY_DSA, nullptr, &derp,
-             sizeof(kExampleDSAKeyDER)));
-  if (!pkey || derp != kExampleDSAKeyDER + sizeof(kExampleDSAKeyDER)) {
-    fprintf(stderr, "Failed to import raw DSA key.\n");
-    return false;
-  }
+  EXPECT_EQ(in + len, ptr);
+  return pkey;
+}
 
-  derp = kExampleRSAKeyPKCS8;
-  pkey.reset(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &derp,
-             sizeof(kExampleRSAKeyPKCS8)));
-  if (!pkey || derp != kExampleRSAKeyPKCS8 + sizeof(kExampleRSAKeyPKCS8)) {
-    fprintf(stderr, "Failed to import PKCS#8 RSA key.\n");
-    return false;
-  }
+TEST(EVPExtraTest, d2i_PrivateKey) {
+  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_RSA, kExampleRSAKeyDER,
+                              sizeof(kExampleRSAKeyDER)));
+  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_DSA, kExampleDSAKeyDER,
+                              sizeof(kExampleDSAKeyDER)));
+  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_RSA, kExampleRSAKeyPKCS8,
+                              sizeof(kExampleRSAKeyPKCS8)));
+  EXPECT_TRUE(
+      ParsePrivateKey(EVP_PKEY_EC, kExampleECKeyDER, sizeof(kExampleECKeyDER)));
 
-  derp = kExampleECKeyDER;
-  pkey.reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &derp,
-             sizeof(kExampleECKeyDER)));
-  if (!pkey || derp != kExampleECKeyDER + sizeof(kExampleECKeyDER)) {
-    fprintf(stderr, "Failed to import raw EC key.\n");
-    return false;
-  }
-
-  derp = kExampleBadECKeyDER;
-  pkey.reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &derp,
-             sizeof(kExampleBadECKeyDER)));
-  if (pkey) {
-    fprintf(stderr, "Imported invalid EC key.\n");
-    return false;
-  }
+  EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, kExampleBadECKeyDER,
+                               sizeof(kExampleBadECKeyDER)));
   ERR_clear_error();
 
   // Copy the input into a |malloc|'d vector to flag memory errors.
-  std::vector<uint8_t> copy(kExampleBadECKeyDER2, kExampleBadECKeyDER2 +
-                                                  sizeof(kExampleBadECKeyDER2));
-  derp = copy.data();
-  pkey.reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &derp, copy.size()));
-  if (pkey) {
-    fprintf(stderr, "Imported invalid EC key #2.\n");
-    return false;
-  }
+  std::vector<uint8_t> copy(
+      kExampleBadECKeyDER2,
+      kExampleBadECKeyDER2 + sizeof(kExampleBadECKeyDER2));
+  EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, copy.data(), copy.size()));
   ERR_clear_error();
 
-  derp = kExampleRSAKeyPKCS8;
-  pkey.reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &derp,
-             sizeof(kExampleRSAKeyPKCS8)));
-  if (pkey) {
-    fprintf(stderr, "Imported RSA key as EC key.\n");
-    return false;
-  }
+  // Test that an RSA key may not be imported as an EC key.
+  EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, kExampleRSAKeyPKCS8,
+                               sizeof(kExampleRSAKeyPKCS8)));
   ERR_clear_error();
-
-  return true;
-}
-
-int main() {
-  CRYPTO_library_init();
-
-  if (!TestEVP_DigestSignInit()) {
-    fprintf(stderr, "EVP_DigestSignInit failed\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  if (!TestEVP_DigestVerifyInit()) {
-    fprintf(stderr, "EVP_DigestVerifyInit failed\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  if (!TestVerifyRecover()) {
-    fprintf(stderr, "EVP_PKEY_verify_recover failed\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  if (!Testd2i_AutoPrivateKey()) {
-    fprintf(stderr, "Testd2i_AutoPrivateKey failed\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  if (!TestEVP_PKCS82PKEY()) {
-    fprintf(stderr, "TestEVP_PKCS82PKEY failed\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  if (!TestEVPMarshalEmptyPublicKey()) {
-    fprintf(stderr, "TestEVPMarshalEmptyPublicKey failed\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  if (!Testd2i_PrivateKey()) {
-    fprintf(stderr, "Testd2i_PrivateKey failed\n");
-    ERR_print_errors_fp(stderr);
-    return 1;
-  }
-
-  printf("PASS\n");
-  return 0;
 }
diff --git a/src/crypto/evp/p_dsa_asn1.c b/src/crypto/evp/p_dsa_asn1.c
index 1f022f1..d4f4132 100644
--- a/src/crypto/evp/p_dsa_asn1.c
+++ b/src/crypto/evp/p_dsa_asn1.c
@@ -151,7 +151,8 @@
   /* Calculate the public key. */
   ctx = BN_CTX_new();
   if (ctx == NULL ||
-      !BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) {
+      !BN_mod_exp_mont(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx,
+                       NULL)) {
     goto err;
   }
 
diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h
index 3f47521..86211bc 100644
--- a/src/include/openssl/base.h
+++ b/src/include/openssl/base.h
@@ -141,7 +141,7 @@
  * A consumer may use this symbol in the preprocessor to temporarily build
  * against multiple revisions of BoringSSL at the same time. It is not
  * recommended to do so for longer than is necessary. */
-#define BORINGSSL_API_VERSION 2
+#define BORINGSSL_API_VERSION 3
 
 #if defined(BORINGSSL_SHARED_LIBRARY)
 
diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h
index 6ba1421..a18ad1c 100644
--- a/src/include/openssl/bio.h
+++ b/src/include/openssl/bio.h
@@ -565,12 +565,8 @@
 #define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in
                                           the previous write operation. */
 
-/* BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT sets a read deadline to drive
- * retransmits. The |parg| argument to |BIO_ctrl| will be a pointer to a
- * |timeval| struct. If the structure is all zeros, it clears the read
- * deadline. Otherwise, |BIO_read| must fail with a temporary error
- * (e.g. |EAGAIN|) after the deadline. */
-#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45
+/* BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT is unsupported as it is unused by consumers
+ * and depends on |timeval|, which is not 2038-clean on all platforms. */
 
 #define BIO_CTRL_DGRAM_GET_PEER           46
 
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 3131539..6b39096 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -187,6 +187,10 @@
 /* DTLS_method is the |SSL_METHOD| used for DTLS connections. */
 OPENSSL_EXPORT const SSL_METHOD *DTLS_method(void);
 
+/* TLS_with_buffers_method is like |TLS_method|, but avoids all use of
+ * crypto/x509. */
+OPENSSL_EXPORT const SSL_METHOD *TLS_with_buffers_method(void);
+
 /* SSL_CTX_new returns a newly-allocated |SSL_CTX| with default settings or NULL
  * on error. */
 OPENSSL_EXPORT SSL_CTX *SSL_CTX_new(const SSL_METHOD *method);
@@ -237,8 +241,8 @@
  * takes ownership of the two |BIO|s. If |rbio| and |wbio| are the same, |ssl|
  * only takes ownership of one reference.
  *
- * In DTLS, if |rbio| is blocking, it must handle
- * |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| control requests to set read timeouts.
+ * In DTLS, |rbio| must be non-blocking to properly handle timeouts and
+ * retransmits.
  *
  * If |rbio| is the same as the currently configured |BIO| for reading, that
  * side is left untouched and is not freed.
@@ -318,12 +322,11 @@
  * returns <= 0. The caller should pass the value into |SSL_get_error| to
  * determine how to proceed.
  *
- * In DTLS, if the read |BIO| is non-blocking, the caller must drive
- * retransmissions. Whenever |SSL_get_error| signals |SSL_ERROR_WANT_READ|, use
- * |DTLSv1_get_timeout| to determine the current timeout. If it expires before
- * the next retry, call |DTLSv1_handle_timeout|. Note that DTLS handshake
- * retransmissions use fresh sequence numbers, so it is not sufficient to replay
- * packets at the transport.
+ * In DTLS, the caller must drive retransmissions. Whenever |SSL_get_error|
+ * signals |SSL_ERROR_WANT_READ|, use |DTLSv1_get_timeout| to determine the
+ * current timeout. If it expires before the next retry, call
+ * |DTLSv1_handle_timeout|. Note that DTLS handshake retransmissions use fresh
+ * sequence numbers, so it is not sufficient to replay packets at the transport.
  *
  * TODO(davidben): Ensure 0 is only returned on transport EOF.
  * https://crbug.com/466303. */
@@ -1047,10 +1050,7 @@
 typedef struct ssl_private_key_method_st {
   /* type returns the type of the key used by |ssl|. For RSA keys, return
    * |NID_rsaEncryption|. For ECDSA keys, return |NID_X9_62_prime256v1|,
-   * |NID_secp384r1|, or |NID_secp521r1|, depending on the curve.
-   *
-   * Returning |EVP_PKEY_EC| for ECDSA keys is deprecated and may result in
-   * connection failures in TLS 1.3. */
+   * |NID_secp384r1|, or |NID_secp521r1|, depending on the curve. */
   int (*type)(SSL *ssl);
 
   /* max_signature_len returns the maximum length of a signature signed by the
@@ -1366,6 +1366,10 @@
  * inputs, unless an empty cipher list results. */
 OPENSSL_EXPORT int SSL_set_cipher_list(SSL *ssl, const char *str);
 
+/* SSL_CTX_get_ciphers returns the cipher list for |ctx|, in order of
+ * preference. */
+OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx);
+
 /* SSL_get_ciphers returns the cipher list for |ssl|, in order of preference. */
 OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl);
 
@@ -1394,11 +1398,9 @@
 OPENSSL_EXPORT X509 *SSL_get_peer_certificate(const SSL *ssl);
 
 /* SSL_get_peer_cert_chain returns the peer's certificate chain or NULL if
- * unavailable or the peer did not use certificates. This is the unverified
- * list of certificates as sent by the peer, not the final chain built during
- * verification. For historical reasons, this value may not be available if
- * resuming a serialized |SSL_SESSION|. The caller does not take ownership of
- * the result.
+ * unavailable or the peer did not use certificates. This is the unverified list
+ * of certificates as sent by the peer, not the final chain built during
+ * verification. The caller does not take ownership of the result.
  *
  * WARNING: This function behaves differently between client and server. If
  * |ssl| is a server, the returned chain does not include the leaf certificate.
@@ -1406,11 +1408,9 @@
 OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl);
 
 /* SSL_get_peer_full_cert_chain returns the peer's certificate chain, or NULL if
- * unavailable or the peer did not use certificates. This is the unverified
- * list of certificates as sent by the peer, not the final chain built during
- * verification. For historical reasons, this value may not be available if
- * resuming a serialized |SSL_SESSION|. The caller does not take ownership of
- * the result.
+ * unavailable or the peer did not use certificates. This is the unverified list
+ * of certificates as sent by the peer, not the final chain built during
+ * verification. The caller does not take ownership of the result.
  *
  * This is the same as |SSL_get_peer_cert_chain| except that this function
  * always returns the full chain, i.e. the first element of the return value
@@ -1419,6 +1419,15 @@
  * |ssl| is a server. */
 OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl);
 
+/* SSL_get0_peer_certificates returns the peer's certificate chain, or NULL if
+ * unavailable or the peer did not use certificates. This is the unverified list
+ * of certificates as sent by the peer, not the final chain built during
+ * verification. The caller does not take ownership of the result.
+ *
+ * This is the |CRYPTO_BUFFER| variant of |SSL_get_peer_full_cert_chain|. */
+OPENSSL_EXPORT STACK_OF(CRYPTO_BUFFER) *
+    SSL_get0_peer_certificates(const SSL *ssl);
+
 /* SSL_get0_signed_cert_timestamp_list sets |*out| and |*out_len| to point to
  * |*out_len| bytes of SCT information from the server. This is only valid if
  * |ssl| is a client. The SCT information is a SignedCertificateTimestampList
@@ -1627,10 +1636,10 @@
 
 /* SSL_SESSION_get_time returns the time at which |session| was established in
  * seconds since the UNIX epoch. */
-OPENSSL_EXPORT long SSL_SESSION_get_time(const SSL_SESSION *session);
+OPENSSL_EXPORT uint64_t SSL_SESSION_get_time(const SSL_SESSION *session);
 
 /* SSL_SESSION_get_timeout returns the lifetime of |session| in seconds. */
-OPENSSL_EXPORT long SSL_SESSION_get_timeout(const SSL_SESSION *session);
+OPENSSL_EXPORT uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session);
 
 /* SSL_SESSION_get0_peer returns the peer leaf certificate stored in
  * |session|.
@@ -1647,12 +1656,14 @@
 /* SSL_SESSION_set_time sets |session|'s creation time to |time| and returns
  * |time|. This function may be useful in writing tests but otherwise should not
  * be used. */
-OPENSSL_EXPORT long SSL_SESSION_set_time(SSL_SESSION *session, long time);
+OPENSSL_EXPORT uint64_t SSL_SESSION_set_time(SSL_SESSION *session,
+                                             uint64_t time);
 
 /* SSL_SESSION_set_timeout sets |session|'s timeout to |timeout| and returns
  * one. This function may be useful in writing tests but otherwise should not
  * be used. */
-OPENSSL_EXPORT long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout);
+OPENSSL_EXPORT uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session,
+                                                uint32_t timeout);
 
 /* SSL_SESSION_set1_id_context sets |session|'s session ID context (see
  * |SSL_CTX_set_session_id_context|) to |sid_ctx|. It returns one on success and
@@ -1766,16 +1777,16 @@
 
 /* SSL_CTX_set_timeout sets the lifetime, in seconds, of TLS 1.2 (or earlier)
  * sessions created in |ctx| to |timeout|. */
-OPENSSL_EXPORT long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout);
+OPENSSL_EXPORT uint32_t SSL_CTX_set_timeout(SSL_CTX *ctx, uint32_t timeout);
 
 /* SSL_CTX_set_session_psk_dhe_timeout sets the lifetime, in seconds, of TLS 1.3
  * sessions created in |ctx| to |timeout|. */
 OPENSSL_EXPORT void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx,
-                                                        long timeout);
+                                                        uint32_t timeout);
 
 /* SSL_CTX_get_timeout returns the lifetime, in seconds, of TLS 1.2 (or earlier)
  * sessions created in |ctx|. */
-OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx);
+OPENSSL_EXPORT uint32_t SSL_CTX_get_timeout(const SSL_CTX *ctx);
 
 /* SSL_CTX_set_session_id_context sets |ctx|'s session ID context to |sid_ctx|.
  * It returns one on success and zero on error. The session ID context is an
@@ -1834,7 +1845,7 @@
 
 /* SSL_CTX_flush_sessions removes all sessions from |ctx| which have expired as
  * of time |time|. If |time| is zero, all sessions are removed. */
-OPENSSL_EXPORT void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time);
+OPENSSL_EXPORT void SSL_CTX_flush_sessions(SSL_CTX *ctx, uint64_t time);
 
 /* SSL_CTX_sess_set_new_cb sets the callback to be called when a new session is
  * established and ready to be cached. If the session cache is disabled (the
@@ -2333,6 +2344,16 @@
  * when the handshake is paused because of them. */
 OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl);
 
+/* SSL_get0_server_requested_CAs returns the CAs sent by a server to guide a
+ * client in certificate selection. They are a series of DER-encoded X.509
+ * names. This function may only be called during a callback set by
+ * |SSL_CTX_set_cert_cb| or when the handshake is paused because of it.
+ *
+ * The returned stack is owned by |ssl|, as are its contents. It should not be
+ * used past the point where the handshake is restarted after the callback. */
+OPENSSL_EXPORT STACK_OF(CRYPTO_BUFFER) *SSL_get0_server_requested_CAs(
+    const SSL *ssl);
+
 /* SSL_CTX_get_client_CA_list returns |ctx|'s client certificate CA list. */
 OPENSSL_EXPORT STACK_OF(X509_NAME) *
     SSL_CTX_get_client_CA_list(const SSL_CTX *ctx);
@@ -3195,11 +3216,6 @@
  * record with |ssl|. */
 OPENSSL_EXPORT size_t SSL_max_seal_overhead(const SSL *ssl);
 
-/* SSL_CTX_set_short_header_enabled configures whether a short record header in
- * TLS 1.3 may be negotiated. This allows client and server to negotiate
- * https://github.com/tlswg/tls13-spec/pull/762 for testing. */
-OPENSSL_EXPORT void SSL_CTX_set_short_header_enabled(SSL_CTX *ctx, int enabled);
-
 
 /* Deprecated functions. */
 
@@ -3773,15 +3789,15 @@
 
   /* timeout is the lifetime of the session in seconds, measured from |time|.
    * This is renewable up to |auth_timeout|. */
-  long timeout;
+  uint32_t timeout;
 
   /* auth_timeout is the non-renewable lifetime of the session in seconds,
    * measured from |time|. */
-  long auth_timeout;
+  uint32_t auth_timeout;
 
   /* time is the time the session was issued, measured in seconds from the UNIX
    * epoch. */
-  long time;
+  uint64_t time;
 
   const SSL_CIPHER *cipher;
 
@@ -3921,11 +3937,11 @@
 
   /* session_timeout is the default lifetime for new sessions in TLS 1.2 and
    * earlier, in seconds. */
-  long session_timeout;
+  uint32_t session_timeout;
 
   /* session_psk_dhe_timeout is the default lifetime for new sessions in TLS
    * 1.3, in seconds. */
-  long session_psk_dhe_timeout;
+  uint32_t session_psk_dhe_timeout;
 
   /* If this callback is not null, it will be called each time a session id is
    * added to the cache.  If this function returns 1, it means that the
@@ -3969,7 +3985,11 @@
   void (*info_callback)(const SSL *ssl, int type, int value);
 
   /* what we put in client cert requests */
-  STACK_OF(X509_NAME) *client_CA;
+  STACK_OF(CRYPTO_BUFFER) *client_CA;
+
+  /* cached_x509_client_CA is a cache of parsed versions of the elements of
+   * |client_CA|. */
+  STACK_OF(X509_NAME) *cached_x509_client_CA;
 
 
   /* Default values to use in SSL structures follow (these are copied by
@@ -4117,10 +4137,6 @@
   /* grease_enabled is one if draft-davidben-tls-grease-01 is enabled and zero
    * otherwise. */
   unsigned grease_enabled:1;
-
-  /* short_header_enabled is one if a short record header in TLS 1.3 may
-   * be negotiated and zero otherwise. */
-  unsigned short_header_enabled:1;
 };
 
 
@@ -4455,6 +4471,7 @@
 #define SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA 270
 #define SSL_R_PSK_IDENTITY_BINDER_COUNT_MISMATCH 271
 #define SSL_R_CANNOT_PARSE_LEAF_CERT 272
+#define SSL_R_SERVER_CERT_CHANGED 273
 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/src/include/openssl/tls1.h b/src/include/openssl/tls1.h
index 2601974..1842ee5 100644
--- a/src/include/openssl/tls1.h
+++ b/src/include/openssl/tls1.h
@@ -227,9 +227,6 @@
 /* This is not an IANA defined extension number */
 #define TLSEXT_TYPE_channel_id 30032
 
-/* This is not an IANA defined extension number */
-#define TLSEXT_TYPE_short_header 27463
-
 /* status request value from RFC 3546 */
 #define TLSEXT_STATUSTYPE_ocsp 1
 
diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c
index 258e9ab..ef15252 100644
--- a/src/ssl/d1_lib.c
+++ b/src/ssl/d1_lib.c
@@ -135,8 +135,6 @@
     ssl->d1->next_timeout.tv_sec++;
     ssl->d1->next_timeout.tv_usec -= 1000000;
   }
-  BIO_ctrl(ssl->rbio, BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
-           &ssl->d1->next_timeout);
 }
 
 int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) {
@@ -149,32 +147,43 @@
     return 0;
   }
 
-  struct timeval timenow;
+  struct OPENSSL_timeval timenow;
   ssl_get_current_time(ssl, &timenow);
 
   /* If timer already expired, set remaining time to 0 */
   if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec ||
       (ssl->d1->next_timeout.tv_sec == timenow.tv_sec &&
        ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
-    OPENSSL_memset(out, 0, sizeof(struct timeval));
+    OPENSSL_memset(out, 0, sizeof(*out));
     return 1;
   }
 
   /* Calculate time left until timer expires */
-  OPENSSL_memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval));
-  out->tv_sec -= timenow.tv_sec;
-  out->tv_usec -= timenow.tv_usec;
-  if (out->tv_usec < 0) {
-    out->tv_sec--;
-    out->tv_usec += 1000000;
+  struct OPENSSL_timeval ret;
+  OPENSSL_memcpy(&ret, &ssl->d1->next_timeout, sizeof(ret));
+  ret.tv_sec -= timenow.tv_sec;
+  if (ret.tv_usec >= timenow.tv_usec) {
+    ret.tv_usec -= timenow.tv_usec;
+  } else {
+    ret.tv_usec = 1000000 + ret.tv_usec - timenow.tv_usec;
+    ret.tv_sec--;
   }
 
   /* If remaining time is less than 15 ms, set it to 0 to prevent issues
-   * because of small devergences with socket timeouts. */
-  if (out->tv_sec == 0 && out->tv_usec < 15000) {
-    OPENSSL_memset(out, 0, sizeof(struct timeval));
+   * because of small divergences with socket timeouts. */
+  if (ret.tv_sec == 0 && ret.tv_usec < 15000) {
+    OPENSSL_memset(&ret, 0, sizeof(ret));
   }
 
+  /* Clamp the result in case of overflow. */
+  if (ret.tv_sec > INT_MAX) {
+    assert(0);
+    out->tv_sec = INT_MAX;
+  } else {
+    out->tv_sec = ret.tv_sec;
+  }
+
+  out->tv_usec = ret.tv_usec;
   return 1;
 }
 
@@ -206,10 +215,9 @@
 void dtls1_stop_timer(SSL *ssl) {
   /* Reset everything */
   ssl->d1->num_timeouts = 0;
-  OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval));
+  OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(ssl->d1->next_timeout));
   ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
-  BIO_ctrl(ssl->rbio, BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
-           &ssl->d1->next_timeout);
+
   /* Clear retransmission buffer */
   dtls_clear_outgoing_messages(ssl);
 }
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 27b2763..3444825 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -142,7 +142,11 @@
   if (ssl_read_buffer_len(ssl) == 0) {
     int read_ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
     if (read_ret < 0 && dtls1_is_timer_expired(ssl)) {
-      /* For blocking BIOs, retransmits must be handled internally. */
+      /* Historically, timeouts were handled implicitly if the caller did not
+       * handle them.
+       *
+       * TODO(davidben): This was to support blocking sockets but affected
+       * non-blocking sockets. Can it be removed? */
       int timeout_ret = DTLSv1_handle_timeout(ssl);
       if (timeout_ret <= 0) {
         return timeout_ret;
diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c
index c4f5e8e..c457772 100644
--- a/src/ssl/handshake_client.c
+++ b/src/ssl/handshake_client.c
@@ -1057,6 +1057,33 @@
     return -1;
   }
 
+  /* Disallow the server certificate from changing during a renegotiation. See
+   * https://mitls.org/pages/attacks/3SHAKE. We never resume on renegotiation,
+   * so this check is sufficient. */
+  if (ssl->s3->established_session != NULL) {
+    if (sk_CRYPTO_BUFFER_num(ssl->s3->established_session->certs) !=
+        sk_CRYPTO_BUFFER_num(hs->new_session->certs)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+      return -1;
+    }
+
+    for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(hs->new_session->certs); i++) {
+      const CRYPTO_BUFFER *old_cert =
+          sk_CRYPTO_BUFFER_value(ssl->s3->established_session->certs, i);
+      const CRYPTO_BUFFER *new_cert =
+          sk_CRYPTO_BUFFER_value(hs->new_session->certs, i);
+      if (CRYPTO_BUFFER_len(old_cert) != CRYPTO_BUFFER_len(new_cert) ||
+          OPENSSL_memcmp(CRYPTO_BUFFER_data(old_cert),
+                         CRYPTO_BUFFER_data(new_cert),
+                         CRYPTO_BUFFER_len(old_cert)) != 0) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+        return -1;
+      }
+    }
+  }
+
   return 1;
 }
 
@@ -1108,8 +1135,7 @@
 
 static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result,
-                             hs->new_session->x509_chain)) {
+  if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) {
     return -1;
   }
 
@@ -1403,22 +1429,24 @@
   }
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
-  STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs);
-  if (ca_sk == NULL) {
+  STACK_OF(CRYPTO_BUFFER) *ca_names =
+      ssl_parse_client_CA_list(ssl, &alert, &cbs);
+  if (ca_names == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return -1;
   }
 
   if (CBS_len(&cbs) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+    sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return -1;
   }
 
   hs->cert_request = 1;
-  sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
-  hs->ca_names = ca_sk;
+  sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+  hs->ca_names = ca_names;
+  ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
   return 1;
 }
 
@@ -1474,7 +1502,7 @@
     }
   }
 
-  if (!ssl_auto_chain_if_needed(ssl) ||
+  if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl) ||
       !ssl3_output_cert_chain(ssl)) {
     return -1;
   }
diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c
index 51338e2..e3a4e51 100644
--- a/src/ssl/handshake_server.c
+++ b/src/ssl/handshake_server.c
@@ -877,7 +877,7 @@
     }
   }
 
-  if (!ssl_auto_chain_if_needed(ssl)) {
+  if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl)) {
     return -1;
   }
 
@@ -1058,7 +1058,7 @@
     ssl->s3->tlsext_channel_id_valid = 0;
   }
 
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
   ssl->s3->server_random[0] = now.tv_sec >> 24;
   ssl->s3->server_random[1] = now.tv_sec >> 16;
@@ -1481,10 +1481,10 @@
     hs->new_session->peer_sha256_valid = 1;
   }
 
-  if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result,
-                             hs->new_session->x509_chain)) {
+  if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) {
     return -1;
   }
+
   return 1;
 }
 
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index a6dfad5..caa9cd2 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -826,11 +826,6 @@
  * empty certificate list. It returns one on success and zero on error. */
 int ssl_add_cert_chain(SSL *ssl, CBB *cbb);
 
-/* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if
- * necessary. On success, it updates |ssl|'s certificate configuration as needed
- * and returns one. Otherwise, it returns zero. */
-int ssl_auto_chain_if_needed(SSL *ssl);
-
 /* ssl_cert_check_digital_signature_key_usage parses the DER-encoded, X.509
  * certificate in |in| and returns one if doesn't specify a key usage or, if it
  * does, if it includes digitalSignature. Otherwise it pushes to the error
@@ -844,9 +839,9 @@
 
 /* ssl_parse_client_CA_list parses a CA list from |cbs| in the format used by a
  * TLS CertificateRequest message. On success, it returns a newly-allocated
- * |X509_NAME| list and advances |cbs|. Otherwise, it returns NULL and sets
+ * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets
  * |*out_alert| to an alert to send to the peer. */
-STACK_OF(X509_NAME) *
+STACK_OF(CRYPTO_BUFFER) *
     ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs);
 
 /* ssl_add_client_CA_list adds the configured CA list to |cbb| in the format
@@ -1037,7 +1032,11 @@
 
   /* ca_names, on the client, contains the list of CAs received in a
    * CertificateRequest message. */
-  STACK_OF(X509_NAME) *ca_names;
+  STACK_OF(CRYPTO_BUFFER) *ca_names;
+
+  /* cached_x509_ca_names contains a cache of parsed versions of the elements
+   * of |ca_names|. */
+  STACK_OF(X509_NAME) *cached_x509_ca_names;
 
   /* certificate_types, on the client, contains the set of certificate types
    * received in a CertificateRequest message. */
@@ -1442,10 +1441,19 @@
 };
 
 struct ssl_x509_method_st {
-  /* cert_clear frees and NULLs all X509-related state. */
+  /* check_client_CA_list returns one if |names| is a good list of X.509
+   * distinguished names and zero otherwise. This is used to ensure that we can
+   * reject unparsable values at handshake time when using crypto/x509. */
+  int (*check_client_CA_list)(STACK_OF(CRYPTO_BUFFER) *names);
+
+  /* cert_clear frees and NULLs all X509 certificate-related state. */
   void (*cert_clear)(CERT *cert);
+  /* cert_free frees all X509-related state. */
+  void (*cert_free)(CERT *cert);
   /* cert_flush_cached_chain drops any cached |X509|-based certificate chain
    * from |cert|. */
+  /* cert_dup duplicates any needed fields from |cert| to |new_cert|. */
+  void (*cert_dup)(CERT *new_cert, const CERT *cert);
   void (*cert_flush_cached_chain)(CERT *cert);
   /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate
    * from |cert|. */
@@ -1460,11 +1468,32 @@
   int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session);
   /* session_clear frees any X509-related state from |session|. */
   void (*session_clear)(SSL_SESSION *session);
-};
+  /* session_verify_cert_chain verifies the certificate chain in |session|,
+   * sets |session->verify_result| and returns one on success or zero on
+   * error. */
+  int (*session_verify_cert_chain)(SSL_SESSION *session, SSL *ssl);
 
-/* ssl_noop_x509_method is implements the |ssl_x509_method_st| functions by
- * doing nothing. */
-extern const struct ssl_x509_method_st ssl_noop_x509_method;
+  /* hs_flush_cached_ca_names drops any cached |X509_NAME|s from |hs|. */
+  void (*hs_flush_cached_ca_names)(SSL_HANDSHAKE *hs);
+  /* ssl_new does any neccessary initialisation of |ssl|. It returns one on
+   * success or zero on error. */
+  int (*ssl_new)(SSL *ssl);
+  /* ssl_free frees anything created by |ssl_new|. */
+  void (*ssl_free)(SSL *ssl);
+  /* ssl_flush_cached_client_CA drops any cached |X509_NAME|s from |ssl|. */
+  void (*ssl_flush_cached_client_CA)(SSL *ssl);
+  /* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if
+   * necessary. On success, it updates |ssl|'s certificate configuration as
+   * needed and returns one. Otherwise, it returns zero. */
+  int (*ssl_auto_chain_if_needed)(SSL *ssl);
+  /* ssl_ctx_new does any neccessary initialisation of |ctx|. It returns one on
+   * success or zero on error. */
+  int (*ssl_ctx_new)(SSL_CTX *ctx);
+  /* ssl_ctx_free frees anything created by |ssl_ctx_new|. */
+  void (*ssl_ctx_free)(SSL_CTX *ctx);
+  /* ssl_ctx_flush_cached_client_CA drops any cached |X509_NAME|s from |ctx|. */
+  void (*ssl_ctx_flush_cached_client_CA)(SSL_CTX *ssl);
+};
 
 /* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using
  * crypto/x509. */
@@ -1575,10 +1604,6 @@
    * handshake. */
   unsigned tlsext_channel_id_valid:1;
 
-  /* short_header is one if https://github.com/tlswg/tls13-spec/pull/762 has
-   * been negotiated. */
-  unsigned short_header:1;
-
   uint8_t send_alert[2];
 
   /* pending_flight is the pending outgoing flight. This is used to flush each
@@ -1691,6 +1716,11 @@
   uint8_t *reassembly;
 } hm_fragment;
 
+struct OPENSSL_timeval {
+  uint64_t tv_sec;
+  uint32_t tv_usec;
+};
+
 typedef struct dtls1_state_st {
   /* send_cookie is true if we are resending the ClientHello
    * with a cookie from a HelloVerifyRequest. */
@@ -1739,7 +1769,7 @@
 
   /* Indicates when the last handshake msg or heartbeat sent will
    * timeout. */
-  struct timeval next_timeout;
+  struct OPENSSL_timeval next_timeout;
 
   /* timeout_duration_ms is the timeout duration in milliseconds. */
   unsigned timeout_duration_ms;
@@ -1832,7 +1862,11 @@
   CRYPTO_EX_DATA ex_data;
 
   /* for server side, keep the list of CA_dn we can use */
-  STACK_OF(X509_NAME) *client_CA;
+  STACK_OF(CRYPTO_BUFFER) *client_CA;
+
+  /* cached_x509_client_CA is a cache of parsed versions of the elements of
+   * |client_CA|. */
+  STACK_OF(X509_NAME) *cached_x509_client_CA;
 
   uint32_t options; /* protocol behaviour */
   uint32_t mode;    /* API behaviour */
@@ -1980,7 +2014,8 @@
 /* ssl_session_renew_timeout calls |ssl_session_rebase_time| and renews
  * |session|'s timeout to |timeout| (measured from the current time). The
  * renewal is clamped to the session's auth_timeout. */
-void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout);
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+                               uint32_t timeout);
 
 void ssl_cipher_preference_list_free(
     struct ssl_cipher_preference_list_st *cipher_list);
@@ -1990,8 +2025,6 @@
 const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
     const SSL *ssl);
 
-int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result,
-                          STACK_OF(X509) *cert_chain);
 void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);
 
 int ssl_verify_alarm_type(long type);
@@ -2172,7 +2205,7 @@
  * call this function before the version is determined. */
 uint16_t ssl3_protocol_version(const SSL *ssl);
 
-void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock);
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock);
 
 /* ssl_reset_error_state resets state for |SSL_get_error|. */
 void ssl_reset_error_state(SSL *ssl);
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 7fd09c6..6b03030 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -173,7 +173,8 @@
   OPENSSL_free(hs->peer_key);
   OPENSSL_free(hs->server_params);
   OPENSSL_free(hs->peer_psk_identity_hint);
-  sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
+  sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+  hs->ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
   OPENSSL_free(hs->certificate_types);
 
   if (hs->key_block != NULL) {
diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c
index 3533225..cfcc12a 100644
--- a/src/ssl/ssl_asn1.c
+++ b/src/ssl/ssl_asn1.c
@@ -210,28 +210,10 @@
       !CBB_add_bytes(&child, in->session_id,
                      for_ticket ? 0 : in->session_id_length) ||
       !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
-      !CBB_add_bytes(&child, in->master_key, in->master_key_length)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    goto err;
-  }
-
-  if (in->time < 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
-  }
-
-  if (!CBB_add_asn1(&session, &child, kTimeTag) ||
-      !CBB_add_asn1_uint64(&child, in->time)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    goto err;
-  }
-
-  if (in->timeout < 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
-  }
-
-  if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
+      !CBB_add_bytes(&child, in->master_key, in->master_key_length) ||
+      !CBB_add_asn1(&session, &child, kTimeTag) ||
+      !CBB_add_asn1_uint64(&child, in->time) ||
+      !CBB_add_asn1(&session, &child, kTimeoutTag) ||
       !CBB_add_asn1_uint64(&child, in->timeout)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -634,19 +616,17 @@
   ret->master_key_length = CBS_len(&master_key);
 
   CBS child;
-  uint64_t time, timeout;
+  uint64_t timeout;
   if (!CBS_get_asn1(&session, &child, kTimeTag) ||
-      !CBS_get_asn1_uint64(&child, &time) ||
-      time > LONG_MAX ||
+      !CBS_get_asn1_uint64(&child, &ret->time) ||
       !CBS_get_asn1(&session, &child, kTimeoutTag) ||
       !CBS_get_asn1_uint64(&child, &timeout) ||
-      timeout > LONG_MAX) {
+      timeout > UINT32_MAX) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
 
-  ret->time = (long)time;
-  ret->timeout = (long)timeout;
+  ret->timeout = (uint32_t)timeout;
 
   CBS peer;
   int has_peer;
@@ -811,8 +791,8 @@
                              kPeerSignatureAlgorithmTag, 0) ||
       !SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data,
                              kTicketMaxEarlyDataTag, 0) ||
-      !SSL_SESSION_parse_long(&session, &ret->auth_timeout, kAuthTimeoutTag,
-                              ret->timeout) ||
+      !SSL_SESSION_parse_u32(&session, &ret->auth_timeout, kAuthTimeoutTag,
+                             ret->timeout) ||
       !SSL_SESSION_parse_octet_string(&session, &ret->early_alpn,
                                       &ret->early_alpn_len, kEarlyALPNTag) ||
       CBS_len(&session) != 0) {
diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c
index c60c6fa..1309a18 100644
--- a/src/ssl/ssl_cert.c
+++ b/src/ssl/ssl_cert.c
@@ -133,14 +133,6 @@
 #include "internal.h"
 
 
-int SSL_get_ex_data_X509_STORE_CTX_idx(void) {
-  /* The ex_data index to go from |X509_STORE_CTX| to |SSL| always uses the
-   * reserved app_data slot. Before ex_data was introduced, app_data was used.
-   * Avoid breaking any software which assumes |X509_STORE_CTX_get_app_data|
-   * works. */
-  return 0;
-}
-
 CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method) {
   CERT *ret = OPENSSL_malloc(sizeof(CERT));
   if (ret == NULL) {
@@ -198,10 +190,7 @@
   ret->cert_cb = cert->cert_cb;
   ret->cert_cb_arg = cert->cert_cb_arg;
 
-  if (cert->verify_store != NULL) {
-    X509_STORE_up_ref(cert->verify_store);
-    ret->verify_store = cert->verify_store;
-  }
+  ret->x509_method->cert_dup(ret, cert);
 
   if (cert->signed_cert_timestamp_list != NULL) {
     CRYPTO_BUFFER_up_ref(cert->signed_cert_timestamp_list);
@@ -246,8 +235,8 @@
   DH_free(c->dh_tmp);
 
   ssl_cert_clear_certs(c);
+  c->x509_method->cert_free(c);
   OPENSSL_free(c->sigalgs);
-  X509_STORE_free(c->verify_store);
   CRYPTO_BUFFER_free(c->signed_cert_timestamp_list);
   CRYPTO_BUFFER_free(c->ocsp_response);
 
@@ -347,155 +336,6 @@
   return ok;
 }
 
-int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result,
-                          STACK_OF(X509) *cert_chain) {
-  if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) {
-    return 0;
-  }
-
-  X509_STORE *verify_store = ssl->ctx->cert_store;
-  if (ssl->cert->verify_store != NULL) {
-    verify_store = ssl->cert->verify_store;
-  }
-
-  X509 *leaf = sk_X509_value(cert_chain, 0);
-  int ret = 0;
-  X509_STORE_CTX ctx;
-  if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
-    return 0;
-  }
-  if (!X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(),
-                                  ssl)) {
-    goto err;
-  }
-
-  /* We need to inherit the verify parameters. These can be determined by the
-   * context: if its a server it will verify SSL client certificates or vice
-   * versa. */
-  X509_STORE_CTX_set_default(&ctx, ssl->server ? "ssl_client" : "ssl_server");
-
-  /* Anything non-default in "param" should overwrite anything in the ctx. */
-  X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param);
-
-  if (ssl->verify_callback) {
-    X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback);
-  }
-
-  int verify_ret;
-  if (ssl->ctx->app_verify_callback != NULL) {
-    verify_ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg);
-  } else {
-    verify_ret = X509_verify_cert(&ctx);
-  }
-
-  *out_verify_result = ctx.error;
-
-  /* If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result. */
-  if (verify_ret <= 0 && ssl->verify_mode != SSL_VERIFY_NONE) {
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, ssl_verify_alarm_type(ctx.error));
-    OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
-    goto err;
-  }
-
-  ERR_clear_error();
-  ret = 1;
-
-err:
-  X509_STORE_CTX_cleanup(&ctx);
-  return ret;
-}
-
-static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,
-                               STACK_OF(X509_NAME) *name_list) {
-  sk_X509_NAME_pop_free(*ca_list, X509_NAME_free);
-  *ca_list = name_list;
-}
-
-STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
-  STACK_OF(X509_NAME) *ret = sk_X509_NAME_new_null();
-  if (ret == NULL) {
-    return NULL;
-  }
-
-  for (size_t i = 0; i < sk_X509_NAME_num(list); i++) {
-      X509_NAME *name = X509_NAME_dup(sk_X509_NAME_value(list, i));
-    if (name == NULL || !sk_X509_NAME_push(ret, name)) {
-      X509_NAME_free(name);
-      sk_X509_NAME_pop_free(ret, X509_NAME_free);
-      return NULL;
-    }
-  }
-
-  return ret;
-}
-
-void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) {
-  set_client_CA_list(&ssl->client_CA, name_list);
-}
-
-void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) {
-  set_client_CA_list(&ctx->client_CA, name_list);
-}
-
-STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) {
-  return ctx->client_CA;
-}
-
-STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
-  /* For historical reasons, this function is used both to query configuration
-   * state on a server as well as handshake state on a client. However, whether
-   * |ssl| is a client or server is not known until explicitly configured with
-   * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
-   * indeterminate mode and |ssl->server| is unset. */
-  if (ssl->handshake_func != NULL && !ssl->server) {
-    if (ssl->s3->hs != NULL) {
-      return ssl->s3->hs->ca_names;
-    }
-
-    return NULL;
-  }
-
-  if (ssl->client_CA != NULL) {
-    return ssl->client_CA;
-  }
-  return ssl->ctx->client_CA;
-}
-
-static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x509) {
-  X509_NAME *name;
-
-  if (x509 == NULL) {
-    return 0;
-  }
-  if (*sk == NULL) {
-    *sk = sk_X509_NAME_new_null();
-    if (*sk == NULL) {
-      return 0;
-    }
-  }
-
-  name = X509_NAME_dup(X509_get_subject_name(x509));
-  if (name == NULL) {
-    return 0;
-  }
-
-  if (!sk_X509_NAME_push(*sk, name)) {
-    X509_NAME_free(name);
-    return 0;
-  }
-
-  return 1;
-}
-
-int SSL_add_client_CA(SSL *ssl, X509 *x509) {
-  return add_client_CA(&ssl->client_CA, x509);
-}
-
-int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) {
-  return add_client_CA(&ctx->client_CA, x509);
-}
-
 int ssl_has_certificate(const SSL *ssl) {
   return ssl->cert->chain != NULL &&
          sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL &&
@@ -779,14 +619,11 @@
   return 0;
 }
 
-static int ca_dn_cmp(const X509_NAME **a, const X509_NAME **b) {
-  return X509_NAME_cmp(*a, *b);
-}
-
-STACK_OF(X509_NAME) *
+STACK_OF(CRYPTO_BUFFER) *
     ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) {
-  STACK_OF(X509_NAME) *ret = sk_X509_NAME_new(ca_dn_cmp);
-  X509_NAME *name = NULL;
+  CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool;
+
+  STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
   if (ret == NULL) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
@@ -808,29 +645,27 @@
       goto err;
     }
 
-    const uint8_t *ptr = CBS_data(&distinguished_name);
-    /* A u16 length cannot overflow a long. */
-    name = d2i_X509_NAME(NULL, &ptr, (long)CBS_len(&distinguished_name));
-    if (name == NULL ||
-        ptr != CBS_data(&distinguished_name) + CBS_len(&distinguished_name)) {
-      *out_alert = SSL_AD_DECODE_ERROR;
-      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-      goto err;
-    }
-
-    if (!sk_X509_NAME_push(ret, name)) {
+    CRYPTO_BUFFER *buffer =
+        CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool);
+    if (buffer == NULL ||
+        !sk_CRYPTO_BUFFER_push(ret, buffer)) {
+      CRYPTO_BUFFER_free(buffer);
       *out_alert = SSL_AD_INTERNAL_ERROR;
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    name = NULL;
+  }
+
+  if (!ssl->ctx->x509_method->check_client_CA_list(ret)) {
+    *out_alert = SSL_AD_INTERNAL_ERROR;
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    goto err;
   }
 
   return ret;
 
 err:
-  X509_NAME_free(name);
-  sk_X509_NAME_pop_free(ret, X509_NAME_free);
+  sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
   return NULL;
 }
 
@@ -840,21 +675,20 @@
     return 0;
   }
 
-  STACK_OF(X509_NAME) *sk = SSL_get_client_CA_list(ssl);
-  if (sk == NULL) {
+  STACK_OF(CRYPTO_BUFFER) *names = ssl->client_CA;
+  if (names == NULL) {
+    names = ssl->ctx->client_CA;
+  }
+  if (names == NULL) {
     return CBB_flush(cbb);
   }
 
-  for (size_t i = 0; i < sk_X509_NAME_num(sk); i++) {
-    X509_NAME *name = sk_X509_NAME_value(sk, i);
-    int len = i2d_X509_NAME(name, NULL);
-    if (len < 0) {
-      return 0;
-    }
-    uint8_t *ptr;
+  for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
+    const CRYPTO_BUFFER *name = sk_CRYPTO_BUFFER_value(names, i);
+
     if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
-        !CBB_add_space(&name_cbb, &ptr, (size_t)len) ||
-        (len > 0 && i2d_X509_NAME(name, &ptr) < 0)) {
+        !CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name),
+                       CRYPTO_BUFFER_len(name))) {
       return 0;
     }
   }
@@ -862,33 +696,6 @@
   return CBB_flush(cbb);
 }
 
-static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store, int take_ref) {
-  X509_STORE_free(*store_ptr);
-  *store_ptr = new_store;
-
-  if (new_store != NULL && take_ref) {
-    X509_STORE_up_ref(new_store);
-  }
-
-  return 1;
-}
-
-int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
-  return set_cert_store(&ctx->cert->verify_store, store, 0);
-}
-
-int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
-  return set_cert_store(&ctx->cert->verify_store, store, 1);
-}
-
-int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) {
-  return set_cert_store(&ssl->cert->verify_store, store, 0);
-}
-
-int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) {
-  return set_cert_store(&ssl->cert->verify_store, store, 1);
-}
-
 void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg),
                          void *arg) {
   ssl_cert_set_cert_cb(ctx->cert, cb, arg);
@@ -898,6 +705,22 @@
   ssl_cert_set_cert_cb(ssl->cert, cb, arg);
 }
 
+STACK_OF(CRYPTO_BUFFER) *SSL_get0_peer_certificates(const SSL *ssl) {
+  SSL_SESSION *session = SSL_get_session(ssl);
+  if (session == NULL) {
+    return NULL;
+  }
+
+  return session->certs;
+}
+
+STACK_OF(CRYPTO_BUFFER) *SSL_get0_server_requested_CAs(const SSL *ssl) {
+  if (ssl->s3->hs == NULL) {
+    return NULL;
+  }
+  return ssl->s3->hs->ca_names;
+}
+
 int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey,
                                const CRYPTO_BUFFER *leaf) {
   SSL *const ssl = hs->ssl;
@@ -940,38 +763,6 @@
   return 1;
 }
 
-static int do_client_cert_cb(SSL *ssl, void *arg) {
-  if (ssl_has_certificate(ssl) || ssl->ctx->client_cert_cb == NULL) {
-    return 1;
-  }
-
-  X509 *x509 = NULL;
-  EVP_PKEY *pkey = NULL;
-  int ret = ssl->ctx->client_cert_cb(ssl, &x509, &pkey);
-  if (ret < 0) {
-    return -1;
-  }
-
-  if (ret != 0) {
-    if (!SSL_use_certificate(ssl, x509) ||
-        !SSL_use_PrivateKey(ssl, pkey)) {
-      return 0;
-    }
-  }
-
-  X509_free(x509);
-  EVP_PKEY_free(pkey);
-  return 1;
-}
-
-void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl,
-                                                        X509 **out_x509,
-                                                        EVP_PKEY **out_pkey)) {
-  /* Emulate the old client certificate callback with the new one. */
-  SSL_CTX_set_cert_cb(ctx, do_client_cert_cb, NULL);
-  ctx->client_cert_cb = cb;
-}
-
 static int set_signed_cert_timestamp_list(CERT *cert, const uint8_t *list,
                                            size_t list_len) {
   CBS sct_list;
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index e37f9f9..7ead554 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -235,11 +235,6 @@
     return NULL;
   }
 
-  if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
-    goto err;
-  }
-
   ret = OPENSSL_malloc(sizeof(SSL_CTX));
   if (ret == NULL) {
     goto err;
@@ -271,8 +266,8 @@
   if (ret->sessions == NULL) {
     goto err;
   }
-  ret->cert_store = X509_STORE_new();
-  if (ret->cert_store == NULL) {
+
+  if (!ret->x509_method->ssl_ctx_new(ret)) {
     goto err;
   }
 
@@ -284,12 +279,7 @@
     goto err2;
   }
 
-  ret->param = X509_VERIFY_PARAM_new();
-  if (!ret->param) {
-    goto err;
-  }
-
-  ret->client_CA = sk_X509_NAME_new_null();
+  ret->client_CA = sk_CRYPTO_BUFFER_new_null();
   if (ret->client_CA == NULL) {
     goto err;
   }
@@ -337,8 +327,6 @@
     return;
   }
 
-  X509_VERIFY_PARAM_free(ctx->param);
-
   /* Free internal session cache. However: the remove_cb() may reference the
    * ex_data of SSL_CTX, thus the ex_data store can only be removed after the
    * sessions were flushed. As the ex_data handling routines might also touch
@@ -351,14 +339,14 @@
 
   CRYPTO_MUTEX_cleanup(&ctx->lock);
   lh_SSL_SESSION_free(ctx->sessions);
-  X509_STORE_free(ctx->cert_store);
   ssl_cipher_preference_list_free(ctx->cipher_list);
   ssl_cert_free(ctx->cert);
   sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions,
                                    SSL_CUSTOM_EXTENSION_free);
   sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->server_custom_extensions,
                                    SSL_CUSTOM_EXTENSION_free);
-  sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free);
+  sk_CRYPTO_BUFFER_pop_free(ctx->client_CA, CRYPTO_BUFFER_free);
+  ctx->x509_method->ssl_ctx_free(ctx);
   sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles);
   OPENSSL_free(ctx->psk_identity_hint);
   OPENSSL_free(ctx->supported_group_list);
@@ -407,11 +395,6 @@
   ssl->retain_only_sha256_of_client_certs =
       ctx->retain_only_sha256_of_client_certs;
 
-  ssl->param = X509_VERIFY_PARAM_new();
-  if (!ssl->param) {
-    goto err;
-  }
-  X509_VERIFY_PARAM_inherit(ssl->param, ctx->param);
   ssl->quiet_shutdown = ctx->quiet_shutdown;
   ssl->max_send_fragment = ctx->max_send_fragment;
 
@@ -420,6 +403,10 @@
   SSL_CTX_up_ref(ctx);
   ssl->initial_ctx = ctx;
 
+  if (!ssl->ctx->x509_method->ssl_new(ssl)) {
+    goto err;
+  }
+
   if (ctx->supported_group_list) {
     ssl->supported_group_list = BUF_memdup(ctx->supported_group_list,
                                            ctx->supported_group_list_len * 2);
@@ -481,8 +468,7 @@
     return;
   }
 
-  X509_VERIFY_PARAM_free(ssl->param);
-
+  ssl->ctx->x509_method->ssl_free(ssl);
   CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data);
 
   BIO_free_all(ssl->rbio);
@@ -503,7 +489,7 @@
   OPENSSL_free(ssl->alpn_client_proto_list);
   EVP_PKEY_free(ssl->tlsext_channel_id_private);
   OPENSSL_free(ssl->psk_identity_hint);
-  sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free);
+  sk_CRYPTO_BUFFER_pop_free(ssl->client_CA, CRYPTO_BUFFER_free);
   sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles);
 
   if (ssl->method != NULL) {
@@ -1469,6 +1455,10 @@
   return 1;
 }
 
+OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx) {
+  return ctx->cipher_list->ciphers;
+}
+
 STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) {
   if (ssl == NULL) {
     return NULL;
@@ -1484,19 +1474,16 @@
 }
 
 const char *SSL_get_cipher_list(const SSL *ssl, int n) {
-  const SSL_CIPHER *c;
-  STACK_OF(SSL_CIPHER) *sk;
-
   if (ssl == NULL) {
     return NULL;
   }
 
-  sk = SSL_get_ciphers(ssl);
+  STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl);
   if (sk == NULL || n < 0 || (size_t)n >= sk_SSL_CIPHER_num(sk)) {
     return NULL;
   }
 
-  c = sk_SSL_CIPHER_value(sk, n);
+  const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, n);
   if (c == NULL) {
     return NULL;
   }
@@ -1902,9 +1889,9 @@
     CRYPTO_MUTEX_unlock_write(&ctx->lock);
 
     if (flush_cache) {
-      struct timeval now;
+      struct OPENSSL_timeval now;
       ssl_get_current_time(ssl, &now);
-      SSL_CTX_flush_sessions(ctx, (long)now.tv_sec);
+      SSL_CTX_flush_sessions(ctx, now.tv_sec);
     }
   }
 }
@@ -2566,10 +2553,6 @@
   ctx->grease_enabled = !!enabled;
 }
 
-void SSL_CTX_set_short_header_enabled(SSL_CTX *ctx, int enabled) {
-  ctx->short_header_enabled = !!enabled;
-}
-
 int SSL_clear(SSL *ssl) {
   /* In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously
    * established session to be offered the next time around. wpa_supplicant
@@ -2700,9 +2683,20 @@
   return SSL_set1_curves(ssl, &nid, 1);
 }
 
-void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock) {
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) {
   if (ssl->ctx->current_time_cb != NULL) {
-    ssl->ctx->current_time_cb(ssl, out_clock);
+    /* TODO(davidben): Update current_time_cb to use OPENSSL_timeval. See
+     * https://crbug.com/boringssl/155. */
+    struct timeval clock;
+    ssl->ctx->current_time_cb(ssl, &clock);
+    if (clock.tv_sec < 0) {
+      assert(0);
+      out_clock->tv_sec = 0;
+      out_clock->tv_usec = 0;
+    } else {
+      out_clock->tv_sec = (uint64_t)clock.tv_sec;
+      out_clock->tv_usec = (uint32_t)clock.tv_usec;
+    }
     return;
   }
 
@@ -2712,10 +2706,25 @@
 #elif defined(OPENSSL_WINDOWS)
   struct _timeb time;
   _ftime(&time);
-  out_clock->tv_sec = time.time;
-  out_clock->tv_usec = time.millitm * 1000;
+  if (time.time < 0) {
+    assert(0);
+    out_clock->tv_sec = 0;
+    out_clock->tv_usec = 0;
+  } else {
+    out_clock->tv_sec = time.time;
+    out_clock->tv_usec = time.millitm * 1000;
+  }
 #else
-  gettimeofday(out_clock, NULL);
+  struct timeval clock;
+  gettimeofday(&clock, NULL);
+  if (clock.tv_sec < 0) {
+    assert(0);
+    out_clock->tv_sec = 0;
+    out_clock->tv_usec = 0;
+  } else {
+    out_clock->tv_sec = (uint64_t)clock.tv_sec;
+    out_clock->tv_usec = (uint32_t)clock.tv_usec;
+  }
 #endif
 }
 
diff --git a/src/ssl/ssl_privkey.c b/src/ssl/ssl_privkey.c
index 7962247..c5441de 100644
--- a/src/ssl/ssl_privkey.c
+++ b/src/ssl/ssl_privkey.c
@@ -304,8 +304,7 @@
 
 int ssl_is_ecdsa_key_type(int type) {
   switch (type) {
-    /* TODO(davidben): Remove support for |EVP_PKEY_EC| key types. */
-    case EVP_PKEY_EC:
+    case NID_secp224r1:
     case NID_X9_62_prime256v1:
     case NID_secp384r1:
     case NID_secp521r1:
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index bbe88c3..c9390d2 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -173,7 +173,7 @@
   session->references = 1;
   session->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
   session->auth_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
-  session->time = (long)time(NULL);
+  session->time = time(NULL);
   CRYPTO_new_ex_data(&session->ex_data);
   return session;
 }
@@ -315,14 +315,12 @@
 }
 
 void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) {
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
 
-  /* To avoid overflows and underflows, if we've gone back in time or any value
-   * is negative, update the time, but mark the session expired. */
-  if (session->time > now.tv_sec ||
-      session->time < 0 ||
-      now.tv_sec < 0) {
+  /* To avoid overflows and underflows, if we've gone back in time, update the
+   * time, but mark the session expired. */
+  if (session->time > now.tv_sec) {
     session->time = now.tv_sec;
     session->timeout = 0;
     session->auth_timeout = 0;
@@ -331,7 +329,7 @@
 
   /* Adjust the session time and timeouts. If the session has already expired,
    * clamp the timeouts at zero. */
-  long delta = now.tv_sec - session->time;
+  uint64_t delta = now.tv_sec - session->time;
   session->time = now.tv_sec;
   if (session->timeout < delta) {
     session->timeout = 0;
@@ -345,7 +343,8 @@
   }
 }
 
-void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout) {
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+                               uint32_t timeout) {
   /* Rebase the timestamp relative to the current time so |timeout| is measured
    * correctly. */
   ssl_session_rebase_time(ssl, session);
@@ -395,11 +394,11 @@
   return session->session_id;
 }
 
-long SSL_SESSION_get_timeout(const SSL_SESSION *session) {
+uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session) {
   return session->timeout;
 }
 
-long SSL_SESSION_get_time(const SSL_SESSION *session) {
+uint64_t SSL_SESSION_get_time(const SSL_SESSION *session) {
   if (session == NULL) {
     /* NULL should crash, but silently accept it here for compatibility. */
     return 0;
@@ -424,7 +423,7 @@
   return max_out;
 }
 
-long SSL_SESSION_set_time(SSL_SESSION *session, long time) {
+uint64_t SSL_SESSION_set_time(SSL_SESSION *session, uint64_t time) {
   if (session == NULL) {
     return 0;
   }
@@ -433,7 +432,7 @@
   return time;
 }
 
-long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout) {
+uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session, uint32_t timeout) {
   if (session == NULL) {
     return 0;
   }
@@ -528,7 +527,7 @@
   session->ssl_version = ssl->version;
 
   /* Fill in the time from the |SSL_CTX|'s clock. */
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
   session->time = now.tv_sec;
 
@@ -689,15 +688,15 @@
     return 0;
   }
 
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
 
   /* Reject tickets from the future to avoid underflow. */
-  if ((long)now.tv_sec < session->time) {
+  if (now.tv_sec < session->time) {
     return 0;
   }
 
-  return session->timeout > (long)now.tv_sec - session->time;
+  return session->timeout > now.tv_sec - session->time;
 }
 
 int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
@@ -933,7 +932,7 @@
   }
 }
 
-long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) {
+uint32_t SSL_CTX_set_timeout(SSL_CTX *ctx, uint32_t timeout) {
   if (ctx == NULL) {
     return 0;
   }
@@ -943,12 +942,12 @@
     timeout = SSL_DEFAULT_SESSION_TIMEOUT;
   }
 
-  long old_timeout = ctx->session_timeout;
+  uint32_t old_timeout = ctx->session_timeout;
   ctx->session_timeout = timeout;
   return old_timeout;
 }
 
-long SSL_CTX_get_timeout(const SSL_CTX *ctx) {
+uint32_t SSL_CTX_get_timeout(const SSL_CTX *ctx) {
   if (ctx == NULL) {
     return 0;
   }
@@ -956,13 +955,13 @@
   return ctx->session_timeout;
 }
 
-void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, long timeout) {
+void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, uint32_t timeout) {
   ctx->session_psk_dhe_timeout = timeout;
 }
 
 typedef struct timeout_param_st {
   SSL_CTX *ctx;
-  long time;
+  uint64_t time;
   LHASH_OF(SSL_SESSION) *cache;
 } TIMEOUT_PARAM;
 
@@ -970,6 +969,7 @@
   TIMEOUT_PARAM *param = void_param;
 
   if (param->time == 0 ||
+      session->time + session->timeout < session->time ||
       param->time > (session->time + session->timeout)) {
     /* timeout */
     /* The reason we don't call SSL_CTX_remove_session() is to
@@ -984,7 +984,7 @@
   }
 }
 
-void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time) {
+void SSL_CTX_flush_sessions(SSL_CTX *ctx, uint64_t time) {
   TIMEOUT_PARAM tp;
 
   tp.ctx = ctx;
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 97bcab3..4180463 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -990,12 +990,25 @@
   bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
   ASSERT_TRUE(ssl);
 
-  STACK_OF(X509_NAME) *stack = sk_X509_NAME_new_null();
-  ASSERT_TRUE(stack);
-  // |SSL_set_client_CA_list| takes ownership.
-  SSL_set_client_CA_list(ssl.get(), stack);
+  bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
+  ASSERT_TRUE(name);
 
-  EXPECT_EQ(stack, SSL_get_client_CA_list(ssl.get()));
+  bssl::UniquePtr<X509_NAME> name_dup(X509_NAME_dup(name.get()));
+  ASSERT_TRUE(name_dup);
+
+  bssl::UniquePtr<STACK_OF(X509_NAME)> stack(sk_X509_NAME_new_null());
+  ASSERT_TRUE(stack);
+
+  ASSERT_TRUE(sk_X509_NAME_push(stack.get(), name_dup.get()));
+  name_dup.release();
+
+  // |SSL_set_client_CA_list| takes ownership.
+  SSL_set_client_CA_list(ssl.get(), stack.release());
+
+  STACK_OF(X509_NAME) *result = SSL_get_client_CA_list(ssl.get());
+  ASSERT_TRUE(result);
+  ASSERT_EQ(1u, sk_X509_NAME_num(result));
+  EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(result, 0), name.get()));
 }
 
 static void AppendSession(SSL_SESSION *session, void *arg) {
diff --git a/src/ssl/ssl_x509.c b/src/ssl/ssl_x509.c
index 2955c21..9a396d0 100644
--- a/src/ssl/ssl_x509.c
+++ b/src/ssl/ssl_x509.c
@@ -152,9 +152,24 @@
 #include <openssl/x509_vfy.h>
 
 #include "internal.h"
+#include "../crypto/internal.h"
 
 
+/* check_ssl_x509_method asserts that |ssl| has the X509-based method
+ * installed. Calling an X509-based method on an |ssl| with a different method
+ * will likely misbehave and possibly crash or leak memory. */
+static void check_ssl_x509_method(const SSL *ssl) {
+  assert(ssl == NULL || ssl->ctx->x509_method == &ssl_crypto_x509_method);
+}
+
+/* check_ssl_ctx_x509_method acts like |check_ssl_x509_method|, but for an
+ * |SSL_CTX|. */
+static void check_ssl_ctx_x509_method(const SSL_CTX *ctx) {
+  assert(ctx == NULL || ctx->x509_method == &ssl_crypto_x509_method);
+}
+
 X509 *SSL_get_peer_certificate(const SSL *ssl) {
+  check_ssl_x509_method(ssl);
   if (ssl == NULL) {
     return NULL;
   }
@@ -167,6 +182,7 @@
 }
 
 STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) {
+  check_ssl_x509_method(ssl);
   if (ssl == NULL) {
     return NULL;
   }
@@ -203,6 +219,7 @@
 }
 
 STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl) {
+  check_ssl_x509_method(ssl);
   SSL_SESSION *session = SSL_get_session(ssl);
   if (session == NULL) {
     return NULL;
@@ -212,54 +229,74 @@
 }
 
 int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) {
+  check_ssl_ctx_x509_method(ctx);
   return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose);
 }
 
 int SSL_set_purpose(SSL *ssl, int purpose) {
+  check_ssl_x509_method(ssl);
   return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose);
 }
 
 int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) {
+  check_ssl_ctx_x509_method(ctx);
   return X509_VERIFY_PARAM_set_trust(ctx->param, trust);
 }
 
 int SSL_set_trust(SSL *ssl, int trust) {
+  check_ssl_x509_method(ssl);
   return X509_VERIFY_PARAM_set_trust(ssl->param, trust);
 }
 
 int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) {
+  check_ssl_ctx_x509_method(ctx);
   return X509_VERIFY_PARAM_set1(ctx->param, param);
 }
 
 int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) {
+  check_ssl_x509_method(ssl);
   return X509_VERIFY_PARAM_set1(ssl->param, param);
 }
 
-X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; }
+X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
+  return ctx->param;
+}
 
-X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; }
+X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) {
+  check_ssl_x509_method(ssl);
+  return ssl->param;
+}
 
 int SSL_get_verify_depth(const SSL *ssl) {
+  check_ssl_x509_method(ssl);
   return X509_VERIFY_PARAM_get_depth(ssl->param);
 }
 
 int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) {
+  check_ssl_x509_method(ssl);
   return ssl->verify_callback;
 }
 
-int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { return ctx->verify_mode; }
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
+  return ctx->verify_mode;
+}
 
 int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
   return X509_VERIFY_PARAM_get_depth(ctx->param);
 }
 
 int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(
     int ok, X509_STORE_CTX *store_ctx) {
+  check_ssl_ctx_x509_method(ctx);
   return ctx->default_verify_callback;
 }
 
 void SSL_set_verify(SSL *ssl, int mode,
                     int (*callback)(int ok, X509_STORE_CTX *store_ctx)) {
+  check_ssl_x509_method(ssl);
   ssl->verify_mode = mode;
   if (callback != NULL) {
     ssl->verify_callback = callback;
@@ -267,6 +304,7 @@
 }
 
 void SSL_set_verify_depth(SSL *ssl, int depth) {
+  check_ssl_x509_method(ssl);
   X509_VERIFY_PARAM_set_depth(ssl->param, depth);
 }
 
@@ -274,36 +312,43 @@
                                       int (*cb)(X509_STORE_CTX *store_ctx,
                                                 void *arg),
                                       void *arg) {
+  check_ssl_ctx_x509_method(ctx);
   ctx->app_verify_callback = cb;
   ctx->app_verify_arg = arg;
 }
 
 void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
                         int (*cb)(int, X509_STORE_CTX *)) {
+  check_ssl_ctx_x509_method(ctx);
   ctx->verify_mode = mode;
   ctx->default_verify_callback = cb;
 }
 
 void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) {
+  check_ssl_ctx_x509_method(ctx);
   X509_VERIFY_PARAM_set_depth(ctx->param, depth);
 }
 
 int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
   return X509_STORE_set_default_paths(ctx->cert_store);
 }
 
 int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file,
                                   const char *ca_dir) {
+  check_ssl_ctx_x509_method(ctx);
   return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir);
 }
 
 void SSL_set_verify_result(SSL *ssl, long result) {
+  check_ssl_x509_method(ssl);
   if (result != X509_V_OK) {
     abort();
   }
 }
 
 long SSL_get_verify_result(const SSL *ssl) {
+  check_ssl_x509_method(ssl);
   SSL_SESSION *session = SSL_get_session(ssl);
   if (session == NULL) {
     return X509_V_ERR_INVALID_CALL;
@@ -312,32 +357,142 @@
 }
 
 X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
   return ctx->cert_store;
 }
 
 void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+  check_ssl_ctx_x509_method(ctx);
   X509_STORE_free(ctx->cert_store);
   ctx->cert_store = store;
 }
 
-static void ssl_crypto_x509_flush_cached_leaf(CERT *cert) {
+/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
+ * contents of |x509|. */
+static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) {
+  uint8_t *buf = NULL;
+  int cert_len = i2d_X509(x509, &buf);
+  if (cert_len <= 0) {
+    return 0;
+  }
+
+  CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL);
+  OPENSSL_free(buf);
+
+  return buffer;
+}
+
+/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */
+static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) {
+  STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null();
+  if (chain == NULL) {
+    return NULL;
+  }
+
+  if (!sk_CRYPTO_BUFFER_push(chain, NULL)) {
+    sk_CRYPTO_BUFFER_free(chain);
+    return NULL;
+  }
+
+  return chain;
+}
+
+/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised
+ * forms of elements of |chain|. It returns one on success or zero on error, in
+ * which case no change to |cert->chain| is made. It preverses the existing
+ * leaf from |cert->chain|, if any. */
+static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) {
+  STACK_OF(CRYPTO_BUFFER) *new_chain = NULL;
+
+  if (cert->chain != NULL) {
+    new_chain = sk_CRYPTO_BUFFER_new_null();
+    if (new_chain == NULL) {
+      return 0;
+    }
+
+    CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
+    if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) {
+      goto err;
+    }
+    /* |leaf| might be NULL if it's a “leafless” chain. */
+    if (leaf != NULL) {
+      CRYPTO_BUFFER_up_ref(leaf);
+    }
+  }
+
+  for (size_t i = 0; i < sk_X509_num(chain); i++) {
+    if (new_chain == NULL) {
+      new_chain = new_leafless_chain();
+      if (new_chain == NULL) {
+        goto err;
+      }
+    }
+
+    CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i));
+    if (buffer == NULL ||
+        !sk_CRYPTO_BUFFER_push(new_chain, buffer)) {
+      CRYPTO_BUFFER_free(buffer);
+      goto err;
+    }
+  }
+
+  sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
+  cert->chain = new_chain;
+
+  return 1;
+
+err:
+  sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free);
+  return 0;
+}
+
+static void ssl_crypto_x509_cert_flush_cached_leaf(CERT *cert) {
   X509_free(cert->x509_leaf);
   cert->x509_leaf = NULL;
 }
 
-static void ssl_crypto_x509_flush_cached_chain(CERT *cert) {
+static void ssl_crypto_x509_cert_flush_cached_chain(CERT *cert) {
   sk_X509_pop_free(cert->x509_chain, X509_free);
   cert->x509_chain = NULL;
 }
 
-static void ssl_crypto_x509_clear(CERT *cert) {
-  ssl_crypto_x509_flush_cached_leaf(cert);
-  ssl_crypto_x509_flush_cached_chain(cert);
+static int ssl_crypto_x509_check_client_CA_list(
+    STACK_OF(CRYPTO_BUFFER) *names) {
+  for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
+    const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(names, i);
+    const uint8_t *inp = CRYPTO_BUFFER_data(buffer);
+    X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer));
+    const int ok = name != NULL && inp == CRYPTO_BUFFER_data(buffer) +
+                                              CRYPTO_BUFFER_len(buffer);
+    X509_NAME_free(name);
+    if (!ok) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+static void ssl_crypto_x509_cert_clear(CERT *cert) {
+  ssl_crypto_x509_cert_flush_cached_leaf(cert);
+  ssl_crypto_x509_cert_flush_cached_chain(cert);
 
   X509_free(cert->x509_stash);
   cert->x509_stash = NULL;
 }
 
+static void ssl_crypto_x509_cert_free(CERT *cert) {
+  ssl_crypto_x509_cert_clear(cert);
+  X509_STORE_free(cert->verify_store);
+}
+
+static void ssl_crypto_x509_cert_dup(CERT *new_cert, const CERT *cert) {
+  if (cert->verify_store != NULL) {
+    X509_STORE_up_ref(cert->verify_store);
+    new_cert->verify_store = cert->verify_store;
+  }
+}
+
 static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) {
   STACK_OF(X509) *chain = NULL;
   const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs);
@@ -410,30 +565,171 @@
   session->x509_chain_without_leaf = NULL;
 }
 
-const SSL_X509_METHOD ssl_crypto_x509_method = {
-  ssl_crypto_x509_clear,
-  ssl_crypto_x509_flush_cached_chain,
-  ssl_crypto_x509_flush_cached_leaf,
-  ssl_crypto_x509_session_cache_objects,
-  ssl_crypto_x509_session_dup,
-  ssl_crypto_x509_session_clear,
-};
-
-/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
- * contents of |x509|. */
-static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) {
-  uint8_t *buf = NULL;
-  int cert_len = i2d_X509(x509, &buf);
-  if (cert_len <= 0) {
+static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session,
+                                                     SSL *ssl) {
+  STACK_OF(X509) *const cert_chain = session->x509_chain;
+  if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) {
     return 0;
   }
 
-  CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL);
-  OPENSSL_free(buf);
+  X509_STORE *verify_store = ssl->ctx->cert_store;
+  if (ssl->cert->verify_store != NULL) {
+    verify_store = ssl->cert->verify_store;
+  }
 
-  return buffer;
+  X509 *leaf = sk_X509_value(cert_chain, 0);
+  int ret = 0;
+  X509_STORE_CTX ctx;
+  if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
+    return 0;
+  }
+  if (!X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(),
+                                  ssl)) {
+    goto err;
+  }
+
+  /* We need to inherit the verify parameters. These can be determined by the
+   * context: if its a server it will verify SSL client certificates or vice
+   * versa. */
+  X509_STORE_CTX_set_default(&ctx, ssl->server ? "ssl_client" : "ssl_server");
+
+  /* Anything non-default in "param" should overwrite anything in the ctx. */
+  X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param);
+
+  if (ssl->verify_callback) {
+    X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback);
+  }
+
+  int verify_ret;
+  if (ssl->ctx->app_verify_callback != NULL) {
+    verify_ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg);
+  } else {
+    verify_ret = X509_verify_cert(&ctx);
+  }
+
+  session->verify_result = ctx.error;
+
+  /* If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result. */
+  if (verify_ret <= 0 && ssl->verify_mode != SSL_VERIFY_NONE) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, ssl_verify_alarm_type(ctx.error));
+    OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
+    goto err;
+  }
+
+  ERR_clear_error();
+  ret = 1;
+
+err:
+  X509_STORE_CTX_cleanup(&ctx);
+  return ret;
 }
 
+static void ssl_crypto_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {
+  sk_X509_NAME_pop_free(hs->cached_x509_ca_names, X509_NAME_free);
+  hs->cached_x509_ca_names = NULL;
+}
+
+static int ssl_crypto_x509_ssl_new(SSL *ssl) {
+  ssl->param = X509_VERIFY_PARAM_new();
+  if (ssl->param == NULL) {
+    return 0;
+  }
+  X509_VERIFY_PARAM_inherit(ssl->param, ssl->ctx->param);
+  return 1;
+}
+
+static void ssl_crypto_x509_ssl_flush_cached_client_CA(SSL *ssl) {
+  sk_X509_NAME_pop_free(ssl->cached_x509_client_CA, X509_NAME_free);
+  ssl->cached_x509_client_CA = NULL;
+}
+
+static void ssl_crypto_x509_ssl_free(SSL *ssl) {
+  ssl_crypto_x509_ssl_flush_cached_client_CA(ssl);
+  X509_VERIFY_PARAM_free(ssl->param);
+}
+
+static int ssl_crypto_x509_ssl_auto_chain_if_needed(SSL *ssl) {
+  /* Only build a chain if there are no intermediates configured and the feature
+   * isn't disabled. */
+  if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) ||
+      !ssl_has_certificate(ssl) ||
+      ssl->cert->chain == NULL ||
+      sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) {
+    return 1;
+  }
+
+  X509 *leaf =
+      X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0));
+  if (!leaf) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
+    return 0;
+  }
+
+  X509_STORE_CTX ctx;
+  if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) {
+    X509_free(leaf);
+    OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
+    return 0;
+  }
+
+  /* Attempt to build a chain, ignoring the result. */
+  X509_verify_cert(&ctx);
+  X509_free(leaf);
+  ERR_clear_error();
+
+  /* Remove the leaf from the generated chain. */
+  X509_free(sk_X509_shift(ctx.chain));
+
+  const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain);
+  X509_STORE_CTX_cleanup(&ctx);
+  if (!ok) {
+    return 0;
+  }
+
+  ssl_crypto_x509_cert_flush_cached_chain(ssl->cert);
+
+  return 1;
+}
+
+static void ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {
+  sk_X509_NAME_pop_free(ctx->cached_x509_client_CA, X509_NAME_free);
+  ctx->cached_x509_client_CA = NULL;
+}
+
+static int ssl_crypto_x509_ssl_ctx_new(SSL_CTX *ctx) {
+  ctx->cert_store = X509_STORE_new();
+  ctx->param = X509_VERIFY_PARAM_new();
+  return (ctx->cert_store != NULL && ctx->param != NULL);
+}
+
+static void ssl_crypto_x509_ssl_ctx_free(SSL_CTX *ctx) {
+  ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(ctx);
+  X509_VERIFY_PARAM_free(ctx->param);
+  X509_STORE_free(ctx->cert_store);
+}
+
+const SSL_X509_METHOD ssl_crypto_x509_method = {
+  ssl_crypto_x509_check_client_CA_list,
+  ssl_crypto_x509_cert_clear,
+  ssl_crypto_x509_cert_free,
+  ssl_crypto_x509_cert_dup,
+  ssl_crypto_x509_cert_flush_cached_chain,
+  ssl_crypto_x509_cert_flush_cached_leaf,
+  ssl_crypto_x509_session_cache_objects,
+  ssl_crypto_x509_session_dup,
+  ssl_crypto_x509_session_clear,
+  ssl_crypto_x509_session_verify_cert_chain,
+  ssl_crypto_x509_hs_flush_cached_ca_names,
+  ssl_crypto_x509_ssl_new,
+  ssl_crypto_x509_ssl_free,
+  ssl_crypto_x509_ssl_flush_cached_client_CA,
+  ssl_crypto_x509_ssl_auto_chain_if_needed,
+  ssl_crypto_x509_ssl_ctx_new,
+  ssl_crypto_x509_ssl_ctx_free,
+  ssl_crypto_x509_ssl_ctx_flush_cached_client_CA,
+};
+
 static int ssl_use_certificate(CERT *cert, X509 *x) {
   if (x == NULL) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
@@ -451,10 +747,12 @@
 }
 
 int SSL_use_certificate(SSL *ssl, X509 *x) {
+  check_ssl_x509_method(ssl);
   return ssl_use_certificate(ssl->cert, x);
 }
 
 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) {
+  check_ssl_ctx_x509_method(ctx);
   return ssl_use_certificate(ctx->cert, x);
 }
 
@@ -487,75 +785,16 @@
 }
 
 X509 *SSL_get_certificate(const SSL *ssl) {
+  check_ssl_x509_method(ssl);
   return ssl_cert_get0_leaf(ssl->cert);
 }
 
 X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
-  return ssl_cert_get0_leaf(ctx->cert);
-}
-
-/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */
-static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) {
-  STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null();
-  if (chain == NULL) {
-    return NULL;
-  }
-
-  if (!sk_CRYPTO_BUFFER_push(chain, NULL)) {
-    sk_CRYPTO_BUFFER_free(chain);
-    return NULL;
-  }
-
-  return chain;
-}
-
-/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised
- * forms of elements of |chain|. It returns one on success or zero on error, in
- * which case no change to |cert->chain| is made. It preverses the existing
- * leaf from |cert->chain|, if any. */
-static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) {
-  STACK_OF(CRYPTO_BUFFER) *new_chain = NULL;
-
-  if (cert->chain != NULL) {
-    new_chain = sk_CRYPTO_BUFFER_new_null();
-    if (new_chain == NULL) {
-      return 0;
-    }
-
-    CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
-    if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) {
-      goto err;
-    }
-    /* |leaf| might be NULL if it's a “leafless” chain. */
-    if (leaf != NULL) {
-      CRYPTO_BUFFER_up_ref(leaf);
-    }
-  }
-
-  for (size_t i = 0; i < sk_X509_num(chain); i++) {
-    if (new_chain == NULL) {
-      new_chain = new_leafless_chain();
-      if (new_chain == NULL) {
-        goto err;
-      }
-    }
-
-    CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i));
-    if (buffer == NULL ||
-        !sk_CRYPTO_BUFFER_push(new_chain, buffer)) {
-      CRYPTO_BUFFER_free(buffer);
-      goto err;
-    }
-  }
-
-  sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
-  cert->chain = new_chain;
-
-  return 1;
-
-err:
-  sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free);
-  return 0;
+  check_ssl_ctx_x509_method(ctx);
+  CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+  X509 *ret = ssl_cert_get0_leaf(ctx->cert);
+  CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+  return ret;
 }
 
 static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) {
@@ -564,7 +803,7 @@
   }
 
   sk_X509_pop_free(chain, X509_free);
-  ssl_crypto_x509_flush_cached_chain(cert);
+  ssl_crypto_x509_cert_flush_cached_chain(cert);
   return 1;
 }
 
@@ -573,7 +812,7 @@
     return 0;
   }
 
-  ssl_crypto_x509_flush_cached_chain(cert);
+  ssl_crypto_x509_cert_flush_cached_chain(cert);
   return 1;
 }
 
@@ -613,7 +852,7 @@
 
   X509_free(cert->x509_stash);
   cert->x509_stash = x509;
-  ssl_crypto_x509_flush_cached_chain(cert);
+  ssl_crypto_x509_cert_flush_cached_chain(cert);
   return 1;
 }
 
@@ -622,101 +861,70 @@
     return 0;
   }
 
-  ssl_crypto_x509_flush_cached_chain(cert);
+  ssl_crypto_x509_cert_flush_cached_chain(cert);
   return 1;
 }
 
 int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+  check_ssl_ctx_x509_method(ctx);
   return ssl_cert_set0_chain(ctx->cert, chain);
 }
 
 int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+  check_ssl_ctx_x509_method(ctx);
   return ssl_cert_set1_chain(ctx->cert, chain);
 }
 
 int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) {
+  check_ssl_x509_method(ssl);
   return ssl_cert_set0_chain(ssl->cert, chain);
 }
 
 int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) {
+  check_ssl_x509_method(ssl);
   return ssl_cert_set1_chain(ssl->cert, chain);
 }
 
 int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) {
+  check_ssl_ctx_x509_method(ctx);
   return ssl_cert_add0_chain_cert(ctx->cert, x509);
 }
 
 int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) {
+  check_ssl_ctx_x509_method(ctx);
   return ssl_cert_add1_chain_cert(ctx->cert, x509);
 }
 
 int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) {
+  check_ssl_ctx_x509_method(ctx);
   return SSL_CTX_add0_chain_cert(ctx, x509);
 }
 
 int SSL_add0_chain_cert(SSL *ssl, X509 *x509) {
+  check_ssl_x509_method(ssl);
   return ssl_cert_add0_chain_cert(ssl->cert, x509);
 }
 
 int SSL_add1_chain_cert(SSL *ssl, X509 *x509) {
+  check_ssl_x509_method(ssl);
   return ssl_cert_add1_chain_cert(ssl->cert, x509);
 }
 
 int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
   return SSL_CTX_set0_chain(ctx, NULL);
 }
 
 int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
   return SSL_CTX_clear_chain_certs(ctx);
 }
 
 int SSL_clear_chain_certs(SSL *ssl) {
+  check_ssl_x509_method(ssl);
   return SSL_set0_chain(ssl, NULL);
 }
 
-int ssl_auto_chain_if_needed(SSL *ssl) {
-  /* Only build a chain if there are no intermediates configured and the feature
-   * isn't disabled. */
-  if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) ||
-      !ssl_has_certificate(ssl) ||
-      ssl->cert->chain == NULL ||
-      sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) {
-    return 1;
-  }
-
-  X509 *leaf =
-      X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0));
-  if (!leaf) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
-    return 0;
-  }
-
-  X509_STORE_CTX ctx;
-  if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) {
-    X509_free(leaf);
-    OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
-    return 0;
-  }
-
-  /* Attempt to build a chain, ignoring the result. */
-  X509_verify_cert(&ctx);
-  X509_free(leaf);
-  ERR_clear_error();
-
-  /* Remove the leaf from the generated chain. */
-  X509_free(sk_X509_shift(ctx.chain));
-
-  const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain);
-  X509_STORE_CTX_cleanup(&ctx);
-  if (!ok) {
-    return 0;
-  }
-
-  ssl_crypto_x509_flush_cached_chain(ssl->cert);
-
-  return 1;
-}
-
 /* ssl_cert_cache_chain_certs fills in |cert->x509_chain| from elements 1.. of
  * |cert->chain|. */
 static int ssl_cert_cache_chain_certs(CERT *cert) {
@@ -752,7 +960,12 @@
 }
 
 int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) {
-  if (!ssl_cert_cache_chain_certs(ctx->cert)) {
+  check_ssl_ctx_x509_method(ctx);
+  CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+  const int ret = ssl_cert_cache_chain_certs(ctx->cert);
+  CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+
+  if (!ret) {
     *out_chain = NULL;
     return 0;
   }
@@ -767,6 +980,7 @@
 }
 
 int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) {
+  check_ssl_x509_method(ssl);
   if (!ssl_cert_cache_chain_certs(ssl->cert)) {
     *out_chain = NULL;
     return 0;
@@ -813,3 +1027,258 @@
   *pp = CBS_data(&cbs);
   return ret;
 }
+
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
+  return sk_X509_NAME_deep_copy(list, X509_NAME_dup, X509_NAME_free);
+}
+
+static void set_client_CA_list(STACK_OF(CRYPTO_BUFFER) **ca_list,
+                               const STACK_OF(X509_NAME) *name_list,
+                               CRYPTO_BUFFER_POOL *pool) {
+  STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null();
+  if (buffers == NULL) {
+    return;
+  }
+
+  for (size_t i = 0; i < sk_X509_NAME_num(name_list); i++) {
+    X509_NAME *name = sk_X509_NAME_value(name_list, i);
+    uint8_t *outp = NULL;
+    int len = i2d_X509_NAME(name, &outp);
+    if (len < 0) {
+      goto err;
+    }
+
+    CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool);
+    OPENSSL_free(outp);
+    if (buffer == NULL ||
+        !sk_CRYPTO_BUFFER_push(buffers, buffer)) {
+      CRYPTO_BUFFER_free(buffer);
+      goto err;
+    }
+  }
+
+  sk_CRYPTO_BUFFER_pop_free(*ca_list, CRYPTO_BUFFER_free);
+  *ca_list = buffers;
+  return;
+
+err:
+  sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
+}
+
+void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) {
+  check_ssl_x509_method(ssl);
+  ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl);
+  set_client_CA_list(&ssl->client_CA, name_list, ssl->ctx->pool);
+  sk_X509_NAME_pop_free(name_list, X509_NAME_free);
+}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) {
+  check_ssl_ctx_x509_method(ctx);
+  ctx->x509_method->ssl_ctx_flush_cached_client_CA(ctx);
+  set_client_CA_list(&ctx->client_CA, name_list, ctx->pool);
+  sk_X509_NAME_pop_free(name_list, X509_NAME_free);
+}
+
+static STACK_OF(X509_NAME) *
+    buffer_names_to_x509(const STACK_OF(CRYPTO_BUFFER) *names,
+                         STACK_OF(X509_NAME) **cached) {
+  if (names == NULL) {
+    return NULL;
+  }
+
+  if (*cached != NULL) {
+    return *cached;
+  }
+
+  STACK_OF(X509_NAME) *new_cache = sk_X509_NAME_new_null();
+  if (new_cache == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    return NULL;
+  }
+
+  for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
+    const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(names, i);
+    const uint8_t *inp = CRYPTO_BUFFER_data(buffer);
+    X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer));
+    if (name == NULL ||
+        inp != CRYPTO_BUFFER_data(buffer) + CRYPTO_BUFFER_len(buffer) ||
+        !sk_X509_NAME_push(new_cache, name)) {
+      X509_NAME_free(name);
+      goto err;
+    }
+  }
+
+  *cached = new_cache;
+  return new_cache;
+
+err:
+  sk_X509_NAME_pop_free(new_cache, X509_NAME_free);
+  return NULL;
+}
+
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
+  check_ssl_x509_method(ssl);
+  /* For historical reasons, this function is used both to query configuration
+   * state on a server as well as handshake state on a client. However, whether
+   * |ssl| is a client or server is not known until explicitly configured with
+   * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
+   * indeterminate mode and |ssl->server| is unset. */
+  if (ssl->handshake_func != NULL && !ssl->server) {
+    if (ssl->s3->hs != NULL) {
+      return buffer_names_to_x509(ssl->s3->hs->ca_names,
+                                  &ssl->s3->hs->cached_x509_ca_names);
+    }
+
+    return NULL;
+  }
+
+  if (ssl->client_CA != NULL) {
+    return buffer_names_to_x509(
+        ssl->client_CA, (STACK_OF(X509_NAME) **)&ssl->cached_x509_client_CA);
+  }
+  return buffer_names_to_x509(ssl->ctx->client_CA,
+                              &ssl->ctx->cached_x509_client_CA);
+}
+
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) {
+  check_ssl_ctx_x509_method(ctx);
+  CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+  STACK_OF(X509_NAME) *ret = buffer_names_to_x509(
+      ctx->client_CA, (STACK_OF(X509_NAME) **)&ctx->cached_x509_client_CA);
+  CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+  return ret;
+}
+
+static int add_client_CA(STACK_OF(CRYPTO_BUFFER) **names, X509 *x509,
+                         CRYPTO_BUFFER_POOL *pool) {
+  if (x509 == NULL) {
+    return 0;
+  }
+
+  uint8_t *outp = NULL;
+  int len = i2d_X509_NAME(X509_get_subject_name(x509), &outp);
+  if (len < 0) {
+    return 0;
+  }
+
+  CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool);
+  OPENSSL_free(outp);
+  if (buffer == NULL) {
+    return 0;
+  }
+
+  int alloced = 0;
+  if (*names == NULL) {
+    *names = sk_CRYPTO_BUFFER_new_null();
+    alloced = 1;
+
+    if (*names == NULL) {
+      CRYPTO_BUFFER_free(buffer);
+      return 0;
+    }
+  }
+
+  if (!sk_CRYPTO_BUFFER_push(*names, buffer)) {
+    CRYPTO_BUFFER_free(buffer);
+    if (alloced) {
+      sk_CRYPTO_BUFFER_pop_free(*names, CRYPTO_BUFFER_free);
+      *names = NULL;
+    }
+    return 0;
+  }
+
+  return 1;
+}
+
+int SSL_add_client_CA(SSL *ssl, X509 *x509) {
+  check_ssl_x509_method(ssl);
+  if (!add_client_CA(&ssl->client_CA, x509, ssl->ctx->pool)) {
+    return 0;
+  }
+
+  ssl_crypto_x509_ssl_flush_cached_client_CA(ssl);
+  return 1;
+}
+
+int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) {
+  check_ssl_ctx_x509_method(ctx);
+  if (!add_client_CA(&ctx->client_CA, x509, ctx->pool)) {
+    return 0;
+  }
+
+  ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(ctx);
+  return 1;
+}
+
+static int do_client_cert_cb(SSL *ssl, void *arg) {
+  if (ssl_has_certificate(ssl) || ssl->ctx->client_cert_cb == NULL) {
+    return 1;
+  }
+
+  X509 *x509 = NULL;
+  EVP_PKEY *pkey = NULL;
+  int ret = ssl->ctx->client_cert_cb(ssl, &x509, &pkey);
+  if (ret < 0) {
+    return -1;
+  }
+
+  if (ret != 0) {
+    if (!SSL_use_certificate(ssl, x509) ||
+        !SSL_use_PrivateKey(ssl, pkey)) {
+      return 0;
+    }
+  }
+
+  X509_free(x509);
+  EVP_PKEY_free(pkey);
+  return 1;
+}
+
+void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl,
+                                                        X509 **out_x509,
+                                                        EVP_PKEY **out_pkey)) {
+  check_ssl_ctx_x509_method(ctx);
+  /* Emulate the old client certificate callback with the new one. */
+  SSL_CTX_set_cert_cb(ctx, do_client_cert_cb, NULL);
+  ctx->client_cert_cb = cb;
+}
+
+static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store,
+                          int take_ref) {
+  X509_STORE_free(*store_ptr);
+  *store_ptr = new_store;
+
+  if (new_store != NULL && take_ref) {
+    X509_STORE_up_ref(new_store);
+  }
+
+  return 1;
+}
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void) {
+  /* The ex_data index to go from |X509_STORE_CTX| to |SSL| always uses the
+   * reserved app_data slot. Before ex_data was introduced, app_data was used.
+   * Avoid breaking any software which assumes |X509_STORE_CTX_get_app_data|
+   * works. */
+  return 0;
+}
+
+int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+  check_ssl_ctx_x509_method(ctx);
+  return set_cert_store(&ctx->cert->verify_store, store, 0);
+}
+
+int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+  check_ssl_ctx_x509_method(ctx);
+  return set_cert_store(&ctx->cert->verify_store, store, 1);
+}
+
+int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) {
+  check_ssl_x509_method(ssl);
+  return set_cert_store(&ssl->cert->verify_store, store, 0);
+}
+
+int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) {
+  check_ssl_x509_method(ssl);
+  return set_cert_store(&ssl->cert->verify_store, store, 1);
+}
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index d6ef1ff..adc7344 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -1901,7 +1901,7 @@
     return 1;
   }
 
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
   uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time);
   uint32_t obfuscated_ticket_age = ticket_age + ssl->session->ticket_age_add;
@@ -2403,46 +2403,6 @@
 }
 
 
-/* Short record headers
- *
- * This is a non-standard extension which negotiates
- * https://github.com/tlswg/tls13-spec/pull/762 for experimenting. */
-
-static int ext_short_header_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
-  SSL *const ssl = hs->ssl;
-  uint16_t min_version, max_version;
-  if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
-    return 0;
-  }
-
-  if (max_version < TLS1_3_VERSION ||
-      !ssl->ctx->short_header_enabled) {
-    return 1;
-  }
-
-  return CBB_add_u16(out, TLSEXT_TYPE_short_header) &&
-         CBB_add_u16(out, 0 /* empty extension */);
-}
-
-static int ext_short_header_parse_clienthello(SSL_HANDSHAKE *hs,
-                                              uint8_t *out_alert,
-                                              CBS *contents) {
-  SSL *const ssl = hs->ssl;
-  if (contents == NULL ||
-      !ssl->ctx->short_header_enabled ||
-      ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
-    return 1;
-  }
-
-  if (CBS_len(contents) != 0) {
-    return 0;
-  }
-
-  ssl->s3->short_header = 1;
-  return 1;
-}
-
-
 /* Negotiated Groups
  *
  * https://tools.ietf.org/html/rfc4492#section-5.1.2
@@ -2673,14 +2633,6 @@
     ignore_parse_clienthello,
     dont_add_serverhello,
   },
-  {
-    TLSEXT_TYPE_short_header,
-    NULL,
-    ext_short_header_add_clienthello,
-    forbid_parse_serverhello,
-    ext_short_header_parse_clienthello,
-    dont_add_serverhello,
-  },
   /* The final extension must be non-empty. WebSphere Application Server 7.0 is
    * intolerant to the last extension being zero-length. See
    * https://crbug.com/363583. */
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 48d0538..984136c 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -191,6 +191,100 @@
       PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL));
 }
 
+static bool FromHexDigit(uint8_t *out, char c) {
+  if ('0' <= c && c <= '9') {
+    *out = c - '0';
+    return true;
+  }
+  if ('a' <= c && c <= 'f') {
+    *out = c - 'a' + 10;
+    return true;
+  }
+  if ('A' <= c && c <= 'F') {
+    *out = c - 'A' + 10;
+    return true;
+  }
+  return false;
+}
+
+static bool HexDecode(std::string *out, const std::string &in) {
+  if ((in.size() & 1) != 0) {
+    return false;
+  }
+
+  std::unique_ptr<uint8_t[]> buf(new uint8_t[in.size() / 2]);
+  for (size_t i = 0; i < in.size() / 2; i++) {
+    uint8_t high, low;
+    if (!FromHexDigit(&high, in[i*2]) ||
+        !FromHexDigit(&low, in[i*2+1])) {
+      return false;
+    }
+    buf[i] = (high << 4) | low;
+  }
+
+  out->assign(reinterpret_cast<const char *>(buf.get()), in.size() / 2);
+  return true;
+}
+
+static std::vector<std::string> SplitParts(const std::string &in,
+                                           const char delim) {
+  std::vector<std::string> ret;
+  size_t start = 0;
+
+  for (size_t i = 0; i < in.size(); i++) {
+    if (in[i] == delim) {
+      ret.push_back(in.substr(start, i - start));
+      start = i + 1;
+    }
+  }
+
+  ret.push_back(in.substr(start, std::string::npos));
+  return ret;
+}
+
+static std::vector<std::string> DecodeHexStrings(
+    const std::string &hex_strings) {
+  std::vector<std::string> ret;
+  const std::vector<std::string> parts = SplitParts(hex_strings, ',');
+
+  for (const auto &part : parts) {
+    std::string binary;
+    if (!HexDecode(&binary, part)) {
+      fprintf(stderr, "Bad hex string: %s\n", part.c_str());
+      return ret;
+    }
+
+    ret.push_back(binary);
+  }
+
+  return ret;
+}
+
+static bssl::UniquePtr<STACK_OF(X509_NAME)> DecodeHexX509Names(
+    const std::string &hex_names) {
+  const std::vector<std::string> der_names = DecodeHexStrings(hex_names);
+  bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
+
+  for (const auto &der_name : der_names) {
+    const uint8_t *const data =
+        reinterpret_cast<const uint8_t *>(der_name.data());
+    const uint8_t *derp = data;
+    bssl::UniquePtr<X509_NAME> name(
+        d2i_X509_NAME(nullptr, &derp, der_name.size()));
+    if (!name || derp != data + der_name.size()) {
+      fprintf(stderr, "Failed to parse X509_NAME.\n");
+      return nullptr;
+    }
+
+    if (!sk_X509_NAME_push(ret.get(), name.get())) {
+      return nullptr;
+    }
+    name.release();
+  }
+
+  return ret;
+}
+
 static int AsyncPrivateKeyType(SSL *ssl) {
   EVP_PKEY *key = GetTestState(ssl)->private_key.get();
   switch (EVP_PKEY_id(key)) {
@@ -509,7 +603,39 @@
     }
   }
 
-  // TODO(davidben): Test |SSL_get_client_CA_list|.
+  if (!config->expected_client_ca_list.empty()) {
+    bssl::UniquePtr<STACK_OF(X509_NAME)> expected =
+        DecodeHexX509Names(config->expected_client_ca_list);
+    const size_t num_expected = sk_X509_NAME_num(expected.get());
+
+    const STACK_OF(X509_NAME) *received = SSL_get_client_CA_list(ssl);
+    const size_t num_received = sk_X509_NAME_num(received);
+
+    if (num_received != num_expected) {
+      fprintf(stderr, "expected %u names in CertificateRequest but got %u\n",
+              static_cast<unsigned>(num_expected),
+              static_cast<unsigned>(num_received));
+      return false;
+    }
+
+    for (size_t i = 0; i < num_received; i++) {
+      if (X509_NAME_cmp(sk_X509_NAME_value(received, i),
+                        sk_X509_NAME_value(expected.get(), i)) != 0) {
+        fprintf(stderr, "names in CertificateRequest differ at index #%d\n",
+                static_cast<unsigned>(i));
+        return false;
+      }
+    }
+
+    STACK_OF(CRYPTO_BUFFER) *buffers = SSL_get0_server_requested_CAs(ssl);
+    if (sk_CRYPTO_BUFFER_num(buffers) != num_received) {
+      fprintf(stderr,
+              "Mismatch between SSL_get_server_requested_CAs and "
+              "SSL_get_client_CA_list.\n");
+      return false;
+    }
+  }
+
   return true;
 }
 
@@ -1026,8 +1152,14 @@
     return nullptr;
   }
 
-  if (config->use_null_client_ca_list) {
-    SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
+  if (!config->use_client_ca_list.empty()) {
+    if (config->use_client_ca_list == "<NULL>") {
+      SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
+    } else {
+      bssl::UniquePtr<STACK_OF(X509_NAME)> names =
+          DecodeHexX509Names(config->use_client_ca_list);
+      SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
+    }
   }
 
   if (config->enable_grease) {
@@ -1044,10 +1176,6 @@
     return nullptr;
   }
 
-  if (config->enable_short_header) {
-    SSL_CTX_set_short_header_enabled(ssl_ctx.get(), 1);
-  }
-
   if (config->enable_early_data) {
     SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
   }
@@ -1660,7 +1788,7 @@
     return false;
   }
   if (config->is_dtls) {
-    bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock, !config->async);
+    bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock);
     if (!packeted) {
       return false;
     }
diff --git a/src/ssl/test/packeted_bio.cc b/src/ssl/test/packeted_bio.cc
index 835df0e..835dbfb 100644
--- a/src/ssl/test/packeted_bio.cc
+++ b/src/ssl/test/packeted_bio.cc
@@ -33,31 +33,17 @@
 const uint8_t kOpcodeTimeoutAck = 't';
 
 struct PacketedBio {
-  PacketedBio(timeval *clock_arg, bool advance_clock_arg)
-      : clock(clock_arg), advance_clock(advance_clock_arg) {
+  explicit PacketedBio(timeval *clock_arg)
+      : clock(clock_arg) {
     OPENSSL_memset(&timeout, 0, sizeof(timeout));
-    OPENSSL_memset(&read_deadline, 0, sizeof(read_deadline));
   }
 
   bool HasTimeout() const {
     return timeout.tv_sec != 0 || timeout.tv_usec != 0;
   }
 
-  bool CanRead() const {
-    if (read_deadline.tv_sec == 0 && read_deadline.tv_usec == 0) {
-      return true;
-    }
-
-    if (clock->tv_sec == read_deadline.tv_sec) {
-      return clock->tv_usec < read_deadline.tv_usec;
-    }
-    return clock->tv_sec < read_deadline.tv_sec;
-  }
-
   timeval timeout;
   timeval *clock;
-  timeval read_deadline;
-  bool advance_clock;
 };
 
 PacketedBio *GetData(BIO *bio) {
@@ -123,109 +109,91 @@
 
   BIO_clear_retry_flags(bio);
 
-  for (;;) {
-    // Check if the read deadline has passed.
-    if (!data->CanRead()) {
-      BIO_set_retry_read(bio);
-      return -1;
-    }
-
-    // Read the opcode.
-    uint8_t opcode;
-    int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
-    if (ret <= 0) {
-      BIO_copy_next_retry(bio);
-      return ret;
-    }
-
-    if (opcode == kOpcodeTimeout) {
-      // The caller is required to advance any pending timeouts before
-      // continuing.
-      if (data->HasTimeout()) {
-        fprintf(stderr, "Unprocessed timeout!\n");
-        return -1;
-      }
-
-      // Process the timeout.
-      uint8_t buf[8];
-      ret = ReadAll(bio->next_bio, buf, sizeof(buf));
-      if (ret <= 0) {
-        BIO_copy_next_retry(bio);
-        return ret;
-      }
-      uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
-          (static_cast<uint64_t>(buf[1]) << 48) |
-          (static_cast<uint64_t>(buf[2]) << 40) |
-          (static_cast<uint64_t>(buf[3]) << 32) |
-          (static_cast<uint64_t>(buf[4]) << 24) |
-          (static_cast<uint64_t>(buf[5]) << 16) |
-          (static_cast<uint64_t>(buf[6]) << 8) |
-          static_cast<uint64_t>(buf[7]);
-      timeout /= 1000;  // Convert nanoseconds to microseconds.
-
-      data->timeout.tv_usec = timeout % 1000000;
-      data->timeout.tv_sec = timeout / 1000000;
-
-      // Send an ACK to the peer.
-      ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
-      if (ret <= 0) {
-        return ret;
-      }
-      assert(ret == 1);
-
-      if (!data->advance_clock) {
-        // Signal to the caller to retry the read, after advancing the clock.
-        BIO_set_retry_read(bio);
-        return -1;
-      }
-
-      PacketedBioAdvanceClock(bio);
-      continue;
-    }
-
-    if (opcode != kOpcodePacket) {
-      fprintf(stderr, "Unknown opcode, %u\n", opcode);
-      return -1;
-    }
-
-    // Read the length prefix.
-    uint8_t len_bytes[4];
-    ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
-    if (ret <= 0) {
-      BIO_copy_next_retry(bio);
-      return ret;
-    }
-
-    uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
-        (len_bytes[2] << 8) | len_bytes[3];
-    uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
-    if (buf == NULL) {
-      return -1;
-    }
-    ret = ReadAll(bio->next_bio, buf, len);
-    if (ret <= 0) {
-      fprintf(stderr, "Packeted BIO was truncated\n");
-      return -1;
-    }
-
-    if (outl > (int)len) {
-      outl = len;
-    }
-    OPENSSL_memcpy(out, buf, outl);
-    OPENSSL_free(buf);
-    return outl;
+  // Read the opcode.
+  uint8_t opcode;
+  int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
+  if (ret <= 0) {
+    BIO_copy_next_retry(bio);
+    return ret;
   }
+
+  if (opcode == kOpcodeTimeout) {
+    // The caller is required to advance any pending timeouts before continuing.
+    if (data->HasTimeout()) {
+      fprintf(stderr, "Unprocessed timeout!\n");
+      return -1;
+    }
+
+    // Process the timeout.
+    uint8_t buf[8];
+    ret = ReadAll(bio->next_bio, buf, sizeof(buf));
+    if (ret <= 0) {
+      BIO_copy_next_retry(bio);
+      return ret;
+    }
+    uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
+                       (static_cast<uint64_t>(buf[1]) << 48) |
+                       (static_cast<uint64_t>(buf[2]) << 40) |
+                       (static_cast<uint64_t>(buf[3]) << 32) |
+                       (static_cast<uint64_t>(buf[4]) << 24) |
+                       (static_cast<uint64_t>(buf[5]) << 16) |
+                       (static_cast<uint64_t>(buf[6]) << 8) |
+                       static_cast<uint64_t>(buf[7]);
+    timeout /= 1000;  // Convert nanoseconds to microseconds.
+
+    data->timeout.tv_usec = timeout % 1000000;
+    data->timeout.tv_sec = timeout / 1000000;
+
+    // Send an ACK to the peer.
+    ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
+    if (ret <= 0) {
+      return ret;
+    }
+    assert(ret == 1);
+
+    // Signal to the caller to retry the read, after advancing the clock.
+    BIO_set_retry_read(bio);
+    return -1;
+  }
+
+  if (opcode != kOpcodePacket) {
+    fprintf(stderr, "Unknown opcode, %u\n", opcode);
+    return -1;
+  }
+
+  // Read the length prefix.
+  uint8_t len_bytes[4];
+  ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
+  if (ret <= 0) {
+    BIO_copy_next_retry(bio);
+    return ret;
+  }
+
+  uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
+                 (len_bytes[2] << 8) | len_bytes[3];
+  uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
+  if (buf == NULL) {
+    return -1;
+  }
+  ret = ReadAll(bio->next_bio, buf, len);
+  if (ret <= 0) {
+    fprintf(stderr, "Packeted BIO was truncated\n");
+    return -1;
+  }
+
+  if (outl > (int)len) {
+    outl = len;
+  }
+  OPENSSL_memcpy(out, buf, outl);
+  OPENSSL_free(buf);
+  return outl;
 }
 
 static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) {
-  if (cmd == BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT) {
-    OPENSSL_memcpy(&GetData(bio)->read_deadline, ptr, sizeof(timeval));
-    return 1;
-  }
-
   if (bio->next_bio == NULL) {
     return 0;
   }
+
   BIO_clear_retry_flags(bio);
   int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
   BIO_copy_next_retry(bio);
@@ -269,12 +237,12 @@
 
 }  // namespace
 
-bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock) {
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock) {
   bssl::UniquePtr<BIO> bio(BIO_new(&g_packeted_bio_method));
   if (!bio) {
     return nullptr;
   }
-  bio->ptr = new PacketedBio(clock, advance_clock);
+  bio->ptr = new PacketedBio(clock);
   return bio;
 }
 
diff --git a/src/ssl/test/packeted_bio.h b/src/ssl/test/packeted_bio.h
index 9d4cdcb..7f07fcb 100644
--- a/src/ssl/test/packeted_bio.h
+++ b/src/ssl/test/packeted_bio.h
@@ -28,15 +28,12 @@
 
 
 // PacketedBioCreate creates a filter BIO which implements a reliable in-order
-// blocking datagram socket. It uses the value of |*clock| as the clock and
-// honors |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| based on it.
+// blocking datagram socket. It uses the value of |*clock| as the clock.
 //
 // During a |BIO_read|, the peer may signal the filter BIO to simulate a
-// timeout. If |advance_clock| is true, it automatically advances the clock and
-// continues reading, subject to the read deadline. Otherwise, it fails
-// immediately. The caller must then call |PacketedBioAdvanceClock| before
-// retrying |BIO_read|.
-bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock);
+// timeout. The operation will fail immediately. The caller must then call
+// |PacketedBioAdvanceClock| before retrying |BIO_read|.
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock);
 
 // PacketedBioAdvanceClock advances |bio|'s clock and returns true if there is a
 // pending timeout. Otherwise, it returns false.
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 2e7b053..d316ddd 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -100,7 +100,6 @@
 	extensionNextProtoNeg               uint16 = 13172 // not IANA assigned
 	extensionRenegotiationInfo          uint16 = 0xff01
 	extensionChannelID                  uint16 = 30032 // not IANA assigned
-	extensionShortHeader                uint16 = 27463 // not IANA assigned
 )
 
 // TLS signaling cipher suite values
@@ -223,7 +222,6 @@
 	SCTList                    []byte                // signed certificate timestamp list
 	PeerSignatureAlgorithm     signatureAlgorithm    // algorithm used by the peer in the handshake
 	CurveID                    CurveID               // the curve used in ECDHE
-	ShortHeader                bool                  // whether the short header extension was negotiated
 }
 
 // ClientAuthType declares the policy the server will follow for
@@ -1274,18 +1272,6 @@
 	// request signed certificate timestamps.
 	NoSignedCertificateTimestamps bool
 
-	// EnableShortHeader, if true, causes the TLS 1.3 short header extension
-	// to be enabled.
-	EnableShortHeader bool
-
-	// AlwaysNegotiateShortHeader, if true, causes the server to always
-	// negotiate the short header extension in ServerHello.
-	AlwaysNegotiateShortHeader bool
-
-	// ClearShortHeaderBit, if true, causes the server to send short headers
-	// without the high bit set.
-	ClearShortHeaderBit bool
-
 	// SendSupportedPointFormats, if not nil, is the list of supported point
 	// formats to send in ClientHello or ServerHello. If set to a non-nil
 	// empty slice, no extension will be sent.
@@ -1302,6 +1288,14 @@
 	// SendServerNameAck, if true, causes the server to acknowledge the SNI
 	// extension.
 	SendServerNameAck bool
+
+	// ExpectCertificateReqNames, if not nil, contains the list of X.509
+	// names that must be sent in a CertificateRequest from the server.
+	ExpectCertificateReqNames [][]byte
+
+	// RenegotiationCertificate, if not nil, is the certificate to use on
+	// renegotiation handshakes.
+	RenegotiationCertificate *Certificate
 }
 
 func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index a4cb573..1bdca84 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -167,8 +167,6 @@
 
 	trafficSecret []byte
 
-	shortHeader bool
-
 	config *Config
 }
 
@@ -315,17 +313,10 @@
 	copy(hc.outSeq[:], hc.seq[:])
 }
 
-func (hc *halfConn) isShortHeader() bool {
-	return hc.shortHeader && hc.cipher != nil
-}
-
 func (hc *halfConn) recordHeaderLen() int {
 	if hc.isDTLS {
 		return dtlsRecordHeaderLen
 	}
-	if hc.isShortHeader() {
-		return 2
-	}
 	return tlsRecordHeaderLen
 }
 
@@ -629,9 +620,6 @@
 	n := len(b.data) - recordHeaderLen
 	b.data[recordHeaderLen-2] = byte(n >> 8)
 	b.data[recordHeaderLen-1] = byte(n)
-	if hc.isShortHeader() && !hc.config.Bugs.ClearShortHeaderBit {
-		b.data[0] |= 0x80
-	}
 	hc.incSeq(true)
 
 	return true, 0
@@ -762,35 +750,20 @@
 		return 0, nil, err
 	}
 
-	var typ recordType
-	var vers uint16
-	var n int
-	if c.in.isShortHeader() {
-		typ = recordTypeApplicationData
-		vers = VersionTLS10
-		n = int(b.data[0])<<8 | int(b.data[1])
-		if n&0x8000 == 0 {
-			c.sendAlert(alertDecodeError)
-			return 0, nil, c.in.setErrorLocked(errors.New("tls: length did not have high bit set"))
-		}
+	typ := recordType(b.data[0])
 
-		n = n & 0x7fff
-	} else {
-		typ = recordType(b.data[0])
-
-		// No valid TLS record has a type of 0x80, however SSLv2 handshakes
-		// start with a uint16 length where the MSB is set and the first record
-		// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
-		// an SSLv2 client.
-		if want == recordTypeHandshake && typ == 0x80 {
-			c.sendAlert(alertProtocolVersion)
-			return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
-		}
-
-		vers = uint16(b.data[1])<<8 | uint16(b.data[2])
-		n = int(b.data[3])<<8 | int(b.data[4])
+	// No valid TLS record has a type of 0x80, however SSLv2 handshakes
+	// start with a uint16 length where the MSB is set and the first record
+	// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+	// an SSLv2 client.
+	if want == recordTypeHandshake && typ == 0x80 {
+		c.sendAlert(alertProtocolVersion)
+		return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
 	}
 
+	vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+	n := int(b.data[3])<<8 | int(b.data[4])
+
 	// Alerts sent near version negotiation do not have a well-defined
 	// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
 	// version is irrelevant.)
@@ -1118,36 +1091,32 @@
 			}
 		}
 		b.resize(recordHeaderLen + explicitIVLen + m)
-		// If using a short record header, the length will be filled in
-		// by encrypt.
-		if !c.out.isShortHeader() {
-			b.data[0] = byte(typ)
-			if c.vers >= VersionTLS13 && c.out.cipher != nil {
-				b.data[0] = byte(recordTypeApplicationData)
-				if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
-					b.data[0] = byte(outerType)
-				}
+		b.data[0] = byte(typ)
+		if c.vers >= VersionTLS13 && c.out.cipher != nil {
+			b.data[0] = byte(recordTypeApplicationData)
+			if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
+				b.data[0] = byte(outerType)
 			}
-			vers := c.vers
-			if vers == 0 || vers >= VersionTLS13 {
-				// Some TLS servers fail if the record version is
-				// greater than TLS 1.0 for the initial ClientHello.
-				//
-				// TLS 1.3 fixes the version number in the record
-				// layer to {3, 1}.
-				vers = VersionTLS10
-			}
-			if c.config.Bugs.SendRecordVersion != 0 {
-				vers = c.config.Bugs.SendRecordVersion
-			}
-			if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
-				vers = c.config.Bugs.SendInitialRecordVersion
-			}
-			b.data[1] = byte(vers >> 8)
-			b.data[2] = byte(vers)
-			b.data[3] = byte(m >> 8)
-			b.data[4] = byte(m)
 		}
+		vers := c.vers
+		if vers == 0 || vers >= VersionTLS13 {
+			// Some TLS servers fail if the record version is
+			// greater than TLS 1.0 for the initial ClientHello.
+			//
+			// TLS 1.3 fixes the version number in the record
+			// layer to {3, 1}.
+			vers = VersionTLS10
+		}
+		if c.config.Bugs.SendRecordVersion != 0 {
+			vers = c.config.Bugs.SendRecordVersion
+		}
+		if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
+			vers = c.config.Bugs.SendInitialRecordVersion
+		}
+		b.data[1] = byte(vers >> 8)
+		b.data[2] = byte(vers)
+		b.data[3] = byte(m >> 8)
+		b.data[4] = byte(m)
 		if explicitIVLen > 0 {
 			explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
 			if explicitIVIsSeq {
@@ -1705,7 +1674,6 @@
 		state.SCTList = c.sctList
 		state.PeerSignatureAlgorithm = c.peerSignatureAlgorithm
 		state.CurveID = c.curveID
-		state.ShortHeader = c.in.shortHeader
 	}
 
 	return state
@@ -1873,8 +1841,3 @@
 	_, err := c.conn.Write(payload)
 	return err
 }
-
-func (c *Conn) setShortHeader() {
-	c.in.shortHeader = true
-	c.out.shortHeader = true
-}
diff --git a/src/ssl/test/runner/ecdsa_p224_cert.pem b/src/ssl/test/runner/ecdsa_p224_cert.pem
new file mode 100644
index 0000000..29246a2
--- /dev/null
+++ b/src/ssl/test/runner/ecdsa_p224_cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBvjCCAWygAwIBAgIJAPlkrPTq4HgnMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
+AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
+aXRzIFB0eSBMdGQwHhcNMTcwMjI3MjAxOTIzWhcNMTkwMjI3MjAxOTIzWjBFMQsw
+CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
+ZXQgV2lkZ2l0cyBQdHkgTHRkME4wEAYHKoZIzj0CAQYFK4EEACEDOgAE6dul6dL0
++CyooFiKK4V+EYNYPbMZoLTxRcjRgrw3db6QzBAviDSxKADTVuyRmaVC74Mf6boB
+HDmjUDBOMB0GA1UdDgQWBBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAfBgNVHSMEGDAW
+gBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMC
+A0AAMD0CHHolWPktSLbVMy9ukQUb2E7+Jb3hcNFqAXh47pYCHQC+jv2EE6oOEZ9F
+tLkFLtap71+83P0NUEJX4Etu
+-----END CERTIFICATE-----
diff --git a/src/ssl/test/runner/ecdsa_p224_key.pem b/src/ssl/test/runner/ecdsa_p224_key.pem
new file mode 100644
index 0000000..cfe411b
--- /dev/null
+++ b/src/ssl/test/runner/ecdsa_p224_key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MGgCAQEEHGi+rNLi+gHJqmRRtdlLBOw1WYv7H/VnlYGAZ0+gBwYFK4EEACGhPAM6
+AATp26Xp0vT4LKigWIorhX4Rg1g9sxmgtPFFyNGCvDd1vpDMEC+INLEoANNW7JGZ
+pULvgx/pugEcOQ==
+-----END EC PRIVATE KEY-----
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 162302e..eb072ad 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -81,7 +81,6 @@
 		srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
 		customExtension:         c.config.Bugs.CustomExtension,
 		pskBinderFirst:          c.config.Bugs.PSKBinderFirst,
-		shortHeaderSupported:    c.config.Bugs.EnableShortHeader,
 	}
 
 	disableEMS := c.config.Bugs.NoExtendedMasterSecret
@@ -717,18 +716,6 @@
 		hs.finishedHash.addEntropy(zeroSecret)
 	}
 
-	if hs.serverHello.shortHeader && !hs.hello.shortHeaderSupported {
-		return errors.New("tls: server sent unsolicited short header extension")
-	}
-
-	if hs.serverHello.shortHeader && hs.hello.hasEarlyData {
-		return errors.New("tls: server sent short header extension in response to early data")
-	}
-
-	if hs.serverHello.shortHeader {
-		c.setShortHeader()
-	}
-
 	// Derive handshake traffic keys and switch read key to handshake
 	// traffic key.
 	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
@@ -1363,10 +1350,6 @@
 func (hs *clientHandshakeState) processServerHello() (bool, error) {
 	c := hs.c
 
-	if hs.serverHello.shortHeader {
-		return false, errors.New("tls: short header extension sent before TLS 1.3")
-	}
-
 	if hs.serverResumedSession() {
 		// For test purposes, assert that the server never accepts the
 		// resumption offer on renegotiation.
@@ -1682,18 +1665,13 @@
 				}
 			}
 
-			if len(certReq.certificateAuthorities) == 0 {
-				// They gave us an empty list, so just take the
-				// first certificate of valid type from
-				// c.config.Certificates.
-				return &chain, nil
-			}
-
-			for _, ca := range certReq.certificateAuthorities {
-				if bytes.Equal(x509Cert.RawIssuer, ca) {
-					return &chain, nil
+			if expected := c.config.Bugs.ExpectCertificateReqNames; expected != nil {
+				if !eqByteSlices(expected, certReq.certificateAuthorities) {
+					return nil, fmt.Errorf("tls: CertificateRequest names differed, got %#v but expected %#v", certReq.certificateAuthorities, expected)
 				}
 			}
+
+			return &chain, nil
 		}
 	}
 
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 4ecb3cb..86e2821 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -167,7 +167,6 @@
 	customExtension         string
 	hasGREASEExtension      bool
 	pskBinderFirst          bool
-	shortHeaderSupported    bool
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -213,8 +212,7 @@
 		m.sctListSupported == m1.sctListSupported &&
 		m.customExtension == m1.customExtension &&
 		m.hasGREASEExtension == m1.hasGREASEExtension &&
-		m.pskBinderFirst == m1.pskBinderFirst &&
-		m.shortHeaderSupported == m1.shortHeaderSupported
+		m.pskBinderFirst == m1.pskBinderFirst
 }
 
 func (m *clientHelloMsg) marshal() []byte {
@@ -430,10 +428,6 @@
 		customExt := extensions.addU16LengthPrefixed()
 		customExt.addBytes([]byte(m.customExtension))
 	}
-	if m.shortHeaderSupported {
-		extensions.addU16(extensionShortHeader)
-		extensions.addU16(0) // Length is always 0
-	}
 	// The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
 	if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
 		extensions.addU16(extensionPreSharedKey)
@@ -805,11 +799,6 @@
 				return false
 			}
 			m.sctListSupported = true
-		case extensionShortHeader:
-			if length != 0 {
-				return false
-			}
-			m.shortHeaderSupported = true
 		case extensionCustom:
 			m.customExtension = string(data[:length])
 		}
@@ -838,7 +827,6 @@
 	compressionMethod uint8
 	customExtension   string
 	unencryptedALPN   string
-	shortHeader       bool
 	extensions        serverExtensions
 }
 
@@ -876,11 +864,6 @@
 
 	extensions := hello.addU16LengthPrefixed()
 
-	if m.shortHeader {
-		extensions.addU16(extensionShortHeader)
-		extensions.addU16(0) // Length
-	}
-
 	if vers >= VersionTLS13 {
 		if m.hasKeyShare {
 			extensions.addU16(extensionKeyShare)
@@ -1000,11 +983,6 @@
 				}
 				m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
 				m.hasPSKIdentity = true
-			case extensionShortHeader:
-				if len(d) != 0 {
-					return false
-				}
-				m.shortHeader = true
 			default:
 				// Only allow the 3 extensions that are sent in
 				// the clear in TLS 1.3.
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 8aa1587..9b4bff8 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -365,15 +365,6 @@
 		versOverride:    config.Bugs.SendServerHelloVersion,
 		customExtension: config.Bugs.CustomUnencryptedExtension,
 		unencryptedALPN: config.Bugs.SendUnencryptedALPN,
-		shortHeader:     hs.clientHello.shortHeaderSupported && config.Bugs.EnableShortHeader,
-	}
-
-	if config.Bugs.AlwaysNegotiateShortHeader {
-		hs.hello.shortHeader = true
-	}
-
-	if hs.hello.shortHeader {
-		c.setShortHeader()
 	}
 
 	hs.hello.random = make([]byte, 32)
@@ -1025,7 +1016,6 @@
 		vers:              versionToWire(c.vers, c.isDTLS),
 		versOverride:      config.Bugs.SendServerHelloVersion,
 		compressionMethod: compressionNone,
-		shortHeader:       config.Bugs.AlwaysNegotiateShortHeader,
 	}
 
 	hs.hello.random = make([]byte, 32)
@@ -1165,6 +1155,10 @@
 		return errors.New("tls: unexpected server name")
 	}
 
+	if cert := config.Bugs.RenegotiationCertificate; c.cipherSuite != nil && cert != nil {
+		hs.cert = cert
+	}
+
 	if len(hs.clientHello.alpnProtocols) > 0 {
 		if proto := c.config.Bugs.ALPNProtocol; proto != nil {
 			serverExtensions.alpnProtocol = *proto
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index d7bad5b..55685b0 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -22,6 +22,7 @@
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"encoding/base64"
+	"encoding/hex"
 	"encoding/json"
 	"encoding/pem"
 	"errors"
@@ -91,6 +92,7 @@
 	testCertRSA testCert = iota
 	testCertRSA1024
 	testCertRSAChain
+	testCertECDSAP224
 	testCertECDSAP256
 	testCertECDSAP384
 	testCertECDSAP521
@@ -100,6 +102,7 @@
 	rsaCertificateFile       = "cert.pem"
 	rsa1024CertificateFile   = "rsa_1024_cert.pem"
 	rsaChainCertificateFile  = "rsa_chain_cert.pem"
+	ecdsaP224CertificateFile = "ecdsa_p224_cert.pem"
 	ecdsaP256CertificateFile = "ecdsa_p256_cert.pem"
 	ecdsaP384CertificateFile = "ecdsa_p384_cert.pem"
 	ecdsaP521CertificateFile = "ecdsa_p521_cert.pem"
@@ -109,6 +112,7 @@
 	rsaKeyFile       = "key.pem"
 	rsa1024KeyFile   = "rsa_1024_key.pem"
 	rsaChainKeyFile  = "rsa_chain_key.pem"
+	ecdsaP224KeyFile = "ecdsa_p224_key.pem"
 	ecdsaP256KeyFile = "ecdsa_p256_key.pem"
 	ecdsaP384KeyFile = "ecdsa_p384_key.pem"
 	ecdsaP521KeyFile = "ecdsa_p521_key.pem"
@@ -119,6 +123,7 @@
 	rsaCertificate       Certificate
 	rsa1024Certificate   Certificate
 	rsaChainCertificate  Certificate
+	ecdsaP224Certificate Certificate
 	ecdsaP256Certificate Certificate
 	ecdsaP384Certificate Certificate
 	ecdsaP521Certificate Certificate
@@ -148,6 +153,12 @@
 		cert:     &rsaChainCertificate,
 	},
 	{
+		id:       testCertECDSAP224,
+		certFile: ecdsaP224CertificateFile,
+		keyFile:  ecdsaP224KeyFile,
+		cert:     &ecdsaP224Certificate,
+	},
+	{
 		id:       testCertECDSAP256,
 		certFile: ecdsaP256CertificateFile,
 		keyFile:  ecdsaP256KeyFile,
@@ -235,6 +246,19 @@
 	panic("Unknown test certificate")
 }
 
+// encodeDERValues encodes a series of bytestrings in comma-separated-hex form.
+func encodeDERValues(values [][]byte) string {
+	var ret string
+	for i, v := range values {
+		if i > 0 {
+			ret += ","
+		}
+		ret += hex.EncodeToString(v)
+	}
+
+	return ret
+}
+
 type testType int
 
 const (
@@ -383,8 +407,6 @@
 	// expectPeerCertificate, if not nil, is the certificate chain the peer
 	// is expected to send.
 	expectPeerCertificate *Certificate
-	// expectShortHeader is whether the short header extension should be negotiated.
-	expectShortHeader bool
 }
 
 var testCases []testCase
@@ -613,10 +635,6 @@
 		}
 	}
 
-	if test.expectShortHeader != connState.ShortHeader {
-		return fmt.Errorf("ShortHeader is %t, but we expected the opposite", connState.ShortHeader)
-	}
-
 	if test.exportKeyingMaterial > 0 {
 		actual := make([]byte, test.exportKeyingMaterial)
 		if _, err := io.ReadFull(tlsConn, actual); err != nil {
@@ -2662,27 +2680,6 @@
 		shouldFail:       shouldFail,
 		expectedError:    expectedError,
 	})
-
-	if ver.version >= VersionTLS13 {
-		testCases = append(testCases, testCase{
-			protocol: protocol,
-			name:     prefix + ver.name + "-" + suite.name + "-ShortHeader",
-			config: Config{
-				MinVersion:           ver.version,
-				MaxVersion:           ver.version,
-				CipherSuites:         []uint16{suite.id},
-				Certificates:         []Certificate{cert},
-				PreSharedKey:         []byte(psk),
-				PreSharedKeyIdentity: pskIdentity,
-				Bugs: ProtocolBugs{
-					EnableShortHeader: true,
-				},
-			},
-			flags:             append([]string{"-enable-short-header"}, flags...),
-			resumeSession:     true,
-			expectShortHeader: true,
-		})
-	}
 }
 
 func addCipherSuiteTests() {
@@ -2965,13 +2962,15 @@
 
 func addClientAuthTests() {
 	// Add a dummy cert pool to stress certificate authority parsing.
-	// TODO(davidben): Add tests that those values parse out correctly.
 	certPool := x509.NewCertPool()
-	cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
-	if err != nil {
-		panic(err)
+	for _, cert := range []Certificate{rsaCertificate, rsa1024Certificate} {
+		cert, err := x509.ParseCertificate(cert.Certificate[0])
+		if err != nil {
+			panic(err)
+		}
+		certPool.AddCert(cert)
 	}
-	certPool.AddCert(cert)
+	caNames := certPool.Subjects()
 
 	for _, ver := range tlsVersions {
 		testCases = append(testCases, testCase{
@@ -3103,6 +3102,40 @@
 				expectedError: ":UNEXPECTED_MESSAGE:",
 			})
 		}
+
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     ver.name + "-Server-CertReq-CA-List",
+			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{rsaCertificate},
+				Bugs: ProtocolBugs{
+					ExpectCertificateReqNames: caNames,
+				},
+			},
+			flags: []string{
+				"-require-any-client-certificate",
+				"-use-client-ca-list", encodeDERValues(caNames),
+			},
+		})
+
+		testCases = append(testCases, testCase{
+			testType: clientTest,
+			name:     ver.name + "-Client-CertReq-CA-List",
+			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{rsaCertificate},
+				ClientAuth:   RequireAnyClientCert,
+				ClientCAs:    certPool,
+			},
+			flags: []string{
+				"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+				"-key-file", path.Join(*resourceDir, rsaKeyFile),
+				"-expect-client-ca-list", encodeDERValues(caNames),
+			},
+		})
 	}
 
 	// Client auth is only legal in certificate-based ciphers.
@@ -3149,10 +3182,13 @@
 		config: Config{
 			MaxVersion:   VersionTLS12,
 			Certificates: []Certificate{rsaCertificate},
+			Bugs: ProtocolBugs{
+				ExpectCertificateReqNames: [][]byte{},
+			},
 		},
 		flags: []string{
 			"-require-any-client-certificate",
-			"-use-null-client-ca-list",
+			"-use-client-ca-list", "<NULL>",
 		},
 	})
 }
@@ -6482,6 +6518,36 @@
 			"-expect-secure-renegotiation",
 		},
 	})
+
+	// Certificates may not change on renegotiation.
+	testCases = append(testCases, testCase{
+		name: "Renegotiation-CertificateChange",
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			Certificates: []Certificate{rsaCertificate},
+			Bugs: ProtocolBugs{
+				RenegotiationCertificate: &rsaChainCertificate,
+			},
+		},
+		renegotiate:   1,
+		flags:         []string{"-renegotiate-freely"},
+		shouldFail:    true,
+		expectedError: ":SERVER_CERT_CHANGED:",
+	})
+	testCases = append(testCases, testCase{
+		name: "Renegotiation-CertificateChange-2",
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			Certificates: []Certificate{rsaCertificate},
+			Bugs: ProtocolBugs{
+				RenegotiationCertificate: &rsa1024Certificate,
+			},
+		},
+		renegotiate:   1,
+		flags:         []string{"-renegotiate-freely"},
+		shouldFail:    true,
+		expectedError: ":SERVER_CERT_CHANGED:",
+	})
 }
 
 func addDTLSReplayTests() {
@@ -7354,6 +7420,31 @@
 		},
 		flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
 	})
+
+	// A server certificate with a P-224 key will only work up to TLS 1.2
+	// and we only test it with BoringSSL acting as a server because that's
+	// all Alphabet requires with it.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "P224-Server",
+		config: Config{
+			VerifySignatureAlgorithms: []signatureAlgorithm{
+				// TLS 1.2 does not require that the curve
+				// match the hash, thus P-256 with SHA-256 is
+				// the same signature algorithm value as P-224
+				// with SHA-256.
+				signatureECDSAWithP256AndSHA256,
+			},
+			// P-256 must be offered as well because ECDHE requires
+			// it.
+			CurvePreferences: []CurveID{CurveP224, CurveP256},
+		},
+		flags: []string{
+			"-max-version", strconv.Itoa(VersionTLS12),
+			"-cert-file", path.Join(*resourceDir, ecdsaP224CertificateFile),
+			"-key-file", path.Join(*resourceDir, ecdsaP224KeyFile),
+		},
+	})
 }
 
 // timeouts is the retransmit schedule for BoringSSL. It doubles and
@@ -7418,123 +7509,119 @@
 	// likely be more epochs to cross and the final message's retransmit may
 	// be more complex.
 
-	for _, async := range []bool{true, false} {
-		var tests []testCase
-
-		// Test that this is indeed the timeout schedule. Stress all
-		// four patterns of handshake.
-		for i := 1; i < len(timeouts); i++ {
-			number := strconv.Itoa(i)
-			tests = append(tests, testCase{
-				protocol: dtls,
-				name:     "DTLS-Retransmit-Client-" + number,
-				config: Config{
-					MaxVersion: VersionTLS12,
-					Bugs: ProtocolBugs{
-						TimeoutSchedule: timeouts[:i],
-					},
-				},
-				resumeSession: true,
-			})
-			tests = append(tests, testCase{
-				protocol: dtls,
-				testType: serverTest,
-				name:     "DTLS-Retransmit-Server-" + number,
-				config: Config{
-					MaxVersion: VersionTLS12,
-					Bugs: ProtocolBugs{
-						TimeoutSchedule: timeouts[:i],
-					},
-				},
-				resumeSession: true,
-			})
-		}
-
-		// Test that exceeding the timeout schedule hits a read
-		// timeout.
-		tests = append(tests, testCase{
+	// Test that this is indeed the timeout schedule. Stress all
+	// four patterns of handshake.
+	for i := 1; i < len(timeouts); i++ {
+		number := strconv.Itoa(i)
+		testCases = append(testCases, testCase{
 			protocol: dtls,
-			name:     "DTLS-Retransmit-Timeout",
+			name:     "DTLS-Retransmit-Client-" + number,
 			config: Config{
 				MaxVersion: VersionTLS12,
 				Bugs: ProtocolBugs{
-					TimeoutSchedule: timeouts,
+					TimeoutSchedule: timeouts[:i],
 				},
 			},
 			resumeSession: true,
-			shouldFail:    true,
-			expectedError: ":READ_TIMEOUT_EXPIRED:",
+			flags:         []string{"-async"},
 		})
-
-		if async {
-			// Test that timeout handling has a fudge factor, due to API
-			// problems.
-			tests = append(tests, testCase{
-				protocol: dtls,
-				name:     "DTLS-Retransmit-Fudge",
-				config: Config{
-					MaxVersion: VersionTLS12,
-					Bugs: ProtocolBugs{
-						TimeoutSchedule: []time.Duration{
-							timeouts[0] - 10*time.Millisecond,
-						},
-					},
-				},
-				resumeSession: true,
-			})
-		}
-
-		// Test that the final Finished retransmitting isn't
-		// duplicated if the peer badly fragments everything.
-		tests = append(tests, testCase{
-			testType: serverTest,
-			protocol: dtls,
-			name:     "DTLS-Retransmit-Fragmented",
-			config: Config{
-				MaxVersion: VersionTLS12,
-				Bugs: ProtocolBugs{
-					TimeoutSchedule:          []time.Duration{timeouts[0]},
-					MaxHandshakeRecordLength: 2,
-				},
-			},
-		})
-
-		// Test the timeout schedule when a shorter initial timeout duration is set.
-		tests = append(tests, testCase{
-			protocol: dtls,
-			name:     "DTLS-Retransmit-Short-Client",
-			config: Config{
-				MaxVersion: VersionTLS12,
-				Bugs: ProtocolBugs{
-					TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
-				},
-			},
-			resumeSession: true,
-			flags:         []string{"-initial-timeout-duration-ms", "250"},
-		})
-		tests = append(tests, testCase{
+		testCases = append(testCases, testCase{
 			protocol: dtls,
 			testType: serverTest,
-			name:     "DTLS-Retransmit-Short-Server",
+			name:     "DTLS-Retransmit-Server-" + number,
 			config: Config{
 				MaxVersion: VersionTLS12,
 				Bugs: ProtocolBugs{
-					TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+					TimeoutSchedule: timeouts[:i],
 				},
 			},
 			resumeSession: true,
-			flags:         []string{"-initial-timeout-duration-ms", "250"},
+			flags:         []string{"-async"},
 		})
-
-		for _, test := range tests {
-			if async {
-				test.name += "-Async"
-				test.flags = append(test.flags, "-async")
-			}
-
-			testCases = append(testCases, test)
-		}
 	}
+
+	// Test that exceeding the timeout schedule hits a read
+	// timeout.
+	testCases = append(testCases, testCase{
+		protocol: dtls,
+		name:     "DTLS-Retransmit-Timeout",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				TimeoutSchedule: timeouts,
+			},
+		},
+		resumeSession: true,
+		flags:         []string{"-async"},
+		shouldFail:    true,
+		expectedError: ":READ_TIMEOUT_EXPIRED:",
+	})
+
+	// Test that timeout handling has a fudge factor, due to API
+	// problems.
+	testCases = append(testCases, testCase{
+		protocol: dtls,
+		name:     "DTLS-Retransmit-Fudge",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				TimeoutSchedule: []time.Duration{
+					timeouts[0] - 10*time.Millisecond,
+				},
+			},
+		},
+		resumeSession: true,
+		flags:         []string{"-async"},
+	})
+
+	// Test that the final Finished retransmitting isn't
+	// duplicated if the peer badly fragments everything.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		protocol: dtls,
+		name:     "DTLS-Retransmit-Fragmented",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				TimeoutSchedule:          []time.Duration{timeouts[0]},
+				MaxHandshakeRecordLength: 2,
+			},
+		},
+		flags: []string{"-async"},
+	})
+
+	// Test the timeout schedule when a shorter initial timeout duration is set.
+	testCases = append(testCases, testCase{
+		protocol: dtls,
+		name:     "DTLS-Retransmit-Short-Client",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+			},
+		},
+		resumeSession: true,
+		flags: []string{
+			"-async",
+			"-initial-timeout-duration-ms", "250",
+		},
+	})
+	testCases = append(testCases, testCase{
+		protocol: dtls,
+		testType: serverTest,
+		name:     "DTLS-Retransmit-Short-Server",
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+			},
+		},
+		resumeSession: true,
+		flags: []string{
+			"-async",
+			"-initial-timeout-duration-ms", "250",
+		},
+	})
 }
 
 func addExportKeyingMaterialTests() {
@@ -10130,150 +10217,6 @@
 	}
 }
 
-func addShortHeaderTests() {
-	// The short header extension may be negotiated as either client or
-	// server.
-	testCases = append(testCases, testCase{
-		name: "ShortHeader-Client",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				EnableShortHeader: true,
-			},
-		},
-		flags:             []string{"-enable-short-header"},
-		expectShortHeader: true,
-	})
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "ShortHeader-Server",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				EnableShortHeader: true,
-			},
-		},
-		flags:             []string{"-enable-short-header"},
-		expectShortHeader: true,
-	})
-
-	// If the peer doesn't support it, it will not be negotiated.
-	testCases = append(testCases, testCase{
-		name: "ShortHeader-No-Yes-Client",
-		config: Config{
-			MaxVersion: VersionTLS13,
-		},
-		flags: []string{"-enable-short-header"},
-	})
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "ShortHeader-No-Yes-Server",
-		config: Config{
-			MaxVersion: VersionTLS13,
-		},
-		flags: []string{"-enable-short-header"},
-	})
-
-	// If we don't support it, it will not be negotiated.
-	testCases = append(testCases, testCase{
-		name: "ShortHeader-Yes-No-Client",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				EnableShortHeader: true,
-			},
-		},
-	})
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "ShortHeader-Yes-No-Server",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				EnableShortHeader: true,
-			},
-		},
-	})
-
-	// It will not be negotiated at TLS 1.2.
-	testCases = append(testCases, testCase{
-		name: "ShortHeader-TLS12-Client",
-		config: Config{
-			MaxVersion: VersionTLS12,
-			Bugs: ProtocolBugs{
-				EnableShortHeader: true,
-			},
-		},
-		flags: []string{"-enable-short-header"},
-	})
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "ShortHeader-TLS12-Server",
-		config: Config{
-			MaxVersion: VersionTLS12,
-			Bugs: ProtocolBugs{
-				EnableShortHeader: true,
-			},
-		},
-		flags: []string{"-enable-short-header"},
-	})
-
-	// Servers reject early data and short header sent together.
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "ShortHeader-EarlyData",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				EnableShortHeader:       true,
-				SendFakeEarlyDataLength: 1,
-			},
-		},
-		flags:         []string{"-enable-short-header"},
-		shouldFail:    true,
-		expectedError: ":UNEXPECTED_EXTENSION:",
-	})
-
-	// Clients reject unsolicited short header extensions.
-	testCases = append(testCases, testCase{
-		name: "ShortHeader-Unsolicited",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				AlwaysNegotiateShortHeader: true,
-			},
-		},
-		shouldFail:    true,
-		expectedError: ":UNEXPECTED_EXTENSION:",
-	})
-	testCases = append(testCases, testCase{
-		name: "ShortHeader-Unsolicited-TLS12",
-		config: Config{
-			MaxVersion: VersionTLS12,
-			Bugs: ProtocolBugs{
-				AlwaysNegotiateShortHeader: true,
-			},
-		},
-		shouldFail:    true,
-		expectedError: ":UNEXPECTED_EXTENSION:",
-	})
-
-	// The high bit must be checked in short headers.
-	testCases = append(testCases, testCase{
-		name: "ShortHeader-ClearShortHeaderBit",
-		config: Config{
-			Bugs: ProtocolBugs{
-				EnableShortHeader:   true,
-				ClearShortHeaderBit: true,
-			},
-		},
-		flags:              []string{"-enable-short-header"},
-		shouldFail:         true,
-		expectedError:      ":DECODE_ERROR:",
-		expectedLocalError: "remote error: error decoding message",
-	})
-}
-
 func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -10400,7 +10343,6 @@
 	addCertificateTests()
 	addRetainOnlySHA256ClientCertTests()
 	addECDSAKeyUsageTests()
-	addShortHeaderTests()
 
 	var wg sync.WaitGroup
 
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index b729f69..fefe376 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -104,7 +104,6 @@
   { "-use-sparse-dh-prime", &TestConfig::use_sparse_dh_prime },
   { "-use-old-client-cert-callback",
     &TestConfig::use_old_client_cert_callback },
-  { "-use-null-client-ca-list", &TestConfig::use_null_client_ca_list },
   { "-send-alert", &TestConfig::send_alert },
   { "-peek-then-read", &TestConfig::peek_then_read },
   { "-enable-grease", &TestConfig::enable_grease },
@@ -117,7 +116,6 @@
     &TestConfig::expect_sha256_client_cert_initial },
   { "-expect-sha256-client-cert-resume",
     &TestConfig::expect_sha256_client_cert_resume },
-  { "-enable-short-header", &TestConfig::enable_short_header },
   { "-read-with-unfinished-write", &TestConfig::read_with_unfinished_write },
   { "-expect-secure-renegotiation",
     &TestConfig::expect_secure_renegotiation },
@@ -148,6 +146,8 @@
   { "-export-label", &TestConfig::export_label },
   { "-export-context", &TestConfig::export_context },
   { "-expect-peer-cert-file", &TestConfig::expect_peer_cert_file },
+  { "-use-client-ca-list", &TestConfig::use_client_ca_list },
+  { "-expect-client-ca-list", &TestConfig::expected_client_ca_list },
 };
 
 const Flag<std::string> kBase64Flags[] = {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 7122856..ee3d462 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -110,7 +110,8 @@
   int expect_resume_curve_id = 0;
   bool use_old_client_cert_callback = false;
   int initial_timeout_duration_ms = 0;
-  bool use_null_client_ca_list = false;
+  std::string use_client_ca_list;
+  std::string expected_client_ca_list;
   bool send_alert = false;
   bool peek_then_read = false;
   bool enable_grease = false;
@@ -125,7 +126,6 @@
   bool retain_only_sha256_client_cert_resume = false;
   bool expect_sha256_client_cert_initial = false;
   bool expect_sha256_client_cert_resume = false;
-  bool enable_short_header = false;
   bool read_with_unfinished_write = false;
   bool expect_secure_renegotiation = false;
   bool expect_no_secure_renegotiation = false;
diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c
index 91cae9a..5bd58eb 100644
--- a/src/ssl/tls13_both.c
+++ b/src/ssl/tls13_both.c
@@ -330,8 +330,8 @@
 
   hs->new_session->peer_sha256_valid = retain_sha256;
 
-  if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result,
-                             hs->new_session->x509_chain)) {
+  if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session,
+                                                        ssl)) {
     goto err;
   }
 
diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c
index 8e994e5..c0eb135 100644
--- a/src/ssl/tls13_client.c
+++ b/src/ssl/tls13_client.c
@@ -199,12 +199,11 @@
   }
 
   /* Parse out the extensions. */
-  int have_key_share = 0, have_pre_shared_key = 0, have_short_header = 0;
-  CBS key_share, pre_shared_key, short_header;
+  int have_key_share = 0, have_pre_shared_key = 0;
+  CBS key_share, pre_shared_key;
   const SSL_EXTENSION_TYPE ext_types[] = {
       {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
       {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
-      {TLSEXT_TYPE_short_header, &have_short_header, &short_header},
   };
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
@@ -318,23 +317,6 @@
   }
   OPENSSL_free(dhe_secret);
 
-  /* Negotiate short record headers. */
-  if (have_short_header) {
-    if (CBS_len(&short_header) != 0) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-      return ssl_hs_error;
-    }
-
-    if (!ssl->ctx->short_header_enabled) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
-      return ssl_hs_error;
-    }
-
-    ssl->s3->short_header = 1;
-  }
-
   if (!ssl_hash_current_message(hs) ||
       !tls13_derive_handshake_secrets(hs) ||
       !tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
@@ -402,8 +384,9 @@
   }
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
-  STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs);
-  if (ca_sk == NULL) {
+  STACK_OF(CRYPTO_BUFFER) *ca_names =
+      ssl_parse_client_CA_list(ssl, &alert, &cbs);
+  if (ca_names == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
   }
@@ -413,14 +396,15 @@
   if (!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
       CBS_len(&cbs) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+    sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return ssl_hs_error;
   }
 
   hs->cert_request = 1;
-  sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
-  hs->ca_names = ca_sk;
+  sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+  hs->ca_names = ca_names;
+  ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
 
   if (!ssl_hash_current_message(hs)) {
     return ssl_hs_error;
@@ -493,7 +477,7 @@
     }
   }
 
-  if (!ssl_auto_chain_if_needed(ssl) ||
+  if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl) ||
       !tls13_add_certificate(hs)) {
     return ssl_hs_error;
   }
@@ -648,18 +632,9 @@
   }
 
   /* Cap the renewable lifetime by the server advertised value. This avoids
-   * wasting bandwidth on 0-RTT when we know the server will reject it.
-   *
-   * TODO(davidben): This dance where we're not sure if long or uint32_t is
-   * bigger is silly. session->timeout should not be a long to begin with.
-   * https://crbug.com/boringssl/155. */
-#if LONG_MAX < 0xffffffff
-  if (server_timeout > LONG_MAX) {
-    server_timeout = LONG_MAX;
-  }
-#endif
-  if (session->timeout > (long)server_timeout) {
-    session->timeout = (long)server_timeout;
+   * wasting bandwidth on 0-RTT when we know the server will reject it. */
+  if (session->timeout > server_timeout) {
+    session->timeout = server_timeout;
   }
 
   /* Parse out the extensions. */
diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c
index 402c234..e7cc296 100644
--- a/src/ssl/tls13_server.c
+++ b/src/ssl/tls13_server.c
@@ -135,11 +135,6 @@
 
 static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  /* The short record header extension is incompatible with early data. */
-  if (ssl->s3->skip_early_data && ssl->s3->short_header) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-    return ssl_hs_error;
-  }
 
   SSL_CLIENT_HELLO client_hello;
   if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
@@ -354,18 +349,8 @@
       !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) ||
       !CBB_add_u16_length_prefixed(&body, &extensions) ||
       !ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
-      !ssl_ext_key_share_add_serverhello(hs, &extensions)) {
-    goto err;
-  }
-
-  if (ssl->s3->short_header) {
-    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_short_header) ||
-        !CBB_add_u16(&extensions, 0 /* empty extension */)) {
-      goto err;
-    }
-  }
-
-  if (!ssl_add_message_cbb(ssl, &cbb)) {
+      !ssl_ext_key_share_add_serverhello(hs, &extensions) ||
+      !ssl_add_message_cbb(ssl, &cbb)) {
     goto err;
   }
 
diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c
index eaad2ca..7778310 100644
--- a/src/ssl/tls_method.c
+++ b/src/ssl/tls_method.c
@@ -258,7 +258,14 @@
   return TLS_method();
 }
 
+static int ssl_noop_x509_check_client_CA_names(
+    STACK_OF(CRYPTO_BUFFER) *names) {
+  return 1;
+}
+
 static void ssl_noop_x509_clear(CERT *cert) {}
+static void ssl_noop_x509_free(CERT *cert) {}
+static void ssl_noop_x509_dup(CERT *new_cert, const CERT *cert) {}
 static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {}
 static void ssl_noop_x509_flush_cached_chain(CERT *cert) {}
 static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) {
@@ -269,12 +276,46 @@
   return 1;
 }
 static void ssl_noop_x509_session_clear(SSL_SESSION *session) {}
+static int ssl_noop_x509_session_verify_cert_chain(SSL_SESSION *session,
+                                                   SSL *ssl) {
+  return 0;
+}
 
-const SSL_X509_METHOD ssl_noop_x509_method = {
+static void ssl_noop_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {}
+static int ssl_noop_x509_ssl_new(SSL *ctx) { return 1; }
+static void ssl_noop_x509_ssl_free(SSL *ctx) { }
+static void ssl_noop_x509_ssl_flush_cached_client_CA(SSL *ssl) {}
+static int ssl_noop_x509_ssl_auto_chain_if_needed(SSL *ssl) { return 1; }
+static int ssl_noop_x509_ssl_ctx_new(SSL_CTX *ctx) { return 1; }
+static void ssl_noop_x509_ssl_ctx_free(SSL_CTX *ctx) { }
+static void ssl_noop_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {}
+
+static const SSL_X509_METHOD ssl_noop_x509_method = {
+  ssl_noop_x509_check_client_CA_names,
   ssl_noop_x509_clear,
+  ssl_noop_x509_free,
+  ssl_noop_x509_dup,
   ssl_noop_x509_flush_cached_chain,
   ssl_noop_x509_flush_cached_leaf,
   ssl_noop_x509_session_cache_objects,
   ssl_noop_x509_session_dup,
   ssl_noop_x509_session_clear,
+  ssl_noop_x509_session_verify_cert_chain,
+  ssl_noop_x509_hs_flush_cached_ca_names,
+  ssl_noop_x509_ssl_new,
+  ssl_noop_x509_ssl_free,
+  ssl_noop_x509_ssl_flush_cached_client_CA,
+  ssl_noop_x509_ssl_auto_chain_if_needed,
+  ssl_noop_x509_ssl_ctx_new,
+  ssl_noop_x509_ssl_ctx_free,
+  ssl_noop_x509_ssl_ctx_flush_cached_client_CA,
 };
+
+const SSL_METHOD *TLS_with_buffers_method(void) {
+  static const SSL_METHOD kMethod = {
+      0,
+      &kTLSProtocolMethod,
+      &ssl_noop_x509_method,
+  };
+  return &kMethod;
+}
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index 6ff79c4..bf9735c 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -145,19 +145,6 @@
          SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher);
 }
 
-static int ssl_uses_short_header(const SSL *ssl,
-                                 enum evp_aead_direction_t dir) {
-  if (!ssl->s3->short_header) {
-    return 0;
-  }
-
-  if (dir == evp_aead_open) {
-    return ssl->s3->aead_read_ctx != NULL;
-  }
-
-  return ssl->s3->aead_write_ctx != NULL;
-}
-
 int ssl_record_sequence_update(uint8_t *seq, size_t seq_len) {
   for (size_t i = seq_len - 1; i < seq_len; i--) {
     ++seq[i];
@@ -173,8 +160,6 @@
   size_t header_len;
   if (SSL_is_dtls(ssl)) {
     header_len = DTLS1_RT_HEADER_LENGTH;
-  } else if (ssl_uses_short_header(ssl, evp_aead_open)) {
-    header_len = 2;
   } else {
     header_len = SSL3_RT_HEADER_LENGTH;
   }
@@ -188,17 +173,10 @@
            SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
   }
 
-  size_t header_len;
-  if (ssl_uses_short_header(ssl, evp_aead_seal)) {
-    header_len = 2;
-  } else {
-    header_len = SSL3_RT_HEADER_LENGTH;
-  }
-
-  size_t ret =
-      header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
+  size_t ret = SSL3_RT_HEADER_LENGTH +
+               SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
   if (ssl_needs_record_splitting(ssl)) {
-    ret += header_len;
+    ret += SSL3_RT_HEADER_LENGTH;
     ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher);
   }
   return ret;
@@ -209,8 +187,7 @@
     return dtls_max_seal_overhead(ssl, dtls1_use_current_epoch);
   }
 
-  size_t ret =
-      ssl_uses_short_header(ssl, evp_aead_seal) ? 2 : SSL3_RT_HEADER_LENGTH;
+  size_t ret = SSL3_RT_HEADER_LENGTH;
   ret += SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
   /* TLS 1.3 needs an extra byte for the encrypted record type. */
   if (ssl->s3->have_version &&
@@ -234,31 +211,11 @@
   /* Decode the record header. */
   uint8_t type;
   uint16_t version, ciphertext_len;
-  size_t header_len;
-  if (ssl_uses_short_header(ssl, evp_aead_open)) {
-    if (!CBS_get_u16(&cbs, &ciphertext_len)) {
-      *out_consumed = 2;
-      return ssl_open_record_partial;
-    }
-
-    if ((ciphertext_len & 0x8000) == 0) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-      *out_alert = SSL_AD_DECODE_ERROR;
-      return ssl_open_record_error;
-    }
-
-    ciphertext_len &= 0x7fff;
-    type = SSL3_RT_APPLICATION_DATA;
-    version = TLS1_VERSION;
-    header_len = 2;
-  } else {
-    if (!CBS_get_u8(&cbs, &type) ||
-        !CBS_get_u16(&cbs, &version) ||
-        !CBS_get_u16(&cbs, &ciphertext_len)) {
-      *out_consumed = SSL3_RT_HEADER_LENGTH;
-      return ssl_open_record_partial;
-    }
-    header_len = SSL3_RT_HEADER_LENGTH;
+  if (!CBS_get_u8(&cbs, &type) ||
+      !CBS_get_u16(&cbs, &version) ||
+      !CBS_get_u16(&cbs, &ciphertext_len)) {
+    *out_consumed = SSL3_RT_HEADER_LENGTH;
+    return ssl_open_record_partial;
   }
 
   int version_ok;
@@ -290,11 +247,12 @@
   /* Extract the body. */
   CBS body;
   if (!CBS_get_bytes(&cbs, &body, ciphertext_len)) {
-    *out_consumed = header_len + (size_t)ciphertext_len;
+    *out_consumed = SSL3_RT_HEADER_LENGTH + (size_t)ciphertext_len;
     return ssl_open_record_partial;
   }
 
-  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, header_len);
+  ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in,
+                      SSL3_RT_HEADER_LENGTH);
 
   *out_consumed = in_len - CBS_len(&cbs);
 
@@ -398,26 +356,24 @@
                           size_t in_len) {
   assert(!buffers_alias(in, in_len, out, max_out));
 
-  const int short_header = ssl_uses_short_header(ssl, evp_aead_seal);
-  size_t header_len = short_header ? 2 : SSL3_RT_HEADER_LENGTH;
-
   /* TLS 1.3 hides the actual record type inside the encrypted data. */
   if (ssl->s3->have_version &&
       ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
       ssl->s3->aead_write_ctx != NULL) {
-    if (in_len > in_len + header_len + 1 || max_out < in_len + header_len + 1) {
+    if (in_len > in_len + SSL3_RT_HEADER_LENGTH + 1 ||
+        max_out < in_len + SSL3_RT_HEADER_LENGTH + 1) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
       return 0;
     }
 
-    OPENSSL_memcpy(out + header_len, in, in_len);
-    out[header_len + in_len] = type;
-    in = out + header_len;
+    OPENSSL_memcpy(out + SSL3_RT_HEADER_LENGTH, in, in_len);
+    out[SSL3_RT_HEADER_LENGTH + in_len] = type;
+    in = out + SSL3_RT_HEADER_LENGTH;
     type = SSL3_RT_APPLICATION_DATA;
     in_len++;
   }
 
-  if (max_out < header_len) {
+  if (max_out < SSL3_RT_HEADER_LENGTH) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
     return 0;
   }
@@ -433,13 +389,11 @@
   }
 
   /* Write the non-length portions of the header. */
-  if (!short_header) {
-    out[0] = type;
-    out[1] = wire_version >> 8;
-    out[2] = wire_version & 0xff;
-    out += 3;
-    max_out -= 3;
-  }
+  out[0] = type;
+  out[1] = wire_version >> 8;
+  out[2] = wire_version & 0xff;
+  out += 3;
+  max_out -= 3;
 
   /* Write the ciphertext, leaving two bytes for the length. */
   size_t ciphertext_len;
@@ -457,13 +411,11 @@
   }
   out[0] = ciphertext_len >> 8;
   out[1] = ciphertext_len & 0xff;
-  if (short_header) {
-    out[0] |= 0x80;
-  }
 
-  *out_len = header_len + ciphertext_len;
+  *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
 
-  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out, header_len);
+  ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out,
+                      SSL3_RT_HEADER_LENGTH);
   return 1;
 }
 
@@ -485,7 +437,6 @@
     out += frag_len;
     max_out -= frag_len;
 
-    assert(!ssl_uses_short_header(ssl, evp_aead_seal));
 #if !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
     assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len(
                                        ssl->s3->aead_write_ctx->cipher) ==
diff --git a/src/tool/speed.cc b/src/tool/speed.cc
index cf4d8ba..3e5952f 100644
--- a/src/tool/speed.cc
+++ b/src/tool/speed.cc
@@ -200,7 +200,8 @@
 }
 
 static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
-                           size_t chunk_len, size_t ad_len) {
+                           size_t chunk_len, size_t ad_len,
+                           evp_aead_direction_t direction) {
   static const unsigned kAlignment = 16;
 
   bssl::ScopedEVP_AEAD_CTX ctx;
@@ -214,6 +215,7 @@
   OPENSSL_memset(nonce.get(), 0, nonce_len);
   std::unique_ptr<uint8_t[]> in_storage(new uint8_t[chunk_len + kAlignment]);
   std::unique_ptr<uint8_t[]> out_storage(new uint8_t[chunk_len + overhead_len + kAlignment]);
+  std::unique_ptr<uint8_t[]> in2_storage(new uint8_t[chunk_len + kAlignment]);
   std::unique_ptr<uint8_t[]> ad(new uint8_t[ad_len]);
   OPENSSL_memset(ad.get(), 0, ad_len);
 
@@ -221,6 +223,7 @@
   OPENSSL_memset(in, 0, chunk_len);
   uint8_t *const out = align(out_storage.get(), kAlignment);
   OPENSSL_memset(out, 0, chunk_len + overhead_len);
+  uint8_t *const in2 = align(in2_storage.get(), kAlignment);
 
   if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
                                         EVP_AEAD_DEFAULT_TAG_LENGTH,
@@ -231,19 +234,38 @@
   }
 
   TimeResults results;
-  if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
-                               out, &ctx, &nonce, &ad]() -> bool {
-        size_t out_len;
-        return EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
-                                 chunk_len + overhead_len, nonce.get(),
-                                 nonce_len, in, chunk_len, ad.get(), ad_len);
-      })) {
-    fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
-    ERR_print_errors_fp(stderr);
-    return false;
+  if (direction == evp_aead_seal) {
+    if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
+                                 out, &ctx, &nonce, &ad]() -> bool {
+          size_t out_len;
+          return EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
+                                   chunk_len + overhead_len, nonce.get(),
+                                   nonce_len, in, chunk_len, ad.get(), ad_len);
+        })) {
+      fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+  } else {
+    size_t out_len;
+    EVP_AEAD_CTX_seal(ctx.get(), out, &out_len, chunk_len + overhead_len,
+                      nonce.get(), nonce_len, in, chunk_len, ad.get(), ad_len);
+
+    if (!TimeFunction(&results, [chunk_len, nonce_len, ad_len, in2, out, &ctx,
+                                 &nonce, &ad, out_len]() -> bool {
+          size_t in2_len;
+          return EVP_AEAD_CTX_open(ctx.get(), in2, &in2_len, chunk_len,
+                                   nonce.get(), nonce_len, out, out_len,
+                                   ad.get(), ad_len);
+        })) {
+      fprintf(stderr, "EVP_AEAD_CTX_open failed.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
   }
 
-  results.PrintWithBytes(name + " seal", chunk_len);
+  results.PrintWithBytes(
+      name + (direction == evp_aead_seal ? " seal" : " open"), chunk_len);
   return true;
 }
 
@@ -253,11 +275,30 @@
     return true;
   }
 
-  return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len) &&
-         SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len) &&
-         SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len);
+  return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len,
+                        evp_aead_seal) &&
+         SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len,
+                        evp_aead_seal) &&
+         SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len,
+                        evp_aead_seal);
 }
 
+#if !defined(OPENSSL_SMALL)
+static bool SpeedAEADOpen(const EVP_AEAD *aead, const std::string &name,
+                          size_t ad_len, const std::string &selected) {
+  if (!selected.empty() && name.find(selected) == std::string::npos) {
+    return true;
+  }
+
+  return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len,
+                        evp_aead_open) &&
+         SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len,
+                        evp_aead_open) &&
+         SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len,
+                        evp_aead_open);
+}
+#endif  /* !SMALL */
+
 static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
                            size_t chunk_len) {
   EVP_MD_CTX *ctx = EVP_MD_CTX_create();
@@ -629,6 +670,10 @@
                  selected) ||
       !SpeedAEAD(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen,
                  selected) ||
+      !SpeedAEADOpen(EVP_aead_aes_128_gcm_siv(), "AES-128-GCM-SIV", kTLSADLen,
+                     selected) ||
+      !SpeedAEADOpen(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen,
+                     selected) ||
 #endif
       !SpeedHash(EVP_sha1(), "SHA-1", selected) ||
       !SpeedHash(EVP_sha256(), "SHA-256", selected) ||
diff --git a/src/util/all_tests.json b/src/util/all_tests.json
index fc49c69..a6e672f 100644
--- a/src/util/all_tests.json
+++ b/src/util/all_tests.json
@@ -29,7 +29,6 @@
 	["crypto/constant_time_test"],
 	["crypto/crypto_test"],
 	["crypto/curve25519/ed25519_test", "crypto/curve25519/ed25519_tests.txt"],
-	["crypto/curve25519/x25519_test"],
 	["crypto/curve25519/spake25519_test"],
 	["crypto/digest/digest_test"],
 	["crypto/ec/example_mul"],
@@ -38,7 +37,6 @@
 	["crypto/ecdsa/ecdsa_sign_test", "crypto/ecdsa/ecdsa_sign_tests.txt"],
 	["crypto/ecdsa/ecdsa_test"],
 	["crypto/ecdsa/ecdsa_verify_test", "crypto/ecdsa/ecdsa_verify_tests.txt"],
-	["crypto/evp/evp_extra_test"],
 	["crypto/evp/evp_test", "crypto/evp/evp_tests.txt"],
 	["crypto/evp/pbkdf_test"],
 	["crypto/hkdf/hkdf_test"],
diff --git a/src/util/bot/DEPS b/src/util/bot/DEPS
index 5036c0c..55eeb86 100644
--- a/src/util/bot/DEPS
+++ b/src/util/bot/DEPS
@@ -24,7 +24,7 @@
 deps_os = {
   'android': {
     'boringssl/util/bot/android_tools':
-      Var('chromium_git') + '/android_tools.git' + '@' + 'c02a002b48d6637714ef98f0e4bf6952b9c4cf10',
+      Var('chromium_git') + '/android_tools.git' + '@' + 'b43a6a289a7588b1769814f04dd6c7d7176974cc',
   },
 }
 
diff --git a/src/util/bot/go/bootstrap.py b/src/util/bot/go/bootstrap.py
index 5661be2..bb64e25 100755
--- a/src/util/bot/go/bootstrap.py
+++ b/src/util/bot/go/bootstrap.py
@@ -45,7 +45,7 @@
 EXE_SFX = '.exe' if sys.platform == 'win32' else ''
 
 # Pinned version of Go toolset to download.
-TOOLSET_VERSION = 'go1.7.3'
+TOOLSET_VERSION = 'go1.8'
 
 # Platform dependent portion of a download URL. See http://golang.org/dl/.
 TOOLSET_VARIANTS = {
diff --git a/src/util/bot/update_clang.py b/src/util/bot/update_clang.py
index 32fb01a..7e91113 100644
--- a/src/util/bot/update_clang.py
+++ b/src/util/bot/update_clang.py
@@ -22,7 +22,7 @@
 # CLANG_REVISION and CLANG_SUB_REVISION determine the build of clang
 # to use. These should be synced with tools/clang/scripts/update.py in
 # Chromium.
-CLANG_REVISION = "284979"
+CLANG_REVISION = "296320"
 CLANG_SUB_REVISION = "1"
 
 PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
diff --git a/src/util/bot/vs_toolchain.py b/src/util/bot/vs_toolchain.py
index 201b000..2e87272 100644
--- a/src/util/bot/vs_toolchain.py
+++ b/src/util/bot/vs_toolchain.py
@@ -19,7 +19,7 @@
 
 
 TOOLCHAIN_VERSION = '2015'
-TOOLCHAIN_HASH = 'd5dc33b15d1b2c086f2f6632e2fd15882f80dbd3'
+TOOLCHAIN_HASH = 'd3cb0e37bdd120ad0ac4650b674b09e81be45616'
 
 
 def SetEnvironmentAndGetRuntimeDllDirs():
diff --git a/src/util/run_android_tests.go b/src/util/run_android_tests.go
index 8e42596..92deac0 100644
--- a/src/util/run_android_tests.go
+++ b/src/util/run_android_tests.go
@@ -243,6 +243,8 @@
 			"BUILDING.md",
 			"ssl/test/runner/cert.pem",
 			"ssl/test/runner/channel_id_key.pem",
+			"ssl/test/runner/ecdsa_p224_cert.pem",
+			"ssl/test/runner/ecdsa_p224_key.pem",
 			"ssl/test/runner/ecdsa_p256_cert.pem",
 			"ssl/test/runner/ecdsa_p256_key.pem",
 			"ssl/test/runner/ecdsa_p384_cert.pem",