shim: move |TestState| and |TestConfig| to their own files.

This makes |TestState| and |TestConfig| accessible outside
bssl_shim.cc, as well as the functions SetupCtx() and NewSSL(), which
become methods on |TestConfig|.  A whole mess of callbacks move in
order to support this change.

Along the way, some bits of global state are moved (e.g. the global
test clock) and made self-initializing.

This helps with creating a separate binary to perform split
handshakes.

Change-Id: I39b00a1819074882353f5f04ed01312916f3cccb
Reviewed-on: https://boringssl-review.googlesource.com/29345
Commit-Queue: Matt Braithwaite <mab@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/test/CMakeLists.txt b/ssl/test/CMakeLists.txt
index 5a73319..2fdee73 100644
--- a/ssl/test/CMakeLists.txt
+++ b/ssl/test/CMakeLists.txt
@@ -8,6 +8,7 @@
   packeted_bio.cc
   settings_writer.cc
   test_config.cc
+  test_state.cc
 
   $<TARGET_OBJECTS:test_support>
 )
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 27a0783..f73fc69 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -67,10 +67,9 @@
 #include "packeted_bio.h"
 #include "settings_writer.h"
 #include "test_config.h"
+#include "test_state.h"
 
 
-static CRYPTO_BUFFER_POOL *g_pool = nullptr;
-
 #if !defined(OPENSSL_WINDOWS)
 static int closesocket(int sock) {
   return close(sock);
@@ -90,79 +89,6 @@
   return 1;
 }
 
-struct TestState {
-  // async_bio is async BIO which pauses reads and writes.
-  BIO *async_bio = nullptr;
-  // packeted_bio is the packeted BIO which simulates read timeouts.
-  BIO *packeted_bio = nullptr;
-  bssl::UniquePtr<EVP_PKEY> channel_id;
-  bool cert_ready = false;
-  bssl::UniquePtr<SSL_SESSION> session;
-  bssl::UniquePtr<SSL_SESSION> pending_session;
-  bool early_callback_called = false;
-  bool handshake_done = false;
-  // private_key is the underlying private key used when testing custom keys.
-  bssl::UniquePtr<EVP_PKEY> private_key;
-  std::vector<uint8_t> private_key_result;
-  // private_key_retries is the number of times an asynchronous private key
-  // operation has been retried.
-  unsigned private_key_retries = 0;
-  bool got_new_session = false;
-  bssl::UniquePtr<SSL_SESSION> new_session;
-  bool ticket_decrypt_done = false;
-  bool alpn_select_done = false;
-  bool is_resume = false;
-  bool early_callback_ready = false;
-  bool custom_verify_ready = false;
-  std::string msg_callback_text;
-  bool msg_callback_ok = true;
-  // cert_verified is true if certificate verification has been driven to
-  // completion. This tests that the callback is not called again after this.
-  bool cert_verified = false;
-};
-
-static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
-                            int index, long argl, void *argp) {
-  delete ((TestState *)ptr);
-}
-
-static int g_config_index = 0;
-static int g_state_index = 0;
-
-static bool SetTestConfig(SSL *ssl, const TestConfig *config) {
-  return SSL_set_ex_data(ssl, g_config_index, (void *)config) == 1;
-}
-
-static const TestConfig *GetTestConfig(const SSL *ssl) {
-  return (const TestConfig *)SSL_get_ex_data(ssl, g_config_index);
-}
-
-static bool SetTestState(SSL *ssl, std::unique_ptr<TestState> state) {
-  // |SSL_set_ex_data| takes ownership of |state| only on success.
-  if (SSL_set_ex_data(ssl, g_state_index, state.get()) == 1) {
-    state.release();
-    return true;
-  }
-  return false;
-}
-
-static TestState *GetTestState(const SSL *ssl) {
-  return (TestState *)SSL_get_ex_data(ssl, g_state_index);
-}
-
-static bool MoveExData(SSL *dest, SSL *src) {
-  TestState *state = GetTestState(src);
-  const TestConfig *config = GetTestConfig(src);
-  if (!SSL_set_ex_data(src, g_state_index, nullptr) ||
-      !SSL_set_ex_data(dest, g_state_index, state) ||
-      !SSL_set_ex_data(src, g_config_index, nullptr) ||
-      !SSL_set_ex_data(dest, g_config_index, (void *) config)) {
-    return false;
-  }
-
-  return true;
-}
-
 // MoveBIOs moves the |BIO|s of |src| to |dst|.  It is used for handoff.
 static void MoveBIOs(SSL *dest, SSL *src) {
   BIO *rbio = SSL_get_rbio(src);
@@ -177,262 +103,6 @@
   SSL_set0_wbio(src, nullptr);
 }
 
-static bool LoadCertificate(bssl::UniquePtr<X509> *out_x509,
-                            bssl::UniquePtr<STACK_OF(X509)> *out_chain,
-                            const std::string &file) {
-  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
-  if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
-    return false;
-  }
-
-  out_x509->reset(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
-  if (!*out_x509) {
-    return false;
-  }
-
-  out_chain->reset(sk_X509_new_null());
-  if (!*out_chain) {
-    return false;
-  }
-
-  // Keep reading the certificate chain.
-  for (;;) {
-    bssl::UniquePtr<X509> cert(
-        PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
-    if (!cert) {
-      break;
-    }
-
-    if (!bssl::PushToStack(out_chain->get(), std::move(cert))) {
-      return false;
-    }
-  }
-
-  uint32_t err = ERR_peek_last_error();
-  if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
-      ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
-    return false;
-}
-
-  ERR_clear_error();
-  return true;
-}
-
-static bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file) {
-  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
-  if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
-    return nullptr;
-  }
-  return bssl::UniquePtr<EVP_PKEY>(
-      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());
-  if (!ret) {
-    return nullptr;
-  }
-
-  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 (!bssl::PushToStack(ret.get(), std::move(name))) {
-      return nullptr;
-    }
-  }
-
-  return ret;
-}
-
-static ssl_private_key_result_t AsyncPrivateKeySign(
-    SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
-    uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
-  TestState *test_state = GetTestState(ssl);
-  if (!test_state->private_key_result.empty()) {
-    fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n");
-    abort();
-  }
-
-  if (EVP_PKEY_id(test_state->private_key.get()) !=
-      SSL_get_signature_algorithm_key_type(signature_algorithm)) {
-    fprintf(stderr, "Key type does not match signature algorithm.\n");
-    abort();
-  }
-
-  // Determine the hash.
-  const EVP_MD *md = SSL_get_signature_algorithm_digest(signature_algorithm);
-  bssl::ScopedEVP_MD_CTX ctx;
-  EVP_PKEY_CTX *pctx;
-  if (!EVP_DigestSignInit(ctx.get(), &pctx, md, nullptr,
-                          test_state->private_key.get())) {
-    return ssl_private_key_failure;
-  }
-
-  // Configure additional signature parameters.
-  if (SSL_is_signature_algorithm_rsa_pss(signature_algorithm)) {
-    if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
-        !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */)) {
-      return ssl_private_key_failure;
-    }
-  }
-
-  // Write the signature into |test_state|.
-  size_t len = 0;
-  if (!EVP_DigestSign(ctx.get(), nullptr, &len, in, in_len)) {
-    return ssl_private_key_failure;
-  }
-  test_state->private_key_result.resize(len);
-  if (!EVP_DigestSign(ctx.get(), test_state->private_key_result.data(), &len,
-                      in, in_len)) {
-    return ssl_private_key_failure;
-  }
-  test_state->private_key_result.resize(len);
-
-  // The signature will be released asynchronously in |AsyncPrivateKeyComplete|.
-  return ssl_private_key_retry;
-}
-
-static ssl_private_key_result_t AsyncPrivateKeyDecrypt(
-    SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
-    const uint8_t *in, size_t in_len) {
-  TestState *test_state = GetTestState(ssl);
-  if (!test_state->private_key_result.empty()) {
-    fprintf(stderr,
-            "AsyncPrivateKeyDecrypt called with operation pending.\n");
-    abort();
-  }
-
-  RSA *rsa = EVP_PKEY_get0_RSA(test_state->private_key.get());
-  if (rsa == NULL) {
-    fprintf(stderr,
-            "AsyncPrivateKeyDecrypt called with incorrect key type.\n");
-    abort();
-  }
-  test_state->private_key_result.resize(RSA_size(rsa));
-  if (!RSA_decrypt(rsa, out_len, test_state->private_key_result.data(),
-                   RSA_size(rsa), in, in_len, RSA_NO_PADDING)) {
-    return ssl_private_key_failure;
-  }
-
-  test_state->private_key_result.resize(*out_len);
-
-  // The decryption will be released asynchronously in |AsyncPrivateComplete|.
-  return ssl_private_key_retry;
-}
-
-static ssl_private_key_result_t AsyncPrivateKeyComplete(
-    SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) {
-  TestState *test_state = GetTestState(ssl);
-  if (test_state->private_key_result.empty()) {
-    fprintf(stderr,
-            "AsyncPrivateKeyComplete called without operation pending.\n");
-    abort();
-  }
-
-  if (test_state->private_key_retries < 2) {
-    // Only return the decryption on the second attempt, to test both incomplete
-    // |decrypt| and |decrypt_complete|.
-    return ssl_private_key_retry;
-  }
-
-  if (max_out < test_state->private_key_result.size()) {
-    fprintf(stderr, "Output buffer too small.\n");
-    return ssl_private_key_failure;
-  }
-  OPENSSL_memcpy(out, test_state->private_key_result.data(),
-                 test_state->private_key_result.size());
-  *out_len = test_state->private_key_result.size();
-
-  test_state->private_key_result.clear();
-  test_state->private_key_retries = 0;
-  return ssl_private_key_success;
-}
-
-static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = {
-    AsyncPrivateKeySign,
-    AsyncPrivateKeyDecrypt,
-    AsyncPrivateKeyComplete,
-};
-
 template<typename T>
 struct Free {
   void operator()(T *buf) {
@@ -440,651 +110,6 @@
   }
 };
 
-static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
-                           bssl::UniquePtr<STACK_OF(X509)> *out_chain,
-                           bssl::UniquePtr<EVP_PKEY> *out_pkey) {
-  const TestConfig *config = GetTestConfig(ssl);
-
-  if (!config->signing_prefs.empty()) {
-    std::vector<uint16_t> u16s(config->signing_prefs.begin(),
-                               config->signing_prefs.end());
-    if (!SSL_set_signing_algorithm_prefs(ssl, u16s.data(), u16s.size())) {
-      return false;
-    }
-  }
-
-  if (!config->key_file.empty()) {
-    *out_pkey = LoadPrivateKey(config->key_file.c_str());
-    if (!*out_pkey) {
-      return false;
-    }
-  }
-  if (!config->cert_file.empty() &&
-      !LoadCertificate(out_x509, out_chain, config->cert_file.c_str())) {
-    return false;
-  }
-  if (!config->ocsp_response.empty() &&
-      !config->set_ocsp_in_callback &&
-      !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(),
-                             config->ocsp_response.size())) {
-    return false;
-  }
-  return true;
-}
-
-static bool InstallCertificate(SSL *ssl) {
-  bssl::UniquePtr<X509> x509;
-  bssl::UniquePtr<STACK_OF(X509)> chain;
-  bssl::UniquePtr<EVP_PKEY> pkey;
-  if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
-    return false;
-  }
-
-  if (pkey) {
-    TestState *test_state = GetTestState(ssl);
-    const TestConfig *config = GetTestConfig(ssl);
-    if (config->async) {
-      test_state->private_key = std::move(pkey);
-      SSL_set_private_key_method(ssl, &g_async_private_key_method);
-    } else if (!SSL_use_PrivateKey(ssl, pkey.get())) {
-      return false;
-    }
-  }
-
-  if (x509 && !SSL_use_certificate(ssl, x509.get())) {
-    return false;
-  }
-
-  if (sk_X509_num(chain.get()) > 0 &&
-      !SSL_set1_chain(ssl, chain.get())) {
-    return false;
-  }
-
-  return true;
-}
-
-static enum ssl_select_cert_result_t SelectCertificateCallback(
-    const SSL_CLIENT_HELLO *client_hello) {
-  const TestConfig *config = GetTestConfig(client_hello->ssl);
-  GetTestState(client_hello->ssl)->early_callback_called = true;
-
-  if (!config->expected_server_name.empty()) {
-    const uint8_t *extension_data;
-    size_t extension_len;
-    CBS extension, server_name_list, host_name;
-    uint8_t name_type;
-
-    if (!SSL_early_callback_ctx_extension_get(
-            client_hello, TLSEXT_TYPE_server_name, &extension_data,
-            &extension_len)) {
-      fprintf(stderr, "Could not find server_name extension.\n");
-      return ssl_select_cert_error;
-    }
-
-    CBS_init(&extension, extension_data, extension_len);
-    if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
-        CBS_len(&extension) != 0 ||
-        !CBS_get_u8(&server_name_list, &name_type) ||
-        name_type != TLSEXT_NAMETYPE_host_name ||
-        !CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
-        CBS_len(&server_name_list) != 0) {
-      fprintf(stderr, "Could not decode server_name extension.\n");
-      return ssl_select_cert_error;
-    }
-
-    if (!CBS_mem_equal(&host_name,
-                       (const uint8_t*)config->expected_server_name.data(),
-                       config->expected_server_name.size())) {
-      fprintf(stderr, "Server name mismatch.\n");
-    }
-  }
-
-  if (config->fail_early_callback) {
-    return ssl_select_cert_error;
-  }
-
-  // Install the certificate in the early callback.
-  if (config->use_early_callback) {
-    bool early_callback_ready =
-        GetTestState(client_hello->ssl)->early_callback_ready;
-    if (config->async && !early_callback_ready) {
-      // Install the certificate asynchronously.
-      return ssl_select_cert_retry;
-    }
-    if (!InstallCertificate(client_hello->ssl)) {
-      return ssl_select_cert_error;
-    }
-  }
-  return ssl_select_cert_success;
-}
-
-static bool CheckCertificateRequest(SSL *ssl) {
-  const TestConfig *config = GetTestConfig(ssl);
-
-  if (!config->expected_certificate_types.empty()) {
-    const uint8_t *certificate_types;
-    size_t certificate_types_len =
-        SSL_get0_certificate_types(ssl, &certificate_types);
-    if (certificate_types_len != config->expected_certificate_types.size() ||
-        OPENSSL_memcmp(certificate_types,
-                       config->expected_certificate_types.data(),
-                       certificate_types_len) != 0) {
-      fprintf(stderr, "certificate types mismatch\n");
-      return false;
-    }
-  }
-
-  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;
-      }
-    }
-
-    const 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;
-}
-
-static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
-  if (!CheckCertificateRequest(ssl)) {
-    return -1;
-  }
-
-  if (GetTestConfig(ssl)->async && !GetTestState(ssl)->cert_ready) {
-    return -1;
-  }
-
-  bssl::UniquePtr<X509> x509;
-  bssl::UniquePtr<STACK_OF(X509)> chain;
-  bssl::UniquePtr<EVP_PKEY> pkey;
-  if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
-    return -1;
-  }
-
-  // Return zero for no certificate.
-  if (!x509) {
-    return 0;
-  }
-
-  // Chains and asynchronous private keys are not supported with client_cert_cb.
-  *out_x509 = x509.release();
-  *out_pkey = pkey.release();
-  return 1;
-}
-
-static int CertCallback(SSL *ssl, void *arg) {
-  const TestConfig *config = GetTestConfig(ssl);
-
-  // Check the CertificateRequest metadata is as expected.
-  if (!SSL_is_server(ssl) && !CheckCertificateRequest(ssl)) {
-    return -1;
-  }
-
-  if (config->fail_cert_callback) {
-    return 0;
-  }
-
-  // The certificate will be installed via other means.
-  if (!config->async || config->use_early_callback) {
-    return 1;
-  }
-
-  if (!GetTestState(ssl)->cert_ready) {
-    return -1;
-  }
-  if (!InstallCertificate(ssl)) {
-    return 0;
-  }
-  return 1;
-}
-
-static bool CheckVerifyCallback(SSL *ssl) {
-  const TestConfig *config = GetTestConfig(ssl);
-  if (!config->expected_ocsp_response.empty()) {
-    const uint8_t *data;
-    size_t len;
-    SSL_get0_ocsp_response(ssl, &data, &len);
-    if (len == 0) {
-      fprintf(stderr, "OCSP response not available in verify callback\n");
-      return false;
-    }
-  }
-
-  if (GetTestState(ssl)->cert_verified) {
-    fprintf(stderr, "Certificate verified twice.\n");
-    return false;
-  }
-
-  return true;
-}
-
-static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) {
-  SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx,
-      SSL_get_ex_data_X509_STORE_CTX_idx());
-  const TestConfig *config = GetTestConfig(ssl);
-  if (!CheckVerifyCallback(ssl)) {
-    return 0;
-  }
-
-  GetTestState(ssl)->cert_verified = true;
-  if (config->verify_fail) {
-    store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION;
-    return 0;
-  }
-
-  return 1;
-}
-
-static ssl_verify_result_t CustomVerifyCallback(SSL *ssl, uint8_t *out_alert) {
-  const TestConfig *config = GetTestConfig(ssl);
-  if (!CheckVerifyCallback(ssl)) {
-    return ssl_verify_invalid;
-  }
-
-  if (config->async && !GetTestState(ssl)->custom_verify_ready) {
-    return ssl_verify_retry;
-  }
-
-  GetTestState(ssl)->cert_verified = true;
-  if (config->verify_fail) {
-    return ssl_verify_invalid;
-  }
-
-  return ssl_verify_ok;
-}
-
-static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out,
-                                        unsigned int *out_len, void *arg) {
-  const TestConfig *config = GetTestConfig(ssl);
-  if (config->advertise_npn.empty()) {
-    return SSL_TLSEXT_ERR_NOACK;
-  }
-
-  *out = (const uint8_t*)config->advertise_npn.data();
-  *out_len = config->advertise_npn.size();
-  return SSL_TLSEXT_ERR_OK;
-}
-
-static int NextProtoSelectCallback(SSL* ssl, uint8_t** out, uint8_t* outlen,
-                                   const uint8_t* in, unsigned inlen, void* arg) {
-  const TestConfig *config = GetTestConfig(ssl);
-  if (config->select_next_proto.empty()) {
-    return SSL_TLSEXT_ERR_NOACK;
-  }
-
-  *out = (uint8_t*)config->select_next_proto.data();
-  *outlen = config->select_next_proto.size();
-  return SSL_TLSEXT_ERR_OK;
-}
-
-static int AlpnSelectCallback(SSL* ssl, const uint8_t** out, uint8_t* outlen,
-                              const uint8_t* in, unsigned inlen, void* arg) {
-  if (GetTestState(ssl)->alpn_select_done) {
-    fprintf(stderr, "AlpnSelectCallback called after completion.\n");
-    exit(1);
-  }
-
-  GetTestState(ssl)->alpn_select_done = true;
-
-  const TestConfig *config = GetTestConfig(ssl);
-  if (config->decline_alpn) {
-    return SSL_TLSEXT_ERR_NOACK;
-  }
-
-  if (!config->expected_advertised_alpn.empty() &&
-      (config->expected_advertised_alpn.size() != inlen ||
-       OPENSSL_memcmp(config->expected_advertised_alpn.data(), in, inlen) !=
-           0)) {
-    fprintf(stderr, "bad ALPN select callback inputs\n");
-    exit(1);
-  }
-
-  assert(config->select_alpn.empty() || !config->select_empty_alpn);
-  *out = (const uint8_t*)config->select_alpn.data();
-  *outlen = config->select_alpn.size();
-  return SSL_TLSEXT_ERR_OK;
-}
-
-static unsigned PskClientCallback(SSL *ssl, const char *hint,
-                                  char *out_identity,
-                                  unsigned max_identity_len,
-                                  uint8_t *out_psk, unsigned max_psk_len) {
-  const TestConfig *config = GetTestConfig(ssl);
-
-  if (config->psk_identity.empty()) {
-    if (hint != nullptr) {
-      fprintf(stderr, "Server PSK hint was non-null.\n");
-      return 0;
-    }
-  } else if (hint == nullptr ||
-             strcmp(hint, config->psk_identity.c_str()) != 0) {
-    fprintf(stderr, "Server PSK hint did not match.\n");
-    return 0;
-  }
-
-  // Account for the trailing '\0' for the identity.
-  if (config->psk_identity.size() >= max_identity_len ||
-      config->psk.size() > max_psk_len) {
-    fprintf(stderr, "PSK buffers too small\n");
-    return 0;
-  }
-
-  BUF_strlcpy(out_identity, config->psk_identity.c_str(),
-              max_identity_len);
-  OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
-  return config->psk.size();
-}
-
-static unsigned PskServerCallback(SSL *ssl, const char *identity,
-                                  uint8_t *out_psk, unsigned max_psk_len) {
-  const TestConfig *config = GetTestConfig(ssl);
-
-  if (strcmp(identity, config->psk_identity.c_str()) != 0) {
-    fprintf(stderr, "Client PSK identity did not match.\n");
-    return 0;
-  }
-
-  if (config->psk.size() > max_psk_len) {
-    fprintf(stderr, "PSK buffers too small\n");
-    return 0;
-  }
-
-  OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
-  return config->psk.size();
-}
-
-static timeval g_clock;
-
-static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
-  *out_clock = g_clock;
-}
-
-static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
-  *out_pkey = GetTestState(ssl)->channel_id.release();
-}
-
-static SSL_SESSION *GetSessionCallback(SSL *ssl, const uint8_t *data, int len,
-                                       int *copy) {
-  TestState *async_state = GetTestState(ssl);
-  if (async_state->session) {
-    *copy = 0;
-    return async_state->session.release();
-  } else if (async_state->pending_session) {
-    return SSL_magic_pending_session_ptr();
-  } else {
-    return NULL;
-  }
-}
-
-static int DDoSCallback(const SSL_CLIENT_HELLO *client_hello) {
-  const TestConfig *config = GetTestConfig(client_hello->ssl);
-  return config->fail_ddos_callback ? 0 : 1;
-}
-
-static void InfoCallback(const SSL *ssl, int type, int val) {
-  if (type == SSL_CB_HANDSHAKE_DONE) {
-    if (GetTestConfig(ssl)->handshake_never_done) {
-      fprintf(stderr, "Handshake unexpectedly completed.\n");
-      // Abort before any expected error code is printed, to ensure the overall
-      // test fails.
-      abort();
-    }
-    // This callback is called when the handshake completes. |SSL_get_session|
-    // must continue to work and |SSL_in_init| must return false.
-    if (SSL_in_init(ssl) || SSL_get_session(ssl) == nullptr) {
-      fprintf(stderr, "Invalid state for SSL_CB_HANDSHAKE_DONE.\n");
-      abort();
-    }
-    GetTestState(ssl)->handshake_done = true;
-
-    // Callbacks may be called again on a new handshake.
-    GetTestState(ssl)->ticket_decrypt_done = false;
-    GetTestState(ssl)->alpn_select_done = false;
-  }
-}
-
-static int NewSessionCallback(SSL *ssl, SSL_SESSION *session) {
-  // This callback is called as the handshake completes. |SSL_get_session|
-  // must continue to work and, historically, |SSL_in_init| returned false at
-  // this point.
-  if (SSL_in_init(ssl) || SSL_get_session(ssl) == nullptr) {
-    fprintf(stderr, "Invalid state for NewSessionCallback.\n");
-    abort();
-  }
-
-  GetTestState(ssl)->got_new_session = true;
-  GetTestState(ssl)->new_session.reset(session);
-  return 1;
-}
-
-static int TicketKeyCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
-                             EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
-                             int encrypt) {
-  if (!encrypt) {
-    if (GetTestState(ssl)->ticket_decrypt_done) {
-      fprintf(stderr, "TicketKeyCallback called after completion.\n");
-      return -1;
-    }
-
-    GetTestState(ssl)->ticket_decrypt_done = true;
-  }
-
-  // This is just test code, so use the all-zeros key.
-  static const uint8_t kZeros[16] = {0};
-
-  if (encrypt) {
-    OPENSSL_memcpy(key_name, kZeros, sizeof(kZeros));
-    RAND_bytes(iv, 16);
-  } else if (OPENSSL_memcmp(key_name, kZeros, 16) != 0) {
-    return 0;
-  }
-
-  if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
-      !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
-    return -1;
-  }
-
-  if (!encrypt) {
-    return GetTestConfig(ssl)->renew_ticket ? 2 : 1;
-  }
-  return 1;
-}
-
-// kCustomExtensionValue is the extension value that the custom extension
-// callbacks will add.
-static const uint16_t kCustomExtensionValue = 1234;
-static void *const kCustomExtensionAddArg =
-    reinterpret_cast<void *>(kCustomExtensionValue);
-static void *const kCustomExtensionParseArg =
-    reinterpret_cast<void *>(kCustomExtensionValue + 1);
-static const char kCustomExtensionContents[] = "custom extension";
-
-static int CustomExtensionAddCallback(SSL *ssl, unsigned extension_value,
-                                      const uint8_t **out, size_t *out_len,
-                                      int *out_alert_value, void *add_arg) {
-  if (extension_value != kCustomExtensionValue ||
-      add_arg != kCustomExtensionAddArg) {
-    abort();
-  }
-
-  if (GetTestConfig(ssl)->custom_extension_skip) {
-    return 0;
-  }
-  if (GetTestConfig(ssl)->custom_extension_fail_add) {
-    return -1;
-  }
-
-  *out = reinterpret_cast<const uint8_t*>(kCustomExtensionContents);
-  *out_len = sizeof(kCustomExtensionContents) - 1;
-
-  return 1;
-}
-
-static void CustomExtensionFreeCallback(SSL *ssl, unsigned extension_value,
-                                        const uint8_t *out, void *add_arg) {
-  if (extension_value != kCustomExtensionValue ||
-      add_arg != kCustomExtensionAddArg ||
-      out != reinterpret_cast<const uint8_t *>(kCustomExtensionContents)) {
-    abort();
-  }
-}
-
-static int CustomExtensionParseCallback(SSL *ssl, unsigned extension_value,
-                                        const uint8_t *contents,
-                                        size_t contents_len,
-                                        int *out_alert_value, void *parse_arg) {
-  if (extension_value != kCustomExtensionValue ||
-      parse_arg != kCustomExtensionParseArg) {
-    abort();
-  }
-
-  if (contents_len != sizeof(kCustomExtensionContents) - 1 ||
-      OPENSSL_memcmp(contents, kCustomExtensionContents, contents_len) != 0) {
-    *out_alert_value = SSL_AD_DECODE_ERROR;
-    return 0;
-  }
-
-  return 1;
-}
-
-static int ServerNameCallback(SSL *ssl, int *out_alert, void *arg) {
-  // SNI must be accessible from the SNI callback.
-  const TestConfig *config = GetTestConfig(ssl);
-  const char *server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
-  if (server_name == nullptr ||
-      std::string(server_name) != config->expected_server_name) {
-    fprintf(stderr, "servername mismatch (got %s; want %s)\n", server_name,
-            config->expected_server_name.c_str());
-    return SSL_TLSEXT_ERR_ALERT_FATAL;
-  }
-
-  return SSL_TLSEXT_ERR_OK;
-}
-
-static void MessageCallback(int is_write, int version, int content_type,
-                            const void *buf, size_t len, SSL *ssl, void *arg) {
-  const uint8_t *buf_u8 = reinterpret_cast<const uint8_t *>(buf);
-  const TestConfig *config = GetTestConfig(ssl);
-  TestState *state = GetTestState(ssl);
-  if (!state->msg_callback_ok) {
-    return;
-  }
-
-  if (content_type == SSL3_RT_HEADER) {
-    if (len !=
-        (config->is_dtls ? DTLS1_RT_HEADER_LENGTH : SSL3_RT_HEADER_LENGTH)) {
-      fprintf(stderr, "Incorrect length for record header: %zu\n", len);
-      state->msg_callback_ok = false;
-    }
-    return;
-  }
-
-  state->msg_callback_text += is_write ? "write " : "read ";
-  switch (content_type) {
-    case 0:
-      if (version != SSL2_VERSION) {
-        fprintf(stderr, "Incorrect version for V2ClientHello: %x\n", version);
-        state->msg_callback_ok = false;
-        return;
-      }
-      state->msg_callback_text += "v2clienthello\n";
-      return;
-
-    case SSL3_RT_HANDSHAKE: {
-      CBS cbs;
-      CBS_init(&cbs, buf_u8, len);
-      uint8_t type;
-      uint32_t msg_len;
-      if (!CBS_get_u8(&cbs, &type) ||
-          // TODO(davidben): Reporting on entire messages would be more
-          // consistent than fragments.
-          (config->is_dtls &&
-           !CBS_skip(&cbs, 3 /* total */ + 2 /* seq */ + 3 /* frag_off */)) ||
-          !CBS_get_u24(&cbs, &msg_len) ||
-          !CBS_skip(&cbs, msg_len) ||
-          CBS_len(&cbs) != 0) {
-        fprintf(stderr, "Could not parse handshake message.\n");
-        state->msg_callback_ok = false;
-        return;
-      }
-      char text[16];
-      snprintf(text, sizeof(text), "hs %d\n", type);
-      state->msg_callback_text += text;
-      return;
-    }
-
-    case SSL3_RT_CHANGE_CIPHER_SPEC:
-      if (len != 1 || buf_u8[0] != 1) {
-        fprintf(stderr, "Invalid ChangeCipherSpec.\n");
-        state->msg_callback_ok = false;
-        return;
-      }
-      state->msg_callback_text += "ccs\n";
-      return;
-
-    case SSL3_RT_ALERT:
-      if (len != 2) {
-        fprintf(stderr, "Invalid alert.\n");
-        state->msg_callback_ok = false;
-        return;
-      }
-      char text[16];
-      snprintf(text, sizeof(text), "alert %d %d\n", buf_u8[0], buf_u8[1]);
-      state->msg_callback_text += text;
-      return;
-
-    default:
-      fprintf(stderr, "Invalid content_type: %d\n", content_type);
-      state->msg_callback_ok = false;
-  }
-}
-
-static int LegacyOCSPCallback(SSL *ssl, void *arg) {
-  const TestConfig *config = GetTestConfig(ssl);
-  if (!SSL_is_server(ssl)) {
-    return !config->fail_ocsp_callback;
-  }
-
-  if (!config->ocsp_response.empty() &&
-      config->set_ocsp_in_callback &&
-      !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(),
-                             config->ocsp_response.size())) {
-    return SSL_TLSEXT_ERR_ALERT_FATAL;
-  }
-  if (config->fail_ocsp_callback) {
-    return SSL_TLSEXT_ERR_ALERT_FATAL;
-  }
-  if (config->decline_ocsp_callback) {
-    return SSL_TLSEXT_ERR_NOACK;
-  }
-  return SSL_TLSEXT_ERR_OK;
-}
-
 // Connect returns a new socket connected to localhost on |port| or -1 on
 // error.
 static int Connect(uint16_t port) {
@@ -1162,231 +187,6 @@
   const int sock_;
 };
 
-static void ssl_ctx_add_session(SSL_SESSION *session, void *void_param) {
-  SSL_CTX *ctx = reinterpret_cast<SSL_CTX *>(void_param);
-  bssl::UniquePtr<SSL_SESSION> new_session = bssl::SSL_SESSION_dup(
-      session, SSL_SESSION_INCLUDE_NONAUTH | SSL_SESSION_INCLUDE_TICKET);
-  if (new_session != nullptr) {
-    SSL_CTX_add_session(ctx, new_session.get());
-  }
-}
-
-static bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx,
-                                         const TestConfig *config) {
-  bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(
-      config->is_dtls ? DTLS_method() : TLS_method()));
-  if (!ssl_ctx) {
-    return nullptr;
-  }
-
-  SSL_CTX_set0_buffer_pool(ssl_ctx.get(), g_pool);
-
-  // Enable TLS 1.3 for tests.
-  if (!config->is_dtls &&
-      !SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION)) {
-    return nullptr;
-  }
-
-  std::string cipher_list = "ALL";
-  if (!config->cipher.empty()) {
-    cipher_list = config->cipher;
-    SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE);
-  }
-  if (!SSL_CTX_set_strict_cipher_list(ssl_ctx.get(), cipher_list.c_str())) {
-    return nullptr;
-  }
-
-  if (config->async && config->is_server) {
-    // Disable the internal session cache. To test asynchronous session lookup,
-    // we use an external session cache.
-    SSL_CTX_set_session_cache_mode(
-        ssl_ctx.get(), SSL_SESS_CACHE_BOTH | SSL_SESS_CACHE_NO_INTERNAL);
-    SSL_CTX_sess_set_get_cb(ssl_ctx.get(), GetSessionCallback);
-  } else {
-    SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_BOTH);
-  }
-
-  SSL_CTX_set_select_certificate_cb(ssl_ctx.get(), SelectCertificateCallback);
-
-  if (config->use_old_client_cert_callback) {
-    SSL_CTX_set_client_cert_cb(ssl_ctx.get(), ClientCertCallback);
-  }
-
-  SSL_CTX_set_next_protos_advertised_cb(
-      ssl_ctx.get(), NextProtosAdvertisedCallback, NULL);
-  if (!config->select_next_proto.empty()) {
-    SSL_CTX_set_next_proto_select_cb(ssl_ctx.get(), NextProtoSelectCallback,
-                                     NULL);
-  }
-
-  if (!config->select_alpn.empty() || config->decline_alpn ||
-      config->select_empty_alpn) {
-    SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
-  }
-
-  SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
-
-  SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
-
-  SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
-  SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
-
-  if (config->use_ticket_callback) {
-    SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx.get(), TicketKeyCallback);
-  }
-
-  if (config->enable_client_custom_extension &&
-      !SSL_CTX_add_client_custom_ext(
-          ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
-          CustomExtensionFreeCallback, kCustomExtensionAddArg,
-          CustomExtensionParseCallback, kCustomExtensionParseArg)) {
-    return nullptr;
-  }
-
-  if (config->enable_server_custom_extension &&
-      !SSL_CTX_add_server_custom_ext(
-          ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
-          CustomExtensionFreeCallback, kCustomExtensionAddArg,
-          CustomExtensionParseCallback, kCustomExtensionParseArg)) {
-    return nullptr;
-  }
-
-  if (!config->use_custom_verify_callback) {
-    SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), CertVerifyCallback, NULL);
-  }
-
-  if (!config->signed_cert_timestamps.empty() &&
-      !SSL_CTX_set_signed_cert_timestamp_list(
-          ssl_ctx.get(), (const uint8_t *)config->signed_cert_timestamps.data(),
-          config->signed_cert_timestamps.size())) {
-    return 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 if (config->use_client_ca_list == "<EMPTY>") {
-      bssl::UniquePtr<STACK_OF(X509_NAME)> names;
-      SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
-    } 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) {
-    SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
-  }
-
-  if (!config->expected_server_name.empty()) {
-    SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), ServerNameCallback);
-  }
-
-  if (!config->ticket_key.empty() &&
-      !SSL_CTX_set_tlsext_ticket_keys(ssl_ctx.get(), config->ticket_key.data(),
-                                      config->ticket_key.size())) {
-    return nullptr;
-  }
-
-  if (config->enable_early_data) {
-    SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
-  }
-
-  SSL_CTX_set_tls13_variant(
-      ssl_ctx.get(), static_cast<enum tls13_variant_t>(config->tls13_variant));
-
-  if (config->allow_unknown_alpn_protos) {
-    SSL_CTX_set_allow_unknown_alpn_protos(ssl_ctx.get(), 1);
-  }
-
-  if (config->enable_ed25519) {
-    SSL_CTX_set_ed25519_enabled(ssl_ctx.get(), 1);
-  }
-  if (config->no_rsa_pss_rsae_certs) {
-    SSL_CTX_set_rsa_pss_rsae_certs_enabled(ssl_ctx.get(), 0);
-  }
-
-  if (!config->verify_prefs.empty()) {
-    std::vector<uint16_t> u16s(config->verify_prefs.begin(),
-                               config->verify_prefs.end());
-    if (!SSL_CTX_set_verify_algorithm_prefs(ssl_ctx.get(), u16s.data(),
-                                            u16s.size())) {
-      return nullptr;
-    }
-  }
-
-  SSL_CTX_set_msg_callback(ssl_ctx.get(), MessageCallback);
-
-  if (config->allow_false_start_without_alpn) {
-    SSL_CTX_set_false_start_allowed_without_alpn(ssl_ctx.get(), 1);
-  }
-
-  if (config->use_ocsp_callback) {
-    SSL_CTX_set_tlsext_status_cb(ssl_ctx.get(), LegacyOCSPCallback);
-  }
-
-  if (old_ctx) {
-    uint8_t keys[48];
-    if (!SSL_CTX_get_tlsext_ticket_keys(old_ctx, &keys, sizeof(keys)) ||
-        !SSL_CTX_set_tlsext_ticket_keys(ssl_ctx.get(), keys, sizeof(keys))) {
-      return nullptr;
-    }
-    lh_SSL_SESSION_doall_arg(old_ctx->sessions, ssl_ctx_add_session,
-                             ssl_ctx.get());
-  }
-
-  if (config->install_cert_compression_algs &&
-      (!SSL_CTX_add_cert_compression_alg(
-           ssl_ctx.get(), 0xff02,
-           [](SSL *ssl, CBB *out, bssl::Span<const uint8_t> in) -> bool {
-             if (!CBB_add_u8(out, 1) ||
-                 !CBB_add_u8(out, 2) ||
-                 !CBB_add_u8(out, 3) ||
-                 !CBB_add_u8(out, 4) ||
-                 !CBB_add_bytes(out, in.data(), in.size())) {
-               return false;
-             }
-             return true;
-           },
-           [](SSL *ssl, bssl::UniquePtr<CRYPTO_BUFFER> *out,
-              size_t uncompressed_len, bssl::Span<const uint8_t> in) -> bool {
-             if (in.size() < 4 || in[0] != 1 || in[1] != 2 || in[2] != 3 ||
-                 in[3] != 4 || uncompressed_len != in.size() - 4) {
-               return false;
-             }
-             const bssl::Span<const uint8_t> uncompressed(in.subspan(4));
-             out->reset(CRYPTO_BUFFER_new(uncompressed.data(),
-                                          uncompressed.size(), nullptr));
-             return true;
-           }) ||
-       !SSL_CTX_add_cert_compression_alg(
-           ssl_ctx.get(), 0xff01,
-           [](SSL *ssl, CBB *out, bssl::Span<const uint8_t> in) -> bool {
-             if (in.size() < 2 || in[0] != 0 || in[1] != 0) {
-               return false;
-             }
-             return CBB_add_bytes(out, in.data() + 2, in.size() - 2);
-           },
-           [](SSL *ssl, bssl::UniquePtr<CRYPTO_BUFFER> *out,
-              size_t uncompressed_len, bssl::Span<const uint8_t> in) -> bool {
-             if (uncompressed_len != 2 + in.size()) {
-               return false;
-             }
-             std::unique_ptr<uint8_t[]> buf(new uint8_t[2 + in.size()]);
-             buf[0] = 0;
-             buf[1] = 0;
-             OPENSSL_memcpy(&buf[2], in.data(), in.size());
-             out->reset(CRYPTO_BUFFER_new(buf.get(), 2 + in.size(), nullptr));
-             return true;
-           }))) {
-    fprintf(stderr, "SSL_CTX_add_cert_compression_alg failed.\n");
-    abort();
-  }
-
-  return ssl_ctx;
-}
-
 // RetryAsync is called after a failed operation on |ssl| with return code
 // |ret|. If the operation should be retried, it simulates one asynchronous
 // event and returns true. Otherwise it returns false.
@@ -1934,219 +734,6 @@
   return true;
 }
 
-static bssl::UniquePtr<SSL> NewSSL(SSL_CTX *ssl_ctx, const TestConfig *config,
-                                   SSL_SESSION *session, bool is_resume,
-                                   std::unique_ptr<TestState> test_state) {
-  bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
-  if (!ssl) {
-    return nullptr;
-  }
-
-  if (!SetTestConfig(ssl.get(), config)) {
-    return nullptr;
-  }
-  if (test_state != nullptr) {
-    if (!SetTestState(ssl.get(), std::move(test_state))) {
-      return nullptr;
-    }
-    GetTestState(ssl.get())->is_resume = is_resume;
-  }
-
-  if (config->fallback_scsv &&
-      !SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
-    return nullptr;
-  }
-  // Install the certificate synchronously if nothing else will handle it.
-  if (!config->use_early_callback &&
-      !config->use_old_client_cert_callback &&
-      !config->async &&
-      !InstallCertificate(ssl.get())) {
-    return nullptr;
-  }
-  if (!config->use_old_client_cert_callback) {
-    SSL_set_cert_cb(ssl.get(), CertCallback, nullptr);
-  }
-  int mode = SSL_VERIFY_NONE;
-  if (config->require_any_client_certificate) {
-    mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-  }
-  if (config->verify_peer) {
-    mode = SSL_VERIFY_PEER;
-  }
-  if (config->verify_peer_if_no_obc) {
-    // Set SSL_VERIFY_FAIL_IF_NO_PEER_CERT so testing whether client
-    // certificates were requested is easy.
-    mode = SSL_VERIFY_PEER | SSL_VERIFY_PEER_IF_NO_OBC |
-           SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-  }
-  if (config->use_custom_verify_callback) {
-    SSL_set_custom_verify(ssl.get(), mode, CustomVerifyCallback);
-  } else if (mode != SSL_VERIFY_NONE) {
-    SSL_set_verify(ssl.get(), mode, NULL);
-  }
-  if (config->false_start) {
-    SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START);
-  }
-  if (config->cbc_record_splitting) {
-    SSL_set_mode(ssl.get(), SSL_MODE_CBC_RECORD_SPLITTING);
-  }
-  if (config->partial_write) {
-    SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_PARTIAL_WRITE);
-  }
-  if (config->no_tls13) {
-    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_3);
-  }
-  if (config->no_tls12) {
-    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_2);
-  }
-  if (config->no_tls11) {
-    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_1);
-  }
-  if (config->no_tls1) {
-    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1);
-  }
-  if (!config->expected_channel_id.empty() ||
-      config->enable_channel_id) {
-    SSL_set_tls_channel_id_enabled(ssl.get(), 1);
-  }
-  if (!config->send_channel_id.empty()) {
-    SSL_set_tls_channel_id_enabled(ssl.get(), 1);
-    if (!config->async) {
-      // The async case will be supplied by |ChannelIdCallback|.
-      bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(config->send_channel_id);
-      if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
-        return nullptr;
-      }
-    }
-  }
-  if (!config->send_token_binding_params.empty()) {
-    SSL_set_token_binding_params(ssl.get(),
-                                 reinterpret_cast<const uint8_t *>(
-                                     config->send_token_binding_params.data()),
-                                 config->send_token_binding_params.length());
-  }
-  if (!config->host_name.empty() &&
-      !SSL_set_tlsext_host_name(ssl.get(), config->host_name.c_str())) {
-    return nullptr;
-  }
-  if (!config->advertise_alpn.empty() &&
-      SSL_set_alpn_protos(ssl.get(),
-                          (const uint8_t *)config->advertise_alpn.data(),
-                          config->advertise_alpn.size()) != 0) {
-    return nullptr;
-  }
-  if (!config->psk.empty()) {
-    SSL_set_psk_client_callback(ssl.get(), PskClientCallback);
-    SSL_set_psk_server_callback(ssl.get(), PskServerCallback);
-  }
-  if (!config->psk_identity.empty() &&
-      !SSL_use_psk_identity_hint(ssl.get(), config->psk_identity.c_str())) {
-    return nullptr;
-  }
-  if (!config->srtp_profiles.empty() &&
-      !SSL_set_srtp_profiles(ssl.get(), config->srtp_profiles.c_str())) {
-    return nullptr;
-  }
-  if (config->enable_ocsp_stapling) {
-    SSL_enable_ocsp_stapling(ssl.get());
-  }
-  if (config->enable_signed_cert_timestamps) {
-    SSL_enable_signed_cert_timestamps(ssl.get());
-  }
-  if (config->min_version != 0 &&
-      !SSL_set_min_proto_version(ssl.get(), (uint16_t)config->min_version)) {
-    return nullptr;
-  }
-  if (config->max_version != 0 &&
-      !SSL_set_max_proto_version(ssl.get(), (uint16_t)config->max_version)) {
-    return nullptr;
-  }
-  if (config->mtu != 0) {
-    SSL_set_options(ssl.get(), SSL_OP_NO_QUERY_MTU);
-    SSL_set_mtu(ssl.get(), config->mtu);
-  }
-  if (config->install_ddos_callback) {
-    SSL_CTX_set_dos_protection_cb(ssl_ctx, DDoSCallback);
-  }
-  SSL_set_shed_handshake_config(ssl.get(), true);
-  if (config->renegotiate_once) {
-    SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_once);
-  }
-  if (config->renegotiate_freely ||
-      config->forbid_renegotiation_after_handshake) {
-    // |forbid_renegotiation_after_handshake| will disable renegotiation later.
-    SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_freely);
-  }
-  if (config->renegotiate_ignore) {
-    SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_ignore);
-  }
-  if (!config->check_close_notify) {
-    SSL_set_quiet_shutdown(ssl.get(), 1);
-  }
-  if (config->p384_only) {
-    int nid = NID_secp384r1;
-    if (!SSL_set1_curves(ssl.get(), &nid, 1)) {
-      return nullptr;
-    }
-  }
-  if (config->enable_all_curves) {
-    static const int kAllCurves[] = {
-        NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1,
-        NID_secp521r1, NID_X25519,
-    };
-    if (!SSL_set1_curves(ssl.get(), kAllCurves,
-                         OPENSSL_ARRAY_SIZE(kAllCurves))) {
-      return nullptr;
-    }
-  }
-  if (config->initial_timeout_duration_ms > 0) {
-    DTLSv1_set_initial_timeout_duration(ssl.get(),
-                                        config->initial_timeout_duration_ms);
-  }
-  if (config->max_cert_list > 0) {
-    SSL_set_max_cert_list(ssl.get(), config->max_cert_list);
-  }
-  if (config->retain_only_sha256_client_cert) {
-    SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
-  }
-  if (config->max_send_fragment > 0) {
-    SSL_set_max_send_fragment(ssl.get(), config->max_send_fragment);
-  }
-  if (config->dummy_pq_padding_len > 0 &&
-      !SSL_set_dummy_pq_padding_size(ssl.get(), config->dummy_pq_padding_len)) {
-    return nullptr;
-  }
-  if (!config->quic_transport_params.empty()) {
-    if (!SSL_set_quic_transport_params(
-            ssl.get(),
-            reinterpret_cast<const uint8_t *>(
-                config->quic_transport_params.data()),
-            config->quic_transport_params.size())) {
-      return nullptr;
-    }
-  }
-
-  if (session != NULL) {
-    if (!config->is_server) {
-      if (SSL_set_session(ssl.get(), session) != 1) {
-        return nullptr;
-      }
-    } else if (config->async) {
-      // The internal session cache is disabled, so install the session
-      // manually.
-      SSL_SESSION_up_ref(session);
-      GetTestState(ssl.get())->pending_session.reset(session);
-    }
-  }
-
-  if (SSL_get_current_cipher(ssl.get()) != nullptr) {
-    fprintf(stderr, "non-null cipher before handshake\n");
-    return nullptr;
-  }
-
-  return ssl;
-}
-
 static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
                        bssl::UniquePtr<SSL> *ssl_uniqueptr,
                        const TestConfig *config, bool is_resume, bool is_retry,
@@ -2160,8 +747,8 @@
                          SSL_CTX *ssl_ctx, const TestConfig *config,
                          const TestConfig *retry_config, bool is_resume,
                          SSL_SESSION *session, SettingsWriter *writer) {
-  bssl::UniquePtr<SSL> ssl = NewSSL(ssl_ctx, config, session, is_resume,
-                                    std::unique_ptr<TestState>(new TestState));
+  bssl::UniquePtr<SSL> ssl = config->NewSSL(
+      ssl_ctx, session, is_resume, std::unique_ptr<TestState>(new TestState));
   if (!ssl) {
     return false;
   }
@@ -2183,7 +770,7 @@
     return false;
   }
   if (config->is_dtls) {
-    bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock);
+    bssl::UniquePtr<BIO> packeted = PacketedBioCreate(GetClock());
     if (!packeted) {
       return false;
     }
@@ -2280,19 +867,20 @@
 
   if (!config->implicit_handshake) {
     if (config->handoff) {
-      bssl::UniquePtr<SSL_CTX> ctx_handoff = SetupCtx(ssl->ctx, config);
+      bssl::UniquePtr<SSL_CTX> ctx_handoff = config->SetupCtx(ssl->ctx);
       if (!ctx_handoff) {
         return false;
       }
       SSL_CTX_set_handoff_mode(ctx_handoff.get(), 1);
 
       bssl::UniquePtr<SSL> ssl_handoff =
-          NewSSL(ctx_handoff.get(), config, nullptr, false, nullptr);
+          config->NewSSL(ctx_handoff.get(), nullptr, false, nullptr);
       if (!ssl_handoff) {
         return false;
       }
       SSL_set_accept_state(ssl_handoff.get());
-      if (!MoveExData(ssl_handoff.get(), ssl)) {
+      if (!MoveTestConfig(ssl_handoff.get(), ssl) ||
+          !MoveTestState(ssl_handoff.get(), ssl)) {
         return false;
       }
       MoveBIOs(ssl_handoff.get(), ssl);
@@ -2322,7 +910,8 @@
       }
 
       MoveBIOs(ssl, ssl_handoff.get());
-      if (!MoveExData(ssl, ssl_handoff.get())) {
+      if (!MoveTestConfig(ssl, ssl_handoff.get()) ||
+          !MoveTestState(ssl, ssl_handoff.get())) {
         return false;
       }
 
@@ -2354,17 +943,18 @@
         return false;
       }
 
-      bssl::UniquePtr<SSL_CTX> ctx_handback = SetupCtx(ssl->ctx, config);
+      bssl::UniquePtr<SSL_CTX> ctx_handback = config->SetupCtx(ssl->ctx);
       if (!ctx_handback) {
         return false;
       }
       bssl::UniquePtr<SSL> ssl_handback =
-          NewSSL(ctx_handback.get(), config, nullptr, false, nullptr);
+          config->NewSSL(ctx_handback.get(), nullptr, false, nullptr);
       if (!ssl_handback) {
         return false;
       }
       MoveBIOs(ssl_handback.get(), ssl);
-      if (!MoveExData(ssl_handback.get(), ssl)) {
+      if (!MoveTestConfig(ssl_handback.get(), ssl) ||
+          !MoveTestState(ssl_handback.get(), ssl)) {
         return false;
       }
 
@@ -2391,8 +981,7 @@
       return false;
     }
 
-    lh_SSL_SESSION_doall_arg(ssl->ctx->sessions, ssl_ctx_add_session,
-                             session_ctx);
+    CopySessions(session_ctx, ssl->ctx);
 
     if (is_resume && !is_retry && !config->is_server &&
         config->expect_no_offer_early_data && SSL_in_early_data(ssl)) {
@@ -2702,11 +1291,6 @@
 #endif
 
   CRYPTO_library_init();
-  g_config_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
-  g_state_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, TestStateExFree);
-  if (g_config_index < 0 || g_state_index < 0) {
-    return 1;
-  }
 
   TestConfig initial_config, resume_config, retry_config;
   if (!ParseConfig(argc - 1, argv + 1, &initial_config, &resume_config,
@@ -2714,20 +1298,13 @@
     return Usage(argv[0]);
   }
 
-  g_pool = CRYPTO_BUFFER_POOL_new();
-
-  // Some code treats the zero time special, so initialize the clock to a
-  // non-zero time.
-  g_clock.tv_sec = 1234;
-  g_clock.tv_usec = 1234;
-
   bssl::UniquePtr<SSL_CTX> ssl_ctx;
 
   bssl::UniquePtr<SSL_SESSION> session;
   for (int i = 0; i < initial_config.resume_count + 1; i++) {
     bool is_resume = i > 0;
     TestConfig *config = is_resume ? &resume_config : &initial_config;
-    ssl_ctx = SetupCtx(ssl_ctx.get(), config);
+    ssl_ctx = config->SetupCtx(ssl_ctx.get());
     if (!ssl_ctx) {
       ERR_print_errors_fp(stderr);
       return 1;
@@ -2757,7 +1334,7 @@
     }
 
     if (config->resumption_delay != 0) {
-      g_clock.tv_sec += config->resumption_delay;
+      AdvanceClock(config->resumption_delay);
     }
   }
 
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 0ae3a73..f7804d6 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -14,6 +14,7 @@
 
 #include "test_config.h"
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -21,6 +22,12 @@
 #include <memory>
 
 #include <openssl/base64.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+
+#include "../../crypto/internal.h"
+#include "../internal.h"
+#include "test_state.h"
 
 namespace {
 
@@ -339,3 +346,1348 @@
 
   return true;
 }
+
+static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
+static int g_config_index = 0;
+static CRYPTO_BUFFER_POOL *g_pool = nullptr;
+
+static void init_once() {
+  g_config_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+  if (g_config_index < 0) {
+    abort();
+  }
+  g_pool = CRYPTO_BUFFER_POOL_new();
+  if (!g_pool) {
+    abort();
+  }
+}
+
+bool SetTestConfig(SSL *ssl, const TestConfig *config) {
+  CRYPTO_once(&once, init_once);
+  return SSL_set_ex_data(ssl, g_config_index, (void *)config) == 1;
+}
+
+const TestConfig *GetTestConfig(const SSL *ssl) {
+  CRYPTO_once(&once, init_once);
+  return (const TestConfig *)SSL_get_ex_data(ssl, g_config_index);
+}
+
+bool MoveTestConfig(SSL *dest, SSL *src) {
+  const TestConfig *config = GetTestConfig(src);
+  if (!SSL_set_ex_data(src, g_config_index, nullptr) ||
+      !SSL_set_ex_data(dest, g_config_index, (void *)config)) {
+    return false;
+  }
+
+  return true;
+}
+
+static int LegacyOCSPCallback(SSL *ssl, void *arg) {
+  const TestConfig *config = GetTestConfig(ssl);
+  if (!SSL_is_server(ssl)) {
+    return !config->fail_ocsp_callback;
+  }
+
+  if (!config->ocsp_response.empty() && config->set_ocsp_in_callback &&
+      !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(),
+                             config->ocsp_response.size())) {
+    return SSL_TLSEXT_ERR_ALERT_FATAL;
+  }
+  if (config->fail_ocsp_callback) {
+    return SSL_TLSEXT_ERR_ALERT_FATAL;
+  }
+  if (config->decline_ocsp_callback) {
+    return SSL_TLSEXT_ERR_NOACK;
+  }
+  return SSL_TLSEXT_ERR_OK;
+}
+
+// kCustomExtensionValue is the extension value that the custom extension
+// callbacks will add.
+static const uint16_t kCustomExtensionValue = 1234;
+static void *const kCustomExtensionAddArg =
+    reinterpret_cast<void *>(kCustomExtensionValue);
+static void *const kCustomExtensionParseArg =
+    reinterpret_cast<void *>(kCustomExtensionValue + 1);
+static const char kCustomExtensionContents[] = "custom extension";
+
+static int CustomExtensionAddCallback(SSL *ssl, unsigned extension_value,
+                                      const uint8_t **out, size_t *out_len,
+                                      int *out_alert_value, void *add_arg) {
+  if (extension_value != kCustomExtensionValue ||
+      add_arg != kCustomExtensionAddArg) {
+    abort();
+  }
+
+  if (GetTestConfig(ssl)->custom_extension_skip) {
+    return 0;
+  }
+  if (GetTestConfig(ssl)->custom_extension_fail_add) {
+    return -1;
+  }
+
+  *out = reinterpret_cast<const uint8_t *>(kCustomExtensionContents);
+  *out_len = sizeof(kCustomExtensionContents) - 1;
+
+  return 1;
+}
+
+static void CustomExtensionFreeCallback(SSL *ssl, unsigned extension_value,
+                                        const uint8_t *out, void *add_arg) {
+  if (extension_value != kCustomExtensionValue ||
+      add_arg != kCustomExtensionAddArg ||
+      out != reinterpret_cast<const uint8_t *>(kCustomExtensionContents)) {
+    abort();
+  }
+}
+
+static int CustomExtensionParseCallback(SSL *ssl, unsigned extension_value,
+                                        const uint8_t *contents,
+                                        size_t contents_len,
+                                        int *out_alert_value, void *parse_arg) {
+  if (extension_value != kCustomExtensionValue ||
+      parse_arg != kCustomExtensionParseArg) {
+    abort();
+  }
+
+  if (contents_len != sizeof(kCustomExtensionContents) - 1 ||
+      OPENSSL_memcmp(contents, kCustomExtensionContents, contents_len) != 0) {
+    *out_alert_value = SSL_AD_DECODE_ERROR;
+    return 0;
+  }
+
+  return 1;
+}
+
+static int ServerNameCallback(SSL *ssl, int *out_alert, void *arg) {
+  // SNI must be accessible from the SNI callback.
+  const TestConfig *config = GetTestConfig(ssl);
+  const char *server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (server_name == nullptr ||
+      std::string(server_name) != config->expected_server_name) {
+    fprintf(stderr, "servername mismatch (got %s; want %s)\n", server_name,
+            config->expected_server_name.c_str());
+    return SSL_TLSEXT_ERR_ALERT_FATAL;
+  }
+
+  return SSL_TLSEXT_ERR_OK;
+}
+
+static int NextProtoSelectCallback(SSL *ssl, uint8_t **out, uint8_t *outlen,
+                                   const uint8_t *in, unsigned inlen,
+                                   void *arg) {
+  const TestConfig *config = GetTestConfig(ssl);
+  if (config->select_next_proto.empty()) {
+    return SSL_TLSEXT_ERR_NOACK;
+  }
+
+  *out = (uint8_t *)config->select_next_proto.data();
+  *outlen = config->select_next_proto.size();
+  return SSL_TLSEXT_ERR_OK;
+}
+
+static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out,
+                                        unsigned int *out_len, void *arg) {
+  const TestConfig *config = GetTestConfig(ssl);
+  if (config->advertise_npn.empty()) {
+    return SSL_TLSEXT_ERR_NOACK;
+  }
+
+  *out = (const uint8_t *)config->advertise_npn.data();
+  *out_len = config->advertise_npn.size();
+  return SSL_TLSEXT_ERR_OK;
+}
+
+static void MessageCallback(int is_write, int version, int content_type,
+                            const void *buf, size_t len, SSL *ssl, void *arg) {
+  const uint8_t *buf_u8 = reinterpret_cast<const uint8_t *>(buf);
+  const TestConfig *config = GetTestConfig(ssl);
+  TestState *state = GetTestState(ssl);
+  if (!state->msg_callback_ok) {
+    return;
+  }
+
+  if (content_type == SSL3_RT_HEADER) {
+    if (len !=
+        (config->is_dtls ? DTLS1_RT_HEADER_LENGTH : SSL3_RT_HEADER_LENGTH)) {
+      fprintf(stderr, "Incorrect length for record header: %zu\n", len);
+      state->msg_callback_ok = false;
+    }
+    return;
+  }
+
+  state->msg_callback_text += is_write ? "write " : "read ";
+  switch (content_type) {
+    case 0:
+      if (version != SSL2_VERSION) {
+        fprintf(stderr, "Incorrect version for V2ClientHello: %x\n", version);
+        state->msg_callback_ok = false;
+        return;
+      }
+      state->msg_callback_text += "v2clienthello\n";
+      return;
+
+    case SSL3_RT_HANDSHAKE: {
+      CBS cbs;
+      CBS_init(&cbs, buf_u8, len);
+      uint8_t type;
+      uint32_t msg_len;
+      if (!CBS_get_u8(&cbs, &type) ||
+          // TODO(davidben): Reporting on entire messages would be more
+          // consistent than fragments.
+          (config->is_dtls &&
+           !CBS_skip(&cbs, 3 /* total */ + 2 /* seq */ + 3 /* frag_off */)) ||
+          !CBS_get_u24(&cbs, &msg_len) || !CBS_skip(&cbs, msg_len) ||
+          CBS_len(&cbs) != 0) {
+        fprintf(stderr, "Could not parse handshake message.\n");
+        state->msg_callback_ok = false;
+        return;
+      }
+      char text[16];
+      snprintf(text, sizeof(text), "hs %d\n", type);
+      state->msg_callback_text += text;
+      return;
+    }
+
+    case SSL3_RT_CHANGE_CIPHER_SPEC:
+      if (len != 1 || buf_u8[0] != 1) {
+        fprintf(stderr, "Invalid ChangeCipherSpec.\n");
+        state->msg_callback_ok = false;
+        return;
+      }
+      state->msg_callback_text += "ccs\n";
+      return;
+
+    case SSL3_RT_ALERT:
+      if (len != 2) {
+        fprintf(stderr, "Invalid alert.\n");
+        state->msg_callback_ok = false;
+        return;
+      }
+      char text[16];
+      snprintf(text, sizeof(text), "alert %d %d\n", buf_u8[0], buf_u8[1]);
+      state->msg_callback_text += text;
+      return;
+
+    default:
+      fprintf(stderr, "Invalid content_type: %d\n", content_type);
+      state->msg_callback_ok = false;
+  }
+}
+
+static int TicketKeyCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+                             EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+                             int encrypt) {
+  if (!encrypt) {
+    if (GetTestState(ssl)->ticket_decrypt_done) {
+      fprintf(stderr, "TicketKeyCallback called after completion.\n");
+      return -1;
+    }
+
+    GetTestState(ssl)->ticket_decrypt_done = true;
+  }
+
+  // This is just test code, so use the all-zeros key.
+  static const uint8_t kZeros[16] = {0};
+
+  if (encrypt) {
+    OPENSSL_memcpy(key_name, kZeros, sizeof(kZeros));
+    RAND_bytes(iv, 16);
+  } else if (OPENSSL_memcmp(key_name, kZeros, 16) != 0) {
+    return 0;
+  }
+
+  if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
+      !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
+    return -1;
+  }
+
+  if (!encrypt) {
+    return GetTestConfig(ssl)->renew_ticket ? 2 : 1;
+  }
+  return 1;
+}
+
+static int NewSessionCallback(SSL *ssl, SSL_SESSION *session) {
+  // This callback is called as the handshake completes. |SSL_get_session|
+  // must continue to work and, historically, |SSL_in_init| returned false at
+  // this point.
+  if (SSL_in_init(ssl) || SSL_get_session(ssl) == nullptr) {
+    fprintf(stderr, "Invalid state for NewSessionCallback.\n");
+    abort();
+  }
+
+  GetTestState(ssl)->got_new_session = true;
+  GetTestState(ssl)->new_session.reset(session);
+  return 1;
+}
+
+static void InfoCallback(const SSL *ssl, int type, int val) {
+  if (type == SSL_CB_HANDSHAKE_DONE) {
+    if (GetTestConfig(ssl)->handshake_never_done) {
+      fprintf(stderr, "Handshake unexpectedly completed.\n");
+      // Abort before any expected error code is printed, to ensure the overall
+      // test fails.
+      abort();
+    }
+    // This callback is called when the handshake completes. |SSL_get_session|
+    // must continue to work and |SSL_in_init| must return false.
+    if (SSL_in_init(ssl) || SSL_get_session(ssl) == nullptr) {
+      fprintf(stderr, "Invalid state for SSL_CB_HANDSHAKE_DONE.\n");
+      abort();
+    }
+    GetTestState(ssl)->handshake_done = true;
+
+    // Callbacks may be called again on a new handshake.
+    GetTestState(ssl)->ticket_decrypt_done = false;
+    GetTestState(ssl)->alpn_select_done = false;
+  }
+}
+
+static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
+  *out_pkey = GetTestState(ssl)->channel_id.release();
+}
+
+static SSL_SESSION *GetSessionCallback(SSL *ssl, const uint8_t *data, int len,
+                                       int *copy) {
+  TestState *async_state = GetTestState(ssl);
+  if (async_state->session) {
+    *copy = 0;
+    return async_state->session.release();
+  } else if (async_state->pending_session) {
+    return SSL_magic_pending_session_ptr();
+  } else {
+    return NULL;
+  }
+}
+
+static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
+  *out_clock = *GetClock();
+}
+
+static int AlpnSelectCallback(SSL *ssl, const uint8_t **out, uint8_t *outlen,
+                              const uint8_t *in, unsigned inlen, void *arg) {
+  if (GetTestState(ssl)->alpn_select_done) {
+    fprintf(stderr, "AlpnSelectCallback called after completion.\n");
+    exit(1);
+  }
+
+  GetTestState(ssl)->alpn_select_done = true;
+
+  const TestConfig *config = GetTestConfig(ssl);
+  if (config->decline_alpn) {
+    return SSL_TLSEXT_ERR_NOACK;
+  }
+
+  if (!config->expected_advertised_alpn.empty() &&
+      (config->expected_advertised_alpn.size() != inlen ||
+       OPENSSL_memcmp(config->expected_advertised_alpn.data(), in, inlen) !=
+           0)) {
+    fprintf(stderr, "bad ALPN select callback inputs\n");
+    exit(1);
+  }
+
+  assert(config->select_alpn.empty() || !config->select_empty_alpn);
+  *out = (const uint8_t *)config->select_alpn.data();
+  *outlen = config->select_alpn.size();
+  return SSL_TLSEXT_ERR_OK;
+}
+
+static bool CheckVerifyCallback(SSL *ssl) {
+  const TestConfig *config = GetTestConfig(ssl);
+  if (!config->expected_ocsp_response.empty()) {
+    const uint8_t *data;
+    size_t len;
+    SSL_get0_ocsp_response(ssl, &data, &len);
+    if (len == 0) {
+      fprintf(stderr, "OCSP response not available in verify callback\n");
+      return false;
+    }
+  }
+
+  if (GetTestState(ssl)->cert_verified) {
+    fprintf(stderr, "Certificate verified twice.\n");
+    return false;
+  }
+
+  return true;
+}
+
+static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) {
+  SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(
+      store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+  const TestConfig *config = GetTestConfig(ssl);
+  if (!CheckVerifyCallback(ssl)) {
+    return 0;
+  }
+
+  GetTestState(ssl)->cert_verified = true;
+  if (config->verify_fail) {
+    store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION;
+    return 0;
+  }
+
+  return 1;
+}
+
+bool LoadCertificate(bssl::UniquePtr<X509> *out_x509,
+                     bssl::UniquePtr<STACK_OF(X509)> *out_chain,
+                     const std::string &file) {
+  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
+  if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
+    return false;
+  }
+
+  out_x509->reset(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+  if (!*out_x509) {
+    return false;
+  }
+
+  out_chain->reset(sk_X509_new_null());
+  if (!*out_chain) {
+    return false;
+  }
+
+  // Keep reading the certificate chain.
+  for (;;) {
+    bssl::UniquePtr<X509> cert(
+        PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+    if (!cert) {
+      break;
+    }
+
+    if (!bssl::PushToStack(out_chain->get(), std::move(cert))) {
+      return false;
+    }
+  }
+
+  uint32_t err = ERR_peek_last_error();
+  if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
+      ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
+    return false;
+  }
+
+  ERR_clear_error();
+  return true;
+}
+
+bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file) {
+  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
+  if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
+    return nullptr;
+  }
+  return bssl::UniquePtr<EVP_PKEY>(
+      PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL));
+}
+
+static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
+                           bssl::UniquePtr<STACK_OF(X509)> *out_chain,
+                           bssl::UniquePtr<EVP_PKEY> *out_pkey) {
+  const TestConfig *config = GetTestConfig(ssl);
+
+  if (!config->signing_prefs.empty()) {
+    std::vector<uint16_t> u16s(config->signing_prefs.begin(),
+                               config->signing_prefs.end());
+    if (!SSL_set_signing_algorithm_prefs(ssl, u16s.data(), u16s.size())) {
+      return false;
+    }
+  }
+
+  if (!config->key_file.empty()) {
+    *out_pkey = LoadPrivateKey(config->key_file.c_str());
+    if (!*out_pkey) {
+      return false;
+    }
+  }
+  if (!config->cert_file.empty() &&
+      !LoadCertificate(out_x509, out_chain, config->cert_file.c_str())) {
+    return false;
+  }
+  if (!config->ocsp_response.empty() && !config->set_ocsp_in_callback &&
+      !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(),
+                             config->ocsp_response.size())) {
+    return false;
+  }
+  return true;
+}
+
+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());
+  if (!ret) {
+    return nullptr;
+  }
+
+  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 (!bssl::PushToStack(ret.get(), std::move(name))) {
+      return nullptr;
+    }
+  }
+
+  return ret;
+}
+
+static bool CheckCertificateRequest(SSL *ssl) {
+  const TestConfig *config = GetTestConfig(ssl);
+
+  if (!config->expected_certificate_types.empty()) {
+    const uint8_t *certificate_types;
+    size_t certificate_types_len =
+        SSL_get0_certificate_types(ssl, &certificate_types);
+    if (certificate_types_len != config->expected_certificate_types.size() ||
+        OPENSSL_memcmp(certificate_types,
+                       config->expected_certificate_types.data(),
+                       certificate_types_len) != 0) {
+      fprintf(stderr, "certificate types mismatch\n");
+      return false;
+    }
+  }
+
+  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;
+      }
+    }
+
+    const 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;
+}
+
+static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
+  if (!CheckCertificateRequest(ssl)) {
+    return -1;
+  }
+
+  if (GetTestConfig(ssl)->async && !GetTestState(ssl)->cert_ready) {
+    return -1;
+  }
+
+  bssl::UniquePtr<X509> x509;
+  bssl::UniquePtr<STACK_OF(X509)> chain;
+  bssl::UniquePtr<EVP_PKEY> pkey;
+  if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
+    return -1;
+  }
+
+  // Return zero for no certificate.
+  if (!x509) {
+    return 0;
+  }
+
+  // Chains and asynchronous private keys are not supported with client_cert_cb.
+  *out_x509 = x509.release();
+  *out_pkey = pkey.release();
+  return 1;
+}
+
+static ssl_private_key_result_t AsyncPrivateKeySign(
+    SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+    uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
+  TestState *test_state = GetTestState(ssl);
+  if (!test_state->private_key_result.empty()) {
+    fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n");
+    abort();
+  }
+
+  if (EVP_PKEY_id(test_state->private_key.get()) !=
+      SSL_get_signature_algorithm_key_type(signature_algorithm)) {
+    fprintf(stderr, "Key type does not match signature algorithm.\n");
+    abort();
+  }
+
+  // Determine the hash.
+  const EVP_MD *md = SSL_get_signature_algorithm_digest(signature_algorithm);
+  bssl::ScopedEVP_MD_CTX ctx;
+  EVP_PKEY_CTX *pctx;
+  if (!EVP_DigestSignInit(ctx.get(), &pctx, md, nullptr,
+                          test_state->private_key.get())) {
+    return ssl_private_key_failure;
+  }
+
+  // Configure additional signature parameters.
+  if (SSL_is_signature_algorithm_rsa_pss(signature_algorithm)) {
+    if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
+        !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */)) {
+      return ssl_private_key_failure;
+    }
+  }
+
+  // Write the signature into |test_state|.
+  size_t len = 0;
+  if (!EVP_DigestSign(ctx.get(), nullptr, &len, in, in_len)) {
+    return ssl_private_key_failure;
+  }
+  test_state->private_key_result.resize(len);
+  if (!EVP_DigestSign(ctx.get(), test_state->private_key_result.data(), &len,
+                      in, in_len)) {
+    return ssl_private_key_failure;
+  }
+  test_state->private_key_result.resize(len);
+
+  // The signature will be released asynchronously in |AsyncPrivateKeyComplete|.
+  return ssl_private_key_retry;
+}
+
+static ssl_private_key_result_t AsyncPrivateKeyDecrypt(SSL *ssl, uint8_t *out,
+                                                       size_t *out_len,
+                                                       size_t max_out,
+                                                       const uint8_t *in,
+                                                       size_t in_len) {
+  TestState *test_state = GetTestState(ssl);
+  if (!test_state->private_key_result.empty()) {
+    fprintf(stderr, "AsyncPrivateKeyDecrypt called with operation pending.\n");
+    abort();
+  }
+
+  RSA *rsa = EVP_PKEY_get0_RSA(test_state->private_key.get());
+  if (rsa == NULL) {
+    fprintf(stderr, "AsyncPrivateKeyDecrypt called with incorrect key type.\n");
+    abort();
+  }
+  test_state->private_key_result.resize(RSA_size(rsa));
+  if (!RSA_decrypt(rsa, out_len, test_state->private_key_result.data(),
+                   RSA_size(rsa), in, in_len, RSA_NO_PADDING)) {
+    return ssl_private_key_failure;
+  }
+
+  test_state->private_key_result.resize(*out_len);
+
+  // The decryption will be released asynchronously in |AsyncPrivateComplete|.
+  return ssl_private_key_retry;
+}
+
+static ssl_private_key_result_t AsyncPrivateKeyComplete(SSL *ssl, uint8_t *out,
+                                                        size_t *out_len,
+                                                        size_t max_out) {
+  TestState *test_state = GetTestState(ssl);
+  if (test_state->private_key_result.empty()) {
+    fprintf(stderr,
+            "AsyncPrivateKeyComplete called without operation pending.\n");
+    abort();
+  }
+
+  if (test_state->private_key_retries < 2) {
+    // Only return the decryption on the second attempt, to test both incomplete
+    // |decrypt| and |decrypt_complete|.
+    return ssl_private_key_retry;
+  }
+
+  if (max_out < test_state->private_key_result.size()) {
+    fprintf(stderr, "Output buffer too small.\n");
+    return ssl_private_key_failure;
+  }
+  OPENSSL_memcpy(out, test_state->private_key_result.data(),
+                 test_state->private_key_result.size());
+  *out_len = test_state->private_key_result.size();
+
+  test_state->private_key_result.clear();
+  test_state->private_key_retries = 0;
+  return ssl_private_key_success;
+}
+
+static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = {
+    AsyncPrivateKeySign,
+    AsyncPrivateKeyDecrypt,
+    AsyncPrivateKeyComplete,
+};
+
+static bool InstallCertificate(SSL *ssl) {
+  bssl::UniquePtr<X509> x509;
+  bssl::UniquePtr<STACK_OF(X509)> chain;
+  bssl::UniquePtr<EVP_PKEY> pkey;
+  if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
+    return false;
+  }
+
+  if (pkey) {
+    TestState *test_state = GetTestState(ssl);
+    const TestConfig *config = GetTestConfig(ssl);
+    if (config->async) {
+      test_state->private_key = std::move(pkey);
+      SSL_set_private_key_method(ssl, &g_async_private_key_method);
+    } else if (!SSL_use_PrivateKey(ssl, pkey.get())) {
+      return false;
+    }
+  }
+
+  if (x509 && !SSL_use_certificate(ssl, x509.get())) {
+    return false;
+  }
+
+  if (sk_X509_num(chain.get()) > 0 && !SSL_set1_chain(ssl, chain.get())) {
+    return false;
+  }
+
+  return true;
+}
+
+static enum ssl_select_cert_result_t SelectCertificateCallback(
+    const SSL_CLIENT_HELLO *client_hello) {
+  const TestConfig *config = GetTestConfig(client_hello->ssl);
+  GetTestState(client_hello->ssl)->early_callback_called = true;
+
+  if (!config->expected_server_name.empty()) {
+    const uint8_t *extension_data;
+    size_t extension_len;
+    CBS extension, server_name_list, host_name;
+    uint8_t name_type;
+
+    if (!SSL_early_callback_ctx_extension_get(
+            client_hello, TLSEXT_TYPE_server_name, &extension_data,
+            &extension_len)) {
+      fprintf(stderr, "Could not find server_name extension.\n");
+      return ssl_select_cert_error;
+    }
+
+    CBS_init(&extension, extension_data, extension_len);
+    if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
+        CBS_len(&extension) != 0 ||
+        !CBS_get_u8(&server_name_list, &name_type) ||
+        name_type != TLSEXT_NAMETYPE_host_name ||
+        !CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
+        CBS_len(&server_name_list) != 0) {
+      fprintf(stderr, "Could not decode server_name extension.\n");
+      return ssl_select_cert_error;
+    }
+
+    if (!CBS_mem_equal(&host_name,
+                       (const uint8_t *)config->expected_server_name.data(),
+                       config->expected_server_name.size())) {
+      fprintf(stderr, "Server name mismatch.\n");
+    }
+  }
+
+  if (config->fail_early_callback) {
+    return ssl_select_cert_error;
+  }
+
+  // Install the certificate in the early callback.
+  if (config->use_early_callback) {
+    bool early_callback_ready =
+        GetTestState(client_hello->ssl)->early_callback_ready;
+    if (config->async && !early_callback_ready) {
+      // Install the certificate asynchronously.
+      return ssl_select_cert_retry;
+    }
+    if (!InstallCertificate(client_hello->ssl)) {
+      return ssl_select_cert_error;
+    }
+  }
+  return ssl_select_cert_success;
+}
+
+bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const {
+  bssl::UniquePtr<SSL_CTX> ssl_ctx(
+      SSL_CTX_new(is_dtls ? DTLS_method() : TLS_method()));
+  if (!ssl_ctx) {
+    return nullptr;
+  }
+
+  CRYPTO_once(&once, init_once);
+  SSL_CTX_set0_buffer_pool(ssl_ctx.get(), g_pool);
+
+  // Enable TLS 1.3 for tests.
+  if (!is_dtls &&
+      !SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION)) {
+    return nullptr;
+  }
+
+  std::string cipher_list = "ALL";
+  if (!cipher.empty()) {
+    cipher_list = cipher;
+    SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE);
+  }
+  if (!SSL_CTX_set_strict_cipher_list(ssl_ctx.get(), cipher_list.c_str())) {
+    return nullptr;
+  }
+
+  if (async && is_server) {
+    // Disable the internal session cache. To test asynchronous session lookup,
+    // we use an external session cache.
+    SSL_CTX_set_session_cache_mode(
+        ssl_ctx.get(), SSL_SESS_CACHE_BOTH | SSL_SESS_CACHE_NO_INTERNAL);
+    SSL_CTX_sess_set_get_cb(ssl_ctx.get(), GetSessionCallback);
+  } else {
+    SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_BOTH);
+  }
+
+  SSL_CTX_set_select_certificate_cb(ssl_ctx.get(), SelectCertificateCallback);
+
+  if (use_old_client_cert_callback) {
+    SSL_CTX_set_client_cert_cb(ssl_ctx.get(), ClientCertCallback);
+  }
+
+  SSL_CTX_set_next_protos_advertised_cb(ssl_ctx.get(),
+                                        NextProtosAdvertisedCallback, NULL);
+  if (!select_next_proto.empty()) {
+    SSL_CTX_set_next_proto_select_cb(ssl_ctx.get(), NextProtoSelectCallback,
+                                     NULL);
+  }
+
+  if (!select_alpn.empty() || decline_alpn || select_empty_alpn) {
+    SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
+  }
+
+  SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
+
+  SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
+
+  SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
+  SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
+
+  if (use_ticket_callback) {
+    SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx.get(), TicketKeyCallback);
+  }
+
+  if (enable_client_custom_extension &&
+      !SSL_CTX_add_client_custom_ext(
+          ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
+          CustomExtensionFreeCallback, kCustomExtensionAddArg,
+          CustomExtensionParseCallback, kCustomExtensionParseArg)) {
+    return nullptr;
+  }
+
+  if (enable_server_custom_extension &&
+      !SSL_CTX_add_server_custom_ext(
+          ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
+          CustomExtensionFreeCallback, kCustomExtensionAddArg,
+          CustomExtensionParseCallback, kCustomExtensionParseArg)) {
+    return nullptr;
+  }
+
+  if (!use_custom_verify_callback) {
+    SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), CertVerifyCallback, NULL);
+  }
+
+  if (!signed_cert_timestamps.empty() &&
+      !SSL_CTX_set_signed_cert_timestamp_list(
+          ssl_ctx.get(), (const uint8_t *)signed_cert_timestamps.data(),
+          signed_cert_timestamps.size())) {
+    return nullptr;
+  }
+
+  if (!use_client_ca_list.empty()) {
+    if (use_client_ca_list == "<NULL>") {
+      SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
+    } else if (use_client_ca_list == "<EMPTY>") {
+      bssl::UniquePtr<STACK_OF(X509_NAME)> names;
+      SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
+    } else {
+      bssl::UniquePtr<STACK_OF(X509_NAME)> names =
+          DecodeHexX509Names(use_client_ca_list);
+      SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
+    }
+  }
+
+  if (enable_grease) {
+    SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
+  }
+
+  if (!expected_server_name.empty()) {
+    SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), ServerNameCallback);
+  }
+
+  if (!ticket_key.empty() &&
+      !SSL_CTX_set_tlsext_ticket_keys(ssl_ctx.get(), ticket_key.data(),
+                                      ticket_key.size())) {
+    return nullptr;
+  }
+
+  if (enable_early_data) {
+    SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
+  }
+
+  SSL_CTX_set_tls13_variant(ssl_ctx.get(),
+                            static_cast<enum tls13_variant_t>(tls13_variant));
+
+  if (allow_unknown_alpn_protos) {
+    SSL_CTX_set_allow_unknown_alpn_protos(ssl_ctx.get(), 1);
+  }
+
+  if (enable_ed25519) {
+    SSL_CTX_set_ed25519_enabled(ssl_ctx.get(), 1);
+  }
+  if (no_rsa_pss_rsae_certs) {
+    SSL_CTX_set_rsa_pss_rsae_certs_enabled(ssl_ctx.get(), 0);
+  }
+
+  if (!verify_prefs.empty()) {
+    std::vector<uint16_t> u16s(verify_prefs.begin(), verify_prefs.end());
+    if (!SSL_CTX_set_verify_algorithm_prefs(ssl_ctx.get(), u16s.data(),
+                                            u16s.size())) {
+      return nullptr;
+    }
+  }
+
+  SSL_CTX_set_msg_callback(ssl_ctx.get(), MessageCallback);
+
+  if (allow_false_start_without_alpn) {
+    SSL_CTX_set_false_start_allowed_without_alpn(ssl_ctx.get(), 1);
+  }
+
+  if (use_ocsp_callback) {
+    SSL_CTX_set_tlsext_status_cb(ssl_ctx.get(), LegacyOCSPCallback);
+  }
+
+  if (old_ctx) {
+    uint8_t keys[48];
+    if (!SSL_CTX_get_tlsext_ticket_keys(old_ctx, &keys, sizeof(keys)) ||
+        !SSL_CTX_set_tlsext_ticket_keys(ssl_ctx.get(), keys, sizeof(keys))) {
+      return nullptr;
+    }
+    CopySessions(ssl_ctx.get(), old_ctx);
+  }
+
+  if (install_cert_compression_algs &&
+      (!SSL_CTX_add_cert_compression_alg(
+           ssl_ctx.get(), 0xff02,
+           [](SSL *ssl, CBB *out, bssl::Span<const uint8_t> in) -> bool {
+             if (!CBB_add_u8(out, 1) || !CBB_add_u8(out, 2) ||
+                 !CBB_add_u8(out, 3) || !CBB_add_u8(out, 4) ||
+                 !CBB_add_bytes(out, in.data(), in.size())) {
+               return false;
+             }
+             return true;
+           },
+           [](SSL *ssl, bssl::UniquePtr<CRYPTO_BUFFER> *out,
+              size_t uncompressed_len, bssl::Span<const uint8_t> in) -> bool {
+             if (in.size() < 4 || in[0] != 1 || in[1] != 2 || in[2] != 3 ||
+                 in[3] != 4 || uncompressed_len != in.size() - 4) {
+               return false;
+             }
+             const bssl::Span<const uint8_t> uncompressed(in.subspan(4));
+             out->reset(CRYPTO_BUFFER_new(uncompressed.data(),
+                                          uncompressed.size(), nullptr));
+             return true;
+           }) ||
+       !SSL_CTX_add_cert_compression_alg(
+           ssl_ctx.get(), 0xff01,
+           [](SSL *ssl, CBB *out, bssl::Span<const uint8_t> in) -> bool {
+             if (in.size() < 2 || in[0] != 0 || in[1] != 0) {
+               return false;
+             }
+             return CBB_add_bytes(out, in.data() + 2, in.size() - 2);
+           },
+           [](SSL *ssl, bssl::UniquePtr<CRYPTO_BUFFER> *out,
+              size_t uncompressed_len, bssl::Span<const uint8_t> in) -> bool {
+             if (uncompressed_len != 2 + in.size()) {
+               return false;
+             }
+             std::unique_ptr<uint8_t[]> buf(new uint8_t[2 + in.size()]);
+             buf[0] = 0;
+             buf[1] = 0;
+             OPENSSL_memcpy(&buf[2], in.data(), in.size());
+             out->reset(CRYPTO_BUFFER_new(buf.get(), 2 + in.size(), nullptr));
+             return true;
+           }))) {
+    fprintf(stderr, "SSL_CTX_add_cert_compression_alg failed.\n");
+    abort();
+  }
+
+  return ssl_ctx;
+}
+
+static int DDoSCallback(const SSL_CLIENT_HELLO *client_hello) {
+  const TestConfig *config = GetTestConfig(client_hello->ssl);
+  return config->fail_ddos_callback ? 0 : 1;
+}
+
+static unsigned PskClientCallback(SSL *ssl, const char *hint,
+                                  char *out_identity, unsigned max_identity_len,
+                                  uint8_t *out_psk, unsigned max_psk_len) {
+  const TestConfig *config = GetTestConfig(ssl);
+
+  if (config->psk_identity.empty()) {
+    if (hint != nullptr) {
+      fprintf(stderr, "Server PSK hint was non-null.\n");
+      return 0;
+    }
+  } else if (hint == nullptr ||
+             strcmp(hint, config->psk_identity.c_str()) != 0) {
+    fprintf(stderr, "Server PSK hint did not match.\n");
+    return 0;
+  }
+
+  // Account for the trailing '\0' for the identity.
+  if (config->psk_identity.size() >= max_identity_len ||
+      config->psk.size() > max_psk_len) {
+    fprintf(stderr, "PSK buffers too small\n");
+    return 0;
+  }
+
+  BUF_strlcpy(out_identity, config->psk_identity.c_str(), max_identity_len);
+  OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
+  return config->psk.size();
+}
+
+static unsigned PskServerCallback(SSL *ssl, const char *identity,
+                                  uint8_t *out_psk, unsigned max_psk_len) {
+  const TestConfig *config = GetTestConfig(ssl);
+
+  if (strcmp(identity, config->psk_identity.c_str()) != 0) {
+    fprintf(stderr, "Client PSK identity did not match.\n");
+    return 0;
+  }
+
+  if (config->psk.size() > max_psk_len) {
+    fprintf(stderr, "PSK buffers too small\n");
+    return 0;
+  }
+
+  OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
+  return config->psk.size();
+}
+
+static ssl_verify_result_t CustomVerifyCallback(SSL *ssl, uint8_t *out_alert) {
+  const TestConfig *config = GetTestConfig(ssl);
+  if (!CheckVerifyCallback(ssl)) {
+    return ssl_verify_invalid;
+  }
+
+  if (config->async && !GetTestState(ssl)->custom_verify_ready) {
+    return ssl_verify_retry;
+  }
+
+  GetTestState(ssl)->cert_verified = true;
+  if (config->verify_fail) {
+    return ssl_verify_invalid;
+  }
+
+  return ssl_verify_ok;
+}
+
+static int CertCallback(SSL *ssl, void *arg) {
+  const TestConfig *config = GetTestConfig(ssl);
+
+  // Check the CertificateRequest metadata is as expected.
+  if (!SSL_is_server(ssl) && !CheckCertificateRequest(ssl)) {
+    return -1;
+  }
+
+  if (config->fail_cert_callback) {
+    return 0;
+  }
+
+  // The certificate will be installed via other means.
+  if (!config->async || config->use_early_callback) {
+    return 1;
+  }
+
+  if (!GetTestState(ssl)->cert_ready) {
+    return -1;
+  }
+  if (!InstallCertificate(ssl)) {
+    return 0;
+  }
+  return 1;
+}
+
+bssl::UniquePtr<SSL> TestConfig::NewSSL(
+    SSL_CTX *ssl_ctx, SSL_SESSION *session, bool is_resume,
+    std::unique_ptr<TestState> test_state) const {
+  bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
+  if (!ssl) {
+    return nullptr;
+  }
+
+  if (!SetTestConfig(ssl.get(), this)) {
+    return nullptr;
+  }
+  if (test_state != nullptr) {
+    if (!SetTestState(ssl.get(), std::move(test_state))) {
+      return nullptr;
+    }
+    GetTestState(ssl.get())->is_resume = is_resume;
+  }
+
+  if (fallback_scsv && !SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
+    return nullptr;
+  }
+  // Install the certificate synchronously if nothing else will handle it.
+  if (!use_early_callback && !use_old_client_cert_callback && !async &&
+      !InstallCertificate(ssl.get())) {
+    return nullptr;
+  }
+  if (!use_old_client_cert_callback) {
+    SSL_set_cert_cb(ssl.get(), CertCallback, nullptr);
+  }
+  int mode = SSL_VERIFY_NONE;
+  if (require_any_client_certificate) {
+    mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+  }
+  if (verify_peer) {
+    mode = SSL_VERIFY_PEER;
+  }
+  if (verify_peer_if_no_obc) {
+    // Set SSL_VERIFY_FAIL_IF_NO_PEER_CERT so testing whether client
+    // certificates were requested is easy.
+    mode = SSL_VERIFY_PEER | SSL_VERIFY_PEER_IF_NO_OBC |
+           SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+  }
+  if (use_custom_verify_callback) {
+    SSL_set_custom_verify(ssl.get(), mode, CustomVerifyCallback);
+  } else if (mode != SSL_VERIFY_NONE) {
+    SSL_set_verify(ssl.get(), mode, NULL);
+  }
+  if (false_start) {
+    SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START);
+  }
+  if (cbc_record_splitting) {
+    SSL_set_mode(ssl.get(), SSL_MODE_CBC_RECORD_SPLITTING);
+  }
+  if (partial_write) {
+    SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_PARTIAL_WRITE);
+  }
+  if (no_tls13) {
+    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_3);
+  }
+  if (no_tls12) {
+    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_2);
+  }
+  if (no_tls11) {
+    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_1);
+  }
+  if (no_tls1) {
+    SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1);
+  }
+  if (!expected_channel_id.empty() || enable_channel_id) {
+    SSL_set_tls_channel_id_enabled(ssl.get(), 1);
+  }
+  if (!send_channel_id.empty()) {
+    SSL_set_tls_channel_id_enabled(ssl.get(), 1);
+    if (!async) {
+      // The async case will be supplied by |ChannelIdCallback|.
+      bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(send_channel_id);
+      if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
+        return nullptr;
+      }
+    }
+  }
+  if (!send_token_binding_params.empty()) {
+    SSL_set_token_binding_params(
+        ssl.get(),
+        reinterpret_cast<const uint8_t *>(send_token_binding_params.data()),
+        send_token_binding_params.length());
+  }
+  if (!host_name.empty() &&
+      !SSL_set_tlsext_host_name(ssl.get(), host_name.c_str())) {
+    return nullptr;
+  }
+  if (!advertise_alpn.empty() &&
+      SSL_set_alpn_protos(ssl.get(), (const uint8_t *)advertise_alpn.data(),
+                          advertise_alpn.size()) != 0) {
+    return nullptr;
+  }
+  if (!psk.empty()) {
+    SSL_set_psk_client_callback(ssl.get(), PskClientCallback);
+    SSL_set_psk_server_callback(ssl.get(), PskServerCallback);
+  }
+  if (!psk_identity.empty() &&
+      !SSL_use_psk_identity_hint(ssl.get(), psk_identity.c_str())) {
+    return nullptr;
+  }
+  if (!srtp_profiles.empty() &&
+      !SSL_set_srtp_profiles(ssl.get(), srtp_profiles.c_str())) {
+    return nullptr;
+  }
+  if (enable_ocsp_stapling) {
+    SSL_enable_ocsp_stapling(ssl.get());
+  }
+  if (enable_signed_cert_timestamps) {
+    SSL_enable_signed_cert_timestamps(ssl.get());
+  }
+  if (min_version != 0 &&
+      !SSL_set_min_proto_version(ssl.get(), (uint16_t)min_version)) {
+    return nullptr;
+  }
+  if (max_version != 0 &&
+      !SSL_set_max_proto_version(ssl.get(), (uint16_t)max_version)) {
+    return nullptr;
+  }
+  if (mtu != 0) {
+    SSL_set_options(ssl.get(), SSL_OP_NO_QUERY_MTU);
+    SSL_set_mtu(ssl.get(), mtu);
+  }
+  if (install_ddos_callback) {
+    SSL_CTX_set_dos_protection_cb(ssl_ctx, DDoSCallback);
+  }
+  SSL_set_shed_handshake_config(ssl.get(), true);
+  if (renegotiate_once) {
+    SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_once);
+  }
+  if (renegotiate_freely || forbid_renegotiation_after_handshake) {
+    // |forbid_renegotiation_after_handshake| will disable renegotiation later.
+    SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_freely);
+  }
+  if (renegotiate_ignore) {
+    SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_ignore);
+  }
+  if (!check_close_notify) {
+    SSL_set_quiet_shutdown(ssl.get(), 1);
+  }
+  if (p384_only) {
+    int nid = NID_secp384r1;
+    if (!SSL_set1_curves(ssl.get(), &nid, 1)) {
+      return nullptr;
+    }
+  }
+  if (enable_all_curves) {
+    static const int kAllCurves[] = {
+        NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1,
+        NID_secp521r1, NID_X25519,
+    };
+    if (!SSL_set1_curves(ssl.get(), kAllCurves,
+                         OPENSSL_ARRAY_SIZE(kAllCurves))) {
+      return nullptr;
+    }
+  }
+  if (initial_timeout_duration_ms > 0) {
+    DTLSv1_set_initial_timeout_duration(ssl.get(), initial_timeout_duration_ms);
+  }
+  if (max_cert_list > 0) {
+    SSL_set_max_cert_list(ssl.get(), max_cert_list);
+  }
+  if (retain_only_sha256_client_cert) {
+    SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
+  }
+  if (max_send_fragment > 0) {
+    SSL_set_max_send_fragment(ssl.get(), max_send_fragment);
+  }
+  if (dummy_pq_padding_len > 0 &&
+      !SSL_set_dummy_pq_padding_size(ssl.get(), dummy_pq_padding_len)) {
+    return nullptr;
+  }
+  if (!quic_transport_params.empty()) {
+    if (!SSL_set_quic_transport_params(
+            ssl.get(),
+            reinterpret_cast<const uint8_t *>(quic_transport_params.data()),
+            quic_transport_params.size())) {
+      return nullptr;
+    }
+  }
+
+  if (session != NULL) {
+    if (!is_server) {
+      if (SSL_set_session(ssl.get(), session) != 1) {
+        return nullptr;
+      }
+    } else if (async) {
+      // The internal session cache is disabled, so install the session
+      // manually.
+      SSL_SESSION_up_ref(session);
+      GetTestState(ssl.get())->pending_session.reset(session);
+    }
+  }
+
+  if (SSL_get_current_cipher(ssl.get()) != nullptr) {
+    fprintf(stderr, "non-null cipher before handshake\n");
+    return nullptr;
+  }
+
+  return ssl;
+}
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index d380007..930100e 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -18,6 +18,10 @@
 #include <string>
 #include <vector>
 
+#include <openssl/base.h>
+#include <openssl/x509.h>
+
+#include "test_state.h"
 
 struct TestConfig {
   int port = 0;
@@ -160,10 +164,27 @@
   bool decline_ocsp_callback = false;
   bool fail_ocsp_callback = false;
   bool install_cert_compression_algs = false;
+
+  bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx) const;
+
+  bssl::UniquePtr<SSL> NewSSL(SSL_CTX *ssl_ctx, SSL_SESSION *session,
+                              bool is_resume,
+                              std::unique_ptr<TestState> test_state) const;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_initial,
                  TestConfig *out_resume, TestConfig *out_retry);
 
+bool SetTestConfig(SSL *ssl, const TestConfig *config);
+
+const TestConfig *GetTestConfig(const SSL *ssl);
+
+bool MoveTestConfig(SSL *dest, SSL *src);
+
+bool LoadCertificate(bssl::UniquePtr<X509> *out_x509,
+                     bssl::UniquePtr<STACK_OF(X509)> *out_chain,
+                     const std::string &file);
+
+bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file);
 
 #endif  // HEADER_TEST_CONFIG
diff --git a/ssl/test/test_state.cc b/ssl/test/test_state.cc
new file mode 100644
index 0000000..14bd4a1
--- /dev/null
+++ b/ssl/test/test_state.cc
@@ -0,0 +1,86 @@
+/* Copyright (c) 2018, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include "test_state.h"
+
+#include <openssl/ssl.h>
+
+#include "../../crypto/internal.h"
+#include "../internal.h"
+
+static CRYPTO_once_t g_once = CRYPTO_ONCE_INIT;
+static int g_state_index = 0;
+// Some code treats the zero time special, so initialize the clock to a
+// non-zero time.
+static timeval g_clock = { 1234, 1234 };
+
+static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+                            int index, long argl, void *argp) {
+  delete ((TestState *)ptr);
+}
+
+static void init_once() {
+  g_state_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, TestStateExFree);
+  if (g_state_index < 0) {
+    abort();
+  }
+}
+
+struct timeval *GetClock() {
+  CRYPTO_once(&g_once, init_once);
+  return &g_clock;
+}
+
+void AdvanceClock(unsigned seconds) {
+  CRYPTO_once(&g_once, init_once);
+  g_clock.tv_sec += seconds;
+}
+
+bool SetTestState(SSL *ssl, std::unique_ptr<TestState> state) {
+  CRYPTO_once(&g_once, init_once);
+  // |SSL_set_ex_data| takes ownership of |state| only on success.
+  if (SSL_set_ex_data(ssl, g_state_index, state.get()) == 1) {
+    state.release();
+    return true;
+  }
+  return false;
+}
+
+TestState *GetTestState(const SSL *ssl) {
+  CRYPTO_once(&g_once, init_once);
+  return (TestState *)SSL_get_ex_data(ssl, g_state_index);
+}
+
+bool MoveTestState(SSL *dest, SSL *src) {
+  TestState *state = GetTestState(src);
+  if (!SSL_set_ex_data(src, g_state_index, nullptr) ||
+      !SSL_set_ex_data(dest, g_state_index, state)) {
+    return false;
+  }
+
+  return true;
+}
+
+static void ssl_ctx_add_session(SSL_SESSION *session, void *void_param) {
+  SSL_CTX *ctx = reinterpret_cast<SSL_CTX *>(void_param);
+  bssl::UniquePtr<SSL_SESSION> new_session = bssl::SSL_SESSION_dup(
+      session, SSL_SESSION_INCLUDE_NONAUTH | SSL_SESSION_INCLUDE_TICKET);
+  if (new_session != nullptr) {
+    SSL_CTX_add_session(ctx, new_session.get());
+  }
+}
+
+void CopySessions(SSL_CTX *dst, const SSL_CTX *src) {
+  lh_SSL_SESSION_doall_arg(src->sessions, ssl_ctx_add_session, dst);
+}
diff --git a/ssl/test/test_state.h b/ssl/test/test_state.h
new file mode 100644
index 0000000..3fe2972
--- /dev/null
+++ b/ssl/test/test_state.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2018, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef HEADER_TEST_STATE
+#define HEADER_TEST_STATE
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <openssl/base.h>
+
+struct TestState {
+  // async_bio is async BIO which pauses reads and writes.
+  BIO *async_bio = nullptr;
+  // packeted_bio is the packeted BIO which simulates read timeouts.
+  BIO *packeted_bio = nullptr;
+  bssl::UniquePtr<EVP_PKEY> channel_id;
+  bool cert_ready = false;
+  bssl::UniquePtr<SSL_SESSION> session;
+  bssl::UniquePtr<SSL_SESSION> pending_session;
+  bool early_callback_called = false;
+  bool handshake_done = false;
+  // private_key is the underlying private key used when testing custom keys.
+  bssl::UniquePtr<EVP_PKEY> private_key;
+  std::vector<uint8_t> private_key_result;
+  // private_key_retries is the number of times an asynchronous private key
+  // operation has been retried.
+  unsigned private_key_retries = 0;
+  bool got_new_session = false;
+  bssl::UniquePtr<SSL_SESSION> new_session;
+  bool ticket_decrypt_done = false;
+  bool alpn_select_done = false;
+  bool is_resume = false;
+  bool early_callback_ready = false;
+  bool custom_verify_ready = false;
+  std::string msg_callback_text;
+  bool msg_callback_ok = true;
+  // cert_verified is true if certificate verification has been driven to
+  // completion. This tests that the callback is not called again after this.
+  bool cert_verified = false;
+};
+
+bool SetTestState(SSL *ssl, std::unique_ptr<TestState> state);
+
+TestState *GetTestState(const SSL *ssl);
+
+bool MoveTestState(SSL *dest, SSL *src);
+
+struct timeval *GetClock();
+
+void AdvanceClock(unsigned seconds);
+
+void CopySessions(SSL_CTX *dest, const SSL_CTX *src);
+
+#endif  // HEADER_TEST_STATE