Loading configure.ac +18 −0 Original line number Diff line number Diff line Loading @@ -610,10 +610,28 @@ else fi AC_SUBST(TOR_OPENSSL_LIBS) dnl Now check for particular openssl functions. save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LIBS="$TOR_OPENSSL_LIBS $LIBS" LDFLAGS="$TOR_LDFLAGS_openssl $LDFLAGS" CPPFLAGS="$TOR_CPPFLAGS_openssl $CPPFLAGS" AC_CHECK_MEMBERS([struct ssl_method_st.get_cipher_by_char], , , [#include <openssl/ssl.h> ]) AC_CHECK_FUNCS([ \ SSL_SESSION_get_master_key \ SSL_get_server_random \ SSL_get_client_ciphers \ SSL_get_client_random \ SSL_CIPHER_find \ ]) LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" CPPFLAGS="$save_CPPFLAGS" dnl ------------------------------------------------------ dnl Where do you live, zlib? And how do we call you? Loading src/common/tortls.c +91 −198 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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. */ Loading Loading @@ -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) { Loading Loading @@ -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. Loading @@ -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; } Loading Loading
configure.ac +18 −0 Original line number Diff line number Diff line Loading @@ -610,10 +610,28 @@ else fi AC_SUBST(TOR_OPENSSL_LIBS) dnl Now check for particular openssl functions. save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LIBS="$TOR_OPENSSL_LIBS $LIBS" LDFLAGS="$TOR_LDFLAGS_openssl $LDFLAGS" CPPFLAGS="$TOR_CPPFLAGS_openssl $CPPFLAGS" AC_CHECK_MEMBERS([struct ssl_method_st.get_cipher_by_char], , , [#include <openssl/ssl.h> ]) AC_CHECK_FUNCS([ \ SSL_SESSION_get_master_key \ SSL_get_server_random \ SSL_get_client_ciphers \ SSL_get_client_random \ SSL_CIPHER_find \ ]) LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" CPPFLAGS="$save_CPPFLAGS" dnl ------------------------------------------------------ dnl Where do you live, zlib? And how do we call you? Loading
src/common/tortls.c +91 −198 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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. */ Loading Loading @@ -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) { Loading Loading @@ -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. Loading @@ -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; } Loading