[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [tor/master] Add tests for tortls.c



commit 94e5db3dca3abfc93a57287516177f14d395ae3f
Author: Ola Bini <ola@xxxxxxxxxx>
Date:   Tue Sep 15 17:09:18 2015 +0200

    Add tests for tortls.c
---
 src/common/crypto.c         |   13 +-
 src/common/crypto.h         |    9 +-
 src/common/tortls.c         |  242 ++--
 src/common/tortls.h         |  111 +-
 src/test/include.am         |    2 +
 src/test/log_test_helpers.c |   95 ++
 src/test/log_test_helpers.h |   27 +
 src/test/test.c             |    3 +-
 src/test/test_tortls.c      | 2762 +++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 3094 insertions(+), 170 deletions(-)

diff --git a/src/common/crypto.c b/src/common/crypto.c
index 815c2ec..b6ead83 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -433,8 +433,8 @@ crypto_pk_get_rsa_(crypto_pk_t *env)
 
 /** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t.  Iff
  * private is set, include the private-key portion of the key. */
-EVP_PKEY *
-crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
+MOCK_IMPL(EVP_PKEY *,
+          crypto_pk_get_evp_pkey_,(crypto_pk_t *env, int private))
 {
   RSA *key = NULL;
   EVP_PKEY *pkey = NULL;
@@ -470,8 +470,8 @@ crypto_dh_get_dh_(crypto_dh_t *dh)
 /** Allocate and return storage for a public key.  The key itself will not yet
  * be set.
  */
-crypto_pk_t *
-crypto_pk_new(void)
+MOCK_IMPL(crypto_pk_t *,
+          crypto_pk_new,(void))
 {
   RSA *rsa;
 
@@ -553,8 +553,8 @@ crypto_cipher_free(crypto_cipher_t *env)
 /** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>.
  * Return 0 on success, -1 on failure.
  */
-int
-crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
+MOCK_IMPL(int,
+          crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits))
 {
   tor_assert(env);
 
@@ -2734,4 +2734,3 @@ crypto_global_cleanup(void)
 }
 
 /** @} */
-
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 6256f73..ede7d5b 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -119,7 +119,7 @@ void crypto_thread_cleanup(void);
 int crypto_global_cleanup(void);
 
 /* environment setup */
-crypto_pk_t *crypto_pk_new(void);
+MOCK_DECL(crypto_pk_t *,crypto_pk_new,(void));
 void crypto_pk_free(crypto_pk_t *env);
 
 void crypto_set_tls_dh_prime(void);
@@ -128,7 +128,7 @@ crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv);
 void crypto_cipher_free(crypto_cipher_t *env);
 
 /* public key crypto */
-int crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits);
+MOCK_DECL(int, crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits));
 #define crypto_pk_generate_key(env)                     \
   crypto_pk_generate_key_with_bits((env), (PK_BYTES*8))
 
@@ -289,11 +289,10 @@ struct evp_pkey_st;
 struct dh_st;
 struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env);
 crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa);
-struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env,
-                                                int private);
+MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_evp_pkey_,(crypto_pk_t *env,
+                                                         int private));
 struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
 
 void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in);
 
 #endif
-
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 7447822..cdb11de 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -69,6 +69,7 @@
 #include "compat_libevent.h"
 #endif
 
+#define TORTLS_PRIVATE
 #include "tortls.h"
 #include "util.h"
 #include "torlog.h"
@@ -108,28 +109,6 @@
 #define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010
 #endif
 
-/** Structure that we use for a single certificate. */
-struct tor_x509_cert_t {
-  X509 *cert;
-  uint8_t *encoded;
-  size_t encoded_len;
-  unsigned pkey_digests_set : 1;
-  digests_t cert_digests;
-  digests_t pkey_digests;
-};
-
-/** Holds a SSL_CTX object and related state used to configure TLS
- * connections.
- */
-typedef struct tor_tls_context_t {
-  int refcnt;
-  SSL_CTX *ctx;
-  tor_x509_cert_t *my_link_cert;
-  tor_x509_cert_t *my_id_cert;
-  tor_x509_cert_t *my_auth_cert;
-  crypto_pk_t *link_key;
-  crypto_pk_t *auth_key;
-} tor_tls_context_t;
 
 /** Return values for tor_tls_classify_client_ciphers.
  *
@@ -149,60 +128,13 @@ typedef struct tor_tls_context_t {
 #define CIPHERS_UNRESTRICTED 3
 /** @} */
 
-#define TOR_TLS_MAGIC 0x71571571
-
-typedef enum {
-    TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
-    TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE,
-    TOR_TLS_ST_BUFFEREVENT
-} tor_tls_state_t;
-#define tor_tls_state_bitfield_t ENUM_BF(tor_tls_state_t)
-
-/** Holds a SSL object and its associated data.  Members are only
- * accessed from within tortls.c.
- */
-struct tor_tls_t {
-  uint32_t magic;
-  tor_tls_context_t *context; /** A link to the context object for this tls. */
-  SSL *ssl; /**< An OpenSSL SSL object. */
-  int socket; /**< The underlying file descriptor for this TLS connection. */
-  char *address; /**< An address to log when describing this connection. */
-  tor_tls_state_bitfield_t state : 3; /**< The current SSL state,
-                                       * depending on which operations
-                                       * have completed successfully. */
-  unsigned int isServer:1; /**< True iff this is a server-side connection */
-  unsigned int wasV2Handshake:1; /**< True iff the original handshake for
-                                  * this connection used the updated version
-                                  * of the connection protocol (client sends
-                                  * different cipher list, server sends only
-                                  * one certificate). */
-  /** True iff we should call negotiated_callback when we're done reading. */
-  unsigned int got_renegotiate:1;
-  /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't
-   * called that function yet. */
-  int8_t client_cipher_list_type;
-  /** Incremented every time we start the server side of a handshake. */
-  uint8_t server_handshake_count;
-  size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
-                       * time. */
-  /** Last values retrieved from BIO_number_read()/write(); see
-   * tor_tls_get_n_raw_bytes() for usage.
-   */
-  unsigned long last_write_count;
-  unsigned long last_read_count;
-  /** If set, a callback to invoke whenever the client tries to renegotiate
-   * the handshake. */
-  void (*negotiated_callback)(tor_tls_t *tls, void *arg);
-  /** Argument to pass to negotiated_callback. */
-  void *callback_arg;
-};
 
 /** 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;
+STATIC int tor_tls_object_ex_data_index = -1;
 
 /** Helper: Allocate tor_tls_object_ex_data_index. */
-static void
+STATIC void
 tor_tls_allocate_tor_tls_object_ex_data_index(void)
 {
   if (tor_tls_object_ex_data_index == -1) {
@@ -214,7 +146,7 @@ tor_tls_allocate_tor_tls_object_ex_data_index(void)
 
 /** Helper: given a SSL* pointer, return the tor_tls_t object using that
  * pointer. */
-static INLINE tor_tls_t *
+STATIC INLINE 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);
@@ -225,21 +157,7 @@ tor_tls_get_by_ssl(const SSL *ssl)
 
 static void tor_tls_context_decref(tor_tls_context_t *ctx);
 static void tor_tls_context_incref(tor_tls_context_t *ctx);
-static X509* tor_tls_create_certificate(crypto_pk_t *rsa,
-                                        crypto_pk_t *rsa_sign,
-                                        const char *cname,
-                                        const char *cname_sign,
-                                        unsigned int cert_lifetime);
-
-static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
-                                    crypto_pk_t *identity,
-                                    unsigned int key_lifetime,
-                                    unsigned int flags,
-                                    int is_client);
-static tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
-                                              unsigned int key_lifetime,
-                                              unsigned int flags,
-                                              int is_client);
+
 static int check_cert_lifetime_internal(int severity, const X509 *cert,
                                    int past_tolerance, int future_tolerance);
 
@@ -247,8 +165,8 @@ static int check_cert_lifetime_internal(int severity, const X509 *cert,
  * to touch them.
  *
  * @{ */
-static tor_tls_context_t *server_tls_context = NULL;
-static tor_tls_context_t *client_tls_context = NULL;
+STATIC tor_tls_context_t *server_tls_context = NULL;
+STATIC tor_tls_context_t *client_tls_context = NULL;
 /**@}*/
 
 /** True iff tor_tls_init() has been called. */
@@ -342,7 +260,7 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
 /** 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.
  */
-static void
+STATIC void
 tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
 {
   unsigned long err;
@@ -354,7 +272,7 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
 
 /** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error
  * code. */
-static int
+STATIC int
 tor_errno_to_tls_error(int e)
 {
   switch (e) {
@@ -405,7 +323,7 @@ tor_tls_err_to_string(int err)
  * If an error has occurred, log it at level <b>severity</b> and describe the
  * current action as <b>doing</b>.
  */
-static int
+STATIC int
 tor_tls_get_error(tor_tls_t *tls, int r, int extra,
                   const char *doing, int severity, int domain)
 {
@@ -463,6 +381,7 @@ tor_tls_init(void)
      OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
     long version = SSLeay();
 
+    /* LCOV_EXCL_START because we can't reasonably 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
@@ -489,6 +408,7 @@ tor_tls_init(void)
                    "support (using the enable-ec_nistp_64_gcc_128 option "
                    "when configuring it) would make ECDH much faster.");
     }
+    /* LCOV_EXCL_STOP */
 #endif
 
     tor_tls_allocate_tor_tls_object_ex_data_index();
@@ -519,7 +439,7 @@ tor_tls_free_all(void)
  * it: We always accept peer certs and complete the handshake.  We
  * don't validate them until later.
  */
-static int
+STATIC int
 always_accept_verify_cb(int preverify_ok,
                         X509_STORE_CTX *x509_ctx)
 {
@@ -534,16 +454,20 @@ tor_x509_name_new(const char *cname)
 {
   int nid;
   X509_NAME *name;
+  /* LCOV_EXCL_BR_START because these branches will only fail on out of memory errors */
   if (!(name = X509_NAME_new()))
     return NULL;
   if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
   if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
                                    (unsigned char*)cname, -1, -1, 0)))
     goto error;
+  /* LCOV_EXCL_BR_STOP */
   return name;
  error:
+  /* LCOV_EXCL_START because these lines will only execute on out of memory errors*/
   X509_NAME_free(name);
   return NULL;
+  /* LCOV_EXCL_STOP */
 }
 
 /** Generate and sign an X509 certificate with the public key <b>rsa</b>,
@@ -554,12 +478,12 @@ tor_x509_name_new(const char *cname)
  *
  * Return a certificate on success, NULL on failure.
  */
-static X509 *
-tor_tls_create_certificate(crypto_pk_t *rsa,
-                           crypto_pk_t *rsa_sign,
-                           const char *cname,
-                           const char *cname_sign,
-                           unsigned int cert_lifetime)
+MOCK_IMPL(STATIC X509 *,
+          tor_tls_create_certificate,(crypto_pk_t *rsa,
+                                      crypto_pk_t *rsa_sign,
+                                      const char *cname,
+                                      const char *cname_sign,
+                                      unsigned int cert_lifetime))
 {
   /* OpenSSL generates self-signed certificates with random 64-bit serial
    * numbers, so let's do that too. */
@@ -590,17 +514,17 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
     goto error;
   if (!(pkey = crypto_pk_get_evp_pkey_(rsa,0)))
     goto error;
-  if (!(x509 = X509_new()))
+  if (!(x509 = X509_new())) /* LCOV_EXCL_BR_LINE because this can only fail when memory failures occur */
     goto error;
-  if (!(X509_set_version(x509, 2)))
+  if (!(X509_set_version(x509, 2))) /* LCOV_EXCL_BR_LINE because this can only fail when something catastrophic happens in openssl  */
     goto error;
 
   { /* our serial number is 8 random bytes. */
     if (crypto_rand((char *)serial_tmp, sizeof(serial_tmp)) < 0)
       goto error;
-    if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL)))
+    if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL))) /* LCOV_EXCL_BR_LINE because this can only fail when memory failures occur */
       goto error;
-    if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509))))
+    if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509)))) /* LCOV_EXCL_BR_LINE because this can only fail when memory failures occur */
       goto error;
   }
 
@@ -726,7 +650,9 @@ tor_x509_cert_free(tor_x509_cert_t *cert)
     X509_free(cert->cert);
   tor_free(cert->encoded);
   memwipe(cert, 0x03, sizeof(*cert));
+  /* LCOV_EXCL_BR_START since cert will never be NULL here */
   tor_free(cert);
+  /* LCOV_EXCL_BR_STOP */
 }
 
 /**
@@ -734,8 +660,8 @@ tor_x509_cert_free(tor_x509_cert_t *cert)
  *
  * Steals a reference to x509_cert.
  */
-static tor_x509_cert_t *
-tor_x509_cert_new(X509 *x509_cert)
+MOCK_IMPL(STATIC tor_x509_cert_t *,
+          tor_x509_cert_new,(X509 *x509_cert))
 {
   tor_x509_cert_t *cert;
   EVP_PKEY *pkey;
@@ -748,11 +674,13 @@ tor_x509_cert_new(X509 *x509_cert)
 
   length = i2d_X509(x509_cert, &buf);
   cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
-  if (length <= 0 || buf == NULL) {
+  if (length <= 0 || buf == NULL) { /* LCOV_EXCL_BR_LINE because these conditions can't be provoked without memory failures */
+    /* LCOV_EXCL_START for the same reason as the exclusion above */
     tor_free(cert);
     log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate");
     X509_free(x509_cert);
     return NULL;
+    /* LCOV_EXCL_STOP */
   }
   cert->encoded_len = (size_t) length;
   cert->encoded = tor_malloc(length);
@@ -859,7 +787,9 @@ tor_tls_context_decref(tor_tls_context_t *ctx)
     tor_x509_cert_free(ctx->my_auth_cert);
     crypto_pk_free(ctx->link_key);
     crypto_pk_free(ctx->auth_key);
+    /* LCOV_EXCL_BR_START since ctx will never be NULL here */
     tor_free(ctx);
+    /* LCOV_EXCL_BR_STOP */
   }
 }
 
@@ -955,7 +885,6 @@ tor_tls_cert_is_valid(int severity,
                       int check_rsa_1024)
 {
   check_no_tls_errors();
-
   EVP_PKEY *cert_key;
   EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert);
   int r, key_ok = 0;
@@ -1080,7 +1009,7 @@ tor_tls_context_init(unsigned flags,
  * it generates new certificates; all new connections will use
  * the new SSL context.
  */
-static int
+STATIC int
 tor_tls_context_init_one(tor_tls_context_t **ppcontext,
                          crypto_pk_t *identity,
                          unsigned int key_lifetime,
@@ -1114,7 +1043,7 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
  * <b>identity</b> should be set to the identity key used to sign the
  * certificate.
  */
-static tor_tls_context_t *
+STATIC tor_tls_context_t *
 tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
                     unsigned flags, int is_client)
 {
@@ -1261,7 +1190,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
       goto error;
     X509_free(cert); /* We just added a reference to cert. */
     cert=NULL;
-    if (idcert) {
+    if (idcert) { /* LCOV_EXCL_BR_LINE because we can't actually get here without a valid idcert */
       X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
       tor_assert(s);
       X509_STORE_add_cert(s, idcert);
@@ -1338,10 +1267,10 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
 }
 
 /** Invoked when a TLS state changes: log the change at severity 'debug' */
-static void
+STATIC void
 tor_tls_debug_state_callback(const SSL *ssl, int type, int val)
 {
-  log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].",
+  log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].", /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
             ssl, SSL_state_string_long(ssl), type, val);
 }
 
@@ -1358,7 +1287,7 @@ tor_tls_get_ciphersuite_name(tor_tls_t *tls)
  * 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[] = {
+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 */
@@ -1394,7 +1323,7 @@ static int v2_cipher_list_pruned = 0;
 
 /** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>;
  * return 1 if it does support it, or if we have no way to tell. */
-static int
+STATIC int
 find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
 {
   const SSL_CIPHER *c;
@@ -1402,7 +1331,7 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
   {
     unsigned char cipherid[3];
     tor_assert(ssl);
-    set_uint16(cipherid, htons(cipher));
+    set_uint16(cipherid, htons(cipher));  /* LCOV_EXCL_BR_LINE since we won't necessarily hit both branches if htons is a macro */
     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. */
@@ -1414,7 +1343,7 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
 #elif defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR)
   if (m && m->get_cipher_by_char) {
     unsigned char cipherid[3];
-    set_uint16(cipherid, htons(cipher));
+    set_uint16(cipherid, htons(cipher)); /* LCOV_EXCL_BR_LINE since we won't necessarily hit both branches if htons is a macro */
     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. */
@@ -1476,7 +1405,7 @@ prune_v2_cipher_list(const SSL *ssl)
  * client it is.  Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2,
  * CIPHERS_UNRESTRICTED.
  **/
-static int
+STATIC int
 tor_tls_classify_client_ciphers(const SSL *ssl,
                                 STACK_OF(SSL_CIPHER) *peer_ciphers)
 {
@@ -1505,7 +1434,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
         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);
+      log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername); /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
       // return 1;
       goto v2_or_higher;
     }
@@ -1543,9 +1472,9 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
       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'",
+    log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s.  It is: '%s'", /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
               (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s);
-    tor_free(s);
+    tor_free(s); /* LCOV_EXCL_BR_LINE since s will always be non-null here */
     smartlist_free(elts);
   }
  done:
@@ -1558,7 +1487,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
 /** Return true iff the cipher list suggested by the client for <b>ssl</b> is
  * a list that indicates that the client knows how to do the v2 TLS connection
  * handshake. */
-static int
+STATIC int
 tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
 {
   STACK_OF(SSL_CIPHER) *ciphers;
@@ -1582,7 +1511,7 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
  *         do not send or request extra certificates in v2 handshakes.</li>
  * <li>To detect renegotiation</li></ul>
  */
-static void
+STATIC void
 tor_tls_server_info_callback(const SSL *ssl, int type, int val)
 {
   tor_tls_t *tls;
@@ -1598,7 +1527,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
   if ((ssl_state != SSL3_ST_SW_SRVR_HELLO_A) &&
       (ssl_state != SSL3_ST_SW_SRVR_HELLO_B))
     return;
-
   tls = tor_tls_get_by_ssl(ssl);
   if (tls) {
     /* Check whether we're watching for renegotiates.  If so, this is one! */
@@ -1625,10 +1553,10 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
     /* Don't send a hello request. */
     SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);
 
-    if (tls) {
+    if (tls) { /* LCOV_EXCL_BR_LINE impossible to have tls be NULL here, it's checked earlier */
       tls->wasV2Handshake = 1;
     } else {
-      log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
+      log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); /* LCOV_EXCL_LINE this line is not reachable */
     }
   }
 }
@@ -1646,7 +1574,7 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
  * authentication on the fly.  But as long as we return 0, we won't actually be
  * setting up a shared secret, and all will be fine.
  */
-static int
+STATIC int
 tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len,
                           STACK_OF(SSL_CIPHER) *peer_ciphers,
                           SSL_CIPHER **cipher, void *arg)
@@ -1688,7 +1616,7 @@ tor_tls_new(int sock, int isServer)
   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);
+    tor_free(result); /* LCOV_EXCL_BR_LINE because result can't be null here */
     goto err;
   }
 
@@ -1697,7 +1625,7 @@ tor_tls_new(int sock, int isServer)
   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);
+    tor_free(fake_hostname); /* LCOV_EXCL_BR_LINE because fake_hostname can't be null here */
   }
 #endif
 
@@ -1708,7 +1636,7 @@ tor_tls_new(int sock, int isServer)
     SSL_set_tlsext_host_name(result->ssl, NULL);
 #endif
     SSL_free(result->ssl);
-    tor_free(result);
+    tor_free(result); /* LCOV_EXCL_BR_LINE because this can't be null here */
     goto err;
   }
   result->socket = sock;
@@ -1861,7 +1789,7 @@ tor_tls_free(tor_tls_t *tls)
     tor_tls_context_decref(tls->context);
   tor_free(tls->address);
   tls->magic = 0x99999999;
-  tor_free(tls);
+  tor_free(tls); /* LCOV_EXCL_BR_LINE because this line will not be reached if tls is NULL */
 }
 
 /** Underlying function for TLS reading.  Reads up to <b>len</b>
@@ -1882,7 +1810,7 @@ tor_tls_read,(tor_tls_t *tls, char *cp, size_t len))
 #ifdef V2_HANDSHAKE_SERVER
     if (tls->got_renegotiate) {
       /* Renegotiation happened! */
-      log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls));
+      log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls)); /* LCOV_EXCL_BR_LINE because testing the branches of ADDR feels not so useful here */
       if (tls->negotiated_callback)
         tls->negotiated_callback(tls, tls->callback_arg);
       tls->got_renegotiate = 0;
@@ -1891,23 +1819,23 @@ tor_tls_read,(tor_tls_t *tls, char *cp, size_t len))
     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);
+  if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) { /* LCOV_EXCL_BR_LINE err can never be TOR_TLS_CLOSE here because tor_tls_get_error will never return it with those parameters */
+    log_debug(LD_NET,"read returned r=%d; TLS is closed",r); /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
     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);
+    log_debug(LD_NET,"read returned r=%d, err=%d",r,err); /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
     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;
+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;
+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
@@ -1927,7 +1855,7 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
   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)",
+    log_debug(LD_NET,"resuming pending-write, (%d to flush, reusing %d)", /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
               (int)n, (int)tls->wantwrite_n);
     n = tls->wantwrite_n;
     tls->wantwrite_n = 0;
@@ -1956,19 +1884,20 @@ tor_tls_handshake(tor_tls_t *tls)
   tor_assert(tls);
   tor_assert(tls->ssl);
   tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
+
   check_no_tls_errors();
   oldstate = SSL_state(tls->ssl);
   if (tls->isServer) {
-    log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
+    log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls, /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
               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,
+    log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls, /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
               SSL_state_string_long(tls->ssl));
     r = SSL_connect(tls->ssl);
   }
   if (oldstate != SSL_state(tls->ssl))
-    log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
+    log_debug(LD_HANDSHAKE, "After call, %p was in state %s",  /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
               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. */
@@ -2013,7 +1942,7 @@ tor_tls_finish_handshake(tor_tls_t *tls)
                  " get set. Fixing that.");
       }
       tls->wasV2Handshake = 1;
-      log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting"
+      log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting" /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
                 " for renegotiation.");
     } else {
       tls->wasV2Handshake = 0;
@@ -2026,11 +1955,11 @@ tor_tls_finish_handshake(tor_tls_t *tls)
     STACK_OF(X509) *chain = SSL_get_peer_cert_chain(tls->ssl);
     int n_certs = sk_X509_num(chain);
     if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0))) {
-      log_debug(LD_HANDSHAKE, "Server sent back multiple certificates; it "
+      log_debug(LD_HANDSHAKE, "Server sent back multiple certificates; it " /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
                 "looks like a v1 handshake on %p", tls);
       tls->wasV2Handshake = 0;
     } else {
-      log_debug(LD_HANDSHAKE,
+      log_debug(LD_HANDSHAKE, /* LCOV_EXCL_BR_LINE since this depends on whether debug is captured or not */
                 "Server sent back a single certificate; looks like "
                 "a v2 handshake on %p.", tls);
       tls->wasV2Handshake = 1;
@@ -2246,15 +2175,13 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem)
  *
  * Note that a reference is added to cert_out, so it needs to be
  * freed. id_cert_out doesn't. */
-static void
-try_to_extract_certs_from_tls(int severity, tor_tls_t *tls,
-                              X509 **cert_out, X509 **id_cert_out)
+MOCK_IMPL(STATIC void, try_to_extract_certs_from_tls, (int severity, tor_tls_t *tls,
+                                                       X509 **cert_out, X509 **id_cert_out))
 {
   X509 *cert = NULL, *id_cert = NULL;
   STACK_OF(X509) *chain = NULL;
   int num_in_chain, i;
   *cert_out = *id_cert_out = NULL;
-
   if (!(cert = SSL_get_peer_certificate(tls->ssl)))
     return;
   *cert_out = cert;
@@ -2271,7 +2198,7 @@ try_to_extract_certs_from_tls(int severity, tor_tls_t *tls,
            num_in_chain);
     return;
   }
-  for (i=0; i<num_in_chain; ++i) {
+  for (i=0; i<num_in_chain; ++i) { /* LCOV_EXCL_BR_LINE because we can never hit the case when we don't enter this loop, since num_in_chain<1 is checked above */
     id_cert = sk_X509_value(chain, i);
     if (X509_cmp(id_cert, cert) != 0)
       break;
@@ -2489,7 +2416,7 @@ tor_tls_used_v1_handshake(tor_tls_t *tls)
 
 /** Return true iff <b>name</b> is a DN of a kind that could only
  * occur in a v3-handshake-indicating certificate */
-static int
+STATIC int
 dn_indicates_v3_cert(X509_NAME *name)
 {
 #ifdef DISABLE_V3_LINKPROTO_CLIENTSIDE
@@ -2504,18 +2431,21 @@ dn_indicates_v3_cert(X509_NAME *name)
   int len, r;
 
   n_entries = X509_NAME_entry_count(name);
-  if (n_entries != 1)
+  if (n_entries != 1) {
     return 1; /* More than one entry in the DN. */
+  }
   entry = X509_NAME_get_entry(name, 0);
 
   obj = X509_NAME_ENTRY_get_object(entry);
-  if (OBJ_obj2nid(obj) != OBJ_txt2nid("commonName"))
+  if (OBJ_obj2nid(obj) != OBJ_txt2nid("commonName")) {
     return 1; /* The entry isn't a commonName. */
+  }
 
   str = X509_NAME_ENTRY_get_data(entry);
   len = ASN1_STRING_to_UTF8(&s, str);
-  if (len < 0)
+  if (len < 0){
     return 0;
+  }
   r = fast_memneq(s + len - 4, ".net", 4);
   OPENSSL_free(s);
   return r;
@@ -2620,7 +2550,7 @@ SSL_get_server_random(SSL *s, uint8_t *out, size_t len)
 #endif
 
 #ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
-static size_t
+STATIC size_t
 SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len)
 {
   tor_assert(s);
@@ -2643,7 +2573,6 @@ 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;
@@ -2667,12 +2596,14 @@ tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
     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);
@@ -2692,7 +2623,7 @@ tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
                      (char*)buf, len);
   memwipe(buf, 0, sizeof(buf));
   memwipe(master_key, 0, master_key_len);
-  tor_free(master_key);
+  tor_free(master_key); /* LCOV_EXCL_BR_LINE since master_key will never be NULL here */
 
   return 0;
 }
@@ -2829,4 +2760,3 @@ evaluate_ecgroup_for_tls(const char *ecgroup)
 
   return ret;
 }
-
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 124b771..461116d 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -11,6 +11,9 @@
  * \brief Headers for tortls.c
  **/
 
+#include <openssl/ssl.h>
+#include <openssl/ssl3.h>
+
 #include "crypto.h"
 #include "compat.h"
 #include "testsupport.h"
@@ -51,6 +54,113 @@ typedef struct tor_x509_cert_t tor_x509_cert_t;
   case TOR_TLS_ERROR_IO
 
 #define TOR_TLS_IS_ERROR(rv) ((rv) < TOR_TLS_CLOSE)
+
+
+#ifdef TORTLS_PRIVATE
+#define TOR_TLS_MAGIC 0x71571571
+
+typedef enum {
+    TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
+    TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE,
+    TOR_TLS_ST_BUFFEREVENT
+} tor_tls_state_t;
+#define tor_tls_state_bitfield_t ENUM_BF(tor_tls_state_t)
+
+/** Holds a SSL_CTX object and related state used to configure TLS
+ * connections.
+ */
+typedef struct tor_tls_context_t {
+  int refcnt;
+  SSL_CTX *ctx;
+  tor_x509_cert_t *my_link_cert;
+  tor_x509_cert_t *my_id_cert;
+  tor_x509_cert_t *my_auth_cert;
+  crypto_pk_t *link_key;
+  crypto_pk_t *auth_key;
+} tor_tls_context_t;
+
+/** Structure that we use for a single certificate. */
+struct tor_x509_cert_t {
+  X509 *cert;
+  uint8_t *encoded;
+  size_t encoded_len;
+  unsigned pkey_digests_set : 1;
+  digests_t cert_digests;
+  digests_t pkey_digests;
+};
+
+/** Holds a SSL object and its associated data.  Members are only
+ * accessed from within tortls.c.
+ */
+struct tor_tls_t {
+  uint32_t magic;
+  tor_tls_context_t *context; /** A link to the context object for this tls. */
+  SSL *ssl; /**< An OpenSSL SSL object. */
+  int socket; /**< The underlying file descriptor for this TLS connection. */
+  char *address; /**< An address to log when describing this connection. */
+  tor_tls_state_bitfield_t state : 3; /**< The current SSL state,
+                                       * depending on which operations
+                                       * have completed successfully. */
+  unsigned int isServer:1; /**< True iff this is a server-side connection */
+  unsigned int wasV2Handshake:1; /**< True iff the original handshake for
+                                  * this connection used the updated version
+                                  * of the connection protocol (client sends
+                                  * different cipher list, server sends only
+                                  * one certificate). */
+  /** True iff we should call negotiated_callback when we're done reading. */
+  unsigned int got_renegotiate:1;
+  /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't
+   * called that function yet. */
+  int8_t client_cipher_list_type;
+  /** Incremented every time we start the server side of a handshake. */
+  uint8_t server_handshake_count;
+  size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
+                       * time. */
+  /** Last values retrieved from BIO_number_read()/write(); see
+   * tor_tls_get_n_raw_bytes() for usage.
+   */
+  unsigned long last_write_count;
+  unsigned long last_read_count;
+  /** If set, a callback to invoke whenever the client tries to renegotiate
+   * the handshake. */
+  void (*negotiated_callback)(tor_tls_t *tls, void *arg);
+  /** Argument to pass to negotiated_callback. */
+  void *callback_arg;
+};
+
+
+STATIC int tor_errno_to_tls_error(int e);
+STATIC int tor_tls_get_error(tor_tls_t *tls, int r, int extra,
+                  const char *doing, int severity, int domain);
+STATIC tor_tls_t *tor_tls_get_by_ssl(const SSL *ssl);
+STATIC void tor_tls_allocate_tor_tls_object_ex_data_index(void);
+STATIC int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx);
+STATIC int tor_tls_classify_client_ciphers(const SSL *ssl, STACK_OF(SSL_CIPHER) *peer_ciphers);
+STATIC int tor_tls_client_is_using_v2_ciphers(const SSL *ssl);
+MOCK_DECL(STATIC void, try_to_extract_certs_from_tls, (int severity, tor_tls_t *tls, X509 **cert_out, X509 **id_cert_out));
+STATIC int dn_indicates_v3_cert(X509_NAME *name);
+STATIC size_t SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len);
+STATIC void tor_tls_debug_state_callback(const SSL *ssl, int type, int val);
+STATIC void tor_tls_server_info_callback(const SSL *ssl, int type, int val);
+STATIC int tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher);
+MOCK_DECL(STATIC X509*, tor_tls_create_certificate,(crypto_pk_t *rsa,
+                                                    crypto_pk_t *rsa_sign,
+                                                    const char *cname,
+                                                    const char *cname_sign,
+                                                    unsigned int cert_lifetime));
+STATIC tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, unsigned flags, int is_client);
+MOCK_DECL(STATIC tor_x509_cert_t *, tor_x509_cert_new,(X509 *x509_cert));
+STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
+                                    crypto_pk_t *identity,
+                                    unsigned int key_lifetime,
+                                    unsigned int flags,
+                                    int is_client);
+#endif
+
+
+
+
 const char *tor_tls_err_to_string(int err);
 void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz);
 
@@ -143,4 +253,3 @@ const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls);
 int evaluate_ecgroup_for_tls(const char *ecgroup);
 
 #endif
-
diff --git a/src/test/include.am b/src/test/include.am
index f7c0204..a2be1ff 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -51,6 +51,7 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
 # matters a lot there, and is quite hard to debug if you forget to do it.
 
 src_test_test_SOURCES = \
+	src/test/log_test_helpers.c \
 	src/test/test.c \
 	src/test/test_accounting.c \
 	src/test/test_addr.c \
@@ -95,6 +96,7 @@ src_test_test_SOURCES = \
 	src/test/test_socks.c \
 	src/test/test_status.c \
 	src/test/test_threads.c \
+	src/test/test_tortls.c \
 	src/test/test_util.c \
 	src/test/test_helpers.c \
         src/test/test_dns.c \
diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c
new file mode 100644
index 0000000..42778d4
--- /dev/null
+++ b/src/test/log_test_helpers.c
@@ -0,0 +1,95 @@
+#define LOG_PRIVATE
+#include "torlog.h"
+#include "log_test_helpers.h"
+
+static smartlist_t *saved_logs = NULL;
+
+int
+setup_capture_of_logs(int new_level)
+{
+  int previous_log = log_global_min_severity_;
+  log_global_min_severity_ = new_level;
+  mock_clean_saved_logs();
+  MOCK(logv, mock_saving_logv);
+  return previous_log;
+}
+
+void
+teardown_capture_of_logs(int prev)
+{
+  UNMOCK(logv);
+  log_global_min_severity_ = prev;
+  mock_clean_saved_logs();
+}
+
+void
+mock_clean_saved_logs(void)
+{
+  if (!saved_logs)
+    return;
+  SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m,
+                    { tor_free(m->generated_msg); tor_free(m); });
+  smartlist_free(saved_logs);
+  saved_logs = NULL;
+}
+
+char *
+mock_saved_log_at(int ix)
+{
+  int saved_log_count = mock_saved_log_number();
+  if(ix < 0) {
+    ix = saved_log_count + ix;
+  }
+
+  if (saved_log_count <= ix)
+    return "";
+  return ((mock_saved_log_entry_t *)smartlist_get(saved_logs, ix))->generated_msg;
+}
+
+int
+mock_saved_severity_at(int ix)
+{
+  int saved_log_count = mock_saved_log_number();
+  if(ix < 0) {
+    ix = saved_log_count + ix;
+  }
+
+  if (saved_log_count <= ix)
+    return -1;
+  return ((mock_saved_log_entry_t *)smartlist_get(saved_logs, ix))->severity;
+}
+
+int
+mock_saved_log_number(void)
+{
+  if (!saved_logs)
+    return 0;
+  return smartlist_len(saved_logs);
+}
+
+const smartlist_t *
+mock_saved_logs(void)
+{
+  return saved_logs;
+}
+
+void
+mock_saving_logv(int severity, log_domain_mask_t domain, const char *funcname, const char *suffix, const char *format, va_list ap)
+{
+  char *buf = tor_malloc_zero(10240);
+  int n;
+  n = tor_vsnprintf(buf,10240,format,ap);
+  buf[n]='\n';
+  buf[n+1]='\0';
+
+  mock_saved_log_entry_t *e = tor_malloc_zero(sizeof(mock_saved_log_entry_t));
+  e->severity = severity;
+  e->funcname = funcname;
+  e->suffix = suffix;
+  e->format = format;
+  e->generated_msg = buf;
+
+  if (!saved_logs)
+    saved_logs = smartlist_new();
+  smartlist_add(saved_logs, e);
+}
diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h
new file mode 100644
index 0000000..789bfe4
--- /dev/null
+++ b/src/test/log_test_helpers.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+
+#ifndef TOR_LOG_TEST_HELPERS_H
+#define TOR_LOG_TEST_HELPERS_H
+
+typedef struct mock_saved_log_entry_t {
+  int severity;
+  const char *funcname;
+  const char *suffix;
+  const char *format;
+  char *generated_msg;
+  struct mock_saved_log_entry_t *next;
+} mock_saved_log_entry_t;
+
+void mock_saving_logv(int severity, log_domain_mask_t domain, const char *funcname, const char *suffix, const char *format, va_list ap);
+void mock_clean_saved_logs(void);
+const smartlist_t *mock_saved_logs(void);
+int setup_capture_of_logs(int new_level);
+void teardown_capture_of_logs(int prev);
+char *mock_saved_log_at(int ix);
+int mock_saved_severity_at(int ix);
+int mock_saved_log_number(void);
+
+#endif
diff --git a/src/test/test.c b/src/test/test.c
index e10e260..3509c12 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1157,6 +1157,7 @@ extern struct testcase_t scheduler_tests[];
 extern struct testcase_t socks_tests[];
 extern struct testcase_t status_tests[];
 extern struct testcase_t thread_tests[];
+extern struct testcase_t tortls_tests[];
 extern struct testcase_t util_tests[];
 extern struct testcase_t dns_tests[];
 
@@ -1202,10 +1203,10 @@ struct testgroup_t testgroups[] = {
   { "scheduler/", scheduler_tests },
   { "socks/", socks_tests },
   { "status/" , status_tests },
+  { "tortls/", tortls_tests },
   { "util/", util_tests },
   { "util/logging/", logging_tests },
   { "util/thread/", thread_tests },
   { "dns/", dns_tests },
   END_OF_GROUPS
 };
-
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
new file mode 100644
index 0000000..d6feec0
--- /dev/null
+++ b/src/test/test_tortls.c
@@ -0,0 +1,2762 @@
+/* Copyright (c) 2010-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define TORTLS_PRIVATE
+#define LOG_PRIVATE
+#include "orconfig.h"
+
+#include "or.h"
+#include "torlog.h"
+#include "config.h"
+#include "tortls.h"
+
+#include "test.h"
+#include "log_test_helpers.h"
+
+#include <openssl/ssl.h>
+#include <openssl/ssl3.h>
+#include <openssl/err.h>
+#include <openssl/asn1t.h>
+
+#define NS_MODULE tortls
+
+extern tor_tls_context_t *server_tls_context;
+extern tor_tls_context_t *client_tls_context;
+
+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;
+}
+
+static void
+test_tortls_errno_to_tls_error(void *data)
+{
+    tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ECONNRESET)),OP_EQ,TOR_TLS_ERROR_CONNRESET);
+    tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ETIMEDOUT)),OP_EQ,TOR_TLS_ERROR_TIMEOUT);
+    tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(EHOSTUNREACH)),OP_EQ,TOR_TLS_ERROR_NO_ROUTE);
+    tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ENETUNREACH)),OP_EQ,TOR_TLS_ERROR_NO_ROUTE);
+    tt_int_op(tor_errno_to_tls_error(SOCK_ERRNO(ECONNREFUSED)),OP_EQ,TOR_TLS_ERROR_CONNREFUSED);
+    tt_int_op(tor_errno_to_tls_error(0),OP_EQ,TOR_TLS_ERROR_MISC);
+ done:
+  (void)1;
+}
+
+static void
+test_tortls_err_to_string(void *data)
+{
+    tt_str_op(tor_tls_err_to_string(1),OP_EQ,"[Not an error.]");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_MISC),OP_EQ,"misc error");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_IO),OP_EQ,"unexpected close");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_CONNREFUSED),OP_EQ,"connection refused");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_CONNRESET),OP_EQ,"connection reset");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_NO_ROUTE),OP_EQ,"host unreachable");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_ERROR_TIMEOUT),OP_EQ,"connection timed out");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_CLOSE),OP_EQ,"closed");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_WANTREAD),OP_EQ,"want to read");
+    tt_str_op(tor_tls_err_to_string(TOR_TLS_WANTWRITE),OP_EQ,"want to write");
+    tt_str_op(tor_tls_err_to_string(-100),OP_EQ,"(unknown error code)");
+ done:
+  (void)1;
+}
+
+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)
+{
+    MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
+    crypto_pk_t *key1 = NULL, *key2 = NULL;
+    key1 = pk_generate(2);
+    key2 = pk_generate(3);
+
+    tor_tls_t *tls;
+    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);
+
+
+    client_tls_context->ctx = NULL;
+    tls = tor_tls_new(-1, 0);
+    tt_assert(!tls);
+
+    SSL_METHOD *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_assert(!tls);
+
+ done:
+  UNMOCK(tor_tls_cert_matches_key);
+  crypto_pk_free(key1);
+  crypto_pk_free(key2);
+}
+
+#define NS_MODULE tortls
+NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
+    const char *funcname, const char *suffix, const char *format, va_list ap));
+
+static void
+NS(logv)(int severity, log_domain_mask_t domain,
+    const char *funcname, const char *suffix, const char *format,
+    va_list ap)
+{
+    (void) severity;
+    (void) domain;
+    (void) funcname;
+    (void) suffix;
+    (void) format;
+    (void) ap; // XXXX look at this.
+    CALLED(logv)++;
+}
+
+static void
+test_tortls_tor_tls_get_error(void *data)
+{
+    MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
+    crypto_pk_t *key1 = NULL, *key2 = NULL;
+    key1 = pk_generate(2);
+    key2 = pk_generate(3);
+
+    tor_tls_t *tls;
+    tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
+                key1, key2, 86400), OP_EQ, 0);
+    tls = tor_tls_new(-1, 0);
+    NS_MOCK(logv);
+    tt_int_op(CALLED(logv), OP_EQ, 0);
+    tor_tls_get_error(tls, 0, 0,
+            (const char *)"test", 0, 0);
+    tt_int_op(CALLED(logv), OP_EQ, 1);
+
+ done:
+  UNMOCK(tor_tls_cert_matches_key);
+  NS_UNMOCK(logv);
+  crypto_pk_free(key1);
+  crypto_pk_free(key2);
+}
+
+static void
+test_tortls_get_state_description(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  char *buf;
+  SSL_CTX *ctx;
+
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  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)");
+
+  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, "before/accept initialization in HANDSHAKE");
+
+  tls->state = TOR_TLS_ST_OPEN;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, "before/accept initialization in OPEN");
+
+  tls->state = TOR_TLS_ST_GOTCLOSE;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, "before/accept initialization in GOTCLOSE");
+
+  tls->state = TOR_TLS_ST_SENTCLOSE;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, "before/accept initialization in SENTCLOSE");
+
+  tls->state = TOR_TLS_ST_CLOSED;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, "before/accept initialization in CLOSED");
+
+  tls->state = TOR_TLS_ST_RENEGOTIATE;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, "before/accept initialization in RENEGOTIATE");
+
+  tls->state = TOR_TLS_ST_BUFFEREVENT;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, "before/accept initialization");
+
+  tls->state = 7;
+  tor_tls_get_state_description(tls, buf, 200);
+  tt_str_op(buf, OP_EQ, "before/accept initialization in unknown TLS state");
+
+ done:
+  SSL_CTX_free(ctx);
+  tor_free(buf);
+  tor_free(tls);
+}
+
+extern int tor_tls_object_ex_data_index;
+
+static void
+test_tortls_get_by_ssl(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  tor_tls_t *res;
+  SSL_CTX *ctx;
+  SSL *ssl;
+
+  SSL_library_init();
+  SSL_load_error_strings();
+  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;
+
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  ctx = SSL_CTX_new(SSLv23_method());
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  int previous_log = setup_capture_of_logs(LOG_INFO);
+
+  tor_tls_log_one_error(NULL, 0, LOG_WARN, 0, "something");
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error while something: (null) (in (null):(null):---)\n");
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error: (null) (in (null):(null):---)\n");
+
+  mock_clean_saved_logs();
+  tls->address = "127.hello";
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error with 127.hello: (null) (in (null):(null):---)\n");
+
+
+  mock_clean_saved_logs();
+  tls->address = "127.hello";
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, "blarg");
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, 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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, 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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_TOO_LARGE), LOG_WARN, 0, NULL);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNKNOWN_PROTOCOL), LOG_WARN, 0, NULL);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNSUPPORTED_PROTOCOL), LOG_WARN, 0, NULL);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO);
+
+  tls->ssl = SSL_new(ctx);
+
+  mock_clean_saved_logs();
+  tor_tls_log_one_error(tls, 0, LOG_WARN, 0, NULL);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error with 127.hello: (null) (in (null):(null):before/accept initialization)\n");
+
+ done:
+  teardown_capture_of_logs(previous_log);
+  SSL_free(ssl);
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+}
+
+static void
+test_tortls_get_error(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  int ret;
+  SSL_CTX *ctx;
+
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  ctx = SSL_CTX_new(SSLv23_method());
+  int previous_log = 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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 0);
+
+  mock_clean_saved_logs();
+  ret = tor_tls_get_error(tls, 0, 1, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, -11);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 0);
+
+  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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 0);
+
+  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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 0);
+
+
+  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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+
+  mock_clean_saved_logs();
+  ret = tor_tls_get_error(tls, 0, 2, "something", LOG_WARN, 0);
+  tt_int_op(ret, OP_EQ, -10);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 0);
+
+  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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 2);
+  tt_str_op(mock_saved_log_at(1), OP_EQ, "TLS error while something: (null) (in system library:connect:before/accept initialization)\n");
+
+ done:
+  teardown_capture_of_logs(previous_log);
+  tor_free(tls);
+}
+
+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;
+}
+
+
+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 = tor_malloc_zero(sizeof(X509));
+  cert->encoded = tor_malloc_zero(1);
+  tor_x509_cert_free(cert);
+}
+
+static void
+test_tortls_x509_cert_get_id_digests(void *ignored)
+{
+  (void)ignored;
+  tor_x509_cert_t *cert;
+  digests_t *d;
+  const digests_t *res;
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  d = tor_malloc_zero(sizeof(digests_t));
+  d->d[0][0] = 42;
+
+  res = tor_x509_cert_get_id_digests(cert);
+  tt_assert(!res);
+
+  cert->pkey_digests_set = 1;
+  cert->pkey_digests = *d;
+  res = tor_x509_cert_get_id_digests(cert);
+  tt_int_op(res->d[0][0], OP_EQ, 42);
+
+ done:
+  (void)0;
+}
+
+static int
+fixed_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
+{
+  return 1;
+}
+
+static void
+test_tortls_cert_matches_key(void *ignored)
+{
+  (void)ignored;
+  int res;
+  tor_tls_t *tls;
+  tor_x509_cert_t *cert;
+  X509 *one, *two;
+  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 = tor_malloc_zero(sizeof(X509));
+  one->references = 1;
+  two = tor_malloc_zero(sizeof(X509));
+  two->references = 1;
+
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+  tls->ssl->session->peer = one;
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  cert->cert = two;
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  one->cert_info = tor_malloc_zero(sizeof(X509_CINF));
+  one->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
+  one->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
+  one->cert_info->key->pkey->references = 1;
+  one->cert_info->key->pkey->ameth = meth;
+  one->cert_info->key->pkey->type = 1;
+
+  two->cert_info = tor_malloc_zero(sizeof(X509_CINF));
+  two->cert_info->key = tor_malloc_zero(sizeof(X509_PUBKEY));
+  two->cert_info->key->pkey = tor_malloc_zero(sizeof(EVP_PKEY));
+  two->cert_info->key->pkey->references = 1;
+  two->cert_info->key->pkey->ameth = meth;
+  two->cert_info->key->pkey->type = 2;
+
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 0);
+
+  one->cert_info->key->pkey->type = 1;
+  two->cert_info->key->pkey->type = 1;
+  res = tor_tls_cert_matches_key(tls, cert);
+  tt_int_op(res, OP_EQ, 1);
+
+ done:
+  EVP_PKEY_asn1_free(meth);
+  tor_free(tls);
+  tor_free(cert);
+}
+
+static void
+test_tortls_cert_get_key(void *ignored)
+{
+  (void)ignored;
+  tor_x509_cert_t *cert;
+  crypto_pk_t *res;
+  cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  X509 *key;
+  key = tor_malloc_zero(sizeof(X509));
+  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:
+  (void)0;
+}
+
+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 = tor_malloc_zero(sizeof(RSA));
+
+  ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
+  expected = crypto_new_pk_from_rsa_(k);
+  ctx->auth_key = expected;
+
+  client_tls_context = NULL;
+  ret = tor_tls_get_my_client_auth_key();
+  tt_assert(!ret);
+
+  client_tls_context = ctx;
+  ret = tor_tls_get_my_client_auth_key();
+  tt_assert(ret == expected);
+
+ done:
+  tor_free(expected);
+  tor_free(k);
+  tor_free(ctx);
+}
+
+static void
+test_tortls_get_my_certs(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_context_t *ctx;
+  const tor_x509_cert_t *link_cert_out = NULL;
+  const tor_x509_cert_t *id_cert_out = NULL;
+
+  ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
+
+  client_tls_context = NULL;
+  ret = tor_tls_get_my_certs(0, NULL, NULL);
+  tt_int_op(ret, OP_EQ, -1);
+
+  server_tls_context = NULL;
+  ret = tor_tls_get_my_certs(1, NULL, NULL);
+  tt_int_op(ret, OP_EQ, -1);
+
+  client_tls_context = ctx;
+  ret = tor_tls_get_my_certs(0, NULL, NULL);
+  tt_int_op(ret, OP_EQ, 0);
+
+  client_tls_context = ctx;
+  ret = tor_tls_get_my_certs(0, &link_cert_out, &id_cert_out);
+  tt_int_op(ret, OP_EQ, 0);
+
+  server_tls_context = ctx;
+  ret = tor_tls_get_my_certs(1, &link_cert_out, &id_cert_out);
+  tt_int_op(ret, OP_EQ, 0);
+
+
+ done:
+  (void)1;
+}
+
+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:
+  (void)1;
+}
+
+static SSL_CIPHER *
+get_cipher_by_name(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;
+}
+
+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;
+}
+
+extern uint16_t v2_cipher_list[];
+
+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;
+
+  SSL_library_init();
+  SSL_load_error_strings();
+  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("ECDH-RSA-AES256-GCM-SHA384");
+  one->id = 0x00ff;
+  two = get_cipher_by_name("ECDH-RSA-AES128-GCM-SHA256");
+  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:
+  (void)1;
+}
+
+static void
+test_tortls_client_is_using_v2_ciphers(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  SSL_CTX *ctx;
+  SSL *ssl;
+  SSL_SESSION *sess;
+  STACK_OF(SSL_CIPHER) *ciphers;
+
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  ctx = SSL_CTX_new(TLSv1_method());
+  ssl = SSL_new(ctx);
+  sess = SSL_SESSION_new();
+
+#ifdef HAVE_SSL_GET_CLIENT_CIPHERS
+#else
+  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("ECDH-RSA-AES256-GCM-SHA384");
+  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);
+#endif
+
+ done:
+  (void)1;
+}
+
+static X509 *fixed_try_to_extract_certs_from_tls_cert_out_result = NULL;
+static X509 *fixed_try_to_extract_certs_from_tls_id_cert_out_result = NULL;
+
+static void
+fixed_try_to_extract_certs_from_tls(int severity, tor_tls_t *tls, X509 **cert_out, X509 **id_cert_out)
+{
+  *cert_out = fixed_try_to_extract_certs_from_tls_cert_out_result;
+  *id_cert_out = fixed_try_to_extract_certs_from_tls_id_cert_out_result;
+}
+
+static const char* notCompletelyValidCertString = "-----BEGIN CERTIFICATE-----\n"
+  "MIICVjCCAb8CAg37MA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG\n"
+  "A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE\n"
+  "MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl\n"
+  "YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw\n"
+  "ODIyMDUyNzIzWhcNMTcwODIxMDUyNzIzWjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE\n"
+  "CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs\n"
+  "ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYBBrx5PlP0WNI/ZdzD\n"
+  "+6Pktmurn+F2kQYbtc7XQh8/LTBvCo+P6iZoLEmUA9e7EXLRxgU1CVqeAi7QcAn9\n"
+  "MwBlc8ksFJHB0rtf9pmf8Oza9E0Bynlq/4/Kb1x+d+AyhL7oK9tQwB24uHOueHi1\n"
+  "C/iVv8CSWKiYe6hzN1txYe8rAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAASPdjigJ\n"
+  "kXCqKWpnZ/Oc75EUcMi6HztaW8abUMlYXPIgkV2F7YanHOB7K4f7OOLjiz8DTPFf\n"
+  "jC9UeuErhaA/zzWi8ewMTFZW/WshOrm3fNvcMrMLKtH534JKvcdMg6qIdjTFINIr\n"
+  "evnAhf0cwULaebn+lMs8Pdl7y37+sfluVok=\n"
+  "-----END CERTIFICATE-----\n";
+
+
+static const char* validCertString = "-----BEGIN CERTIFICATE-----\n"
+  "MIIDpTCCAY0CAg3+MA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMREwDwYD\n"
+  "VQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIGA1UECgwLVG9yIFRl\n"
+  "c3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkwNjEzMzk1OVoXDTQz\n"
+  "MDEyMjEzMzk1OVowVjELMAkGA1UEBhMCVVMxEDAOBgNVBAcMB0NoaWNhZ28xFDAS\n"
+  "BgNVBAoMC1RvciBUZXN0aW5nMR8wHQYDVQQDDBZ0ZXN0aW5nLnRvcnByb2plY3Qu\n"
+  "b3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoT6uyVVhWyOF3wkHjjYbd\n"
+  "nKaykyRv4JVtKQdZ4OpEErmX1zw4MmyzpQNV6iR4bQnWiyLfzyVJMZDIC/WILBfX\n"
+  "w2Pza/yuLgUvDc3twMuhOACzOQVO8PrEF/aVv2+hbCCy2udXvKhnYn+CCXl3ozc8\n"
+  "XcKYvujTXDyvGWY3xwAjlQIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQCUvnhzQWuQ\n"
+  "MrN+pERkE+zcTI/9dGS90rUMMLgu8VDNqTa0TUQh8uO0EQ6uDvI8Js6e8tgwS0BR\n"
+  "UBahqb7ZHv+rejGCBr5OudqD+x4STiiuPNJVs86JTLN8SpM9CHjIBH5WCCN2KOy3\n"
+  "mevNoRcRRyYJzSFULCunIK6FGulszigMYGscrO4oiTkZiHPh9KvWT40IMiHfL+Lw\n"
+  "EtEWiLex6064LcA2YQ1AMuSZyCexks63lcfaFmQbkYOKqXa1oLkIRuDsOaSVjTfe\n"
+  "vec+X6jvf12cFTKS5WIeqkKF2Irt+dJoiHEGTe5RscUMN/f+gqHPzfFz5dR23sxo\n"
+  "g+HC6MZHlFkLAOx3wW6epPS8A/m1mw3zMPoTnb2U2YYt8T0dJMMlUn/7Y1sEAa+a\n"
+  "dSTMaeUf6VnJ//11m454EZl1to9Z7oJOgqmFffSrdD4BGIWe8f7hhW6L1Enmqe/J\n"
+  "BKL3wbzZh80O1W0bndAwhnEEhlzneFY84cbBo9pmVxpODHkUcStpr5Z7pBDrcL21\n"
+  "Ss/aB/1YrsVXhdvJdOGxl3Mnl9dUY57CympLGlT8f0pPS6GAKOelECOhFMHmJd8L\n"
+  "dj3XQSmKtYHevZ6IvuMXSlB/fJvSjSlkCuLo5+kJoaqPuRu+i/S1qxeRy3CBwmnE\n"
+  "LdSNdcX4N79GQJ996PA8+mUCQG7YRtK+WA==\n"
+  "-----END CERTIFICATE-----\n";
+
+static const char* caCertString = "-----BEGIN CERTIFICATE-----\n"
+  "MIIFjzCCA3egAwIBAgIJAKd5WgyfPMYRMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV\n"
+  "BAYTAlVTMREwDwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIG\n"
+  "A1UECgwLVG9yIFRlc3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkw\n"
+  "NjEzMzc0MVoXDTQzMDEyMjEzMzc0MVowXjELMAkGA1UEBhMCVVMxETAPBgNVBAgM\n"
+  "CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRQwEgYDVQQKDAtUb3IgVGVzdGlu\n"
+  "ZzEUMBIGA1UEAwwLVG9yIFRlc3RpbmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n"
+  "ggIKAoICAQCpLMUEiLW5leUgBZoEJms2V7lZRhIAjnJBhVMHD0e3UubNknmaQoxf\n"
+  "ARz3rvqOaRd0JlV+qM9qE0DjiYcCVP1cAfqAo9d83uS1vwY3YMVJzADlaIiHfyVW\n"
+  "uEgBy0vvkeUBqaua24dYlcwsemOiXYLu41yM1wkcGHW1AhBNHppY6cznb8TyLgNM\n"
+  "2x3SGUdzc5XMyAFx51faKGBA3wjs+Hg1PLY7d30nmCgEOBavpm5I1disM/0k+Mcy\n"
+  "YmAKEo/iHJX/rQzO4b9znP69juLlR8PDBUJEVIG/CYb6+uw8MjjUyiWXYoqfVmN2\n"
+  "hm/lH8b6rXw1a2Aa3VTeD0DxaWeacMYHY/i01fd5n7hCoDTRNdSw5KJ0L3Z0SKTu\n"
+  "0lzffKzDaIfyZGlpW5qdouACkWYzsaitQOePVE01PIdO30vUfzNTFDfy42ccx3Di\n"
+  "59UCu+IXB+eMtrBfsok0Qc63vtF1linJgjHW1z/8ujk8F7/qkOfODhk4l7wngc2A\n"
+  "EmwWFIFoGaiTEZHB9qteXr4unbXZ0AHpM02uGGwZEGohjFyebEb73M+J57WKKAFb\n"
+  "PqbLcGUksL1SHNBNAJcVLttX55sO4nbidOS/kA3m+F1R04MBTyQF9qA6YDDHqdI3\n"
+  "h/3pw0Z4fxVouTYT4/NfRnX4JTP4u+7Mpcoof28VME0qWqD1LnRhFQIDAQABo1Aw\n"
+  "TjAdBgNVHQ4EFgQUMoAgIXH7pZ3QMRwTjT+DM9Yo/v0wHwYDVR0jBBgwFoAUMoAg\n"
+  "IXH7pZ3QMRwTjT+DM9Yo/v0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
+  "AgEAUJxacjXR9sT+Xs6ISFiUsyd0T6WVKMnV46xrYJHirGfx+krWHrjxMY+ZtxYD\n"
+  "DBDGlo11Qc4v6QrclNf5QUBfIiGQsP9Cm6hHcQ+Tpg9HHCgSqG1YNPwCPReCR4br\n"
+  "BLvLfrfkcBL2IWM0PdQdCze+59DBfipsULD2mEn9fjYRXQEwb2QWtQ9qRc20Yb/x\n"
+  "Q4b/+CvUodLkaq7B8MHz0BV8HHcBoph6DYaRmO/N+hPauIuSp6XyaGYcEefGKVKj\n"
+  "G2+fcsdyXsoijNdL8vNKwm4j2gVwCBnw16J00yfFoV46YcbfqEdJB2je0XSvwXqt\n"
+  "14AOTngxso2h9k9HLtrfpO1ZG/B5AcCMs1lzbZ2fp5DPHtjvvmvA2RJqgo3yjw4W\n"
+  "4DHAuTglYFlC3mDHNfNtcGP20JvepcQNzNP2UzwcpOc94hfKikOFw+gf9Vf1qd0y\n"
+  "h/Sk6OZHn2+JVUPiWHIQV98Vtoh4RmUZDJD+b55ia3fQGTGzt4z1XFzQYSva5sfs\n"
+  "wocS/papthqWldQU7x+3wofNd5CNU1x6WKXG/yw30IT/4F8ADJD6GeygNT8QJYvt\n"
+  "u/8lAkbOy6B9xGmSvr0Kk1oq9P2NshA6kalxp1Oz/DTNDdL4AeBXV3JmM6WWCjGn\n"
+  "Yy1RT69d0rwYc5u/vnqODz1IjvT90smsrkBumGt791FAFeg=\n"
+  "-----END CERTIFICATE-----\n";
+
+static X509 *
+read_cert_from(const char *str)
+{
+  BIO *bio = BIO_new(BIO_s_mem());
+  BIO_write(bio, str, strlen(str));
+  X509 *res = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+  BIO_free(bio);
+  return res;
+}
+
+static void
+test_tortls_verify(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  crypto_pk_t *k = NULL;
+  X509 *cert1 = NULL, *cert2 = NULL, *invalidCert = NULL, *validCert = NULL, *caCert = NULL;
+
+  cert1 = tor_malloc_zero(sizeof(X509));
+  cert1->references = 10;
+
+  cert2 = tor_malloc_zero(sizeof(X509));
+  cert2->references = 10;
+
+  validCert = read_cert_from(validCertString);
+  caCert = read_cert_from(caCertString);
+  invalidCert = read_cert_from(notCompletelyValidCertString);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  MOCK(try_to_extract_certs_from_tls, fixed_try_to_extract_certs_from_tls);
+
+  fixed_try_to_extract_certs_from_tls_cert_out_result = cert1;
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  fixed_try_to_extract_certs_from_tls_id_cert_out_result = cert2;
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  fixed_try_to_extract_certs_from_tls_cert_out_result = invalidCert;
+  fixed_try_to_extract_certs_from_tls_id_cert_out_result = invalidCert;
+
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, -1);
+
+  fixed_try_to_extract_certs_from_tls_cert_out_result = validCert;
+  fixed_try_to_extract_certs_from_tls_id_cert_out_result = caCert;
+
+  ret = tor_tls_verify(LOG_WARN, tls, &k);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_assert(k);
+
+ done:
+  UNMOCK(try_to_extract_certs_from_tls);
+  tor_free(cert1);
+  tor_free(cert2);
+  tor_free(tls);
+  tor_free(k);
+}
+
+static void
+test_tortls_check_lifetime(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  X509 *validCert = read_cert_from(validCertString);
+  time_t now = time(NULL);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0);
+  tt_int_op(ret, OP_EQ, -1);
+
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
+  tls->ssl->session->peer = validCert;
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+  validCert->cert_info->validity->notBefore = ASN1_TIME_set(NULL, now-10);
+  validCert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, now+60);
+
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, -1000);
+  tt_int_op(ret, OP_EQ, -1);
+
+  ret = tor_tls_check_lifetime(LOG_WARN, tls, -1000, 0);
+  tt_int_op(ret, OP_EQ, -1);
+
+ done:
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+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);
+}
+
+static void
+test_tortls_get_forced_write_size(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+
+  tls->wantwrite_n = 43;
+  ret = tor_tls_get_forced_write_size(tls);
+  tt_int_op(ret, OP_EQ, 43);
+
+ done:
+  tor_free(tls);
+}
+
+extern uint64_t total_bytes_written_over_tls;
+extern uint64_t total_bytes_written_by_tls;
+
+static void
+test_tortls_get_write_overhead_ratio(void *ignored)
+{
+  (void)ignored;
+  double ret;
+
+  total_bytes_written_over_tls = 0;
+  ret = tls_get_write_overhead_ratio();
+  tt_int_op(ret, OP_EQ, 1.0);
+
+  total_bytes_written_by_tls = 10;
+  total_bytes_written_over_tls = 1;
+  ret = tls_get_write_overhead_ratio();
+  tt_int_op(ret, OP_EQ, 10.0);
+
+  total_bytes_written_by_tls = 10;
+  total_bytes_written_over_tls = 2;
+  ret = tls_get_write_overhead_ratio();
+  tt_int_op(ret, OP_EQ, 5.0);
+
+ done:
+  (void)0;
+}
+
+static void
+test_tortls_used_v1_handshake(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+
+  // These tests assume both V2 handshake server and client are enabled
+  tls->wasV2Handshake = 0;
+  ret = tor_tls_used_v1_handshake(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+  tls->wasV2Handshake = 1;
+  ret = tor_tls_used_v1_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+
+ done:
+  tor_free(tls);
+}
+
+static void
+test_tortls_dn_indicates_v3_cert(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  X509_NAME *name;
+
+  name = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (const unsigned char *)"US", -1, -1, 0);
+  X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (const unsigned char *)"Foobar", -1, -1, 0);
+  ret = dn_indicates_v3_cert(name);
+  tt_int_op(ret, OP_EQ, 1);
+
+  X509_NAME_free(name);
+  name = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (const unsigned char *)"US", -1, -1, 0);
+  ret = dn_indicates_v3_cert(name);
+  tt_int_op(ret, OP_EQ, 1);
+
+  X509_NAME_free(name);
+  name = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(name, "commonName", V_ASN1_REAL, (const unsigned char *)"123", -1, -1, 0);
+  ret = dn_indicates_v3_cert(name);
+  tt_int_op(ret, OP_EQ, 0);
+
+  X509_NAME_free(name);
+  name = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC, (const unsigned char *)"hello.com", -1, -1, 0);
+  ret = dn_indicates_v3_cert(name);
+  tt_int_op(ret, OP_EQ, 1);
+
+  X509_NAME_free(name);
+  name = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC, (const unsigned char *)"hello.net", -1, -1, 0);
+  ret = dn_indicates_v3_cert(name);
+  tt_int_op(ret, OP_EQ, 0);
+
+  X509_NAME_free(name);
+  name = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_ASC, (const unsigned char *)"x.s", -1, -1, 0);
+  ret = dn_indicates_v3_cert(name);
+  tt_int_op(ret, OP_EQ, 1);
+
+ done:
+  X509_NAME_free(name);
+}
+
+static void
+test_tortls_received_v3_certificate(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  X509 *validCert = read_cert_from(validCertString);
+  X509_NAME *subject=NULL, *issuer=NULL;
+
+  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_received_v3_certificate(tls);
+  tt_int_op(ret, OP_EQ, 0);
+
+  tls->ssl->session->peer = validCert;
+
+  subject = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, (const unsigned char *)"same.com", -1, -1, 0);
+  X509_set_subject_name(validCert, subject);
+
+  issuer = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(issuer, "commonName", MBSTRING_ASC, (const unsigned char *)"same.com", -1, -1, 0);
+  X509_set_issuer_name(validCert, issuer);
+
+  ret = tor_tls_received_v3_certificate(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+
+  X509_NAME_free(subject);
+  subject = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, (const unsigned char *)"different.net", -1, -1, 0);
+  X509_set_subject_name(validCert, subject);
+
+  ret = tor_tls_received_v3_certificate(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+
+
+  X509_NAME_free(subject);
+  subject = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, (const unsigned char *)"same.com", -1, -1, 0);
+  X509_set_subject_name(validCert, subject);
+
+  X509_NAME_free(issuer);
+  issuer = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(issuer, "commonName", MBSTRING_ASC, (const unsigned char *)"different.net", -1, -1, 0);
+  X509_set_issuer_name(validCert, issuer);
+
+  ret = tor_tls_received_v3_certificate(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+
+  X509_NAME_free(subject);
+  subject = X509_NAME_new();
+  X509_NAME_add_entry_by_txt(subject, "commonName", MBSTRING_ASC, (const unsigned char *)"different2.net", -1, -1, 0);
+  X509_set_subject_name(validCert, subject);
+  ret = tor_tls_received_v3_certificate(tls);
+  tt_int_op(ret, OP_EQ, 0);
+
+  EVP_PKEY *key = X509_get_pubkey(validCert);
+  key->type = 5;
+  ret = tor_tls_received_v3_certificate(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+  key->type = 6;
+  key->ameth = NULL;
+  ret = tor_tls_received_v3_certificate(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+
+ done:
+  X509_NAME_free(subject);
+  X509_NAME_free(issuer);
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+static void
+test_tortls_get_num_server_handshakes(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+
+  tls->server_handshake_count = 3;
+  ret = tor_tls_get_num_server_handshakes(tls);
+  tt_int_op(ret, OP_EQ, 3);
+
+ done:
+  tor_free(tls);
+}
+
+static void
+test_tortls_server_got_renegotiate(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+
+  tls->got_renegotiate = 1;
+  ret = tor_tls_server_got_renegotiate(tls);
+  tt_int_op(ret, OP_EQ, 1);
+
+ done:
+  tor_free(tls);
+}
+
+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
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+  tor_free(out);
+}
+
+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);
+}
+
+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;
+
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+  ret = tor_tls_get_buffer_sizes(NULL, NULL, NULL, NULL, NULL);
+  tt_int_op(ret, OP_EQ, -1);
+#else
+  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, 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
+
+ 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);
+}
+
+static void
+test_tortls_evaluate_ecgroup_for_tls(void *ignored)
+{
+  (void)ignored;
+  int ret;
+
+  ret = evaluate_ecgroup_for_tls(NULL);
+  tt_int_op(ret, OP_EQ, 1);
+
+  ret = evaluate_ecgroup_for_tls("foobar");
+  tt_int_op(ret, OP_EQ, 0);
+
+  ret = evaluate_ecgroup_for_tls("P256");
+  tt_int_op(ret, OP_EQ, 1);
+
+  ret = evaluate_ecgroup_for_tls("P224");
+  //  tt_int_op(ret, OP_EQ, 1); This varies between machines
+
+ done:
+  (void)0;
+}
+
+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);
+
+  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);
+
+  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);
+
+ done:
+  tor_free(sess);
+  tor_free(tls->ssl->session);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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;
+
+  SSL_library_init();
+  SSL_load_error_strings();
+  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("ECDH-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);
+}
+
+
+/* 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));
+  tls->ssl->s3->flags = 0x0010;
+
+  tor_tls_block_renegotiation(tls);
+
+  tt_assert(!(SSL_get_options(tls->ssl) & 0x0010));
+
+ done:
+  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_assert(SSL_get_options(tls->ssl) & 0x00040000L);
+
+ done:
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+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);
+}
+
+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);
+}
+
+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;
+  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, 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, arg);
+  tt_assert(tls->ssl->info_callback == tor_tls_debug_state_callback);
+
+ done:
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+static const SSL_CIPHER *
+fake_get_cipher(unsigned ncipher)
+{
+  SSL_CIPHER *fixed = tor_malloc_zero(sizeof(SSL_CIPHER));
+  SSL_CIPHER *fixed2 = tor_malloc_zero(sizeof(SSL_CIPHER));
+  fixed2->id = 0xC00A;
+  switch(ncipher) {
+  case 1:
+    return fixed;
+  case 2:
+    return fixed2;
+  default:
+    return NULL;
+  }
+}
+
+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));
+
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  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);
+}
+
+static void
+test_tortls_debug_state_callback(void *ignored)
+{
+  (void)ignored;
+  SSL *ssl;
+  char *buf = tor_malloc_zero(1000);
+  int n;
+
+  int previous_log = setup_capture_of_logs(LOG_DEBUG);
+
+  ssl = tor_malloc_zero(sizeof(SSL));
+
+  tor_tls_debug_state_callback(ssl, 32, 45);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  n = snprintf(buf, 1000, "SSL %p is now in state unknown state [type=32,val=45].\n", ssl);
+  buf[n]='\0';
+  tt_str_op(mock_saved_log_at(0), OP_EQ, buf);
+
+ done:
+  teardown_capture_of_logs(previous_log);
+}
+
+static void
+test_tortls_server_info_callback(void *ignored)
+{
+  (void)ignored;
+  tor_tls_t *tls;
+  SSL_CTX *ctx;
+  SSL *ssl;
+  int previous_log = setup_capture_of_logs(LOG_WARN);
+
+  SSL_library_init();
+  SSL_load_error_strings();
+
+  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;
+
+  tor_tls_server_info_callback(NULL, 0, 0);
+
+  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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 1);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 0);
+
+  SSL_set_ex_data(tls->ssl, tor_tls_object_ex_data_index, tls);
+  SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_B);
+  tls->negotiated_callback = 0;
+  tls->server_handshake_count = 120;
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  tt_int_op(tls->server_handshake_count, OP_EQ, 121);
+
+  tls->server_handshake_count = 127;
+  tls->negotiated_callback = (void *)1;
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  tt_int_op(tls->server_handshake_count, OP_EQ, 127);
+  tt_int_op(tls->got_renegotiate, OP_EQ, 1);
+
+  tls->ssl->session = SSL_SESSION_new();
+  tls->wasV2Handshake = 0;
+  tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 0);
+
+ done:
+  teardown_capture_of_logs(previous_log);
+  tor_free(ssl);
+}
+
+
+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)
+{
+  return fixed_ssl_read_result[fixed_ssl_read_result_index++];
+}
+
+static int
+fixed_ssl_shutdown(SSL *s)
+{
+  return fixed_ssl_shutdown_result;
+}
+
+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;
+}
+
+static int
+dummy_handshake_func(SSL *s)
+{
+  return 1;
+}
+
+static void
+test_tortls_shutdown(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  SSL_METHOD *method = give_me_a_test_method();
+  int previous_log = setup_capture_of_logs(LOG_WARN);
+
+  tls = tor_malloc_zero(sizeof(tor_tls_t));
+  tls->ssl = tor_malloc_zero(sizeof(SSL));
+  tls->ssl->method = method;
+  method->ssl_read = fixed_ssl_read;
+  method->ssl_shutdown = fixed_ssl_shutdown;
+
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+  tls->state = TOR_TLS_ST_SENTCLOSE;
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = -1;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+  tls->ssl->handshake_func = dummy_handshake_func;
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 1;
+  ERR_clear_error();
+  tls->ssl->version = SSL2_VERSION;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_DONE);
+  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 0;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_DONE);
+  tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 0;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  method->ssl_shutdown = setting_version_ssl_shutdown;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_shutdown_result = 0;
+  fixed_tls = tls;
+  fixed_ssl_state_to_set = TOR_TLS_ST_GOTCLOSE;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  method->ssl_shutdown = setting_version_and_state_ssl_shutdown;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+
+  fixed_ssl_read_result_index = 0;
+  fixed_ssl_read_result[0] = 10;
+  fixed_ssl_read_result[1] = 42;
+  fixed_ssl_read_result[2] = 0;
+  fixed_ssl_read_result[3] = -1;
+  fixed_ssl_shutdown_result = 0;
+  fixed_tls = tls;
+  fixed_ssl_state_to_set = 0;
+  ERR_clear_error();
+  tls->ssl->version = 0;
+  method->ssl_shutdown = setting_version_and_state_ssl_shutdown;
+  ret = tor_tls_shutdown(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
+
+ done:
+  teardown_capture_of_logs(previous_log);
+  tor_free(method);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+static int negotiated_callback_called;
+
+static void
+negotiated_callback_setter(tor_tls_t *t, void *arg)
+{
+  (void)t;
+  (void)arg;
+  negotiated_callback_called++;
+}
+
+static void
+test_tortls_read(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  char buf[100];
+  SSL_METHOD *method = give_me_a_test_method();
+  int previous_log = 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);
+
+  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);
+
+  // TODO: fill up
+
+ done:
+  teardown_capture_of_logs(previous_log);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+static int fixed_ssl_write_result;
+
+static int
+fixed_ssl_write(SSL *s, const void *buf, int 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];
+  int previous_log = 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(previous_log);
+  tor_free(tls->ssl);
+  tor_free(tls);
+}
+
+static int fixed_ssl_renegotiate_result;
+
+static int
+fixed_ssl_renegotiate(SSL *s)
+{
+  return fixed_ssl_renegotiate_result;
+}
+
+static void
+test_tortls_renegotiate(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_tls_t *tls;
+  SSL_CTX *ctx;
+  SSL_METHOD *method = give_me_a_test_method();
+  int previous_log = setup_capture_of_logs(LOG_WARN);
+
+  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_OPEN;
+
+  ret = tor_tls_renegotiate(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+  tls->ssl->method = method;
+  method->ssl_renegotiate = fixed_ssl_renegotiate;
+  fixed_ssl_renegotiate_result = 0;
+  ERR_clear_error();
+  ret = tor_tls_renegotiate(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+  ERR_clear_error();
+  tls->ssl->handshake_func = dummy_handshake_func;
+  tls->state = TOR_TLS_ST_RENEGOTIATE;
+  ret = tor_tls_renegotiate(tls);
+  tt_int_op(ret, OP_EQ, TOR_TLS_DONE);
+
+  ERR_clear_error();
+  tls->state = TOR_TLS_ST_OPEN;
+  fixed_ssl_renegotiate_result = -1;
+  ret = tor_tls_renegotiate(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+ done:
+  teardown_capture_of_logs(previous_log);
+  SSL_free(tls->ssl);
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+}
+
+static int fixed_ssl_accept_result;
+static int fixed_ssl_connect_result;
+
+static int
+setting_error_ssl_accept(SSL *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)
+{
+  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)
+{
+  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();
+  int previous_log = 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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 2);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error while handshaking: (null) (in bignum routines:(null):SSLv3 write client hello B)\n");
+  tt_str_op(mock_saved_log_at(1), OP_EQ, "TLS error while handshaking: (null) (in system library:connect:SSLv3 write client hello B)\n");
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_INFO);
+  tt_int_op(mock_saved_severity_at(1), OP_EQ, 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);
+  tt_int_op(mock_saved_log_number(), OP_EQ, 2);
+  tt_str_op(mock_saved_log_at(0), OP_EQ, "TLS error while handshaking: (null) (in bignum routines:(null):SSLv3 write client hello B)\n");
+  tt_str_op(mock_saved_log_at(1), OP_EQ, "TLS error while handshaking: (null) (in system library:connect:SSLv3 write client hello B)\n");
+  tt_int_op(mock_saved_severity_at(0), OP_EQ, LOG_WARN);
+  tt_int_op(mock_saved_severity_at(1), OP_EQ, LOG_WARN);
+
+ done:
+  teardown_capture_of_logs(previous_log);
+  SSL_free(tls->ssl);
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+}
+
+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);
+  X509 *c2 = read_cert_from(caCertString);
+
+  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;
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 1);
+
+  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_CERT_local *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);
+
+  tls->ssl->session->peer = c2;
+  tls->wasV2Handshake = 1;
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 0);
+
+  sk_X509_push(sess->cert_chain, c2);
+  tls->wasV2Handshake = 1;
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(tls->wasV2Handshake, OP_EQ, 0);
+
+  method->num_ciphers = fake_num_ciphers;
+  ret = tor_tls_finish_handshake(tls);
+  tt_int_op(ret, OP_EQ, -9);
+
+ done:
+  SSL_CTX_free(ctx);
+  tor_free(tls);
+}
+
+static int fixed_crypto_pk_new_result_index;
+static crypto_pk_t *fixed_crypto_pk_new_result[5];
+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 crypto_pk_t *
+fixed_crypto_pk_new(void)
+{
+  return fixed_crypto_pk_new_result[fixed_crypto_pk_new_result_index++];
+}
+
+static int
+fixed_crypto_pk_generate_key_with_bits(crypto_pk_t *env, int 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)
+{
+  return fixed_tor_tls_create_certificate_result[fixed_tor_tls_create_certificate_result_index++];
+}
+
+static tor_x509_cert_t *
+fixed_tor_x509_cert_new(X509 *x509_cert)
+{
+  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);
+
+  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] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+  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] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[1] = NULL;
+  fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+  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] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
+  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] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+  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] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+  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] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+  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] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[1] = tor_malloc_zero(sizeof(X509));
+  fixed_tor_tls_create_certificate_result[2] = tor_malloc_zero(sizeof(X509));
+  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);
+}
+
+static int fixed_crypto_pk_get_evp_pkey_result_index = 0;
+static EVP_PKEY *fixed_crypto_pk_get_evp_pkey_result[5];
+static int fixed_crypto_rand_result;
+
+static EVP_PKEY *
+fixed_crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
+{
+  return fixed_crypto_pk_get_evp_pkey_result[fixed_crypto_pk_get_evp_pkey_result_index++];
+}
+
+static int
+fixed_crypto_rand(char *to, size_t n)
+{
+  return fixed_crypto_rand_result;
+}
+
+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_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] = tor_malloc_zero(sizeof(EVP_PKEY));;
+  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] = tor_malloc_zero(sizeof(EVP_PKEY));
+  fixed_crypto_pk_get_evp_pkey_result[1] = tor_malloc_zero(sizeof(EVP_PKEY));
+  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
+  tt_assert(!ret);
+
+  MOCK(crypto_rand, fixed_crypto_rand);
+  fixed_crypto_rand_result = -1;
+  fixed_crypto_pk_get_evp_pkey_result_index = 0;
+  fixed_crypto_pk_get_evp_pkey_result[0] = tor_malloc_zero(sizeof(EVP_PKEY));
+  fixed_crypto_pk_get_evp_pkey_result[1] = tor_malloc_zero(sizeof(EVP_PKEY));
+  ret = tor_tls_create_certificate(pk1, pk2, "hello", "hello2", 1);
+  tt_assert(!ret);
+
+ done:
+  UNMOCK(crypto_rand);
+  UNMOCK(crypto_pk_get_evp_pkey_);
+}
+
+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);
+
+  X509_get_pubkey(cert)->type = EVP_PKEY_DSA;
+  ret = tor_x509_cert_new(cert);
+  tt_assert(ret);
+
+  cert->cert_info = NULL;
+  ret = tor_x509_cert_new(cert);
+  tt_assert(ret);
+
+ done:
+  (void)0;
+}
+
+
+static void
+test_tortls_cert_is_valid(void *ignored)
+{
+  (void)ignored;
+  int ret;
+  tor_x509_cert_t *cert = NULL, *scert;
+
+  scert = tor_malloc_zero(sizeof(tor_x509_cert_t));
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+  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, 0);
+  tt_int_op(ret, OP_EQ, 1);
+
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  cert->cert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, time(NULL)-1000000);
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  cert->cert->cert_info->key = NULL;
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
+  tt_int_op(ret, OP_EQ, 0);
+
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  BN_one(EVP_PKEY_get1_RSA(X509_get_pubkey(cert->cert))->n);
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
+  tt_int_op(ret, OP_EQ, 0);
+
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
+  tt_int_op(ret, OP_EQ, 0);
+
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
+  ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+  tt_int_op(ret, OP_EQ, 1);
+
+  cert = tor_x509_cert_new(read_cert_from(validCertString));
+  scert = tor_x509_cert_new(read_cert_from(caCertString));
+  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, 0);
+  tt_int_op(ret, OP_EQ, 0);
+
+ done:
+  (void)0;
+}
+
+
+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), NULL, NULL }
+
+struct testcase_t tortls_tests[] = {
+  LOCAL_TEST_CASE(errno_to_tls_error, 0),
+  LOCAL_TEST_CASE(err_to_string, 0),
+  LOCAL_TEST_CASE(tor_tls_new, 0),
+  LOCAL_TEST_CASE(tor_tls_get_error, 0),
+  LOCAL_TEST_CASE(get_state_description, TT_FORK),
+  LOCAL_TEST_CASE(get_by_ssl, TT_FORK),
+  LOCAL_TEST_CASE(allocate_tor_tls_object_ex_data_index, TT_FORK),
+  LOCAL_TEST_CASE(log_one_error, TT_FORK),
+  LOCAL_TEST_CASE(get_error, TT_FORK),
+  LOCAL_TEST_CASE(always_accept_verify_cb, 0),
+  LOCAL_TEST_CASE(x509_cert_free, 0),
+  LOCAL_TEST_CASE(x509_cert_get_id_digests, 0),
+  LOCAL_TEST_CASE(cert_matches_key, 0),
+  LOCAL_TEST_CASE(cert_get_key, 0),
+  LOCAL_TEST_CASE(get_my_client_auth_key, TT_FORK),
+  LOCAL_TEST_CASE(get_my_certs, TT_FORK),
+  LOCAL_TEST_CASE(get_ciphersuite_name, 0),
+  LOCAL_TEST_CASE(classify_client_ciphers, 0),
+  LOCAL_TEST_CASE(client_is_using_v2_ciphers, 0),
+  LOCAL_TEST_CASE(verify, 0),
+  LOCAL_TEST_CASE(check_lifetime, 0),
+  LOCAL_TEST_CASE(get_pending_bytes, 0),
+  LOCAL_TEST_CASE(get_forced_write_size, 0),
+  LOCAL_TEST_CASE(get_write_overhead_ratio, TT_FORK),
+  LOCAL_TEST_CASE(used_v1_handshake, TT_FORK),
+  LOCAL_TEST_CASE(dn_indicates_v3_cert, 0),
+  LOCAL_TEST_CASE(received_v3_certificate, 0),
+  LOCAL_TEST_CASE(get_num_server_handshakes, 0),
+  LOCAL_TEST_CASE(server_got_renegotiate, 0),
+  LOCAL_TEST_CASE(SSL_SESSION_get_master_key, 0),
+  LOCAL_TEST_CASE(get_tlssecrets, 0),
+  LOCAL_TEST_CASE(get_buffer_sizes, 0),
+  LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0),
+  LOCAL_TEST_CASE(try_to_extract_certs_from_tls, 0),
+  LOCAL_TEST_CASE(get_peer_cert, 0),
+  LOCAL_TEST_CASE(peer_has_cert, 0),
+  LOCAL_TEST_CASE(shutdown, 0),
+  LOCAL_TEST_CASE(renegotiate, 0),
+  LOCAL_TEST_CASE(finish_handshake, 0),
+   LOCAL_TEST_CASE(handshake, 0),
+  LOCAL_TEST_CASE(write, 0),
+  LOCAL_TEST_CASE(read, 0),
+  LOCAL_TEST_CASE(server_info_callback, 0),
+  LOCAL_TEST_CASE(is_server, 0),
+  LOCAL_TEST_CASE(assert_renegotiation_unblocked, 0),
+  LOCAL_TEST_CASE(block_renegotiation, 0),
+  LOCAL_TEST_CASE(unblock_renegotiation, 0),
+  LOCAL_TEST_CASE(set_renegotiate_callback, 0),
+  LOCAL_TEST_CASE(set_logged_address, 0),
+  LOCAL_TEST_CASE(find_cipher_by_id, 0),
+  LOCAL_TEST_CASE(session_secret_cb, 0),
+  LOCAL_TEST_CASE(debug_state_callback, 0),
+  LOCAL_TEST_CASE(context_new, 0),
+  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
+};



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits