Maintain separate server and client TLS contexts.

Fixes bug #988.
This commit is contained in:
Robert Ransom 2010-10-03 18:14:08 -07:00
parent d3879dbd16
commit 17efbe031d
4 changed files with 104 additions and 21 deletions

View File

@ -190,12 +190,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;
@ -431,9 +435,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.");
@ -620,21 +630,80 @@ tor_tls_context_incref(tor_tls_context_t *ctx)
++ctx->refcnt;
}
/** Create new global client and server TLS contexts.
*
* If <b>server_identity</b> is NULL, this will not generate a server
* TLS context. If <b>is_public_server</b> is non-zero, this will use
* the same TLS context for incoming and outgoing connections, and
* ignore <b>client_identity</b>. */
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 MIN(rv1, rv2);
}
/** Create a new global TLS context.
*
* You can call this function multiple times. Each time you call it,
* 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) {
@ -946,9 +1015,11 @@ 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))) {
tor_assert(context); /* make sure somebody made it first */
if (!(result->ssl = SSL_new(context->ctx))) {
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating SSL object");
tor_free(result);
return NULL;
@ -988,8 +1059,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;

View File

@ -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);

View File

@ -875,6 +875,7 @@ run_scheduled_events(time_t now)
static int should_init_bridge_stats = 1;
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;
@ -896,7 +897,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();
@ -930,7 +931,10 @@ run_scheduled_events(time_t now)
last_rotated_x509_certificate = now;
if (last_rotated_x509_certificate+MAX_SSL_KEY_LIFETIME < now) {
log_info(LD_GENERAL,"Rotating tls context.");
if (tor_tls_context_init(get_identity_key(), MAX_SSL_KEY_LIFETIME) < 0) {
if (tor_tls_context_init(public_server_mode(options),
get_identity_key(),
is_server ? get_identity_key() : NULL,
MAX_SSL_KEY_LIFETIME) < 0) {
log_warn(LD_BUG, "Error reinitializing TLS context");
/* XXX is it a bug here, that we just keep going? -RD */
}
@ -1213,7 +1217,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 {

View File

@ -471,8 +471,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) < 0) {
/* Create a TLS context. */
if (tor_tls_context_init(0,
get_identity_key(),
NULL,
MAX_SSL_KEY_LIFETIME) < 0) {
log_err(LD_GENERAL,"Error creating TLS context for Tor client.");
return -1;
}
@ -550,7 +553,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) < 0) {
if (tor_tls_context_init(public_server_mode(options),
get_identity_key(),
get_identity_key(),
MAX_SSL_KEY_LIFETIME) < 0) {
log_err(LD_GENERAL,"Error initializing TLS context");
return -1;
}