Browse Source

Merge branch 'bug16034_no_more_openssl_098_squashed'

Conflicts:
	src/test/testing_common.c
Nick Mathewson 9 years ago
parent
commit
ed02a409cf

+ 6 - 0
changes/ticket16034

@@ -0,0 +1,6 @@
+  o Removed features:
+
+    - Tor no longer supports versions of OpenSSL before 1.0. (If you
+      are on an operating system that has not upgraded to OpenSSL 1.0
+      or later, and you compile Tor from source, you will need to
+      install a more recent OpenSSL to link Tor against.)

+ 2 - 26
src/common/aes.c

@@ -32,11 +32,7 @@
 #include <openssl/evp.h>
 #include <openssl/engine.h>
 #include "crypto.h"
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
-/* See comments about which counter mode implementation to use below. */
 #include <openssl/modes.h>
-#define CAN_USE_OPENSSL_CTR
-#endif
 #include "compat.h"
 #include "aes.h"
 #include "util.h"
@@ -189,11 +185,9 @@ struct aes_cnt_cipher {
  * we're testing it or because we have hardware acceleration configured */
 static int should_use_EVP = 0;
 
-#ifdef CAN_USE_OPENSSL_CTR
 /** True iff we have tested the counter-mode implementation and found that it
  * doesn't have the counter-mode bug from OpenSSL 1.0.0. */
 static int should_use_openssl_CTR = 0;
-#endif
 
 /** Check whether we should use the EVP interface for AES. If <b>force_val</b>
  * is nonnegative, we use use EVP iff it is true.  Otherwise, we use EVP
@@ -235,7 +229,6 @@ evaluate_evp_for_aes(int force_val)
 int
 evaluate_ctr_for_aes(void)
 {
-#ifdef CAN_USE_OPENSSL_CTR
   /* Result of encrypting an all-zero block with an all-zero 128-bit AES key.
    * This should be the same as encrypting an all-zero block with an all-zero
    * 128-bit AES key in counter mode, starting at position 0 of the stream.
@@ -268,10 +261,6 @@ evaluate_ctr_for_aes(void)
                "mode; using it.");
     should_use_openssl_CTR = 1;
   }
-#else
-  log_info(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
-             "counter mode; not using it.");
-#endif
   return 0;
 }
 
@@ -356,11 +345,9 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
 
   cipher->pos = 0;
 
-#ifdef CAN_USE_OPENSSL_CTR
   if (should_use_openssl_CTR)
     memset(cipher->buf, 0, sizeof(cipher->buf));
   else
-#endif
     aes_fill_buf_(cipher);
 }
 
@@ -386,7 +373,6 @@ aes_cipher_free(aes_cnt_cipher_t *cipher)
 #define UPDATE_CTR_BUF(c, n)
 #endif
 
-#ifdef CAN_USE_OPENSSL_CTR
 /* Helper function to use EVP with openssl's counter-mode wrapper. */
 static void
 evp_block128_fn(const uint8_t in[16],
@@ -397,7 +383,6 @@ evp_block128_fn(const uint8_t in[16],
   int inl=16, outl=16;
   EVP_EncryptUpdate(ctx, out, &outl, in, inl);
 }
-#endif
 
 /** Encrypt <b>len</b> bytes from <b>input</b>, storing the result in
  * <b>output</b>.  Uses the key in <b>cipher</b>, and advances the counter
@@ -407,7 +392,6 @@ void
 aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
           char *output)
 {
-#ifdef CAN_USE_OPENSSL_CTR
   if (should_use_openssl_CTR) {
     if (cipher->using_evp) {
       /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h.  If
@@ -431,9 +415,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
                          &cipher->pos);
     }
     return;
-  } else
-#endif
-  {
+  } else {
     int c = cipher->pos;
     if (PREDICT_UNLIKELY(!len)) return;
 
@@ -466,13 +448,10 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
 void
 aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
 {
-#ifdef CAN_USE_OPENSSL_CTR
   if (should_use_openssl_CTR) {
     aes_crypt(cipher, data, len, data);
     return;
-  } else
-#endif
-  {
+  } else {
     int c = cipher->pos;
     if (PREDICT_UNLIKELY(!len)) return;
 
@@ -512,11 +491,8 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
   cipher->pos = 0;
   memcpy(cipher->ctr_buf.buf, iv, 16);
 
-#ifdef CAN_USE_OPENSSL_CTR
   if (!should_use_openssl_CTR)
-#endif
     aes_fill_buf_(cipher);
 }
 
 #endif
-

+ 16 - 32
src/common/crypto.c

@@ -58,8 +58,8 @@
 #include "compat.h"
 #include "sandbox.h"
 
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
-#error "We require OpenSSL >= 0.9.8"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
+#error "We require OpenSSL >= 1.0.0"
 #endif
 
 #ifdef ANDROID
@@ -300,16 +300,9 @@ crypto_early_init(void)
                SSLeay(), SSLeay_version(SSLEAY_VERSION));
     }
 
-    if (SSLeay() < OPENSSL_V_SERIES(1,0,0)) {
-      log_notice(LD_CRYPTO,
-                 "Your OpenSSL version seems to be %s. We recommend 1.0.0 "
-                 "or later.",
-                 crypto_openssl_get_version_str());
-    }
-
     crypto_force_rand_ssleay();
 
-    if (crypto_seed_rng(1) < 0)
+    if (crypto_seed_rng() < 0)
       return -1;
     if (crypto_init_siphash_key() < 0)
       return -1;
@@ -391,7 +384,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
     }
 
     if (crypto_force_rand_ssleay()) {
-      if (crypto_seed_rng(1) < 0)
+      if (crypto_seed_rng() < 0)
         return -1;
     }
 
@@ -405,7 +398,11 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
 void
 crypto_thread_cleanup(void)
 {
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+  ERR_remove_thread_state(NULL);
+#else
   ERR_remove_state(0);
+#endif
 }
 
 /** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
@@ -2246,15 +2243,6 @@ crypto_dh_free(crypto_dh_t *dh)
  * work for us too. */
 #define ADD_ENTROPY 32
 
-/** True iff it's safe to use RAND_poll after setup.
- *
- * Versions of OpenSSL prior to 0.9.7k and 0.9.8c had a bug where RAND_poll
- * would allocate an fd_set on the stack, open a new file, and try to FD_SET
- * that fd without checking whether it fit in the fd_set.  Thus, if the
- * system has not just been started up, it is unsafe to call */
-#define RAND_POLL_IS_SAFE                       \
-  (OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
-
 /** Set the seed of the weak RNG to a random value. */
 void
 crypto_seed_weak_rng(tor_weak_rng_t *rng)
@@ -2324,7 +2312,7 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
  * have not yet allocated a bunch of fds.  Return 0 on success, -1 on failure.
  */
 int
-crypto_seed_rng(int startup)
+crypto_seed_rng(void)
 {
   int rand_poll_ok = 0, load_entropy_ok = 0;
   uint8_t buf[ADD_ENTROPY];
@@ -2332,11 +2320,9 @@ crypto_seed_rng(int startup)
   /* OpenSSL has a RAND_poll function that knows about more kinds of
    * entropy than we do.  We'll try calling that, *and* calling our own entropy
    * functions.  If one succeeds, we'll accept the RNG as seeded. */
-  if (startup || RAND_POLL_IS_SAFE) {
-    rand_poll_ok = RAND_poll();
-    if (rand_poll_ok == 0)
-      log_warn(LD_CRYPTO, "RAND_poll() failed.");
-  }
+  rand_poll_ok = RAND_poll();
+  if (rand_poll_ok == 0)
+    log_warn(LD_CRYPTO, "RAND_poll() failed.");
 
   load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf));
   if (load_entropy_ok) {
@@ -3058,13 +3044,11 @@ openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
   tor_free(v);
 }
 
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
 static void
 tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
 {
   CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id());
 }
-#endif
 
 /** @{ */
 /** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
@@ -3079,11 +3063,7 @@ setup_openssl_threading(void)
   for (i=0; i < n; ++i)
     openssl_mutexes_[i] = tor_mutex_new();
   CRYPTO_set_locking_callback(openssl_locking_cb_);
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
-  CRYPTO_set_id_callback(tor_get_thread_id);
-#else
   CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
-#endif
   CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_);
   CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_);
   CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
@@ -3096,7 +3076,11 @@ int
 crypto_global_cleanup(void)
 {
   EVP_cleanup();
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+  ERR_remove_thread_state(NULL);
+#else
   ERR_remove_state(0);
+#endif
   ERR_free_strings();
 
   if (dh_param_p)

+ 1 - 1
src/common/crypto.h

@@ -253,7 +253,7 @@ int crypto_expand_key_material_rfc5869_sha256(
                                     uint8_t *key_out, size_t key_out_len);
 
 /* random numbers */
-int crypto_seed_rng(int startup);
+int crypto_seed_rng(void);
 MOCK_DECL(int,crypto_rand,(char *to, size_t n));
 int crypto_strongest_rand(uint8_t *out, size_t out_len);
 int crypto_rand_int(unsigned int max);

+ 150 - 150
src/common/tortls.c

@@ -75,8 +75,8 @@
 #include "container.h"
 #include <string.h>
 
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
-#error "We require OpenSSL >= 0.9.8"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
+#error "We require OpenSSL >= 1.0.0"
 #endif
 
 /* Enable the "v2" TLS handshake.
@@ -93,10 +93,8 @@
 
 #define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer")
 
-#if (OPENSSL_VERSION_NUMBER  <  OPENSSL_V(0,9,8,'s') ||         \
-     (OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,9) &&      \
-      OPENSSL_VERSION_NUMBER <  OPENSSL_V(1,0,0,'f')))
-/* This is a version of OpenSSL before 0.9.8s/1.0.0f. It does not have
+#if OPENSSL_VERSION_NUMBER <  OPENSSL_V(1,0,0,'f')
+/* This is a version of OpenSSL before 1.0.0f. It does not have
  * the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and
  * SSL3 safely at the same time.
  */
@@ -114,13 +112,6 @@
 #define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010
 #endif
 
-/** Does the run-time openssl version look like we need
- * SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION? */
-static int use_unsafe_renegotiation_op = 0;
-/** Does the run-time openssl version look like we need
- * SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION? */
-static int use_unsafe_renegotiation_flag = 0;
-
 /** Structure that we use for a single certificate. */
 struct tor_cert_t {
   X509 *cert;
@@ -485,56 +476,6 @@ tor_tls_init(void)
 
     version = SSLeay();
 
-    /* OpenSSL 0.9.8l introduced SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
-     * here, but without thinking too hard about it: it turns out that the
-     * flag in question needed to be set at the last minute, and that it
-     * conflicted with an existing flag number that had already been added
-     * in the OpenSSL 1.0.0 betas.  OpenSSL 0.9.8m thoughtfully replaced
-     * the flag with an option and (it seems) broke anything that used
-     * SSL3_FLAGS_* for the purpose.  So we need to know how to do both,
-     * and we mustn't use the SSL3_FLAGS option with anything besides
-     * OpenSSL 0.9.8l.
-     *
-     * No, we can't just set flag 0x0010 everywhere.  It breaks Tor with
-     * OpenSSL 1.0.0beta3 and later.  On the other hand, we might be able to
-     * set option 0x00040000L everywhere.
-     *
-     * No, we can't simply detect whether the flag or the option is present
-     * in the headers at build-time: some vendors (notably Apple) like to
-     * leave their headers out of sync with their libraries.
-     *
-     * Yes, it _is_ almost as if the OpenSSL developers decided that no
-     * program should be allowed to use renegotiation unless it first passed
-     * a test of intelligence and determination.
-     */
-    if (version > OPENSSL_V(0,9,8,'k') && version <= OPENSSL_V(0,9,8,'l')) {
-      log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
-                 "some vendors have backported renegotiation code from "
-                 "0.9.8m without updating the version number. "
-                 "I will try SSL3_FLAGS and SSL_OP to enable renegotation.",
-                 SSLeay_version(SSLEAY_VERSION));
-      use_unsafe_renegotiation_flag = 1;
-      use_unsafe_renegotiation_op = 1;
-    } else if (version > OPENSSL_V(0,9,8,'l')) {
-      log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
-                 "I will try SSL_OP to enable renegotiation",
-                 SSLeay_version(SSLEAY_VERSION));
-      use_unsafe_renegotiation_op = 1;
-    } else if (version <= OPENSSL_V(0,9,8,'k')) {
-      log_info(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
-                 "0.9.8l, but some vendors have backported 0.9.8l's "
-                 "renegotiation code to earlier versions, and some have "
-                 "backported the code from 0.9.8m or 0.9.8n.  I'll set both "
-                 "SSL3_FLAGS and SSL_OP just to be safe.",
-                 SSLeay_version(SSLEAY_VERSION), version);
-      use_unsafe_renegotiation_flag = 1;
-      use_unsafe_renegotiation_op = 1;
-    } else {
-      /* this is dead code, yes? */
-      log_info(LD_GENERAL, "OpenSSL %s has version %lx",
-               SSLeay_version(SSLEAY_VERSION), version);
-    }
-
 #if (SIZEOF_VOID_P >= 8 &&                              \
      !defined(OPENSSL_NO_EC) &&                         \
      OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
@@ -1327,24 +1268,6 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
   }
 #endif
 
-  /* XXX This block is now obsolete. */
-  if (
-#ifdef DISABLE_SSL3_HANDSHAKE
-      1 ||
-#endif
-      SSLeay()  <  OPENSSL_V(0,9,8,'s') ||
-      (SSLeay() >= OPENSSL_V_SERIES(0,9,9) &&
-       SSLeay() <  OPENSSL_V(1,0,0,'f'))) {
-    /* And not SSL3 if it's subject to CVE-2011-4576. */
-    log_info(LD_NET, "Disabling SSLv3 because this OpenSSL version "
-             "might otherwise be vulnerable to CVE-2011-4576 "
-             "(compile-time version %08lx (%s); "
-             "runtime version %08lx (%s))",
-             (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT,
-             (unsigned long)SSLeay(), SSLeay_version(SSLEAY_VERSION));
-    SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3);
-  }
-
   SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE);
   SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE);
 
@@ -1355,16 +1278,21 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
   /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
    * as authenticating any earlier-received data.
    */
-  if (use_unsafe_renegotiation_op) {
+  {
     SSL_CTX_set_options(result->ctx,
                         SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
   }
+#ifdef SSL_OP_NO_COMPRESSION
+  SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION);
+#endif
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
 #ifndef OPENSSL_NO_COMP
   /* Don't actually allow compression; it uses ram and time, but the data
    * we transmit is all encrypted anyway. */
   if (result->ctx->comp_methods)
     result->ctx->comp_methods = NULL;
 #endif
+#endif
 #ifdef SSL_MODE_RELEASE_BUFFERS
   SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS);
 #endif
@@ -1399,8 +1327,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
     SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh));
     crypto_dh_free(dh);
   }
-#if (!defined(OPENSSL_NO_EC) &&                         \
-     OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0))
+#if !defined(OPENSSL_NO_EC)
   if (! is_client) {
     int nid;
     EC_KEY *ec_key;
@@ -1512,10 +1439,23 @@ static int v2_cipher_list_pruned = 0;
 /** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>;
  * return 1 if it does support it, or if we have no way to tell. */
 static int
-find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher)
+find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
 {
   const SSL_CIPHER *c;
-#ifdef HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,2)
+  {
+    unsigned char cipherid[3];
+    tor_assert(ssl);
+    set_uint16(cipherid, htons(cipher));
+    cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting
+                      * with a two-byte 'cipherid', it may look for a v2
+                      * cipher with the appropriate 3 bytes. */
+    c = SSL_CIPHER_find((SSL*)ssl, cipherid);
+    if (c)
+      tor_assert((c->id & 0xffff) == cipher);
+    return c != NULL;
+  }
+#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));
@@ -1528,6 +1468,7 @@ find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher)
     return c != NULL;
   } else
 #endif
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
   if (m && m->get_cipher && m->num_ciphers) {
     /* It would seem that some of the "let's-clean-up-openssl" forks have
      * removed the get_cipher_by_char function.  Okay, so now you get a
@@ -1541,23 +1482,24 @@ find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher)
       }
     }
     return 0;
-  } else {
-    return 1; /* No way to search */
   }
+#endif
+  (void) ssl;
+  return 1; /* No way to search */
 }
 
 /** Remove from v2_cipher_list every cipher that we don't support, so that
  * comparing v2_cipher_list to a client's cipher list will give a sensible
  * result. */
 static void
-prune_v2_cipher_list(void)
+prune_v2_cipher_list(const SSL *ssl)
 {
   uint16_t *inp, *outp;
   const SSL_METHOD *m = SSLv23_method();
 
   inp = outp = v2_cipher_list;
   while (*inp) {
-    if (find_cipher_by_id(m, *inp)) {
+    if (find_cipher_by_id(ssl, m, *inp)) {
       *outp++ = *inp++;
     } else {
       inp++;
@@ -1579,7 +1521,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
   int i, res;
   tor_tls_t *tor_tls;
   if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
-    prune_v2_cipher_list();
+    prune_v2_cipher_list(ssl);
 
   tor_tls = tor_tls_get_by_ssl(ssl);
   if (tor_tls && tor_tls->client_cipher_list_type)
@@ -1613,7 +1555,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
     const uint16_t *v2_cipher = v2_cipher_list;
     for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
       SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
-      uint16_t id = cipher->id & 0xffff;
+      uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff;
       if (id == 0x00ff) /* extended renegotiation indicator. */
         continue;
       if (!id || id != *v2_cipher) {
@@ -1657,13 +1599,39 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
 static int
 tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
 {
-  SSL_SESSION *session;
-  if (!(session = SSL_get_session((SSL *)ssl))) {
-    log_info(LD_NET, "No session on TLS?");
-    return CIPHERS_ERR;
+  STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
+
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0)
+  {
+    SSL_SESSION *session;
+    STACK_OF(SSL_CIPHER) *c1;
+    int i;
+    if (!(session = SSL_get_session((SSL *)ssl))) {
+      log_info(LD_NET, "No session on TLS?");
+      return CIPHERS_ERR;
+    }
+    c1 = session->ciphers;
+
+    if (sk_SSL_CIPHER_num(c1) != sk_SSL_CIPHER_num(ciphers)) {
+      log_warn(LD_BUG, "Whoops. session->ciphers doesn't "
+               "match SSL_get_ciphers()");
+      return 0;
+    }
+    for (i = 0; i < sk_SSL_CIPHER_num(c1); ++i) {
+      SSL_CIPHER *a = sk_SSL_CIPHER_value(ciphers, i);
+      SSL_CIPHER *b = sk_SSL_CIPHER_value(c1, i);
+      unsigned long a_id = SSL_CIPHER_get_id(a);
+      unsigned long b_id = SSL_CIPHER_get_id(b);
+      if (a_id != b_id) {
+        log_warn(LD_BUG, "Cipher mismatch between session->ciphers and "
+                 "SSL_get_ciphers() at %d: %lx vs %lx", i,
+                 a_id, b_id);
+      }
+    }
   }
+#endif
 
-  return tor_tls_classify_client_ciphers(ssl, session->ciphers) >= CIPHERS_V2;
+  return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2;
 }
 
 /** Invoked when we're accepting a connection on <b>ssl</b>, and the connection
@@ -1676,14 +1644,17 @@ static void
 tor_tls_server_info_callback(const SSL *ssl, int type, int val)
 {
   tor_tls_t *tls;
+  int ssl_state;
   (void) val;
 
   tor_tls_debug_state_callback(ssl, type, val);
 
   if (type != SSL_CB_ACCEPT_LOOP)
     return;
-  if ((ssl->state != SSL3_ST_SW_SRVR_HELLO_A) &&
-      (ssl->state != SSL3_ST_SW_SRVR_HELLO_B))
+
+  ssl_state = SSL_state(ssl);
+  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);
@@ -1714,10 +1685,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
 
     if (tls) {
       tls->wasV2Handshake = 1;
-#ifdef USE_BUFFEREVENTS
-      if (use_unsafe_renegotiation_flag)
-        tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
-#endif
     } else {
       log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
     }
@@ -1725,7 +1692,6 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
 }
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
 /** Callback to get invoked on a server after we've read the list of ciphers
  * the client supports, but before we pick our own ciphersuite.
  *
@@ -1763,9 +1729,6 @@ tor_tls_setup_session_secret_cb(tor_tls_t *tls)
 {
   SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
 }
-#else
-#define tor_tls_setup_session_secret_cb(tls) STMT_NIL
-#endif
 
 /** Explain which ciphers we're missing. */
 static void
@@ -1791,21 +1754,46 @@ log_unsupported_ciphers(smartlist_t *unsupported)
   tor_free(joined);
 }
 
-/** Replace *<b>ciphers</b> with a new list of SSL ciphersuites: specifically,
- * a list designed to mimic a common web browser.  We might not be able to do
- * that if OpenSSL doesn't support all the ciphers we want.  Some of the
- * ciphers in the list won't actually be implemented by OpenSSL: that's okay
- * so long as the server doesn't select them.
+static void
+set_ssl_ciphers_to_list(SSL *ssl, STACK_OF(SSL_CIPHER) *stack)
+{
+  STACK_OF(SSL_CIPHER) *ciphers;
+
+  int r, i;
+  /* #1: ensure that the ssl object has its own list of ciphers.  Otherwise we
+   *     might be about to stomp the SSL_CTX ciphers list. */
+  r = SSL_set_cipher_list(ssl, "HIGH");
+  tor_assert(r);
+
+  /* #2: Grab ssl_ciphers and clear it.  */
+  ciphers = SSL_get_ciphers(ssl);
+  tor_assert(ciphers);
+  sk_SSL_CIPHER_zero(ciphers);
+
+  /* #3: Copy the elements from stack. */
+  for (i = 0; i < sk_SSL_CIPHER_num(stack); ++i) {
+    SSL_CIPHER *c = sk_SSL_CIPHER_value(stack, i);
+    sk_SSL_CIPHER_push(ciphers, c);
+  }
+}
+
+/** Replace the ciphers on <b>ssl</b> with a new list of SSL ciphersuites:
+ * specifically, a list designed to mimic a common web browser.  We might not
+ * be able to do that if OpenSSL doesn't support all the ciphers we want.
+ * Some of the ciphers in the list won't actually be implemented by OpenSSL:
+ * that's okay so long as the server doesn't select them.
  *
  * [If the server <b>does</b> select a bogus cipher, we won't crash or
  * anything; we'll just fail later when we try to look up the cipher in
  * ssl->cipher_list_by_id.]
  */
 static void
-rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
+rectify_client_ciphers(SSL *ssl)
 {
 #ifdef V2_HANDSHAKE_CLIENT
   if (PREDICT_UNLIKELY(!CLIENT_CIPHER_STACK)) {
+    STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
+
     /* We need to set CLIENT_CIPHER_STACK to an array of the ciphers
      * we want to use/advertise. */
     int i = 0, j = 0;
@@ -1826,32 +1814,33 @@ rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
     tor_assert(CLIENT_CIPHER_STACK);
 
     log_debug(LD_NET, "List was: %s", CLIENT_CIPHER_LIST);
-    for (j = 0; j < sk_SSL_CIPHER_num(*ciphers); ++j) {
-      SSL_CIPHER *cipher = sk_SSL_CIPHER_value(*ciphers, j);
-      log_debug(LD_NET, "Cipher %d: %lx %s", j, cipher->id, cipher->name);
+    for (j = 0; j < sk_SSL_CIPHER_num(ciphers); ++j) {
+      SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, j);
+      log_debug(LD_NET, "Cipher %d: %lx %s", j,
+                SSL_CIPHER_get_id(cipher), SSL_CIPHER_get_name(cipher));
     }
 
     /* Then copy as many ciphers as we can from the good list, inserting
      * dummies as needed. Let j be an index into list of ciphers we have
-     * (*ciphers) and let i be an index into the ciphers we want
+     * (ciphers) and let i be an index into the ciphers we want
      * (CLIENT_INFO_CIPHER_LIST).  We are building a list of ciphers in
      * CLIENT_CIPHER_STACK.
      */
     for (i = j = 0; i < N_CLIENT_CIPHERS; ) {
       SSL_CIPHER *cipher = NULL;
-      if (j < sk_SSL_CIPHER_num(*ciphers))
-        cipher = sk_SSL_CIPHER_value(*ciphers, j);
-      if (cipher && ((cipher->id >> 24) & 0xff) != 3) {
+      if (j < sk_SSL_CIPHER_num(ciphers))
+        cipher = sk_SSL_CIPHER_value(ciphers, j);
+      if (cipher && ((SSL_CIPHER_get_id(cipher) >> 24) & 0xff) != 3) {
         /* Skip over non-v3 ciphers entirely.  (This should no longer be
          * needed, thanks to saying !SSLv2 above.) */
         log_debug(LD_NET, "Skipping v%d cipher %s",
-                  (int)((cipher->id>>24) & 0xff),
-                  cipher->name);
+                  (int)((SSL_CIPHER_get_id(cipher)>>24) & 0xff),
+                  SSL_CIPHER_get_name(cipher));
         ++j;
       } else if (cipher &&
-                 (cipher->id & 0xffff) == CLIENT_CIPHER_INFO_LIST[i].id) {
+                 (SSL_CIPHER_get_id(cipher) & 0xffff) == CLIENT_CIPHER_INFO_LIST[i].id) {
         /* "cipher" is the cipher we expect. Put it on the list. */
-        log_debug(LD_NET, "Found cipher %s", cipher->name);
+        log_debug(LD_NET, "Found cipher %s", SSL_CIPHER_get_name(cipher));
         sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, cipher);
         ++j;
         ++i;
@@ -1877,12 +1866,10 @@ rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers)
     smartlist_free(unsupported);
   }
 
-  sk_SSL_CIPHER_free(*ciphers);
-  *ciphers = sk_SSL_CIPHER_dup(CLIENT_CIPHER_STACK);
-  tor_assert(*ciphers);
+  set_ssl_ciphers_to_list(ssl, CLIENT_CIPHER_STACK);
 
 #else
-    (void)ciphers;
+  (void)ciphers;
 #endif
 }
 
@@ -1926,7 +1913,7 @@ tor_tls_new(int sock, int isServer)
     goto err;
   }
   if (!isServer)
-    rectify_client_ciphers(&result->ssl->cipher_list);
+    rectify_client_ciphers(result->ssl);
   result->socket = sock;
   bio = BIO_new_socket(sock, BIO_NOCLOSE);
   if (! bio) {
@@ -2019,13 +2006,8 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls)
 {
   /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
    * as authenticating any earlier-received data. */
-  if (use_unsafe_renegotiation_flag) {
-    tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
-  }
-  if (use_unsafe_renegotiation_op) {
-    SSL_set_options(tls->ssl,
-                    SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
-  }
+  SSL_set_options(tls->ssl,
+                  SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
 }
 
 /** If this version of openssl supports it, turn off renegotiation on
@@ -2035,21 +2017,19 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls)
 void
 tor_tls_block_renegotiation(tor_tls_t *tls)
 {
+#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG
   tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+#else
+  (void) tls;
+#endif
 }
 
 /** Assert that the flags that allow legacy renegotiation are still set */
 void
 tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
 {
-  if (use_unsafe_renegotiation_flag) {
-    tor_assert(0 != (tls->ssl->s3->flags &
-                     SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
-  }
-  if (use_unsafe_renegotiation_op) {
-    long options = SSL_get_options(tls->ssl);
-    tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
-  }
+  long options = SSL_get_options(tls->ssl);
+  tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));
 }
 
 /** Return whether this tls initiated the connect (client) or
@@ -2180,7 +2160,7 @@ tor_tls_handshake(tor_tls_t *tls)
   tor_assert(tls->ssl);
   tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
   check_no_tls_errors();
-  oldstate = tls->ssl->state;
+  oldstate = SSL_state(tls->ssl);
   if (tls->isServer) {
     log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
               SSL_state_string_long(tls->ssl));
@@ -2190,7 +2170,7 @@ tor_tls_handshake(tor_tls_t *tls)
               SSL_state_string_long(tls->ssl));
     r = SSL_connect(tls->ssl);
   }
-  if (oldstate != tls->ssl->state)
+  if (oldstate != SSL_state(tls->ssl))
     log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
               tls, SSL_state_string_long(tls->ssl));
   /* We need to call this here and not earlier, since OpenSSL has a penchant
@@ -2209,6 +2189,14 @@ tor_tls_handshake(tor_tls_t *tls)
   return r;
 }
 
+/* SSL_clear_mode was introduced in 0.9.8m */
+#ifndef SSL_clear_mode
+static void SSL_clear_mode(SSL *s, unsigned long m)
+{
+  s->mode &= ~m;
+}
+#endif
+
 /** Perform the final part of the intial TLS handshake on <b>tls</b>.  This
  * should be called for the first handshake only: it determines whether the v1
  * or the v2 handshake was used, and adjusts things for the renegotiation
@@ -2225,8 +2213,7 @@ tor_tls_finish_handshake(tor_tls_t *tls)
   if (tls->isServer) {
     SSL_set_info_callback(tls->ssl, NULL);
     SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb);
-    /* There doesn't seem to be a clear OpenSSL API to clear mode flags. */
-    tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN;
+    SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN);
 #ifdef V2_HANDSHAKE_SERVER
     if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) {
       /* This check is redundant, but back when we did it in the callback,
@@ -2851,12 +2838,23 @@ tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
  * Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read
  * buffer and *<b>rbuf_bytes</b> to the amount actually used.
  * Set *<b>wbuf_capacity</b> to the amount of storage allocated for the write
- * buffer and *<b>wbuf_bytes</b> to the amount actually used. */
-void
+ * buffer and *<b>wbuf_bytes</b> to the amount actually used.
+ *
+ * Return 0 on success, -1 on failure.*/
+int
 tor_tls_get_buffer_sizes(tor_tls_t *tls,
                          size_t *rbuf_capacity, size_t *rbuf_bytes,
                          size_t *wbuf_capacity, size_t *wbuf_bytes)
 {
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+  (void)tls;
+  (void)rbuf_capacity;
+  (void)rbuf_bytes;
+  (void)wbuf_capacity;
+  (void)wbuf_bytes;
+
+  return -1;
+#else
   if (tls->ssl->s3->rbuf.buf)
     *rbuf_capacity = tls->ssl->s3->rbuf.len;
   else
@@ -2867,6 +2865,8 @@ tor_tls_get_buffer_sizes(tor_tls_t *tls,
     *wbuf_capacity = 0;
   *rbuf_bytes = tls->ssl->s3->rbuf.left;
   *wbuf_bytes = tls->ssl->s3->wbuf.left;
+  return 0;
+#endif
 }
 
 #ifdef USE_BUFFEREVENTS

+ 1 - 1
src/common/tortls.h

@@ -92,7 +92,7 @@ size_t tor_tls_get_forced_write_size(tor_tls_t *tls);
 void tor_tls_get_n_raw_bytes(tor_tls_t *tls,
                              size_t *n_read, size_t *n_written);
 
-void tor_tls_get_buffer_sizes(tor_tls_t *tls,
+int tor_tls_get_buffer_sizes(tor_tls_t *tls,
                               size_t *rbuf_capacity, size_t *rbuf_bytes,
                               size_t *wbuf_capacity, size_t *wbuf_bytes);
 

+ 8 - 7
src/or/main.c

@@ -1336,7 +1336,7 @@ run_scheduled_events(time_t now)
   if (time_to.add_entropy < now) {
     if (time_to.add_entropy) {
       /* We already seeded once, so don't die on failure. */
-      crypto_seed_rng(0);
+      crypto_seed_rng();
     }
 /** How often do we add more entropy to OpenSSL's RNG pool? */
 #define ENTROPY_INTERVAL (60*60)
@@ -2333,12 +2333,13 @@ dumpstats(int severity)
       if (conn->type == CONN_TYPE_OR) {
         or_connection_t *or_conn = TO_OR_CONN(conn);
         if (or_conn->tls) {
-          tor_tls_get_buffer_sizes(or_conn->tls, &rbuf_cap, &rbuf_len,
-                                   &wbuf_cap, &wbuf_len);
-          tor_log(severity, LD_GENERAL,
-              "Conn %d: %d/%d bytes used on OpenSSL read buffer; "
-              "%d/%d bytes used on write buffer.",
-              i, (int)rbuf_len, (int)rbuf_cap, (int)wbuf_len, (int)wbuf_cap);
+          if (tor_tls_get_buffer_sizes(or_conn->tls, &rbuf_cap, &rbuf_len,
+                                       &wbuf_cap, &wbuf_len) == 0) {
+            tor_log(severity, LD_GENERAL,
+                "Conn %d: %d/%d bytes used on OpenSSL read buffer; "
+                "%d/%d bytes used on write buffer.",
+                i, (int)rbuf_len, (int)rbuf_cap, (int)wbuf_len, (int)wbuf_cap);
+          }
         }
       }
     }

+ 2 - 3
src/test/bench.c

@@ -502,8 +502,7 @@ bench_dh(void)
          "      %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
 }
 
-#if (!defined(OPENSSL_NO_EC)                    \
-     && OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0))
+#if !defined(OPENSSL_NO_EC)
 #define HAVE_EC_BENCHMARKS
 static void
 bench_ecdh_impl(int nid, const char *name)
@@ -625,7 +624,7 @@ main(int argc, const char **argv)
 
   reset_perftime();
 
-  crypto_seed_rng(1);
+  crypto_seed_rng();
   crypto_init_siphash_key();
   options = options_new();
   init_logging(1);

+ 1 - 1
src/test/test_crypto.c

@@ -74,7 +74,7 @@ test_crypto_rng(void *arg)
 
   /* Try out RNG. */
   (void)arg;
-  tt_assert(! crypto_seed_rng(0));
+  tt_assert(! crypto_seed_rng());
   crypto_rand(data1, 100);
   crypto_rand(data2, 100);
   tt_mem_op(data1,OP_NE, data2,100);

+ 1 - 1
src/test/test_workqueue.c

@@ -358,7 +358,7 @@ main(int argc, char **argv)
 
   init_logging(1);
   crypto_global_init(1, NULL, NULL);
-  crypto_seed_rng(1);
+  crypto_seed_rng();
 
   rq = replyqueue_new(as_flags);
   tor_assert(rq);

+ 1 - 1
src/test/testing_common.c

@@ -270,7 +270,7 @@ main(int c, const char **v)
     return 1;
   }
   crypto_set_tls_dh_prime();
-  crypto_seed_rng(1);
+  crypto_seed_rng();
   rep_hist_init();
   network_init();
   setup_directory();

+ 1 - 1
src/tools/tor-gencert.c

@@ -533,7 +533,7 @@ main(int argc, char **argv)
     fprintf(stderr, "Couldn't initialize crypto library.\n");
     return 1;
   }
-  if (crypto_seed_rng(1)) {
+  if (crypto_seed_rng()) {
     fprintf(stderr, "Couldn't seed RNG.\n");
     goto done;
   }