From 9976df9e5619b89339390c322138f7228b8fa715 Mon Sep 17 00:00:00 2001 From: Robert Ransom Date: Sun, 3 Oct 2010 18:14:08 -0700 Subject: Maintain separate server and client TLS contexts. Fixes bug #988. Conflicts: src/or/main.c src/or/router.c --- src/common/tortls.c | 101 ++++++++++++++++++++++++++++++++++++++++++++-------- src/common/tortls.h | 4 ++- src/or/main.c | 10 ++++-- src/or/router.c | 13 ++++--- 4 files changed, 105 insertions(+), 23 deletions(-) diff --git a/src/common/tortls.c b/src/common/tortls.c index d3435e7603..c78a9ec953 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -184,12 +184,16 @@ static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa, const char *cname_sign, unsigned int lifetime); 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); static tor_tls_context_t *tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime); -/** Global tls context. We keep it here because nobody else needs to - * touch it. */ -static tor_tls_context_t *global_tls_context = NULL; +/** Global TLS contexts. We keep them here because nobody else needs + * to touch them. */ +static tor_tls_context_t *server_tls_context = NULL; +static tor_tls_context_t *client_tls_context = NULL; /** True iff tor_tls_init() has been called. */ static int tls_library_is_initialized = 0; @@ -402,9 +406,15 @@ tor_tls_init(void) void tor_tls_free_all(void) { - if (global_tls_context) { - tor_tls_context_decref(global_tls_context); - global_tls_context = NULL; + if (server_tls_context) { + tor_tls_context_t *ctx = server_tls_context; + server_tls_context = NULL; + tor_tls_context_decref(ctx); + } + if (client_tls_context) { + tor_tls_context_t *ctx = client_tls_context; + client_tls_context = NULL; + tor_tls_context_decref(ctx); } if (!HT_EMPTY(&tlsmap_root)) { log_warn(LD_MM, "Still have entries in the tlsmap at shutdown."); @@ -591,6 +601,63 @@ tor_tls_context_incref(tor_tls_context_t *ctx) ++ctx->refcnt; } +/** Create new global client and server TLS contexts. + * + * If server_identity is NULL, this will not generate a server + * TLS context. If is_public_server is non-zero, this will use + * the same TLS context for incoming and outgoing connections, and + * ignore client_identity. */ +int +tor_tls_context_init(int is_public_server, + crypto_pk_env_t *client_identity, + crypto_pk_env_t *server_identity, + unsigned int key_lifetime) +{ + int rv1 = 0; + int rv2 = 0; + + if (is_public_server) { + tor_tls_context_t *new_ctx; + tor_tls_context_t *old_ctx; + + tor_assert(server_identity != NULL); + + rv1 = tor_tls_context_init_one(&server_tls_context, + server_identity, + key_lifetime); + + if (rv1 >= 0) { + new_ctx = server_tls_context; + tor_tls_context_incref(new_ctx); + old_ctx = client_tls_context; + client_tls_context = new_ctx; + + if (old_ctx != NULL) { + tor_tls_context_decref(old_ctx); + } + } + } else { + if (server_identity != NULL) { + rv1 = tor_tls_context_init_one(&server_tls_context, + server_identity, + key_lifetime); + } else { + tor_tls_context_t *old_ctx = server_tls_context; + server_tls_context = NULL; + + if (old_ctx != NULL) { + tor_tls_context_decref(old_ctx); + } + } + + rv2 = tor_tls_context_init_one(&client_tls_context, + client_identity, + key_lifetime); + } + + return rv1 < rv2 ? rv1 : rv2; +} + /** Create a new TLS context for use with Tor TLS handshakes. * identity should be set to the identity key used to sign the * certificate. @@ -599,15 +666,17 @@ tor_tls_context_incref(tor_tls_context_t *ctx) * it generates new certificates; all new connections will use * the new SSL context. */ -int -tor_tls_context_init(crypto_pk_env_t *identity, unsigned int key_lifetime) +static int +tor_tls_context_init_one(tor_tls_context_t **ppcontext, + crypto_pk_env_t *identity, + unsigned int key_lifetime) { tor_tls_context_t *new_ctx = tor_tls_context_new(identity, key_lifetime); - tor_tls_context_t *old_ctx = global_tls_context; + tor_tls_context_t *old_ctx = *ppcontext; if (new_ctx != NULL) { - global_tls_context = new_ctx; + *ppcontext = new_ctx; /* Free the old context if one existed. */ if (old_ctx != NULL) { @@ -920,10 +989,12 @@ tor_tls_new(int sock, int isServer) { BIO *bio = NULL; tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t)); + tor_tls_context_t *context = isServer ? server_tls_context : + client_tls_context; - tor_assert(global_tls_context); /* make sure somebody made it first */ - if (!(result->ssl = SSL_new(global_tls_context->ctx))) { - tls_log_errors(NULL, LOG_WARN, "generating TLS context"); + tor_assert(context); /* make sure somebody made it first */ + if (!(result->ssl = SSL_new(context->ctx))) { + tls_log_errors(NULL, LOG_WARN, "creating SSL object"); tor_free(result); return NULL; } @@ -962,8 +1033,8 @@ tor_tls_new(int sock, int isServer) } HT_INSERT(tlsmap, &tlsmap_root, result); SSL_set_bio(result->ssl, bio, bio); - tor_tls_context_incref(global_tls_context); - result->context = global_tls_context; + tor_tls_context_incref(context); + result->context = context; result->state = TOR_TLS_ST_HANDSHAKE; result->isServer = isServer; result->wantwrite_n = 0; diff --git a/src/common/tortls.h b/src/common/tortls.h index 3f80d998b7..55fee81aea 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -50,7 +50,9 @@ typedef struct tor_tls_t tor_tls_t; const char *tor_tls_err_to_string(int err); void tor_tls_free_all(void); -int tor_tls_context_init(crypto_pk_env_t *identity, +int tor_tls_context_init(int is_public_server, + crypto_pk_env_t *client_identity, + crypto_pk_env_t *server_identity, unsigned int key_lifetime); tor_tls_t *tor_tls_new(int sock, int is_server); void tor_tls_set_logged_address(tor_tls_t *tls, const char *address); diff --git a/src/or/main.c b/src/or/main.c index fe1f42ece3..00fce80024 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -816,6 +816,7 @@ run_scheduled_events(time_t now) static time_t time_to_dump_geoip_stats = 0; static time_t time_to_retry_dns_init = 0; or_options_t *options = get_options(); + int is_server = server_mode(options); int i; int have_dir_info; @@ -837,7 +838,7 @@ run_scheduled_events(time_t now) * shut down and restart all cpuworkers, and update the directory if * necessary. */ - if (server_mode(options) && + if (is_server && get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) { log_info(LD_GENERAL,"Rotating onion key."); rotate_onion_key(); @@ -872,7 +873,10 @@ run_scheduled_events(time_t now) last_rotated_x509_certificate = now; if (last_rotated_x509_certificate+MAX_SSL_KEY_LIFETIME_INTERNAL < now) { log_info(LD_GENERAL,"Rotating tls context."); - if (tor_tls_context_init(get_identity_key(), MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + if (tor_tls_context_init(public_server_mode(options), + get_identity_key(), + is_server ? get_identity_key() : NULL, + MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { log_warn(LD_BUG, "Error reinitializing TLS context"); /* XXX is it a bug here, that we just keep going? -RD */ } @@ -1110,7 +1114,7 @@ run_scheduled_events(time_t now) /** 9. and if we're a server, check whether our DNS is telling stories to * us. */ - if (server_mode(options) && time_to_check_for_correct_dns < now) { + if (is_server && time_to_check_for_correct_dns < now) { if (!time_to_check_for_correct_dns) { time_to_check_for_correct_dns = now + 60 + crypto_rand_int(120); } else { diff --git a/src/or/router.c b/src/or/router.c index 9afa983bc3..dce2ad6018 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -457,8 +457,11 @@ init_keys(void) return -1; } set_identity_key(prkey); - /* Create a TLS context; default the client nickname to "client". */ - if (tor_tls_context_init(get_identity_key(), MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + /* Create a TLS context. */ + if (tor_tls_context_init(0, + get_identity_key(), + NULL, + MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { log_err(LD_GENERAL,"Error creating TLS context for Tor client."); return -1; } @@ -536,8 +539,10 @@ init_keys(void) tor_free(keydir); /* 3. Initialize link key and TLS context. */ - if (tor_tls_context_init(get_identity_key(), - MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + if (tor_tls_context_init(public_server_mode(options), + get_identity_key(), + get_identity_key(), + MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { log_err(LD_GENERAL,"Error initializing TLS context"); return -1; } -- cgit v1.2.3-54-g00ecf