[tor-commits] [tor/master] Merge branch 'nss_squashed' into nss_merge

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


commit 0db5c549571eb0098a3f709ffb25c2e4909ca01d
Merge: fd994f55c d644c93ae
Author: Nick Mathewson <nickm at torproject.org>
Date:   Tue Sep 4 20:21:07 2018 -0400

    Merge branch 'nss_squashed' into nss_merge

 Makefile.am                                     |    8 +
 changes/NSS                                     |    7 +
 changes/feature26815                            |    3 +
 changes/feature26816                            |   11 +
 config.rust.in                                  |    2 +
 configure.ac                                    |   30 +
 src/app/config/config.c                         |   16 +-
 src/app/include.am                              |    8 +-
 src/core/crypto/onion_ntor.c                    |    2 +-
 src/core/crypto/relay_crypto.c                  |    2 +-
 src/core/mainloop/connection.c                  |   25 +-
 src/core/mainloop/main.c                        |    6 +-
 src/core/or/channeltls.c                        |    1 +
 src/core/or/connection_or.c                     |    1 +
 src/core/or/or.h                                |    3 +-
 src/ext/tinytest.c                              |   11 +
 src/feature/control/control.c                   |    4 +-
 src/feature/nodelist/parsecommon.c              |    2 +-
 src/feature/nodelist/torcert.c                  |    1 +
 src/feature/relay/router.c                      |    3 +-
 src/feature/relay/routerkeys.c                  |    1 +
 src/feature/rend/rendmid.c                      |    2 +-
 src/feature/rend/rendservice.c                  |    2 +-
 src/lib/crypt_ops/aes_nss.c                     |  106 +
 src/lib/crypt_ops/{aes.c => aes_openssl.c}      |    4 +-
 src/lib/crypt_ops/compat_openssl.h              |    6 +
 src/lib/crypt_ops/crypto.c                      |  509 ----
 src/lib/crypt_ops/crypto_cipher.c               |  190 ++
 src/lib/crypt_ops/{crypto.h => crypto_cipher.h} |   25 +-
 src/lib/crypt_ops/crypto_dh.c                   |  484 +---
 src/lib/crypt_ops/crypto_dh.h                   |   23 +-
 src/lib/crypt_ops/crypto_dh_nss.c               |  207 ++
 src/lib/crypt_ops/crypto_dh_openssl.c           |  471 ++++
 src/lib/crypt_ops/crypto_digest.c               |  262 ++-
 src/lib/crypt_ops/crypto_digest.h               |    6 +-
 src/lib/crypt_ops/crypto_ed25519.c              |    1 +
 src/lib/crypt_ops/crypto_format.c               |    1 +
 src/lib/crypt_ops/crypto_hkdf.c                 |    2 +
 src/lib/crypt_ops/crypto_init.c                 |  193 ++
 src/lib/crypt_ops/crypto_init.h                 |   34 +
 src/lib/crypt_ops/crypto_nss_mgt.c              |  132 ++
 src/lib/crypt_ops/crypto_nss_mgt.h              |   34 +
 src/lib/crypt_ops/crypto_ope.c                  |    2 +-
 src/lib/crypt_ops/crypto_openssl_mgt.c          |  228 +-
 src/lib/crypt_ops/crypto_openssl_mgt.h          |   15 +-
 src/lib/crypt_ops/crypto_pwbox.c                |    2 +-
 src/lib/crypt_ops/crypto_rand.c                 |  122 +-
 src/lib/crypt_ops/crypto_rsa.c                  | 1001 ++------
 src/lib/crypt_ops/crypto_rsa.h                  |   48 +-
 src/lib/crypt_ops/crypto_rsa_nss.c              |  738 ++++++
 src/lib/crypt_ops/crypto_rsa_openssl.c          |  590 +++++
 src/lib/crypt_ops/crypto_s2k.c                  |   50 +-
 src/lib/crypt_ops/crypto_util.c                 |   29 +-
 src/lib/crypt_ops/crypto_util.h                 |    9 -
 src/lib/crypt_ops/include.am                    |   32 +-
 src/lib/encoding/.may_include                   |    1 +
 src/lib/encoding/include.am                     |    2 +
 src/lib/encoding/pem.c                          |  106 +
 src/lib/encoding/pem.h                          |   26 +
 src/lib/include.libdonna.am                     |    2 +-
 src/lib/process/daemon.c                        |   25 +-
 src/lib/process/daemon.h                        |    4 +-
 src/lib/tls/include.am                          |   24 +-
 src/lib/tls/tortls.c                            | 2673 ++-------------------
 src/lib/tls/tortls.h                            |  210 +-
 src/lib/tls/tortls_internal.h                   |   76 +
 src/lib/tls/tortls_nss.c                        |  741 ++++++
 src/lib/tls/tortls_openssl.c                    | 1708 ++++++++++++++
 src/lib/tls/tortls_st.h                         |   74 +
 src/lib/tls/x509.c                              |  143 ++
 src/lib/tls/x509.h                              |   75 +
 src/lib/tls/x509_internal.h                     |   53 +
 src/lib/tls/x509_nss.c                          |  450 ++++
 src/lib/tls/x509_openssl.c                      |  461 ++++
 src/rust/build.rs                               |    1 +
 src/test/bench.c                                |   14 +-
 src/test/fuzz/fuzzing_common.c                  |   15 +-
 src/test/fuzz/include.am                        |    4 +-
 src/test/include.am                             |   35 +-
 src/test/log_test_helpers.h                     |   37 +-
 src/test/test-timers.c                          |    5 +
 src/test/test.c                                 |    7 +
 src/test/test.h                                 |    3 +
 src/test/test_controller.c                      |    2 +-
 src/test/test_crypto.c                          |  127 +-
 src/test/test_crypto_ope.c                      |    4 +-
 src/test/test_crypto_slow.c                     |    2 +
 src/test/test_dir_handle_get.c                  |    2 +-
 src/test/test_hs_client.c                       |    2 +-
 src/test/test_hs_ntor_cl.c                      |    7 +-
 src/test/test_introduce.c                       |    2 +-
 src/test/test_link_handshake.c                  |   34 +-
 src/test/test_ntor_cl.c                         |    8 +-
 src/test/test_pem.c                             |  122 +
 src/test/test_relaycell.c                       |    2 +-
 src/test/test_router.c                          |    2 +
 src/test/test_routerkeys.c                      |    2 +-
 src/test/test_shared_random.c                   |    2 +-
 src/test/test_tortls.c                          | 2863 +++--------------------
 src/test/test_tortls.h                          |   13 +
 src/test/test_tortls_openssl.c                  | 2277 ++++++++++++++++++
 src/test/test_util_slow.c                       |    2 +-
 src/test/test_workqueue.c                       |    1 +
 src/test/test_x509.c                            |  203 ++
 src/test/testing_common.c                       |   17 +-
 src/test/testing_rsakeys.c                      |    3 +-
 src/tools/include.am                            |   24 +-
 src/tools/tor-gencert.c                         |   23 +-
 108 files changed, 11268 insertions(+), 7160 deletions(-)

diff --cc src/lib/tls/tortls.c
index 7135820d2,923b0db4c..3ae3a1a09
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@@ -3,168 -3,19 +3,25 @@@
   * 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.h"
- #include "lib/crypt_ops/crypto_rand.h"
- #include "lib/crypt_ops/crypto_dh.h"
- #include "lib/crypt_ops/crypto_util.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)
- 
  #define TORTLS_PRIVATE
+ #define TOR_X509_PRIVATE
+ #include "lib/tls/x509.h"
+ #include "lib/tls/x509_internal.h"
  #include "lib/tls/tortls.h"
- #include "lib/log/log.h"
+ #include "lib/tls/tortls_st.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"
- 
- #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
- 
- /* 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') */
+ #include "lib/crypt_ops/crypto_rsa.h"
+ #include "lib/crypt_ops/crypto_rand.h"
++#include "lib/net/socket.h"
 +
- /* 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
++#ifdef _WIN32
++  #include <winsock2.h>
++  #include <ws2tcpip.h>
 +#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);
- 
- static int check_cert_lifetime_internal(int severity, const X509 *cert,
-                                    time_t now,
-                                    int past_tolerance, int future_tolerance);
+ #include <time.h>
  
  /** Global TLS contexts. We keep them here because nobody else needs
   * to touch them.
diff --cc src/lib/tls/tortls_openssl.c
index 000000000,9371c9393..ab9712962
mode 000000,100644..100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@@ -1,0 -1,1706 +1,1708 @@@
+ /* 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
+ #define TOR_X509_PRIVATE
+ 
+ #ifdef _WIN32
+   /* We need to include these here, or else the dtls1.h header will include
+    * <winsock.h> and mess things up, in at least some openssl versions. */
+   #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"
+ #include "lib/tls/x509_internal.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"
+ 
+ #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);
+   }
+ }
+ 
+ #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
+ 
+ /** 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);
++  tor_x509_cert_t *peer = tor_tls_get_peer_cert((tor_tls_t *)tls);
++  if (!peer)
++    return 0;
++
++  X509 *peercert = peer->cert;
+   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(cert->cert);
+ 
+   result = link_key && cert_key && EVP_PKEY_cmp(cert_key, link_key) == 1;
+ 
 -  X509_free(peercert);
++  tor_x509_cert_free(peer);
+   if (link_key)
+     EVP_PKEY_free(link_key);
+   if (cert_key)
+     EVP_PKEY_free(cert_key);
+ 
+   return result;
+ }
+ 
+ void
+ tor_tls_context_impl_free_(struct ssl_ctx_st *ctx)
+ {
+   if (!ctx)
+     return;
+   SSL_CTX_free(ctx);
+ }
+ 
+ /** The group we should use for ecdhe when none was selected. */
+ #define  NID_tor_default_ecdhe_group NID_X9_62_prime256v1
+ 
+ /** 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)
+ {
+   EVP_PKEY *pkey = NULL;
+   tor_tls_context_t *result = NULL;
+ 
+   tor_tls_init();
+ 
+   result = tor_malloc_zero(sizeof(tor_tls_context_t));
+   result->refcnt = 1;
+ 
+   if (! is_client) {
+     if (tor_tls_context_init_certificates(result, identity, key_lifetime,
+                                           flags) < 0) {
+       goto error;
+     }
+   }
+ 
+ #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 (result->my_link_cert &&
+         !SSL_CTX_use_certificate(result->ctx,
+                                  result->my_link_cert->cert)) {
+       goto error;
+     }
+     if (result->my_id_cert) {
+       X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
+       tor_assert(s);
+       X509_STORE_add_cert(s, result->my_id_cert->cert);
+     }
+   }
+   SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
+   if (!is_client) {
+     tor_assert(result->link_key);
+     if (!(pkey = crypto_pk_get_openssl_evp_pkey_(result->link_key,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);
+ 
+   return result;
+ 
+  error:
+   tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context");
+   if (pkey)
+     EVP_PKEY_free(pkey);
+   if (result)
+     tor_tls_context_decref(result);
+   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;
+   } 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, 0);
+   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) && ... */
+ }
+ 
+ void
+ tor_tls_impl_free_(tor_tls_impl_t *ssl)
+ {
+   if (!ssl)
+     return;
+ 
+ #ifdef SSL_set_tlsext_host_name
+   SSL_set_tlsext_host_name(ssl, NULL);
+ #endif
+   SSL_free(ssl);
+ }
+ 
+ /** 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;
+ }
+ 
+ /** 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;
+ }
+ 
+ /** 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 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 --cc src/test/log_test_helpers.h
index dcd329734,330da3811..6a774cdfc
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@@ -45,12 -44,8 +45,12 @@@ void mock_dump_saved_logs(void)
  
  #define expect_log_msg_containing(str) \
    assert_log_predicate(mock_saved_log_has_message_containing(str), \
-                 "expected log to contain " # str);
+                        ("expected log to contain \"%s\"", str));
  
 +#define expect_log_msg_not_containing(str) \
 +  assert_log_predicate(mock_saved_log_has_message_not_containing(str), \
-                 "expected log to not contain " # str);
++                       ("expected log to not contain \"%s\"", str));
 +
  #define expect_log_msg_containing_either(str1, str2)                    \
    assert_log_predicate(mock_saved_log_has_message_containing(str1) ||   \
                         mock_saved_log_has_message_containing(str2),     \
diff --cc src/test/test_router.c
index 6e64131fc,14e739d6f..533135669
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@@ -52,10 -49,11 +52,12 @@@ NS(router_get_my_routerinfo)(void
      mock_routerinfo->platform = tor_strdup("unittest");
      mock_routerinfo->cache_info.published_on = now;
      mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key);
 -    mock_routerinfo->onion_pkey = crypto_pk_dup_key(tap_key);
 +    router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->onion_pkey,
 +                              &mock_routerinfo->onion_pkey_len);
      mock_routerinfo->bandwidthrate = 9001;
      mock_routerinfo->bandwidthburst = 9002;
+     crypto_pk_free(ident_key);
+     crypto_pk_free(tap_key);
    }
  
    return mock_routerinfo;
diff --cc src/test/test_tortls_openssl.c
index 000000000,2e71de43a..608625288
mode 000000,100644..100644
--- a/src/test/test_tortls_openssl.c
+++ b/src/test/test_tortls_openssl.c
@@@ -1,0 -1,2305 +1,2277 @@@
+ /* 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/x509_internal.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"
+ #include "test/test_tortls.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);
+   }
+ }
++#endif
++
++static tor_x509_cert_t *fixed_x509_cert = NULL;
++static tor_x509_cert_t *
++get_peer_cert_mock_return_fixed(tor_tls_t *tls)
++{
++  (void)tls;
++  if (fixed_x509_cert)
++    return tor_x509_cert_dup(fixed_x509_cert);
++  else
++    return NULL;
++}
+ 
+ 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;
++  X509 *cert1 = NULL, *cert2 = NULL, *cert3 = NULL, *cert4 = NULL;
++  tor_x509_cert_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL;
++  crypto_pk_t *k1 = NULL, *k2 = NULL, *k3 = NULL;
+ 
 -  res = tor_tls_cert_matches_key(tls, cert);
 -  tt_int_op(res, OP_EQ, 0);
++  k1 = pk_generate(1);
++  k2 = pk_generate(2);
++  k3 = pk_generate(3);
+ 
 -  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);
++  cert1 = tor_tls_create_certificate(k1, k2, "A", "B", 1000);
++  cert2 = tor_tls_create_certificate(k1, k3, "C", "D", 1000);
++  cert3 = tor_tls_create_certificate(k2, k3, "C", "D", 1000);
++  cert4 = tor_tls_create_certificate(k3, k2, "E", "F", 1000);
++
++  tt_assert(cert1 && cert2 && cert3 && cert4);
++
++  c1 = tor_x509_cert_new(cert1); cert1 = NULL;
++  c2 = tor_x509_cert_new(cert2); cert2 = NULL;
++  c3 = tor_x509_cert_new(cert3); cert3 = NULL;
++  c4 = tor_x509_cert_new(cert4); cert4 = NULL;
++
++  tt_assert(c1 && c2 && c3 && c4);
++
++  MOCK(tor_tls_get_peer_cert, get_peer_cert_mock_return_fixed);
++
++  fixed_x509_cert = NULL;
++  /* If the peer has no certificate, it shouldn't match anything. */
++  tt_assert(! tor_tls_cert_matches_key(NULL, c1));
++  tt_assert(! tor_tls_cert_matches_key(NULL, c2));
++  tt_assert(! tor_tls_cert_matches_key(NULL, c3));
++  tt_assert(! tor_tls_cert_matches_key(NULL, c4));
++  fixed_x509_cert = c1;
++  /* If the peer has a certificate, it should match every cert with the same
++   * subject key. */
++  tt_assert(tor_tls_cert_matches_key(NULL, c1));
++  tt_assert(tor_tls_cert_matches_key(NULL, c2));
++  tt_assert(! tor_tls_cert_matches_key(NULL, c3));
++  tt_assert(! tor_tls_cert_matches_key(NULL, c4));
+ 
+  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);
++  tor_x509_cert_free(c1);
++  tor_x509_cert_free(c2);
++  tor_x509_cert_free(c3);
++  tor_x509_cert_free(c4);
++  if (cert1) X509_free(cert1);
++  if (cert2) X509_free(cert2);
++  if (cert3) X509_free(cert3);
++  if (cert4) X509_free(cert4);
++  crypto_pk_free(k1);
++  crypto_pk_free(k2);
++  crypto_pk_free(k3);
++  UNMOCK(tor_tls_get_peer_cert);
+ }
+ 
++#ifndef OPENSSL_OPAQUE
+ 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:
+   crypto_pk_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 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;
++  //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);
++  //tt_int_op(tls->server_handshake_count, OP_EQ, 121);
+ 
 -  tls->server_handshake_count = 127;
++  //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->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 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),
++  LOCAL_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(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