Commit 9976df9e authored by Robert Ransom's avatar Robert Ransom Committed by Sebastian Hahn
Browse files

Maintain separate server and client TLS contexts.

Fixes bug #988.

Conflicts:

	src/or/main.c
	src/or/router.c
parent 87816401
Loading
Loading
Loading
Loading
+86 −15
Original line number Diff line number Diff line
@@ -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 <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 rv1 < rv2 ? rv1 : rv2;
}

/** Create a new TLS context for use with Tor TLS handshakes.
 * <b>identity</b> 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;
+3 −1
Original line number Diff line number Diff line
@@ -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);
+7 −3
Original line number Diff line number Diff line
@@ -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 {
+9 −4
Original line number Diff line number Diff line
@@ -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,7 +539,9 @@ init_keys(void)
  tor_free(keydir);

  /* 3. Initialize link key and TLS context. */
  if (tor_tls_context_init(get_identity_key(),
  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;