Commit 1744e447 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Decide whether to use SSL flags based on runtime OpenSSL version.

We need to do this because Apple doesn't update its dev-tools headers
when it updates its libraries in a security patch.  On the bright
side, this might get us out of shipping a statically linked OpenSSL on
OSX.

May fix bug 1225.

[backported]
parent b6038f4a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -8,6 +8,12 @@ Changes in version 0.2.1.23 - 2010-0?-??
      automatically discard guards picked using the old algorithm. Fixes
      bug 1217; bugfix on 0.2.1.3-alpha. Found by Mike Perry.

  o Minor bugfixes:
    - When deciding whether to use strange flags to turn TLS renegotiation
      on, detect the OpenSSL version at run-time, not compile time.  We
      need to do this because Apple doesn't update its dev-tools headers
      when it updates its libraries in a security patch.

  o Minor features:
    - Avoid a mad rush at the beginning of each month when each client
      rotates half of its guards. Instead we spread the rotation out
+46 −15
Original line number Diff line number Diff line
@@ -53,6 +53,24 @@

#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer")

/* We redefine these so that we can run correctly even if the vendor gives us
 * a version of OpenSSL that does not match its header files.  (Apple: I am
 * looking at you.)
 */
#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L
#endif
#ifndef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010
#endif

/** 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 holding the TLS state for a single connection. */
typedef struct tor_tls_context_t {
  int refcnt;
@@ -309,9 +327,29 @@ static void
tor_tls_init(void)
{
  if (!tls_library_is_initialized) {
    long version;
    SSL_library_init();
    SSL_load_error_strings();
    crypto_global_init(-1);

    version = SSLeay();
    if (version >= 0x009070c0L && version < 0x00908000L) {
      log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.7l or later; "
                 "I will try SSL3_FLAGS and SSL3_OP to enable renegotation",
                 SSLeay_version(SSLEAY_VERSION));
      use_unsafe_renegotiation_flag = 1;
      use_unsafe_renegotiation_op = 1;
    } else if (version >= 0x009080c0L) {
      log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l or later; "
                 "I will try SSL3_FLAGS and SSL_OP to enable renegotiation",
                 SSLeay_version(SSLEAY_VERSION));
      use_unsafe_renegotiation_flag = 1;
      use_unsafe_renegotiation_op = 1;
    } else {
      log_info(LD_GENERAL, "OpenSSL %s has version %lx",
               SSLeay_version(SSLEAY_VERSION), version);
    }

    tls_library_is_initialized = 1;
  }
}
@@ -568,7 +606,6 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime)
  SSL_CTX_set_options(result->ctx,
                      SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#endif
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
  /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
   * as authenticating any earlier-received data.
   *
@@ -577,9 +614,10 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime)
   * seems) broke anything that used SSL3_FLAGS_* for the purpose.  So we need
   * to do both.)
   */
  if (use_unsafe_renegotiation_op) {
    SSL_CTX_set_options(result->ctx,
                        SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
#endif
  }
  /* Don't actually allow compression; it uses ram and time, but the data
   * we transmit is all encrypted anyway. */
  if (result->ctx->comp_methods)
@@ -920,19 +958,16 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls,
}

/** If this version of openssl requires it, turn on renegotiation on
 * <b>tls</b>.  (Our protocol never requires this for security, but it's nice
 * to use belt-and-suspenders here.)
 * <b>tls</b>.
 */
static void
tor_tls_unblock_renegotiation(tor_tls_t *tls)
{
#ifdef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
  /* 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;
#else
  (void)tls;
#endif
  }
}

/** If this version of openssl supports it, turn off renegotiation on
@@ -942,11 +977,7 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls)
void
tor_tls_block_renegotiation(tor_tls_t *tls)
{
#ifdef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
  tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
#else
  (void)tls;
#endif
}

/** Return whether this tls initiated the connect (client) or