|  | @@ -678,11 +678,42 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
 | 
	
		
			
				|  |  |  #undef SERIAL_NUMBER_SIZE
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/** List of ciphers that servers should select from.*/
 | 
	
		
			
				|  |  | +/** List of ciphers that servers should select from when the client might be
 | 
	
		
			
				|  |  | + * claiming extra unsupported ciphers in order to avoid fingerprinting.  */
 | 
	
		
			
				|  |  |  #define SERVER_CIPHER_LIST                         \
 | 
	
		
			
				|  |  |    (TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"           \
 | 
	
		
			
				|  |  |     TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"           \
 | 
	
		
			
				|  |  |     SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** List of ciphers that servers should select from when we actually have
 | 
	
		
			
				|  |  | + * our choice of what cipher to use. */
 | 
	
		
			
				|  |  | +const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
 | 
	
		
			
				|  |  | +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CHC_SHA
 | 
	
		
			
				|  |  | +       TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384
 | 
	
		
			
				|  |  | +       TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256
 | 
	
		
			
				|  |  | +       TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
 | 
	
		
			
				|  |  | +       TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
 | 
	
		
			
				|  |  | +       TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +//#if TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA
 | 
	
		
			
				|  |  | +//    TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA ":"
 | 
	
		
			
				|  |  | +//#endif
 | 
	
		
			
				|  |  | +  /* These next two are mandatory. */
 | 
	
		
			
				|  |  | +  TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
 | 
	
		
			
				|  |  | +  TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"
 | 
	
		
			
				|  |  | +#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA
 | 
	
		
			
				|  |  | +       TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA ":"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +  SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /* Note: to set up your own private testing network with link crypto
 | 
	
		
			
				|  |  |   * disabled, set your Tors' cipher list to
 | 
	
		
			
				|  |  |   * (SSL3_TXT_RSA_NULL_SHA).  If you do this, you won't be able to communicate
 | 
	
	
		
			
				|  | @@ -1410,15 +1441,22 @@ prune_v2_cipher_list(void)
 | 
	
		
			
				|  |  |    v2_cipher_list_pruned = 1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Return the name of the negotiated ciphersuite in use on <b>tls</b> */
 | 
	
		
			
				|  |  | +const char *
 | 
	
		
			
				|  |  | +tor_tls_get_ciphersuite_name(tor_tls_t *tls)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  return SSL_get_cipher(tls->ssl);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Examine the client cipher list in <b>ssl</b>, and determine what kind of
 | 
	
		
			
				|  |  |   * client it is.  Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2,
 | 
	
		
			
				|  |  |   * CIPHERS_UNRESTRICTED.
 | 
	
		
			
				|  |  |   **/
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  | -tor_tls_classify_client_ciphers(const SSL *ssl)
 | 
	
		
			
				|  |  | +tor_tls_classify_client_ciphers(const SSL *ssl,
 | 
	
		
			
				|  |  | +                                STACK_OF(SSL_CIPHER) *peer_ciphers)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    int i, res;
 | 
	
		
			
				|  |  | -  SSL_SESSION *session;
 | 
	
		
			
				|  |  |    tor_tls_t *tor_tls;
 | 
	
		
			
				|  |  |    if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
 | 
	
		
			
				|  |  |      prune_v2_cipher_list();
 | 
	
	
		
			
				|  | @@ -1429,20 +1467,15 @@ tor_tls_classify_client_ciphers(const SSL *ssl)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* If we reached this point, we just got a client hello.  See if there is
 | 
	
		
			
				|  |  |     * a cipher list. */
 | 
	
		
			
				|  |  | -  if (!(session = SSL_get_session((SSL *)ssl))) {
 | 
	
		
			
				|  |  | -    log_info(LD_NET, "No session on TLS?");
 | 
	
		
			
				|  |  | -    res = CIPHERS_ERR;
 | 
	
		
			
				|  |  | -    goto done;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (!session->ciphers) {
 | 
	
		
			
				|  |  | +  if (!peer_ciphers) {
 | 
	
		
			
				|  |  |      log_info(LD_NET, "No ciphers on session");
 | 
	
		
			
				|  |  |      res = CIPHERS_ERR;
 | 
	
		
			
				|  |  |      goto done;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    /* Now we need to see if there are any ciphers whose presence means we're
 | 
	
		
			
				|  |  |     * dealing with an updated Tor. */
 | 
	
		
			
				|  |  | -  for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
 | 
	
		
			
				|  |  | -    SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
 | 
	
		
			
				|  |  | +  for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
 | 
	
		
			
				|  |  | +    SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
 | 
	
		
			
				|  |  |      const char *ciphername = SSL_CIPHER_get_name(cipher);
 | 
	
		
			
				|  |  |      if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) &&
 | 
	
		
			
				|  |  |          strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) &&
 | 
	
	
		
			
				|  | @@ -1458,8 +1491,8 @@ tor_tls_classify_client_ciphers(const SSL *ssl)
 | 
	
		
			
				|  |  |   v2_or_higher:
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      const uint16_t *v2_cipher = v2_cipher_list;
 | 
	
		
			
				|  |  | -    for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
 | 
	
		
			
				|  |  | -      SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
 | 
	
		
			
				|  |  | +    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;
 | 
	
		
			
				|  |  |        if (id == 0x00ff) /* extended renegotiation indicator. */
 | 
	
		
			
				|  |  |          continue;
 | 
	
	
		
			
				|  | @@ -1480,8 +1513,8 @@ tor_tls_classify_client_ciphers(const SSL *ssl)
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      smartlist_t *elts = smartlist_new();
 | 
	
		
			
				|  |  |      char *s;
 | 
	
		
			
				|  |  | -    for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
 | 
	
		
			
				|  |  | -      SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
 | 
	
		
			
				|  |  | +    for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
 | 
	
		
			
				|  |  | +      SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
 | 
	
		
			
				|  |  |        const char *ciphername = SSL_CIPHER_get_name(cipher);
 | 
	
		
			
				|  |  |        smartlist_add(elts, (char*)ciphername);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1504,8 +1537,56 @@ tor_tls_classify_client_ciphers(const SSL *ssl)
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  |  tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  return tor_tls_classify_client_ciphers(ssl) >= CIPHERS_V2;
 | 
	
		
			
				|  |  | +  SSL_SESSION *session;
 | 
	
		
			
				|  |  | +  if (!(session = SSL_get_session((SSL *)ssl))) {
 | 
	
		
			
				|  |  | +    log_info(LD_NET, "No session on TLS?");
 | 
	
		
			
				|  |  | +    return CIPHERS_ERR;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return tor_tls_classify_client_ciphers(ssl, session->ciphers) >= CIPHERS_V2;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#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.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * We can't abuse an info_cb for this, since by the time one of the
 | 
	
		
			
				|  |  | + * client_hello info_cbs is called, we've already picked which ciphersuite to
 | 
	
		
			
				|  |  | + * use.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Technically, this function is an abuse of this callback, since the point of
 | 
	
		
			
				|  |  | + * a session_secret_cb is to try to set up and/or verify a shared-secret for
 | 
	
		
			
				|  |  | + * authentication on the fly.  But as long as we return 0, we won't actually be
 | 
	
		
			
				|  |  | + * setting up a shared secret, and all will be fine.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +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)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  (void) secret;
 | 
	
		
			
				|  |  | +  (void) secret_len;
 | 
	
		
			
				|  |  | +  (void) peer_ciphers;
 | 
	
		
			
				|  |  | +  (void) cipher;
 | 
	
		
			
				|  |  | +  (void) arg;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) ==
 | 
	
		
			
				|  |  | +       CIPHERS_UNRESTRICTED) {
 | 
	
		
			
				|  |  | +    SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  SSL_set_session_secret_cb(ssl, NULL, NULL);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +static void
 | 
	
		
			
				|  |  | +tor_tls_setup_session_secret_cb(tor_tls_t *tls)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +#define tor_tls_setup_session_secret_cb(tls) STMT_NIL
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Invoked when a TLS state changes: log the change at severity 'debug' */
 | 
	
		
			
				|  |  |  static void
 | 
	
	
		
			
				|  | @@ -1773,6 +1854,9 @@ tor_tls_new(int sock, int isServer)
 | 
	
		
			
				|  |  |      SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  if (isServer)
 | 
	
		
			
				|  |  | +    tor_tls_setup_session_secret_cb(result);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /* Not expected to get called. */
 | 
	
		
			
				|  |  |    tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
 | 
	
		
			
				|  |  |    return result;
 |