[tor-commits] [tor/master] Split tls modules and their tests into openssl and generic.

nickm at torproject.org nickm at torproject.org
Wed Sep 5 00:47:14 UTC 2018


commit 1992c761308538cffea64abecc9e45cbd47b1bda
Author: Nick Mathewson <nickm at torproject.org>
Date:   Sun Aug 12 16:04:12 2018 -0400

    Split tls modules and their tests into openssl and generic.
    
    Also, add a stubbed-out nss version of the modules.  The tests won't
    pass with NSS yet since the NSS modules don't do anything.
    
    This is a good patch to read with --color-moved.
---
 src/lib/tls/include.am         |   12 +
 src/lib/tls/tortls.c           | 2055 +-----------------------------
 src/lib/tls/tortls.h           |   64 +-
 src/lib/tls/tortls_internal.h  |   65 +
 src/lib/tls/tortls_nss.c       |  432 +++++++
 src/lib/tls/tortls_openssl.c   | 2032 ++++++++++++++++++++++++++++++
 src/lib/tls/x509.c             |  479 +------
 src/lib/tls/x509.h             |    4 +-
 src/lib/tls/x509_nss.c         |  122 ++
 src/lib/tls/x509_openssl.c     |  489 +++++++
 src/test/include.am            |    8 +
 src/test/test.c                |    3 +
 src/test/test.h                |    1 +
 src/test/test_tortls.c         | 2732 ++--------------------------------------
 src/test/test_tortls_openssl.c | 2597 ++++++++++++++++++++++++++++++++++++++
 15 files changed, 5873 insertions(+), 5222 deletions(-)

diff --git a/src/lib/tls/include.am b/src/lib/tls/include.am
index 1fd25a0b3..173104903 100644
--- a/src/lib/tls/include.am
+++ b/src/lib/tls/include.am
@@ -10,6 +10,16 @@ src_lib_libtor_tls_a_SOURCES =			\
 	src/lib/tls/tortls.c			\
 	src/lib/tls/x509.c
 
+if USE_NSS
+src_lib_libtor_tls_a_SOURCES +=			\
+	src/lib/tls/tortls_nss.c		\
+	src/lib/tls/x509_nss.c
+else
+src_lib_libtor_tls_a_SOURCES +=			\
+	src/lib/tls/tortls_openssl.c		\
+	src/lib/tls/x509_openssl.c
+endif
+
 src_lib_libtor_tls_a_CFLAGS = $(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB)
 
 src_lib_libtor_tls_testing_a_SOURCES = \
@@ -22,4 +32,6 @@ noinst_HEADERS +=				\
 	src/lib/tls/ciphers.inc			\
 	src/lib/tls/buffers_tls.h		\
 	src/lib/tls/tortls.h			\
+	src/lib/tls/tortls_internal.h		\
+	src/lib/tls/tortls_st.h			\
 	src/lib/tls/x509.h
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index 4c5dedb57..4b35177df 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -3,146 +3,13 @@
  * Copyright (c) 2007-2018, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
-/**
- * \file tortls.c
- * \brief Wrapper functions to present a consistent interface to
- * TLS, SSL, and X.509 functions from OpenSSL.
- **/
-
-/* (Unlike other tor functions, these
- * are prefixed with tor_ in order to avoid conflicting with OpenSSL
- * functions and variables.)
- */
-
-#include "orconfig.h"
-
 #define TORTLS_PRIVATE
-#define TORTLS_OPENSSL_PRIVATE
-
-#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
-  #include <winsock2.h>
-  #include <ws2tcpip.h>
-#endif
-
-#include "lib/crypt_ops/crypto_cipher.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/crypt_ops/crypto_dh.h"
-#include "lib/crypt_ops/crypto_util.h"
-#include "lib/crypt_ops/compat_openssl.h"
 #include "lib/tls/x509.h"
-
-/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
- * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
-
-#include <openssl/opensslv.h>
-
-#ifdef OPENSSL_NO_EC
-#error "We require OpenSSL with ECC support"
-#endif
-
-#include <openssl/ssl.h>
-#include <openssl/ssl3.h>
-#include <openssl/err.h>
-#include <openssl/tls1.h>
-#include <openssl/asn1.h>
-#include <openssl/bio.h>
-#include <openssl/bn.h>
-#include <openssl/rsa.h>
-
-ENABLE_GCC_WARNING(redundant-decls)
-
 #include "lib/tls/tortls.h"
 #include "lib/tls/tortls_st.h"
-#include "lib/log/log.h"
+#include "lib/tls/tortls_internal.h"
 #include "lib/log/util_bug.h"
-#include "lib/container/smartlist.h"
-#include "lib/string/compat_string.h"
-#include "lib/string/printf.h"
-#include "lib/net/socket.h"
 #include "lib/intmath/cmp.h"
-#include "lib/ctime/di_ops.h"
-#include "lib/encoding/time_fmt.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "lib/arch/bytes.h"
-
-/* Copied from or.h */
-#define LEGAL_NICKNAME_CHARACTERS \
-  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-
-/** How long do identity certificates live? (sec) */
-#define IDENTITY_CERT_LIFETIME  (365*24*60*60)
-
-#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer")
-
-#if OPENSSL_VERSION_NUMBER <  OPENSSL_V(1,0,0,'f')
-/* This is a version of OpenSSL before 1.0.0f. It does not have
- * the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and
- * SSL3 safely at the same time.
- */
-#define DISABLE_SSL3_HANDSHAKE
-#endif /* OPENSSL_VERSION_NUMBER <  OPENSSL_V(1,0,0,'f') */
-
-/* We redefine these so that we can run correctly even if the vendor gives us
- * a version of OpenSSL that does not match its header files.  (Apple: I am
- * looking at you.)
- */
-#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
-#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L
-#endif
-#ifndef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
-#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010
-#endif
-
-/** Return values for tor_tls_classify_client_ciphers.
- *
- * @{
- */
-/** An error occurred when examining the client ciphers */
-#define CIPHERS_ERR -1
-/** The client cipher list indicates that a v1 handshake was in use. */
-#define CIPHERS_V1 1
-/** The client cipher list indicates that the client is using the v2 or the
- * v3 handshake, but that it is (probably!) lying about what ciphers it
- * supports */
-#define CIPHERS_V2 2
-/** The client cipher list indicates that the client is using the v2 or the
- * v3 handshake, and that it is telling the truth about what ciphers it
- * supports */
-#define CIPHERS_UNRESTRICTED 3
-/** @} */
-
-/** The ex_data index in which we store a pointer to an SSL object's
- * corresponding tor_tls_t object. */
-STATIC int tor_tls_object_ex_data_index = -1;
-
-/** Helper: Allocate tor_tls_object_ex_data_index. */
-STATIC void
-tor_tls_allocate_tor_tls_object_ex_data_index(void)
-{
-  if (tor_tls_object_ex_data_index == -1) {
-    tor_tls_object_ex_data_index =
-      SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
-    tor_assert(tor_tls_object_ex_data_index != -1);
-  }
-}
-
-/** Helper: given a SSL* pointer, return the tor_tls_t object using that
- * pointer. */
-STATIC tor_tls_t *
-tor_tls_get_by_ssl(const SSL *ssl)
-{
-  tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index);
-  if (result)
-    tor_assert(result->magic == TOR_TLS_MAGIC);
-  return result;
-}
-
-static void tor_tls_context_decref(tor_tls_context_t *ctx);
-static void tor_tls_context_incref(tor_tls_context_t *ctx);
 
 /** Global TLS contexts. We keep them here because nobody else needs
  * to touch them.
@@ -152,126 +19,37 @@ STATIC tor_tls_context_t *server_tls_context = NULL;
 STATIC tor_tls_context_t *client_tls_context = NULL;
 /**@}*/
 
-/** True iff tor_tls_init() has been called. */
-static int tls_library_is_initialized = 0;
-
-/* Module-internal error codes. */
-#define TOR_TLS_SYSCALL_    (MIN_TOR_TLS_ERROR_VAL_ - 2)
-#define TOR_TLS_ZERORETURN_ (MIN_TOR_TLS_ERROR_VAL_ - 1)
-
-/** Write a description of the current state of <b>tls</b> into the
- * <b>sz</b>-byte buffer at <b>buf</b>. */
-void
-tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
+/**
+ * Return the appropriate TLS context.
+ */
+tor_tls_context_t *
+tor_tls_context_get(int is_server)
 {
-  const char *ssl_state;
-  const char *tortls_state;
-
-  if (PREDICT_UNLIKELY(!tls || !tls->ssl)) {
-    strlcpy(buf, "(No SSL object)", sz);
-    return;
-  }
-
-  ssl_state = SSL_state_string_long(tls->ssl);
-  switch (tls->state) {
-#define CASE(st) case TOR_TLS_ST_##st: tortls_state = " in "#st ; break
-    CASE(HANDSHAKE);
-    CASE(OPEN);
-    CASE(GOTCLOSE);
-    CASE(SENTCLOSE);
-    CASE(CLOSED);
-    CASE(RENEGOTIATE);
-#undef CASE
-  case TOR_TLS_ST_BUFFEREVENT:
-    tortls_state = "";
-    break;
-  default:
-    tortls_state = " in unknown TLS state";
-    break;
-  }
-
-  tor_snprintf(buf, sz, "%s%s", ssl_state, tortls_state);
+  return is_server ? server_tls_context : client_tls_context;
 }
 
-/** Log a single error <b>err</b> as returned by ERR_get_error(), which was
- * received while performing an operation <b>doing</b> on <b>tls</b>.  Log
- * the message at <b>severity</b>, in log domain <b>domain</b>. */
+/** Increase the reference count of <b>ctx</b>. */
 void
-tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
-                  int severity, int domain, const char *doing)
+tor_tls_context_incref(tor_tls_context_t *ctx)
 {
-  const char *state = NULL, *addr;
-  const char *msg, *lib, *func;
-
-  state = (tls && tls->ssl)?SSL_state_string_long(tls->ssl):"---";
-
-  addr = tls ? tls->address : NULL;
-
-  /* Some errors are known-benign, meaning they are the fault of the other
-   * side of the connection. The caller doesn't know this, so override the
-   * priority for those cases. */
-  switch (ERR_GET_REASON(err)) {
-    case SSL_R_HTTP_REQUEST:
-    case SSL_R_HTTPS_PROXY_REQUEST:
-    case SSL_R_RECORD_LENGTH_MISMATCH:
-#ifndef OPENSSL_1_1_API
-    case SSL_R_RECORD_TOO_LARGE:
-#endif
-    case SSL_R_UNKNOWN_PROTOCOL:
-    case SSL_R_UNSUPPORTED_PROTOCOL:
-      severity = LOG_INFO;
-      break;
-    default:
-      break;
-  }
-
-  msg = (const char*)ERR_reason_error_string(err);
-  lib = (const char*)ERR_lib_error_string(err);
-  func = (const char*)ERR_func_error_string(err);
-  if (!msg) msg = "(null)";
-  if (!lib) lib = "(null)";
-  if (!func) func = "(null)";
-  if (doing) {
-    tor_log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
-        doing, addr?" with ":"", addr?addr:"",
-        msg, lib, func, state);
-  } else {
-    tor_log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
-        addr?" with ":"", addr?addr:"",
-        msg, lib, func, state);
-  }
+  ++ctx->refcnt;
 }
 
-/** Log all pending tls errors at level <b>severity</b> in log domain
- * <b>domain</b>.  Use <b>doing</b> to describe our current activities.
- */
+/** Free all global TLS structures. */
 void
-tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
+tor_tls_free_all(void)
 {
-  unsigned long err;
+  check_no_tls_errors();
 
-  while ((err = ERR_get_error()) != 0) {
-    tor_tls_log_one_error(tls, err, severity, domain, doing);
+  if (server_tls_context) {
+    tor_tls_context_t *ctx = server_tls_context;
+    server_tls_context = NULL;
+    tor_tls_context_decref(ctx);
   }
-}
-
-/** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error
- * code. */
-STATIC int
-tor_errno_to_tls_error(int e)
-{
-  switch (e) {
-    case SOCK_ERRNO(ECONNRESET): // most common
-      return TOR_TLS_ERROR_CONNRESET;
-    case SOCK_ERRNO(ETIMEDOUT):
-      return TOR_TLS_ERROR_TIMEOUT;
-    case SOCK_ERRNO(EHOSTUNREACH):
-    case SOCK_ERRNO(ENETUNREACH):
-      return TOR_TLS_ERROR_NO_ROUTE;
-    case SOCK_ERRNO(ECONNREFUSED):
-      return TOR_TLS_ERROR_CONNREFUSED; // least common
-    default:
-      return TOR_TLS_ERROR_MISC;
+  if (client_tls_context) {
+    tor_tls_context_t *ctx = client_tls_context;
+    client_tls_context = NULL;
+    tor_tls_context_decref(ctx);
   }
 }
 
@@ -295,331 +73,6 @@ tor_tls_err_to_string(int err)
   }
 }
 
-#define CATCH_SYSCALL 1
-#define CATCH_ZERO    2
-
-/** Given a TLS object and the result of an SSL_* call, use
- * SSL_get_error to determine whether an error has occurred, and if so
- * which one.  Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}.
- * If extra&CATCH_SYSCALL is true, return TOR_TLS_SYSCALL_ instead of
- * reporting syscall errors.  If extra&CATCH_ZERO is true, return
- * TOR_TLS_ZERORETURN_ instead of reporting zero-return errors.
- *
- * If an error has occurred, log it at level <b>severity</b> and describe the
- * current action as <b>doing</b>.
- */
-STATIC int
-tor_tls_get_error(tor_tls_t *tls, int r, int extra,
-                  const char *doing, int severity, int domain)
-{
-  int err = SSL_get_error(tls->ssl, r);
-  int tor_error = TOR_TLS_ERROR_MISC;
-  switch (err) {
-    case SSL_ERROR_NONE:
-      return TOR_TLS_DONE;
-    case SSL_ERROR_WANT_READ:
-      return TOR_TLS_WANTREAD;
-    case SSL_ERROR_WANT_WRITE:
-      return TOR_TLS_WANTWRITE;
-    case SSL_ERROR_SYSCALL:
-      if (extra&CATCH_SYSCALL)
-        return TOR_TLS_SYSCALL_;
-      if (r == 0) {
-        tor_log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
-            doing, SSL_state_string_long(tls->ssl));
-        tor_error = TOR_TLS_ERROR_IO;
-      } else {
-        int e = tor_socket_errno(tls->socket);
-        tor_log(severity, LD_NET,
-            "TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
-            doing, e, tor_socket_strerror(e),
-            SSL_state_string_long(tls->ssl));
-        tor_error = tor_errno_to_tls_error(e);
-      }
-      tls_log_errors(tls, severity, domain, doing);
-      return tor_error;
-    case SSL_ERROR_ZERO_RETURN:
-      if (extra&CATCH_ZERO)
-        return TOR_TLS_ZERORETURN_;
-      tor_log(severity, LD_NET, "TLS connection closed while %s in state %s",
-          doing, SSL_state_string_long(tls->ssl));
-      tls_log_errors(tls, severity, domain, doing);
-      return TOR_TLS_CLOSE;
-    default:
-      tls_log_errors(tls, severity, domain, doing);
-      return TOR_TLS_ERROR_MISC;
-  }
-}
-
-/** Initialize OpenSSL, unless it has already been initialized.
- */
-void
-tor_tls_init(void)
-{
-  check_no_tls_errors();
-
-  if (!tls_library_is_initialized) {
-#ifdef OPENSSL_1_1_API
-    OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
-#else
-    SSL_library_init();
-    SSL_load_error_strings();
-#endif
-
-#if (SIZEOF_VOID_P >= 8 &&                              \
-     OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
-    long version = OpenSSL_version_num();
-
-    /* LCOV_EXCL_START : we can't test these lines on the same machine */
-    if (version >= OPENSSL_V_SERIES(1,0,1)) {
-      /* Warn if we could *almost* be running with much faster ECDH.
-         If we're built for a 64-bit target, using OpenSSL 1.0.1, but we
-         don't have one of the built-in __uint128-based speedups, we are
-         just one build operation away from an accelerated handshake.
-
-         (We could be looking at OPENSSL_NO_EC_NISTP_64_GCC_128 instead of
-          doing this test, but that gives compile-time options, not runtime
-          behavior.)
-      */
-      EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
-      const EC_GROUP *g = key ? EC_KEY_get0_group(key) : NULL;
-      const EC_METHOD *m = g ? EC_GROUP_method_of(g) : NULL;
-      const int warn = (m == EC_GFp_simple_method() ||
-                        m == EC_GFp_mont_method() ||
-                        m == EC_GFp_nist_method());
-      EC_KEY_free(key);
-
-      if (warn)
-        log_notice(LD_GENERAL, "We were built to run on a 64-bit CPU, with "
-                   "OpenSSL 1.0.1 or later, but with a version of OpenSSL "
-                   "that apparently lacks accelerated support for the NIST "
-                   "P-224 and P-256 groups. Building openssl with such "
-                   "support (using the enable-ec_nistp_64_gcc_128 option "
-                   "when configuring it) would make ECDH much faster.");
-    }
-    /* LCOV_EXCL_STOP */
-#endif /* (SIZEOF_VOID_P >= 8 &&                              ... */
-
-    tor_tls_allocate_tor_tls_object_ex_data_index();
-
-    tls_library_is_initialized = 1;
-  }
-}
-
-/** Free all global TLS structures. */
-void
-tor_tls_free_all(void)
-{
-  check_no_tls_errors();
-
-  if (server_tls_context) {
-    tor_tls_context_t *ctx = server_tls_context;
-    server_tls_context = NULL;
-    tor_tls_context_decref(ctx);
-  }
-  if (client_tls_context) {
-    tor_tls_context_t *ctx = client_tls_context;
-    client_tls_context = NULL;
-    tor_tls_context_decref(ctx);
-  }
-}
-
-/** We need to give OpenSSL a callback to verify certificates. This is
- * it: We always accept peer certs and complete the handshake.  We
- * don't validate them until later.
- */
-STATIC int
-always_accept_verify_cb(int preverify_ok,
-                        X509_STORE_CTX *x509_ctx)
-{
-  (void) preverify_ok;
-  (void) x509_ctx;
-  return 1;
-}
-
-/** List of ciphers that servers should select from when the client might be
- * claiming extra unsupported ciphers in order to avoid fingerprinting.  */
-static const char SERVER_CIPHER_LIST[] =
-#ifdef  TLS1_3_TXT_AES_128_GCM_SHA256
-  /* This one can never actually get selected, since if the client lists it,
-   * we will assume that the client is honest, and not use this list.
-   * Nonetheless we list it if it's available, so that the server doesn't
-   * conclude that it has no valid ciphers if it's running with TLS1.3.
-   */
-  TLS1_3_TXT_AES_128_GCM_SHA256 ":"
-#endif
-  TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
-  TLS1_TXT_DHE_RSA_WITH_AES_128_SHA;
-
-/** List of ciphers that servers should select from when we actually have
- * our choice of what cipher to use. */
-static const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
-  /* Here are the TLS 1.3 ciphers we like, in the order we prefer. */
-#ifdef TLS1_3_TXT_AES_256_GCM_SHA384
-  TLS1_3_TXT_AES_256_GCM_SHA384 ":"
-#endif
-#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256
-  TLS1_3_TXT_CHACHA20_POLY1305_SHA256 ":"
-#endif
-#ifdef TLS1_3_TXT_AES_128_GCM_SHA256
-  TLS1_3_TXT_AES_128_GCM_SHA256 ":"
-#endif
-#ifdef TLS1_3_TXT_AES_128_CCM_SHA256
-  TLS1_3_TXT_AES_128_CCM_SHA256 ":"
-#endif
-
-  /* This list is autogenerated with the gen_server_ciphers.py script;
-   * don't hand-edit it. */
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-       TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":"
-#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-       TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":"
-#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384
-       TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":"
-#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256
-       TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":"
-#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA
-       TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":"
-#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
-       TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":"
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384
-       TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":"
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256
-       TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":"
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_CCM
-       TLS1_TXT_DHE_RSA_WITH_AES_256_CCM ":"
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_CCM
-       TLS1_TXT_DHE_RSA_WITH_AES_128_CCM ":"
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256
-       TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":"
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256
-       TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":"
-#endif
-       /* Required */
-       TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
-       /* Required */
-       TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305
-       TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 ":"
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305
-       TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305
-#endif
-  ;
-
-/* Note: to set up your own private testing network with link crypto
- * disabled, set your Tors' cipher list to
- * (SSL3_TXT_RSA_NULL_SHA).  If you do this, you won't be able to communicate
- * with any of the "real" Tors, though. */
-
-#define CIPHER(id, name) name ":"
-#define XCIPHER(id, name)
-/** List of ciphers that clients should advertise, omitting items that
- * our OpenSSL doesn't know about. */
-static const char CLIENT_CIPHER_LIST[] =
-#include "ciphers.inc"
-  /* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version
-   * of any cipher we say. */
-  "!SSLv2"
-  ;
-#undef CIPHER
-#undef XCIPHER
-
-/** Remove a reference to <b>ctx</b>, and free it if it has no more
- * references. */
-static void
-tor_tls_context_decref(tor_tls_context_t *ctx)
-{
-  tor_assert(ctx);
-  if (--ctx->refcnt == 0) {
-    SSL_CTX_free(ctx->ctx);
-    tor_x509_cert_free(ctx->my_link_cert);
-    tor_x509_cert_free(ctx->my_id_cert);
-    tor_x509_cert_free(ctx->my_auth_cert);
-    crypto_pk_free(ctx->link_key);
-    crypto_pk_free(ctx->auth_key);
-    /* LCOV_EXCL_BR_START since ctx will never be NULL here */
-    tor_free(ctx);
-    /* LCOV_EXCL_BR_STOP */
-  }
-}
-
-/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate
- * and ID certificate that we're currently using for our V3 in-protocol
- * handshake's certificate chain.  If <b>server</b> is true, provide the certs
- * that we use in server mode (auth, ID); otherwise, provide the certs that we
- * use in client mode. (link, ID) */
-int
-tor_tls_get_my_certs(int server,
-                     const tor_x509_cert_t **link_cert_out,
-                     const tor_x509_cert_t **id_cert_out)
-{
-  tor_tls_context_t *ctx = server ? server_tls_context : client_tls_context;
-  if (! ctx)
-    return -1;
-  if (link_cert_out)
-    *link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert;
-  if (id_cert_out)
-    *id_cert_out = ctx->my_id_cert;
-  return 0;
-}
-
-/**
- * Return the authentication key that we use to authenticate ourselves as a
- * client in the V3 in-protocol handshake.
- */
-crypto_pk_t *
-tor_tls_get_my_client_auth_key(void)
-{
-  if (! client_tls_context)
-    return NULL;
-  return client_tls_context->auth_key;
-}
-
-/** Return true iff the other side of <b>tls</b> has authenticated to us, and
- * the key certified in <b>cert</b> is the same as the key they used to do it.
- */
-MOCK_IMPL(int,
-tor_tls_cert_matches_key,(const tor_tls_t *tls, const tor_x509_cert_t *cert))
-{
-  X509 *peercert = SSL_get_peer_certificate(tls->ssl);
-  EVP_PKEY *link_key = NULL, *cert_key = NULL;
-  int result;
-
-  if (!peercert)
-    return 0;
-  link_key = X509_get_pubkey(peercert);
-  cert_key = X509_get_pubkey((X509 *)tor_x509_cert_get_impl(cert));
-
-  result = link_key && cert_key && EVP_PKEY_cmp(cert_key, link_key) == 1;
-
-  X509_free(peercert);
-  if (link_key)
-    EVP_PKEY_free(link_key);
-  if (cert_key)
-    EVP_PKEY_free(cert_key);
-
-  return result;
-}
-
-/** Increase the reference count of <b>ctx</b>. */
-static void
-tor_tls_context_incref(tor_tls_context_t *ctx)
-{
-  ++ctx->refcnt;
-}
-
 /** Create new global client and server TLS contexts.
  *
  * If <b>server_identity</b> is NULL, this will not generate a server
@@ -686,687 +139,6 @@ tor_tls_context_init(unsigned flags,
   return MIN(rv1, rv2);
 }
 
-/** Create a new global TLS context.
- *
- * You can call this function multiple times.  Each time you call it,
- * it generates new certificates; all new connections will use
- * the new SSL context.
- */
-STATIC int
-tor_tls_context_init_one(tor_tls_context_t **ppcontext,
-                         crypto_pk_t *identity,
-                         unsigned int key_lifetime,
-                         unsigned int flags,
-                         int is_client)
-{
-  tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
-                                                   key_lifetime,
-                                                   flags,
-                                                   is_client);
-  tor_tls_context_t *old_ctx = *ppcontext;
-
-  if (new_ctx != NULL) {
-    *ppcontext = new_ctx;
-
-    /* Free the old context if one existed. */
-    if (old_ctx != NULL) {
-      /* This is safe even if there are open connections: we reference-
-       * count tor_tls_context_t objects. */
-      tor_tls_context_decref(old_ctx);
-    }
-  }
-
-  return ((new_ctx != NULL) ? 0 : -1);
-}
-
-/** The group we should use for ecdhe when none was selected. */
-#define  NID_tor_default_ecdhe_group NID_X9_62_prime256v1
-
-#define RSA_LINK_KEY_BITS 2048
-
-/** Create a new TLS context for use with Tor TLS handshakes.
- * <b>identity</b> should be set to the identity key used to sign the
- * certificate.
- */
-STATIC tor_tls_context_t *
-tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
-                    unsigned flags, int is_client)
-{
-  crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
-  EVP_PKEY *pkey = NULL;
-  tor_tls_context_t *result = NULL;
-  X509 *cert = NULL, *idcert = NULL, *authcert = NULL;
-  char *nickname = NULL, *nn2 = NULL;
-
-  tor_tls_init();
-  nickname = crypto_random_hostname(8, 20, "www.", ".net");
-#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
-  nn2 = crypto_random_hostname(8, 20, "www.", ".net");
-#else
-  nn2 = crypto_random_hostname(8, 20, "www.", ".com");
-#endif
-
-  /* Generate short-term RSA key for use with TLS. */
-  if (!(rsa = crypto_pk_new()))
-    goto error;
-  if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0)
-    goto error;
-  if (!is_client) {
-    /* Generate short-term RSA key for use in the in-protocol ("v3")
-     * authentication handshake. */
-    if (!(rsa_auth = crypto_pk_new()))
-      goto error;
-    if (crypto_pk_generate_key(rsa_auth)<0)
-      goto error;
-    /* Create a link certificate signed by identity key. */
-    cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
-                                      key_lifetime);
-    /* Create self-signed certificate for identity key. */
-    idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
-                                        IDENTITY_CERT_LIFETIME);
-    /* Create an authentication certificate signed by identity key. */
-    authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
-                                          key_lifetime);
-    if (!cert || !idcert || !authcert) {
-      log_warn(LD_CRYPTO, "Error creating certificate");
-      goto error;
-    }
-  }
-
-  result = tor_malloc_zero(sizeof(tor_tls_context_t));
-  result->refcnt = 1;
-  if (!is_client) {
-    result->my_link_cert = tor_x509_cert_new(X509_dup(cert));
-    result->my_id_cert = tor_x509_cert_new(X509_dup(idcert));
-    result->my_auth_cert = tor_x509_cert_new(X509_dup(authcert));
-    if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
-      goto error;
-    result->link_key = crypto_pk_dup_key(rsa);
-    result->auth_key = crypto_pk_dup_key(rsa_auth);
-  }
-
-#if 0
-  /* Tell OpenSSL to only use TLS1.  This may have subtly different results
-   * from SSLv23_method() with SSLv2 and SSLv3 disabled, so we need to do some
-   * investigation before we consider adjusting it. It should be compatible
-   * with existing Tors. */
-  if (!(result->ctx = SSL_CTX_new(TLSv1_method())))
-    goto error;
-#endif /* 0 */
-
-  /* Tell OpenSSL to use TLS 1.0 or later but not SSL2 or SSL3. */
-#ifdef HAVE_TLS_METHOD
-  if (!(result->ctx = SSL_CTX_new(TLS_method())))
-    goto error;
-#else
-  if (!(result->ctx = SSL_CTX_new(SSLv23_method())))
-    goto error;
-#endif /* defined(HAVE_TLS_METHOD) */
-  SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2);
-  SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3);
-
-  /* Prefer the server's ordering of ciphers: the client's ordering has
-  * historically been chosen for fingerprinting resistance. */
-  SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
-
-  /* Disable TLS tickets if they're supported.  We never want to use them;
-   * using them can make our perfect forward secrecy a little worse, *and*
-   * create an opportunity to fingerprint us (since it's unusual to use them
-   * with TLS sessions turned off).
-   *
-   * In 0.2.4, clients advertise support for them though, to avoid a TLS
-   * distinguishability vector.  This can give us worse PFS, though, if we
-   * get a server that doesn't set SSL_OP_NO_TICKET.  With luck, there will
-   * be few such servers by the time 0.2.4 is more stable.
-   */
-#ifdef SSL_OP_NO_TICKET
-  if (! is_client) {
-    SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
-  }
-#endif
-
-  SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE);
-  SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE);
-
-#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
-  SSL_CTX_set_options(result->ctx,
-                      SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
-#endif
-  /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
-   * as authenticating any earlier-received data.
-   */
-  {
-    SSL_CTX_set_options(result->ctx,
-                        SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
-  }
-
-  /* Don't actually allow compression; it uses RAM and time, it makes TLS
-   * vulnerable to CRIME-style attacks, and most of the data we transmit over
-   * TLS is encrypted (and therefore uncompressible) anyway. */
-#ifdef SSL_OP_NO_COMPRESSION
-  SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION);
-#endif
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
-#ifndef OPENSSL_NO_COMP
-  if (result->ctx->comp_methods)
-    result->ctx->comp_methods = NULL;
-#endif
-#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) */
-
-#ifdef SSL_MODE_RELEASE_BUFFERS
-  SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS);
-#endif
-  if (! is_client) {
-    if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
-      goto error;
-    X509_free(cert); /* We just added a reference to cert. */
-    cert=NULL;
-    if (idcert) {
-      X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
-      tor_assert(s);
-      X509_STORE_add_cert(s, idcert);
-      X509_free(idcert); /* The context now owns the reference to idcert */
-      idcert = NULL;
-    }
-  }
-  SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
-  if (!is_client) {
-    tor_assert(rsa);
-    if (!(pkey = crypto_pk_get_openssl_evp_pkey_(rsa,1)))
-      goto error;
-    if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
-      goto error;
-    EVP_PKEY_free(pkey);
-    pkey = NULL;
-    if (!SSL_CTX_check_private_key(result->ctx))
-      goto error;
-  }
-  {
-    DH *dh = crypto_dh_new_openssl_tls();
-    tor_assert(dh);
-    SSL_CTX_set_tmp_dh(result->ctx, dh);
-    DH_free(dh);
-  }
-  if (! is_client) {
-    int nid;
-    EC_KEY *ec_key;
-    if (flags & TOR_TLS_CTX_USE_ECDHE_P224)
-      nid = NID_secp224r1;
-    else if (flags & TOR_TLS_CTX_USE_ECDHE_P256)
-      nid = NID_X9_62_prime256v1;
-    else
-      nid = NID_tor_default_ecdhe_group;
-    /* Use P-256 for ECDHE. */
-    ec_key = EC_KEY_new_by_curve_name(nid);
-    if (ec_key != NULL) /*XXXX Handle errors? */
-      SSL_CTX_set_tmp_ecdh(result->ctx, ec_key);
-    EC_KEY_free(ec_key);
-  }
-  SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
-                     always_accept_verify_cb);
-  /* let us realloc bufs that we're writing from */
-  SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
-  if (rsa)
-    crypto_pk_free(rsa);
-  if (rsa_auth)
-    crypto_pk_free(rsa_auth);
-  X509_free(authcert);
-  tor_free(nickname);
-  tor_free(nn2);
-  return result;
-
- error:
-  tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context");
-  tor_free(nickname);
-  tor_free(nn2);
-  if (pkey)
-    EVP_PKEY_free(pkey);
-  if (rsa)
-    crypto_pk_free(rsa);
-  if (rsa_auth)
-    crypto_pk_free(rsa_auth);
-  if (result)
-    tor_tls_context_decref(result);
-  if (cert)
-    X509_free(cert);
-  if (idcert)
-    X509_free(idcert);
-  if (authcert)
-    X509_free(authcert);
-  return NULL;
-}
-
-/** Invoked when a TLS state changes: log the change at severity 'debug' */
-STATIC void
-tor_tls_debug_state_callback(const SSL *ssl, int type, int val)
-{
-  /* LCOV_EXCL_START since this depends on whether debug is captured or not */
-  log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].",
-            ssl, SSL_state_string_long(ssl), type, val);
-  /* LCOV_EXCL_STOP */
-}
-
-/* Return the name of the negotiated ciphersuite in use on <b>tls</b> */
-const char *
-tor_tls_get_ciphersuite_name(tor_tls_t *tls)
-{
-  return SSL_get_cipher(tls->ssl);
-}
-
-/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to
- * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers
- * that it claims to support.  We'll prune this list to remove the ciphers
- * *we* don't recognize. */
-STATIC uint16_t v2_cipher_list[] = {
-  0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */
-  0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */
-  0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */
-  0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */
-  0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */
-  0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */
-  0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */
-  0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */
-  0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */
-  0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */
-  0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */
-  0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */
-  0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */
-  0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */
-  0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */
-  0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */
-  0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */
-  0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */
-  0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */
-  0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */
-  0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */
-  0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */
-  0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */
-  0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */
-  0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */
-  0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */
-  0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */
-  0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */
-  0
-};
-/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */
-static int v2_cipher_list_pruned = 0;
-
-/** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>;
- * return 1 if it does support it, or if we have no way to tell. */
-STATIC int
-find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
-{
-  const SSL_CIPHER *c;
-#ifdef HAVE_SSL_CIPHER_FIND
-  (void) m;
-  {
-    unsigned char cipherid[3];
-    tor_assert(ssl);
-    set_uint16(cipherid, tor_htons(cipher));
-    cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting
-                      * with a two-byte 'cipherid', it may look for a v2
-                      * cipher with the appropriate 3 bytes. */
-    c = SSL_CIPHER_find((SSL*)ssl, cipherid);
-    if (c)
-      tor_assert((SSL_CIPHER_get_id(c) & 0xffff) == cipher);
-    return c != NULL;
-  }
-#else /* !(defined(HAVE_SSL_CIPHER_FIND)) */
-
-# if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR)
-  if (m && m->get_cipher_by_char) {
-    unsigned char cipherid[3];
-    set_uint16(cipherid, tor_htons(cipher));
-    cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting
-                      * with a two-byte 'cipherid', it may look for a v2
-                      * cipher with the appropriate 3 bytes. */
-    c = m->get_cipher_by_char(cipherid);
-    if (c)
-      tor_assert((c->id & 0xffff) == cipher);
-    return c != NULL;
-  }
-#endif /* defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) */
-# ifndef OPENSSL_1_1_API
-  if (m && m->get_cipher && m->num_ciphers) {
-    /* It would seem that some of the "let's-clean-up-openssl" forks have
-     * removed the get_cipher_by_char function.  Okay, so now you get a
-     * quadratic search.
-     */
-    int i;
-    for (i = 0; i < m->num_ciphers(); ++i) {
-      c = m->get_cipher(i);
-      if (c && (c->id & 0xffff) == cipher) {
-        return 1;
-      }
-    }
-    return 0;
-  }
-#endif /* !defined(OPENSSL_1_1_API) */
-  (void) ssl;
-  (void) m;
-  (void) cipher;
-  return 1; /* No way to search */
-#endif /* defined(HAVE_SSL_CIPHER_FIND) */
-}
-
-/** Remove from v2_cipher_list every cipher that we don't support, so that
- * comparing v2_cipher_list to a client's cipher list will give a sensible
- * result. */
-static void
-prune_v2_cipher_list(const SSL *ssl)
-{
-  uint16_t *inp, *outp;
-#ifdef HAVE_TLS_METHOD
-  const SSL_METHOD *m = TLS_method();
-#else
-  const SSL_METHOD *m = SSLv23_method();
-#endif
-
-  inp = outp = v2_cipher_list;
-  while (*inp) {
-    if (find_cipher_by_id(ssl, m, *inp)) {
-      *outp++ = *inp++;
-    } else {
-      inp++;
-    }
-  }
-  *outp = 0;
-
-  v2_cipher_list_pruned = 1;
-}
-
-/** Examine the client cipher list in <b>ssl</b>, and determine what kind of
- * client it is.  Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2,
- * CIPHERS_UNRESTRICTED.
- **/
-STATIC int
-tor_tls_classify_client_ciphers(const SSL *ssl,
-                                STACK_OF(SSL_CIPHER) *peer_ciphers)
-{
-  int i, res;
-  tor_tls_t *tor_tls;
-  if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
-    prune_v2_cipher_list(ssl);
-
-  tor_tls = tor_tls_get_by_ssl(ssl);
-  if (tor_tls && tor_tls->client_cipher_list_type)
-    return tor_tls->client_cipher_list_type;
-
-  /* If we reached this point, we just got a client hello.  See if there is
-   * a cipher list. */
-  if (!peer_ciphers) {
-    log_info(LD_NET, "No ciphers on session");
-    res = CIPHERS_ERR;
-    goto done;
-  }
-  /* Now we need to see if there are any ciphers whose presence means we're
-   * dealing with an updated Tor. */
-  for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
-    const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
-    const char *ciphername = SSL_CIPHER_get_name(cipher);
-    if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) &&
-        strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) &&
-        strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) &&
-        strcmp(ciphername, "(NONE)")) {
-      log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername);
-      // return 1;
-      goto v2_or_higher;
-    }
-  }
-  res = CIPHERS_V1;
-  goto done;
- v2_or_higher:
-  {
-    const uint16_t *v2_cipher = v2_cipher_list;
-    for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
-      const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
-      uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff;
-      if (id == 0x00ff) /* extended renegotiation indicator. */
-        continue;
-      if (!id || id != *v2_cipher) {
-        res = CIPHERS_UNRESTRICTED;
-        goto dump_ciphers;
-      }
-      ++v2_cipher;
-    }
-    if (*v2_cipher != 0) {
-      res = CIPHERS_UNRESTRICTED;
-      goto dump_ciphers;
-    }
-    res = CIPHERS_V2;
-  }
-
- dump_ciphers:
-  {
-    smartlist_t *elts = smartlist_new();
-    char *s;
-    for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
-      const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
-      const char *ciphername = SSL_CIPHER_get_name(cipher);
-      smartlist_add(elts, (char*)ciphername);
-    }
-    s = smartlist_join_strings(elts, ":", 0, NULL);
-    log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s.  It is: '%s'",
-              (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s);
-    tor_free(s);
-    smartlist_free(elts);
-  }
- done:
-  if (tor_tls)
-    return tor_tls->client_cipher_list_type = res;
-
-  return res;
-}
-
-/** Return true iff the cipher list suggested by the client for <b>ssl</b> is
- * a list that indicates that the client knows how to do the v2 TLS connection
- * handshake. */
-STATIC int
-tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
-{
-  STACK_OF(SSL_CIPHER) *ciphers;
-#ifdef HAVE_SSL_GET_CLIENT_CIPHERS
-  ciphers = SSL_get_client_ciphers(ssl);
-#else
-  SSL_SESSION *session;
-  if (!(session = SSL_get_session((SSL *)ssl))) {
-    log_info(LD_NET, "No session on TLS?");
-    return CIPHERS_ERR;
-  }
-  ciphers = session->ciphers;
-#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
-
-  return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2;
-}
-
-/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection
- * changes state. We use this:
- * <ul><li>To alter the state of the handshake partway through, so we
- *         do not send or request extra certificates in v2 handshakes.</li>
- * <li>To detect renegotiation</li></ul>
- */
-STATIC void
-tor_tls_server_info_callback(const SSL *ssl, int type, int val)
-{
-  tor_tls_t *tls;
-  (void) val;
-
-  IF_BUG_ONCE(ssl == NULL) {
-    return; // LCOV_EXCL_LINE
-  }
-
-  tor_tls_debug_state_callback(ssl, type, val);
-
-  if (type != SSL_CB_ACCEPT_LOOP)
-    return;
-
-  OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl);
-  if (! STATE_IS_SW_SERVER_HELLO(ssl_state))
-    return;
-  tls = tor_tls_get_by_ssl(ssl);
-  if (tls) {
-    /* Check whether we're watching for renegotiates.  If so, this is one! */
-    if (tls->negotiated_callback)
-      tls->got_renegotiate = 1;
-    if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/
-      ++tls->server_handshake_count;
-  } else {
-    log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
-    return;
-  }
-
-  /* Now check the cipher list. */
-  if (tor_tls_client_is_using_v2_ciphers(ssl)) {
-    if (tls->wasV2Handshake)
-      return; /* We already turned this stuff off for the first handshake;
-               * This is a renegotiation. */
-
-    /* Yes, we're casting away the const from ssl.  This is very naughty of us.
-     * Let's hope openssl doesn't notice! */
-
-    /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */
-    SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN);
-    /* Don't send a hello request. */
-    SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);
-
-    if (tls) {
-      tls->wasV2Handshake = 1;
-    } else {
-      /* LCOV_EXCL_START this line is not reachable */
-      log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
-      /* LCOV_EXCL_STOP */
-    }
-  }
-}
-
-/** Callback to get invoked on a server after we've read the list of ciphers
- * the client supports, but before we pick our own ciphersuite.
- *
- * We can't abuse an info_cb for this, since by the time one of the
- * client_hello info_cbs is called, we've already picked which ciphersuite to
- * use.
- *
- * Technically, this function is an abuse of this callback, since the point of
- * a session_secret_cb is to try to set up and/or verify a shared-secret for
- * authentication on the fly.  But as long as we return 0, we won't actually be
- * setting up a shared secret, and all will be fine.
- */
-STATIC int
-tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len,
-                          STACK_OF(SSL_CIPHER) *peer_ciphers,
-                          CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher,
-                          void *arg)
-{
-  (void) secret;
-  (void) secret_len;
-  (void) peer_ciphers;
-  (void) cipher;
-  (void) arg;
-
-  if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) ==
-       CIPHERS_UNRESTRICTED) {
-    SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST);
-  }
-
-  SSL_set_session_secret_cb(ssl, NULL, NULL);
-
-  return 0;
-}
-static void
-tor_tls_setup_session_secret_cb(tor_tls_t *tls)
-{
-  SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
-}
-
-/** Create a new TLS object from a file descriptor, and a flag to
- * determine whether it is functioning as a server.
- */
-tor_tls_t *
-tor_tls_new(int sock, int isServer)
-{
-  BIO *bio = NULL;
-  tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t));
-  tor_tls_context_t *context = isServer ? server_tls_context :
-    client_tls_context;
-  result->magic = TOR_TLS_MAGIC;
-
-  check_no_tls_errors();
-  tor_assert(context); /* make sure somebody made it first */
-  if (!(result->ssl = SSL_new(context->ctx))) {
-    tls_log_errors(NULL, LOG_WARN, LD_NET, "creating SSL object");
-    tor_free(result);
-    goto err;
-  }
-
-#ifdef SSL_set_tlsext_host_name
-  /* Browsers use the TLS hostname extension, so we should too. */
-  if (!isServer) {
-    char *fake_hostname = crypto_random_hostname(4,25, "www.",".com");
-    SSL_set_tlsext_host_name(result->ssl, fake_hostname);
-    tor_free(fake_hostname);
-  }
-#endif /* defined(SSL_set_tlsext_host_name) */
-
-  if (!SSL_set_cipher_list(result->ssl,
-                     isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) {
-    tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers");
-#ifdef SSL_set_tlsext_host_name
-    SSL_set_tlsext_host_name(result->ssl, NULL);
-#endif
-    SSL_free(result->ssl);
-    tor_free(result);
-    goto err;
-  }
-  result->socket = sock;
-  bio = BIO_new_socket(sock, BIO_NOCLOSE);
-  if (! bio) {
-    tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO");
-#ifdef SSL_set_tlsext_host_name
-    SSL_set_tlsext_host_name(result->ssl, NULL);
-#endif
-    SSL_free(result->ssl);
-    tor_free(result);
-    goto err;
-  }
-  {
-    int set_worked =
-      SSL_set_ex_data(result->ssl, tor_tls_object_ex_data_index, result);
-    if (!set_worked) {
-      log_warn(LD_BUG,
-               "Couldn't set the tls for an SSL*; connection will fail");
-    }
-  }
-  SSL_set_bio(result->ssl, bio, bio);
-  tor_tls_context_incref(context);
-  result->context = context;
-  result->state = TOR_TLS_ST_HANDSHAKE;
-  result->isServer = isServer;
-  result->wantwrite_n = 0;
-  result->last_write_count = (unsigned long) BIO_number_written(bio);
-  result->last_read_count = (unsigned long) BIO_number_read(bio);
-  if (result->last_write_count || result->last_read_count) {
-    log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu",
-             result->last_read_count, result->last_write_count);
-  }
-  if (isServer) {
-    SSL_set_info_callback(result->ssl, tor_tls_server_info_callback);
-  } else {
-    SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
-  }
-
-  if (isServer)
-    tor_tls_setup_session_secret_cb(result);
-
-  goto done;
- err:
-  result = NULL;
- done:
-  /* Not expected to get called. */
-  tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
-  return result;
-}
-
 /** Make future log messages about <b>tls</b> display the address
  * <b>address</b>.
  */
@@ -1378,64 +150,6 @@ tor_tls_set_logged_address(tor_tls_t *tls, const char *address)
   tls->address = tor_strdup(address);
 }
 
-/** Set <b>cb</b> to be called with argument <b>arg</b> whenever <b>tls</b>
- * next gets a client-side renegotiate in the middle of a read.  Do not
- * invoke this function until <em>after</em> initial handshaking is done!
- */
-void
-tor_tls_set_renegotiate_callback(tor_tls_t *tls,
-                                 void (*cb)(tor_tls_t *, void *arg),
-                                 void *arg)
-{
-  tls->negotiated_callback = cb;
-  tls->callback_arg = arg;
-  tls->got_renegotiate = 0;
-  if (cb) {
-    SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback);
-  } else {
-    SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback);
-  }
-}
-
-/** If this version of openssl requires it, turn on renegotiation on
- * <b>tls</b>.
- */
-void
-tor_tls_unblock_renegotiation(tor_tls_t *tls)
-{
-  /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
-   * as authenticating any earlier-received data. */
-  SSL_set_options(tls->ssl,
-                  SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
-}
-
-/** If this version of openssl supports it, turn off renegotiation on
- * <b>tls</b>.  (Our protocol never requires this for security, but it's nice
- * to use belt-and-suspenders here.)
- */
-void
-tor_tls_block_renegotiation(tor_tls_t *tls)
-{
-#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG
-  tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
-#else
-  (void) tls;
-#endif
-}
-
-/** Assert that the flags that allow legacy renegotiation are still set */
-void
-tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
-{
-#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && \
-  SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION != 0
-  long options = SSL_get_options(tls->ssl);
-  tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
-#else
-  (void) tls;
-#endif /* defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && ... */
-}
-
 /** Return whether this tls initiated the connect (client) or
  * received it (server). */
 int
@@ -1444,730 +158,3 @@ tor_tls_is_server(tor_tls_t *tls)
   tor_assert(tls);
   return tls->isServer;
 }
-
-/** Release resources associated with a TLS object.  Does not close the
- * underlying file descriptor.
- */
-void
-tor_tls_free_(tor_tls_t *tls)
-{
-  if (!tls)
-    return;
-  tor_assert(tls->ssl);
-  {
-    size_t r,w;
-    tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
-  }
-#ifdef SSL_set_tlsext_host_name
-  SSL_set_tlsext_host_name(tls->ssl, NULL);
-#endif
-  SSL_free(tls->ssl);
-  tls->ssl = NULL;
-  tls->negotiated_callback = NULL;
-  if (tls->context)
-    tor_tls_context_decref(tls->context);
-  tor_free(tls->address);
-  tls->magic = 0x99999999;
-  tor_free(tls);
-}
-
-/** Underlying function for TLS reading.  Reads up to <b>len</b>
- * characters from <b>tls</b> into <b>cp</b>.  On success, returns the
- * number of characters read.  On failure, returns TOR_TLS_ERROR,
- * TOR_TLS_CLOSE, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.
- */
-MOCK_IMPL(int,
-tor_tls_read,(tor_tls_t *tls, char *cp, size_t len))
-{
-  int r, err;
-  tor_assert(tls);
-  tor_assert(tls->ssl);
-  tor_assert(tls->state == TOR_TLS_ST_OPEN);
-  tor_assert(len<INT_MAX);
-  r = SSL_read(tls->ssl, cp, (int)len);
-  if (r > 0) {
-    if (tls->got_renegotiate) {
-      /* Renegotiation happened! */
-      log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls));
-      if (tls->negotiated_callback)
-        tls->negotiated_callback(tls, tls->callback_arg);
-      tls->got_renegotiate = 0;
-    }
-    return r;
-  }
-  err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
-  if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) {
-    log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
-    tls->state = TOR_TLS_ST_CLOSED;
-    return TOR_TLS_CLOSE;
-  } else {
-    tor_assert(err != TOR_TLS_DONE);
-    log_debug(LD_NET,"read returned r=%d, err=%d",r,err);
-    return err;
-  }
-}
-
-/** Total number of bytes that we've used TLS to send.  Used to track TLS
- * overhead. */
-STATIC uint64_t total_bytes_written_over_tls = 0;
-/** Total number of bytes that TLS has put on the network for us. Used to
- * track TLS overhead. */
-STATIC uint64_t total_bytes_written_by_tls = 0;
-
-/** Underlying function for TLS writing.  Write up to <b>n</b>
- * characters from <b>cp</b> onto <b>tls</b>.  On success, returns the
- * number of characters written.  On failure, returns TOR_TLS_ERROR,
- * TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.
- */
-int
-tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
-{
-  int r, err;
-  tor_assert(tls);
-  tor_assert(tls->ssl);
-  tor_assert(tls->state == TOR_TLS_ST_OPEN);
-  tor_assert(n < INT_MAX);
-  if (n == 0)
-    return 0;
-  if (tls->wantwrite_n) {
-    /* if WANTWRITE last time, we must use the _same_ n as before */
-    tor_assert(n >= tls->wantwrite_n);
-    log_debug(LD_NET,"resuming pending-write, (%d to flush, reusing %d)",
-              (int)n, (int)tls->wantwrite_n);
-    n = tls->wantwrite_n;
-    tls->wantwrite_n = 0;
-  }
-  r = SSL_write(tls->ssl, cp, (int)n);
-  err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
-  if (err == TOR_TLS_DONE) {
-    total_bytes_written_over_tls += r;
-    return r;
-  }
-  if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) {
-    tls->wantwrite_n = n;
-  }
-  return err;
-}
-
-/** Perform initial handshake on <b>tls</b>.  When finished, returns
- * TOR_TLS_DONE.  On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
- * or TOR_TLS_WANTWRITE.
- */
-int
-tor_tls_handshake(tor_tls_t *tls)
-{
-  int r;
-  tor_assert(tls);
-  tor_assert(tls->ssl);
-  tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
-
-  check_no_tls_errors();
-
-  OSSL_HANDSHAKE_STATE oldstate = SSL_get_state(tls->ssl);
-
-  if (tls->isServer) {
-    log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
-              SSL_state_string_long(tls->ssl));
-    r = SSL_accept(tls->ssl);
-  } else {
-    log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls,
-              SSL_state_string_long(tls->ssl));
-    r = SSL_connect(tls->ssl);
-  }
-
-  OSSL_HANDSHAKE_STATE newstate = SSL_get_state(tls->ssl);
-
-  if (oldstate != newstate)
-    log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
-              tls, SSL_state_string_long(tls->ssl));
-  /* We need to call this here and not earlier, since OpenSSL has a penchant
-   * for clearing its flags when you say accept or connect. */
-  tor_tls_unblock_renegotiation(tls);
-  r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE);
-  if (ERR_peek_error() != 0) {
-    tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE,
-                   "handshaking");
-    return TOR_TLS_ERROR_MISC;
-  }
-  if (r == TOR_TLS_DONE) {
-    tls->state = TOR_TLS_ST_OPEN;
-    return tor_tls_finish_handshake(tls);
-  }
-  return r;
-}
-
-/** Perform the final part of the initial TLS handshake on <b>tls</b>.  This
- * should be called for the first handshake only: it determines whether the v1
- * or the v2 handshake was used, and adjusts things for the renegotiation
- * handshake as appropriate.
- *
- * tor_tls_handshake() calls this on its own; you only need to call this if
- * bufferevent is doing the handshake for you.
- */
-int
-tor_tls_finish_handshake(tor_tls_t *tls)
-{
-  int r = TOR_TLS_DONE;
-  check_no_tls_errors();
-  if (tls->isServer) {
-    SSL_set_info_callback(tls->ssl, NULL);
-    SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb);
-    SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN);
-    if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) {
-      /* This check is redundant, but back when we did it in the callback,
-       * we might have not been able to look up the tor_tls_t if the code
-       * was buggy.  Fixing that. */
-      if (!tls->wasV2Handshake) {
-        log_warn(LD_BUG, "For some reason, wasV2Handshake didn't"
-                 " get set. Fixing that.");
-      }
-      tls->wasV2Handshake = 1;
-      log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting"
-                " for renegotiation.");
-    } else {
-      tls->wasV2Handshake = 0;
-    }
-  } else {
-    /* Client-side */
-    tls->wasV2Handshake = 1;
-    /* XXXX this can move, probably? -NM */
-    if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) {
-      tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers");
-      r = TOR_TLS_ERROR_MISC;
-    }
-  }
-  tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake");
-  return r;
-}
-
-/** Shut down an open tls connection <b>tls</b>.  When finished, returns
- * TOR_TLS_DONE.  On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
- * or TOR_TLS_WANTWRITE.
- */
-int
-tor_tls_shutdown(tor_tls_t *tls)
-{
-  int r, err;
-  char buf[128];
-  tor_assert(tls);
-  tor_assert(tls->ssl);
-  check_no_tls_errors();
-
-  while (1) {
-    if (tls->state == TOR_TLS_ST_SENTCLOSE) {
-      /* If we've already called shutdown once to send a close message,
-       * we read until the other side has closed too.
-       */
-      do {
-        r = SSL_read(tls->ssl, buf, 128);
-      } while (r>0);
-      err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
-                              LOG_INFO, LD_NET);
-      if (err == TOR_TLS_ZERORETURN_) {
-        tls->state = TOR_TLS_ST_GOTCLOSE;
-        /* fall through... */
-      } else {
-        return err;
-      }
-    }
-
-    r = SSL_shutdown(tls->ssl);
-    if (r == 1) {
-      /* If shutdown returns 1, the connection is entirely closed. */
-      tls->state = TOR_TLS_ST_CLOSED;
-      return TOR_TLS_DONE;
-    }
-    err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
-                            LOG_INFO, LD_NET);
-    if (err == TOR_TLS_SYSCALL_) {
-      /* The underlying TCP connection closed while we were shutting down. */
-      tls->state = TOR_TLS_ST_CLOSED;
-      return TOR_TLS_DONE;
-    } else if (err == TOR_TLS_ZERORETURN_) {
-      /* The TLS connection says that it sent a shutdown record, but
-       * isn't done shutting down yet.  Make sure that this hasn't
-       * happened before, then go back to the start of the function
-       * and try to read.
-       */
-      if (tls->state == TOR_TLS_ST_GOTCLOSE ||
-         tls->state == TOR_TLS_ST_SENTCLOSE) {
-        log_warn(LD_NET,
-            "TLS returned \"half-closed\" value while already half-closed");
-        return TOR_TLS_ERROR_MISC;
-      }
-      tls->state = TOR_TLS_ST_SENTCLOSE;
-      /* fall through ... */
-    } else {
-      return err;
-    }
-  } /* end loop */
-}
-
-/** Return true iff this TLS connection is authenticated.
- */
-int
-tor_tls_peer_has_cert(tor_tls_t *tls)
-{
-  X509 *cert;
-  cert = SSL_get_peer_certificate(tls->ssl);
-  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
-  if (!cert)
-    return 0;
-  X509_free(cert);
-  return 1;
-}
-
-/** Return a newly allocated copy of the peer certificate, or NULL if there
- * isn't one. */
-MOCK_IMPL(tor_x509_cert_t *,
-tor_tls_get_peer_cert,(tor_tls_t *tls))
-{
-  X509 *cert;
-  cert = SSL_get_peer_certificate(tls->ssl);
-  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
-  if (!cert)
-    return NULL;
-  return tor_x509_cert_new(cert);
-}
-
-/** Return a newly allocated copy of the cerficate we used on the connection,
- * or NULL if somehow we didn't use one. */
-MOCK_IMPL(tor_x509_cert_t *,
-tor_tls_get_own_cert,(tor_tls_t *tls))
-{
-  X509 *cert = SSL_get_certificate(tls->ssl);
-  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE,
-                 "getting own-connection certificate");
-  if (!cert)
-    return NULL;
-  /* Fun inconsistency: SSL_get_peer_certificate increments the reference
-   * count, but SSL_get_certificate does not. */
-  X509 *duplicate = X509_dup(cert);
-  if (BUG(duplicate == NULL))
-    return NULL;
-  return tor_x509_cert_new(duplicate);
-}
-
-/** Helper function: try to extract a link certificate and an identity
- * certificate from <b>tls</b>, and store them in *<b>cert_out</b> and
- * *<b>id_cert_out</b> respectively.  Log all messages at level
- * <b>severity</b>.
- *
- * Note that a reference is added to cert_out, so it needs to be
- * freed. id_cert_out doesn't. */
-MOCK_IMPL(STATIC void,
-try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
-                               X509 **cert_out, X509 **id_cert_out))
-{
-  X509 *cert = NULL, *id_cert = NULL;
-  STACK_OF(X509) *chain = NULL;
-  int num_in_chain, i;
-  *cert_out = *id_cert_out = NULL;
-  if (!(cert = SSL_get_peer_certificate(tls->ssl)))
-    return;
-  *cert_out = cert;
-  if (!(chain = SSL_get_peer_cert_chain(tls->ssl)))
-    return;
-  num_in_chain = sk_X509_num(chain);
-  /* 1 means we're receiving (server-side), and it's just the id_cert.
-   * 2 means we're connecting (client-side), and it's both the link
-   * cert and the id_cert.
-   */
-  if (num_in_chain < 1) {
-    log_fn(severity,LD_PROTOCOL,
-           "Unexpected number of certificates in chain (%d)",
-           num_in_chain);
-    return;
-  }
-  for (i=0; i<num_in_chain; ++i) {
-    id_cert = sk_X509_value(chain, i);
-    if (X509_cmp(id_cert, cert) != 0)
-      break;
-  }
-  *id_cert_out = id_cert;
-}
-
-/** If the provided tls connection is authenticated and has a
- * certificate chain that is currently valid and signed, then set
- * *<b>identity_key</b> to the identity certificate's key and return
- * 0.  Else, return -1 and log complaints with log-level <b>severity</b>.
- */
-int
-tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
-{
-  X509 *cert = NULL, *id_cert = NULL;
-  EVP_PKEY *id_pkey = NULL;
-  RSA *rsa;
-  int r = -1;
-
-  check_no_tls_errors();
-  *identity_key = NULL;
-
-  try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert);
-  if (!cert)
-    goto done;
-  if (!id_cert) {
-    log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found");
-    goto done;
-  }
-  tls_log_errors(tls, severity, LD_HANDSHAKE, "before verifying certificate");
-
-  if (!(id_pkey = X509_get_pubkey(id_cert)) ||
-      X509_verify(cert, id_pkey) <= 0) {
-    log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0");
-    tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate");
-    goto done;
-  }
-
-  rsa = EVP_PKEY_get1_RSA(id_pkey);
-  if (!rsa)
-    goto done;
-  *identity_key = crypto_new_pk_from_openssl_rsa_(rsa);
-
-  r = 0;
-
- done:
-  if (cert)
-    X509_free(cert);
-  if (id_pkey)
-    EVP_PKEY_free(id_pkey);
-
-  /* This should never get invoked, but let's make sure in case OpenSSL
-   * acts unexpectedly. */
-  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify");
-
-  return r;
-}
-
-/** Check whether the certificate set on the connection <b>tls</b> is expired
- * give or take <b>past_tolerance</b> seconds, or not-yet-valid give or take
- * <b>future_tolerance</b> seconds. Return 0 for valid, -1 for failure.
- *
- * NOTE: you should call tor_tls_verify before tor_tls_check_lifetime.
- */
-int
-tor_tls_check_lifetime(int severity, tor_tls_t *tls,
-                       time_t now,
-                       int past_tolerance, int future_tolerance)
-{
-  X509 *cert;
-  int r = -1;
-
-  if (!(cert = SSL_get_peer_certificate(tls->ssl)))
-    goto done;
-
-  if (tor_x509_check_cert_lifetime_internal(severity, cert, now,
-                                            past_tolerance,
-                                            future_tolerance) < 0)
-    goto done;
-
-  r = 0;
- done:
-  if (cert)
-    X509_free(cert);
-  /* Not expected to get invoked */
-  tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime");
-
-  return r;
-}
-
-/** Return the number of bytes available for reading from <b>tls</b>.
- */
-int
-tor_tls_get_pending_bytes(tor_tls_t *tls)
-{
-  tor_assert(tls);
-  return SSL_pending(tls->ssl);
-}
-
-/** If <b>tls</b> requires that the next write be of a particular size,
- * return that size.  Otherwise, return 0. */
-size_t
-tor_tls_get_forced_write_size(tor_tls_t *tls)
-{
-  return tls->wantwrite_n;
-}
-
-/** Sets n_read and n_written to the number of bytes read and written,
- * respectively, on the raw socket used by <b>tls</b> since the last time this
- * function was called on <b>tls</b>. */
-void
-tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written)
-{
-  BIO *wbio, *tmpbio;
-  unsigned long r, w;
-  r = (unsigned long) BIO_number_read(SSL_get_rbio(tls->ssl));
-  /* We want the number of bytes actually for real written.  Unfortunately,
-   * sometimes OpenSSL replaces the wbio on tls->ssl with a buffering bio,
-   * which makes the answer turn out wrong.  Let's cope with that.  Note
-   * that this approach will fail if we ever replace tls->ssl's BIOs with
-   * buffering bios for reasons of our own.  As an alternative, we could
-   * save the original BIO for  tls->ssl in the tor_tls_t structure, but
-   * that would be tempting fate. */
-  wbio = SSL_get_wbio(tls->ssl);
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)
-  /* BIO structure is opaque as of OpenSSL 1.1.0-pre5-dev.  Again, not
-   * supposed to use this form of the version macro, but the OpenSSL developers
-   * introduced major API changes in the pre-release stage.
-   */
-  if (BIO_method_type(wbio) == BIO_TYPE_BUFFER &&
-        (tmpbio = BIO_next(wbio)) != NULL)
-    wbio = tmpbio;
-#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)) */
-  if (wbio->method == BIO_f_buffer() && (tmpbio = BIO_next(wbio)) != NULL)
-    wbio = tmpbio;
-#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) */
-  w = (unsigned long) BIO_number_written(wbio);
-
-  /* We are ok with letting these unsigned ints go "negative" here:
-   * If we wrapped around, this should still give us the right answer, unless
-   * we wrapped around by more than ULONG_MAX since the last time we called
-   * this function.
-   */
-  *n_read = (size_t)(r - tls->last_read_count);
-  *n_written = (size_t)(w - tls->last_write_count);
-  if (*n_read > INT_MAX || *n_written > INT_MAX) {
-    log_warn(LD_BUG, "Preposterously large value in tor_tls_get_n_raw_bytes. "
-             "r=%lu, last_read=%lu, w=%lu, last_written=%lu",
-             r, tls->last_read_count, w, tls->last_write_count);
-  }
-  total_bytes_written_by_tls += *n_written;
-  tls->last_read_count = r;
-  tls->last_write_count = w;
-}
-
-/** Return a ratio of the bytes that TLS has sent to the bytes that we've told
- * it to send. Used to track whether our TLS records are getting too tiny. */
-MOCK_IMPL(double,
-tls_get_write_overhead_ratio,(void))
-{
-  if (total_bytes_written_over_tls == 0)
-    return 1.0;
-
-  return ((double)total_bytes_written_by_tls) /
-    ((double)total_bytes_written_over_tls);
-}
-
-/** Implement check_no_tls_errors: If there are any pending OpenSSL
- * errors, log an error message. */
-void
-check_no_tls_errors_(const char *fname, int line)
-{
-  if (ERR_peek_error() == 0)
-    return;
-  log_warn(LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
-      tor_fix_source_file(fname), line);
-  tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
-}
-
-/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2
- * TLS handshake. Output is undefined if the handshake isn't finished. */
-int
-tor_tls_used_v1_handshake(tor_tls_t *tls)
-{
-  return ! tls->wasV2Handshake;
-}
-
-/** Return the number of server handshakes that we've noticed doing on
- * <b>tls</b>. */
-int
-tor_tls_get_num_server_handshakes(tor_tls_t *tls)
-{
-  return tls->server_handshake_count;
-}
-
-/** Return true iff the server TLS connection <b>tls</b> got the renegotiation
- * request it was waiting for. */
-int
-tor_tls_server_got_renegotiate(tor_tls_t *tls)
-{
-  return tls->got_renegotiate;
-}
-
-#ifndef HAVE_SSL_GET_CLIENT_RANDOM
-static size_t
-SSL_get_client_random(SSL *s, uint8_t *out, size_t len)
-{
-  if (len == 0)
-    return SSL3_RANDOM_SIZE;
-  tor_assert(len == SSL3_RANDOM_SIZE);
-  tor_assert(s->s3);
-  memcpy(out, s->s3->client_random, len);
-  return len;
-}
-#endif /* !defined(HAVE_SSL_GET_CLIENT_RANDOM) */
-
-#ifndef HAVE_SSL_GET_SERVER_RANDOM
-static size_t
-SSL_get_server_random(SSL *s, uint8_t *out, size_t len)
-{
-  if (len == 0)
-    return SSL3_RANDOM_SIZE;
-  tor_assert(len == SSL3_RANDOM_SIZE);
-  tor_assert(s->s3);
-  memcpy(out, s->s3->server_random, len);
-  return len;
-}
-#endif /* !defined(HAVE_SSL_GET_SERVER_RANDOM) */
-
-#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
-STATIC size_t
-SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len)
-{
-  tor_assert(s);
-  if (len == 0)
-    return s->master_key_length;
-  tor_assert(len == (size_t)s->master_key_length);
-  tor_assert(out);
-  memcpy(out, s->master_key, len);
-  return len;
-}
-#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */
-
-/** Set the DIGEST256_LEN buffer at <b>secrets_out</b> to the value used in
- * the v3 handshake to prove that the client knows the TLS secrets for the
- * connection <b>tls</b>.  Return 0 on success, -1 on failure.
- */
-MOCK_IMPL(int,
-tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
-{
-#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification"
-  uint8_t buf[128];
-  size_t len;
-  tor_assert(tls);
-
-  SSL *const ssl = tls->ssl;
-  SSL_SESSION *const session = SSL_get_session(ssl);
-
-  tor_assert(ssl);
-  tor_assert(session);
-
-  const size_t server_random_len = SSL_get_server_random(ssl, NULL, 0);
-  const size_t client_random_len = SSL_get_client_random(ssl, NULL, 0);
-  const size_t master_key_len = SSL_SESSION_get_master_key(session, NULL, 0);
-
-  tor_assert(server_random_len);
-  tor_assert(client_random_len);
-  tor_assert(master_key_len);
-
-  len = client_random_len + server_random_len + strlen(TLSSECRET_MAGIC) + 1;
-  tor_assert(len <= sizeof(buf));
-
-  {
-    size_t r = SSL_get_client_random(ssl, buf, client_random_len);
-    tor_assert(r == client_random_len);
-  }
-
-  {
-    size_t r = SSL_get_server_random(ssl,
-                                     buf+client_random_len,
-                                     server_random_len);
-    tor_assert(r == server_random_len);
-  }
-
-  uint8_t *master_key = tor_malloc_zero(master_key_len);
-  {
-    size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len);
-    tor_assert(r == master_key_len);
-  }
-
-  uint8_t *nextbuf = buf + client_random_len + server_random_len;
-  memcpy(nextbuf, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1);
-
-  /*
-    The value is an HMAC, using the TLS master key as the HMAC key, of
-    client_random | server_random | TLSSECRET_MAGIC
-  */
-  crypto_hmac_sha256((char*)secrets_out,
-                     (char*)master_key,
-                     master_key_len,
-                     (char*)buf, len);
-  memwipe(buf, 0, sizeof(buf));
-  memwipe(master_key, 0, master_key_len);
-  tor_free(master_key);
-
-  return 0;
-}
-
-/** Using the RFC5705 key material exporting construction, and the
- * provided <b>context</b> (<b>context_len</b> bytes long) and
- * <b>label</b> (a NUL-terminated string), compute a 32-byte secret in
- * <b>secrets_out</b> that only the parties to this TLS session can
- * compute.  Return 0 on success and -1 on failure.
- */
-MOCK_IMPL(int,
-tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
-                             const uint8_t *context,
-                             size_t context_len,
-                             const char *label))
-{
-  tor_assert(tls);
-  tor_assert(tls->ssl);
-
-  int r = SSL_export_keying_material(tls->ssl,
-                                     secrets_out, DIGEST256_LEN,
-                                     label, strlen(label),
-                                     context, context_len, 1);
-  return (r == 1) ? 0 : -1;
-}
-
-/** Examine the amount of memory used and available for buffers in <b>tls</b>.
- * Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read
- * buffer and *<b>rbuf_bytes</b> to the amount actually used.
- * Set *<b>wbuf_capacity</b> to the amount of storage allocated for the write
- * buffer and *<b>wbuf_bytes</b> to the amount actually used.
- *
- * Return 0 on success, -1 on failure.*/
-int
-tor_tls_get_buffer_sizes(tor_tls_t *tls,
-                         size_t *rbuf_capacity, size_t *rbuf_bytes,
-                         size_t *wbuf_capacity, size_t *wbuf_bytes)
-{
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
-  (void)tls;
-  (void)rbuf_capacity;
-  (void)rbuf_bytes;
-  (void)wbuf_capacity;
-  (void)wbuf_bytes;
-
-  return -1;
-#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)) */
-  if (tls->ssl->s3->rbuf.buf)
-    *rbuf_capacity = tls->ssl->s3->rbuf.len;
-  else
-    *rbuf_capacity = 0;
-  if (tls->ssl->s3->wbuf.buf)
-    *wbuf_capacity = tls->ssl->s3->wbuf.len;
-  else
-    *wbuf_capacity = 0;
-  *rbuf_bytes = tls->ssl->s3->rbuf.left;
-  *wbuf_bytes = tls->ssl->s3->wbuf.left;
-  return 0;
-#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
-}
-
-/** Check whether the ECC group requested is supported by the current OpenSSL
- * library instance.  Return 1 if the group is supported, and 0 if not.
- */
-int
-evaluate_ecgroup_for_tls(const char *ecgroup)
-{
-  EC_KEY *ec_key;
-  int nid;
-  int ret;
-
-  if (!ecgroup)
-    nid = NID_tor_default_ecdhe_group;
-  else if (!strcasecmp(ecgroup, "P256"))
-    nid = NID_X9_62_prime256v1;
-  else if (!strcasecmp(ecgroup, "P224"))
-    nid = NID_secp224r1;
-  else
-    return 0;
-
-  ec_key = EC_KEY_new_by_curve_name(nid);
-  ret = (ec_key != NULL);
-  EC_KEY_free(ec_key);
-
-  return ret;
-}
diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h
index f46e73267..306d321cd 100644
--- a/src/lib/tls/tortls.h
+++ b/src/lib/tls/tortls.h
@@ -50,74 +50,13 @@ struct tor_x509_cert_t;
 
 #define TOR_TLS_IS_ERROR(rv) ((rv) < TOR_TLS_CLOSE)
 
-#ifdef TORTLS_PRIVATE
-
-#ifdef ENABLE_OPENSSL
-struct ssl_st;
-struct ssl_ctx_st;
-struct ssl_session_st;
-#endif
-
 /** Holds a SSL_CTX object and related state used to configure TLS
  * connections.
  */
 typedef struct tor_tls_context_t tor_tls_context_t;
 
-STATIC int tor_errno_to_tls_error(int e);
-STATIC int tor_tls_get_error(tor_tls_t *tls, int r, int extra,
-                  const char *doing, int severity, int domain);
-STATIC tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl);
-STATIC void tor_tls_allocate_tor_tls_object_ex_data_index(void);
-MOCK_DECL(STATIC void, try_to_extract_certs_from_tls,
-          (int severity, tor_tls_t *tls, struct x509_st **cert_out,
-           struct x509_st **id_cert_out));
-#ifdef TORTLS_OPENSSL_PRIVATE
-STATIC int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx);
-STATIC int tor_tls_classify_client_ciphers(const struct ssl_st *ssl,
-                                           STACK_OF(SSL_CIPHER) *peer_ciphers);
-#endif
-STATIC int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl);
-#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
-STATIC size_t SSL_SESSION_get_master_key(struct ssl_session_st *s,
-                                         uint8_t *out,
-                                         size_t len);
-#endif
-STATIC void tor_tls_debug_state_callback(const struct ssl_st *ssl,
-                                         int type, int val);
-STATIC void tor_tls_server_info_callback(const struct ssl_st *ssl,
-                                         int type, int val);
-#ifdef TORTLS_OPENSSL_PRIVATE
-STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret,
-                            int *secret_len,
-                            STACK_OF(SSL_CIPHER) *peer_ciphers,
-                            CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher,
-                            void *arg);
-STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m,
-                             uint16_t cipher);
-#endif /* defined(TORTLS_OPENSSL_PRIVATE) */
-STATIC tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
-                   unsigned int key_lifetime, unsigned flags, int is_client);
-STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
-                                    crypto_pk_t *identity,
-                                    unsigned int key_lifetime,
-                                    unsigned int flags,
-                                    int is_client);
-
-#ifdef TOR_UNIT_TESTS
-extern int tor_tls_object_ex_data_index;
-extern tor_tls_context_t *server_tls_context;
-extern tor_tls_context_t *client_tls_context;
-extern uint16_t v2_cipher_list[];
-extern uint64_t total_bytes_written_over_tls;
-extern uint64_t total_bytes_written_by_tls;
-
-#endif /* defined(TOR_UNIT_TESTS) */
-
-#endif /* defined(TORTLS_PRIVATE) */
-
 const char *tor_tls_err_to_string(int err);
 void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz);
-
 void tor_tls_free_all(void);
 
 #define TOR_TLS_CTX_IS_PUBLIC_SERVER (1u<<0)
@@ -131,6 +70,9 @@ int tor_tls_context_init(unsigned flags,
                          crypto_pk_t *client_identity,
                          crypto_pk_t *server_identity,
                          unsigned int key_lifetime);
+void tor_tls_context_incref(tor_tls_context_t *ctx);
+void tor_tls_context_decref(tor_tls_context_t *ctx);
+tor_tls_context_t *tor_tls_context_get(int is_server);
 tor_tls_t *tor_tls_new(int sock, int is_server);
 void tor_tls_set_logged_address(tor_tls_t *tls, const char *address);
 void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
new file mode 100644
index 000000000..f6afb348c
--- /dev/null
+++ b/src/lib/tls/tortls_internal.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TORTLS_INTERNAL_H
+#define TORTLS_INTERNAL_H
+
+#ifdef ENABLE_OPENSSL
+struct ssl_st;
+struct ssl_ctx_st;
+struct ssl_session_st;
+#endif
+
+int tor_errno_to_tls_error(int e);
+int tor_tls_get_error(tor_tls_t *tls, int r, int extra,
+                  const char *doing, int severity, int domain);
+tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl);
+void tor_tls_allocate_tor_tls_object_ex_data_index(void);
+MOCK_DECL(void, try_to_extract_certs_from_tls,
+          (int severity, tor_tls_t *tls,
+           tor_x509_cert_impl_t **cert_out,
+           tor_x509_cert_impl_t **id_cert_out));
+#ifdef TORTLS_OPENSSL_PRIVATE
+int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx);
+int tor_tls_classify_client_ciphers(const struct ssl_st *ssl,
+                                           STACK_OF(SSL_CIPHER) *peer_ciphers);
+#endif
+int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl);
+#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
+size_t SSL_SESSION_get_master_key(struct ssl_session_st *s,
+                                  uint8_t *out,
+                                  size_t len);
+#endif
+void tor_tls_debug_state_callback(const struct ssl_st *ssl,
+                                         int type, int val);
+void tor_tls_server_info_callback(const struct ssl_st *ssl,
+                                         int type, int val);
+#ifdef TORTLS_OPENSSL_PRIVATE
+STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret,
+                            int *secret_len,
+                            STACK_OF(SSL_CIPHER) *peer_ciphers,
+                            CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher,
+                            void *arg);
+STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m,
+                             uint16_t cipher);
+#endif /* defined(TORTLS_OPENSSL_PRIVATE) */
+tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
+                   unsigned int key_lifetime, unsigned flags, int is_client);
+int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
+                             crypto_pk_t *identity,
+                             unsigned int key_lifetime,
+                             unsigned int flags,
+                             int is_client);
+
+#ifdef TOR_UNIT_TESTS
+extern int tor_tls_object_ex_data_index;
+extern tor_tls_context_t *server_tls_context;
+extern tor_tls_context_t *client_tls_context;
+extern uint16_t v2_cipher_list[];
+extern uint64_t total_bytes_written_over_tls;
+extern uint64_t total_bytes_written_by_tls;
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* defined(TORTLS_INTERNAL_H) */
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
new file mode 100644
index 000000000..078196ac5
--- /dev/null
+++ b/src/lib/tls/tortls_nss.c
@@ -0,0 +1,432 @@
+/* Copyright (c) 2003, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tortls_nss.c
+ * \brief Wrapper functions to present a consistent interface to
+ * TLS and SSL X.509 functions from NSS.
+ **/
+
+#include "orconfig.h"
+
+#define TORTLS_PRIVATE
+
+#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
+  #include <winsock2.h>
+  #include <ws2tcpip.h>
+#endif
+
+#include "lib/crypt_ops/crypto_cipher.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_dh.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/tls/x509.h"
+#include "lib/tls/tortls.h"
+#include "lib/tls/tortls_internal.h"
+#include "lib/log/util_bug.h"
+
+int
+tor_errno_to_tls_error(int e)
+{
+  (void)e;
+  // XXXX
+  return -1;
+}
+int
+tor_tls_get_error(tor_tls_t *tls, int r, int extra,
+                  const char *doing, int severity, int domain)
+{
+  (void)tls;
+  (void)r;
+  (void)extra;
+  (void)doing;
+  (void)severity;
+  (void)domain;
+  // XXXX
+  return -1;
+}
+tor_tls_t *
+tor_tls_get_by_ssl(const struct ssl_st *ssl)
+{
+  (void) ssl;
+  // XXXX
+  // XXXX refers to ssl_st.
+  return NULL;
+}
+void
+tor_tls_allocate_tor_tls_object_ex_data_index(void)
+{
+  // XXXX openssl only.
+}
+MOCK_IMPL(void,
+try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
+                               tor_x509_cert_impl_t **cert_out,
+                               tor_x509_cert_impl_t **id_cert_out))
+{
+  tor_assert(tls);
+  tor_assert(cert_out);
+  tor_assert(id_cert_out);
+  (void)severity;
+  // XXXX
+}
+int
+tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl)
+{
+  (void) ssl;
+  // XXXX
+  // XXXX refers to ssl_st.
+  return 0;
+}
+
+void
+tor_tls_debug_state_callback(const struct ssl_st *ssl,
+                             int type, int val)
+{
+  (void) ssl;
+  (void)type;
+  (void)val;
+  // XXXX
+  // XXXX refers to ssl_st.
+}
+
+void
+tor_tls_server_info_callback(const struct ssl_st *ssl,
+                             int type, int val)
+{
+  (void)ssl;
+  (void)type;
+  (void)val;
+  // XXXX
+  // XXXX refers to ssl_st.
+}
+tor_tls_context_t *
+tor_tls_context_new(crypto_pk_t *identity,
+                    unsigned int key_lifetime, unsigned flags, int is_client)
+{
+  tor_assert(identity);
+  tor_assert(key_lifetime);
+  (void)flags;
+  (void)is_client;
+  // XXXX
+  return NULL;
+}
+int
+tor_tls_context_init_one(tor_tls_context_t **ppcontext,
+                         crypto_pk_t *identity,
+                         unsigned int key_lifetime,
+                         unsigned int flags,
+                         int is_client)
+{
+  tor_assert(ppcontext);
+  tor_assert(identity);
+  tor_assert(key_lifetime);
+  (void)flags;
+  (void)is_client;
+  // XXXX
+  return -1;
+}
+
+void
+tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
+{
+  (void)tls;
+  (void)buf;
+  (void)sz;
+  // XXXX
+}
+
+void
+tor_tls_init(void)
+{
+  // XXXX
+}
+void
+tls_log_errors(tor_tls_t *tls, int severity, int domain,
+               const char *doing)
+{
+  (void)tls;
+  (void)severity;
+  (void)domain;
+  (void)doing;
+  // XXXX
+}
+
+tor_tls_t *
+tor_tls_new(int sock, int is_server)
+{
+  (void)sock;
+  (void)is_server;
+  // XXXX
+  return NULL;
+}
+void
+tor_tls_set_renegotiate_callback(tor_tls_t *tls,
+                                 void (*cb)(tor_tls_t *, void *arg),
+                                 void *arg)
+{
+  tor_assert(tls);
+  (void)cb;
+  (void)arg;
+  // XXXX;
+}
+
+void
+tor_tls_free_(tor_tls_t *tls)
+{
+  (void)tls;
+  // XXXX
+}
+
+int
+tor_tls_peer_has_cert(tor_tls_t *tls)
+{
+  (void)tls;
+  // XXXX
+  return -1;
+}
+MOCK_IMPL(tor_x509_cert_t *,
+tor_tls_get_peer_cert,(tor_tls_t *tls))
+{
+  tor_assert(tls);
+  // XXXX
+  return NULL;
+}
+MOCK_IMPL(tor_x509_cert_t *,
+tor_tls_get_own_cert,(tor_tls_t *tls))
+{
+  tor_assert(tls);
+  // XXXX
+  return NULL;
+}
+int
+tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity)
+{
+  tor_assert(tls);
+  tor_assert(identity);
+  (void)severity;
+  // XXXX
+  return -1;
+}
+int
+tor_tls_check_lifetime(int severity,
+                       tor_tls_t *tls, time_t now,
+                       int past_tolerance,
+                       int future_tolerance)
+{
+  tor_assert(tls);
+  (void)severity;
+  (void)now;
+  (void)past_tolerance;
+  (void)future_tolerance;
+  // XXXX
+  return -1;
+}
+MOCK_IMPL(int,
+tor_tls_read, (tor_tls_t *tls, char *cp, size_t len))
+{
+  tor_assert(tls);
+  tor_assert(cp);
+  (void)len;
+  // XXXX
+  return -1;
+}
+int
+tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
+{
+  tor_assert(tls);
+  tor_assert(cp);
+  (void)n;
+  // XXXX
+  return -1;
+}
+int
+tor_tls_handshake(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return -1;
+}
+int
+tor_tls_finish_handshake(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return -1;
+}
+void
+tor_tls_unblock_renegotiation(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+}
+void
+tor_tls_block_renegotiation(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+}
+void
+tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+}
+int
+tor_tls_shutdown(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return -1;
+}
+int
+tor_tls_get_pending_bytes(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return -1;
+}
+size_t
+tor_tls_get_forced_write_size(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return 0;
+}
+void
+tor_tls_get_n_raw_bytes(tor_tls_t *tls,
+                        size_t *n_read, size_t *n_written)
+{
+  tor_assert(tls);
+  tor_assert(n_read);
+  tor_assert(n_written);
+  // XXXX
+}
+
+int
+tor_tls_get_buffer_sizes(tor_tls_t *tls,
+                         size_t *rbuf_capacity, size_t *rbuf_bytes,
+                         size_t *wbuf_capacity, size_t *wbuf_bytes)
+{
+  tor_assert(tls);
+  tor_assert(rbuf_capacity);
+  tor_assert(rbuf_bytes);
+  tor_assert(wbuf_capacity);
+  tor_assert(wbuf_bytes);
+  // XXXX
+  return -1;
+}
+MOCK_IMPL(double,
+tls_get_write_overhead_ratio, (void))
+{
+  // XXXX
+  return 0.0;
+}
+
+int
+tor_tls_used_v1_handshake(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return -1;
+}
+int
+tor_tls_get_num_server_handshakes(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return -1;
+}
+int
+tor_tls_server_got_renegotiate(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return -1;
+}
+MOCK_IMPL(int,
+tor_tls_cert_matches_key,(const tor_tls_t *tls,
+                          const struct tor_x509_cert_t *cert))
+{
+  tor_assert(tls);
+  tor_assert(cert);
+  // XXXX
+  return 0;
+}
+MOCK_IMPL(int,
+tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
+{
+  tor_assert(tls);
+  tor_assert(secrets_out);
+  // XXXX
+  return -1;
+}
+MOCK_IMPL(int,
+tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
+                             const uint8_t *context,
+                             size_t context_len,
+                             const char *label))
+{
+  tor_assert(tls);
+  tor_assert(secrets_out);
+  tor_assert(context);
+  tor_assert(label);
+  (void)context_len;
+  // XXXX
+  return -1;
+}
+
+void
+check_no_tls_errors_(const char *fname, int line)
+{
+  (void)fname;
+  (void)line;
+  // XXXX
+}
+void
+tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
+                      int severity, int domain, const char *doing)
+{
+  tor_assert(tls);
+  (void)err;
+  (void)severity;
+  (void)domain;
+  (void)doing;
+  // XXXX
+}
+
+int
+tor_tls_get_my_certs(int server,
+                     const struct tor_x509_cert_t **link_cert_out,
+                     const struct tor_x509_cert_t **id_cert_out)
+{
+  tor_assert(link_cert_out);
+  tor_assert(id_cert_out);
+  (void)server;
+  // XXXX
+  return -1;
+}
+
+crypto_pk_t *
+tor_tls_get_my_client_auth_key(void)
+{
+  // XXXX
+  return NULL;
+}
+
+const char *
+tor_tls_get_ciphersuite_name(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  // XXXX
+  return NULL;
+}
+
+int
+evaluate_ecgroup_for_tls(const char *ecgroup)
+{
+  (void)ecgroup;
+  // XXXX
+  return -1;
+}
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
new file mode 100644
index 000000000..333b86481
--- /dev/null
+++ b/src/lib/tls/tortls_openssl.c
@@ -0,0 +1,2032 @@
+/* Copyright (c) 2003, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tortls.c
+ * \brief Wrapper functions to present a consistent interface to
+ * TLS, SSL, and X.509 functions from OpenSSL.
+ **/
+
+/* (Unlike other tor functions, these
+ * are prefixed with tor_ in order to avoid conflicting with OpenSSL
+ * functions and variables.)
+ */
+
+#include "orconfig.h"
+
+#define TORTLS_PRIVATE
+#define TORTLS_OPENSSL_PRIVATE
+
+#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
+  #include <winsock2.h>
+  #include <ws2tcpip.h>
+#endif
+
+#include "lib/crypt_ops/crypto_cipher.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_dh.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/crypt_ops/compat_openssl.h"
+#include "lib/tls/x509.h"
+
+/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
+ * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/opensslv.h>
+
+#ifdef OPENSSL_NO_EC
+#error "We require OpenSSL with ECC support"
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/ssl3.h>
+#include <openssl/err.h>
+#include <openssl/tls1.h>
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+#include "lib/tls/tortls.h"
+#include "lib/tls/tortls_st.h"
+#include "lib/tls/tortls_internal.h"
+#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
+#include "lib/container/smartlist.h"
+#include "lib/string/compat_string.h"
+#include "lib/string/printf.h"
+#include "lib/net/socket.h"
+#include "lib/intmath/cmp.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/encoding/time_fmt.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/arch/bytes.h"
+
+/* Copied from or.h */
+#define LEGAL_NICKNAME_CHARACTERS \
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+/** How long do identity certificates live? (sec) */
+#define IDENTITY_CERT_LIFETIME  (365*24*60*60)
+
+#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer")
+
+#if OPENSSL_VERSION_NUMBER <  OPENSSL_V(1,0,0,'f')
+/* This is a version of OpenSSL before 1.0.0f. It does not have
+ * the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and
+ * SSL3 safely at the same time.
+ */
+#define DISABLE_SSL3_HANDSHAKE
+#endif /* OPENSSL_VERSION_NUMBER <  OPENSSL_V(1,0,0,'f') */
+
+/* We redefine these so that we can run correctly even if the vendor gives us
+ * a version of OpenSSL that does not match its header files.  (Apple: I am
+ * looking at you.)
+ */
+#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L
+#endif
+#ifndef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010
+#endif
+
+/** Return values for tor_tls_classify_client_ciphers.
+ *
+ * @{
+ */
+/** An error occurred when examining the client ciphers */
+#define CIPHERS_ERR -1
+/** The client cipher list indicates that a v1 handshake was in use. */
+#define CIPHERS_V1 1
+/** The client cipher list indicates that the client is using the v2 or the
+ * v3 handshake, but that it is (probably!) lying about what ciphers it
+ * supports */
+#define CIPHERS_V2 2
+/** The client cipher list indicates that the client is using the v2 or the
+ * v3 handshake, and that it is telling the truth about what ciphers it
+ * supports */
+#define CIPHERS_UNRESTRICTED 3
+/** @} */
+
+/** The ex_data index in which we store a pointer to an SSL object's
+ * corresponding tor_tls_t object. */
+STATIC int tor_tls_object_ex_data_index = -1;
+
+/** Helper: Allocate tor_tls_object_ex_data_index. */
+void
+tor_tls_allocate_tor_tls_object_ex_data_index(void)
+{
+  if (tor_tls_object_ex_data_index == -1) {
+    tor_tls_object_ex_data_index =
+      SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+    tor_assert(tor_tls_object_ex_data_index != -1);
+  }
+}
+
+/** Helper: given a SSL* pointer, return the tor_tls_t object using that
+ * pointer. */
+tor_tls_t *
+tor_tls_get_by_ssl(const SSL *ssl)
+{
+  tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index);
+  if (result)
+    tor_assert(result->magic == TOR_TLS_MAGIC);
+  return result;
+}
+
+/** True iff tor_tls_init() has been called. */
+static int tls_library_is_initialized = 0;
+
+/* Module-internal error codes. */
+#define TOR_TLS_SYSCALL_    (MIN_TOR_TLS_ERROR_VAL_ - 2)
+#define TOR_TLS_ZERORETURN_ (MIN_TOR_TLS_ERROR_VAL_ - 1)
+
+/** Write a description of the current state of <b>tls</b> into the
+ * <b>sz</b>-byte buffer at <b>buf</b>. */
+void
+tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
+{
+  const char *ssl_state;
+  const char *tortls_state;
+
+  if (PREDICT_UNLIKELY(!tls || !tls->ssl)) {
+    strlcpy(buf, "(No SSL object)", sz);
+    return;
+  }
+
+  ssl_state = SSL_state_string_long(tls->ssl);
+  switch (tls->state) {
+#define CASE(st) case TOR_TLS_ST_##st: tortls_state = " in "#st ; break
+    CASE(HANDSHAKE);
+    CASE(OPEN);
+    CASE(GOTCLOSE);
+    CASE(SENTCLOSE);
+    CASE(CLOSED);
+    CASE(RENEGOTIATE);
+#undef CASE
+  case TOR_TLS_ST_BUFFEREVENT:
+    tortls_state = "";
+    break;
+  default:
+    tortls_state = " in unknown TLS state";
+    break;
+  }
+
+  tor_snprintf(buf, sz, "%s%s", ssl_state, tortls_state);
+}
+
+/** Log a single error <b>err</b> as returned by ERR_get_error(), which was
+ * received while performing an operation <b>doing</b> on <b>tls</b>.  Log
+ * the message at <b>severity</b>, in log domain <b>domain</b>. */
+void
+tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
+                  int severity, int domain, const char *doing)
+{
+  const char *state = NULL, *addr;
+  const char *msg, *lib, *func;
+
+  state = (tls && tls->ssl)?SSL_state_string_long(tls->ssl):"---";
+
+  addr = tls ? tls->address : NULL;
+
+  /* Some errors are known-benign, meaning they are the fault of the other
+   * side of the connection. The caller doesn't know this, so override the
+   * priority for those cases. */
+  switch (ERR_GET_REASON(err)) {
+    case SSL_R_HTTP_REQUEST:
+    case SSL_R_HTTPS_PROXY_REQUEST:
+    case SSL_R_RECORD_LENGTH_MISMATCH:
+#ifndef OPENSSL_1_1_API
+    case SSL_R_RECORD_TOO_LARGE:
+#endif
+    case SSL_R_UNKNOWN_PROTOCOL:
+    case SSL_R_UNSUPPORTED_PROTOCOL:
+      severity = LOG_INFO;
+      break;
+    default:
+      break;
+  }
+
+  msg = (const char*)ERR_reason_error_string(err);
+  lib = (const char*)ERR_lib_error_string(err);
+  func = (const char*)ERR_func_error_string(err);
+  if (!msg) msg = "(null)";
+  if (!lib) lib = "(null)";
+  if (!func) func = "(null)";
+  if (doing) {
+    tor_log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
+        doing, addr?" with ":"", addr?addr:"",
+        msg, lib, func, state);
+  } else {
+    tor_log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
+        addr?" with ":"", addr?addr:"",
+        msg, lib, func, state);
+  }
+}
+
+/** Log all pending tls errors at level <b>severity</b> in log domain
+ * <b>domain</b>.  Use <b>doing</b> to describe our current activities.
+ */
+void
+tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
+{
+  unsigned long err;
+
+  while ((err = ERR_get_error()) != 0) {
+    tor_tls_log_one_error(tls, err, severity, domain, doing);
+  }
+}
+
+/** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error
+ * code. */
+int
+tor_errno_to_tls_error(int e)
+{
+  switch (e) {
+    case SOCK_ERRNO(ECONNRESET): // most common
+      return TOR_TLS_ERROR_CONNRESET;
+    case SOCK_ERRNO(ETIMEDOUT):
+      return TOR_TLS_ERROR_TIMEOUT;
+    case SOCK_ERRNO(EHOSTUNREACH):
+    case SOCK_ERRNO(ENETUNREACH):
+      return TOR_TLS_ERROR_NO_ROUTE;
+    case SOCK_ERRNO(ECONNREFUSED):
+      return TOR_TLS_ERROR_CONNREFUSED; // least common
+    default:
+      return TOR_TLS_ERROR_MISC;
+  }
+}
+
+#define CATCH_SYSCALL 1
+#define CATCH_ZERO    2
+
+/** Given a TLS object and the result of an SSL_* call, use
+ * SSL_get_error to determine whether an error has occurred, and if so
+ * which one.  Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}.
+ * If extra&CATCH_SYSCALL is true, return TOR_TLS_SYSCALL_ instead of
+ * reporting syscall errors.  If extra&CATCH_ZERO is true, return
+ * TOR_TLS_ZERORETURN_ instead of reporting zero-return errors.
+ *
+ * If an error has occurred, log it at level <b>severity</b> and describe the
+ * current action as <b>doing</b>.
+ */
+int
+tor_tls_get_error(tor_tls_t *tls, int r, int extra,
+                  const char *doing, int severity, int domain)
+{
+  int err = SSL_get_error(tls->ssl, r);
+  int tor_error = TOR_TLS_ERROR_MISC;
+  switch (err) {
+    case SSL_ERROR_NONE:
+      return TOR_TLS_DONE;
+    case SSL_ERROR_WANT_READ:
+      return TOR_TLS_WANTREAD;
+    case SSL_ERROR_WANT_WRITE:
+      return TOR_TLS_WANTWRITE;
+    case SSL_ERROR_SYSCALL:
+      if (extra&CATCH_SYSCALL)
+        return TOR_TLS_SYSCALL_;
+      if (r == 0) {
+        tor_log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
+            doing, SSL_state_string_long(tls->ssl));
+        tor_error = TOR_TLS_ERROR_IO;
+      } else {
+        int e = tor_socket_errno(tls->socket);
+        tor_log(severity, LD_NET,
+            "TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
+            doing, e, tor_socket_strerror(e),
+            SSL_state_string_long(tls->ssl));
+        tor_error = tor_errno_to_tls_error(e);
+      }
+      tls_log_errors(tls, severity, domain, doing);
+      return tor_error;
+    case SSL_ERROR_ZERO_RETURN:
+      if (extra&CATCH_ZERO)
+        return TOR_TLS_ZERORETURN_;
+      tor_log(severity, LD_NET, "TLS connection closed while %s in state %s",
+          doing, SSL_state_string_long(tls->ssl));
+      tls_log_errors(tls, severity, domain, doing);
+      return TOR_TLS_CLOSE;
+    default:
+      tls_log_errors(tls, severity, domain, doing);
+      return TOR_TLS_ERROR_MISC;
+  }
+}
+
+/** Initialize OpenSSL, unless it has already been initialized.
+ */
+void
+tor_tls_init(void)
+{
+  check_no_tls_errors();
+
+  if (!tls_library_is_initialized) {
+#ifdef OPENSSL_1_1_API
+    OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
+#else
+    SSL_library_init();
+    SSL_load_error_strings();
+#endif
+
+#if (SIZEOF_VOID_P >= 8 &&                              \
+     OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
+    long version = OpenSSL_version_num();
+
+    /* LCOV_EXCL_START : we can't test these lines on the same machine */
+    if (version >= OPENSSL_V_SERIES(1,0,1)) {
+      /* Warn if we could *almost* be running with much faster ECDH.
+         If we're built for a 64-bit target, using OpenSSL 1.0.1, but we
+         don't have one of the built-in __uint128-based speedups, we are
+         just one build operation away from an accelerated handshake.
+
+         (We could be looking at OPENSSL_NO_EC_NISTP_64_GCC_128 instead of
+          doing this test, but that gives compile-time options, not runtime
+          behavior.)
+      */
+      EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+      const EC_GROUP *g = key ? EC_KEY_get0_group(key) : NULL;
+      const EC_METHOD *m = g ? EC_GROUP_method_of(g) : NULL;
+      const int warn = (m == EC_GFp_simple_method() ||
+                        m == EC_GFp_mont_method() ||
+                        m == EC_GFp_nist_method());
+      EC_KEY_free(key);
+
+      if (warn)
+        log_notice(LD_GENERAL, "We were built to run on a 64-bit CPU, with "
+                   "OpenSSL 1.0.1 or later, but with a version of OpenSSL "
+                   "that apparently lacks accelerated support for the NIST "
+                   "P-224 and P-256 groups. Building openssl with such "
+                   "support (using the enable-ec_nistp_64_gcc_128 option "
+                   "when configuring it) would make ECDH much faster.");
+    }
+    /* LCOV_EXCL_STOP */
+#endif /* (SIZEOF_VOID_P >= 8 &&                              ... */
+
+    tor_tls_allocate_tor_tls_object_ex_data_index();
+
+    tls_library_is_initialized = 1;
+  }
+}
+
+/** We need to give OpenSSL a callback to verify certificates. This is
+ * it: We always accept peer certs and complete the handshake.  We
+ * don't validate them until later.
+ */
+int
+always_accept_verify_cb(int preverify_ok,
+                        X509_STORE_CTX *x509_ctx)
+{
+  (void) preverify_ok;
+  (void) x509_ctx;
+  return 1;
+}
+
+/** List of ciphers that servers should select from when the client might be
+ * claiming extra unsupported ciphers in order to avoid fingerprinting.  */
+static const char SERVER_CIPHER_LIST[] =
+#ifdef  TLS1_3_TXT_AES_128_GCM_SHA256
+  /* This one can never actually get selected, since if the client lists it,
+   * we will assume that the client is honest, and not use this list.
+   * Nonetheless we list it if it's available, so that the server doesn't
+   * conclude that it has no valid ciphers if it's running with TLS1.3.
+   */
+  TLS1_3_TXT_AES_128_GCM_SHA256 ":"
+#endif
+  TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
+  TLS1_TXT_DHE_RSA_WITH_AES_128_SHA;
+
+/** List of ciphers that servers should select from when we actually have
+ * our choice of what cipher to use. */
+static const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
+  /* Here are the TLS 1.3 ciphers we like, in the order we prefer. */
+#ifdef TLS1_3_TXT_AES_256_GCM_SHA384
+  TLS1_3_TXT_AES_256_GCM_SHA384 ":"
+#endif
+#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256
+  TLS1_3_TXT_CHACHA20_POLY1305_SHA256 ":"
+#endif
+#ifdef TLS1_3_TXT_AES_128_GCM_SHA256
+  TLS1_3_TXT_AES_128_GCM_SHA256 ":"
+#endif
+#ifdef TLS1_3_TXT_AES_128_CCM_SHA256
+  TLS1_3_TXT_AES_128_CCM_SHA256 ":"
+#endif
+
+  /* This list is autogenerated with the gen_server_ciphers.py script;
+   * don't hand-edit it. */
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+       TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+       TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384
+       TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256
+       TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA
+       TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
+       TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384
+       TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256
+       TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_CCM
+       TLS1_TXT_DHE_RSA_WITH_AES_256_CCM ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_CCM
+       TLS1_TXT_DHE_RSA_WITH_AES_128_CCM ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256
+       TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256
+       TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":"
+#endif
+       /* Required */
+       TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
+       /* Required */
+       TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305
+       TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305
+       TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305
+#endif
+  ;
+
+/* Note: to set up your own private testing network with link crypto
+ * disabled, set your Tors' cipher list to
+ * (SSL3_TXT_RSA_NULL_SHA).  If you do this, you won't be able to communicate
+ * with any of the "real" Tors, though. */
+
+#define CIPHER(id, name) name ":"
+#define XCIPHER(id, name)
+/** List of ciphers that clients should advertise, omitting items that
+ * our OpenSSL doesn't know about. */
+static const char CLIENT_CIPHER_LIST[] =
+#include "ciphers.inc"
+  /* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version
+   * of any cipher we say. */
+  "!SSLv2"
+  ;
+#undef CIPHER
+#undef XCIPHER
+
+/** Remove a reference to <b>ctx</b>, and free it if it has no more
+ * references. */
+void
+tor_tls_context_decref(tor_tls_context_t *ctx)
+{
+  tor_assert(ctx);
+  if (--ctx->refcnt == 0) {
+    SSL_CTX_free(ctx->ctx);
+    tor_x509_cert_free(ctx->my_link_cert);
+    tor_x509_cert_free(ctx->my_id_cert);
+    tor_x509_cert_free(ctx->my_auth_cert);
+    crypto_pk_free(ctx->link_key);
+    crypto_pk_free(ctx->auth_key);
+    /* LCOV_EXCL_BR_START since ctx will never be NULL here */
+    tor_free(ctx);
+    /* LCOV_EXCL_BR_STOP */
+  }
+}
+
+/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate
+ * and ID certificate that we're currently using for our V3 in-protocol
+ * handshake's certificate chain.  If <b>server</b> is true, provide the certs
+ * that we use in server mode (auth, ID); otherwise, provide the certs that we
+ * use in client mode. (link, ID) */
+int
+tor_tls_get_my_certs(int server,
+                     const tor_x509_cert_t **link_cert_out,
+                     const tor_x509_cert_t **id_cert_out)
+{
+  tor_tls_context_t *ctx = tor_tls_context_get(server);
+  if (! ctx)
+    return -1;
+  if (link_cert_out)
+    *link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert;
+  if (id_cert_out)
+    *id_cert_out = ctx->my_id_cert;
+  return 0;
+}
+
+/**
+ * Return the authentication key that we use to authenticate ourselves as a
+ * client in the V3 in-protocol handshake.
+ */
+crypto_pk_t *
+tor_tls_get_my_client_auth_key(void)
+{
+  tor_tls_context_t *context = tor_tls_context_get(0);
+  if (! context)
+    return NULL;
+  return context->auth_key;
+}
+
+/** Return true iff the other side of <b>tls</b> has authenticated to us, and
+ * the key certified in <b>cert</b> is the same as the key they used to do it.
+ */
+MOCK_IMPL(int,
+tor_tls_cert_matches_key,(const tor_tls_t *tls, const tor_x509_cert_t *cert))
+{
+  X509 *peercert = SSL_get_peer_certificate(tls->ssl);
+  EVP_PKEY *link_key = NULL, *cert_key = NULL;
+  int result;
+
+  if (!peercert)
+    return 0;
+  link_key = X509_get_pubkey(peercert);
+  cert_key = X509_get_pubkey((X509 *)tor_x509_cert_get_impl(cert));
+
+  result = link_key && cert_key && EVP_PKEY_cmp(cert_key, link_key) == 1;
+
+  X509_free(peercert);
+  if (link_key)
+    EVP_PKEY_free(link_key);
+  if (cert_key)
+    EVP_PKEY_free(cert_key);
+
+  return result;
+}
+
+/** Create a new global TLS context.
+ *
+ * You can call this function multiple times.  Each time you call it,
+ * it generates new certificates; all new connections will use
+ * the new SSL context.
+ */
+int
+tor_tls_context_init_one(tor_tls_context_t **ppcontext,
+                         crypto_pk_t *identity,
+                         unsigned int key_lifetime,
+                         unsigned int flags,
+                         int is_client)
+{
+  tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
+                                                   key_lifetime,
+                                                   flags,
+                                                   is_client);
+  tor_tls_context_t *old_ctx = *ppcontext;
+
+  if (new_ctx != NULL) {
+    *ppcontext = new_ctx;
+
+    /* Free the old context if one existed. */
+    if (old_ctx != NULL) {
+      /* This is safe even if there are open connections: we reference-
+       * count tor_tls_context_t objects. */
+      tor_tls_context_decref(old_ctx);
+    }
+  }
+
+  return ((new_ctx != NULL) ? 0 : -1);
+}
+
+/** The group we should use for ecdhe when none was selected. */
+#define  NID_tor_default_ecdhe_group NID_X9_62_prime256v1
+
+#define RSA_LINK_KEY_BITS 2048
+
+/** Create a new TLS context for use with Tor TLS handshakes.
+ * <b>identity</b> should be set to the identity key used to sign the
+ * certificate.
+ */
+tor_tls_context_t *
+tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
+                    unsigned flags, int is_client)
+{
+  crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
+  EVP_PKEY *pkey = NULL;
+  tor_tls_context_t *result = NULL;
+  X509 *cert = NULL, *idcert = NULL, *authcert = NULL;
+  char *nickname = NULL, *nn2 = NULL;
+
+  tor_tls_init();
+  nickname = crypto_random_hostname(8, 20, "www.", ".net");
+#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
+  nn2 = crypto_random_hostname(8, 20, "www.", ".net");
+#else
+  nn2 = crypto_random_hostname(8, 20, "www.", ".com");
+#endif
+
+  /* Generate short-term RSA key for use with TLS. */
+  if (!(rsa = crypto_pk_new()))
+    goto error;
+  if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0)
+    goto error;
+  if (!is_client) {
+    /* Generate short-term RSA key for use in the in-protocol ("v3")
+     * authentication handshake. */
+    if (!(rsa_auth = crypto_pk_new()))
+      goto error;
+    if (crypto_pk_generate_key(rsa_auth)<0)
+      goto error;
+    /* Create a link certificate signed by identity key. */
+    cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
+                                      key_lifetime);
+    /* Create self-signed certificate for identity key. */
+    idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
+                                        IDENTITY_CERT_LIFETIME);
+    /* Create an authentication certificate signed by identity key. */
+    authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
+                                          key_lifetime);
+    if (!cert || !idcert || !authcert) {
+      log_warn(LD_CRYPTO, "Error creating certificate");
+      goto error;
+    }
+  }
+
+  result = tor_malloc_zero(sizeof(tor_tls_context_t));
+  result->refcnt = 1;
+  if (!is_client) {
+    result->my_link_cert = tor_x509_cert_new(X509_dup(cert));
+    result->my_id_cert = tor_x509_cert_new(X509_dup(idcert));
+    result->my_auth_cert = tor_x509_cert_new(X509_dup(authcert));
+    if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
+      goto error;
+    result->link_key = crypto_pk_dup_key(rsa);
+    result->auth_key = crypto_pk_dup_key(rsa_auth);
+  }
+
+#if 0
+  /* Tell OpenSSL to only use TLS1.  This may have subtly different results
+   * from SSLv23_method() with SSLv2 and SSLv3 disabled, so we need to do some
+   * investigation before we consider adjusting it. It should be compatible
+   * with existing Tors. */
+  if (!(result->ctx = SSL_CTX_new(TLSv1_method())))
+    goto error;
+#endif /* 0 */
+
+  /* Tell OpenSSL to use TLS 1.0 or later but not SSL2 or SSL3. */
+#ifdef HAVE_TLS_METHOD
+  if (!(result->ctx = SSL_CTX_new(TLS_method())))
+    goto error;
+#else
+  if (!(result->ctx = SSL_CTX_new(SSLv23_method())))
+    goto error;
+#endif /* defined(HAVE_TLS_METHOD) */
+  SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2);
+  SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3);
+
+  /* Prefer the server's ordering of ciphers: the client's ordering has
+  * historically been chosen for fingerprinting resistance. */
+  SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+
+  /* Disable TLS tickets if they're supported.  We never want to use them;
+   * using them can make our perfect forward secrecy a little worse, *and*
+   * create an opportunity to fingerprint us (since it's unusual to use them
+   * with TLS sessions turned off).
+   *
+   * In 0.2.4, clients advertise support for them though, to avoid a TLS
+   * distinguishability vector.  This can give us worse PFS, though, if we
+   * get a server that doesn't set SSL_OP_NO_TICKET.  With luck, there will
+   * be few such servers by the time 0.2.4 is more stable.
+   */
+#ifdef SSL_OP_NO_TICKET
+  if (! is_client) {
+    SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
+  }
+#endif
+
+  SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE);
+  SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE);
+
+#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+  SSL_CTX_set_options(result->ctx,
+                      SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+#endif
+  /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
+   * as authenticating any earlier-received data.
+   */
+  {
+    SSL_CTX_set_options(result->ctx,
+                        SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
+  }
+
+  /* Don't actually allow compression; it uses RAM and time, it makes TLS
+   * vulnerable to CRIME-style attacks, and most of the data we transmit over
+   * TLS is encrypted (and therefore uncompressible) anyway. */
+#ifdef SSL_OP_NO_COMPRESSION
+  SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION);
+#endif
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+#ifndef OPENSSL_NO_COMP
+  if (result->ctx->comp_methods)
+    result->ctx->comp_methods = NULL;
+#endif
+#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) */
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+  SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+  if (! is_client) {
+    if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
+      goto error;
+    X509_free(cert); /* We just added a reference to cert. */
+    cert=NULL;
+    if (idcert) {
+      X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
+      tor_assert(s);
+      X509_STORE_add_cert(s, idcert);
+      X509_free(idcert); /* The context now owns the reference to idcert */
+      idcert = NULL;
+    }
+  }
+  SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
+  if (!is_client) {
+    tor_assert(rsa);
+    if (!(pkey = crypto_pk_get_openssl_evp_pkey_(rsa,1)))
+      goto error;
+    if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
+      goto error;
+    EVP_PKEY_free(pkey);
+    pkey = NULL;
+    if (!SSL_CTX_check_private_key(result->ctx))
+      goto error;
+  }
+  {
+    DH *dh = crypto_dh_new_openssl_tls();
+    tor_assert(dh);
+    SSL_CTX_set_tmp_dh(result->ctx, dh);
+    DH_free(dh);
+  }
+  if (! is_client) {
+    int nid;
+    EC_KEY *ec_key;
+    if (flags & TOR_TLS_CTX_USE_ECDHE_P224)
+      nid = NID_secp224r1;
+    else if (flags & TOR_TLS_CTX_USE_ECDHE_P256)
+      nid = NID_X9_62_prime256v1;
+    else
+      nid = NID_tor_default_ecdhe_group;
+    /* Use P-256 for ECDHE. */
+    ec_key = EC_KEY_new_by_curve_name(nid);
+    if (ec_key != NULL) /*XXXX Handle errors? */
+      SSL_CTX_set_tmp_ecdh(result->ctx, ec_key);
+    EC_KEY_free(ec_key);
+  }
+  SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
+                     always_accept_verify_cb);
+  /* let us realloc bufs that we're writing from */
+  SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+  if (rsa)
+    crypto_pk_free(rsa);
+  if (rsa_auth)
+    crypto_pk_free(rsa_auth);
+  X509_free(authcert);
+  tor_free(nickname);
+  tor_free(nn2);
+  return result;
+
+ error:
+  tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context");
+  tor_free(nickname);
+  tor_free(nn2);
+  if (pkey)
+    EVP_PKEY_free(pkey);
+  if (rsa)
+    crypto_pk_free(rsa);
+  if (rsa_auth)
+    crypto_pk_free(rsa_auth);
+  if (result)
+    tor_tls_context_decref(result);
+  if (cert)
+    X509_free(cert);
+  if (idcert)
+    X509_free(idcert);
+  if (authcert)
+    X509_free(authcert);
+  return NULL;
+}
+
+/** Invoked when a TLS state changes: log the change at severity 'debug' */
+void
+tor_tls_debug_state_callback(const SSL *ssl, int type, int val)
+{
+  /* LCOV_EXCL_START since this depends on whether debug is captured or not */
+  log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].",
+            ssl, SSL_state_string_long(ssl), type, val);
+  /* LCOV_EXCL_STOP */
+}
+
+/* Return the name of the negotiated ciphersuite in use on <b>tls</b> */
+const char *
+tor_tls_get_ciphersuite_name(tor_tls_t *tls)
+{
+  return SSL_get_cipher(tls->ssl);
+}
+
+/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to
+ * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers
+ * that it claims to support.  We'll prune this list to remove the ciphers
+ * *we* don't recognize. */
+STATIC uint16_t v2_cipher_list[] = {
+  0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */
+  0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */
+  0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */
+  0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */
+  0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */
+  0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */
+  0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */
+  0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */
+  0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */
+  0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */
+  0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */
+  0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */
+  0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */
+  0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */
+  0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */
+  0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */
+  0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */
+  0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */
+  0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */
+  0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */
+  0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */
+  0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */
+  0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */
+  0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */
+  0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */
+  0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */
+  0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */
+  0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */
+  0
+};
+/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */
+static int v2_cipher_list_pruned = 0;
+
+/** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>;
+ * return 1 if it does support it, or if we have no way to tell. */
+int
+find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
+{
+  const SSL_CIPHER *c;
+#ifdef HAVE_SSL_CIPHER_FIND
+  (void) m;
+  {
+    unsigned char cipherid[3];
+    tor_assert(ssl);
+    set_uint16(cipherid, tor_htons(cipher));
+    cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting
+                      * with a two-byte 'cipherid', it may look for a v2
+                      * cipher with the appropriate 3 bytes. */
+    c = SSL_CIPHER_find((SSL*)ssl, cipherid);
+    if (c)
+      tor_assert((SSL_CIPHER_get_id(c) & 0xffff) == cipher);
+    return c != NULL;
+  }
+#else /* !(defined(HAVE_SSL_CIPHER_FIND)) */
+
+# if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR)
+  if (m && m->get_cipher_by_char) {
+    unsigned char cipherid[3];
+    set_uint16(cipherid, tor_htons(cipher));
+    cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting
+                      * with a two-byte 'cipherid', it may look for a v2
+                      * cipher with the appropriate 3 bytes. */
+    c = m->get_cipher_by_char(cipherid);
+    if (c)
+      tor_assert((c->id & 0xffff) == cipher);
+    return c != NULL;
+  }
+#endif /* defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) */
+# ifndef OPENSSL_1_1_API
+  if (m && m->get_cipher && m->num_ciphers) {
+    /* It would seem that some of the "let's-clean-up-openssl" forks have
+     * removed the get_cipher_by_char function.  Okay, so now you get a
+     * quadratic search.
+     */
+    int i;
+    for (i = 0; i < m->num_ciphers(); ++i) {
+      c = m->get_cipher(i);
+      if (c && (c->id & 0xffff) == cipher) {
+        return 1;
+      }
+    }
+    return 0;
+  }
+#endif /* !defined(OPENSSL_1_1_API) */
+  (void) ssl;
+  (void) m;
+  (void) cipher;
+  return 1; /* No way to search */
+#endif /* defined(HAVE_SSL_CIPHER_FIND) */
+}
+
+/** Remove from v2_cipher_list every cipher that we don't support, so that
+ * comparing v2_cipher_list to a client's cipher list will give a sensible
+ * result. */
+static void
+prune_v2_cipher_list(const SSL *ssl)
+{
+  uint16_t *inp, *outp;
+#ifdef HAVE_TLS_METHOD
+  const SSL_METHOD *m = TLS_method();
+#else
+  const SSL_METHOD *m = SSLv23_method();
+#endif
+
+  inp = outp = v2_cipher_list;
+  while (*inp) {
+    if (find_cipher_by_id(ssl, m, *inp)) {
+      *outp++ = *inp++;
+    } else {
+      inp++;
+    }
+  }
+  *outp = 0;
+
+  v2_cipher_list_pruned = 1;
+}
+
+/** Examine the client cipher list in <b>ssl</b>, and determine what kind of
+ * client it is.  Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2,
+ * CIPHERS_UNRESTRICTED.
+ **/
+int
+tor_tls_classify_client_ciphers(const SSL *ssl,
+                                STACK_OF(SSL_CIPHER) *peer_ciphers)
+{
+  int i, res;
+  tor_tls_t *tor_tls;
+  if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
+    prune_v2_cipher_list(ssl);
+
+  tor_tls = tor_tls_get_by_ssl(ssl);
+  if (tor_tls && tor_tls->client_cipher_list_type)
+    return tor_tls->client_cipher_list_type;
+
+  /* If we reached this point, we just got a client hello.  See if there is
+   * a cipher list. */
+  if (!peer_ciphers) {
+    log_info(LD_NET, "No ciphers on session");
+    res = CIPHERS_ERR;
+    goto done;
+  }
+  /* Now we need to see if there are any ciphers whose presence means we're
+   * dealing with an updated Tor. */
+  for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+    const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
+    const char *ciphername = SSL_CIPHER_get_name(cipher);
+    if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) &&
+        strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) &&
+        strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) &&
+        strcmp(ciphername, "(NONE)")) {
+      log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername);
+      // return 1;
+      goto v2_or_higher;
+    }
+  }
+  res = CIPHERS_V1;
+  goto done;
+ v2_or_higher:
+  {
+    const uint16_t *v2_cipher = v2_cipher_list;
+    for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+      const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
+      uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff;
+      if (id == 0x00ff) /* extended renegotiation indicator. */
+        continue;
+      if (!id || id != *v2_cipher) {
+        res = CIPHERS_UNRESTRICTED;
+        goto dump_ciphers;
+      }
+      ++v2_cipher;
+    }
+    if (*v2_cipher != 0) {
+      res = CIPHERS_UNRESTRICTED;
+      goto dump_ciphers;
+    }
+    res = CIPHERS_V2;
+  }
+
+ dump_ciphers:
+  {
+    smartlist_t *elts = smartlist_new();
+    char *s;
+    for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+      const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
+      const char *ciphername = SSL_CIPHER_get_name(cipher);
+      smartlist_add(elts, (char*)ciphername);
+    }
+    s = smartlist_join_strings(elts, ":", 0, NULL);
+    log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s.  It is: '%s'",
+              (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s);
+    tor_free(s);
+    smartlist_free(elts);
+  }
+ done:
+  if (tor_tls)
+    return tor_tls->client_cipher_list_type = res;
+
+  return res;
+}
+
+/** Return true iff the cipher list suggested by the client for <b>ssl</b> is
+ * a list that indicates that the client knows how to do the v2 TLS connection
+ * handshake. */
+int
+tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
+{
+  STACK_OF(SSL_CIPHER) *ciphers;
+#ifdef HAVE_SSL_GET_CLIENT_CIPHERS
+  ciphers = SSL_get_client_ciphers(ssl);
+#else
+  SSL_SESSION *session;
+  if (!(session = SSL_get_session((SSL *)ssl))) {
+    log_info(LD_NET, "No session on TLS?");
+    return CIPHERS_ERR;
+  }
+  ciphers = session->ciphers;
+#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
+
+  return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2;
+}
+
+/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection
+ * changes state. We use this:
+ * <ul><li>To alter the state of the handshake partway through, so we
+ *         do not send or request extra certificates in v2 handshakes.</li>
+ * <li>To detect renegotiation</li></ul>
+ */
+void
+tor_tls_server_info_callback(const SSL *ssl, int type, int val)
+{
+  tor_tls_t *tls;
+  (void) val;
+
+  IF_BUG_ONCE(ssl == NULL) {
+    return; // LCOV_EXCL_LINE
+  }
+
+  tor_tls_debug_state_callback(ssl, type, val);
+
+  if (type != SSL_CB_ACCEPT_LOOP)
+    return;
+
+  OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl);
+  if (! STATE_IS_SW_SERVER_HELLO(ssl_state))
+    return;
+  tls = tor_tls_get_by_ssl(ssl);
+  if (tls) {
+    /* Check whether we're watching for renegotiates.  If so, this is one! */
+    if (tls->negotiated_callback)
+      tls->got_renegotiate = 1;
+    if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/
+      ++tls->server_handshake_count;
+  } else {
+    log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
+    return;
+  }
+
+  /* Now check the cipher list. */
+  if (tor_tls_client_is_using_v2_ciphers(ssl)) {
+    if (tls->wasV2Handshake)
+      return; /* We already turned this stuff off for the first handshake;
+               * This is a renegotiation. */
+
+    /* Yes, we're casting away the const from ssl.  This is very naughty of us.
+     * Let's hope openssl doesn't notice! */
+
+    /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */
+    SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN);
+    /* Don't send a hello request. */
+    SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);
+
+    if (tls) {
+      tls->wasV2Handshake = 1;
+    } else {
+      /* LCOV_EXCL_START this line is not reachable */
+      log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
+      /* LCOV_EXCL_STOP */
+    }
+  }
+}
+
+/** Callback to get invoked on a server after we've read the list of ciphers
+ * the client supports, but before we pick our own ciphersuite.
+ *
+ * We can't abuse an info_cb for this, since by the time one of the
+ * client_hello info_cbs is called, we've already picked which ciphersuite to
+ * use.
+ *
+ * Technically, this function is an abuse of this callback, since the point of
+ * a session_secret_cb is to try to set up and/or verify a shared-secret for
+ * authentication on the fly.  But as long as we return 0, we won't actually be
+ * setting up a shared secret, and all will be fine.
+ */
+int
+tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len,
+                          STACK_OF(SSL_CIPHER) *peer_ciphers,
+                          CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher,
+                          void *arg)
+{
+  (void) secret;
+  (void) secret_len;
+  (void) peer_ciphers;
+  (void) cipher;
+  (void) arg;
+
+  if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) ==
+       CIPHERS_UNRESTRICTED) {
+    SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST);
+  }
+
+  SSL_set_session_secret_cb(ssl, NULL, NULL);
+
+  return 0;
+}
+static void
+tor_tls_setup_session_secret_cb(tor_tls_t *tls)
+{
+  SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
+}
+
+/** Create a new TLS object from a file descriptor, and a flag to
+ * determine whether it is functioning as a server.
+ */
+tor_tls_t *
+tor_tls_new(int sock, int isServer)
+{
+  BIO *bio = NULL;
+  tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t));
+  tor_tls_context_t *context = tor_tls_context_get(isServer);
+  result->magic = TOR_TLS_MAGIC;
+
+  check_no_tls_errors();
+  tor_assert(context); /* make sure somebody made it first */
+  if (!(result->ssl = SSL_new(context->ctx))) {
+    tls_log_errors(NULL, LOG_WARN, LD_NET, "creating SSL object");
+    tor_free(result);
+    goto err;
+  }
+
+#ifdef SSL_set_tlsext_host_name
+  /* Browsers use the TLS hostname extension, so we should too. */
+  if (!isServer) {
+    char *fake_hostname = crypto_random_hostname(4,25, "www.",".com");
+    SSL_set_tlsext_host_name(result->ssl, fake_hostname);
+    tor_free(fake_hostname);
+  }
+#endif /* defined(SSL_set_tlsext_host_name) */
+
+  if (!SSL_set_cipher_list(result->ssl,
+                     isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) {
+    tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers");
+#ifdef SSL_set_tlsext_host_name
+    SSL_set_tlsext_host_name(result->ssl, NULL);
+#endif
+    SSL_free(result->ssl);
+    tor_free(result);
+    goto err;
+  }
+  result->socket = sock;
+  bio = BIO_new_socket(sock, BIO_NOCLOSE);
+  if (! bio) {
+    tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO");
+#ifdef SSL_set_tlsext_host_name
+    SSL_set_tlsext_host_name(result->ssl, NULL);
+#endif
+    SSL_free(result->ssl);
+    tor_free(result);
+    goto err;
+  }
+  {
+    int set_worked =
+      SSL_set_ex_data(result->ssl, tor_tls_object_ex_data_index, result);
+    if (!set_worked) {
+      log_warn(LD_BUG,
+               "Couldn't set the tls for an SSL*; connection will fail");
+    }
+  }
+  SSL_set_bio(result->ssl, bio, bio);
+  tor_tls_context_incref(context);
+  result->context = context;
+  result->state = TOR_TLS_ST_HANDSHAKE;
+  result->isServer = isServer;
+  result->wantwrite_n = 0;
+  result->last_write_count = (unsigned long) BIO_number_written(bio);
+  result->last_read_count = (unsigned long) BIO_number_read(bio);
+  if (result->last_write_count || result->last_read_count) {
+    log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu",
+             result->last_read_count, result->last_write_count);
+  }
+  if (isServer) {
+    SSL_set_info_callback(result->ssl, tor_tls_server_info_callback);
+  } else {
+    SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
+  }
+
+  if (isServer)
+    tor_tls_setup_session_secret_cb(result);
+
+  goto done;
+ err:
+  result = NULL;
+ done:
+  /* Not expected to get called. */
+  tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
+  return result;
+}
+
+/** Set <b>cb</b> to be called with argument <b>arg</b> whenever <b>tls</b>
+ * next gets a client-side renegotiate in the middle of a read.  Do not
+ * invoke this function until <em>after</em> initial handshaking is done!
+ */
+void
+tor_tls_set_renegotiate_callback(tor_tls_t *tls,
+                                 void (*cb)(tor_tls_t *, void *arg),
+                                 void *arg)
+{
+  tls->negotiated_callback = cb;
+  tls->callback_arg = arg;
+  tls->got_renegotiate = 0;
+  if (cb) {
+    SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback);
+  } else {
+    SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback);
+  }
+}
+
+/** If this version of openssl requires it, turn on renegotiation on
+ * <b>tls</b>.
+ */
+void
+tor_tls_unblock_renegotiation(tor_tls_t *tls)
+{
+  /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
+   * as authenticating any earlier-received data. */
+  SSL_set_options(tls->ssl,
+                  SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
+}
+
+/** If this version of openssl supports it, turn off renegotiation on
+ * <b>tls</b>.  (Our protocol never requires this for security, but it's nice
+ * to use belt-and-suspenders here.)
+ */
+void
+tor_tls_block_renegotiation(tor_tls_t *tls)
+{
+#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG
+  tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+#else
+  (void) tls;
+#endif
+}
+
+/** Assert that the flags that allow legacy renegotiation are still set */
+void
+tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
+{
+#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && \
+  SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION != 0
+  long options = SSL_get_options(tls->ssl);
+  tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
+#else
+  (void) tls;
+#endif /* defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && ... */
+}
+
+/** Release resources associated with a TLS object.  Does not close the
+ * underlying file descriptor.
+ */
+void
+tor_tls_free_(tor_tls_t *tls)
+{
+  if (!tls)
+    return;
+  tor_assert(tls->ssl);
+  {
+    size_t r,w;
+    tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
+  }
+#ifdef SSL_set_tlsext_host_name
+  SSL_set_tlsext_host_name(tls->ssl, NULL);
+#endif
+  SSL_free(tls->ssl);
+  tls->ssl = NULL;
+  tls->negotiated_callback = NULL;
+  if (tls->context)
+    tor_tls_context_decref(tls->context);
+  tor_free(tls->address);
+  tls->magic = 0x99999999;
+  tor_free(tls);
+}
+
+/** Underlying function for TLS reading.  Reads up to <b>len</b>
+ * characters from <b>tls</b> into <b>cp</b>.  On success, returns the
+ * number of characters read.  On failure, returns TOR_TLS_ERROR,
+ * TOR_TLS_CLOSE, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.
+ */
+MOCK_IMPL(int,
+tor_tls_read,(tor_tls_t *tls, char *cp, size_t len))
+{
+  int r, err;
+  tor_assert(tls);
+  tor_assert(tls->ssl);
+  tor_assert(tls->state == TOR_TLS_ST_OPEN);
+  tor_assert(len<INT_MAX);
+  r = SSL_read(tls->ssl, cp, (int)len);
+  if (r > 0) {
+    if (tls->got_renegotiate) {
+      /* Renegotiation happened! */
+      log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls));
+      if (tls->negotiated_callback)
+        tls->negotiated_callback(tls, tls->callback_arg);
+      tls->got_renegotiate = 0;
+    }
+    return r;
+  }
+  err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
+  if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) {
+    log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
+    tls->state = TOR_TLS_ST_CLOSED;
+    return TOR_TLS_CLOSE;
+  } else {
+    tor_assert(err != TOR_TLS_DONE);
+    log_debug(LD_NET,"read returned r=%d, err=%d",r,err);
+    return err;
+  }
+}
+
+/** Total number of bytes that we've used TLS to send.  Used to track TLS
+ * overhead. */
+STATIC uint64_t total_bytes_written_over_tls = 0;
+/** Total number of bytes that TLS has put on the network for us. Used to
+ * track TLS overhead. */
+STATIC uint64_t total_bytes_written_by_tls = 0;
+
+/** Underlying function for TLS writing.  Write up to <b>n</b>
+ * characters from <b>cp</b> onto <b>tls</b>.  On success, returns the
+ * number of characters written.  On failure, returns TOR_TLS_ERROR,
+ * TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.
+ */
+int
+tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
+{
+  int r, err;
+  tor_assert(tls);
+  tor_assert(tls->ssl);
+  tor_assert(tls->state == TOR_TLS_ST_OPEN);
+  tor_assert(n < INT_MAX);
+  if (n == 0)
+    return 0;
+  if (tls->wantwrite_n) {
+    /* if WANTWRITE last time, we must use the _same_ n as before */
+    tor_assert(n >= tls->wantwrite_n);
+    log_debug(LD_NET,"resuming pending-write, (%d to flush, reusing %d)",
+              (int)n, (int)tls->wantwrite_n);
+    n = tls->wantwrite_n;
+    tls->wantwrite_n = 0;
+  }
+  r = SSL_write(tls->ssl, cp, (int)n);
+  err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
+  if (err == TOR_TLS_DONE) {
+    total_bytes_written_over_tls += r;
+    return r;
+  }
+  if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) {
+    tls->wantwrite_n = n;
+  }
+  return err;
+}
+
+/** Perform initial handshake on <b>tls</b>.  When finished, returns
+ * TOR_TLS_DONE.  On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
+ * or TOR_TLS_WANTWRITE.
+ */
+int
+tor_tls_handshake(tor_tls_t *tls)
+{
+  int r;
+  tor_assert(tls);
+  tor_assert(tls->ssl);
+  tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
+
+  check_no_tls_errors();
+
+  OSSL_HANDSHAKE_STATE oldstate = SSL_get_state(tls->ssl);
+
+  if (tls->isServer) {
+    log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
+              SSL_state_string_long(tls->ssl));
+    r = SSL_accept(tls->ssl);
+  } else {
+    log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls,
+              SSL_state_string_long(tls->ssl));
+    r = SSL_connect(tls->ssl);
+  }
+
+  OSSL_HANDSHAKE_STATE newstate = SSL_get_state(tls->ssl);
+
+  if (oldstate != newstate)
+    log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
+              tls, SSL_state_string_long(tls->ssl));
+  /* We need to call this here and not earlier, since OpenSSL has a penchant
+   * for clearing its flags when you say accept or connect. */
+  tor_tls_unblock_renegotiation(tls);
+  r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE);
+  if (ERR_peek_error() != 0) {
+    tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE,
+                   "handshaking");
+    return TOR_TLS_ERROR_MISC;
+  }
+  if (r == TOR_TLS_DONE) {
+    tls->state = TOR_TLS_ST_OPEN;
+    return tor_tls_finish_handshake(tls);
+  }
+  return r;
+}
+
+/** Perform the final part of the initial TLS handshake on <b>tls</b>.  This
+ * should be called for the first handshake only: it determines whether the v1
+ * or the v2 handshake was used, and adjusts things for the renegotiation
+ * handshake as appropriate.
+ *
+ * tor_tls_handshake() calls this on its own; you only need to call this if
+ * bufferevent is doing the handshake for you.
+ */
+int
+tor_tls_finish_handshake(tor_tls_t *tls)
+{
+  int r = TOR_TLS_DONE;
+  check_no_tls_errors();
+  if (tls->isServer) {
+    SSL_set_info_callback(tls->ssl, NULL);
+    SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb);
+    SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN);
+    if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) {
+      /* This check is redundant, but back when we did it in the callback,
+       * we might have not been able to look up the tor_tls_t if the code
+       * was buggy.  Fixing that. */
+      if (!tls->wasV2Handshake) {
+        log_warn(LD_BUG, "For some reason, wasV2Handshake didn't"
+                 " get set. Fixing that.");
+      }
+      tls->wasV2Handshake = 1;
+      log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting"
+                " for renegotiation.");
+    } else {
+      tls->wasV2Handshake = 0;
+    }
+  } else {
+    /* Client-side */
+    tls->wasV2Handshake = 1;
+    /* XXXX this can move, probably? -NM */
+    if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) {
+      tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers");
+      r = TOR_TLS_ERROR_MISC;
+    }
+  }
+  tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake");
+  return r;
+}
+
+/** Shut down an open tls connection <b>tls</b>.  When finished, returns
+ * TOR_TLS_DONE.  On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
+ * or TOR_TLS_WANTWRITE.
+ */
+int
+tor_tls_shutdown(tor_tls_t *tls)
+{
+  int r, err;
+  char buf[128];
+  tor_assert(tls);
+  tor_assert(tls->ssl);
+  check_no_tls_errors();
+
+  while (1) {
+    if (tls->state == TOR_TLS_ST_SENTCLOSE) {
+      /* If we've already called shutdown once to send a close message,
+       * we read until the other side has closed too.
+       */
+      do {
+        r = SSL_read(tls->ssl, buf, 128);
+      } while (r>0);
+      err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
+                              LOG_INFO, LD_NET);
+      if (err == TOR_TLS_ZERORETURN_) {
+        tls->state = TOR_TLS_ST_GOTCLOSE;
+        /* fall through... */
+      } else {
+        return err;
+      }
+    }
+
+    r = SSL_shutdown(tls->ssl);
+    if (r == 1) {
+      /* If shutdown returns 1, the connection is entirely closed. */
+      tls->state = TOR_TLS_ST_CLOSED;
+      return TOR_TLS_DONE;
+    }
+    err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
+                            LOG_INFO, LD_NET);
+    if (err == TOR_TLS_SYSCALL_) {
+      /* The underlying TCP connection closed while we were shutting down. */
+      tls->state = TOR_TLS_ST_CLOSED;
+      return TOR_TLS_DONE;
+    } else if (err == TOR_TLS_ZERORETURN_) {
+      /* The TLS connection says that it sent a shutdown record, but
+       * isn't done shutting down yet.  Make sure that this hasn't
+       * happened before, then go back to the start of the function
+       * and try to read.
+       */
+      if (tls->state == TOR_TLS_ST_GOTCLOSE ||
+         tls->state == TOR_TLS_ST_SENTCLOSE) {
+        log_warn(LD_NET,
+            "TLS returned \"half-closed\" value while already half-closed");
+        return TOR_TLS_ERROR_MISC;
+      }
+      tls->state = TOR_TLS_ST_SENTCLOSE;
+      /* fall through ... */
+    } else {
+      return err;
+    }
+  } /* end loop */
+}
+
+/** Return true iff this TLS connection is authenticated.
+ */
+int
+tor_tls_peer_has_cert(tor_tls_t *tls)
+{
+  X509 *cert;
+  cert = SSL_get_peer_certificate(tls->ssl);
+  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
+  if (!cert)
+    return 0;
+  X509_free(cert);
+  return 1;
+}
+
+/** Return a newly allocated copy of the peer certificate, or NULL if there
+ * isn't one. */
+MOCK_IMPL(tor_x509_cert_t *,
+tor_tls_get_peer_cert,(tor_tls_t *tls))
+{
+  X509 *cert;
+  cert = SSL_get_peer_certificate(tls->ssl);
+  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
+  if (!cert)
+    return NULL;
+  return tor_x509_cert_new(cert);
+}
+
+/** Return a newly allocated copy of the cerficate we used on the connection,
+ * or NULL if somehow we didn't use one. */
+MOCK_IMPL(tor_x509_cert_t *,
+tor_tls_get_own_cert,(tor_tls_t *tls))
+{
+  X509 *cert = SSL_get_certificate(tls->ssl);
+  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE,
+                 "getting own-connection certificate");
+  if (!cert)
+    return NULL;
+  /* Fun inconsistency: SSL_get_peer_certificate increments the reference
+   * count, but SSL_get_certificate does not. */
+  X509 *duplicate = X509_dup(cert);
+  if (BUG(duplicate == NULL))
+    return NULL;
+  return tor_x509_cert_new(duplicate);
+}
+
+/** Helper function: try to extract a link certificate and an identity
+ * certificate from <b>tls</b>, and store them in *<b>cert_out</b> and
+ * *<b>id_cert_out</b> respectively.  Log all messages at level
+ * <b>severity</b>.
+ *
+ * Note that a reference is added to cert_out, so it needs to be
+ * freed. id_cert_out doesn't. */
+MOCK_IMPL(void,
+try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
+                               X509 **cert_out, X509 **id_cert_out))
+{
+  X509 *cert = NULL, *id_cert = NULL;
+  STACK_OF(X509) *chain = NULL;
+  int num_in_chain, i;
+  *cert_out = *id_cert_out = NULL;
+  if (!(cert = SSL_get_peer_certificate(tls->ssl)))
+    return;
+  *cert_out = cert;
+  if (!(chain = SSL_get_peer_cert_chain(tls->ssl)))
+    return;
+  num_in_chain = sk_X509_num(chain);
+  /* 1 means we're receiving (server-side), and it's just the id_cert.
+   * 2 means we're connecting (client-side), and it's both the link
+   * cert and the id_cert.
+   */
+  if (num_in_chain < 1) {
+    log_fn(severity,LD_PROTOCOL,
+           "Unexpected number of certificates in chain (%d)",
+           num_in_chain);
+    return;
+  }
+  for (i=0; i<num_in_chain; ++i) {
+    id_cert = sk_X509_value(chain, i);
+    if (X509_cmp(id_cert, cert) != 0)
+      break;
+  }
+  *id_cert_out = id_cert;
+}
+
+/** If the provided tls connection is authenticated and has a
+ * certificate chain that is currently valid and signed, then set
+ * *<b>identity_key</b> to the identity certificate's key and return
+ * 0.  Else, return -1 and log complaints with log-level <b>severity</b>.
+ */
+int
+tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
+{
+  X509 *cert = NULL, *id_cert = NULL;
+  EVP_PKEY *id_pkey = NULL;
+  RSA *rsa;
+  int r = -1;
+
+  check_no_tls_errors();
+  *identity_key = NULL;
+
+  try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert);
+  if (!cert)
+    goto done;
+  if (!id_cert) {
+    log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found");
+    goto done;
+  }
+  tls_log_errors(tls, severity, LD_HANDSHAKE, "before verifying certificate");
+
+  if (!(id_pkey = X509_get_pubkey(id_cert)) ||
+      X509_verify(cert, id_pkey) <= 0) {
+    log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0");
+    tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate");
+    goto done;
+  }
+
+  rsa = EVP_PKEY_get1_RSA(id_pkey);
+  if (!rsa)
+    goto done;
+  *identity_key = crypto_new_pk_from_openssl_rsa_(rsa);
+
+  r = 0;
+
+ done:
+  if (cert)
+    X509_free(cert);
+  if (id_pkey)
+    EVP_PKEY_free(id_pkey);
+
+  /* This should never get invoked, but let's make sure in case OpenSSL
+   * acts unexpectedly. */
+  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify");
+
+  return r;
+}
+
+/** Check whether the certificate set on the connection <b>tls</b> is expired
+ * give or take <b>past_tolerance</b> seconds, or not-yet-valid give or take
+ * <b>future_tolerance</b> seconds. Return 0 for valid, -1 for failure.
+ *
+ * NOTE: you should call tor_tls_verify before tor_tls_check_lifetime.
+ */
+int
+tor_tls_check_lifetime(int severity, tor_tls_t *tls,
+                       time_t now,
+                       int past_tolerance, int future_tolerance)
+{
+  X509 *cert;
+  int r = -1;
+
+  if (!(cert = SSL_get_peer_certificate(tls->ssl)))
+    goto done;
+
+  if (tor_x509_check_cert_lifetime_internal(severity, cert, now,
+                                            past_tolerance,
+                                            future_tolerance) < 0)
+    goto done;
+
+  r = 0;
+ done:
+  if (cert)
+    X509_free(cert);
+  /* Not expected to get invoked */
+  tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime");
+
+  return r;
+}
+
+/** Return the number of bytes available for reading from <b>tls</b>.
+ */
+int
+tor_tls_get_pending_bytes(tor_tls_t *tls)
+{
+  tor_assert(tls);
+  return SSL_pending(tls->ssl);
+}
+
+/** If <b>tls</b> requires that the next write be of a particular size,
+ * return that size.  Otherwise, return 0. */
+size_t
+tor_tls_get_forced_write_size(tor_tls_t *tls)
+{
+  return tls->wantwrite_n;
+}
+
+/** Sets n_read and n_written to the number of bytes read and written,
+ * respectively, on the raw socket used by <b>tls</b> since the last time this
+ * function was called on <b>tls</b>. */
+void
+tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written)
+{
+  BIO *wbio, *tmpbio;
+  unsigned long r, w;
+  r = (unsigned long) BIO_number_read(SSL_get_rbio(tls->ssl));
+  /* We want the number of bytes actually for real written.  Unfortunately,
+   * sometimes OpenSSL replaces the wbio on tls->ssl with a buffering bio,
+   * which makes the answer turn out wrong.  Let's cope with that.  Note
+   * that this approach will fail if we ever replace tls->ssl's BIOs with
+   * buffering bios for reasons of our own.  As an alternative, we could
+   * save the original BIO for  tls->ssl in the tor_tls_t structure, but
+   * that would be tempting fate. */
+  wbio = SSL_get_wbio(tls->ssl);
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)
+  /* BIO structure is opaque as of OpenSSL 1.1.0-pre5-dev.  Again, not
+   * supposed to use this form of the version macro, but the OpenSSL developers
+   * introduced major API changes in the pre-release stage.
+   */
+  if (BIO_method_type(wbio) == BIO_TYPE_BUFFER &&
+        (tmpbio = BIO_next(wbio)) != NULL)
+    wbio = tmpbio;
+#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)) */
+  if (wbio->method == BIO_f_buffer() && (tmpbio = BIO_next(wbio)) != NULL)
+    wbio = tmpbio;
+#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) */
+  w = (unsigned long) BIO_number_written(wbio);
+
+  /* We are ok with letting these unsigned ints go "negative" here:
+   * If we wrapped around, this should still give us the right answer, unless
+   * we wrapped around by more than ULONG_MAX since the last time we called
+   * this function.
+   */
+  *n_read = (size_t)(r - tls->last_read_count);
+  *n_written = (size_t)(w - tls->last_write_count);
+  if (*n_read > INT_MAX || *n_written > INT_MAX) {
+    log_warn(LD_BUG, "Preposterously large value in tor_tls_get_n_raw_bytes. "
+             "r=%lu, last_read=%lu, w=%lu, last_written=%lu",
+             r, tls->last_read_count, w, tls->last_write_count);
+  }
+  total_bytes_written_by_tls += *n_written;
+  tls->last_read_count = r;
+  tls->last_write_count = w;
+}
+
+/** Return a ratio of the bytes that TLS has sent to the bytes that we've told
+ * it to send. Used to track whether our TLS records are getting too tiny. */
+MOCK_IMPL(double,
+tls_get_write_overhead_ratio,(void))
+{
+  if (total_bytes_written_over_tls == 0)
+    return 1.0;
+
+  return ((double)total_bytes_written_by_tls) /
+    ((double)total_bytes_written_over_tls);
+}
+
+/** Implement check_no_tls_errors: If there are any pending OpenSSL
+ * errors, log an error message. */
+void
+check_no_tls_errors_(const char *fname, int line)
+{
+  if (ERR_peek_error() == 0)
+    return;
+  log_warn(LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
+      tor_fix_source_file(fname), line);
+  tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
+}
+
+/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2
+ * TLS handshake. Output is undefined if the handshake isn't finished. */
+int
+tor_tls_used_v1_handshake(tor_tls_t *tls)
+{
+  return ! tls->wasV2Handshake;
+}
+
+/** Return the number of server handshakes that we've noticed doing on
+ * <b>tls</b>. */
+int
+tor_tls_get_num_server_handshakes(tor_tls_t *tls)
+{
+  return tls->server_handshake_count;
+}
+
+/** Return true iff the server TLS connection <b>tls</b> got the renegotiation
+ * request it was waiting for. */
+int
+tor_tls_server_got_renegotiate(tor_tls_t *tls)
+{
+  return tls->got_renegotiate;
+}
+
+#ifndef HAVE_SSL_GET_CLIENT_RANDOM
+static size_t
+SSL_get_client_random(SSL *s, uint8_t *out, size_t len)
+{
+  if (len == 0)
+    return SSL3_RANDOM_SIZE;
+  tor_assert(len == SSL3_RANDOM_SIZE);
+  tor_assert(s->s3);
+  memcpy(out, s->s3->client_random, len);
+  return len;
+}
+#endif /* !defined(HAVE_SSL_GET_CLIENT_RANDOM) */
+
+#ifndef HAVE_SSL_GET_SERVER_RANDOM
+static size_t
+SSL_get_server_random(SSL *s, uint8_t *out, size_t len)
+{
+  if (len == 0)
+    return SSL3_RANDOM_SIZE;
+  tor_assert(len == SSL3_RANDOM_SIZE);
+  tor_assert(s->s3);
+  memcpy(out, s->s3->server_random, len);
+  return len;
+}
+#endif /* !defined(HAVE_SSL_GET_SERVER_RANDOM) */
+
+#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
+size_t
+SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len)
+{
+  tor_assert(s);
+  if (len == 0)
+    return s->master_key_length;
+  tor_assert(len == (size_t)s->master_key_length);
+  tor_assert(out);
+  memcpy(out, s->master_key, len);
+  return len;
+}
+#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */
+
+/** Set the DIGEST256_LEN buffer at <b>secrets_out</b> to the value used in
+ * the v3 handshake to prove that the client knows the TLS secrets for the
+ * connection <b>tls</b>.  Return 0 on success, -1 on failure.
+ */
+MOCK_IMPL(int,
+tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
+{
+#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification"
+  uint8_t buf[128];
+  size_t len;
+  tor_assert(tls);
+
+  SSL *const ssl = tls->ssl;
+  SSL_SESSION *const session = SSL_get_session(ssl);
+
+  tor_assert(ssl);
+  tor_assert(session);
+
+  const size_t server_random_len = SSL_get_server_random(ssl, NULL, 0);
+  const size_t client_random_len = SSL_get_client_random(ssl, NULL, 0);
+  const size_t master_key_len = SSL_SESSION_get_master_key(session, NULL, 0);
+
+  tor_assert(server_random_len);
+  tor_assert(client_random_len);
+  tor_assert(master_key_len);
+
+  len = client_random_len + server_random_len + strlen(TLSSECRET_MAGIC) + 1;
+  tor_assert(len <= sizeof(buf));
+
+  {
+    size_t r = SSL_get_client_random(ssl, buf, client_random_len);
+    tor_assert(r == client_random_len);
+  }
+
+  {
+    size_t r = SSL_get_server_random(ssl,
+                                     buf+client_random_len,
+                                     server_random_len);
+    tor_assert(r == server_random_len);
+  }
+
+  uint8_t *master_key = tor_malloc_zero(master_key_len);
+  {
+    size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len);
+    tor_assert(r == master_key_len);
+  }
+
+  uint8_t *nextbuf = buf + client_random_len + server_random_len;
+  memcpy(nextbuf, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1);
+
+  /*
+    The value is an HMAC, using the TLS master key as the HMAC key, of
+    client_random | server_random | TLSSECRET_MAGIC
+  */
+  crypto_hmac_sha256((char*)secrets_out,
+                     (char*)master_key,
+                     master_key_len,
+                     (char*)buf, len);
+  memwipe(buf, 0, sizeof(buf));
+  memwipe(master_key, 0, master_key_len);
+  tor_free(master_key);
+
+  return 0;
+}
+
+/** Using the RFC5705 key material exporting construction, and the
+ * provided <b>context</b> (<b>context_len</b> bytes long) and
+ * <b>label</b> (a NUL-terminated string), compute a 32-byte secret in
+ * <b>secrets_out</b> that only the parties to this TLS session can
+ * compute.  Return 0 on success and -1 on failure.
+ */
+MOCK_IMPL(int,
+tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
+                             const uint8_t *context,
+                             size_t context_len,
+                             const char *label))
+{
+  tor_assert(tls);
+  tor_assert(tls->ssl);
+
+  int r = SSL_export_keying_material(tls->ssl,
+                                     secrets_out, DIGEST256_LEN,
+                                     label, strlen(label),
+                                     context, context_len, 1);
+  return (r == 1) ? 0 : -1;
+}
+
+/** Examine the amount of memory used and available for buffers in <b>tls</b>.
+ * Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read
+ * buffer and *<b>rbuf_bytes</b> to the amount actually used.
+ * Set *<b>wbuf_capacity</b> to the amount of storage allocated for the write
+ * buffer and *<b>wbuf_bytes</b> to the amount actually used.
+ *
+ * Return 0 on success, -1 on failure.*/
+int
+tor_tls_get_buffer_sizes(tor_tls_t *tls,
+                         size_t *rbuf_capacity, size_t *rbuf_bytes,
+                         size_t *wbuf_capacity, size_t *wbuf_bytes)
+{
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+  (void)tls;
+  (void)rbuf_capacity;
+  (void)rbuf_bytes;
+  (void)wbuf_capacity;
+  (void)wbuf_bytes;
+
+  return -1;
+#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)) */
+  if (tls->ssl->s3->rbuf.buf)
+    *rbuf_capacity = tls->ssl->s3->rbuf.len;
+  else
+    *rbuf_capacity = 0;
+  if (tls->ssl->s3->wbuf.buf)
+    *wbuf_capacity = tls->ssl->s3->wbuf.len;
+  else
+    *wbuf_capacity = 0;
+  *rbuf_bytes = tls->ssl->s3->rbuf.left;
+  *wbuf_bytes = tls->ssl->s3->wbuf.left;
+  return 0;
+#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
+}
+
+/** Check whether the ECC group requested is supported by the current OpenSSL
+ * library instance.  Return 1 if the group is supported, and 0 if not.
+ */
+int
+evaluate_ecgroup_for_tls(const char *ecgroup)
+{
+  EC_KEY *ec_key;
+  int nid;
+  int ret;
+
+  if (!ecgroup)
+    nid = NID_tor_default_ecdhe_group;
+  else if (!strcasecmp(ecgroup, "P256"))
+    nid = NID_X9_62_prime256v1;
+  else if (!strcasecmp(ecgroup, "P224"))
+    nid = NID_secp224r1;
+  else
+    return 0;
+
+  ec_key = EC_KEY_new_by_curve_name(nid);
+  ret = (ec_key != NULL);
+  EC_KEY_free(ec_key);
+
+  return ret;
+}
diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c
index 8bed6f5a1..dbf1dd927 100644
--- a/src/lib/tls/x509.c
+++ b/src/lib/tls/x509.c
@@ -4,86 +4,15 @@
 /* See LICENSE for licensing information */
 
 /**
- * \file x509.c
+ * \file x509_openssl.c
  * \brief Wrapper functions to present a consistent interface to
- * X.509 functions from OpenSSL.
+ * X.509 functions.
  **/
 
 #define TOR_X509_PRIVATE
 #include "lib/tls/x509.h"
-#include "lib/tls/tortls.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/crypt_ops/crypto_util.h"
-#include "lib/crypt_ops/compat_openssl.h"
-
-/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
- * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
-
-#include <openssl/opensslv.h>
-
-#ifdef OPENSSL_NO_EC
-#error "We require OpenSSL with ECC support"
-#endif
-
-#include <openssl/err.h>
-#include <openssl/asn1.h>
-#include <openssl/bio.h>
-#include <openssl/bn.h>
-#include <openssl/rsa.h>
-
-ENABLE_GCC_WARNING(redundant-decls)
-
-#include "lib/log/log.h"
 #include "lib/log/util_bug.h"
-#include "lib/ctime/di_ops.h"
-#include "lib/encoding/time_fmt.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef OPENSSL_1_1_API
-#define X509_get_notBefore_const(cert) \
-    X509_get0_notBefore(cert)
-#define X509_get_notAfter_const(cert) \
-    X509_get0_notAfter(cert)
-#ifndef X509_get_notBefore
-#define X509_get_notBefore(cert) \
-    X509_getm_notBefore(cert)
-#endif
-#ifndef X509_get_notAfter
-#define X509_get_notAfter(cert) \
-    X509_getm_notAfter(cert)
-#endif
-#else /* ! OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
-#define X509_get_notBefore_const(cert) \
-  ((const ASN1_TIME*) X509_get_notBefore((X509 *)cert))
-#define X509_get_notAfter_const(cert) \
-  ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert))
-#endif
-
-/** Return a newly allocated X509 name with commonName <b>cname</b>. */
-static X509_NAME *
-tor_x509_name_new(const char *cname)
-{
-  int nid;
-  X509_NAME *name;
-  /* LCOV_EXCL_BR_START : these branches will only fail on OOM errors */
-  if (!(name = X509_NAME_new()))
-    return NULL;
-  if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
-  if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
-                                   (unsigned char*)cname, -1, -1, 0)))
-    goto error;
-  /* LCOV_EXCL_BR_STOP */
-  return name;
-
-  /* LCOV_EXCL_START : these lines will only execute on out of memory errors*/
- error:
-  X509_NAME_free(name);
-  return NULL;
-  /* LCOV_EXCL_STOP */
-}
+#include "lib/crypt_ops/crypto_rand.h"
 
 /** Choose the start and end times for a certificate */
 void
@@ -121,221 +50,6 @@ tor_tls_pick_certificate_lifetime(time_t now,
   *end_time_out = end_time;
 }
 
-/** Generate and sign an X509 certificate with the public key <b>rsa</b>,
- * signed by the private key <b>rsa_sign</b>.  The commonName of the
- * certificate will be <b>cname</b>; the commonName of the issuer will be
- * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b>
- * seconds, starting from some time in the past.
- *
- * Return a certificate on success, NULL on failure.
- */
-MOCK_IMPL(X509 *,
-tor_tls_create_certificate,(crypto_pk_t *rsa,
-                            crypto_pk_t *rsa_sign,
-                            const char *cname,
-                            const char *cname_sign,
-                            unsigned int cert_lifetime))
-{
-  /* OpenSSL generates self-signed certificates with random 64-bit serial
-   * numbers, so let's do that too. */
-#define SERIAL_NUMBER_SIZE 8
-
-  time_t start_time, end_time;
-  BIGNUM *serial_number = NULL;
-  unsigned char serial_tmp[SERIAL_NUMBER_SIZE];
-  EVP_PKEY *sign_pkey = NULL, *pkey=NULL;
-  X509 *x509 = NULL;
-  X509_NAME *name = NULL, *name_issuer=NULL;
-
-  tor_tls_init();
-
-  time_t now = time(NULL);
-
-  tor_tls_pick_certificate_lifetime(now, cert_lifetime,
-                                    &start_time, &end_time);
-
-  tor_assert(rsa);
-  tor_assert(cname);
-  tor_assert(rsa_sign);
-  tor_assert(cname_sign);
-  if (!(sign_pkey = crypto_pk_get_openssl_evp_pkey_(rsa_sign,1)))
-    goto error;
-  if (!(pkey = crypto_pk_get_openssl_evp_pkey_(rsa,0)))
-    goto error;
-  if (!(x509 = X509_new()))
-    goto error;
-  if (!(X509_set_version(x509, 2)))
-    goto error;
-
-  { /* our serial number is 8 random bytes. */
-    crypto_rand((char *)serial_tmp, sizeof(serial_tmp));
-    if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL)))
-      goto error;
-    if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509))))
-      goto error;
-  }
-
-  if (!(name = tor_x509_name_new(cname)))
-    goto error;
-  if (!(X509_set_subject_name(x509, name)))
-    goto error;
-  if (!(name_issuer = tor_x509_name_new(cname_sign)))
-    goto error;
-  if (!(X509_set_issuer_name(x509, name_issuer)))
-    goto error;
-
-  if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time))
-    goto error;
-  if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time))
-    goto error;
-  if (!X509_set_pubkey(x509, pkey))
-    goto error;
-
-  if (!X509_sign(x509, sign_pkey, EVP_sha256()))
-    goto error;
-
-  goto done;
- error:
-  if (x509) {
-    X509_free(x509);
-    x509 = NULL;
-  }
- done:
-  tls_log_errors(NULL, LOG_WARN, LD_NET, "generating certificate");
-  if (sign_pkey)
-    EVP_PKEY_free(sign_pkey);
-  if (pkey)
-    EVP_PKEY_free(pkey);
-  if (serial_number)
-    BN_clear_free(serial_number);
-  if (name)
-    X509_NAME_free(name);
-  if (name_issuer)
-    X509_NAME_free(name_issuer);
-  return x509;
-
-#undef SERIAL_NUMBER_SIZE
-}
-
-/** Free all storage held in <b>cert</b> */
-void
-tor_x509_cert_free_(tor_x509_cert_t *cert)
-{
-  if (! cert)
-    return;
-  if (cert->cert)
-    X509_free(cert->cert);
-  tor_free(cert->encoded);
-  memwipe(cert, 0x03, sizeof(*cert));
-  /* LCOV_EXCL_BR_START since cert will never be NULL here */
-  tor_free(cert);
-  /* LCOV_EXCL_BR_STOP */
-}
-
-/**
- * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert".
- *
- * Steals a reference to x509_cert.
- */
-MOCK_IMPL(tor_x509_cert_t *,
-tor_x509_cert_new,(X509 *x509_cert))
-{
-  tor_x509_cert_t *cert;
-  EVP_PKEY *pkey;
-  RSA *rsa;
-  int length;
-  unsigned char *buf = NULL;
-
-  if (!x509_cert)
-    return NULL;
-
-  length = i2d_X509(x509_cert, &buf);
-  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  if (length <= 0 || buf == NULL) {
-    goto err;
-  }
-  cert->encoded_len = (size_t) length;
-  cert->encoded = tor_malloc(length);
-  memcpy(cert->encoded, buf, length);
-  OPENSSL_free(buf);
-
-  cert->cert = x509_cert;
-
-  crypto_common_digests(&cert->cert_digests,
-                    (char*)cert->encoded, cert->encoded_len);
-
-  if ((pkey = X509_get_pubkey(x509_cert)) &&
-      (rsa = EVP_PKEY_get1_RSA(pkey))) {
-    crypto_pk_t *pk = crypto_new_pk_from_openssl_rsa_(rsa);
-    if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) {
-      crypto_pk_free(pk);
-      EVP_PKEY_free(pkey);
-      goto err;
-    }
-
-    cert->pkey_digests_set = 1;
-    crypto_pk_free(pk);
-    EVP_PKEY_free(pkey);
-  }
-
-  return cert;
- err:
-  /* LCOV_EXCL_START for the same reason as the exclusion above */
-  tor_free(cert);
-  log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate.");
-  X509_free(x509_cert);
-  return NULL;
-  /* LCOV_EXCL_STOP */
-}
-
-/** Return a new copy of <b>cert</b>. */
-tor_x509_cert_t *
-tor_x509_cert_dup(const tor_x509_cert_t *cert)
-{
-  tor_assert(cert);
-  X509 *x509 = cert->cert;
-  return tor_x509_cert_new(X509_dup(x509));
-}
-
-/** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>,
- * from a <b>certificate</b>.  Return a newly allocated tor_x509_cert_t on
- * success and NULL on failure. */
-tor_x509_cert_t *
-tor_x509_cert_decode(const uint8_t *certificate, size_t certificate_len)
-{
-  X509 *x509;
-  const unsigned char *cp = (const unsigned char *)certificate;
-  tor_x509_cert_t *newcert;
-  tor_assert(certificate);
-  check_no_tls_errors();
-
-  if (certificate_len > INT_MAX)
-    goto err;
-
-  x509 = d2i_X509(NULL, &cp, (int)certificate_len);
-
-  if (!x509)
-    goto err; /* Couldn't decode */
-  if (cp - certificate != (int)certificate_len) {
-    X509_free(x509);
-    goto err; /* Didn't use all the bytes */
-  }
-  newcert = tor_x509_cert_new(x509);
-  if (!newcert) {
-    goto err;
-  }
-  if (newcert->encoded_len != certificate_len ||
-      fast_memneq(newcert->encoded, certificate, certificate_len)) {
-    /* Cert wasn't in DER */
-    tor_x509_cert_free(newcert);
-    goto err;
-  }
-  return newcert;
- err:
-  tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "decoding a certificate");
-  return NULL;
-}
-
 /** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER
  * representation and length, respectively. */
 void
@@ -375,190 +89,3 @@ tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert)
   return &cert->cert_digests;
 }
 
-/**
- * Return a newly allocated copy of the public key that a certificate
- * certifies. Watch out! This returns NULL if the cert's key is not RSA.
- */
-crypto_pk_t *
-tor_tls_cert_get_key(tor_x509_cert_t *cert)
-{
-  crypto_pk_t *result = NULL;
-  EVP_PKEY *pkey = X509_get_pubkey(cert->cert);
-  RSA *rsa;
-  if (!pkey)
-    return NULL;
-  rsa = EVP_PKEY_get1_RSA(pkey);
-  if (!rsa) {
-    EVP_PKEY_free(pkey);
-    return NULL;
-  }
-  result = crypto_new_pk_from_openssl_rsa_(rsa);
-  EVP_PKEY_free(pkey);
-  return result;
-}
-
-/** Check whether <b>cert</b> is well-formed, currently live, and correctly
- * signed by the public key in <b>signing_cert</b>.  If <b>check_rsa_1024</b>,
- * make sure that it has an RSA key with 1024 bits; otherwise, just check that
- * the key is long enough. Return 1 if the cert is good, and 0 if it's bad or
- * we couldn't check it. */
-int
-tor_tls_cert_is_valid(int severity,
-                      const tor_x509_cert_t *cert,
-                      const tor_x509_cert_t *signing_cert,
-                      time_t now,
-                      int check_rsa_1024)
-{
-  check_no_tls_errors();
-  EVP_PKEY *cert_key;
-  int r, key_ok = 0;
-
-  if (!signing_cert || !cert)
-    goto bad;
-
-  EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert);
-  if (!signing_key)
-    goto bad;
-  r = X509_verify(cert->cert, signing_key);
-  EVP_PKEY_free(signing_key);
-  if (r <= 0)
-    goto bad;
-
-  /* okay, the signature checked out right.  Now let's check the check the
-   * lifetime. */
-  if (tor_x509_check_cert_lifetime_internal(severity, cert->cert, now,
-                                   48*60*60, 30*24*60*60) < 0)
-    goto bad;
-
-  cert_key = X509_get_pubkey(cert->cert);
-  if (check_rsa_1024 && cert_key) {
-    RSA *rsa = EVP_PKEY_get1_RSA(cert_key);
-#ifdef OPENSSL_1_1_API
-    if (rsa && RSA_bits(rsa) == 1024)
-#else
-    if (rsa && BN_num_bits(rsa->n) == 1024)
-#endif
-      key_ok = 1;
-    if (rsa)
-      RSA_free(rsa);
-  } else if (cert_key) {
-    int min_bits = 1024;
-#ifdef EVP_PKEY_EC
-    if (EVP_PKEY_base_id(cert_key) == EVP_PKEY_EC)
-      min_bits = 128;
-#endif
-    if (EVP_PKEY_bits(cert_key) >= min_bits)
-      key_ok = 1;
-  }
-  EVP_PKEY_free(cert_key);
-  if (!key_ok)
-    goto bad;
-
-  /* XXXX compare DNs or anything? */
-
-  return 1;
- bad:
-  tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "checking a certificate");
-  return 0;
-}
-
-/** Warn that a certificate lifetime extends through a certain range. */
-static void
-log_cert_lifetime(int severity, const X509 *cert, const char *problem,
-                  time_t now)
-{
-  BIO *bio = NULL;
-  BUF_MEM *buf;
-  char *s1=NULL, *s2=NULL;
-  char mytime[33];
-  struct tm tm;
-  size_t n;
-
-  if (problem)
-    tor_log(severity, LD_GENERAL,
-        "Certificate %s. Either their clock is set wrong, or your clock "
-        "is wrong.",
-           problem);
-
-  if (!(bio = BIO_new(BIO_s_mem()))) {
-    log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end;
-  }
-  if (!(ASN1_TIME_print(bio, X509_get_notBefore_const(cert)))) {
-    tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
-    goto end;
-  }
-  BIO_get_mem_ptr(bio, &buf);
-  s1 = tor_strndup(buf->data, buf->length);
-
-  (void)BIO_reset(bio);
-  if (!(ASN1_TIME_print(bio, X509_get_notAfter_const(cert)))) {
-    tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
-    goto end;
-  }
-  BIO_get_mem_ptr(bio, &buf);
-  s2 = tor_strndup(buf->data, buf->length);
-
-  n = strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm));
-  if (n > 0) {
-    tor_log(severity, LD_GENERAL,
-        "(certificate lifetime runs from %s through %s. Your time is %s.)",
-        s1,s2,mytime);
-  } else {
-    tor_log(severity, LD_GENERAL,
-        "(certificate lifetime runs from %s through %s. "
-        "Couldn't get your time.)",
-        s1, s2);
-  }
-
- end:
-  /* Not expected to get invoked */
-  tls_log_errors(NULL, LOG_WARN, LD_NET, "getting certificate lifetime");
-  if (bio)
-    BIO_free(bio);
-  tor_free(s1);
-  tor_free(s2);
-}
-
-/** Helper: check whether <b>cert</b> is expired give or take
- * <b>past_tolerance</b> seconds, or not-yet-valid give or take
- * <b>future_tolerance</b> seconds.  (Relative to the current time
- * <b>now</b>.)  If it is live, return 0.  If it is not live, log a message
- * and return -1. */
-int
-tor_x509_check_cert_lifetime_internal(int severity, const X509 *cert,
-                                      time_t now,
-                                      int past_tolerance, int future_tolerance)
-{
-  time_t t;
-
-  t = now + future_tolerance;
-  if (X509_cmp_time(X509_get_notBefore_const(cert), &t) > 0) {
-    log_cert_lifetime(severity, cert, "not yet valid", now);
-    return -1;
-  }
-  t = now - past_tolerance;
-  if (X509_cmp_time(X509_get_notAfter_const(cert), &t) < 0) {
-    log_cert_lifetime(severity, cert, "already expired", now);
-    return -1;
-  }
-
-  return 0;
-}
-
-#ifdef TOR_UNIT_TESTS
-/* Testing only: return a new x509 cert with the same contents as <b>inp</b>,
-   but with the expiration time <b>new_expiration_time</b>, signed with
-   <b>signing_key</b>. */
-STATIC tor_x509_cert_t *
-tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp,
-                                 time_t new_expiration_time,
-                                 crypto_pk_t *signing_key)
-{
-  X509 *newc = X509_dup(inp->cert);
-  X509_time_adj(X509_get_notAfter(newc), 0, &new_expiration_time);
-  EVP_PKEY *pk = crypto_pk_get_openssl_evp_pkey_(signing_key, 1);
-  tor_assert(X509_sign(newc, pk, EVP_sha256()));
-  EVP_PKEY_free(pk);
-  return tor_x509_cert_new(newc);
-}
-#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index e3dfcf393..f75d15d7e 100644
--- a/src/lib/tls/x509.h
+++ b/src/lib/tls/x509.h
@@ -17,7 +17,9 @@
 /* Opaque structure to hold an X509 certificate. */
 typedef struct tor_x509_cert_t tor_x509_cert_t;
 
-#ifdef ENABLE_OPENSSL
+#ifdef ENABLE_NSS
+typedef struct CERTCertificateStr tor_x509_cert_impl_t;
+#elif defined(ENABLE_OPENSSL)
 typedef struct x509_st tor_x509_cert_impl_t;
 #endif
 
diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c
new file mode 100644
index 000000000..e856c9518
--- /dev/null
+++ b/src/lib/tls/x509_nss.c
@@ -0,0 +1,122 @@
+/* Copyright (c) 2003, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file x509_nss.c
+ * \brief Wrapper functions to present a consistent interface to
+ * X.509 functions from NSS.
+ **/
+
+#define TOR_X509_PRIVATE
+#include "lib/tls/x509.h"
+#include "lib/tls/tortls.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/log/util_bug.h"
+
+MOCK_IMPL(tor_x509_cert_impl_t *,
+tor_tls_create_certificate,(crypto_pk_t *rsa,
+                            crypto_pk_t *rsa_sign,
+                            const char *cname,
+                            const char *cname_sign,
+                            unsigned int cert_lifetime))
+{
+  tor_assert(rsa);
+  tor_assert(rsa_sign);
+  tor_assert(cname);
+  tor_assert(cname_sign);
+  (void) cert_lifetime;
+  // XXXX
+  return NULL;
+}
+
+MOCK_IMPL(tor_x509_cert_t *,
+tor_x509_cert_new,(tor_x509_cert_impl_t *x509_cert))
+{
+  tor_assert(x509_cert);
+  // XXXX
+  return NULL;
+}
+
+tor_x509_cert_t *
+tor_x509_cert_dup(const tor_x509_cert_t *cert)
+{
+  tor_assert(cert);
+  // XXXX
+  return NULL;
+}
+
+void
+tor_x509_cert_free_(tor_x509_cert_t *cert)
+{
+  (void)cert;
+  // XXXX
+}
+
+tor_x509_cert_t *
+tor_x509_cert_decode(const uint8_t *certificate,
+                     size_t certificate_len)
+{
+  tor_assert(certificate);
+  (void) certificate_len;
+  // XXXX
+  return NULL;
+}
+
+crypto_pk_t *
+tor_tls_cert_get_key(tor_x509_cert_t *cert)
+{
+  tor_assert(cert);
+  // XXXXX
+  return NULL;
+}
+
+int
+tor_tls_cert_is_valid(int severity,
+                      const tor_x509_cert_t *cert,
+                      const tor_x509_cert_t *signing_cert,
+                      time_t now,
+                      int check_rsa_1024)
+{
+  tor_assert(cert);
+  tor_assert(signing_cert);
+  (void)severity;
+  (void)now;
+  (void)check_rsa_1024;
+  // XXXXX
+
+  return 0;
+}
+
+int
+tor_x509_check_cert_lifetime_internal(int severity,
+                                      const tor_x509_cert_impl_t *cert,
+                                      time_t now,
+                                      int past_tolerance,
+                                      int future_tolerance)
+{
+  tor_assert(cert);
+  (void)severity;
+  (void)now;
+  (void)past_tolerance;
+  (void)future_tolerance;
+  // XXXX
+  return -1;
+}
+
+#ifdef TOR_UNIT_TESTS
+tor_x509_cert_t *
+tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp,
+                                 time_t new_expiration_time,
+                                 crypto_pk_t *signing_key)
+{
+  tor_assert(inp);
+  tor_assert(signing_key);
+  (void)new_expiration_time;
+
+  // XXXX
+  return NULL;
+}
+#endif
diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c
new file mode 100644
index 000000000..c003d4704
--- /dev/null
+++ b/src/lib/tls/x509_openssl.c
@@ -0,0 +1,489 @@
+/* Copyright (c) 2003, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file x509_openssl.c
+ * \brief Wrapper functions to present a consistent interface to
+ * X.509 functions from OpenSSL.
+ **/
+
+#define TOR_X509_PRIVATE
+#include "lib/tls/x509.h"
+#include "lib/tls/tortls.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/crypt_ops/compat_openssl.h"
+
+/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
+ * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/opensslv.h>
+
+#ifdef OPENSSL_NO_EC
+#error "We require OpenSSL with ECC support"
+#endif
+
+#include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/encoding/time_fmt.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef OPENSSL_1_1_API
+#define X509_get_notBefore_const(cert) \
+    X509_get0_notBefore(cert)
+#define X509_get_notAfter_const(cert) \
+    X509_get0_notAfter(cert)
+#ifndef X509_get_notBefore
+#define X509_get_notBefore(cert) \
+    X509_getm_notBefore(cert)
+#endif
+#ifndef X509_get_notAfter
+#define X509_get_notAfter(cert) \
+    X509_getm_notAfter(cert)
+#endif
+#else /* ! OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
+#define X509_get_notBefore_const(cert) \
+  ((const ASN1_TIME*) X509_get_notBefore((X509 *)cert))
+#define X509_get_notAfter_const(cert) \
+  ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert))
+#endif
+
+/** Return a newly allocated X509 name with commonName <b>cname</b>. */
+static X509_NAME *
+tor_x509_name_new(const char *cname)
+{
+  int nid;
+  X509_NAME *name;
+  /* LCOV_EXCL_BR_START : these branches will only fail on OOM errors */
+  if (!(name = X509_NAME_new()))
+    return NULL;
+  if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
+  if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
+                                   (unsigned char*)cname, -1, -1, 0)))
+    goto error;
+  /* LCOV_EXCL_BR_STOP */
+  return name;
+
+  /* LCOV_EXCL_START : these lines will only execute on out of memory errors*/
+ error:
+  X509_NAME_free(name);
+  return NULL;
+  /* LCOV_EXCL_STOP */
+}
+
+/** Generate and sign an X509 certificate with the public key <b>rsa</b>,
+ * signed by the private key <b>rsa_sign</b>.  The commonName of the
+ * certificate will be <b>cname</b>; the commonName of the issuer will be
+ * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b>
+ * seconds, starting from some time in the past.
+ *
+ * Return a certificate on success, NULL on failure.
+ */
+MOCK_IMPL(X509 *,
+tor_tls_create_certificate,(crypto_pk_t *rsa,
+                            crypto_pk_t *rsa_sign,
+                            const char *cname,
+                            const char *cname_sign,
+                            unsigned int cert_lifetime))
+{
+  /* OpenSSL generates self-signed certificates with random 64-bit serial
+   * numbers, so let's do that too. */
+#define SERIAL_NUMBER_SIZE 8
+
+  time_t start_time, end_time;
+  BIGNUM *serial_number = NULL;
+  unsigned char serial_tmp[SERIAL_NUMBER_SIZE];
+  EVP_PKEY *sign_pkey = NULL, *pkey=NULL;
+  X509 *x509 = NULL;
+  X509_NAME *name = NULL, *name_issuer=NULL;
+
+  tor_tls_init();
+
+  time_t now = time(NULL);
+
+  tor_tls_pick_certificate_lifetime(now, cert_lifetime,
+                                    &start_time, &end_time);
+
+  tor_assert(rsa);
+  tor_assert(cname);
+  tor_assert(rsa_sign);
+  tor_assert(cname_sign);
+  if (!(sign_pkey = crypto_pk_get_openssl_evp_pkey_(rsa_sign,1)))
+    goto error;
+  if (!(pkey = crypto_pk_get_openssl_evp_pkey_(rsa,0)))
+    goto error;
+  if (!(x509 = X509_new()))
+    goto error;
+  if (!(X509_set_version(x509, 2)))
+    goto error;
+
+  { /* our serial number is 8 random bytes. */
+    crypto_rand((char *)serial_tmp, sizeof(serial_tmp));
+    if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL)))
+      goto error;
+    if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509))))
+      goto error;
+  }
+
+  if (!(name = tor_x509_name_new(cname)))
+    goto error;
+  if (!(X509_set_subject_name(x509, name)))
+    goto error;
+  if (!(name_issuer = tor_x509_name_new(cname_sign)))
+    goto error;
+  if (!(X509_set_issuer_name(x509, name_issuer)))
+    goto error;
+
+  if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time))
+    goto error;
+  if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time))
+    goto error;
+  if (!X509_set_pubkey(x509, pkey))
+    goto error;
+
+  if (!X509_sign(x509, sign_pkey, EVP_sha256()))
+    goto error;
+
+  goto done;
+ error:
+  if (x509) {
+    X509_free(x509);
+    x509 = NULL;
+  }
+ done:
+  tls_log_errors(NULL, LOG_WARN, LD_NET, "generating certificate");
+  if (sign_pkey)
+    EVP_PKEY_free(sign_pkey);
+  if (pkey)
+    EVP_PKEY_free(pkey);
+  if (serial_number)
+    BN_clear_free(serial_number);
+  if (name)
+    X509_NAME_free(name);
+  if (name_issuer)
+    X509_NAME_free(name_issuer);
+  return x509;
+
+#undef SERIAL_NUMBER_SIZE
+}
+
+/** Free all storage held in <b>cert</b> */
+void
+tor_x509_cert_free_(tor_x509_cert_t *cert)
+{
+  if (! cert)
+    return;
+  if (cert->cert)
+    X509_free(cert->cert);
+  tor_free(cert->encoded);
+  memwipe(cert, 0x03, sizeof(*cert));
+  /* LCOV_EXCL_BR_START since cert will never be NULL here */
+  tor_free(cert);
+  /* LCOV_EXCL_BR_STOP */
+}
+
+/**
+ * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert".
+ *
+ * Steals a reference to x509_cert.
+ */
+MOCK_IMPL(tor_x509_cert_t *,
+tor_x509_cert_new,(X509 *x509_cert))
+{
+  tor_x509_cert_t *cert;
+  EVP_PKEY *pkey;
+  RSA *rsa;
+  int length;
+  unsigned char *buf = NULL;
+
+  if (!x509_cert)
+    return NULL;
+
+  length = i2d_X509(x509_cert, &buf);
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  if (length <= 0 || buf == NULL) {
+    goto err;
+  }
+  cert->encoded_len = (size_t) length;
+  cert->encoded = tor_malloc(length);
+  memcpy(cert->encoded, buf, length);
+  OPENSSL_free(buf);
+
+  cert->cert = x509_cert;
+
+  crypto_common_digests(&cert->cert_digests,
+                    (char*)cert->encoded, cert->encoded_len);
+
+  if ((pkey = X509_get_pubkey(x509_cert)) &&
+      (rsa = EVP_PKEY_get1_RSA(pkey))) {
+    crypto_pk_t *pk = crypto_new_pk_from_openssl_rsa_(rsa);
+    if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) {
+      crypto_pk_free(pk);
+      EVP_PKEY_free(pkey);
+      goto err;
+    }
+
+    cert->pkey_digests_set = 1;
+    crypto_pk_free(pk);
+    EVP_PKEY_free(pkey);
+  }
+
+  return cert;
+ err:
+  /* LCOV_EXCL_START for the same reason as the exclusion above */
+  tor_free(cert);
+  log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate.");
+  X509_free(x509_cert);
+  return NULL;
+  /* LCOV_EXCL_STOP */
+}
+
+/** Return a new copy of <b>cert</b>. */
+tor_x509_cert_t *
+tor_x509_cert_dup(const tor_x509_cert_t *cert)
+{
+  tor_assert(cert);
+  X509 *x509 = cert->cert;
+  return tor_x509_cert_new(X509_dup(x509));
+}
+
+/** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>,
+ * from a <b>certificate</b>.  Return a newly allocated tor_x509_cert_t on
+ * success and NULL on failure. */
+tor_x509_cert_t *
+tor_x509_cert_decode(const uint8_t *certificate, size_t certificate_len)
+{
+  X509 *x509;
+  const unsigned char *cp = (const unsigned char *)certificate;
+  tor_x509_cert_t *newcert;
+  tor_assert(certificate);
+  check_no_tls_errors();
+
+  if (certificate_len > INT_MAX)
+    goto err;
+
+  x509 = d2i_X509(NULL, &cp, (int)certificate_len);
+
+  if (!x509)
+    goto err; /* Couldn't decode */
+  if (cp - certificate != (int)certificate_len) {
+    X509_free(x509);
+    goto err; /* Didn't use all the bytes */
+  }
+  newcert = tor_x509_cert_new(x509);
+  if (!newcert) {
+    goto err;
+  }
+  if (newcert->encoded_len != certificate_len ||
+      fast_memneq(newcert->encoded, certificate, certificate_len)) {
+    /* Cert wasn't in DER */
+    tor_x509_cert_free(newcert);
+    goto err;
+  }
+  return newcert;
+ err:
+  tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "decoding a certificate");
+  return NULL;
+}
+
+/**
+ * Return a newly allocated copy of the public key that a certificate
+ * certifies. Watch out! This returns NULL if the cert's key is not RSA.
+ */
+crypto_pk_t *
+tor_tls_cert_get_key(tor_x509_cert_t *cert)
+{
+  crypto_pk_t *result = NULL;
+  EVP_PKEY *pkey = X509_get_pubkey(cert->cert);
+  RSA *rsa;
+  if (!pkey)
+    return NULL;
+  rsa = EVP_PKEY_get1_RSA(pkey);
+  if (!rsa) {
+    EVP_PKEY_free(pkey);
+    return NULL;
+  }
+  result = crypto_new_pk_from_openssl_rsa_(rsa);
+  EVP_PKEY_free(pkey);
+  return result;
+}
+
+/** Check whether <b>cert</b> is well-formed, currently live, and correctly
+ * signed by the public key in <b>signing_cert</b>.  If <b>check_rsa_1024</b>,
+ * make sure that it has an RSA key with 1024 bits; otherwise, just check that
+ * the key is long enough. Return 1 if the cert is good, and 0 if it's bad or
+ * we couldn't check it. */
+int
+tor_tls_cert_is_valid(int severity,
+                      const tor_x509_cert_t *cert,
+                      const tor_x509_cert_t *signing_cert,
+                      time_t now,
+                      int check_rsa_1024)
+{
+  check_no_tls_errors();
+  EVP_PKEY *cert_key;
+  int r, key_ok = 0;
+
+  if (!signing_cert || !cert)
+    goto bad;
+
+  EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert);
+  if (!signing_key)
+    goto bad;
+  r = X509_verify(cert->cert, signing_key);
+  EVP_PKEY_free(signing_key);
+  if (r <= 0)
+    goto bad;
+
+  /* okay, the signature checked out right.  Now let's check the check the
+   * lifetime. */
+  if (tor_x509_check_cert_lifetime_internal(severity, cert->cert, now,
+                                   48*60*60, 30*24*60*60) < 0)
+    goto bad;
+
+  cert_key = X509_get_pubkey(cert->cert);
+  if (check_rsa_1024 && cert_key) {
+    RSA *rsa = EVP_PKEY_get1_RSA(cert_key);
+#ifdef OPENSSL_1_1_API
+    if (rsa && RSA_bits(rsa) == 1024)
+#else
+    if (rsa && BN_num_bits(rsa->n) == 1024)
+#endif
+      key_ok = 1;
+    if (rsa)
+      RSA_free(rsa);
+  } else if (cert_key) {
+    int min_bits = 1024;
+#ifdef EVP_PKEY_EC
+    if (EVP_PKEY_base_id(cert_key) == EVP_PKEY_EC)
+      min_bits = 128;
+#endif
+    if (EVP_PKEY_bits(cert_key) >= min_bits)
+      key_ok = 1;
+  }
+  EVP_PKEY_free(cert_key);
+  if (!key_ok)
+    goto bad;
+
+  /* XXXX compare DNs or anything? */
+
+  return 1;
+ bad:
+  tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "checking a certificate");
+  return 0;
+}
+
+/** Warn that a certificate lifetime extends through a certain range. */
+static void
+log_cert_lifetime(int severity, const X509 *cert, const char *problem,
+                  time_t now)
+{
+  BIO *bio = NULL;
+  BUF_MEM *buf;
+  char *s1=NULL, *s2=NULL;
+  char mytime[33];
+  struct tm tm;
+  size_t n;
+
+  if (problem)
+    tor_log(severity, LD_GENERAL,
+        "Certificate %s. Either their clock is set wrong, or your clock "
+        "is wrong.",
+           problem);
+
+  if (!(bio = BIO_new(BIO_s_mem()))) {
+    log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end;
+  }
+  if (!(ASN1_TIME_print(bio, X509_get_notBefore_const(cert)))) {
+    tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
+    goto end;
+  }
+  BIO_get_mem_ptr(bio, &buf);
+  s1 = tor_strndup(buf->data, buf->length);
+
+  (void)BIO_reset(bio);
+  if (!(ASN1_TIME_print(bio, X509_get_notAfter_const(cert)))) {
+    tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
+    goto end;
+  }
+  BIO_get_mem_ptr(bio, &buf);
+  s2 = tor_strndup(buf->data, buf->length);
+
+  n = strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm));
+  if (n > 0) {
+    tor_log(severity, LD_GENERAL,
+        "(certificate lifetime runs from %s through %s. Your time is %s.)",
+        s1,s2,mytime);
+  } else {
+    tor_log(severity, LD_GENERAL,
+        "(certificate lifetime runs from %s through %s. "
+        "Couldn't get your time.)",
+        s1, s2);
+  }
+
+ end:
+  /* Not expected to get invoked */
+  tls_log_errors(NULL, LOG_WARN, LD_NET, "getting certificate lifetime");
+  if (bio)
+    BIO_free(bio);
+  tor_free(s1);
+  tor_free(s2);
+}
+
+/** Helper: check whether <b>cert</b> is expired give or take
+ * <b>past_tolerance</b> seconds, or not-yet-valid give or take
+ * <b>future_tolerance</b> seconds.  (Relative to the current time
+ * <b>now</b>.)  If it is live, return 0.  If it is not live, log a message
+ * and return -1. */
+int
+tor_x509_check_cert_lifetime_internal(int severity, const X509 *cert,
+                                      time_t now,
+                                      int past_tolerance, int future_tolerance)
+{
+  time_t t;
+
+  t = now + future_tolerance;
+  if (X509_cmp_time(X509_get_notBefore_const(cert), &t) > 0) {
+    log_cert_lifetime(severity, cert, "not yet valid", now);
+    return -1;
+  }
+  t = now - past_tolerance;
+  if (X509_cmp_time(X509_get_notAfter_const(cert), &t) < 0) {
+    log_cert_lifetime(severity, cert, "already expired", now);
+    return -1;
+  }
+
+  return 0;
+}
+
+#ifdef TOR_UNIT_TESTS
+/* Testing only: return a new x509 cert with the same contents as <b>inp</b>,
+   but with the expiration time <b>new_expiration_time</b>, signed with
+   <b>signing_key</b>. */
+STATIC tor_x509_cert_t *
+tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp,
+                                 time_t new_expiration_time,
+                                 crypto_pk_t *signing_key)
+{
+  X509 *newc = X509_dup(inp->cert);
+  X509_time_adj(X509_get_notAfter(newc), 0, &new_expiration_time);
+  EVP_PKEY *pk = crypto_pk_get_openssl_evp_pkey_(signing_key, 1);
+  tor_assert(X509_sign(newc, pk, EVP_sha256()));
+  EVP_PKEY_free(pk);
+  return tor_x509_cert_new(newc);
+}
+#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/test/include.am b/src/test/include.am
index 68372adc7..c2e08aa3d 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -184,6 +184,14 @@ src_test_test_SOURCES += \
 	src/test/testing_common.c \
 	src/test/testing_rsakeys.c \
 	src/ext/tinytest.c
+
+if USE_NSS
+# ...
+else
+src_test_test_SOURCES += \
+	src/test/test_tortls_openssl.c
+endif
+
 endif
 
 src_test_test_slow_SOURCES =
diff --git a/src/test/test.c b/src/test/test.c
index 94eae5a4f..3b63f1c07 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -919,6 +919,9 @@ struct testgroup_t testgroups[] = {
   { "status/" , status_tests },
   { "storagedir/", storagedir_tests },
   { "tortls/", tortls_tests },
+#ifndef ENABLE_NSS
+  { "tortls/openssl/", tortls_openssl_tests },
+#endif
   { "util/", util_tests },
   { "util/format/", util_format_tests },
   { "util/logging/", logging_tests },
diff --git a/src/test/test.h b/src/test/test.h
index b3a73271e..94aa9443d 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -257,6 +257,7 @@ extern struct testcase_t socks_tests[];
 extern struct testcase_t status_tests[];
 extern struct testcase_t thread_tests[];
 extern struct testcase_t tortls_tests[];
+extern struct testcase_t tortls_openssl_tests[];
 extern struct testcase_t util_tests[];
 extern struct testcase_t util_format_tests[];
 extern struct testcase_t util_process_tests[];
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index ec197ba99..d20bc5fa6 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -2,7 +2,6 @@
 /* See LICENSE for licensing information */
 
 #define TORTLS_PRIVATE
-#define TORTLS_OPENSSL_PRIVATE
 #define TOR_X509_PRIVATE
 #define LOG_PRIVATE
 #include "orconfig.h"
@@ -11,64 +10,24 @@
 #include <winsock2.h>
 #endif
 #include <math.h>
+#include <stddef.h>
 
 #include "lib/cc/compat_compiler.h"
 
-/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
- * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
-
-#include <openssl/opensslv.h>
-
-#include <openssl/ssl.h>
-#include <openssl/ssl3.h>
-#include <openssl/err.h>
-#include <openssl/asn1t.h>
-#include <openssl/x509.h>
-#include <openssl/rsa.h>
-#include <openssl/evp.h>
-#include <openssl/bn.h>
-
-ENABLE_GCC_WARNING(redundant-decls)
-
 #include "core/or/or.h"
 #include "lib/log/log.h"
 #include "app/config/config.h"
 #include "lib/crypt_ops/compat_openssl.h"
+#include "lib/tls/x509.h"
 #include "lib/tls/tortls.h"
 #include "lib/tls/tortls_st.h"
-#include "lib/tls/x509.h"
+#include "lib/tls/tortls_internal.h"
 #include "app/config/or_state_st.h"
 
 #include "test/test.h"
 #include "test/log_test_helpers.h"
-#define NS_MODULE tortls
-
-#ifndef HAVE_SSL_STATE
-#define OPENSSL_OPAQUE
-#endif
 
-#if defined(OPENSSL_OPAQUE) && !defined(LIBRESSL_VERSION_NUMBER)
-#define SSL_STATE_STR "before SSL initialization"
-#else
-#define SSL_STATE_STR "before/accept initialization"
-#endif
-
-#ifndef OPENSSL_OPAQUE
-static SSL_METHOD *
-give_me_a_test_method(void)
-{
-  SSL_METHOD *method = tor_malloc_zero(sizeof(SSL_METHOD));
-  memcpy(method, TLSv1_method(), sizeof(SSL_METHOD));
-  return method;
-}
-
-static int
-fake_num_ciphers(void)
-{
-  return 0;
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
+#include "tinytest.h"
 
 static void
 test_tortls_errno_to_tls_error(void *data)
@@ -121,66 +80,6 @@ mock_tls_cert_matches_key(const tor_tls_t *tls, const tor_x509_cert_t *cert)
 }
 
 static void
-test_tortls_tor_tls_new(void *data)
-{
-  (void) data;
-  MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
-  crypto_pk_t *key1 = NULL, *key2 = NULL;
-  SSL_METHOD *method = NULL;
-
-  key1 = pk_generate(2);
-  key2 = pk_generate(3);
-
-  tor_tls_t *tls = NULL;
-  tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
-                                 key1, key2, 86400), OP_EQ, 0);
-  tls = tor_tls_new(-1, 0);
-  tt_want(tls);
-  tor_tls_free(tls); tls = NULL;
-
-  SSL_CTX_free(client_tls_context->ctx);
-  client_tls_context->ctx = NULL;
-  tls = tor_tls_new(-1, 0);
-  tt_ptr_op(tls, OP_EQ, NULL);
-
-#ifndef OPENSSL_OPAQUE
-  method = give_me_a_test_method();
-  SSL_CTX *ctx = SSL_CTX_new(method);
-  method->num_ciphers = fake_num_ciphers;
-  client_tls_context->ctx = ctx;
-  tls = tor_tls_new(-1, 0);
-  tt_ptr_op(tls, OP_EQ, NULL);
-#endif /* !defined(OPENSSL_OPAQUE) */
-
- done:
-  UNMOCK(tor_tls_cert_matches_key);
-  crypto_pk_free(key1);
-  crypto_pk_free(key2);
-  tor_tls_free(tls);
-  tor_free(method);
-  tor_tls_free_all();
-}
-
-#define NS_MODULE tortls
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
-                     const char *funcname, const char *suffix,
-                     const char *format, va_list ap));
-
-static void
-NS(logv)(int severity, log_domain_mask_t domain,
-         const char *funcname, const char *suffix, const char *format,
-         va_list ap)
-{
-  (void) severity;
-  (void) domain;
-  (void) funcname;
-  (void) suffix;
-  (void) format;
-  (void) ap; // XXXX look at this.
-  CALLED(logv)++;
-}
-
-static void
 test_tortls_tor_tls_get_error(void *data)
 {
   (void) data;
@@ -193,11 +92,10 @@ test_tortls_tor_tls_get_error(void *data)
   tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
                                  key1, key2, 86400), OP_EQ, 0);
   tls = tor_tls_new(-1, 0);
-  NS_MOCK(logv);
-  tt_int_op(CALLED(logv), OP_EQ, 0);
+  setup_capture_of_logs(LOG_WARN);
   tor_tls_get_error(tls, 0, 0,
-                    (const char *)"test", 0, 0);
-  tt_int_op(CALLED(logv), OP_EQ, 1);
+                    (const char *)"in unit test", LOG_WARN, LD_GENERAL);
+  expect_single_log_msg_containing("unexpected close while in unit test");
 
  done:
   UNMOCK(tor_tls_cert_matches_key);
@@ -208,2638 +106,172 @@ test_tortls_tor_tls_get_error(void *data)
 }
 
 static void
-library_init(void)
-{
-#ifdef OPENSSL_1_1_API
-  OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
-#else
-  SSL_library_init();
-  SSL_load_error_strings();
-#endif
-}
-
-static void
-test_tortls_get_state_description(void *ignored)
+test_tortls_x509_cert_get_id_digests(void *ignored)
 {
   (void)ignored;
-  tor_tls_t *tls;
-  char *buf;
-  SSL_CTX *ctx;
-
-  library_init();
-  ctx = SSL_CTX_new(SSLv23_method());
-
-  buf = tor_malloc_zero(1000);
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-
-  tor_tls_get_state_description(NULL, buf, 20);
-  tt_str_op(buf, OP_EQ, "(No SSL object)");
-
-  SSL_free(tls->ssl);
-  tls->ssl = NULL;
-  tor_tls_get_state_description(tls, buf, 20);
-  tt_str_op(buf, OP_EQ, "(No SSL object)");
-
-  tls->ssl = SSL_new(ctx);
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in HANDSHAKE");
-
-  tls->state = TOR_TLS_ST_OPEN;
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in OPEN");
-
-  tls->state = TOR_TLS_ST_GOTCLOSE;
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in GOTCLOSE");
-
-  tls->state = TOR_TLS_ST_SENTCLOSE;
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in SENTCLOSE");
-
-  tls->state = TOR_TLS_ST_CLOSED;
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in CLOSED");
-
-  tls->state = TOR_TLS_ST_RENEGOTIATE;
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in RENEGOTIATE");
+  tor_x509_cert_t *cert;
+  common_digests_t *d;
+  const common_digests_t *res;
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  d = tor_malloc_zero(sizeof(common_digests_t));
+  d->d[0][0] = 42;
 
-  tls->state = TOR_TLS_ST_BUFFEREVENT;
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR);
+  res = tor_x509_cert_get_id_digests(cert);
+  tt_assert(!res);
 
-  tls->state = 7;
-  tor_tls_get_state_description(tls, buf, 200);
-  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in unknown TLS state");
+  cert->pkey_digests_set = 1;
+  cert->pkey_digests = *d;
+  res = tor_x509_cert_get_id_digests(cert);
+  tt_int_op(res->d[0][0], OP_EQ, 42);
 
  done:
-  SSL_CTX_free(ctx);
-  SSL_free(tls->ssl);
-  tor_free(buf);
-  tor_free(tls);
+  tor_free(cert);
+  tor_free(d);
 }
 
 static void
-test_tortls_get_by_ssl(void *ignored)
+test_tortls_get_my_certs(void *ignored)
 {
   (void)ignored;
-  tor_tls_t *tls;
-  tor_tls_t *res;
-  SSL_CTX *ctx;
-  SSL *ssl;
-
-  library_init();
-  tor_tls_allocate_tor_tls_object_ex_data_index();
-
-  ctx = SSL_CTX_new(SSLv23_method());
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->magic = TOR_TLS_MAGIC;
-
-  ssl = SSL_new(ctx);
-
-  res = tor_tls_get_by_ssl(ssl);
-  tt_assert(!res);
+  int ret;
+  tor_tls_context_t *ctx;
+  const tor_x509_cert_t *link_cert_out = NULL;
+  const tor_x509_cert_t *id_cert_out = NULL;
 
-  SSL_set_ex_data(ssl, tor_tls_object_ex_data_index, tls);
+  ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
 
-  res = tor_tls_get_by_ssl(ssl);
-  tt_assert(res == tls);
+  client_tls_context = NULL;
+  ret = tor_tls_get_my_certs(0, NULL, NULL);
+  tt_int_op(ret, OP_EQ, -1);
 
- done:
-  SSL_free(ssl);
-  SSL_CTX_free(ctx);
-  tor_free(tls);
-}
+  server_tls_context = NULL;
+  ret = tor_tls_get_my_certs(1, NULL, NULL);
+  tt_int_op(ret, OP_EQ, -1);
 
-static void
-test_tortls_allocate_tor_tls_object_ex_data_index(void *ignored)
-{
-  (void)ignored;
-  int first;
+  client_tls_context = ctx;
+  ret = tor_tls_get_my_certs(0, NULL, NULL);
+  tt_int_op(ret, OP_EQ, 0);
 
-  tor_tls_allocate_tor_tls_object_ex_data_index();
+  client_tls_context = ctx;
+  ret = tor_tls_get_my_certs(0, &link_cert_out, &id_cert_out);
+  tt_int_op(ret, OP_EQ, 0);
 
-  first = tor_tls_object_ex_data_index;
-  tor_tls_allocate_tor_tls_object_ex_data_index();
-  tt_int_op(first, OP_EQ, tor_tls_object_ex_data_index);
+  server_tls_context = ctx;
+  ret = tor_tls_get_my_certs(1, &link_cert_out, &id_cert_out);
+  tt_int_op(ret, OP_EQ, 0);
 
  done:
-  (void)0;
+  (void)1;
 }
 
 static void
-test_tortls_log_one_error(void *ignored)
+test_tortls_get_forced_write_size(void *ignored)
 {
   (void)ignored;
+  long ret;
   tor_tls_t *tls;
-  SSL_CTX *ctx;
-  SSL *ssl = NULL;
 
-  library_init();
-
-  ctx = SSL_CTX_new(SSLv23_method());
   tls = tor_malloc_zero(sizeof(tor_tls_t));
-  setup_capture_of_logs(LOG_INFO);
-
-  tor_tls_log_one_error(NULL, 0, LOG_WARN, 0, "something");
-  expect_log_msg("TLS error while something: "
-            "(null) (in (null):(null):---)\n");
-
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
-  expect_log_msg("TLS error: (null) "
-            "(in (null):(null):---)\n");
-
-  mock_clean_saved_logs();
-  tls->address = tor_strdup("127.hello");
-  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
-  expect_log_msg("TLS error with 127.hello: "
-            "(null) (in (null):(null):---)\n");
-  tor_free(tls->address);
-
-  mock_clean_saved_logs();
-  tls->address = tor_strdup("127.hello");
-  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, "blarg");
-  expect_log_msg("TLS error while blarg with "
-            "127.hello: (null) (in (null):(null):---)\n");
-
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, ERR_PACK(1, 2, 3), LOG_WARN, 0, NULL);
-  expect_log_msg("TLS error with 127.hello: "
-            "BN lib (in unknown library:(null):---)\n");
-
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_HTTP_REQUEST),
-                        LOG_WARN, 0, NULL);
-  expect_log_severity(LOG_INFO);
-
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_HTTPS_PROXY_REQUEST),
-                        LOG_WARN, 0, NULL);
-  expect_log_severity(LOG_INFO);
-
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_LENGTH_MISMATCH),
-                        LOG_WARN, 0, NULL);
-  expect_log_severity(LOG_INFO);
-
-#ifndef OPENSSL_1_1_API
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_TOO_LARGE),
-                        LOG_WARN, 0, NULL);
-  expect_log_severity(LOG_INFO);
-#endif /* !defined(OPENSSL_1_1_API) */
 
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNKNOWN_PROTOCOL),
-                        LOG_WARN, 0, NULL);
-  expect_log_severity(LOG_INFO);
-
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNSUPPORTED_PROTOCOL),
-                        LOG_WARN, 0, NULL);
-  expect_log_severity(LOG_INFO);
-
-  tls->ssl = SSL_new(ctx);
-
-  mock_clean_saved_logs();
-  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
-  expect_log_msg("TLS error with 127.hello: (null)"
-            " (in (null):(null):" SSL_STATE_STR ")\n");
+  tls->wantwrite_n = 43;
+  ret = tor_tls_get_forced_write_size(tls);
+  tt_int_op(ret, OP_EQ, 43);
 
  done:
-  teardown_capture_of_logs();
-  SSL_free(ssl);
-  SSL_CTX_free(ctx);
-  if (tls && tls->ssl)
-    SSL_free(tls->ssl);
-  if (tls)
-    tor_free(tls->address);
   tor_free(tls);
 }
 
-#ifndef OPENSSL_OPAQUE
 static void
-test_tortls_get_error(void *ignored)
+test_tortls_used_v1_handshake(void *ignored)
 {
   (void)ignored;
-  tor_tls_t *tls;
   int ret;
-  SSL_CTX *ctx;
-
-  library_init();
-
-  ctx = SSL_CTX_new(SSLv23_method());
-  setup_capture_of_logs(LOG_INFO);
+  tor_tls_t *tls;
   tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = SSL_new(ctx);
-  SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL);
 
-  ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_IO);
-  expect_log_msg("TLS error: unexpected close while"
-            " something (before/accept initialization)\n");
+  // These tests assume both V2 handshake server and client are enabled
+  tls->wasV2Handshake = 0;
+  ret = tor_tls_used_v1_handshake(tls);
+  tt_int_op(ret, OP_EQ, 1);
 
-  mock_clean_saved_logs();
-  ret = tor_tls_get_error(tls, 2, 0, "something", LOG_WARN, 0);
+  tls->wasV2Handshake = 1;
+  ret = tor_tls_used_v1_handshake(tls);
   tt_int_op(ret, OP_EQ, 0);
-  expect_no_log_entry();
-
-  mock_clean_saved_logs();
-  ret = tor_tls_get_error(tls, 0, 1, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, -11);
-  expect_no_log_entry();
-
-  mock_clean_saved_logs();
-  ERR_clear_error();
-  ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99);
-  ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
-  expect_log_msg("TLS error while something: (null)"
-            " (in bignum routines:(null):before/accept initialization)\n");
-
-  mock_clean_saved_logs();
-  ERR_clear_error();
-  tls->ssl->rwstate = SSL_READING;
-  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_READ;
-  ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, TOR_TLS_WANTREAD);
-  expect_no_log_entry();
-
-  mock_clean_saved_logs();
-  ERR_clear_error();
-  tls->ssl->rwstate = SSL_READING;
-  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_WRITE;
-  ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, TOR_TLS_WANTWRITE);
-  expect_no_log_entry();
-
-  mock_clean_saved_logs();
-  ERR_clear_error();
-  tls->ssl->rwstate = 0;
-  tls->ssl->shutdown = SSL_RECEIVED_SHUTDOWN;
-  tls->ssl->s3->warn_alert =SSL_AD_CLOSE_NOTIFY;
-  ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, TOR_TLS_CLOSE);
-  expect_log_entry();
-
-  mock_clean_saved_logs();
-  ret = tor_tls_get_error(tls, 0, 2, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, -10);
-  expect_no_log_entry();
-
-  mock_clean_saved_logs();
-  ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99);
-  ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0);
-  tt_int_op(ret, OP_EQ, -9);
-  expect_log_msg("TLS error while something: (null) (in system library:"
-            "connect:before/accept initialization)\n");
 
  done:
-  teardown_capture_of_logs();
-  SSL_free(tls->ssl);
   tor_free(tls);
-  SSL_CTX_free(ctx);
 }
-#endif /* !defined(OPENSSL_OPAQUE) */
 
 static void
-test_tortls_always_accept_verify_cb(void *ignored)
+test_tortls_get_num_server_handshakes(void *ignored)
 {
   (void)ignored;
   int ret;
+  tor_tls_t *tls;
 
-  ret = always_accept_verify_cb(0, NULL);
-  tt_int_op(ret, OP_EQ, 1);
-
- done:
-  (void)0;
-}
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_x509_cert_free(void *ignored)
-{
-  (void)ignored;
-  tor_x509_cert_t *cert;
-
-  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  tor_x509_cert_free(cert);
-
-  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  cert->cert = X509_new();
-  cert->encoded = tor_malloc_zero(1);
-  tor_x509_cert_free(cert);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static void
-test_tortls_x509_cert_get_id_digests(void *ignored)
-{
-  (void)ignored;
-  tor_x509_cert_t *cert;
-  common_digests_t *d;
-  const common_digests_t *res;
-  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  d = tor_malloc_zero(sizeof(common_digests_t));
-  d->d[0][0] = 42;
-
-  res = tor_x509_cert_get_id_digests(cert);
-  tt_assert(!res);
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
 
-  cert->pkey_digests_set = 1;
-  cert->pkey_digests = *d;
-  res = tor_x509_cert_get_id_digests(cert);
-  tt_int_op(res->d[0][0], OP_EQ, 42);
+  tls->server_handshake_count = 3;
+  ret = tor_tls_get_num_server_handshakes(tls);
+  tt_int_op(ret, OP_EQ, 3);
 
  done:
-  tor_free(cert);
-  tor_free(d);
-}
-
-#ifndef OPENSSL_OPAQUE
-static int
-fixed_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
-{
-  (void) a; (void) b;
-  return 1;
-}
-
-/*
- * Use only for the matching fake_x509_free() call
- */
-static X509 *
-fake_x509_malloc(void)
-{
-  return tor_malloc_zero(sizeof(X509));
-}
-
-static void
-fake_x509_free(X509 *cert)
-{
-  if (cert) {
-    if (cert->cert_info) {
-      if (cert->cert_info->key) {
-        if (cert->cert_info->key->pkey) {
-          tor_free(cert->cert_info->key->pkey);
-        }
-        tor_free(cert->cert_info->key);
-      }
-      tor_free(cert->cert_info);
-    }
-    tor_free(cert);
-  }
+  tor_free(tls);
 }
 
 static void
-test_tortls_cert_matches_key(void *ignored)
+test_tortls_server_got_renegotiate(void *ignored)
 {
   (void)ignored;
-  int res;
+  int ret;
   tor_tls_t *tls;
-  tor_x509_cert_t *cert;
-  X509 *one = NULL, *two = NULL;
-  EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_new(999, 0, NULL, NULL);
-  EVP_PKEY_asn1_set_public(meth, NULL, NULL, fixed_pub_cmp, NULL, NULL, NULL);
 
   tls = tor_malloc_zero(sizeof(tor_tls_t));
-  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  one = fake_x509_malloc();
-  one->references = 1;
-  two = fake_x509_malloc();
-  two->references = 1;
-
-  res = tor_tls_cert_matches_key(tls, cert);
-  tt_int_op(res, OP_EQ, 0);
-
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
-  tls->ssl->session->peer = one;
-  res = tor_tls_cert_matches_key(tls, cert);
-  tt_int_op(res, OP_EQ, 0);
-
-  cert->cert = two;
-  res = tor_tls_cert_matches_key(tls, cert);
-  tt_int_op(res, OP_EQ, 0);
-
-  one->cert_info = tor_malloc_zero(sizeof(X509_CINF));
-  one->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
-  one->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
-  one->cert_info->key->pkey->references = 1;
-  one->cert_info->key->pkey->ameth = meth;
-  one->cert_info->key->pkey->type = 1;
-
-  two->cert_info = tor_malloc_zero(sizeof(X509_CINF));
-  two->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
-  two->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
-  two->cert_info->key->pkey->references = 1;
-  two->cert_info->key->pkey->ameth = meth;
-  two->cert_info->key->pkey->type = 2;
-
-  res = tor_tls_cert_matches_key(tls, cert);
-  tt_int_op(res, OP_EQ, 0);
 
-  one->cert_info->key->pkey->type = 1;
-  two->cert_info->key->pkey->type = 1;
-  res = tor_tls_cert_matches_key(tls, cert);
-  tt_int_op(res, OP_EQ, 1);
+  tls->got_renegotiate = 1;
+  ret = tor_tls_server_got_renegotiate(tls);
+  tt_int_op(ret, OP_EQ, 1);
 
  done:
-  EVP_PKEY_asn1_free(meth);
-  tor_free(tls->ssl->session);
-  tor_free(tls->ssl);
   tor_free(tls);
-  tor_free(cert);
-  fake_x509_free(one);
-  fake_x509_free(two);
 }
 
 static void
-test_tortls_cert_get_key(void *ignored)
+test_tortls_evaluate_ecgroup_for_tls(void *ignored)
 {
   (void)ignored;
-  tor_x509_cert_t *cert = NULL;
-  crypto_pk_t *res = NULL;
-  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  X509 *key = NULL;
-  key = fake_x509_malloc();
-  key->references = 1;
-
-  res = tor_tls_cert_get_key(cert);
-  tt_assert(!res);
-
-  cert->cert = key;
-  key->cert_info = tor_malloc_zero(sizeof(X509_CINF));
-  key->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
-  key->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
-  key->cert_info->key->pkey->references = 1;
-  key->cert_info->key->pkey->type = 2;
-  res = tor_tls_cert_get_key(cert);
-  tt_assert(!res);
-
- done:
-  fake_x509_free(key);
-  tor_free(cert);
-  crypto_pk_free(res);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
+  int ret;
 
-static void
-test_tortls_get_my_client_auth_key(void *ignored)
-{
-  (void)ignored;
-  crypto_pk_t *ret;
-  crypto_pk_t *expected;
-  tor_tls_context_t *ctx;
-  RSA *k = RSA_new();
+  ret = evaluate_ecgroup_for_tls(NULL);
+  tt_int_op(ret, OP_EQ, 1);
 
-  ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
-  expected = crypto_new_pk_from_openssl_rsa_(k);
-  ctx->auth_key = expected;
+  ret = evaluate_ecgroup_for_tls("foobar");
+  tt_int_op(ret, OP_EQ, 0);
 
-  client_tls_context = NULL;
-  ret = tor_tls_get_my_client_auth_key();
-  tt_assert(!ret);
+  ret = evaluate_ecgroup_for_tls("P256");
+  tt_int_op(ret, OP_EQ, 1);
 
-  client_tls_context = ctx;
-  ret = tor_tls_get_my_client_auth_key();
-  tt_assert(ret == expected);
+  ret = evaluate_ecgroup_for_tls("P224");
+  //  tt_int_op(ret, OP_EQ, 1); This varies between machines
+  tt_assert(ret == 0 || ret == 1);
 
  done:
-  tor_free(expected);
-  tor_free(ctx);
+  (void)0;
 }
 
-static void
-test_tortls_get_my_certs(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_context_t *ctx;
-  const tor_x509_cert_t *link_cert_out = NULL;
-  const tor_x509_cert_t *id_cert_out = NULL;
-
-  ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
-
-  client_tls_context = NULL;
-  ret = tor_tls_get_my_certs(0, NULL, NULL);
-  tt_int_op(ret, OP_EQ, -1);
-
-  server_tls_context = NULL;
-  ret = tor_tls_get_my_certs(1, NULL, NULL);
-  tt_int_op(ret, OP_EQ, -1);
-
-  client_tls_context = ctx;
-  ret = tor_tls_get_my_certs(0, NULL, NULL);
-  tt_int_op(ret, OP_EQ, 0);
-
-  client_tls_context = ctx;
-  ret = tor_tls_get_my_certs(0, &link_cert_out, &id_cert_out);
-  tt_int_op(ret, OP_EQ, 0);
-
-  server_tls_context = ctx;
-  ret = tor_tls_get_my_certs(1, &link_cert_out, &id_cert_out);
-  tt_int_op(ret, OP_EQ, 0);
-
- done:
-  (void)1;
-}
-
-#ifndef HAVE_SSL_GET_CLIENT_CIPHERS
-static SSL_CIPHER *
-get_cipher_by_name(const char *name)
-{
-  int i;
-  const SSL_METHOD *method = SSLv23_method();
-  int num = method->num_ciphers();
-
-  for (i = 0; i < num; ++i) {
-    const SSL_CIPHER *cipher = method->get_cipher(i);
-    const char *ciphername = SSL_CIPHER_get_name(cipher);
-    if (!strcmp(ciphername, name)) {
-      return (SSL_CIPHER *)cipher;
-    }
-  }
-
-  return NULL;
-}
-#endif /* !defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_get_ciphersuite_name(void *ignored)
-{
-  (void)ignored;
-  const char *ret;
-  tor_tls_t *ctx;
-  ctx = tor_malloc_zero(sizeof(tor_tls_t));
-  ctx->ssl = tor_malloc_zero(sizeof(SSL));
-
-  ret = tor_tls_get_ciphersuite_name(ctx);
-  tt_str_op(ret, OP_EQ, "(NONE)");
-
- done:
-  tor_free(ctx->ssl);
-  tor_free(ctx);
-}
-
-static SSL_CIPHER *
-get_cipher_by_id(uint16_t id)
-{
-  int i;
-  const SSL_METHOD *method = SSLv23_method();
-  int num = method->num_ciphers();
-  for (i = 0; i < num; ++i) {
-    const SSL_CIPHER *cipher = method->get_cipher(i);
-    if (id == (SSL_CIPHER_get_id(cipher) & 0xffff)) {
-      return (SSL_CIPHER *)cipher;
-    }
-  }
-
-  return NULL;
-}
-
-static void
-test_tortls_classify_client_ciphers(void *ignored)
-{
-  (void)ignored;
-  int i;
-  int ret;
-  SSL_CTX *ctx;
-  SSL *ssl;
-  tor_tls_t *tls;
-  STACK_OF(SSL_CIPHER) *ciphers;
-  SSL_CIPHER *tmp_cipher;
-
-  library_init();
-
-  tor_tls_allocate_tor_tls_object_ex_data_index();
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->magic = TOR_TLS_MAGIC;
-
-  ctx = SSL_CTX_new(TLSv1_method());
-  ssl = SSL_new(ctx);
-  tls->ssl = ssl;
-
-  ciphers = sk_SSL_CIPHER_new_null();
-
-  ret = tor_tls_classify_client_ciphers(ssl, NULL);
-  tt_int_op(ret, OP_EQ, -1);
-
-  SSL_set_ex_data(ssl, tor_tls_object_ex_data_index, tls);
-  tls->client_cipher_list_type = 42;
-
-  ret = tor_tls_classify_client_ciphers(ssl, NULL);
-  tt_int_op(ret, OP_EQ, 42);
-
-  tls->client_cipher_list_type = 0;
-  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
-  tt_int_op(ret, OP_EQ, 1);
-  tt_int_op(tls->client_cipher_list_type, OP_EQ, 1);
-
-  tls->client_cipher_list_type = 0;
-  ret = tor_tls_classify_client_ciphers(ssl, SSL_get_ciphers(ssl));
-  tt_int_op(ret, OP_EQ, 3);
-  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
-
-  SSL_CIPHER *one = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_128_SHA),
-    *two = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA),
-    *three = get_cipher_by_name(SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA),
-    *four = NULL;
-  sk_SSL_CIPHER_push(ciphers, one);
-  sk_SSL_CIPHER_push(ciphers, two);
-  sk_SSL_CIPHER_push(ciphers, three);
-  sk_SSL_CIPHER_push(ciphers, four);
-
-  tls->client_cipher_list_type = 0;
-  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
-  tt_int_op(ret, OP_EQ, 1);
-  tt_int_op(tls->client_cipher_list_type, OP_EQ, 1);
-
-  sk_SSL_CIPHER_zero(ciphers);
-
-  one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
-  tt_assert(one);
-  one->id = 0x00ff;
-  two = get_cipher_by_name("ECDHE-RSA-AES128-GCM-SHA256");
-  tt_assert(two);
-  two->id = 0x0000;
-  sk_SSL_CIPHER_push(ciphers, one);
-  tls->client_cipher_list_type = 0;
-  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
-  tt_int_op(ret, OP_EQ, 3);
-  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
-
-  sk_SSL_CIPHER_push(ciphers, two);
-  tls->client_cipher_list_type = 0;
-  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
-  tt_int_op(ret, OP_EQ, 3);
-  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
-
-  one->id = 0xC00A;
-  tls->client_cipher_list_type = 0;
-  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
-  tt_int_op(ret, OP_EQ, 3);
-  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
-
-  sk_SSL_CIPHER_zero(ciphers);
-  for (i=0; v2_cipher_list[i]; i++) {
-    tmp_cipher = get_cipher_by_id(v2_cipher_list[i]);
-    tt_assert(tmp_cipher);
-    sk_SSL_CIPHER_push(ciphers, tmp_cipher);
-  }
-  tls->client_cipher_list_type = 0;
-  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
-  tt_int_op(ret, OP_EQ, 2);
-  tt_int_op(tls->client_cipher_list_type, OP_EQ, 2);
-
- done:
-  sk_SSL_CIPHER_free(ciphers);
-  SSL_free(tls->ssl);
-  tor_free(tls);
-  SSL_CTX_free(ctx);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static void
-test_tortls_client_is_using_v2_ciphers(void *ignored)
-{
-  (void)ignored;
-
-#ifdef HAVE_SSL_GET_CLIENT_CIPHERS
-  tt_skip();
- done:
-  (void)1;
-#else
-  int ret;
-  SSL_CTX *ctx;
-  SSL *ssl;
-  SSL_SESSION *sess;
-  STACK_OF(SSL_CIPHER) *ciphers;
-
-  library_init();
-
-  ctx = SSL_CTX_new(TLSv1_method());
-  ssl = SSL_new(ctx);
-  sess = SSL_SESSION_new();
-
-  ret = tor_tls_client_is_using_v2_ciphers(ssl);
-  tt_int_op(ret, OP_EQ, -1);
-
-  ssl->session = sess;
-  ret = tor_tls_client_is_using_v2_ciphers(ssl);
-  tt_int_op(ret, OP_EQ, 0);
-
-  ciphers = sk_SSL_CIPHER_new_null();
-  SSL_CIPHER *one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
-  tt_assert(one);
-  one->id = 0x00ff;
-  sk_SSL_CIPHER_push(ciphers, one);
-  sess->ciphers = ciphers;
-  ret = tor_tls_client_is_using_v2_ciphers(ssl);
-  tt_int_op(ret, OP_EQ, 1);
- done:
-  SSL_free(ssl);
-  SSL_CTX_free(ctx);
-#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
-}
-
-#ifndef OPENSSL_OPAQUE
-static X509 *fixed_try_to_extract_certs_from_tls_cert_out_result = NULL;
-static X509 *fixed_try_to_extract_certs_from_tls_id_cert_out_result = NULL;
-
-static void
-fixed_try_to_extract_certs_from_tls(int severity, tor_tls_t *tls,
-                                    X509 **cert_out, X509 **id_cert_out)
-{
-  (void) severity;
-  (void) tls;
-  *cert_out = fixed_try_to_extract_certs_from_tls_cert_out_result;
-  *id_cert_out = fixed_try_to_extract_certs_from_tls_id_cert_out_result;
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static const char* notCompletelyValidCertString =
-  "-----BEGIN CERTIFICATE-----\n"
-  "MIICVjCCAb8CAg37MA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG\n"
-  "A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE\n"
-  "MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl\n"
-  "YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw\n"
-  "ODIyMDUyNzIzWhcNMTcwODIxMDUyNzIzWjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE\n"
-  "CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs\n"
-  "ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYBBrx5PlP0WNI/ZdzD\n"
-  "+6Pktmurn+F2kQYbtc7XQh8/LTBvCo+P6iZoLEmUA9e7EXLRxgU1CVqeAi7QcAn9\n"
-  "MwBlc8ksFJHB0rtf9pmf8Oza9E0Bynlq/4/Kb1x+d+AyhL7oK9tQwB24uHOueHi1\n"
-  "C/iVv8CSWKiYe6hzN1txYe8rAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAASPdjigJ\n"
-  "kXCqKWpnZ/Oc75EUcMi6HztaW8abUMlYXPIgkV2F7YanHOB7K4f7OOLjiz8DTPFf\n"
-  "jC9UeuErhaA/zzWi8ewMTFZW/WshOrm3fNvcMrMLKtH534JKvcdMg6qIdjTFINIr\n"
-  "evnAhf0cwULaebn+lMs8Pdl7y37+sfluVok=\n"
-  "-----END CERTIFICATE-----\n";
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static const char* validCertString = "-----BEGIN CERTIFICATE-----\n"
-  "MIIDpTCCAY0CAg3+MA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMREwDwYD\n"
-  "VQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIGA1UECgwLVG9yIFRl\n"
-  "c3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkwNjEzMzk1OVoXDTQz\n"
-  "MDEyMjEzMzk1OVowVjELMAkGA1UEBhMCVVMxEDAOBgNVBAcMB0NoaWNhZ28xFDAS\n"
-  "BgNVBAoMC1RvciBUZXN0aW5nMR8wHQYDVQQDDBZ0ZXN0aW5nLnRvcnByb2plY3Qu\n"
-  "b3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoT6uyVVhWyOF3wkHjjYbd\n"
-  "nKaykyRv4JVtKQdZ4OpEErmX1zw4MmyzpQNV6iR4bQnWiyLfzyVJMZDIC/WILBfX\n"
-  "w2Pza/yuLgUvDc3twMuhOACzOQVO8PrEF/aVv2+hbCCy2udXvKhnYn+CCXl3ozc8\n"
-  "XcKYvujTXDyvGWY3xwAjlQIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQCUvnhzQWuQ\n"
-  "MrN+pERkE+zcTI/9dGS90rUMMLgu8VDNqTa0TUQh8uO0EQ6uDvI8Js6e8tgwS0BR\n"
-  "UBahqb7ZHv+rejGCBr5OudqD+x4STiiuPNJVs86JTLN8SpM9CHjIBH5WCCN2KOy3\n"
-  "mevNoRcRRyYJzSFULCunIK6FGulszigMYGscrO4oiTkZiHPh9KvWT40IMiHfL+Lw\n"
-  "EtEWiLex6064LcA2YQ1AMuSZyCexks63lcfaFmQbkYOKqXa1oLkIRuDsOaSVjTfe\n"
-  "vec+X6jvf12cFTKS5WIeqkKF2Irt+dJoiHEGTe5RscUMN/f+gqHPzfFz5dR23sxo\n"
-  "g+HC6MZHlFkLAOx3wW6epPS8A/m1mw3zMPoTnb2U2YYt8T0dJMMlUn/7Y1sEAa+a\n"
-  "dSTMaeUf6VnJ//11m454EZl1to9Z7oJOgqmFffSrdD4BGIWe8f7hhW6L1Enmqe/J\n"
-  "BKL3wbzZh80O1W0bndAwhnEEhlzneFY84cbBo9pmVxpODHkUcStpr5Z7pBDrcL21\n"
-  "Ss/aB/1YrsVXhdvJdOGxl3Mnl9dUY57CympLGlT8f0pPS6GAKOelECOhFMHmJd8L\n"
-  "dj3XQSmKtYHevZ6IvuMXSlB/fJvSjSlkCuLo5+kJoaqPuRu+i/S1qxeRy3CBwmnE\n"
-  "LdSNdcX4N79GQJ996PA8+mUCQG7YRtK+WA==\n"
-  "-----END CERTIFICATE-----\n";
-
-static const char* caCertString = "-----BEGIN CERTIFICATE-----\n"
-  "MIIFjzCCA3egAwIBAgIJAKd5WgyfPMYRMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV\n"
-  "BAYTAlVTMREwDwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIG\n"
-  "A1UECgwLVG9yIFRlc3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkw\n"
-  "NjEzMzc0MVoXDTQzMDEyMjEzMzc0MVowXjELMAkGA1UEBhMCVVMxETAPBgNVBAgM\n"
-  "CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRQwEgYDVQQKDAtUb3IgVGVzdGlu\n"
-  "ZzEUMBIGA1UEAwwLVG9yIFRlc3RpbmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n"
-  "ggIKAoICAQCpLMUEiLW5leUgBZoEJms2V7lZRhIAjnJBhVMHD0e3UubNknmaQoxf\n"
-  "ARz3rvqOaRd0JlV+qM9qE0DjiYcCVP1cAfqAo9d83uS1vwY3YMVJzADlaIiHfyVW\n"
-  "uEgBy0vvkeUBqaua24dYlcwsemOiXYLu41yM1wkcGHW1AhBNHppY6cznb8TyLgNM\n"
-  "2x3SGUdzc5XMyAFx51faKGBA3wjs+Hg1PLY7d30nmCgEOBavpm5I1disM/0k+Mcy\n"
-  "YmAKEo/iHJX/rQzO4b9znP69juLlR8PDBUJEVIG/CYb6+uw8MjjUyiWXYoqfVmN2\n"
-  "hm/lH8b6rXw1a2Aa3VTeD0DxaWeacMYHY/i01fd5n7hCoDTRNdSw5KJ0L3Z0SKTu\n"
-  "0lzffKzDaIfyZGlpW5qdouACkWYzsaitQOePVE01PIdO30vUfzNTFDfy42ccx3Di\n"
-  "59UCu+IXB+eMtrBfsok0Qc63vtF1linJgjHW1z/8ujk8F7/qkOfODhk4l7wngc2A\n"
-  "EmwWFIFoGaiTEZHB9qteXr4unbXZ0AHpM02uGGwZEGohjFyebEb73M+J57WKKAFb\n"
-  "PqbLcGUksL1SHNBNAJcVLttX55sO4nbidOS/kA3m+F1R04MBTyQF9qA6YDDHqdI3\n"
-  "h/3pw0Z4fxVouTYT4/NfRnX4JTP4u+7Mpcoof28VME0qWqD1LnRhFQIDAQABo1Aw\n"
-  "TjAdBgNVHQ4EFgQUMoAgIXH7pZ3QMRwTjT+DM9Yo/v0wHwYDVR0jBBgwFoAUMoAg\n"
-  "IXH7pZ3QMRwTjT+DM9Yo/v0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
-  "AgEAUJxacjXR9sT+Xs6ISFiUsyd0T6WVKMnV46xrYJHirGfx+krWHrjxMY+ZtxYD\n"
-  "DBDGlo11Qc4v6QrclNf5QUBfIiGQsP9Cm6hHcQ+Tpg9HHCgSqG1YNPwCPReCR4br\n"
-  "BLvLfrfkcBL2IWM0PdQdCze+59DBfipsULD2mEn9fjYRXQEwb2QWtQ9qRc20Yb/x\n"
-  "Q4b/+CvUodLkaq7B8MHz0BV8HHcBoph6DYaRmO/N+hPauIuSp6XyaGYcEefGKVKj\n"
-  "G2+fcsdyXsoijNdL8vNKwm4j2gVwCBnw16J00yfFoV46YcbfqEdJB2je0XSvwXqt\n"
-  "14AOTngxso2h9k9HLtrfpO1ZG/B5AcCMs1lzbZ2fp5DPHtjvvmvA2RJqgo3yjw4W\n"
-  "4DHAuTglYFlC3mDHNfNtcGP20JvepcQNzNP2UzwcpOc94hfKikOFw+gf9Vf1qd0y\n"
-  "h/Sk6OZHn2+JVUPiWHIQV98Vtoh4RmUZDJD+b55ia3fQGTGzt4z1XFzQYSva5sfs\n"
-  "wocS/papthqWldQU7x+3wofNd5CNU1x6WKXG/yw30IT/4F8ADJD6GeygNT8QJYvt\n"
-  "u/8lAkbOy6B9xGmSvr0Kk1oq9P2NshA6kalxp1Oz/DTNDdL4AeBXV3JmM6WWCjGn\n"
-  "Yy1RT69d0rwYc5u/vnqODz1IjvT90smsrkBumGt791FAFeg=\n"
-  "-----END CERTIFICATE-----\n";
-
-static X509 *
-read_cert_from(const char *str)
-{
-  BIO *bio = BIO_new(BIO_s_mem());
-  BIO_write(bio, str, (int) strlen(str));
-  X509 *res = PEM_read_bio_X509(bio, NULL, NULL, NULL);
-  BIO_free(bio);
-  return res;
-}
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_verify(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  crypto_pk_t *k = NULL;
-  X509 *cert1 = NULL, *cert2 = NULL, *invalidCert = NULL,
-    *validCert = NULL, *caCert = NULL;
-
-  cert1 = tor_malloc_zero(sizeof(X509));
-  cert1->references = 10;
-
-  cert2 = tor_malloc_zero(sizeof(X509));
-  cert2->references = 10;
-
-  validCert = read_cert_from(validCertString);
-  caCert = read_cert_from(caCertString);
-  invalidCert = read_cert_from(notCompletelyValidCertString);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  ret = tor_tls_verify(LOG_WARN, tls, &k);
-  tt_int_op(ret, OP_EQ, -1);
-
-  MOCK(try_to_extract_certs_from_tls, fixed_try_to_extract_certs_from_tls);
-
-  fixed_try_to_extract_certs_from_tls_cert_out_result = cert1;
-  ret = tor_tls_verify(LOG_WARN, tls, &k);
-  tt_int_op(ret, OP_EQ, -1);
-
-  fixed_try_to_extract_certs_from_tls_id_cert_out_result = cert2;
-  ret = tor_tls_verify(LOG_WARN, tls, &k);
-  tt_int_op(ret, OP_EQ, -1);
-
-  fixed_try_to_extract_certs_from_tls_cert_out_result = invalidCert;
-  fixed_try_to_extract_certs_from_tls_id_cert_out_result = invalidCert;
-
-  ret = tor_tls_verify(LOG_WARN, tls, &k);
-  tt_int_op(ret, OP_EQ, -1);
-
-  fixed_try_to_extract_certs_from_tls_cert_out_result = validCert;
-  fixed_try_to_extract_certs_from_tls_id_cert_out_result = caCert;
-
-  ret = tor_tls_verify(LOG_WARN, tls, &k);
-  tt_int_op(ret, OP_EQ, 0);
-  tt_assert(k);
-
- done:
-  UNMOCK(try_to_extract_certs_from_tls);
-  tor_free(cert1);
-  tor_free(cert2);
-  tor_free(tls);
-  tor_free(k);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_check_lifetime(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  X509 *validCert = read_cert_from(validCertString);
-  time_t now = time(NULL);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
-  tt_int_op(ret, OP_EQ, -1);
-
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
-  tls->ssl->session->peer = validCert;
-  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
-  tt_int_op(ret, OP_EQ, 0);
-
-  ASN1_STRING_free(validCert->cert_info->validity->notBefore);
-  validCert->cert_info->validity->notBefore = ASN1_TIME_set(NULL, now-10);
-  ASN1_STRING_free(validCert->cert_info->validity->notAfter);
-  validCert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, now+60);
-
-  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, -1000);
-  tt_int_op(ret, OP_EQ, -1);
-
-  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), -1000, 0);
-  tt_int_op(ret, OP_EQ, -1);
-
- done:
-  tor_free(tls->ssl->session);
-  tor_free(tls->ssl);
-  tor_free(tls);
-  X509_free(validCert);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static int fixed_ssl_pending_result = 0;
-
-static int
-fixed_ssl_pending(const SSL *ignored)
-{
-  (void)ignored;
-  return fixed_ssl_pending_result;
-}
-
-static void
-test_tortls_get_pending_bytes(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  SSL_METHOD *method;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  method = tor_malloc_zero(sizeof(SSL_METHOD));
-  method->ssl_pending = fixed_ssl_pending;
-  tls->ssl->method = method;
-
-  fixed_ssl_pending_result = 42;
-  ret = tor_tls_get_pending_bytes(tls);
-  tt_int_op(ret, OP_EQ, 42);
-
- done:
-  tor_free(method);
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static void
-test_tortls_get_forced_write_size(void *ignored)
-{
-  (void)ignored;
-  long ret;
-  tor_tls_t *tls;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-
-  tls->wantwrite_n = 43;
-  ret = tor_tls_get_forced_write_size(tls);
-  tt_int_op(ret, OP_EQ, 43);
-
- done:
-  tor_free(tls);
-}
-
-static void
-test_tortls_get_write_overhead_ratio(void *ignored)
-{
-  (void)ignored;
-  double ret;
-
-  total_bytes_written_over_tls = 0;
-  ret = tls_get_write_overhead_ratio();
-  tt_double_op(fabs(ret - 1.0), OP_LT, 1E-12);
-
-  total_bytes_written_by_tls = 10;
-  total_bytes_written_over_tls = 1;
-  ret = tls_get_write_overhead_ratio();
-  tt_double_op(fabs(ret - 10.0), OP_LT, 1E-12);
-
-  total_bytes_written_by_tls = 10;
-  total_bytes_written_over_tls = 2;
-  ret = tls_get_write_overhead_ratio();
-  tt_double_op(fabs(ret - 5.0), OP_LT, 1E-12);
-
- done:
-  (void)0;
-}
-
-static void
-test_tortls_used_v1_handshake(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-
-  // These tests assume both V2 handshake server and client are enabled
-  tls->wasV2Handshake = 0;
-  ret = tor_tls_used_v1_handshake(tls);
-  tt_int_op(ret, OP_EQ, 1);
-
-  tls->wasV2Handshake = 1;
-  ret = tor_tls_used_v1_handshake(tls);
-  tt_int_op(ret, OP_EQ, 0);
-
- done:
-  tor_free(tls);
-}
-
-static void
-test_tortls_get_num_server_handshakes(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-
-  tls->server_handshake_count = 3;
-  ret = tor_tls_get_num_server_handshakes(tls);
-  tt_int_op(ret, OP_EQ, 3);
-
- done:
-  tor_free(tls);
-}
-
-static void
-test_tortls_server_got_renegotiate(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-
-  tls->got_renegotiate = 1;
-  ret = tor_tls_server_got_renegotiate(tls);
-  tt_int_op(ret, OP_EQ, 1);
-
- done:
-  tor_free(tls);
-}
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_SSL_SESSION_get_master_key(void *ignored)
-{
-  (void)ignored;
-  size_t ret;
-  tor_tls_t *tls;
-  uint8_t *out;
-  out = tor_malloc_zero(1);
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
-  tls->ssl->session->master_key_length = 1;
-
-#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
-  tls->ssl->session->master_key[0] = 43;
-  ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 0);
-  tt_int_op(ret, OP_EQ, 1);
-  tt_int_op(out[0], OP_EQ, 0);
-
-  ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 1);
-  tt_int_op(ret, OP_EQ, 1);
-  tt_int_op(out[0], OP_EQ, 43);
-
- done:
-#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */
-  tor_free(tls->ssl->session);
-  tor_free(tls->ssl);
-  tor_free(tls);
-  tor_free(out);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_get_tlssecrets(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  uint8_t *secret_out = tor_malloc_zero(DIGEST256_LEN);
-  tor_tls_t *tls;
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
-  tls->ssl->session->master_key_length = 1;
-  tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE));
-
-  ret = tor_tls_get_tlssecrets(tls, secret_out);
-  tt_int_op(ret, OP_EQ, 0);
-
- done:
-  tor_free(secret_out);
-  tor_free(tls->ssl->s3);
-  tor_free(tls->ssl->session);
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_get_buffer_sizes(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  size_t rbuf_c=-1, rbuf_b=-1, wbuf_c=-1, wbuf_b=-1;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE));
-
-  tls->ssl->s3->rbuf.buf = NULL;
-  tls->ssl->s3->rbuf.len = 1;
-  tls->ssl->s3->rbuf.offset = 0;
-  tls->ssl->s3->rbuf.left = 42;
-
-  tls->ssl->s3->wbuf.buf = NULL;
-  tls->ssl->s3->wbuf.len = 2;
-  tls->ssl->s3->wbuf.offset = 0;
-  tls->ssl->s3->wbuf.left = 43;
-
-  ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b);
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
-  tt_int_op(ret, OP_EQ, -1);
-#else
-  tt_int_op(ret, OP_EQ, 0);
-  tt_int_op(rbuf_c, OP_EQ, 0);
-  tt_int_op(wbuf_c, OP_EQ, 0);
-  tt_int_op(rbuf_b, OP_EQ, 42);
-  tt_int_op(wbuf_b, OP_EQ, 43);
-
-  tls->ssl->s3->rbuf.buf = tor_malloc_zero(1);
-  tls->ssl->s3->wbuf.buf = tor_malloc_zero(1);
-  ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b);
-  tt_int_op(ret, OP_EQ, 0);
-  tt_int_op(rbuf_c, OP_EQ, 1);
-  tt_int_op(wbuf_c, OP_EQ, 2);
-
-#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
-
- done:
-  tor_free(tls->ssl->s3->rbuf.buf);
-  tor_free(tls->ssl->s3->wbuf.buf);
-  tor_free(tls->ssl->s3);
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static void
-test_tortls_evaluate_ecgroup_for_tls(void *ignored)
-{
-  (void)ignored;
-  int ret;
-
-  ret = evaluate_ecgroup_for_tls(NULL);
-  tt_int_op(ret, OP_EQ, 1);
-
-  ret = evaluate_ecgroup_for_tls("foobar");
-  tt_int_op(ret, OP_EQ, 0);
-
-  ret = evaluate_ecgroup_for_tls("P256");
-  tt_int_op(ret, OP_EQ, 1);
-
-  ret = evaluate_ecgroup_for_tls("P224");
-  //  tt_int_op(ret, OP_EQ, 1); This varies between machines
-  tt_assert(ret == 0 || ret == 1);
-
- done:
-  (void)0;
-}
-
-#ifndef OPENSSL_OPAQUE
-typedef struct cert_pkey_st_local
-{
-  X509 *x509;
-  EVP_PKEY *privatekey;
-  const EVP_MD *digest;
-} CERT_PKEY_local;
-
-typedef struct sess_cert_st_local
-{
-  STACK_OF(X509) *cert_chain;
-  int peer_cert_type;
-  CERT_PKEY_local *peer_key;
-  CERT_PKEY_local peer_pkeys[8];
-  int references;
-} SESS_CERT_local;
-
-static void
-test_tortls_try_to_extract_certs_from_tls(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-  X509 *cert = NULL, *id_cert = NULL, *c1 = NULL, *c2 = NULL;
-  SESS_CERT_local *sess = NULL;
-
-  c1 = read_cert_from(validCertString);
-  c2 = read_cert_from(caCertString);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
-  sess = tor_malloc_zero(sizeof(SESS_CERT_local));
-  tls->ssl->session->sess_cert = (void *)sess;
-
-  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
-  tt_assert(!cert);
-  tt_assert(!id_cert);
-
-  tls->ssl->session->peer = c1;
-  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
-  tt_assert(cert == c1);
-  tt_assert(!id_cert);
-  X509_free(cert); /* decrease refcnt */
-
-  sess->cert_chain = sk_X509_new_null();
-  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
-  tt_assert(cert == c1);
-  tt_assert(!id_cert);
-  X509_free(cert); /* decrease refcnt */
-
-  sk_X509_push(sess->cert_chain, c1);
-  sk_X509_push(sess->cert_chain, c2);
-
-  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
-  tt_assert(cert == c1);
-  tt_assert(id_cert);
-  X509_free(cert); /* decrease refcnt */
-
- done:
-  sk_X509_free(sess->cert_chain);
-  tor_free(sess);
-  tor_free(tls->ssl->session);
-  tor_free(tls->ssl);
-  tor_free(tls);
-  X509_free(c1);
-  X509_free(c2);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_get_peer_cert(void *ignored)
-{
-  (void)ignored;
-  tor_x509_cert_t *ret;
-  tor_tls_t *tls;
-  X509 *cert = NULL;
-
-  cert = read_cert_from(validCertString);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
-
-  ret = tor_tls_get_peer_cert(tls);
-  tt_assert(!ret);
-
-  tls->ssl->session->peer = cert;
-  ret = tor_tls_get_peer_cert(tls);
-  tt_assert(ret);
-  tt_assert(ret->cert == cert);
-
- done:
-  tor_x509_cert_free(ret);
-  tor_free(tls->ssl->session);
-  tor_free(tls->ssl);
-  tor_free(tls);
-  X509_free(cert);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_peer_has_cert(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  X509 *cert = NULL;
-
-  cert = read_cert_from(validCertString);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
-
-  ret = tor_tls_peer_has_cert(tls);
-  tt_assert(!ret);
-
-  tls->ssl->session->peer = cert;
-  ret = tor_tls_peer_has_cert(tls);
-  tt_assert(ret);
-
- done:
-  tor_free(tls->ssl->session);
-  tor_free(tls->ssl);
-  tor_free(tls);
-  X509_free(cert);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static void
-test_tortls_is_server(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-  int ret;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->isServer = 1;
-  ret = tor_tls_is_server(tls);
-  tt_int_op(ret, OP_EQ, 1);
-
- done:
-  tor_free(tls);
-}
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_session_secret_cb(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-  SSL_CTX *ctx;
-  STACK_OF(SSL_CIPHER) *ciphers = NULL;
-  SSL_CIPHER *one;
-
-  library_init();
-
-  tor_tls_allocate_tor_tls_object_ex_data_index();
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-
-  tls->magic = TOR_TLS_MAGIC;
-
-  ctx = SSL_CTX_new(TLSv1_method());
-  tls->ssl = SSL_new(ctx);
-  SSL_set_ex_data(tls->ssl, tor_tls_object_ex_data_index, tls);
-
-  SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
-
-  tor_tls_session_secret_cb(tls->ssl, NULL, NULL, NULL, NULL, NULL);
-  tt_assert(!tls->ssl->tls_session_secret_cb);
-
-  one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
-  one->id = 0x00ff;
-  ciphers = sk_SSL_CIPHER_new_null();
-  sk_SSL_CIPHER_push(ciphers, one);
-
-  tls->client_cipher_list_type = 0;
-  tor_tls_session_secret_cb(tls->ssl, NULL, NULL, ciphers, NULL, NULL);
-  tt_assert(!tls->ssl->tls_session_secret_cb);
-
- done:
-  sk_SSL_CIPHER_free(ciphers);
-  SSL_free(tls->ssl);
-  SSL_CTX_free(ctx);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-/* TODO: It seems block_renegotiation and unblock_renegotiation and
- * using different blags. This might not be correct */
-static void
-test_tortls_block_renegotiation(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE));
-#ifndef SUPPORT_UNSAFE_RENEGOTIATION_FLAG
-#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0
-#endif
-
-  tls->ssl->s3->flags = SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
-
-  tor_tls_block_renegotiation(tls);
-
-#ifndef OPENSSL_1_1_API
-  tt_assert(!(tls->ssl->s3->flags &
-              SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
-#endif
-
- done:
-  tor_free(tls->ssl->s3);
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-
-static void
-test_tortls_unblock_renegotiation(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tor_tls_unblock_renegotiation(tls);
-
-  tt_uint_op(SSL_get_options(tls->ssl) &
-             SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, OP_EQ,
-             SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
-
- done:
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_assert_renegotiation_unblocked(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tor_tls_unblock_renegotiation(tls);
-  tor_tls_assert_renegotiation_unblocked(tls);
-  /* No assertion here - this test will fail if tor_assert is turned on
-   * and things are bad. */
-
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static void
-test_tortls_set_logged_address(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-
-  tor_tls_set_logged_address(tls, "foo bar");
-
-  tt_str_op(tls->address, OP_EQ, "foo bar");
-
-  tor_tls_set_logged_address(tls, "foo bar 2");
-  tt_str_op(tls->address, OP_EQ, "foo bar 2");
-
- done:
-  tor_free(tls->address);
-  tor_free(tls);
-}
-
-#ifndef OPENSSL_OPAQUE
-static void
-example_cb(tor_tls_t *t, void *arg)
-{
-  (void)t;
-  (void)arg;
-}
-
-static void
-test_tortls_set_renegotiate_callback(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-  const char *arg = "hello";
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-
-  tor_tls_set_renegotiate_callback(tls, example_cb, (void*)arg);
-  tt_assert(tls->negotiated_callback == example_cb);
-  tt_assert(tls->callback_arg == arg);
-  tt_assert(!tls->got_renegotiate);
-
-  /* Assumes V2_HANDSHAKE_SERVER */
-  tt_assert(tls->ssl->info_callback == tor_tls_server_info_callback);
-
-  tor_tls_set_renegotiate_callback(tls, NULL, (void*)arg);
-  tt_assert(tls->ssl->info_callback == tor_tls_debug_state_callback);
-
- done:
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static SSL_CIPHER *fixed_cipher1 = NULL;
-static SSL_CIPHER *fixed_cipher2 = NULL;
-static const SSL_CIPHER *
-fake_get_cipher(unsigned ncipher)
-{
-
-  switch (ncipher) {
-  case 1:
-    return fixed_cipher1;
-  case 2:
-    return fixed_cipher2;
-  default:
-    return NULL;
-  }
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_find_cipher_by_id(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  SSL *ssl;
-  SSL_CTX *ctx;
-  const SSL_METHOD *m = TLSv1_method();
-  SSL_METHOD *empty_method = tor_malloc_zero(sizeof(SSL_METHOD));
-
-  fixed_cipher1 = tor_malloc_zero(sizeof(SSL_CIPHER));
-  fixed_cipher2 = tor_malloc_zero(sizeof(SSL_CIPHER));
-  fixed_cipher2->id = 0xC00A;
-
-  library_init();
-
-  ctx = SSL_CTX_new(m);
-  ssl = SSL_new(ctx);
-
-  ret = find_cipher_by_id(ssl, NULL, 0xC00A);
-  tt_int_op(ret, OP_EQ, 1);
-
-  ret = find_cipher_by_id(ssl, m, 0xC00A);
-  tt_int_op(ret, OP_EQ, 1);
-
-  ret = find_cipher_by_id(ssl, m, 0xFFFF);
-  tt_int_op(ret, OP_EQ, 0);
-
-  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
-  tt_int_op(ret, OP_EQ, 1);
-
-  ret = find_cipher_by_id(ssl, empty_method, 0xFFFF);
-#ifdef HAVE_SSL_CIPHER_FIND
-  tt_int_op(ret, OP_EQ, 0);
-#else
-  tt_int_op(ret, OP_EQ, 1);
-#endif
-
-  empty_method->get_cipher = fake_get_cipher;
-  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
-  tt_int_op(ret, OP_EQ, 1);
-
-  empty_method->get_cipher = m->get_cipher;
-  empty_method->num_ciphers = m->num_ciphers;
-  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
-  tt_int_op(ret, OP_EQ, 1);
-
-  empty_method->get_cipher = fake_get_cipher;
-  empty_method->num_ciphers = m->num_ciphers;
-  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
-  tt_int_op(ret, OP_EQ, 1);
-
-  empty_method->num_ciphers = fake_num_ciphers;
-  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
-#ifdef HAVE_SSL_CIPHER_FIND
-  tt_int_op(ret, OP_EQ, 1);
-#else
-  tt_int_op(ret, OP_EQ, 0);
-#endif
-
- done:
-  tor_free(empty_method);
-  SSL_free(ssl);
-  SSL_CTX_free(ctx);
-  tor_free(fixed_cipher1);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_debug_state_callback(void *ignored)
-{
-  (void)ignored;
-  SSL *ssl;
-  char *buf = tor_malloc_zero(1000);
-  int n;
-
-  setup_capture_of_logs(LOG_DEBUG);
-
-  ssl = tor_malloc_zero(sizeof(SSL));
-
-  tor_tls_debug_state_callback(ssl, 32, 45);
-
-  n = tor_snprintf(buf, 1000, "SSL %p is now in state unknown"
-               " state [type=32,val=45].\n", ssl);
-  /* tor's snprintf returns -1 on error */
-  tt_int_op(n, OP_NE, -1);
-  expect_log_msg(buf);
-
- done:
-  teardown_capture_of_logs();
-  tor_free(buf);
-  tor_free(ssl);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_server_info_callback(void *ignored)
-{
-  (void)ignored;
-  tor_tls_t *tls;
-  SSL_CTX *ctx;
-  SSL *ssl;
-
-  library_init();
-
-  ctx = SSL_CTX_new(TLSv1_method());
-  ssl = SSL_new(ctx);
-
-  tor_tls_allocate_tor_tls_object_ex_data_index();
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->magic = TOR_TLS_MAGIC;
-  tls->ssl = ssl;
-
-  setup_full_capture_of_logs(LOG_WARN);
-  SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_A);
-  mock_clean_saved_logs();
-  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
-  expect_single_log_msg("Couldn't look up the tls for an SSL*. How odd!\n");
-
-  SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_B);
-  mock_clean_saved_logs();
-  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
-  expect_single_log_msg("Couldn't look up the tls for an SSL*. How odd!\n");
-
-  SSL_set_state(ssl, 99);
-  mock_clean_saved_logs();
-  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
-  expect_no_log_entry();
-  teardown_capture_of_logs();
-
-  SSL_set_ex_data(tls->ssl, tor_tls_object_ex_data_index, tls);
-  SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_B);
-  tls->negotiated_callback = 0;
-  tls->server_handshake_count = 120;
-  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
-  tt_int_op(tls->server_handshake_count, OP_EQ, 121);
-
-  tls->server_handshake_count = 127;
-  tls->negotiated_callback = (void *)1;
-  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
-  tt_int_op(tls->server_handshake_count, OP_EQ, 127);
-  tt_int_op(tls->got_renegotiate, OP_EQ, 1);
-
-  tls->ssl->session = SSL_SESSION_new();
-  tls->wasV2Handshake = 0;
-  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
-  tt_int_op(tls->wasV2Handshake, OP_EQ, 0);
-
- done:
-  teardown_capture_of_logs();
-  SSL_free(ssl);
-  SSL_CTX_free(ctx);
-  tor_free(tls);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static int fixed_ssl_read_result_index;
-static int fixed_ssl_read_result[5];
-static int fixed_ssl_shutdown_result;
-
-static int
-fixed_ssl_read(SSL *s, void *buf, int len)
-{
-  (void)s;
-  (void)buf;
-  (void)len;
-  return fixed_ssl_read_result[fixed_ssl_read_result_index++];
-}
-
-static int
-fixed_ssl_shutdown(SSL *s)
-{
-  (void)s;
-  return fixed_ssl_shutdown_result;
-}
-
-#ifndef LIBRESSL_VERSION_NUMBER
-static int fixed_ssl_state_to_set;
-static tor_tls_t *fixed_tls;
-
-static int
-setting_version_ssl_shutdown(SSL *s)
-{
-  s->version = SSL2_VERSION;
-  return fixed_ssl_shutdown_result;
-}
-
-static int
-setting_version_and_state_ssl_shutdown(SSL *s)
-{
-  fixed_tls->state = fixed_ssl_state_to_set;
-  s->version = SSL2_VERSION;
-  return fixed_ssl_shutdown_result;
-}
-#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
-
-static int
-dummy_handshake_func(SSL *s)
-{
-  (void)s;
-  return 1;
-}
-
-static void
-test_tortls_shutdown(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  SSL_METHOD *method = give_me_a_test_method();
-  setup_capture_of_logs(LOG_WARN);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->ssl->method = method;
-  method->ssl_read = fixed_ssl_read;
-  method->ssl_shutdown = fixed_ssl_shutdown;
-
-  ret = tor_tls_shutdown(tls);
-  tt_int_op(ret, OP_EQ, -9);
-
-  tls->state = TOR_TLS_ST_SENTCLOSE;
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 10;
-  fixed_ssl_read_result[1] = -1;
-  ret = tor_tls_shutdown(tls);
-  tt_int_op(ret, OP_EQ, -9);
-
-#ifndef LIBRESSL_VERSION_NUMBER
-  tls->ssl->handshake_func = dummy_handshake_func;
-
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 10;
-  fixed_ssl_read_result[1] = 42;
-  fixed_ssl_read_result[2] = 0;
-  fixed_ssl_shutdown_result = 1;
-  ERR_clear_error();
-  tls->ssl->version = SSL2_VERSION;
-  ret = tor_tls_shutdown(tls);
-  tt_int_op(ret, OP_EQ, TOR_TLS_DONE);
-  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
-
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 10;
-  fixed_ssl_read_result[1] = 42;
-  fixed_ssl_read_result[2] = 0;
-  fixed_ssl_shutdown_result = 0;
-  ERR_clear_error();
-  tls->ssl->version = 0;
-  ret = tor_tls_shutdown(tls);
-  tt_int_op(ret, OP_EQ, TOR_TLS_DONE);
-  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
-
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 10;
-  fixed_ssl_read_result[1] = 42;
-  fixed_ssl_read_result[2] = 0;
-  fixed_ssl_shutdown_result = 0;
-  ERR_clear_error();
-  tls->ssl->version = 0;
-  method->ssl_shutdown = setting_version_ssl_shutdown;
-  ret = tor_tls_shutdown(tls);
-  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
-
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 10;
-  fixed_ssl_read_result[1] = 42;
-  fixed_ssl_read_result[2] = 0;
-  fixed_ssl_shutdown_result = 0;
-  fixed_tls = tls;
-  fixed_ssl_state_to_set = TOR_TLS_ST_GOTCLOSE;
-  ERR_clear_error();
-  tls->ssl->version = 0;
-  method->ssl_shutdown = setting_version_and_state_ssl_shutdown;
-  ret = tor_tls_shutdown(tls);
-  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
-
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 10;
-  fixed_ssl_read_result[1] = 42;
-  fixed_ssl_read_result[2] = 0;
-  fixed_ssl_read_result[3] = -1;
-  fixed_ssl_shutdown_result = 0;
-  fixed_tls = tls;
-  fixed_ssl_state_to_set = 0;
-  ERR_clear_error();
-  tls->ssl->version = 0;
-  method->ssl_shutdown = setting_version_and_state_ssl_shutdown;
-  ret = tor_tls_shutdown(tls);
-  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
-#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
-
- done:
-  teardown_capture_of_logs();
-  tor_free(method);
-  tor_free(tls->ssl);
-  tor_free(tls);
-}
-
-static int negotiated_callback_called;
-
-static void
-negotiated_callback_setter(tor_tls_t *t, void *arg)
-{
-  (void)t;
-  (void)arg;
-  negotiated_callback_called++;
-}
-
-static void
-test_tortls_read(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  char buf[100];
-  SSL_METHOD *method = give_me_a_test_method();
-  setup_capture_of_logs(LOG_WARN);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->state = TOR_TLS_ST_OPEN;
-
-  ret = tor_tls_read(tls, buf, 10);
-  tt_int_op(ret, OP_EQ, -9);
-
-  /* These tests assume that V2_HANDSHAKE_SERVER is set */
-  tls->ssl->handshake_func = dummy_handshake_func;
-  tls->ssl->method = method;
-  method->ssl_read = fixed_ssl_read;
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 42;
-  tls->state = TOR_TLS_ST_OPEN;
-  ERR_clear_error();
-  ret = tor_tls_read(tls, buf, 10);
-  tt_int_op(ret, OP_EQ, 42);
-
-  tls->state = TOR_TLS_ST_OPEN;
-  tls->got_renegotiate = 1;
-  fixed_ssl_read_result_index = 0;
-  ERR_clear_error();
-  ret = tor_tls_read(tls, buf, 10);
-  tt_int_op(tls->got_renegotiate, OP_EQ, 0);
-
-  tls->state = TOR_TLS_ST_OPEN;
-  tls->got_renegotiate = 1;
-  negotiated_callback_called = 0;
-  tls->negotiated_callback = negotiated_callback_setter;
-  fixed_ssl_read_result_index = 0;
-  ERR_clear_error();
-  ret = tor_tls_read(tls, buf, 10);
-  tt_int_op(negotiated_callback_called, OP_EQ, 1);
-
-#ifndef LIBRESSL_VERSION_NUMBER
-  fixed_ssl_read_result_index = 0;
-  fixed_ssl_read_result[0] = 0;
-  tls->ssl->version = SSL2_VERSION;
-  ERR_clear_error();
-  ret = tor_tls_read(tls, buf, 10);
-  tt_int_op(ret, OP_EQ, TOR_TLS_CLOSE);
-  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
-#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
-  // TODO: fill up
-
- done:
-  teardown_capture_of_logs();
-  tor_free(tls->ssl);
-  tor_free(tls);
-  tor_free(method);
-}
-
-static int fixed_ssl_write_result;
-
-static int
-fixed_ssl_write(SSL *s, const void *buf, int len)
-{
-  (void)s;
-  (void)buf;
-  (void)len;
-  return fixed_ssl_write_result;
-}
-
-static void
-test_tortls_write(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  SSL_METHOD *method = give_me_a_test_method();
-  char buf[100];
-  setup_capture_of_logs(LOG_WARN);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = tor_malloc_zero(sizeof(SSL));
-  tls->state = TOR_TLS_ST_OPEN;
-
-  ret = tor_tls_write(tls, buf, 0);
-  tt_int_op(ret, OP_EQ, 0);
-
-  ret = tor_tls_write(tls, buf, 10);
-  tt_int_op(ret, OP_EQ, -9);
-
-  tls->ssl->method = method;
-  tls->wantwrite_n = 1;
-  ret = tor_tls_write(tls, buf, 10);
-  tt_int_op(tls->wantwrite_n, OP_EQ, 0);
-
-  method->ssl_write = fixed_ssl_write;
-  tls->ssl->handshake_func = dummy_handshake_func;
-  fixed_ssl_write_result = 1;
-  ERR_clear_error();
-  ret = tor_tls_write(tls, buf, 10);
-  tt_int_op(ret, OP_EQ, 1);
-
-  fixed_ssl_write_result = -1;
-  ERR_clear_error();
-  tls->ssl->rwstate = SSL_READING;
-  SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL);
-  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_READ;
-  ret = tor_tls_write(tls, buf, 10);
-  tt_int_op(ret, OP_EQ, TOR_TLS_WANTREAD);
-
-  ERR_clear_error();
-  tls->ssl->rwstate = SSL_READING;
-  SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL);
-  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_WRITE;
-  ret = tor_tls_write(tls, buf, 10);
-  tt_int_op(ret, OP_EQ, TOR_TLS_WANTWRITE);
-
- done:
-  teardown_capture_of_logs();
-  BIO_free(tls->ssl->rbio);
-  tor_free(tls->ssl);
-  tor_free(tls);
-  tor_free(method);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static int fixed_ssl_accept_result;
-static int fixed_ssl_connect_result;
-
-static int
-setting_error_ssl_accept(SSL *ssl)
-{
-  (void)ssl;
-  ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99);
-  ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99);
-  return fixed_ssl_accept_result;
-}
-
-static int
-setting_error_ssl_connect(SSL *ssl)
-{
-  (void)ssl;
-  ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99);
-  ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99);
-  return fixed_ssl_connect_result;
-}
-
-static int
-fixed_ssl_accept(SSL *ssl)
-{
-  (void) ssl;
-  return fixed_ssl_accept_result;
-}
-
-static void
-test_tortls_handshake(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  SSL_CTX *ctx;
-  SSL_METHOD *method = give_me_a_test_method();
-  setup_capture_of_logs(LOG_INFO);
-
-  SSL_library_init();
-  SSL_load_error_strings();
-
-  ctx = SSL_CTX_new(TLSv1_method());
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = SSL_new(ctx);
-  tls->state = TOR_TLS_ST_HANDSHAKE;
-
-  ret = tor_tls_handshake(tls);
-  tt_int_op(ret, OP_EQ, -9);
-
-  tls->isServer = 1;
-  tls->state = TOR_TLS_ST_HANDSHAKE;
-  ret = tor_tls_handshake(tls);
-  tt_int_op(ret, OP_EQ, -9);
-
-  tls->ssl->method = method;
-  method->ssl_accept = fixed_ssl_accept;
-  fixed_ssl_accept_result = 2;
-  ERR_clear_error();
-  tls->state = TOR_TLS_ST_HANDSHAKE;
-  ret = tor_tls_handshake(tls);
-  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_OPEN);
-
-  method->ssl_accept = setting_error_ssl_accept;
-  fixed_ssl_accept_result = 1;
-  ERR_clear_error();
-  mock_clean_saved_logs();
-  tls->state = TOR_TLS_ST_HANDSHAKE;
-  ret = tor_tls_handshake(tls);
-  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
-  expect_log_entry();
-  /* This fails on jessie.  Investigate why! */
-#if 0
-  expect_log_msg("TLS error while handshaking: (null) (in bignum routines:"
-            "(null):SSLv3 write client hello B)\n");
-  expect_log_msg("TLS error while handshaking: (null) (in system library:"
-            "connect:SSLv3 write client hello B)\n");
-#endif /* 0 */
-  expect_log_severity(LOG_INFO);
-
-  tls->isServer = 0;
-  method->ssl_connect = setting_error_ssl_connect;
-  fixed_ssl_connect_result = 1;
-  ERR_clear_error();
-  mock_clean_saved_logs();
-  tls->state = TOR_TLS_ST_HANDSHAKE;
-  ret = tor_tls_handshake(tls);
-  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
-  expect_log_entry();
-#if 0
-  /* See above */
-  expect_log_msg("TLS error while handshaking: "
-            "(null) (in bignum routines:(null):SSLv3 write client hello B)\n");
-  expect_log_msg("TLS error while handshaking: "
-            "(null) (in system library:connect:SSLv3 write client hello B)\n");
-#endif /* 0 */
-  expect_log_severity(LOG_WARN);
-
- done:
-  teardown_capture_of_logs();
-  SSL_free(tls->ssl);
-  SSL_CTX_free(ctx);
-  tor_free(tls);
-  tor_free(method);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#ifndef OPENSSL_OPAQUE
-static void
-test_tortls_finish_handshake(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_t *tls;
-  SSL_CTX *ctx;
-  SSL_METHOD *method = give_me_a_test_method();
-  SSL_library_init();
-  SSL_load_error_strings();
-
-  X509 *c1 = read_cert_from(validCertString);
-  SESS_CERT_local *sess = NULL;
-
-  ctx = SSL_CTX_new(method);
-
-  tls = tor_malloc_zero(sizeof(tor_tls_t));
-  tls->ssl = SSL_new(ctx);
-  tls->state = TOR_TLS_ST_OPEN;
-
-  ret = tor_tls_finish_handshake(tls);
-  tt_int_op(ret, OP_EQ, 0);
-
-  tls->isServer = 1;
-  tls->wasV2Handshake = 0;
-  setup_full_capture_of_logs(LOG_WARN);
-  ret = tor_tls_finish_handshake(tls);
-  tt_int_op(ret, OP_EQ, 0);
-  tt_int_op(tls->wasV2Handshake, OP_EQ, 1);
-  expect_single_log_msg_containing("For some reason, wasV2Handshake didn't "
-                                   "get set.");
-  teardown_capture_of_logs();
-
-  tls->wasV2Handshake = 1;
-  ret = tor_tls_finish_handshake(tls);
-  tt_int_op(ret, OP_EQ, 0);
-  tt_int_op(tls->wasV2Handshake, OP_EQ, 1);
-
-  tls->wasV2Handshake = 1;
-  tls->ssl->session = SSL_SESSION_new();
-  ret = tor_tls_finish_handshake(tls);
-  tt_int_op(ret, OP_EQ, 0);
-  tt_int_op(tls->wasV2Handshake, OP_EQ, 0);
-
-  tls->isServer = 0;
-
-  sess = tor_malloc_zero(sizeof(SESS_CERT_local));
-  tls->ssl->session->sess_cert = (void *)sess;
-  sess->cert_chain = sk_X509_new_null();
-  sk_X509_push(sess->cert_chain, c1);
-  tls->ssl->session->peer = c1;
-  tls->wasV2Handshake = 0;
-  ret = tor_tls_finish_handshake(tls);
-  tt_int_op(ret, OP_EQ, 0);
-  tt_int_op(tls->wasV2Handshake, OP_EQ, 1);
-
-  method->num_ciphers = fake_num_ciphers;
-  ret = tor_tls_finish_handshake(tls);
-  tt_int_op(ret, OP_EQ, -9);
-
- done:
-  if (sess)
-    sk_X509_free(sess->cert_chain);
-  if (tls->ssl && tls->ssl->session) {
-    tor_free(tls->ssl->session->sess_cert);
-  }
-  SSL_free(tls->ssl);
-  tor_free(tls);
-  SSL_CTX_free(ctx);
-  tor_free(method);
-  teardown_capture_of_logs();
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static int fixed_crypto_pk_new_result_index;
-static crypto_pk_t *fixed_crypto_pk_new_result[5];
-
-static crypto_pk_t *
-fixed_crypto_pk_new(void)
-{
-  return fixed_crypto_pk_new_result[fixed_crypto_pk_new_result_index++];
-}
-
-#ifndef OPENSSL_OPAQUE
-static int fixed_crypto_pk_generate_key_with_bits_result_index;
-static int fixed_crypto_pk_generate_key_with_bits_result[5];
-static int fixed_tor_tls_create_certificate_result_index;
-static X509 *fixed_tor_tls_create_certificate_result[5];
-static int fixed_tor_x509_cert_new_result_index;
-static tor_x509_cert_t *fixed_tor_x509_cert_new_result[5];
-
-static int
-fixed_crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
-{
-  (void)env;
-  (void)bits;
-  return fixed_crypto_pk_generate_key_with_bits_result[
-                    fixed_crypto_pk_generate_key_with_bits_result_index++];
-}
-
-static X509 *
-fixed_tor_tls_create_certificate(crypto_pk_t *rsa,
-                                 crypto_pk_t *rsa_sign,
-                                 const char *cname,
-                                 const char *cname_sign,
-                                 unsigned int cert_lifetime)
-{
-  (void)rsa;
-  (void)rsa_sign;
-  (void)cname;
-  (void)cname_sign;
-  (void)cert_lifetime;
-  return fixed_tor_tls_create_certificate_result[
-                             fixed_tor_tls_create_certificate_result_index++];
-}
-
-static tor_x509_cert_t *
-fixed_tor_x509_cert_new(X509 *x509_cert)
-{
-  (void) x509_cert;
-  return fixed_tor_x509_cert_new_result[
-                                      fixed_tor_x509_cert_new_result_index++];
-}
-
-static void
-test_tortls_context_new(void *ignored)
-{
-  (void)ignored;
-  tor_tls_context_t *ret;
-  crypto_pk_t *pk1, *pk2, *pk3, *pk4, *pk5, *pk6, *pk7, *pk8, *pk9, *pk10,
-    *pk11, *pk12, *pk13, *pk14, *pk15, *pk16, *pk17, *pk18;
-
-  pk1 = crypto_pk_new();
-  pk2 = crypto_pk_new();
-  pk3 = crypto_pk_new();
-  pk4 = crypto_pk_new();
-  pk5 = crypto_pk_new();
-  pk6 = crypto_pk_new();
-  pk7 = crypto_pk_new();
-  pk8 = crypto_pk_new();
-  pk9 = crypto_pk_new();
-  pk10 = crypto_pk_new();
-  pk11 = crypto_pk_new();
-  pk12 = crypto_pk_new();
-  pk13 = crypto_pk_new();
-  pk14 = crypto_pk_new();
-  pk15 = crypto_pk_new();
-  pk16 = crypto_pk_new();
-  pk17 = crypto_pk_new();
-  pk18 = crypto_pk_new();
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = NULL;
-  MOCK(crypto_pk_new, fixed_crypto_pk_new);
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  /* note: we already override this in testing_common.c, so we
-   * run this unit test in a subprocess. */
-  MOCK(crypto_pk_generate_key_with_bits,
-       fixed_crypto_pk_generate_key_with_bits);
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk1;
-  fixed_crypto_pk_new_result[1] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result[0] = -1;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk2;
-  fixed_crypto_pk_new_result[1] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result[0] = 0;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk3;
-  fixed_crypto_pk_new_result[1] = pk4;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result[0] = 0;
-  fixed_crypto_pk_generate_key_with_bits_result[1] = -1;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  MOCK(tor_tls_create_certificate, fixed_tor_tls_create_certificate);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk5;
-  fixed_crypto_pk_new_result[1] = pk6;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  fixed_crypto_pk_generate_key_with_bits_result[1] = 0;
-  fixed_tor_tls_create_certificate_result_index = 0;
-  fixed_tor_tls_create_certificate_result[0] = NULL;
-  fixed_tor_tls_create_certificate_result[1] = X509_new();
-  fixed_tor_tls_create_certificate_result[2] = X509_new();
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk7;
-  fixed_crypto_pk_new_result[1] = pk8;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  fixed_tor_tls_create_certificate_result_index = 0;
-  fixed_tor_tls_create_certificate_result[0] = X509_new();
-  fixed_tor_tls_create_certificate_result[1] = NULL;
-  fixed_tor_tls_create_certificate_result[2] = X509_new();
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk9;
-  fixed_crypto_pk_new_result[1] = pk10;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  fixed_tor_tls_create_certificate_result_index = 0;
-  fixed_tor_tls_create_certificate_result[0] = X509_new();
-  fixed_tor_tls_create_certificate_result[1] = X509_new();
-  fixed_tor_tls_create_certificate_result[2] = NULL;
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  MOCK(tor_x509_cert_new, fixed_tor_x509_cert_new);
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk11;
-  fixed_crypto_pk_new_result[1] = pk12;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  fixed_tor_tls_create_certificate_result_index = 0;
-  fixed_tor_tls_create_certificate_result[0] = X509_new();
-  fixed_tor_tls_create_certificate_result[1] = X509_new();
-  fixed_tor_tls_create_certificate_result[2] = X509_new();
-  fixed_tor_x509_cert_new_result_index = 0;
-  fixed_tor_x509_cert_new_result[0] = NULL;
-  fixed_tor_x509_cert_new_result[1] = NULL;
-  fixed_tor_x509_cert_new_result[2] = NULL;
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk13;
-  fixed_crypto_pk_new_result[1] = pk14;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  fixed_tor_tls_create_certificate_result_index = 0;
-  fixed_tor_tls_create_certificate_result[0] = X509_new();
-  fixed_tor_tls_create_certificate_result[1] = X509_new();
-  fixed_tor_tls_create_certificate_result[2] = X509_new();
-  fixed_tor_x509_cert_new_result_index = 0;
-  fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  fixed_tor_x509_cert_new_result[1] = NULL;
-  fixed_tor_x509_cert_new_result[2] = NULL;
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk15;
-  fixed_crypto_pk_new_result[1] = pk16;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  fixed_tor_tls_create_certificate_result_index = 0;
-  fixed_tor_tls_create_certificate_result[0] = X509_new();
-  fixed_tor_tls_create_certificate_result[1] = X509_new();
-  fixed_tor_tls_create_certificate_result[2] = X509_new();
-  fixed_tor_x509_cert_new_result_index = 0;
-  fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  fixed_tor_x509_cert_new_result[2] = NULL;
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = pk17;
-  fixed_crypto_pk_new_result[1] = pk18;
-  fixed_crypto_pk_new_result[2] = NULL;
-  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
-  fixed_tor_tls_create_certificate_result_index = 0;
-  fixed_tor_tls_create_certificate_result[0] = X509_new();
-  fixed_tor_tls_create_certificate_result[1] = X509_new();
-  fixed_tor_tls_create_certificate_result[2] = X509_new();
-  fixed_tor_x509_cert_new_result_index = 0;
-  fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  fixed_tor_x509_cert_new_result[2] = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  ret = tor_tls_context_new(NULL, 0, 0, 0);
-  tt_assert(!ret);
-
- done:
-  UNMOCK(tor_x509_cert_new);
-  UNMOCK(tor_tls_create_certificate);
-  UNMOCK(crypto_pk_generate_key_with_bits);
-  UNMOCK(crypto_pk_new);
-}
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-static int fixed_crypto_pk_get_evp_pkey_result_index = 0;
-static EVP_PKEY *fixed_crypto_pk_get_evp_pkey_result[5];
-
-static EVP_PKEY *
-fixed_crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
-{
-  (void) env;
-  (void) private;
-  return fixed_crypto_pk_get_evp_pkey_result[
-                               fixed_crypto_pk_get_evp_pkey_result_index++];
-}
-
-static void
-test_tortls_create_certificate(void *ignored)
-{
-  (void)ignored;
-  X509 *ret;
-  crypto_pk_t *pk1, *pk2;
-
-  pk1 = crypto_pk_new();
-  pk2 = crypto_pk_new();
-
-  MOCK(crypto_pk_get_openssl_evp_pkey_, fixed_crypto_pk_get_evp_pkey_);
-  fixed_crypto_pk_get_evp_pkey_result_index = 0;
-  fixed_crypto_pk_get_evp_pkey_result[0] = NULL;
-  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_get_evp_pkey_result_index = 0;
-  fixed_crypto_pk_get_evp_pkey_result[0] = EVP_PKEY_new();
-  fixed_crypto_pk_get_evp_pkey_result[1] = NULL;
-  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
-  tt_assert(!ret);
-
-  fixed_crypto_pk_get_evp_pkey_result_index = 0;
-  fixed_crypto_pk_get_evp_pkey_result[0] = EVP_PKEY_new();
-  fixed_crypto_pk_get_evp_pkey_result[1] = EVP_PKEY_new();
-  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
-  tt_assert(!ret);
-
- done:
-  UNMOCK(crypto_pk_get_openssl_evp_pkey_);
-  crypto_pk_free(pk1);
-  crypto_pk_free(pk2);
-}
-
-static void
-test_tortls_cert_new(void *ignored)
-{
-  (void)ignored;
-  tor_x509_cert_t *ret;
-  X509 *cert = read_cert_from(validCertString);
-
-  ret = tor_x509_cert_new(NULL);
-  tt_assert(!ret);
-
-  ret = tor_x509_cert_new(cert);
-  tt_assert(ret);
-  tor_x509_cert_free(ret);
-  ret = NULL;
-
-#if 0
-  cert = read_cert_from(validCertString);
-  /* XXX this doesn't do what you think: it alters a copy of the pubkey. */
-  X509_get_pubkey(cert)->type = EVP_PKEY_DSA;
-  ret = tor_x509_cert_new(cert);
-  tt_assert(ret);
-#endif /* 0 */
-
-#ifndef OPENSSL_OPAQUE
-  cert = read_cert_from(validCertString);
-  X509_CINF_free(cert->cert_info);
-  cert->cert_info = NULL;
-  ret = tor_x509_cert_new(cert);
-  tt_assert(ret);
-#endif /* !defined(OPENSSL_OPAQUE) */
-
- done:
-  tor_x509_cert_free(ret);
-}
-
-static void
-test_tortls_cert_is_valid(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_x509_cert_t *cert = NULL, *scert = NULL;
-
-  scert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
-  tt_int_op(ret, OP_EQ, 0);
-
-  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
-  tt_int_op(ret, OP_EQ, 0);
-  tor_free(scert);
-  tor_free(cert);
-
-  cert = tor_x509_cert_new(read_cert_from(validCertString));
-  scert = tor_x509_cert_new(read_cert_from(caCertString));
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
-  tt_int_op(ret, OP_EQ, 1);
-
-#ifndef OPENSSL_OPAQUE
-  tor_x509_cert_free(cert);
-  tor_x509_cert_free(scert);
-  cert = tor_x509_cert_new(read_cert_from(validCertString));
-  scert = tor_x509_cert_new(read_cert_from(caCertString));
-  ASN1_TIME_free(cert->cert->cert_info->validity->notAfter);
-  cert->cert->cert_info->validity->notAfter =
-    ASN1_TIME_set(NULL, time(NULL)-1000000);
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
-  tt_int_op(ret, OP_EQ, 0);
-
-  tor_x509_cert_free(cert);
-  tor_x509_cert_free(scert);
-  cert = tor_x509_cert_new(read_cert_from(validCertString));
-  scert = tor_x509_cert_new(read_cert_from(caCertString));
-  X509_PUBKEY_free(cert->cert->cert_info->key);
-  cert->cert->cert_info->key = NULL;
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
-  tt_int_op(ret, OP_EQ, 0);
-#endif /* !defined(OPENSSL_OPAQUE) */
-
-#if 0
-  tor_x509_cert_free(cert);
-  tor_x509_cert_free(scert);
-  cert = tor_x509_cert_new(read_cert_from(validCertString));
-  scert = tor_x509_cert_new(read_cert_from(caCertString));
-  /* This doesn't actually change the key in the cert. XXXXXX */
-  BN_one(EVP_PKEY_get1_RSA(X509_get_pubkey(cert->cert))->n);
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
-  tt_int_op(ret, OP_EQ, 0);
-
-  tor_x509_cert_free(cert);
-  tor_x509_cert_free(scert);
-  cert = tor_x509_cert_new(read_cert_from(validCertString));
-  scert = tor_x509_cert_new(read_cert_from(caCertString));
-  /* This doesn't actually change the key in the cert. XXXXXX */
-  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
-  tt_int_op(ret, OP_EQ, 0);
-
-  tor_x509_cert_free(cert);
-  tor_x509_cert_free(scert);
-  cert = tor_x509_cert_new(read_cert_from(validCertString));
-  scert = tor_x509_cert_new(read_cert_from(caCertString));
-  /* This doesn't actually change the key in the cert. XXXXXX */
-  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
-  tt_int_op(ret, OP_EQ, 1);
-
-  tor_x509_cert_free(cert);
-  tor_x509_cert_free(scert);
-  cert = tor_x509_cert_new(read_cert_from(validCertString));
-  scert = tor_x509_cert_new(read_cert_from(caCertString));
-  /* This doesn't actually change the key in the cert. XXXXXX */
-  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
-  X509_get_pubkey(cert->cert)->ameth = NULL;
-  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
-  tt_int_op(ret, OP_EQ, 0);
-#endif /* 0 */
-
- done:
-  tor_x509_cert_free(cert);
-  tor_x509_cert_free(scert);
-}
-
-static void
-test_tortls_context_init_one(void *ignored)
-{
-  (void)ignored;
-  int ret;
-  tor_tls_context_t *old = NULL;
-
-  MOCK(crypto_pk_new, fixed_crypto_pk_new);
-
-  fixed_crypto_pk_new_result_index = 0;
-  fixed_crypto_pk_new_result[0] = NULL;
-  ret = tor_tls_context_init_one(&old, NULL, 0, 0, 0);
-  tt_int_op(ret, OP_EQ, -1);
-
- done:
-  UNMOCK(crypto_pk_new);
-}
-
-#define LOCAL_TEST_CASE(name, flags)                    \
+#define LOCAL_TEST_CASE(name, flags)                            \
   { #name, test_tortls_##name, (flags|TT_FORK), NULL, NULL }
 
-#ifdef OPENSSL_OPAQUE
-#define INTRUSIVE_TEST_CASE(name, flags)        \
-  { #name, NULL, TT_SKIP, NULL, NULL }
-#else
-#define INTRUSIVE_TEST_CASE(name, flags) LOCAL_TEST_CASE(name, flags)
-#endif /* defined(OPENSSL_OPAQUE) */
-
 struct testcase_t tortls_tests[] = {
   LOCAL_TEST_CASE(errno_to_tls_error, 0),
   LOCAL_TEST_CASE(err_to_string, 0),
-  LOCAL_TEST_CASE(tor_tls_new, TT_FORK),
   LOCAL_TEST_CASE(tor_tls_get_error, 0),
-  LOCAL_TEST_CASE(get_state_description, TT_FORK),
-  LOCAL_TEST_CASE(get_by_ssl, TT_FORK),
-  LOCAL_TEST_CASE(allocate_tor_tls_object_ex_data_index, TT_FORK),
-  LOCAL_TEST_CASE(log_one_error, TT_FORK),
-  INTRUSIVE_TEST_CASE(get_error, TT_FORK),
-  LOCAL_TEST_CASE(always_accept_verify_cb, 0),
-  INTRUSIVE_TEST_CASE(x509_cert_free, 0),
   LOCAL_TEST_CASE(x509_cert_get_id_digests, 0),
-  INTRUSIVE_TEST_CASE(cert_matches_key, 0),
-  INTRUSIVE_TEST_CASE(cert_get_key, 0),
-  LOCAL_TEST_CASE(get_my_client_auth_key, TT_FORK),
   LOCAL_TEST_CASE(get_my_certs, TT_FORK),
-  INTRUSIVE_TEST_CASE(get_ciphersuite_name, 0),
-  INTRUSIVE_TEST_CASE(classify_client_ciphers, 0),
-  LOCAL_TEST_CASE(client_is_using_v2_ciphers, 0),
-  INTRUSIVE_TEST_CASE(verify, 0),
-  INTRUSIVE_TEST_CASE(check_lifetime, 0),
-  INTRUSIVE_TEST_CASE(get_pending_bytes, 0),
   LOCAL_TEST_CASE(get_forced_write_size, 0),
-  LOCAL_TEST_CASE(get_write_overhead_ratio, TT_FORK),
   LOCAL_TEST_CASE(used_v1_handshake, TT_FORK),
   LOCAL_TEST_CASE(get_num_server_handshakes, 0),
   LOCAL_TEST_CASE(server_got_renegotiate, 0),
-  INTRUSIVE_TEST_CASE(SSL_SESSION_get_master_key, 0),
-  INTRUSIVE_TEST_CASE(get_tlssecrets, 0),
-  INTRUSIVE_TEST_CASE(get_buffer_sizes, 0),
   LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0),
-  INTRUSIVE_TEST_CASE(try_to_extract_certs_from_tls, 0),
-  INTRUSIVE_TEST_CASE(get_peer_cert, 0),
-  INTRUSIVE_TEST_CASE(peer_has_cert, 0),
-  INTRUSIVE_TEST_CASE(shutdown, 0),
-  INTRUSIVE_TEST_CASE(finish_handshake, 0),
-  INTRUSIVE_TEST_CASE(handshake, 0),
-  INTRUSIVE_TEST_CASE(write, 0),
-  INTRUSIVE_TEST_CASE(read, 0),
-  INTRUSIVE_TEST_CASE(server_info_callback, 0),
-  LOCAL_TEST_CASE(is_server, 0),
-  INTRUSIVE_TEST_CASE(assert_renegotiation_unblocked, 0),
-  INTRUSIVE_TEST_CASE(block_renegotiation, 0),
-  INTRUSIVE_TEST_CASE(unblock_renegotiation, 0),
-  INTRUSIVE_TEST_CASE(set_renegotiate_callback, 0),
-  LOCAL_TEST_CASE(set_logged_address, 0),
-  INTRUSIVE_TEST_CASE(find_cipher_by_id, 0),
-  INTRUSIVE_TEST_CASE(session_secret_cb, 0),
-  INTRUSIVE_TEST_CASE(debug_state_callback, 0),
-  INTRUSIVE_TEST_CASE(context_new, TT_FORK /* redundant */),
-  LOCAL_TEST_CASE(create_certificate, 0),
-  LOCAL_TEST_CASE(cert_new, 0),
-  LOCAL_TEST_CASE(cert_is_valid, 0),
-  LOCAL_TEST_CASE(context_init_one, 0),
   END_OF_TESTCASES
 };
diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c
new file mode 100644
index 000000000..a9336a6f1
--- /dev/null
+++ b/src/test/test_tortls_openssl.c
@@ -0,0 +1,2597 @@
+/* Copyright (c) 2010-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define TORTLS_PRIVATE
+#define TORTLS_OPENSSL_PRIVATE
+#define TOR_X509_PRIVATE
+#define LOG_PRIVATE
+#include "orconfig.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+#include <math.h>
+
+#include "lib/cc/compat_compiler.h"
+
+/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
+ * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/opensslv.h>
+
+#include <openssl/ssl.h>
+#include <openssl/ssl3.h>
+#include <openssl/err.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/bn.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+#include "core/or/or.h"
+#include "lib/log/log.h"
+#include "app/config/config.h"
+#include "lib/crypt_ops/compat_openssl.h"
+#include "lib/tls/x509.h"
+#include "lib/tls/tortls.h"
+#include "lib/tls/tortls_st.h"
+#include "lib/tls/tortls_internal.h"
+#include "app/config/or_state_st.h"
+
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+#define NS_MODULE tortls
+
+#ifndef HAVE_SSL_STATE
+#define OPENSSL_OPAQUE
+#endif
+
+#if defined(OPENSSL_OPAQUE) && !defined(LIBRESSL_VERSION_NUMBER)
+#define SSL_STATE_STR "before SSL initialization"
+#else
+#define SSL_STATE_STR "before/accept initialization"
+#endif
+
+#ifndef OPENSSL_OPAQUE
+static SSL_METHOD *
+give_me_a_test_method(void)
+{
+  SSL_METHOD *method = tor_malloc_zero(sizeof(SSL_METHOD));
+  memcpy(method, TLSv1_method(), sizeof(SSL_METHOD));
+  return method;
+}
+
+static int
+fake_num_ciphers(void)
+{
+  return 0;
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static int
+mock_tls_cert_matches_key(const tor_tls_t *tls, const tor_x509_cert_t *cert)
+{
+  (void) tls;
+  (void) cert; // XXXX look at this.
+  return 1;
+}
+
+static void
+test_tortls_tor_tls_new(void *data)
+{
+  (void) data;
+  MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
+  crypto_pk_t *key1 = NULL, *key2 = NULL;
+  SSL_METHOD *method = NULL;
+
+  key1 = pk_generate(2);
+  key2 = pk_generate(3);
+
+  tor_tls_t *tls = NULL;
+  tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
+                                 key1, key2, 86400), OP_EQ, 0);
+  tls = tor_tls_new(-1, 0);
+  tt_want(tls);
+  tor_tls_free(tls); tls = NULL;
+
+  SSL_CTX_free(client_tls_context->ctx);
+  client_tls_context->ctx = NULL;
+  tls = tor_tls_new(-1, 0);
+  tt_ptr_op(tls, OP_EQ, NULL);
+
+#ifndef OPENSSL_OPAQUE
+  method = give_me_a_test_method();
+  SSL_CTX *ctx = SSL_CTX_new(method);
+  method->num_ciphers = fake_num_ciphers;
+  client_tls_context->ctx = ctx;
+  tls = tor_tls_new(-1, 0);
+  tt_ptr_op(tls, OP_EQ, NULL);
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+ done:
+  UNMOCK(tor_tls_cert_matches_key);
+  crypto_pk_free(key1);
+  crypto_pk_free(key2);
+  tor_tls_free(tls);
+  tor_free(method);
+  tor_tls_free_all();
+}
+
+#define NS_MODULE tortls
+
+static void
+library_init(void)
+{
+#ifdef OPENSSL_1_1_API
+  OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
+#else
+  SSL_library_init();
+  SSL_load_error_strings();
+#endif
+}
+
+static void
+test_tortls_get_state_description(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  char *buf;
+  SSL_CTX *ctx;
+
+  library_init();
+  ctx = SSL_CTX_new(SSLv23_method());
+
+  buf = tor_malloc_zero(1000);
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+
+  tor_tls_get_state_description(NULL, buf, 20);
+  tt_str_op(buf, OP_EQ, "(No SSL object)");
+
+  SSL_free(tls->ssl);
+  tls->ssl = NULL;
+  tor_tls_get_state_description(tls, buf, 20);
+  tt_str_op(buf, OP_EQ, "(No SSL object)");
+
+  tls->ssl = SSL_new(ctx);
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in HANDSHAKE");
+
+  tls->state = TOR_TLS_ST_OPEN;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in OPEN");
+
+  tls->state = TOR_TLS_ST_GOTCLOSE;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in GOTCLOSE");
+
+  tls->state = TOR_TLS_ST_SENTCLOSE;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in SENTCLOSE");
+
+  tls->state = TOR_TLS_ST_CLOSED;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in CLOSED");
+
+  tls->state = TOR_TLS_ST_RENEGOTIATE;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in RENEGOTIATE");
+
+  tls->state = TOR_TLS_ST_BUFFEREVENT;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR);
+
+  tls->state = 7;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, SSL_STATE_STR " in unknown TLS state");
+
+ done:
+  SSL_CTX_free(ctx);
+  SSL_free(tls->ssl);
+  tor_free(buf);
+  tor_free(tls);
+}
+
+static void
+test_tortls_get_by_ssl(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  tor_tls_t *res;
+  SSL_CTX *ctx;
+  SSL *ssl;
+
+  library_init();
+  tor_tls_allocate_tor_tls_object_ex_data_index();
+
+  ctx = SSL_CTX_new(SSLv23_method());
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->magic = TOR_TLS_MAGIC;
+
+  ssl = SSL_new(ctx);
+
+  res = tor_tls_get_by_ssl(ssl);
+  tt_assert(!res);
+
+  SSL_set_ex_data(ssl, tor_tls_object_ex_data_index, tls);
+
+  res = tor_tls_get_by_ssl(ssl);
+  tt_assert(res == tls);
+
+ done:
+  SSL_free(ssl);
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+}
+
+static void
+test_tortls_allocate_tor_tls_object_ex_data_index(void *ignored)
+{
+  (void)ignored;
+  int first;
+
+  tor_tls_allocate_tor_tls_object_ex_data_index();
+
+  first = tor_tls_object_ex_data_index;
+  tor_tls_allocate_tor_tls_object_ex_data_index();
+  tt_int_op(first, OP_EQ, tor_tls_object_ex_data_index);
+
+ done:
+  (void)0;
+}
+
+static void
+test_tortls_log_one_error(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  SSL_CTX *ctx;
+  SSL *ssl = NULL;
+
+  library_init();
+
+  ctx = SSL_CTX_new(SSLv23_method());
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  setup_capture_of_logs(LOG_INFO);
+
+  tor_tls_log_one_error(NULL, 0, LOG_WARN, 0, "something");
+  expect_log_msg("TLS error while something: "
+            "(null) (in (null):(null):---)\n");
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
+  expect_log_msg("TLS error: (null) "
+            "(in (null):(null):---)\n");
+
+  mock_clean_saved_logs();
+  tls->address = tor_strdup("127.hello");
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
+  expect_log_msg("TLS error with 127.hello: "
+            "(null) (in (null):(null):---)\n");
+  tor_free(tls->address);
+
+  mock_clean_saved_logs();
+  tls->address = tor_strdup("127.hello");
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, "blarg");
+  expect_log_msg("TLS error while blarg with "
+            "127.hello: (null) (in (null):(null):---)\n");
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, 3), LOG_WARN, 0, NULL);
+  expect_log_msg("TLS error with 127.hello: "
+            "BN lib (in unknown library:(null):---)\n");
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_HTTP_REQUEST),
+                        LOG_WARN, 0, NULL);
+  expect_log_severity(LOG_INFO);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_HTTPS_PROXY_REQUEST),
+                        LOG_WARN, 0, NULL);
+  expect_log_severity(LOG_INFO);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_LENGTH_MISMATCH),
+                        LOG_WARN, 0, NULL);
+  expect_log_severity(LOG_INFO);
+
+#ifndef OPENSSL_1_1_API
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_TOO_LARGE),
+                        LOG_WARN, 0, NULL);
+  expect_log_severity(LOG_INFO);
+#endif /* !defined(OPENSSL_1_1_API) */
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNKNOWN_PROTOCOL),
+                        LOG_WARN, 0, NULL);
+  expect_log_severity(LOG_INFO);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNSUPPORTED_PROTOCOL),
+                        LOG_WARN, 0, NULL);
+  expect_log_severity(LOG_INFO);
+
+  tls->ssl = SSL_new(ctx);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
+  expect_log_msg("TLS error with 127.hello: (null)"
+            " (in (null):(null):" SSL_STATE_STR ")\n");
+
+ done:
+  teardown_capture_of_logs();
+  SSL_free(ssl);
+  SSL_CTX_free(ctx);
+  if (tls && tls->ssl)
+    SSL_free(tls->ssl);
+  if (tls)
+    tor_free(tls->address);
+  tor_free(tls);
+}
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_get_error(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  int ret;
+  SSL_CTX *ctx;
+
+  library_init();
+
+  ctx = SSL_CTX_new(SSLv23_method());
+  setup_capture_of_logs(LOG_INFO);
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = SSL_new(ctx);
+  SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL);
+
+  ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_IO);
+  expect_log_msg("TLS error: unexpected close while"
+            " something (before/accept initialization)\n");
+
+  mock_clean_saved_logs();
+  ret = tor_tls_get_error(tls, 2, 0, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, 0);
+  expect_no_log_entry();
+
+  mock_clean_saved_logs();
+  ret = tor_tls_get_error(tls, 0, 1, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, -11);
+  expect_no_log_entry();
+
+  mock_clean_saved_logs();
+  ERR_clear_error();
+  ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99);
+  ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+  expect_log_msg("TLS error while something: (null)"
+            " (in bignum routines:(null):before/accept initialization)\n");
+
+  mock_clean_saved_logs();
+  ERR_clear_error();
+  tls->ssl->rwstate = SSL_READING;
+  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_READ;
+  ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, TOR_TLS_WANTREAD);
+  expect_no_log_entry();
+
+  mock_clean_saved_logs();
+  ERR_clear_error();
+  tls->ssl->rwstate = SSL_READING;
+  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_WRITE;
+  ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, TOR_TLS_WANTWRITE);
+  expect_no_log_entry();
+
+  mock_clean_saved_logs();
+  ERR_clear_error();
+  tls->ssl->rwstate = 0;
+  tls->ssl->shutdown = SSL_RECEIVED_SHUTDOWN;
+  tls->ssl->s3->warn_alert =SSL_AD_CLOSE_NOTIFY;
+  ret = tor_tls_get_error(tls, 0, 0, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, TOR_TLS_CLOSE);
+  expect_log_entry();
+
+  mock_clean_saved_logs();
+  ret = tor_tls_get_error(tls, 0, 2, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, -10);
+  expect_no_log_entry();
+
+  mock_clean_saved_logs();
+  ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99);
+  ret = tor_tls_get_error(tls, -1, 0, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, -9);
+  expect_log_msg("TLS error while something: (null) (in system library:"
+            "connect:before/accept initialization)\n");
+
+ done:
+  teardown_capture_of_logs();
+  SSL_free(tls->ssl);
+  tor_free(tls);
+  SSL_CTX_free(ctx);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static void
+test_tortls_always_accept_verify_cb(void *ignored)
+{
+  (void)ignored;
+  int ret;
+
+  ret = always_accept_verify_cb(0, NULL);
+  tt_int_op(ret, OP_EQ, 1);
+
+ done:
+  (void)0;
+}
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_x509_cert_free(void *ignored)
+{
+  (void)ignored;
+  tor_x509_cert_t *cert;
+
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  tor_x509_cert_free(cert);
+
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  cert->cert = X509_new();
+  cert->encoded = tor_malloc_zero(1);
+  tor_x509_cert_free(cert);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static int
+fixed_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
+{
+  (void) a; (void) b;
+  return 1;
+}
+
+/*
+ * Use only for the matching fake_x509_free() call
+ */
+static X509 *
+fake_x509_malloc(void)
+{
+  return tor_malloc_zero(sizeof(X509));
+}
+
+static void
+fake_x509_free(X509 *cert)
+{
+  if (cert) {
+    if (cert->cert_info) {
+      if (cert->cert_info->key) {
+        if (cert->cert_info->key->pkey) {
+          tor_free(cert->cert_info->key->pkey);
+        }
+        tor_free(cert->cert_info->key);
+      }
+      tor_free(cert->cert_info);
+    }
+    tor_free(cert);
+  }
+}
+
+static void
+test_tortls_cert_matches_key(void *ignored)
+{
+  (void)ignored;
+  int res;
+  tor_tls_t *tls;
+  tor_x509_cert_t *cert;
+  X509 *one = NULL, *two = NULL;
+  EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_new(999, 0, NULL, NULL);
+  EVP_PKEY_asn1_set_public(meth, NULL, NULL, fixed_pub_cmp, NULL, NULL, NULL);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  one = fake_x509_malloc();
+  one->references = 1;
+  two = fake_x509_malloc();
+  two->references = 1;
+
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+  tls->ssl->session->peer = one;
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  cert->cert = two;
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  one->cert_info = tor_malloc_zero(sizeof(X509_CINF));
+  one->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
+  one->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
+  one->cert_info->key->pkey->references = 1;
+  one->cert_info->key->pkey->ameth = meth;
+  one->cert_info->key->pkey->type = 1;
+
+  two->cert_info = tor_malloc_zero(sizeof(X509_CINF));
+  two->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
+  two->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
+  two->cert_info->key->pkey->references = 1;
+  two->cert_info->key->pkey->ameth = meth;
+  two->cert_info->key->pkey->type = 2;
+
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  one->cert_info->key->pkey->type = 1;
+  two->cert_info->key->pkey->type = 1;
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 1);
+
+ done:
+  EVP_PKEY_asn1_free(meth);
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  tor_free(cert);
+  fake_x509_free(one);
+  fake_x509_free(two);
+}
+
+static void
+test_tortls_cert_get_key(void *ignored)
+{
+  (void)ignored;
+  tor_x509_cert_t *cert = NULL;
+  crypto_pk_t *res = NULL;
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  X509 *key = NULL;
+  key = fake_x509_malloc();
+  key->references = 1;
+
+  res = tor_tls_cert_get_key(cert);
+  tt_assert(!res);
+
+  cert->cert = key;
+  key->cert_info = tor_malloc_zero(sizeof(X509_CINF));
+  key->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
+  key->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
+  key->cert_info->key->pkey->references = 1;
+  key->cert_info->key->pkey->type = 2;
+  res = tor_tls_cert_get_key(cert);
+  tt_assert(!res);
+
+ done:
+  fake_x509_free(key);
+  tor_free(cert);
+  crypto_pk_free(res);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static void
+test_tortls_get_my_client_auth_key(void *ignored)
+{
+  (void)ignored;
+  crypto_pk_t *ret;
+  crypto_pk_t *expected;
+  tor_tls_context_t *ctx;
+  RSA *k = RSA_new();
+
+  ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
+  expected = crypto_new_pk_from_openssl_rsa_(k);
+  ctx->auth_key = expected;
+
+  client_tls_context = NULL;
+  ret = tor_tls_get_my_client_auth_key();
+  tt_assert(!ret);
+
+  client_tls_context = ctx;
+  ret = tor_tls_get_my_client_auth_key();
+  tt_assert(ret == expected);
+
+ done:
+  tor_free(expected);
+  tor_free(ctx);
+}
+
+#ifndef HAVE_SSL_GET_CLIENT_CIPHERS
+static SSL_CIPHER *
+get_cipher_by_name(const char *name)
+{
+  int i;
+  const SSL_METHOD *method = SSLv23_method();
+  int num = method->num_ciphers();
+
+  for (i = 0; i < num; ++i) {
+    const SSL_CIPHER *cipher = method->get_cipher(i);
+    const char *ciphername = SSL_CIPHER_get_name(cipher);
+    if (!strcmp(ciphername, name)) {
+      return (SSL_CIPHER *)cipher;
+    }
+  }
+
+  return NULL;
+}
+#endif /* !defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_get_ciphersuite_name(void *ignored)
+{
+  (void)ignored;
+  const char *ret;
+  tor_tls_t *ctx;
+  ctx = tor_malloc_zero(sizeof(tor_tls_t));
+  ctx->ssl = tor_malloc_zero(sizeof(SSL));
+
+  ret = tor_tls_get_ciphersuite_name(ctx);
+  tt_str_op(ret, OP_EQ, "(NONE)");
+
+ done:
+  tor_free(ctx->ssl);
+  tor_free(ctx);
+}
+
+static SSL_CIPHER *
+get_cipher_by_id(uint16_t id)
+{
+  int i;
+  const SSL_METHOD *method = SSLv23_method();
+  int num = method->num_ciphers();
+  for (i = 0; i < num; ++i) {
+    const SSL_CIPHER *cipher = method->get_cipher(i);
+    if (id == (SSL_CIPHER_get_id(cipher) & 0xffff)) {
+      return (SSL_CIPHER *)cipher;
+    }
+  }
+
+  return NULL;
+}
+
+static void
+test_tortls_classify_client_ciphers(void *ignored)
+{
+  (void)ignored;
+  int i;
+  int ret;
+  SSL_CTX *ctx;
+  SSL *ssl;
+  tor_tls_t *tls;
+  STACK_OF(SSL_CIPHER) *ciphers;
+  SSL_CIPHER *tmp_cipher;
+
+  library_init();
+
+  tor_tls_allocate_tor_tls_object_ex_data_index();
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->magic = TOR_TLS_MAGIC;
+
+  ctx = SSL_CTX_new(TLSv1_method());
+  ssl = SSL_new(ctx);
+  tls->ssl = ssl;
+
+  ciphers = sk_SSL_CIPHER_new_null();
+
+  ret = tor_tls_classify_client_ciphers(ssl, NULL);
+  tt_int_op(ret, OP_EQ, -1);
+
+  SSL_set_ex_data(ssl, tor_tls_object_ex_data_index, tls);
+  tls->client_cipher_list_type = 42;
+
+  ret = tor_tls_classify_client_ciphers(ssl, NULL);
+  tt_int_op(ret, OP_EQ, 42);
+
+  tls->client_cipher_list_type = 0;
+  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
+  tt_int_op(ret, OP_EQ, 1);
+  tt_int_op(tls->client_cipher_list_type, OP_EQ, 1);
+
+  tls->client_cipher_list_type = 0;
+  ret = tor_tls_classify_client_ciphers(ssl, SSL_get_ciphers(ssl));
+  tt_int_op(ret, OP_EQ, 3);
+  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
+
+  SSL_CIPHER *one = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_128_SHA),
+    *two = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA),
+    *three = get_cipher_by_name(SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA),
+    *four = NULL;
+  sk_SSL_CIPHER_push(ciphers, one);
+  sk_SSL_CIPHER_push(ciphers, two);
+  sk_SSL_CIPHER_push(ciphers, three);
+  sk_SSL_CIPHER_push(ciphers, four);
+
+  tls->client_cipher_list_type = 0;
+  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
+  tt_int_op(ret, OP_EQ, 1);
+  tt_int_op(tls->client_cipher_list_type, OP_EQ, 1);
+
+  sk_SSL_CIPHER_zero(ciphers);
+
+  one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
+  tt_assert(one);
+  one->id = 0x00ff;
+  two = get_cipher_by_name("ECDHE-RSA-AES128-GCM-SHA256");
+  tt_assert(two);
+  two->id = 0x0000;
+  sk_SSL_CIPHER_push(ciphers, one);
+  tls->client_cipher_list_type = 0;
+  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
+  tt_int_op(ret, OP_EQ, 3);
+  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
+
+  sk_SSL_CIPHER_push(ciphers, two);
+  tls->client_cipher_list_type = 0;
+  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
+  tt_int_op(ret, OP_EQ, 3);
+  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
+
+  one->id = 0xC00A;
+  tls->client_cipher_list_type = 0;
+  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
+  tt_int_op(ret, OP_EQ, 3);
+  tt_int_op(tls->client_cipher_list_type, OP_EQ, 3);
+
+  sk_SSL_CIPHER_zero(ciphers);
+  for (i=0; v2_cipher_list[i]; i++) {
+    tmp_cipher = get_cipher_by_id(v2_cipher_list[i]);
+    tt_assert(tmp_cipher);
+    sk_SSL_CIPHER_push(ciphers, tmp_cipher);
+  }
+  tls->client_cipher_list_type = 0;
+  ret = tor_tls_classify_client_ciphers(ssl, ciphers);
+  tt_int_op(ret, OP_EQ, 2);
+  tt_int_op(tls->client_cipher_list_type, OP_EQ, 2);
+
+ done:
+  sk_SSL_CIPHER_free(ciphers);
+  SSL_free(tls->ssl);
+  tor_free(tls);
+  SSL_CTX_free(ctx);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static void
+test_tortls_client_is_using_v2_ciphers(void *ignored)
+{
+  (void)ignored;
+
+#ifdef HAVE_SSL_GET_CLIENT_CIPHERS
+  tt_skip();
+ done:
+  (void)1;
+#else
+  int ret;
+  SSL_CTX *ctx;
+  SSL *ssl;
+  SSL_SESSION *sess;
+  STACK_OF(SSL_CIPHER) *ciphers;
+
+  library_init();
+
+  ctx = SSL_CTX_new(TLSv1_method());
+  ssl = SSL_new(ctx);
+  sess = SSL_SESSION_new();
+
+  ret = tor_tls_client_is_using_v2_ciphers(ssl);
+  tt_int_op(ret, OP_EQ, -1);
+
+  ssl->session = sess;
+  ret = tor_tls_client_is_using_v2_ciphers(ssl);
+  tt_int_op(ret, OP_EQ, 0);
+
+  ciphers = sk_SSL_CIPHER_new_null();
+  SSL_CIPHER *one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
+  tt_assert(one);
+  one->id = 0x00ff;
+  sk_SSL_CIPHER_push(ciphers, one);
+  sess->ciphers = ciphers;
+  ret = tor_tls_client_is_using_v2_ciphers(ssl);
+  tt_int_op(ret, OP_EQ, 1);
+ done:
+  SSL_free(ssl);
+  SSL_CTX_free(ctx);
+#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
+}
+
+#ifndef OPENSSL_OPAQUE
+static X509 *fixed_try_to_extract_certs_from_tls_cert_out_result = NULL;
+static X509 *fixed_try_to_extract_certs_from_tls_id_cert_out_result = NULL;
+
+static void
+fixed_try_to_extract_certs_from_tls(int severity, tor_tls_t *tls,
+                                    tor_x509_cert_impl_t **cert_out,
+                                    tor_x509_cert_impl_t **id_cert_out)
+{
+  (void) severity;
+  (void) tls;
+  *cert_out = fixed_try_to_extract_certs_from_tls_cert_out_result;
+  *id_cert_out = fixed_try_to_extract_certs_from_tls_id_cert_out_result;
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static const char* notCompletelyValidCertString =
+  "-----BEGIN CERTIFICATE-----\n"
+  "MIICVjCCAb8CAg37MA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG\n"
+  "A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE\n"
+  "MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl\n"
+  "YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw\n"
+  "ODIyMDUyNzIzWhcNMTcwODIxMDUyNzIzWjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE\n"
+  "CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs\n"
+  "ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYBBrx5PlP0WNI/ZdzD\n"
+  "+6Pktmurn+F2kQYbtc7XQh8/LTBvCo+P6iZoLEmUA9e7EXLRxgU1CVqeAi7QcAn9\n"
+  "MwBlc8ksFJHB0rtf9pmf8Oza9E0Bynlq/4/Kb1x+d+AyhL7oK9tQwB24uHOueHi1\n"
+  "C/iVv8CSWKiYe6hzN1txYe8rAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAASPdjigJ\n"
+  "kXCqKWpnZ/Oc75EUcMi6HztaW8abUMlYXPIgkV2F7YanHOB7K4f7OOLjiz8DTPFf\n"
+  "jC9UeuErhaA/zzWi8ewMTFZW/WshOrm3fNvcMrMLKtH534JKvcdMg6qIdjTFINIr\n"
+  "evnAhf0cwULaebn+lMs8Pdl7y37+sfluVok=\n"
+  "-----END CERTIFICATE-----\n";
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static const char* validCertString = "-----BEGIN CERTIFICATE-----\n"
+  "MIIDpTCCAY0CAg3+MA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMREwDwYD\n"
+  "VQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIGA1UECgwLVG9yIFRl\n"
+  "c3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkwNjEzMzk1OVoXDTQz\n"
+  "MDEyMjEzMzk1OVowVjELMAkGA1UEBhMCVVMxEDAOBgNVBAcMB0NoaWNhZ28xFDAS\n"
+  "BgNVBAoMC1RvciBUZXN0aW5nMR8wHQYDVQQDDBZ0ZXN0aW5nLnRvcnByb2plY3Qu\n"
+  "b3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoT6uyVVhWyOF3wkHjjYbd\n"
+  "nKaykyRv4JVtKQdZ4OpEErmX1zw4MmyzpQNV6iR4bQnWiyLfzyVJMZDIC/WILBfX\n"
+  "w2Pza/yuLgUvDc3twMuhOACzOQVO8PrEF/aVv2+hbCCy2udXvKhnYn+CCXl3ozc8\n"
+  "XcKYvujTXDyvGWY3xwAjlQIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQCUvnhzQWuQ\n"
+  "MrN+pERkE+zcTI/9dGS90rUMMLgu8VDNqTa0TUQh8uO0EQ6uDvI8Js6e8tgwS0BR\n"
+  "UBahqb7ZHv+rejGCBr5OudqD+x4STiiuPNJVs86JTLN8SpM9CHjIBH5WCCN2KOy3\n"
+  "mevNoRcRRyYJzSFULCunIK6FGulszigMYGscrO4oiTkZiHPh9KvWT40IMiHfL+Lw\n"
+  "EtEWiLex6064LcA2YQ1AMuSZyCexks63lcfaFmQbkYOKqXa1oLkIRuDsOaSVjTfe\n"
+  "vec+X6jvf12cFTKS5WIeqkKF2Irt+dJoiHEGTe5RscUMN/f+gqHPzfFz5dR23sxo\n"
+  "g+HC6MZHlFkLAOx3wW6epPS8A/m1mw3zMPoTnb2U2YYt8T0dJMMlUn/7Y1sEAa+a\n"
+  "dSTMaeUf6VnJ//11m454EZl1to9Z7oJOgqmFffSrdD4BGIWe8f7hhW6L1Enmqe/J\n"
+  "BKL3wbzZh80O1W0bndAwhnEEhlzneFY84cbBo9pmVxpODHkUcStpr5Z7pBDrcL21\n"
+  "Ss/aB/1YrsVXhdvJdOGxl3Mnl9dUY57CympLGlT8f0pPS6GAKOelECOhFMHmJd8L\n"
+  "dj3XQSmKtYHevZ6IvuMXSlB/fJvSjSlkCuLo5+kJoaqPuRu+i/S1qxeRy3CBwmnE\n"
+  "LdSNdcX4N79GQJ996PA8+mUCQG7YRtK+WA==\n"
+  "-----END CERTIFICATE-----\n";
+
+static const char* caCertString = "-----BEGIN CERTIFICATE-----\n"
+  "MIIFjzCCA3egAwIBAgIJAKd5WgyfPMYRMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV\n"
+  "BAYTAlVTMREwDwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIG\n"
+  "A1UECgwLVG9yIFRlc3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkw\n"
+  "NjEzMzc0MVoXDTQzMDEyMjEzMzc0MVowXjELMAkGA1UEBhMCVVMxETAPBgNVBAgM\n"
+  "CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRQwEgYDVQQKDAtUb3IgVGVzdGlu\n"
+  "ZzEUMBIGA1UEAwwLVG9yIFRlc3RpbmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n"
+  "ggIKAoICAQCpLMUEiLW5leUgBZoEJms2V7lZRhIAjnJBhVMHD0e3UubNknmaQoxf\n"
+  "ARz3rvqOaRd0JlV+qM9qE0DjiYcCVP1cAfqAo9d83uS1vwY3YMVJzADlaIiHfyVW\n"
+  "uEgBy0vvkeUBqaua24dYlcwsemOiXYLu41yM1wkcGHW1AhBNHppY6cznb8TyLgNM\n"
+  "2x3SGUdzc5XMyAFx51faKGBA3wjs+Hg1PLY7d30nmCgEOBavpm5I1disM/0k+Mcy\n"
+  "YmAKEo/iHJX/rQzO4b9znP69juLlR8PDBUJEVIG/CYb6+uw8MjjUyiWXYoqfVmN2\n"
+  "hm/lH8b6rXw1a2Aa3VTeD0DxaWeacMYHY/i01fd5n7hCoDTRNdSw5KJ0L3Z0SKTu\n"
+  "0lzffKzDaIfyZGlpW5qdouACkWYzsaitQOePVE01PIdO30vUfzNTFDfy42ccx3Di\n"
+  "59UCu+IXB+eMtrBfsok0Qc63vtF1linJgjHW1z/8ujk8F7/qkOfODhk4l7wngc2A\n"
+  "EmwWFIFoGaiTEZHB9qteXr4unbXZ0AHpM02uGGwZEGohjFyebEb73M+J57WKKAFb\n"
+  "PqbLcGUksL1SHNBNAJcVLttX55sO4nbidOS/kA3m+F1R04MBTyQF9qA6YDDHqdI3\n"
+  "h/3pw0Z4fxVouTYT4/NfRnX4JTP4u+7Mpcoof28VME0qWqD1LnRhFQIDAQABo1Aw\n"
+  "TjAdBgNVHQ4EFgQUMoAgIXH7pZ3QMRwTjT+DM9Yo/v0wHwYDVR0jBBgwFoAUMoAg\n"
+  "IXH7pZ3QMRwTjT+DM9Yo/v0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
+  "AgEAUJxacjXR9sT+Xs6ISFiUsyd0T6WVKMnV46xrYJHirGfx+krWHrjxMY+ZtxYD\n"
+  "DBDGlo11Qc4v6QrclNf5QUBfIiGQsP9Cm6hHcQ+Tpg9HHCgSqG1YNPwCPReCR4br\n"
+  "BLvLfrfkcBL2IWM0PdQdCze+59DBfipsULD2mEn9fjYRXQEwb2QWtQ9qRc20Yb/x\n"
+  "Q4b/+CvUodLkaq7B8MHz0BV8HHcBoph6DYaRmO/N+hPauIuSp6XyaGYcEefGKVKj\n"
+  "G2+fcsdyXsoijNdL8vNKwm4j2gVwCBnw16J00yfFoV46YcbfqEdJB2je0XSvwXqt\n"
+  "14AOTngxso2h9k9HLtrfpO1ZG/B5AcCMs1lzbZ2fp5DPHtjvvmvA2RJqgo3yjw4W\n"
+  "4DHAuTglYFlC3mDHNfNtcGP20JvepcQNzNP2UzwcpOc94hfKikOFw+gf9Vf1qd0y\n"
+  "h/Sk6OZHn2+JVUPiWHIQV98Vtoh4RmUZDJD+b55ia3fQGTGzt4z1XFzQYSva5sfs\n"
+  "wocS/papthqWldQU7x+3wofNd5CNU1x6WKXG/yw30IT/4F8ADJD6GeygNT8QJYvt\n"
+  "u/8lAkbOy6B9xGmSvr0Kk1oq9P2NshA6kalxp1Oz/DTNDdL4AeBXV3JmM6WWCjGn\n"
+  "Yy1RT69d0rwYc5u/vnqODz1IjvT90smsrkBumGt791FAFeg=\n"
+  "-----END CERTIFICATE-----\n";
+
+static X509 *
+read_cert_from(const char *str)
+{
+  BIO *bio = BIO_new(BIO_s_mem());
+  BIO_write(bio, str, (int) strlen(str));
+  X509 *res = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+  BIO_free(bio);
+  return res;
+}
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_verify(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  crypto_pk_t *k = NULL;
+  X509 *cert1 = NULL, *cert2 = NULL, *invalidCert = NULL,
+    *validCert = NULL, *caCert = NULL;
+
+  cert1 = tor_malloc_zero(sizeof(X509));
+  cert1->references = 10;
+
+  cert2 = tor_malloc_zero(sizeof(X509));
+  cert2->references = 10;
+
+  validCert = read_cert_from(validCertString);
+  caCert = read_cert_from(caCertString);
+  invalidCert = read_cert_from(notCompletelyValidCertString);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  MOCK(try_to_extract_certs_from_tls, fixed_try_to_extract_certs_from_tls);
+
+  fixed_try_to_extract_certs_from_tls_cert_out_result = cert1;
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  fixed_try_to_extract_certs_from_tls_id_cert_out_result = cert2;
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  fixed_try_to_extract_certs_from_tls_cert_out_result = invalidCert;
+  fixed_try_to_extract_certs_from_tls_id_cert_out_result = invalidCert;
+
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  fixed_try_to_extract_certs_from_tls_cert_out_result = validCert;
+  fixed_try_to_extract_certs_from_tls_id_cert_out_result = caCert;
+
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_assert(k);
+
+ done:
+  UNMOCK(try_to_extract_certs_from_tls);
+  tor_free(cert1);
+  tor_free(cert2);
+  tor_free(tls);
+  tor_free(k);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_check_lifetime(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  X509 *validCert = read_cert_from(validCertString);
+  time_t now = time(NULL);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
+  tt_int_op(ret, OP_EQ, -1);
+
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+  tls->ssl->session->peer = validCert;
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+  ASN1_STRING_free(validCert->cert_info->validity->notBefore);
+  validCert->cert_info->validity->notBefore = ASN1_TIME_set(NULL, now-10);
+  ASN1_STRING_free(validCert->cert_info->validity->notAfter);
+  validCert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, now+60);
+
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, -1000);
+  tt_int_op(ret, OP_EQ, -1);
+
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), -1000, 0);
+  tt_int_op(ret, OP_EQ, -1);
+
+ done:
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  X509_free(validCert);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static int fixed_ssl_pending_result = 0;
+
+static int
+fixed_ssl_pending(const SSL *ignored)
+{
+  (void)ignored;
+  return fixed_ssl_pending_result;
+}
+
+static void
+test_tortls_get_pending_bytes(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  SSL_METHOD *method;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  method = tor_malloc_zero(sizeof(SSL_METHOD));
+  method->ssl_pending = fixed_ssl_pending;
+  tls->ssl->method = method;
+
+  fixed_ssl_pending_result = 42;
+  ret = tor_tls_get_pending_bytes(tls);
+  tt_int_op(ret, OP_EQ, 42);
+
+ done:
+  tor_free(method);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_SSL_SESSION_get_master_key(void *ignored)
+{
+  (void)ignored;
+  size_t ret;
+  tor_tls_t *tls;
+  uint8_t *out;
+  out = tor_malloc_zero(1);
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+  tls->ssl->session->master_key_length = 1;
+
+#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
+  tls->ssl->session->master_key[0] = 43;
+  ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 0);
+  tt_int_op(ret, OP_EQ, 1);
+  tt_int_op(out[0], OP_EQ, 0);
+
+  ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 1);
+  tt_int_op(ret, OP_EQ, 1);
+  tt_int_op(out[0], OP_EQ, 43);
+
+ done:
+#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  tor_free(out);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_get_tlssecrets(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  uint8_t *secret_out = tor_malloc_zero(DIGEST256_LEN);
+  tor_tls_t *tls;
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+  tls->ssl->session->master_key_length = 1;
+  tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE));
+
+  ret = tor_tls_get_tlssecrets(tls, secret_out);
+  tt_int_op(ret, OP_EQ, 0);
+
+ done:
+  tor_free(secret_out);
+  tor_free(tls->ssl->s3);
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_get_buffer_sizes(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  size_t rbuf_c=-1, rbuf_b=-1, wbuf_c=-1, wbuf_b=-1;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE));
+
+  tls->ssl->s3->rbuf.buf = NULL;
+  tls->ssl->s3->rbuf.len = 1;
+  tls->ssl->s3->rbuf.offset = 0;
+  tls->ssl->s3->rbuf.left = 42;
+
+  tls->ssl->s3->wbuf.buf = NULL;
+  tls->ssl->s3->wbuf.len = 2;
+  tls->ssl->s3->wbuf.offset = 0;
+  tls->ssl->s3->wbuf.left = 43;
+
+  ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b);
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+  tt_int_op(ret, OP_EQ, -1);
+#else
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(rbuf_c, OP_EQ, 0);
+  tt_int_op(wbuf_c, OP_EQ, 0);
+  tt_int_op(rbuf_b, OP_EQ, 42);
+  tt_int_op(wbuf_b, OP_EQ, 43);
+
+  tls->ssl->s3->rbuf.buf = tor_malloc_zero(1);
+  tls->ssl->s3->wbuf.buf = tor_malloc_zero(1);
+  ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(rbuf_c, OP_EQ, 1);
+  tt_int_op(wbuf_c, OP_EQ, 2);
+
+#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
+
+ done:
+  tor_free(tls->ssl->s3->rbuf.buf);
+  tor_free(tls->ssl->s3->wbuf.buf);
+  tor_free(tls->ssl->s3);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+typedef struct cert_pkey_st_local
+{
+  X509 *x509;
+  EVP_PKEY *privatekey;
+  const EVP_MD *digest;
+} CERT_PKEY_local;
+
+typedef struct sess_cert_st_local
+{
+  STACK_OF(X509) *cert_chain;
+  int peer_cert_type;
+  CERT_PKEY_local *peer_key;
+  CERT_PKEY_local peer_pkeys[8];
+  int references;
+} SESS_CERT_local;
+
+static void
+test_tortls_try_to_extract_certs_from_tls(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  X509 *cert = NULL, *id_cert = NULL, *c1 = NULL, *c2 = NULL;
+  SESS_CERT_local *sess = NULL;
+
+  c1 = read_cert_from(validCertString);
+  c2 = read_cert_from(caCertString);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+  sess = tor_malloc_zero(sizeof(SESS_CERT_local));
+  tls->ssl->session->sess_cert = (void *)sess;
+
+  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
+  tt_assert(!cert);
+  tt_assert(!id_cert);
+
+  tls->ssl->session->peer = c1;
+  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
+  tt_assert(cert == c1);
+  tt_assert(!id_cert);
+  X509_free(cert); /* decrease refcnt */
+
+  sess->cert_chain = sk_X509_new_null();
+  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
+  tt_assert(cert == c1);
+  tt_assert(!id_cert);
+  X509_free(cert); /* decrease refcnt */
+
+  sk_X509_push(sess->cert_chain, c1);
+  sk_X509_push(sess->cert_chain, c2);
+
+  try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert);
+  tt_assert(cert == c1);
+  tt_assert(id_cert);
+  X509_free(cert); /* decrease refcnt */
+
+ done:
+  sk_X509_free(sess->cert_chain);
+  tor_free(sess);
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  X509_free(c1);
+  X509_free(c2);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_get_peer_cert(void *ignored)
+{
+  (void)ignored;
+  tor_x509_cert_t *ret;
+  tor_tls_t *tls;
+  X509 *cert = NULL;
+
+  cert = read_cert_from(validCertString);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+
+  ret = tor_tls_get_peer_cert(tls);
+  tt_assert(!ret);
+
+  tls->ssl->session->peer = cert;
+  ret = tor_tls_get_peer_cert(tls);
+  tt_assert(ret);
+  tt_assert(ret->cert == cert);
+
+ done:
+  tor_x509_cert_free(ret);
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  X509_free(cert);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_peer_has_cert(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  X509 *cert = NULL;
+
+  cert = read_cert_from(validCertString);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+
+  ret = tor_tls_peer_has_cert(tls);
+  tt_assert(!ret);
+
+  tls->ssl->session->peer = cert;
+  ret = tor_tls_peer_has_cert(tls);
+  tt_assert(ret);
+
+ done:
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  X509_free(cert);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static void
+test_tortls_get_write_overhead_ratio(void *ignored)
+{
+  (void)ignored;
+  double ret;
+
+  total_bytes_written_over_tls = 0;
+  ret = tls_get_write_overhead_ratio();
+  tt_double_op(fabs(ret - 1.0), OP_LT, 1E-12);
+
+  total_bytes_written_by_tls = 10;
+  total_bytes_written_over_tls = 1;
+  ret = tls_get_write_overhead_ratio();
+  tt_double_op(fabs(ret - 10.0), OP_LT, 1E-12);
+
+  total_bytes_written_by_tls = 10;
+  total_bytes_written_over_tls = 2;
+  ret = tls_get_write_overhead_ratio();
+  tt_double_op(fabs(ret - 5.0), OP_LT, 1E-12);
+
+ done:
+  (void)0;
+}
+
+static void
+test_tortls_is_server(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  int ret;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->isServer = 1;
+  ret = tor_tls_is_server(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+ done:
+  tor_free(tls);
+}
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_session_secret_cb(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  SSL_CTX *ctx;
+  STACK_OF(SSL_CIPHER) *ciphers = NULL;
+  SSL_CIPHER *one;
+
+  library_init();
+
+  tor_tls_allocate_tor_tls_object_ex_data_index();
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+
+  tls->magic = TOR_TLS_MAGIC;
+
+  ctx = SSL_CTX_new(TLSv1_method());
+  tls->ssl = SSL_new(ctx);
+  SSL_set_ex_data(tls->ssl, tor_tls_object_ex_data_index, tls);
+
+  SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
+
+  tor_tls_session_secret_cb(tls->ssl, NULL, NULL, NULL, NULL, NULL);
+  tt_assert(!tls->ssl->tls_session_secret_cb);
+
+  one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384");
+  one->id = 0x00ff;
+  ciphers = sk_SSL_CIPHER_new_null();
+  sk_SSL_CIPHER_push(ciphers, one);
+
+  tls->client_cipher_list_type = 0;
+  tor_tls_session_secret_cb(tls->ssl, NULL, NULL, ciphers, NULL, NULL);
+  tt_assert(!tls->ssl->tls_session_secret_cb);
+
+ done:
+  sk_SSL_CIPHER_free(ciphers);
+  SSL_free(tls->ssl);
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+/* TODO: It seems block_renegotiation and unblock_renegotiation and
+ * using different blags. This might not be correct */
+static void
+test_tortls_block_renegotiation(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE));
+#ifndef SUPPORT_UNSAFE_RENEGOTIATION_FLAG
+#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0
+#endif
+
+  tls->ssl->s3->flags = SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+
+  tor_tls_block_renegotiation(tls);
+
+#ifndef OPENSSL_1_1_API
+  tt_assert(!(tls->ssl->s3->flags &
+              SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
+#endif
+
+ done:
+  tor_free(tls->ssl->s3);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+static void
+test_tortls_unblock_renegotiation(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tor_tls_unblock_renegotiation(tls);
+
+  tt_uint_op(SSL_get_options(tls->ssl) &
+             SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, OP_EQ,
+             SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
+
+ done:
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_assert_renegotiation_unblocked(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tor_tls_unblock_renegotiation(tls);
+  tor_tls_assert_renegotiation_unblocked(tls);
+  /* No assertion here - this test will fail if tor_assert is turned on
+   * and things are bad. */
+
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static void
+test_tortls_set_logged_address(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+
+  tor_tls_set_logged_address(tls, "foo bar");
+
+  tt_str_op(tls->address, OP_EQ, "foo bar");
+
+  tor_tls_set_logged_address(tls, "foo bar 2");
+  tt_str_op(tls->address, OP_EQ, "foo bar 2");
+
+ done:
+  tor_free(tls->address);
+  tor_free(tls);
+}
+
+#ifndef OPENSSL_OPAQUE
+static void
+example_cb(tor_tls_t *t, void *arg)
+{
+  (void)t;
+  (void)arg;
+}
+
+static void
+test_tortls_set_renegotiate_callback(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  const char *arg = "hello";
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+
+  tor_tls_set_renegotiate_callback(tls, example_cb, (void*)arg);
+  tt_assert(tls->negotiated_callback == example_cb);
+  tt_assert(tls->callback_arg == arg);
+  tt_assert(!tls->got_renegotiate);
+
+  /* Assumes V2_HANDSHAKE_SERVER */
+  tt_assert(tls->ssl->info_callback == tor_tls_server_info_callback);
+
+  tor_tls_set_renegotiate_callback(tls, NULL, (void*)arg);
+  tt_assert(tls->ssl->info_callback == tor_tls_debug_state_callback);
+
+ done:
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static SSL_CIPHER *fixed_cipher1 = NULL;
+static SSL_CIPHER *fixed_cipher2 = NULL;
+static const SSL_CIPHER *
+fake_get_cipher(unsigned ncipher)
+{
+
+  switch (ncipher) {
+  case 1:
+    return fixed_cipher1;
+  case 2:
+    return fixed_cipher2;
+  default:
+    return NULL;
+  }
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_find_cipher_by_id(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  SSL *ssl;
+  SSL_CTX *ctx;
+  const SSL_METHOD *m = TLSv1_method();
+  SSL_METHOD *empty_method = tor_malloc_zero(sizeof(SSL_METHOD));
+
+  fixed_cipher1 = tor_malloc_zero(sizeof(SSL_CIPHER));
+  fixed_cipher2 = tor_malloc_zero(sizeof(SSL_CIPHER));
+  fixed_cipher2->id = 0xC00A;
+
+  library_init();
+
+  ctx = SSL_CTX_new(m);
+  ssl = SSL_new(ctx);
+
+  ret = find_cipher_by_id(ssl, NULL, 0xC00A);
+  tt_int_op(ret, OP_EQ, 1);
+
+  ret = find_cipher_by_id(ssl, m, 0xC00A);
+  tt_int_op(ret, OP_EQ, 1);
+
+  ret = find_cipher_by_id(ssl, m, 0xFFFF);
+  tt_int_op(ret, OP_EQ, 0);
+
+  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
+  tt_int_op(ret, OP_EQ, 1);
+
+  ret = find_cipher_by_id(ssl, empty_method, 0xFFFF);
+#ifdef HAVE_SSL_CIPHER_FIND
+  tt_int_op(ret, OP_EQ, 0);
+#else
+  tt_int_op(ret, OP_EQ, 1);
+#endif
+
+  empty_method->get_cipher = fake_get_cipher;
+  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
+  tt_int_op(ret, OP_EQ, 1);
+
+  empty_method->get_cipher = m->get_cipher;
+  empty_method->num_ciphers = m->num_ciphers;
+  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
+  tt_int_op(ret, OP_EQ, 1);
+
+  empty_method->get_cipher = fake_get_cipher;
+  empty_method->num_ciphers = m->num_ciphers;
+  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
+  tt_int_op(ret, OP_EQ, 1);
+
+  empty_method->num_ciphers = fake_num_ciphers;
+  ret = find_cipher_by_id(ssl, empty_method, 0xC00A);
+#ifdef HAVE_SSL_CIPHER_FIND
+  tt_int_op(ret, OP_EQ, 1);
+#else
+  tt_int_op(ret, OP_EQ, 0);
+#endif
+
+ done:
+  tor_free(empty_method);
+  SSL_free(ssl);
+  SSL_CTX_free(ctx);
+  tor_free(fixed_cipher1);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_debug_state_callback(void *ignored)
+{
+  (void)ignored;
+  SSL *ssl;
+  char *buf = tor_malloc_zero(1000);
+  int n;
+
+  setup_capture_of_logs(LOG_DEBUG);
+
+  ssl = tor_malloc_zero(sizeof(SSL));
+
+  tor_tls_debug_state_callback(ssl, 32, 45);
+
+  n = tor_snprintf(buf, 1000, "SSL %p is now in state unknown"
+               " state [type=32,val=45].\n", ssl);
+  /* tor's snprintf returns -1 on error */
+  tt_int_op(n, OP_NE, -1);
+  expect_log_msg(buf);
+
+ done:
+  teardown_capture_of_logs();
+  tor_free(buf);
+  tor_free(ssl);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_server_info_callback(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  SSL_CTX *ctx;
+  SSL *ssl;
+
+  library_init();
+
+  ctx = SSL_CTX_new(TLSv1_method());
+  ssl = SSL_new(ctx);
+
+  tor_tls_allocate_tor_tls_object_ex_data_index();
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->magic = TOR_TLS_MAGIC;
+  tls->ssl = ssl;
+
+  setup_full_capture_of_logs(LOG_WARN);
+  SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_A);
+  mock_clean_saved_logs();
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  expect_single_log_msg("Couldn't look up the tls for an SSL*. How odd!\n");
+
+  SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_B);
+  mock_clean_saved_logs();
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  expect_single_log_msg("Couldn't look up the tls for an SSL*. How odd!\n");
+
+  SSL_set_state(ssl, 99);
+  mock_clean_saved_logs();
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  expect_no_log_entry();
+  teardown_capture_of_logs();
+
+  SSL_set_ex_data(tls->ssl, tor_tls_object_ex_data_index, tls);
+  SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_B);
+  tls->negotiated_callback = 0;
+  tls->server_handshake_count = 120;
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  tt_int_op(tls->server_handshake_count, OP_EQ, 121);
+
+  tls->server_handshake_count = 127;
+  tls->negotiated_callback = (void *)1;
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  tt_int_op(tls->server_handshake_count, OP_EQ, 127);
+  tt_int_op(tls->got_renegotiate, OP_EQ, 1);
+
+  tls->ssl->session = SSL_SESSION_new();
+  tls->wasV2Handshake = 0;
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 0);
+
+ done:
+  teardown_capture_of_logs();
+  SSL_free(ssl);
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static int fixed_ssl_read_result_index;
+static int fixed_ssl_read_result[5];
+static int fixed_ssl_shutdown_result;
+
+static int
+fixed_ssl_read(SSL *s, void *buf, int len)
+{
+  (void)s;
+  (void)buf;
+  (void)len;
+  return fixed_ssl_read_result[fixed_ssl_read_result_index++];
+}
+
+static int
+fixed_ssl_shutdown(SSL *s)
+{
+  (void)s;
+  return fixed_ssl_shutdown_result;
+}
+
+#ifndef LIBRESSL_VERSION_NUMBER
+static int fixed_ssl_state_to_set;
+static tor_tls_t *fixed_tls;
+
+static int
+setting_version_ssl_shutdown(SSL *s)
+{
+  s->version = SSL2_VERSION;
+  return fixed_ssl_shutdown_result;
+}
+
+static int
+setting_version_and_state_ssl_shutdown(SSL *s)
+{
+  fixed_tls->state = fixed_ssl_state_to_set;
+  s->version = SSL2_VERSION;
+  return fixed_ssl_shutdown_result;
+}
+#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
+
+static int
+dummy_handshake_func(SSL *s)
+{
+  (void)s;
+  return 1;
+}
+
+static void
+test_tortls_shutdown(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  SSL_METHOD *method = give_me_a_test_method();
+  setup_capture_of_logs(LOG_WARN);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->method = method;
+  method->ssl_read = fixed_ssl_read;
+  method->ssl_shutdown = fixed_ssl_shutdown;
+
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+  tls->state = TOR_TLS_ST_SENTCLOSE;
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = -1;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+#ifndef LIBRESSL_VERSION_NUMBER
+  tls->ssl->handshake_func = dummy_handshake_func;
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 1;
+  ERR_clear_error();
+  tls->ssl->version = SSL2_VERSION;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_DONE);
+  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 0;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_DONE);
+  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 0;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  method->ssl_shutdown = setting_version_ssl_shutdown;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 0;
+  fixed_tls = tls;
+  fixed_ssl_state_to_set = TOR_TLS_ST_GOTCLOSE;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  method->ssl_shutdown = setting_version_and_state_ssl_shutdown;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_read_result[3] = -1;
+  fixed_ssl_shutdown_result = 0;
+  fixed_tls = tls;
+  fixed_ssl_state_to_set = 0;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  method->ssl_shutdown = setting_version_and_state_ssl_shutdown;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
+
+ done:
+  teardown_capture_of_logs();
+  tor_free(method);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+static int negotiated_callback_called;
+
+static void
+negotiated_callback_setter(tor_tls_t *t, void *arg)
+{
+  (void)t;
+  (void)arg;
+  negotiated_callback_called++;
+}
+
+static void
+test_tortls_read(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  char buf[100];
+  SSL_METHOD *method = give_me_a_test_method();
+  setup_capture_of_logs(LOG_WARN);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->state = TOR_TLS_ST_OPEN;
+
+  ret = tor_tls_read(tls, buf, 10);
+  tt_int_op(ret, OP_EQ, -9);
+
+  /* These tests assume that V2_HANDSHAKE_SERVER is set */
+  tls->ssl->handshake_func = dummy_handshake_func;
+  tls->ssl->method = method;
+  method->ssl_read = fixed_ssl_read;
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 42;
+  tls->state = TOR_TLS_ST_OPEN;
+  ERR_clear_error();
+  ret = tor_tls_read(tls, buf, 10);
+  tt_int_op(ret, OP_EQ, 42);
+
+  tls->state = TOR_TLS_ST_OPEN;
+  tls->got_renegotiate = 1;
+  fixed_ssl_read_result_index = 0;
+  ERR_clear_error();
+  ret = tor_tls_read(tls, buf, 10);
+  tt_int_op(tls->got_renegotiate, OP_EQ, 0);
+
+  tls->state = TOR_TLS_ST_OPEN;
+  tls->got_renegotiate = 1;
+  negotiated_callback_called = 0;
+  tls->negotiated_callback = negotiated_callback_setter;
+  fixed_ssl_read_result_index = 0;
+  ERR_clear_error();
+  ret = tor_tls_read(tls, buf, 10);
+  tt_int_op(negotiated_callback_called, OP_EQ, 1);
+
+#ifndef LIBRESSL_VERSION_NUMBER
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 0;
+  tls->ssl->version = SSL2_VERSION;
+  ERR_clear_error();
+  ret = tor_tls_read(tls, buf, 10);
+  tt_int_op(ret, OP_EQ, TOR_TLS_CLOSE);
+  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
+#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
+  // TODO: fill up
+
+ done:
+  teardown_capture_of_logs();
+  tor_free(tls->ssl);
+  tor_free(tls);
+  tor_free(method);
+}
+
+static int fixed_ssl_write_result;
+
+static int
+fixed_ssl_write(SSL *s, const void *buf, int len)
+{
+  (void)s;
+  (void)buf;
+  (void)len;
+  return fixed_ssl_write_result;
+}
+
+static void
+test_tortls_write(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  SSL_METHOD *method = give_me_a_test_method();
+  char buf[100];
+  setup_capture_of_logs(LOG_WARN);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->state = TOR_TLS_ST_OPEN;
+
+  ret = tor_tls_write(tls, buf, 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+  ret = tor_tls_write(tls, buf, 10);
+  tt_int_op(ret, OP_EQ, -9);
+
+  tls->ssl->method = method;
+  tls->wantwrite_n = 1;
+  ret = tor_tls_write(tls, buf, 10);
+  tt_int_op(tls->wantwrite_n, OP_EQ, 0);
+
+  method->ssl_write = fixed_ssl_write;
+  tls->ssl->handshake_func = dummy_handshake_func;
+  fixed_ssl_write_result = 1;
+  ERR_clear_error();
+  ret = tor_tls_write(tls, buf, 10);
+  tt_int_op(ret, OP_EQ, 1);
+
+  fixed_ssl_write_result = -1;
+  ERR_clear_error();
+  tls->ssl->rwstate = SSL_READING;
+  SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL);
+  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_READ;
+  ret = tor_tls_write(tls, buf, 10);
+  tt_int_op(ret, OP_EQ, TOR_TLS_WANTREAD);
+
+  ERR_clear_error();
+  tls->ssl->rwstate = SSL_READING;
+  SSL_set_bio(tls->ssl, BIO_new(BIO_s_mem()), NULL);
+  SSL_get_rbio(tls->ssl)->flags = BIO_FLAGS_WRITE;
+  ret = tor_tls_write(tls, buf, 10);
+  tt_int_op(ret, OP_EQ, TOR_TLS_WANTWRITE);
+
+ done:
+  teardown_capture_of_logs();
+  BIO_free(tls->ssl->rbio);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  tor_free(method);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static int fixed_ssl_accept_result;
+static int fixed_ssl_connect_result;
+
+static int
+setting_error_ssl_accept(SSL *ssl)
+{
+  (void)ssl;
+  ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99);
+  ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99);
+  return fixed_ssl_accept_result;
+}
+
+static int
+setting_error_ssl_connect(SSL *ssl)
+{
+  (void)ssl;
+  ERR_put_error(ERR_LIB_BN, 2, -1, "somewhere.c", 99);
+  ERR_put_error(ERR_LIB_SYS, 2, -1, "somewhere.c", 99);
+  return fixed_ssl_connect_result;
+}
+
+static int
+fixed_ssl_accept(SSL *ssl)
+{
+  (void) ssl;
+  return fixed_ssl_accept_result;
+}
+
+static void
+test_tortls_handshake(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  SSL_CTX *ctx;
+  SSL_METHOD *method = give_me_a_test_method();
+  setup_capture_of_logs(LOG_INFO);
+
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  ctx = SSL_CTX_new(TLSv1_method());
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = SSL_new(ctx);
+  tls->state = TOR_TLS_ST_HANDSHAKE;
+
+  ret = tor_tls_handshake(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+  tls->isServer = 1;
+  tls->state = TOR_TLS_ST_HANDSHAKE;
+  ret = tor_tls_handshake(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+  tls->ssl->method = method;
+  method->ssl_accept = fixed_ssl_accept;
+  fixed_ssl_accept_result = 2;
+  ERR_clear_error();
+  tls->state = TOR_TLS_ST_HANDSHAKE;
+  ret = tor_tls_handshake(tls);
+  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_OPEN);
+
+  method->ssl_accept = setting_error_ssl_accept;
+  fixed_ssl_accept_result = 1;
+  ERR_clear_error();
+  mock_clean_saved_logs();
+  tls->state = TOR_TLS_ST_HANDSHAKE;
+  ret = tor_tls_handshake(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+  expect_log_entry();
+  /* This fails on jessie.  Investigate why! */
+#if 0
+  expect_log_msg("TLS error while handshaking: (null) (in bignum routines:"
+            "(null):SSLv3 write client hello B)\n");
+  expect_log_msg("TLS error while handshaking: (null) (in system library:"
+            "connect:SSLv3 write client hello B)\n");
+#endif /* 0 */
+  expect_log_severity(LOG_INFO);
+
+  tls->isServer = 0;
+  method->ssl_connect = setting_error_ssl_connect;
+  fixed_ssl_connect_result = 1;
+  ERR_clear_error();
+  mock_clean_saved_logs();
+  tls->state = TOR_TLS_ST_HANDSHAKE;
+  ret = tor_tls_handshake(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+  expect_log_entry();
+#if 0
+  /* See above */
+  expect_log_msg("TLS error while handshaking: "
+            "(null) (in bignum routines:(null):SSLv3 write client hello B)\n");
+  expect_log_msg("TLS error while handshaking: "
+            "(null) (in system library:connect:SSLv3 write client hello B)\n");
+#endif /* 0 */
+  expect_log_severity(LOG_WARN);
+
+ done:
+  teardown_capture_of_logs();
+  SSL_free(tls->ssl);
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+  tor_free(method);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#ifndef OPENSSL_OPAQUE
+static void
+test_tortls_finish_handshake(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  SSL_CTX *ctx;
+  SSL_METHOD *method = give_me_a_test_method();
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  X509 *c1 = read_cert_from(validCertString);
+  SESS_CERT_local *sess = NULL;
+
+  ctx = SSL_CTX_new(method);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = SSL_new(ctx);
+  tls->state = TOR_TLS_ST_OPEN;
+
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+
+  tls->isServer = 1;
+  tls->wasV2Handshake = 0;
+  setup_full_capture_of_logs(LOG_WARN);
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 1);
+  expect_single_log_msg_containing("For some reason, wasV2Handshake didn't "
+                                   "get set.");
+  teardown_capture_of_logs();
+
+  tls->wasV2Handshake = 1;
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 1);
+
+  tls->wasV2Handshake = 1;
+  tls->ssl->session = SSL_SESSION_new();
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 0);
+
+  tls->isServer = 0;
+
+  sess = tor_malloc_zero(sizeof(SESS_CERT_local));
+  tls->ssl->session->sess_cert = (void *)sess;
+  sess->cert_chain = sk_X509_new_null();
+  sk_X509_push(sess->cert_chain, c1);
+  tls->ssl->session->peer = c1;
+  tls->wasV2Handshake = 0;
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 1);
+
+  method->num_ciphers = fake_num_ciphers;
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+ done:
+  if (sess)
+    sk_X509_free(sess->cert_chain);
+  if (tls->ssl && tls->ssl->session) {
+    tor_free(tls->ssl->session->sess_cert);
+  }
+  SSL_free(tls->ssl);
+  tor_free(tls);
+  SSL_CTX_free(ctx);
+  tor_free(method);
+  teardown_capture_of_logs();
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static int fixed_crypto_pk_new_result_index;
+static crypto_pk_t *fixed_crypto_pk_new_result[5];
+
+static crypto_pk_t *
+fixed_crypto_pk_new(void)
+{
+  return fixed_crypto_pk_new_result[fixed_crypto_pk_new_result_index++];
+}
+
+#ifndef OPENSSL_OPAQUE
+static int fixed_crypto_pk_generate_key_with_bits_result_index;
+static int fixed_crypto_pk_generate_key_with_bits_result[5];
+static int fixed_tor_tls_create_certificate_result_index;
+static X509 *fixed_tor_tls_create_certificate_result[5];
+static int fixed_tor_x509_cert_new_result_index;
+static tor_x509_cert_t *fixed_tor_x509_cert_new_result[5];
+
+static int
+fixed_crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
+{
+  (void)env;
+  (void)bits;
+  return fixed_crypto_pk_generate_key_with_bits_result[
+                    fixed_crypto_pk_generate_key_with_bits_result_index++];
+}
+
+static X509 *
+fixed_tor_tls_create_certificate(crypto_pk_t *rsa,
+                                 crypto_pk_t *rsa_sign,
+                                 const char *cname,
+                                 const char *cname_sign,
+                                 unsigned int cert_lifetime)
+{
+  (void)rsa;
+  (void)rsa_sign;
+  (void)cname;
+  (void)cname_sign;
+  (void)cert_lifetime;
+  return fixed_tor_tls_create_certificate_result[
+                             fixed_tor_tls_create_certificate_result_index++];
+}
+
+static tor_x509_cert_t *
+fixed_tor_x509_cert_new(tor_x509_cert_impl_t *x509_cert)
+{
+  (void) x509_cert;
+  return fixed_tor_x509_cert_new_result[
+                                      fixed_tor_x509_cert_new_result_index++];
+}
+
+static void
+test_tortls_context_new(void *ignored)
+{
+  (void)ignored;
+  tor_tls_context_t *ret;
+  crypto_pk_t *pk1, *pk2, *pk3, *pk4, *pk5, *pk6, *pk7, *pk8, *pk9, *pk10,
+    *pk11, *pk12, *pk13, *pk14, *pk15, *pk16, *pk17, *pk18;
+
+  pk1 = crypto_pk_new();
+  pk2 = crypto_pk_new();
+  pk3 = crypto_pk_new();
+  pk4 = crypto_pk_new();
+  pk5 = crypto_pk_new();
+  pk6 = crypto_pk_new();
+  pk7 = crypto_pk_new();
+  pk8 = crypto_pk_new();
+  pk9 = crypto_pk_new();
+  pk10 = crypto_pk_new();
+  pk11 = crypto_pk_new();
+  pk12 = crypto_pk_new();
+  pk13 = crypto_pk_new();
+  pk14 = crypto_pk_new();
+  pk15 = crypto_pk_new();
+  pk16 = crypto_pk_new();
+  pk17 = crypto_pk_new();
+  pk18 = crypto_pk_new();
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = NULL;
+  MOCK(crypto_pk_new, fixed_crypto_pk_new);
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  /* note: we already override this in testing_common.c, so we
+   * run this unit test in a subprocess. */
+  MOCK(crypto_pk_generate_key_with_bits,
+       fixed_crypto_pk_generate_key_with_bits);
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk1;
+  fixed_crypto_pk_new_result[1] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result[0] = -1;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk2;
+  fixed_crypto_pk_new_result[1] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result[0] = 0;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk3;
+  fixed_crypto_pk_new_result[1] = pk4;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result[0] = 0;
+  fixed_crypto_pk_generate_key_with_bits_result[1] = -1;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  MOCK(tor_tls_create_certificate, fixed_tor_tls_create_certificate);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk5;
+  fixed_crypto_pk_new_result[1] = pk6;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  fixed_crypto_pk_generate_key_with_bits_result[1] = 0;
+  fixed_tor_tls_create_certificate_result_index = 0;
+  fixed_tor_tls_create_certificate_result[0] = NULL;
+  fixed_tor_tls_create_certificate_result[1] = X509_new();
+  fixed_tor_tls_create_certificate_result[2] = X509_new();
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk7;
+  fixed_crypto_pk_new_result[1] = pk8;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  fixed_tor_tls_create_certificate_result_index = 0;
+  fixed_tor_tls_create_certificate_result[0] = X509_new();
+  fixed_tor_tls_create_certificate_result[1] = NULL;
+  fixed_tor_tls_create_certificate_result[2] = X509_new();
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk9;
+  fixed_crypto_pk_new_result[1] = pk10;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  fixed_tor_tls_create_certificate_result_index = 0;
+  fixed_tor_tls_create_certificate_result[0] = X509_new();
+  fixed_tor_tls_create_certificate_result[1] = X509_new();
+  fixed_tor_tls_create_certificate_result[2] = NULL;
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  MOCK(tor_x509_cert_new, fixed_tor_x509_cert_new);
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk11;
+  fixed_crypto_pk_new_result[1] = pk12;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  fixed_tor_tls_create_certificate_result_index = 0;
+  fixed_tor_tls_create_certificate_result[0] = X509_new();
+  fixed_tor_tls_create_certificate_result[1] = X509_new();
+  fixed_tor_tls_create_certificate_result[2] = X509_new();
+  fixed_tor_x509_cert_new_result_index = 0;
+  fixed_tor_x509_cert_new_result[0] = NULL;
+  fixed_tor_x509_cert_new_result[1] = NULL;
+  fixed_tor_x509_cert_new_result[2] = NULL;
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk13;
+  fixed_crypto_pk_new_result[1] = pk14;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  fixed_tor_tls_create_certificate_result_index = 0;
+  fixed_tor_tls_create_certificate_result[0] = X509_new();
+  fixed_tor_tls_create_certificate_result[1] = X509_new();
+  fixed_tor_tls_create_certificate_result[2] = X509_new();
+  fixed_tor_x509_cert_new_result_index = 0;
+  fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  fixed_tor_x509_cert_new_result[1] = NULL;
+  fixed_tor_x509_cert_new_result[2] = NULL;
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk15;
+  fixed_crypto_pk_new_result[1] = pk16;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  fixed_tor_tls_create_certificate_result_index = 0;
+  fixed_tor_tls_create_certificate_result[0] = X509_new();
+  fixed_tor_tls_create_certificate_result[1] = X509_new();
+  fixed_tor_tls_create_certificate_result[2] = X509_new();
+  fixed_tor_x509_cert_new_result_index = 0;
+  fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  fixed_tor_x509_cert_new_result[2] = NULL;
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = pk17;
+  fixed_crypto_pk_new_result[1] = pk18;
+  fixed_crypto_pk_new_result[2] = NULL;
+  fixed_crypto_pk_generate_key_with_bits_result_index = 0;
+  fixed_tor_tls_create_certificate_result_index = 0;
+  fixed_tor_tls_create_certificate_result[0] = X509_new();
+  fixed_tor_tls_create_certificate_result[1] = X509_new();
+  fixed_tor_tls_create_certificate_result[2] = X509_new();
+  fixed_tor_x509_cert_new_result_index = 0;
+  fixed_tor_x509_cert_new_result[0] = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  fixed_tor_x509_cert_new_result[1] = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  fixed_tor_x509_cert_new_result[2] = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  ret = tor_tls_context_new(NULL, 0, 0, 0);
+  tt_assert(!ret);
+
+ done:
+  UNMOCK(tor_x509_cert_new);
+  UNMOCK(tor_tls_create_certificate);
+  UNMOCK(crypto_pk_generate_key_with_bits);
+  UNMOCK(crypto_pk_new);
+}
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+static int fixed_crypto_pk_get_evp_pkey_result_index = 0;
+static EVP_PKEY *fixed_crypto_pk_get_evp_pkey_result[5];
+
+static EVP_PKEY *
+fixed_crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
+{
+  (void) env;
+  (void) private;
+  return fixed_crypto_pk_get_evp_pkey_result[
+                               fixed_crypto_pk_get_evp_pkey_result_index++];
+}
+
+static void
+test_tortls_create_certificate(void *ignored)
+{
+  (void)ignored;
+  X509 *ret;
+  crypto_pk_t *pk1, *pk2;
+
+  pk1 = crypto_pk_new();
+  pk2 = crypto_pk_new();
+
+  MOCK(crypto_pk_get_openssl_evp_pkey_, fixed_crypto_pk_get_evp_pkey_);
+  fixed_crypto_pk_get_evp_pkey_result_index = 0;
+  fixed_crypto_pk_get_evp_pkey_result[0] = NULL;
+  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_get_evp_pkey_result_index = 0;
+  fixed_crypto_pk_get_evp_pkey_result[0] = EVP_PKEY_new();
+  fixed_crypto_pk_get_evp_pkey_result[1] = NULL;
+  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
+  tt_assert(!ret);
+
+  fixed_crypto_pk_get_evp_pkey_result_index = 0;
+  fixed_crypto_pk_get_evp_pkey_result[0] = EVP_PKEY_new();
+  fixed_crypto_pk_get_evp_pkey_result[1] = EVP_PKEY_new();
+  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
+  tt_assert(!ret);
+
+ done:
+  UNMOCK(crypto_pk_get_openssl_evp_pkey_);
+  crypto_pk_free(pk1);
+  crypto_pk_free(pk2);
+}
+
+static void
+test_tortls_cert_new(void *ignored)
+{
+  (void)ignored;
+  tor_x509_cert_t *ret;
+  X509 *cert = read_cert_from(validCertString);
+
+  ret = tor_x509_cert_new(NULL);
+  tt_assert(!ret);
+
+  ret = tor_x509_cert_new(cert);
+  tt_assert(ret);
+  tor_x509_cert_free(ret);
+  ret = NULL;
+
+#if 0
+  cert = read_cert_from(validCertString);
+  /* XXX this doesn't do what you think: it alters a copy of the pubkey. */
+  X509_get_pubkey(cert)->type = EVP_PKEY_DSA;
+  ret = tor_x509_cert_new(cert);
+  tt_assert(ret);
+#endif /* 0 */
+
+#ifndef OPENSSL_OPAQUE
+  cert = read_cert_from(validCertString);
+  X509_CINF_free(cert->cert_info);
+  cert->cert_info = NULL;
+  ret = tor_x509_cert_new(cert);
+  tt_assert(ret);
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+ done:
+  tor_x509_cert_free(ret);
+}
+
+static void
+test_tortls_cert_is_valid(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_x509_cert_t *cert = NULL, *scert = NULL;
+
+  scert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
+  tt_int_op(ret, OP_EQ, 0);
+  tor_free(scert);
+  tor_free(cert);
+
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
+  tt_int_op(ret, OP_EQ, 1);
+
+#ifndef OPENSSL_OPAQUE
+  tor_x509_cert_free(cert);
+  tor_x509_cert_free(scert);
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  ASN1_TIME_free(cert->cert->cert_info->validity->notAfter);
+  cert->cert->cert_info->validity->notAfter =
+    ASN1_TIME_set(NULL, time(NULL)-1000000);
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+  tor_x509_cert_free(cert);
+  tor_x509_cert_free(scert);
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  X509_PUBKEY_free(cert->cert->cert_info->key);
+  cert->cert->cert_info->key = NULL;
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
+  tt_int_op(ret, OP_EQ, 0);
+#endif /* !defined(OPENSSL_OPAQUE) */
+
+#if 0
+  tor_x509_cert_free(cert);
+  tor_x509_cert_free(scert);
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  /* This doesn't actually change the key in the cert. XXXXXX */
+  BN_one(EVP_PKEY_get1_RSA(X509_get_pubkey(cert->cert))->n);
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
+  tt_int_op(ret, OP_EQ, 0);
+
+  tor_x509_cert_free(cert);
+  tor_x509_cert_free(scert);
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  /* This doesn't actually change the key in the cert. XXXXXX */
+  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
+  tt_int_op(ret, OP_EQ, 0);
+
+  tor_x509_cert_free(cert);
+  tor_x509_cert_free(scert);
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  /* This doesn't actually change the key in the cert. XXXXXX */
+  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
+  tt_int_op(ret, OP_EQ, 1);
+
+  tor_x509_cert_free(cert);
+  tor_x509_cert_free(scert);
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  /* This doesn't actually change the key in the cert. XXXXXX */
+  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
+  X509_get_pubkey(cert->cert)->ameth = NULL;
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
+  tt_int_op(ret, OP_EQ, 0);
+#endif /* 0 */
+
+ done:
+  tor_x509_cert_free(cert);
+  tor_x509_cert_free(scert);
+}
+
+static void
+test_tortls_context_init_one(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_context_t *old = NULL;
+
+  MOCK(crypto_pk_new, fixed_crypto_pk_new);
+
+  fixed_crypto_pk_new_result_index = 0;
+  fixed_crypto_pk_new_result[0] = NULL;
+  ret = tor_tls_context_init_one(&old, NULL, 0, 0, 0);
+  tt_int_op(ret, OP_EQ, -1);
+
+ done:
+  UNMOCK(crypto_pk_new);
+}
+
+#define LOCAL_TEST_CASE(name, flags)                    \
+  { #name, test_tortls_##name, (flags|TT_FORK), NULL, NULL }
+
+#ifdef OPENSSL_OPAQUE
+#define INTRUSIVE_TEST_CASE(name, flags)        \
+  { #name, NULL, TT_SKIP, NULL, NULL }
+#else
+#define INTRUSIVE_TEST_CASE(name, flags) LOCAL_TEST_CASE(name, flags)
+#endif /* defined(OPENSSL_OPAQUE) */
+
+struct testcase_t tortls_openssl_tests[] = {
+  LOCAL_TEST_CASE(tor_tls_new, TT_FORK),
+  LOCAL_TEST_CASE(get_state_description, TT_FORK),
+  LOCAL_TEST_CASE(get_by_ssl, TT_FORK),
+  LOCAL_TEST_CASE(allocate_tor_tls_object_ex_data_index, TT_FORK),
+  LOCAL_TEST_CASE(log_one_error, TT_FORK),
+  INTRUSIVE_TEST_CASE(get_error, TT_FORK),
+  LOCAL_TEST_CASE(always_accept_verify_cb, 0),
+  INTRUSIVE_TEST_CASE(x509_cert_free, 0),
+  INTRUSIVE_TEST_CASE(cert_matches_key, 0),
+  INTRUSIVE_TEST_CASE(cert_get_key, 0),
+  LOCAL_TEST_CASE(get_my_client_auth_key, TT_FORK),
+  INTRUSIVE_TEST_CASE(get_ciphersuite_name, 0),
+  INTRUSIVE_TEST_CASE(classify_client_ciphers, 0),
+  LOCAL_TEST_CASE(client_is_using_v2_ciphers, 0),
+  INTRUSIVE_TEST_CASE(verify, 0),
+  INTRUSIVE_TEST_CASE(check_lifetime, 0),
+  INTRUSIVE_TEST_CASE(get_pending_bytes, 0),
+  INTRUSIVE_TEST_CASE(SSL_SESSION_get_master_key, 0),
+  INTRUSIVE_TEST_CASE(get_tlssecrets, 0),
+  INTRUSIVE_TEST_CASE(get_buffer_sizes, 0),
+  INTRUSIVE_TEST_CASE(try_to_extract_certs_from_tls, 0),
+  INTRUSIVE_TEST_CASE(get_peer_cert, 0),
+  INTRUSIVE_TEST_CASE(peer_has_cert, 0),
+  INTRUSIVE_TEST_CASE(shutdown, 0),
+  INTRUSIVE_TEST_CASE(finish_handshake, 0),
+  INTRUSIVE_TEST_CASE(handshake, 0),
+  INTRUSIVE_TEST_CASE(write, 0),
+  INTRUSIVE_TEST_CASE(read, 0),
+  INTRUSIVE_TEST_CASE(server_info_callback, 0),
+  LOCAL_TEST_CASE(get_write_overhead_ratio, TT_FORK),
+  LOCAL_TEST_CASE(is_server, 0),
+  INTRUSIVE_TEST_CASE(assert_renegotiation_unblocked, 0),
+  INTRUSIVE_TEST_CASE(block_renegotiation, 0),
+  INTRUSIVE_TEST_CASE(unblock_renegotiation, 0),
+  INTRUSIVE_TEST_CASE(set_renegotiate_callback, 0),
+  LOCAL_TEST_CASE(set_logged_address, 0),
+  INTRUSIVE_TEST_CASE(find_cipher_by_id, 0),
+  INTRUSIVE_TEST_CASE(session_secret_cb, 0),
+  INTRUSIVE_TEST_CASE(debug_state_callback, 0),
+  INTRUSIVE_TEST_CASE(context_new, TT_FORK /* redundant */),
+  LOCAL_TEST_CASE(create_certificate, 0),
+  LOCAL_TEST_CASE(cert_new, 0),
+  LOCAL_TEST_CASE(cert_is_valid, 0),
+  LOCAL_TEST_CASE(context_init_one, 0),
+  END_OF_TESTCASES
+};





More information about the tor-commits mailing list