|  | @@ -205,16 +205,6 @@ struct tor_tls_t {
 | 
	
		
			
				|  |  |    void *callback_arg;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#ifdef V2_HANDSHAKE_CLIENT
 | 
	
		
			
				|  |  | -/** An array of fake SSL_CIPHER objects that we use in order to trick OpenSSL
 | 
	
		
			
				|  |  | - * in client mode into advertising the ciphers we want.  See
 | 
	
		
			
				|  |  | - * rectify_client_ciphers() for details. */
 | 
	
		
			
				|  |  | -static SSL_CIPHER *CLIENT_CIPHER_DUMMIES = NULL;
 | 
	
		
			
				|  |  | -/** A stack of SSL_CIPHER objects, some real, some fake.
 | 
	
		
			
				|  |  | - * See rectify_client_ciphers() for details. */
 | 
	
		
			
				|  |  | -static STACK_OF(SSL_CIPHER) *CLIENT_CIPHER_STACK = NULL;
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /** 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;
 | 
	
	
		
			
				|  | @@ -531,12 +521,6 @@ tor_tls_free_all(void)
 | 
	
		
			
				|  |  |      client_tls_context = NULL;
 | 
	
		
			
				|  |  |      tor_tls_context_decref(ctx);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -#ifdef V2_HANDSHAKE_CLIENT
 | 
	
		
			
				|  |  | -  if (CLIENT_CIPHER_DUMMIES)
 | 
	
		
			
				|  |  | -    tor_free(CLIENT_CIPHER_DUMMIES);
 | 
	
		
			
				|  |  | -  if (CLIENT_CIPHER_STACK)
 | 
	
		
			
				|  |  | -    sk_SSL_CIPHER_free(CLIENT_CIPHER_STACK);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** We need to give OpenSSL a callback to verify certificates. This is
 | 
	
	
		
			
				|  | @@ -727,7 +711,6 @@ const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
 | 
	
		
			
				|  |  |   * (SSL3_TXT_RSA_NULL_SHA).  If you do this, you won't be able to communicate
 | 
	
		
			
				|  |  |   * with any of the "real" Tors, though. */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#ifdef V2_HANDSHAKE_CLIENT
 | 
	
		
			
				|  |  |  #define CIPHER(id, name) name ":"
 | 
	
		
			
				|  |  |  #define XCIPHER(id, name)
 | 
	
		
			
				|  |  |  /** List of ciphers that clients should advertise, omitting items that
 | 
	
	
		
			
				|  | @@ -741,28 +724,6 @@ static const char CLIENT_CIPHER_LIST[] =
 | 
	
		
			
				|  |  |  #undef CIPHER
 | 
	
		
			
				|  |  |  #undef XCIPHER
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/** Holds a cipher that we want to advertise, and its 2-byte ID. */
 | 
	
		
			
				|  |  | -typedef struct cipher_info_t { unsigned id; const char *name; } cipher_info_t;
 | 
	
		
			
				|  |  | -/** A list of all the ciphers that clients should advertise, including items
 | 
	
		
			
				|  |  | - * that OpenSSL might not know about. */
 | 
	
		
			
				|  |  | -static const cipher_info_t CLIENT_CIPHER_INFO_LIST[] = {
 | 
	
		
			
				|  |  | -#define CIPHER(id, name) { id, name },
 | 
	
		
			
				|  |  | -#define XCIPHER(id, name) { id, #name },
 | 
	
		
			
				|  |  | -#include "ciphers.inc"
 | 
	
		
			
				|  |  | -#undef CIPHER
 | 
	
		
			
				|  |  | -#undef XCIPHER
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** The length of CLIENT_CIPHER_INFO_LIST and CLIENT_CIPHER_DUMMIES. */
 | 
	
		
			
				|  |  | -static const int N_CLIENT_CIPHERS = ARRAY_LENGTH(CLIENT_CIPHER_INFO_LIST);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifndef V2_HANDSHAKE_CLIENT
 | 
	
		
			
				|  |  | -#undef CLIENT_CIPHER_LIST
 | 
	
		
			
				|  |  | -#define CLIENT_CIPHER_LIST  (TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"      \
 | 
	
		
			
				|  |  | -                             SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /** Free all storage held in <b>cert</b> */
 | 
	
		
			
				|  |  |  void
 | 
	
		
			
				|  |  |  tor_x509_cert_free(tor_x509_cert_t *cert)
 | 
	
	
		
			
				|  | @@ -1440,7 +1401,7 @@ static int
 | 
	
		
			
				|  |  |  find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    const SSL_CIPHER *c;
 | 
	
		
			
				|  |  | -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,2)
 | 
	
		
			
				|  |  | +#ifdef HAVE_SSL_CIPHER_FIND
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      unsigned char cipherid[3];
 | 
	
		
			
				|  |  |      tor_assert(ssl);
 | 
	
	
		
			
				|  | @@ -1597,13 +1558,19 @@ tor_tls_classify_client_ciphers(const SSL *ssl,
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  |  tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +  STACK_OF(SSL_CIPHER) *ciphers;
 | 
	
		
			
				|  |  | +#ifdef HAVE_SSL_GET_CLIENT_CIPHERS
 | 
	
		
			
				|  |  | +  ciphers = SSL_get_ciphers(ssl);
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  |    SSL_SESSION *session;
 | 
	
		
			
				|  |  |    if (!(session = SSL_get_session((SSL *)ssl))) {
 | 
	
		
			
				|  |  |      log_info(LD_NET, "No session on TLS?");
 | 
	
		
			
				|  |  |      return CIPHERS_ERR;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  ciphers = session->ciphers;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  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
 | 
	
	
		
			
				|  | @@ -1702,150 +1669,6 @@ tor_tls_setup_session_secret_cb(tor_tls_t *tls)
 | 
	
		
			
				|  |  |    SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/** Explain which ciphers we're missing. */
 | 
	
		
			
				|  |  | -static void
 | 
	
		
			
				|  |  | -log_unsupported_ciphers(smartlist_t *unsupported)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  char *joined;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  log_notice(LD_NET, "We weren't able to find support for all of the "
 | 
	
		
			
				|  |  | -             "TLS ciphersuites that we wanted to advertise. This won't "
 | 
	
		
			
				|  |  | -             "hurt security, but it might make your Tor (if run as a client) "
 | 
	
		
			
				|  |  | -             "more easy for censors to block.");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (SSLeay() < 0x10000000L) {
 | 
	
		
			
				|  |  | -    log_notice(LD_NET, "To correct this, use a more recent OpenSSL, "
 | 
	
		
			
				|  |  | -               "built without disabling any secure ciphers or features.");
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    log_notice(LD_NET, "To correct this, use a version of OpenSSL "
 | 
	
		
			
				|  |  | -               "built with none of its ciphers disabled.");
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  joined = smartlist_join_strings(unsupported, ":", 0, NULL);
 | 
	
		
			
				|  |  | -  log_info(LD_NET, "The unsupported ciphers were: %s", joined);
 | 
	
		
			
				|  |  | -  tor_free(joined);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -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(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;
 | 
	
		
			
				|  |  | -    smartlist_t *unsupported = smartlist_new();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* First, create a dummy SSL_CIPHER for every cipher. */
 | 
	
		
			
				|  |  | -    CLIENT_CIPHER_DUMMIES =
 | 
	
		
			
				|  |  | -      tor_malloc_zero(sizeof(SSL_CIPHER)*N_CLIENT_CIPHERS);
 | 
	
		
			
				|  |  | -    for (i=0; i < N_CLIENT_CIPHERS; ++i) {
 | 
	
		
			
				|  |  | -      CLIENT_CIPHER_DUMMIES[i].valid = 1;
 | 
	
		
			
				|  |  | -      /* The "3<<24" here signifies that the cipher is supposed to work with
 | 
	
		
			
				|  |  | -       * SSL3 and TLS1. */
 | 
	
		
			
				|  |  | -      CLIENT_CIPHER_DUMMIES[i].id = CLIENT_CIPHER_INFO_LIST[i].id | (3<<24);
 | 
	
		
			
				|  |  | -      CLIENT_CIPHER_DUMMIES[i].name = CLIENT_CIPHER_INFO_LIST[i].name;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    CLIENT_CIPHER_STACK = sk_SSL_CIPHER_new_null();
 | 
	
		
			
				|  |  | -    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,
 | 
	
		
			
				|  |  | -                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
 | 
	
		
			
				|  |  | -     * (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 && ((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)((SSL_CIPHER_get_id(cipher)>>24) & 0xff),
 | 
	
		
			
				|  |  | -                  SSL_CIPHER_get_name(cipher));
 | 
	
		
			
				|  |  | -        ++j;
 | 
	
		
			
				|  |  | -      } else if (cipher &&
 | 
	
		
			
				|  |  | -                 (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", SSL_CIPHER_get_name(cipher));
 | 
	
		
			
				|  |  | -        sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, cipher);
 | 
	
		
			
				|  |  | -        ++j;
 | 
	
		
			
				|  |  | -        ++i;
 | 
	
		
			
				|  |  | -      } else if (!strcmp(CLIENT_CIPHER_DUMMIES[i].name,
 | 
	
		
			
				|  |  | -                         "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA")) {
 | 
	
		
			
				|  |  | -        /* We found bogus cipher 0xfeff, which OpenSSL doesn't support and
 | 
	
		
			
				|  |  | -         * never has.  For this one, we need a dummy. */
 | 
	
		
			
				|  |  | -        log_debug(LD_NET, "Inserting fake %s", CLIENT_CIPHER_DUMMIES[i].name);
 | 
	
		
			
				|  |  | -        sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, &CLIENT_CIPHER_DUMMIES[i]);
 | 
	
		
			
				|  |  | -        ++i;
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        /* OpenSSL doesn't have this one. */
 | 
	
		
			
				|  |  | -        log_debug(LD_NET, "Completely omitting unsupported cipher %s",
 | 
	
		
			
				|  |  | -                  CLIENT_CIPHER_INFO_LIST[i].name);
 | 
	
		
			
				|  |  | -        smartlist_add(unsupported, (char*) CLIENT_CIPHER_INFO_LIST[i].name);
 | 
	
		
			
				|  |  | -        ++i;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (smartlist_len(unsupported))
 | 
	
		
			
				|  |  | -      log_unsupported_ciphers(unsupported);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    smartlist_free(unsupported);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  set_ssl_ciphers_to_list(ssl, CLIENT_CIPHER_STACK);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -  (void)ciphers;
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /** Create a new TLS object from a file descriptor, and a flag to
 | 
	
		
			
				|  |  |   * determine whether it is functioning as a server.
 | 
	
		
			
				|  |  |   */
 | 
	
	
		
			
				|  | @@ -1885,8 +1708,6 @@ tor_tls_new(int sock, int isServer)
 | 
	
		
			
				|  |  |      tor_free(result);
 | 
	
		
			
				|  |  |      goto err;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  if (!isServer)
 | 
	
		
			
				|  |  | -    rectify_client_ciphers(result->ssl);
 | 
	
		
			
				|  |  |    result->socket = sock;
 | 
	
		
			
				|  |  |    bio = BIO_new_socket(sock, BIO_NOCLOSE);
 | 
	
		
			
				|  |  |    if (! bio) {
 | 
	
	
		
			
				|  | @@ -2769,6 +2590,46 @@ tor_tls_server_got_renegotiate(tor_tls_t *tls)
 | 
	
		
			
				|  |  |    return tls->got_renegotiate;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifndef HAVE_SSL_GET_CLIENT_RANDOM
 | 
	
		
			
				|  |  | +static size_t
 | 
	
		
			
				|  |  | +SSL_get_client_random(SSL *s, uint8_t *out, size_t len)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if (len == 0)
 | 
	
		
			
				|  |  | +    return SSL3_RANDOM_SIZE;
 | 
	
		
			
				|  |  | +  tor_assert(len == SSL3_RANDOM_SIZE);
 | 
	
		
			
				|  |  | +  tor_assert(s->s3);
 | 
	
		
			
				|  |  | +  memcpy(out, s->s3->client_random, len);
 | 
	
		
			
				|  |  | +  return len;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifndef HAVE_SSL_GET_SERVER_RANDOM
 | 
	
		
			
				|  |  | +static size_t
 | 
	
		
			
				|  |  | +SSL_get_server_random(SSL *s, uint8_t *out, size_t len)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if (len == 0)
 | 
	
		
			
				|  |  | +    return SSL3_RANDOM_SIZE;
 | 
	
		
			
				|  |  | +  tor_assert(len == SSL3_RANDOM_SIZE);
 | 
	
		
			
				|  |  | +  tor_assert(s->s3);
 | 
	
		
			
				|  |  | +  memcpy(out, s->s3->server_random, len);
 | 
	
		
			
				|  |  | +  return len;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
 | 
	
		
			
				|  |  | +static size_t
 | 
	
		
			
				|  |  | +SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if (len == 0)
 | 
	
		
			
				|  |  | +    return s->master_key_length;
 | 
	
		
			
				|  |  | +  tor_assert(len == (size_t)s->master_key_length);
 | 
	
		
			
				|  |  | +  tor_assert(s->master_key);
 | 
	
		
			
				|  |  | +  memcpy(out, s->master_key, len);
 | 
	
		
			
				|  |  | +  return len;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Set the DIGEST256_LEN buffer at <b>secrets_out</b> to the value used in
 | 
	
		
			
				|  |  |   * the v3 handshake to prove that the client knows the TLS secrets for the
 | 
	
		
			
				|  |  |   * connection <b>tls</b>.  Return 0 on success, -1 on failure.
 | 
	
	
		
			
				|  | @@ -2777,25 +2638,57 @@ MOCK_IMPL(int,
 | 
	
		
			
				|  |  |  tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  #define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification"
 | 
	
		
			
				|  |  | -  char buf[128];
 | 
	
		
			
				|  |  | +  uint8_t buf[128];
 | 
	
		
			
				|  |  |    size_t len;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    tor_assert(tls);
 | 
	
		
			
				|  |  | -  tor_assert(tls->ssl);
 | 
	
		
			
				|  |  | -  tor_assert(tls->ssl->s3);
 | 
	
		
			
				|  |  | -  tor_assert(tls->ssl->session);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  SSL *const ssl = tls->ssl;
 | 
	
		
			
				|  |  | +  SSL_SESSION *const session = SSL_get_session(ssl);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  tor_assert(ssl);
 | 
	
		
			
				|  |  | +  tor_assert(session);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const size_t server_random_len = SSL_get_server_random(ssl, NULL, 0);
 | 
	
		
			
				|  |  | +  const size_t client_random_len = SSL_get_client_random(ssl, NULL, 0);
 | 
	
		
			
				|  |  | +  const size_t master_key_len = SSL_SESSION_get_master_key(session, NULL, 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  tor_assert(server_random_len);
 | 
	
		
			
				|  |  | +  tor_assert(client_random_len);
 | 
	
		
			
				|  |  | +  tor_assert(master_key_len);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  len = client_random_len + server_random_len + strlen(TLSSECRET_MAGIC) + 1;
 | 
	
		
			
				|  |  | +  tor_assert(len <= sizeof(buf));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    size_t r = SSL_get_client_random(ssl, buf, client_random_len);
 | 
	
		
			
				|  |  | +    tor_assert(r == client_random_len);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    size_t r = SSL_get_server_random(ssl, buf+client_random_len, server_random_len);
 | 
	
		
			
				|  |  | +    tor_assert(r == server_random_len);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  uint8_t *master_key = tor_malloc_zero(master_key_len);
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len);
 | 
	
		
			
				|  |  | +    tor_assert(r == master_key_len);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  uint8_t *nextbuf = buf + client_random_len + server_random_len;
 | 
	
		
			
				|  |  | +  memcpy(nextbuf, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /*
 | 
	
		
			
				|  |  |      The value is an HMAC, using the TLS master key as the HMAC key, of
 | 
	
		
			
				|  |  |      client_random | server_random | TLSSECRET_MAGIC
 | 
	
		
			
				|  |  |    */
 | 
	
		
			
				|  |  | -  memcpy(buf +  0, tls->ssl->s3->client_random, 32);
 | 
	
		
			
				|  |  | -  memcpy(buf + 32, tls->ssl->s3->server_random, 32);
 | 
	
		
			
				|  |  | -  memcpy(buf + 64, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1);
 | 
	
		
			
				|  |  | -  len = 64 + strlen(TLSSECRET_MAGIC) + 1;
 | 
	
		
			
				|  |  |    crypto_hmac_sha256((char*)secrets_out,
 | 
	
		
			
				|  |  | -                     (char*)tls->ssl->session->master_key,
 | 
	
		
			
				|  |  | -                     tls->ssl->session->master_key_length,
 | 
	
		
			
				|  |  | -                     buf, len);
 | 
	
		
			
				|  |  | +                     (char*)master_key,
 | 
	
		
			
				|  |  | +                     master_key_len,
 | 
	
		
			
				|  |  | +                     (char*)buf, len);
 | 
	
		
			
				|  |  |    memwipe(buf, 0, sizeof(buf));
 | 
	
		
			
				|  |  | +  memwipe(master_key, 0, master_key_len);
 | 
	
		
			
				|  |  | +  tor_free(master_key);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |