@@ -120,24 +120,6 @@ typedef struct tor_tls_context_t {
crypto_pk_t *auth_key;
} tor_tls_context_t ;
/* * Return values for tor_tls_classify_client_ciphers.
*
* @{
*/
/* * An error occurred when examining the client ciphers */
#define CIPHERS_ERR -1
/* * The client cipher list indicates that a v1 handshake was in use. */
#define CIPHERS_V1 1
/* * The client cipher list indicates that the client is using the v2 or the
* v3 handshake, but that it is (probably!) lying about what ciphers it
* supports */
#define CIPHERS_V2 2
/* * The client cipher list indicates that the client is using the v2 or the
* v3 handshake, and that it is telling the truth about what ciphers it
* supports */
#define CIPHERS_UNRESTRICTED 3
/* * @} */
#define TOR_TLS_MAGIC 0x71571571
typedef enum {
@@ -167,9 +149,6 @@ struct tor_tls_t {
* 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
@@ -698,16 +677,8 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
#undef SERIAL_NUMBER_SIZE
}
/* * 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[] =
/* * List of ciphers that servers should select from. */
const char SERVER_CIPHER_LIST[] =
/* This list is autogenerated with the gen_server_ciphers.py script;
* don't hand-edit it. */
#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384
@@ -755,7 +726,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
@@ -783,13 +753,6 @@ static const cipher_info_t CLIENT_CIPHER_INFO_LIST[] = {
/* * 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
@@ -1226,7 +1189,8 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
result->refcnt = 1 ;
if (!is_client) {
result->my_link_cert = tor_cert_new (X509_dup (cert));
result->my_id_cert = tor_cert_new (X509_dup (idcert));
result->my_id_cert = tor_cert_new (idcert);
if (result->my_id_cert ) idcert = NULL ;
result->my_auth_cert = tor_cert_new (X509_dup (authcert));
if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert )
goto error;
@@ -1332,13 +1296,6 @@ 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) {
X509_STORE *s = SSL_CTX_get_cert_store (result->ctx );
tor_assert (s);
X509_STORE_add_cert (s, idcert);
X509_free (idcert); /* The context now owns the reference to idcert */
idcert = NULL ;
}
}
SSL_CTX_set_session_cache_mode (result->ctx , SSL_SESS_CACHE_OFF);
if (!is_client) {
@@ -1430,205 +1387,8 @@ tor_tls_get_ciphersuite_name(tor_tls_t *tls)
#ifdef V2_HANDSHAKE_SERVER
/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to
* 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[] = {
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 */
0x0038 , /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */
0xc00f , /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */
0xc005 , /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */
0x0035 , /* TLS1_TXT_RSA_WITH_AES_256_SHA */
0xc007 , /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */
0xc009 , /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */
0xc011 , /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */
0xc013 , /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */
0x0033 , /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */
0x0032 , /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */
0xc00c , /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */
0xc00e , /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */
0xc002 , /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */
0xc004 , /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */
0x0004 , /* SSL3_TXT_RSA_RC4_128_MD5 */
0x0005 , /* SSL3_TXT_RSA_RC4_128_SHA */
0x002f , /* TLS1_TXT_RSA_WITH_AES_128_SHA */
0xc008 , /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */
0xc012 , /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */
0x0016 , /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */
0x0013 , /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */
0xc00d , /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */
0xc003 , /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */
0xfeff , /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */
0x000a , /* SSL3_TXT_RSA_DES_192_CBC3_SHA */
0
};
/* * Have we removed the unrecognized ciphers from v2_cipher_list yet? */
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)
{
const SSL_CIPHER *c;
#ifdef 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));
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 = m->get_cipher_by_char (cipherid);
if (c)
tor_assert ((c->id & 0xffff ) == cipher);
return c != NULL ;
} else
#endif
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
* quadratic search.
*/
int i;
for (i = 0 ; i < m->num_ciphers (); ++i) {
c = m->get_cipher (i);
if (c && (c->id & 0xffff ) == cipher) {
return 1 ;
}
}
return 0 ;
} else {
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 )
{
uint16_t *inp, *outp;
const SSL_METHOD *m = SSLv23_method ();
inp = outp = v2_cipher_list;
while (*inp) {
if (find_cipher_by_id (m, *inp)) {
*outp++ = *inp++;
} else {
inp++;
}
}
*outp = 0 ;
v2_cipher_list_pruned = 1 ;
}
/* * 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,
STACK_OF (SSL_CIPHER) *peer_ciphers)
{
int i, res;
tor_tls_t *tor_tls;
if (PREDICT_UNLIKELY (!v2_cipher_list_pruned))
prune_v2_cipher_list ();
tor_tls = tor_tls_get_by_ssl (ssl);
if (tor_tls && tor_tls->client_cipher_list_type )
return tor_tls->client_cipher_list_type ;
/* If we reached this point, we just got a client hello. See if there is
* a cipher list. */
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 (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) &&
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);
// return 1;
goto v2_or_higher;
}
}
res = CIPHERS_V1;
goto done;
v2_or_higher:
{
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 ;
if (id == 0x00ff ) /* extended renegotiation indicator. */
continue ;
if (!id || id != *v2_cipher) {
res = CIPHERS_UNRESTRICTED;
goto dump_ciphers;
}
++v2_cipher;
}
if (*v2_cipher != 0 ) {
res = CIPHERS_UNRESTRICTED;
goto dump_ciphers;
}
res = CIPHERS_V2;
}
dump_ciphers:
{
smartlist_t *elts = smartlist_new ();
char *s;
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);
}
s = smartlist_join_strings (elts, " :" , 0 , NULL );
log_debug (LD_NET, " Got a %s V2/V3 cipher list from %s . It is: '%s '" ,
(res == CIPHERS_V2) ? " fictitious" : " real" , ADDR (tor_tls), s);
tor_free (s);
smartlist_free (elts);
}
done:
if (tor_tls)
return tor_tls->client_cipher_list_type = res;
return res;
}
/* * 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
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;
}
return tor_tls_classify_client_ciphers (ssl, session->ciphers ) >= CIPHERS_V2;
}
/* * Invoked when we're accepting a connection on <b>ssl</b>, and the connection
* changes state. We use this:
* <ul><li>To alter the state of the handshake partway through, so we
* do not send or request extra certificates in v2 handshakes.</li>
* <li>To detect renegotiation</li></ul>
*/
static void
@@ -1658,74 +1418,28 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
}
/* Now check the cipher list. */
if (tor_tls_client_is_using_v2_ciphers (ssl)) {
if (tls->wasV2Handshake )
return ; /* We already turned this stuff off for the first handshake;
* This is a renegotiation. */
if (tls->wasV2Handshake )
return ; /* We already turned this stuff off for the first handshake;
* This is a renegotiation. */
/* Yes, we're casting away the const from ssl. This is very naughty of us.
* Let's hope openssl doesn't notice! */
/* Yes, we're casting away the const from ssl. This is very naughty of us.
* Let's hope openssl doesn't notice! */
/* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */
SSL_set_mode ((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN);
/* Don't send a hello request. */
SSL_set_verify ((SSL*) ssl, SSL_VERIFY_NONE, NULL );
/* Don't send a hello request. */
SSL_set_verify ((SSL*) ssl, SSL_VERIFY_NONE, NULL );
if (tls) {
tls->wasV2Handshake = 1 ;
if (tls) {
tls->wasV2Handshake = 1 ;
#ifdef USE_BUFFEREVENTS
if (use_unsafe_renegotiation_flag)
tls->ssl ->s3 ->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
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!" );
}
} else {
log_warn (LD_BUG, " Couldn't look up the tls for an SSL*. How odd!" );
}
}
#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.
*
* 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
/* * Explain which ciphers we're missing. */
static void
log_unsupported_ciphers (smartlist_t *unsupported)
@@ -1925,9 +1639,6 @@ 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;
@@ -2178,43 +1889,18 @@ 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;
#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,
* we might have not been able to look up the tor_tls_t if the code
* was buggy. Fixing that. */
if (!tls->wasV2Handshake ) {
log_warn (LD_BUG, " For some reason, wasV2Handshake didn't"
" get set. Fixing that." );
}
tls->wasV2Handshake = 1 ;
log_debug (LD_HANDSHAKE, " Completed V2 TLS handshake with client; waiting"
" for renegotiation." );
} else {
tls->wasV2Handshake = 0 ;
/* This check is redundant, but back when we did it in the callback,
* we might have not been able to look up the tor_tls_t if the code
* was buggy. Fixing that. */
if (!tls->wasV2Handshake ) {
log_warn (LD_BUG, " For some reason, wasV2Handshake didn't"
" get set. Fixing that." );
}
#endif
tls->wasV2Handshake = 1 ;
log_debug (LD_HANDSHAKE, " Completed V2 TLS handshake with client; waiting"
" for renegotiation." );
} else {
#ifdef V2_HANDSHAKE_CLIENT
/* If we got no ID cert, we're a v2 handshake. */
X509 *cert = SSL_get_peer_certificate (tls->ssl );
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 "
" looks like a v1 handshake on %p " , tls);
tls->wasV2Handshake = 0 ;
} else {
log_debug (LD_HANDSHAKE,
" Server sent back a single certificate; looks like "
" a v2 handshake on %p ." , tls);
tls->wasV2Handshake = 1 ;
}
if (cert)
X509_free (cert);
#endif
tls->wasV2Handshake = 1 ;
if (SSL_set_cipher_list (tls->ssl , SERVER_CIPHER_LIST) == 0 ) {
tls_log_errors (NULL , LOG_WARN, LD_HANDSHAKE, " re-setting ciphers" );
r = TOR_TLS_ERROR_MISC;
@@ -2638,27 +2324,6 @@ check_no_tls_errors_(const char *fname, int line)
tls_log_errors (NULL , LOG_WARN, LD_NET, NULL );
}
/* * Return true iff the initial TLS connection at <b>tls</b> did not use a v2
* TLS handshake. Output is undefined if the handshake isn't finished. */
int
tor_tls_used_v1_handshake (tor_tls_t *tls)
{
#if defined(V2_HANDSHAKE_SERVER) && defined(V2_HANDSHAKE_CLIENT)
return ! tls->wasV2Handshake ;
#else
if (tls->isServer ) {
# ifdef V2_HANDSHAKE_SERVER
return ! tls->wasV2Handshake ;
# endif
} else {
# ifdef V2_HANDSHAKE_CLIENT
return ! tls->wasV2Handshake ;
# endif
}
return 1 ;
#endif
}
/* * Return true iff <b>name</b> is a DN of a kind that could only
* occur in a v3-handshake-indicating certificate */
static int