⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 router.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Copyright (c) 2001 Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2008, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* $Id$ */
const char router_c_id[] =
  "$Id$";

#define ROUTER_PRIVATE

#include "or.h"

/**
 * \file router.c
 * \brief OR functionality, including key maintenance, generating
 * and uploading server descriptors, retrying OR connections.
 **/

extern long stats_n_seconds_working;

/************************************************************/

/*****
 * Key management: ORs only.
 *****/

/** Private keys for this OR.  There is also an SSL key managed by tortls.c.
 */
static tor_mutex_t *key_lock=NULL;
static time_t onionkey_set_at=0; /**< When was onionkey last changed? */
/** Current private onionskin decryption key: used to decode CREATE cells. */
static crypto_pk_env_t *onionkey=NULL;
/** Previous private onionskin decription key: used to decode CREATE cells
 * generated by clients that have an older version of our descriptor. */
static crypto_pk_env_t *lastonionkey=NULL;
/** Private "identity key": used to sign directory info and TLS
 * certificates. Never changes. */
static crypto_pk_env_t *identitykey=NULL;
/** Digest of identitykey. */
static char identitykey_digest[DIGEST_LEN];
/** Signing key used for v3 directory material; only set for authorities. */
static crypto_pk_env_t *authority_signing_key = NULL;
/** Key certificate to authenticate v3 directory material; only set for
 * authorities. */
static authority_cert_t *authority_key_certificate = NULL;

/* (Note that v3 authorities also have a separate "authority identity key",
 * but this key is never actually loaded by the Tor process.  Instead, it's
 * used by tor-gencert to sign new signing keys and make new key
 * certificates. */

/** Replace the current onion key with <b>k</b>.  Does not affect lastonionkey;
 * to update onionkey correctly, call rotate_onion_key().
 */
static void
set_onion_key(crypto_pk_env_t *k)
{
  tor_mutex_acquire(key_lock);
  onionkey = k;
  onionkey_set_at = time(NULL);
  tor_mutex_release(key_lock);
  mark_my_descriptor_dirty();
}

/** Return the current onion key.  Requires that the onion key has been
 * loaded or generated. */
crypto_pk_env_t *
get_onion_key(void)
{
  tor_assert(onionkey);
  return onionkey;
}

/** Store a copy of the current onion key into *<b>key</b>, and a copy
 * of the most recent onion key into *<b>last</b>.
 */
void
dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last)
{
  tor_assert(key);
  tor_assert(last);
  tor_mutex_acquire(key_lock);
  tor_assert(onionkey);
  *key = crypto_pk_dup_key(onionkey);
  if (lastonionkey)
    *last = crypto_pk_dup_key(lastonionkey);
  else
    *last = NULL;
  tor_mutex_release(key_lock);
}

/** Return the time when the onion key was last set.  This is either the time
 * when the process launched, or the time of the most recent key rotation since
 * the process launched.
 */
time_t
get_onion_key_set_at(void)
{
  return onionkey_set_at;
}

/** Set the current identity key to k.
 */
void
set_identity_key(crypto_pk_env_t *k)
{
  if (identitykey)
    crypto_free_pk_env(identitykey);
  identitykey = k;
  crypto_pk_get_digest(identitykey, identitykey_digest);
}

/** Returns the current identity key; requires that the identity key has been
 * set.
 */
crypto_pk_env_t *
get_identity_key(void)
{
  tor_assert(identitykey);
  return identitykey;
}

/** Return true iff the identity key has been set. */
int
identity_key_is_set(void)
{
  return identitykey != NULL;
}

/** Return the key certificate for this v3 (voting) authority, or NULL
 * if we have no such certificate. */
authority_cert_t *
get_my_v3_authority_cert(void)
{
  return authority_key_certificate;
}

/** Return the v3 signing key for this v3 (voting) authority, or NULL
 * if we have no such key. */
crypto_pk_env_t *
get_my_v3_authority_signing_key(void)
{
  return authority_signing_key;
}

/** Replace the previous onion key with the current onion key, and generate
 * a new previous onion key.  Immediately after calling this function,
 * the OR should:
 *   - schedule all previous cpuworkers to shut down _after_ processing
 *     pending work.  (This will cause fresh cpuworkers to be generated.)
 *   - generate and upload a fresh routerinfo.
 */
void
rotate_onion_key(void)
{
  char *fname, *fname_prev;
  crypto_pk_env_t *prkey;
  or_state_t *state = get_or_state();
  time_t now;
  fname = get_datadir_fname2("keys", "secret_onion_key");
  fname_prev = get_datadir_fname2("keys", "secret_onion_key.old");
  if (!(prkey = crypto_new_pk_env())) {
    log_err(LD_GENERAL,"Error constructing rotated onion key");
    goto error;
  }
  if (crypto_pk_generate_key(prkey)) {
    log_err(LD_BUG,"Error generating onion key");
    goto error;
  }
  if (file_status(fname) == FN_FILE) {
    if (replace_file(fname, fname_prev))
      goto error;
  }
  if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
    log_err(LD_FS,"Couldn't write generated onion key to \"%s\".", fname);
    goto error;
  }
  log_info(LD_GENERAL, "Rotating onion key");
  tor_mutex_acquire(key_lock);
  if (lastonionkey)
    crypto_free_pk_env(lastonionkey);
  lastonionkey = onionkey;
  onionkey = prkey;
  now = time(NULL);
  state->LastRotatedOnionKey = onionkey_set_at = now;
  tor_mutex_release(key_lock);
  mark_my_descriptor_dirty();
  or_state_mark_dirty(state, get_options()->AvoidDiskWrites ? now+3600 : 0);
  goto done;
 error:
  log_warn(LD_GENERAL, "Couldn't rotate onion key.");
  if (prkey)
    crypto_free_pk_env(prkey);
 done:
  tor_free(fname);
  tor_free(fname_prev);
}

/** Try to read an RSA key from <b>fname</b>.  If <b>fname</b> doesn't exist
 * and <b>generate</b> is true, create a new RSA key and save it in
 * <b>fname</b>.  Return the read/created key, or NULL on error.  Log all
 * errors at level <b>severity</b>.
 */
crypto_pk_env_t *
init_key_from_file(const char *fname, int generate, int severity)
{
  crypto_pk_env_t *prkey = NULL;
  FILE *file = NULL;

  if (!(prkey = crypto_new_pk_env())) {
    log(severity, LD_GENERAL,"Error constructing key");
    goto error;
  }

  switch (file_status(fname)) {
    case FN_DIR:
    case FN_ERROR:
      log(severity, LD_FS,"Can't read key from \"%s\"", fname);
      goto error;
    case FN_NOENT:
      if (generate) {
        log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.",
                 fname);
        if (crypto_pk_generate_key(prkey)) {
          log(severity, LD_GENERAL,"Error generating onion key");
          goto error;
        }
        if (crypto_pk_check_key(prkey) <= 0) {
          log(severity, LD_GENERAL,"Generated key seems invalid");
          goto error;
        }
        log_info(LD_GENERAL, "Generated key seems valid");
        if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
          log(severity, LD_FS,
              "Couldn't write generated key to \"%s\".", fname);
          goto error;
        }
      } else {
        log_info(LD_GENERAL, "No key found in \"%s\"", fname);
      }
      return prkey;
    case FN_FILE:
      if (crypto_pk_read_private_key_from_filename(prkey, fname)) {
        log(severity, LD_GENERAL,"Error loading private key.");
        goto error;
      }
      return prkey;
    default:
      tor_assert(0);
  }

 error:
  if (prkey)
    crypto_free_pk_env(prkey);
  if (file)
    fclose(file);
  return NULL;
}

/** Load the v3 (voting) authority signing key and certificate, if they are
 * present.  Return -1 if anything is missing, mismatched, or unloadable;
 * return 0 on success. */
static int
init_v3_authority_keys(void)
{
  char *fname = NULL, *cert = NULL;
  const char *eos = NULL;
  crypto_pk_env_t *signing_key = NULL;
  authority_cert_t *parsed = NULL;
  int r = -1;

  fname = get_datadir_fname2("keys", "authority_signing_key");
  signing_key = init_key_from_file(fname, 0, LOG_INFO);
  if (!signing_key) {
    log_warn(LD_DIR, "No version 3 directory key found in %s", fname);
    goto done;
  }
  tor_free(fname);
  fname = get_datadir_fname2("keys", "authority_certificate");
  cert = read_file_to_str(fname, 0, NULL);
  if (!cert) {
    log_warn(LD_DIR, "Signing key found, but no certificate found in %s",
               fname);
    goto done;
  }
  parsed = authority_cert_parse_from_string(cert, &eos);
  if (!parsed) {
    log_warn(LD_DIR, "Unable to parse certificate in %s", fname);
    goto done;
  }
  if (crypto_pk_cmp_keys(signing_key, parsed->signing_key) != 0) {
    log_warn(LD_DIR, "Stored signing key does not match signing key in "
             "certificate");
    goto done;
  }
  parsed->cache_info.signed_descriptor_body = cert;
  parsed->cache_info.signed_descriptor_len = eos-cert;
  cert = NULL;

  /* Free old values... */
  if (authority_key_certificate)
    authority_cert_free(authority_key_certificate);
  if (authority_signing_key)
    crypto_free_pk_env(authority_signing_key);
  /* ...and replace them. */
  authority_key_certificate = parsed;
  authority_signing_key = signing_key;
  parsed = NULL;
  signing_key = NULL;

  r = 0;
 done:
  tor_free(fname);
  tor_free(cert);
  if (signing_key)
    crypto_free_pk_env(signing_key);
  if (parsed)
    authority_cert_free(parsed);
  return r;
}

/** If we're a v3 authority, check whether we have a certificate that's
 * likely to expire soon.  Warn if we do, but not too often. */
void
v3_authority_check_key_expiry(void)
{
  time_t now, expires;
  static time_t last_warned = 0;
  int badness, time_left, warn_interval;
  if (!authdir_mode_v3(get_options()) || !authority_key_certificate)
    return;

  now = time(NULL);
  expires = authority_key_certificate->expires;
  time_left = (int)( expires - now );
  if (time_left <= 0) {
    badness = LOG_ERR;
    warn_interval = 60*60;
  } else if (time_left <= 24*60*60) {
    badness = LOG_WARN;
    warn_interval = 60*60;
  } else if (time_left <= 24*60*60*7) {
    badness = LOG_WARN;
    warn_interval = 24*60*60;
  } else if (time_left <= 24*60*60*30) {
    badness = LOG_WARN;
    warn_interval = 24*60*60*5;
  } else {
    return;
  }

  if (last_warned + warn_interval > now)
    return;

  if (time_left <= 0) {
    log(badness, LD_DIR, "Your v3 authority certificate has expired."
        " Generate a new one NOW.");
  } else if (time_left <= 24*60*60) {
    log(badness, LD_DIR, "Your v3 authority certificate expires in %d hours;"
        " Generate a new one NOW.", time_left/(60*60));
  } else {
    log(badness, LD_DIR, "Your v3 authority certificate expires in %d days;"
        " Generate a new one soon.", time_left/(24*60*60));
  }
  last_warned = now;
}

/** Initialize all OR private keys, and the TLS context, as necessary.
 * On OPs, this only initializes the tls context. Return 0 on success,
 * or -1 if Tor should die.
 */
int
init_keys(void)
{
  char *keydir;
  char fingerprint[FINGERPRINT_LEN+1];
  /*nickname<space>fp\n\0 */
  char fingerprint_line[MAX_NICKNAME_LEN+FINGERPRINT_LEN+3];
  const char *mydesc;
  crypto_pk_env_t *prkey;
  char digest[20];
  char v3_digest[20];
  char *cp;
  or_options_t *options = get_options();
  authority_type_t type;
  time_t now = time(NULL);
  trusted_dir_server_t *ds;
  int v3_digest_set = 0;
  authority_cert_t *cert = NULL;

  if (!key_lock)
    key_lock = tor_mutex_new();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -