From 638fdedcf16cf7d6f7c586d36f7ef335c1c9714f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 23 Oct 2011 16:06:06 +0000 Subject: [PATCH] Don't send a certificate chain on outgoing TLS connections from non-relays --- changes/issue-2011-10-19L | 12 +++++ src/common/tortls.c | 93 +++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 changes/issue-2011-10-19L diff --git a/changes/issue-2011-10-19L b/changes/issue-2011-10-19L new file mode 100644 index 0000000000..972823eeea --- /dev/null +++ b/changes/issue-2011-10-19L @@ -0,0 +1,12 @@ + o Security fixes: + + - Don't send TLS certificate chains on outgoing OR connections + from clients and bridges. Previously, each client or bridge + would use a single cert chain for all outgoing OR connections + for up to 24 hours, which allowed any relay connected to by a + client or bridge to determine which entry guards it is using. + This is a potential user-tracing bug for *all* users; everyone + who uses Tor's client or hidden service functionality should + upgrade. Fixes CVE-2011-2768. Bugfix on FIXME; found by + frosty_un. + diff --git a/src/common/tortls.c b/src/common/tortls.c index c78a9ec953..cc805f80ce 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -186,9 +186,11 @@ static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa, static void tor_tls_unblock_renegotiation(tor_tls_t *tls); static int tor_tls_context_init_one(tor_tls_context_t **ppcontext, crypto_pk_env_t *identity, - unsigned int key_lifetime); + unsigned int key_lifetime, + int is_client); static tor_tls_context_t *tor_tls_context_new(crypto_pk_env_t *identity, - unsigned int key_lifetime); + unsigned int key_lifetime, + int is_client); /** Global TLS contexts. We keep them here because nobody else needs * to touch them. */ @@ -624,7 +626,7 @@ tor_tls_context_init(int is_public_server, rv1 = tor_tls_context_init_one(&server_tls_context, server_identity, - key_lifetime); + key_lifetime, 0); if (rv1 >= 0) { new_ctx = server_tls_context; @@ -640,7 +642,8 @@ tor_tls_context_init(int is_public_server, if (server_identity != NULL) { rv1 = tor_tls_context_init_one(&server_tls_context, server_identity, - key_lifetime); + key_lifetime, + 0); } else { tor_tls_context_t *old_ctx = server_tls_context; server_tls_context = NULL; @@ -652,7 +655,8 @@ tor_tls_context_init(int is_public_server, rv2 = tor_tls_context_init_one(&client_tls_context, client_identity, - key_lifetime); + key_lifetime, + 1); } return rv1 < rv2 ? rv1 : rv2; @@ -669,10 +673,12 @@ tor_tls_context_init(int is_public_server, static int tor_tls_context_init_one(tor_tls_context_t **ppcontext, crypto_pk_env_t *identity, - unsigned int key_lifetime) + unsigned int key_lifetime, + int is_client) { tor_tls_context_t *new_ctx = tor_tls_context_new(identity, - key_lifetime); + key_lifetime, + is_client); tor_tls_context_t *old_ctx = *ppcontext; if (new_ctx != NULL) { @@ -694,7 +700,8 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext, * certificate. */ static tor_tls_context_t * -tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime) +tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime, + int is_client) { crypto_pk_env_t *rsa = NULL; EVP_PKEY *pkey = NULL; @@ -711,22 +718,26 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime) goto error; if (crypto_pk_generate_key(rsa)<0) goto error; - /* Create certificate signed by identity key. */ - cert = tor_tls_create_certificate(rsa, identity, nickname, nn2, - key_lifetime); - /* Create self-signed certificate for identity key. */ - idcert = tor_tls_create_certificate(identity, identity, nn2, nn2, - IDENTITY_CERT_LIFETIME); - if (!cert || !idcert) { - log(LOG_WARN, LD_CRYPTO, "Error creating certificate"); - goto error; + if (!is_client) { + /* Create certificate signed by identity key. */ + cert = tor_tls_create_certificate(rsa, identity, nickname, nn2, + key_lifetime); + /* Create self-signed certificate for identity key. */ + idcert = tor_tls_create_certificate(identity, identity, nn2, nn2, + IDENTITY_CERT_LIFETIME); + if (!cert || !idcert) { + log(LOG_WARN, LD_CRYPTO, "Error creating certificate"); + goto error; + } } result = tor_malloc_zero(sizeof(tor_tls_context_t)); result->refcnt = 1; - result->my_cert = X509_dup(cert); - result->my_id_cert = X509_dup(idcert); - result->key = crypto_pk_dup_key(rsa); + if (!is_client) { + result->my_cert = X509_dup(cert); + result->my_id_cert = X509_dup(idcert); + result->key = crypto_pk_dup_key(rsa); + } #ifdef EVERYONE_HAS_AES /* Tell OpenSSL to only use TLS1 */ @@ -758,27 +769,31 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime) #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS); #endif - if (cert && !SSL_CTX_use_certificate(result->ctx,cert)) - 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; + if (! is_client) { + if (cert && !SSL_CTX_use_certificate(result->ctx,cert)) + 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); - tor_assert(rsa); - if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1))) - goto error; - if (!SSL_CTX_use_PrivateKey(result->ctx, pkey)) - goto error; - EVP_PKEY_free(pkey); - pkey = NULL; - if (!SSL_CTX_check_private_key(result->ctx)) - goto error; + if (!is_client) { + tor_assert(rsa); + if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1))) + goto error; + if (!SSL_CTX_use_PrivateKey(result->ctx, pkey)) + goto error; + EVP_PKEY_free(pkey); + pkey = NULL; + if (!SSL_CTX_check_private_key(result->ctx)) + goto error; + } { crypto_dh_env_t *dh = crypto_dh_new(DH_TYPE_TLS); SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_env_get_dh(dh));