📄 router.c
字号:
/* 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 + -