Newer
Older
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTER_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "app/config/statefile.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
#include "core/or/policies.h"
#include "core/or/protover.h"
#include "feature/client/transports.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/process_descs.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
#include "feature/dircommon/directory.h"
#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/routerparse.h"
#include "feature/dirparse/signing.h"
#include "feature/hibernate/hibernate.h"
#include "feature/keymgt/loadkey.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nickname.h"
#include "feature/nodelist/nodefamily.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/torcert.h"
#include "feature/relay/dns.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/relay_find_addr.h"
#include "feature/relay/relay_periodic.h"
#include "feature/relay/router.h"
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
#include "lib/geoip/geoip.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/encoding/confline.h"
#include "lib/osinfo/uname.h"
#include "lib/tls/tortls.h"
#include "lib/version/torversion.h"
#include "feature/dirauth/authmode.h"
#include "app/config/or_state_st.h"
#include "core/or/port_cfg_st.h"
#include "feature/dirclient/dir_server_st.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/extrainfo_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerstatus_st.h"
* \brief Miscellaneous relay functionality, including RSA key maintenance,
* generating and uploading server descriptors, picking an address to
* advertise, and so on.
*
* This module handles the job of deciding whether we are a Tor relay, and if
* so what kind. (Mostly through functions like server_mode() that inspect an
* or_options_t, but in some cases based on our own capabilities, such as when
* we are deciding whether to be a directory cache in
* router_has_bandwidth_to_be_dirserver().)
*
* Also in this module are the functions to generate our own routerinfo_t and
* extrainfo_t, and to encode those to signed strings for upload to the
* directory authorities.
*
* This module also handles key maintenance for RSA and Curve25519-ntor keys,
* and for our TLS context. (These functions should eventually move to
* routerkeys.c along with the code that handles Ed25519 keys now.)
/************************************************************/
/** 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. */
/** Previous private onionskin decryption key: used to decode CREATE cells
* generated by clients that have an older version of our descriptor. */
static crypto_pk_t *lastonionkey=NULL;
/** Current private ntor secret key: used to perform the ntor handshake. */
static curve25519_keypair_t curve25519_onion_key;
/** Previous private ntor secret key: used to perform the ntor handshake
* with clients that have an older version of our descriptor. */
static curve25519_keypair_t last_curve25519_onion_key;
/** Private server "identity key": used to sign directory info and TLS
* certificates. Never changes. */
static crypto_pk_t *server_identitykey=NULL;
/** Digest of server_identitykey. */
static char server_identitykey_digest[DIGEST_LEN];
/** Private client "identity key": used to sign bridges' and clients'
* outbound TLS certificates. Regenerated on startup and on IP address
* change. */
static crypto_pk_t *client_identitykey=NULL;
/** Signing key used for v3 directory material; only set for authorities. */
static crypto_pk_t *authority_signing_key = NULL;
/** Key certificate to authenticate v3 directory material; only set for
* authorities. */
static authority_cert_t *authority_key_certificate = NULL;
/** For emergency V3 authority key migration: An extra signing key that we use
* with our old (obsolete) identity key for a while. */
static crypto_pk_t *legacy_signing_key = NULL;
/** For emergency V3 authority key migration: An extra certificate to
* authenticate legacy_signing_key with our obsolete identity key.*/
static authority_cert_t *legacy_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. */
/** Indicate if the IPv6 address should be omitted from the descriptor when
* publishing it. This can happen if the IPv4 is reachable but the
* auto-discovered IPv6 is not. We still publish the descriptor.
*
* Only relays should look at this and only for their descriptor.
*
* XXX: The real harder fix is to never put in the routerinfo_t a non
* reachable address and instead use the last resolved address cache to do
* reachability test or anything that has to do with what address tor thinks
* it has. */
static bool omit_ipv6_on_publish = false;
/** Return a readonly string with human readable description
* of <b>err</b>.
*/
const char *
{
switch (err) {
case TOR_ROUTERINFO_ERROR_NO_EXT_ADDR:
return "No known exit address yet";
case TOR_ROUTERINFO_ERROR_CANNOT_PARSE:
return "Cannot parse descriptor";
case TOR_ROUTERINFO_ERROR_NOT_A_SERVER:
return "Not running in server mode";
case TOR_ROUTERINFO_ERROR_DIGEST_FAILED:
return "Key digest failed";
case TOR_ROUTERINFO_ERROR_CANNOT_GENERATE:
return "Cannot generate descriptor";
case TOR_ROUTERINFO_ERROR_DESC_REBUILDING:
return "Descriptor still rebuilding - not ready yet";
case TOR_ROUTERINFO_ERROR_INTERNAL_BUG:
return "Internal bug, see logs for details";
log_warn(LD_BUG, "unknown routerinfo error %d - shouldn't happen", err);
tor_assert_unreached();
return "Unknown error";
}
/** Return true if we expect given error to be transient.
* Return false otherwise.
*/
int
routerinfo_err_is_transient(int err)
{
/**
* For simplicity, we consider all errors other than
* "not a server" transient - see discussion on
* https://bugs.torproject.org/tpo/core/tor/27034.
*/
return err != TOR_ROUTERINFO_ERROR_NOT_A_SERVER;
/** Replace the current onion key with <b>k</b>. Does not affect
* lastonionkey; to update lastonionkey correctly, call rotate_onion_key().

Nick Mathewson
committed
{
if (onionkey && crypto_pk_eq_keys(onionkey, k)) {
/* k is already our onion key; free it and return */
return;
}
tor_mutex_acquire(key_lock);
onionkey = k;
tor_mutex_release(key_lock);
mark_my_descriptor_dirty("set onion key");
/** Return the current onion key. Requires that the onion key has been
MOCK_IMPL(crypto_pk_t *,
get_onion_key,(void))

Nick Mathewson
committed
{
return onionkey;
}
/** Store a full copy of the current onion key into *<b>key</b>, and a full
* copy of the most recent onion key into *<b>last</b>. Store NULL into
* a pointer if the corresponding key does not exist.
*/

Nick Mathewson
committed
void
dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last)
tor_assert(key);
tor_assert(last);
tor_mutex_acquire(key_lock);
if (onionkey)
*key = crypto_pk_copy_full(onionkey);
else
if (lastonionkey)
*last = crypto_pk_copy_full(lastonionkey);
else
*last = NULL;
tor_mutex_release(key_lock);
}
/** Expire our old set of onion keys. This is done by setting
* last_curve25519_onion_key and lastonionkey to all zero's and NULL
* respectively.
*
* This function does not perform any grace period checks for the old onion
* keys.
*/
void
expire_old_onion_keys(void)
{
char *fname = NULL;
tor_mutex_acquire(key_lock);
/* Free lastonionkey and set it to NULL. */
if (lastonionkey) {
crypto_pk_free(lastonionkey);
lastonionkey = NULL;
}
/* We zero out the keypair. See the fast_mem_is_zero() check made in
* construct_ntor_key_map() below. */
memset(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key));
tor_mutex_release(key_lock);
fname = get_keydir_fname("secret_onion_key.old");
if (file_status(fname) == FN_FILE) {
if (tor_unlink(fname) != 0) {
log_warn(LD_FS, "Couldn't unlink old onion key file %s: %s",
fname, strerror(errno));
}
}
tor_free(fname);
fname = get_keydir_fname("secret_onion_key_ntor.old");
if (file_status(fname) == FN_FILE) {
if (tor_unlink(fname) != 0) {
log_warn(LD_FS, "Couldn't unlink old ntor onion key file %s: %s",
fname, strerror(errno));
}
}
tor_free(fname);
}
/** Return the current secret onion key for the ntor handshake. Must only
* be called from the main thread. */
MOCK_IMPL(STATIC const struct curve25519_keypair_t *,
get_current_curve25519_keypair,(void))
{
return &curve25519_onion_key;
}
/** Return a map from KEYID (the key itself) to keypairs for use in the ntor
* handshake. Must only be called from the main thread. */
di_digest256_map_t *
construct_ntor_key_map(void)
{
di_digest256_map_t *m = NULL;
const uint8_t *cur_pk = curve25519_onion_key.pubkey.public_key;
const uint8_t *last_pk = last_curve25519_onion_key.pubkey.public_key;
if (!fast_mem_is_zero((const char *)cur_pk, CURVE25519_PUBKEY_LEN)) {
dimap_add_entry(&m, cur_pk,
tor_memdup(&curve25519_onion_key,
sizeof(curve25519_keypair_t)));
}
if (!fast_mem_is_zero((const char*)last_pk, CURVE25519_PUBKEY_LEN) &&
tor_memneq(cur_pk, last_pk, CURVE25519_PUBKEY_LEN)) {
dimap_add_entry(&m, last_pk,
tor_memdup(&last_curve25519_onion_key,
sizeof(curve25519_keypair_t)));
}
return m;
}
/** Helper used to deallocate a di_digest256_map_t returned by
* construct_ntor_key_map. */
static void
ntor_key_map_free_helper(void *arg)
{
curve25519_keypair_t *k = arg;
memwipe(k, 0, sizeof(*k));
tor_free(k);
}
/** Release all storage from a keymap returned by construct_ntor_key_map. */
void
ntor_key_map_free_(di_digest256_map_t *map)
{
dimap_free(map, ntor_key_map_free_helper);
}
/** 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.
*/

Nick Mathewson
committed
time_t
get_onion_key_set_at(void)
{
/** Set the current server identity key to <b>k</b>.

Nick Mathewson
committed
void
set_server_identity_key(crypto_pk_t *k)

Nick Mathewson
committed
{
server_identitykey = k;
if (crypto_pk_get_digest(server_identitykey,
server_identitykey_digest) < 0) {
log_err(LD_BUG, "Couldn't compute our own identity key digest.");
tor_assert(0);
}
#ifdef TOR_UNIT_TESTS
/** Testing only -- set the server's RSA identity digest to
* be <b>digest</b> */
void
set_server_identity_key_digest_testing(const uint8_t *digest)
{
memcpy(server_identitykey_digest, digest, DIGEST_LEN);
}
/** Make sure that we have set up our identity keys to match or not match as
* appropriate, and die with an assertion if we have not. */
static void
assert_identity_keys_ok(void)
{
tor_assert(client_identitykey);
if (public_server_mode(get_options())) {
/* assert that we have set the client and server keys to be equal */
tor_assert(server_identitykey);
tor_assert(crypto_pk_eq_keys(client_identitykey, server_identitykey));
} else {
/* assert that we have set the client and server keys to be unequal */
if (server_identitykey)
tor_assert(!crypto_pk_eq_keys(client_identitykey, server_identitykey));
#ifdef HAVE_MODULE_RELAY
/** Returns the current server identity key; requires that the key has
* been set, and that we are running as a Tor server.
MOCK_IMPL(crypto_pk_t *,
get_server_identity_key,(void))

Nick Mathewson
committed
{
tor_assert(server_identitykey);
tor_assert(server_mode(get_options()) ||
get_options()->command == CMD_KEY_EXPIRATION);
assert_identity_keys_ok();
return server_identitykey;
/** Return true iff we are a server and the server identity key
* has been set. */

Nick Mathewson
committed
int
server_identity_key_is_set(void)

Nick Mathewson
committed
{
return (server_mode(get_options()) ||
get_options()->command == CMD_KEY_EXPIRATION) &&
server_identitykey != NULL;
}
/** Set the current client identity key to <b>k</b>.
*/
void
set_client_identity_key(crypto_pk_t *k)

Nick Mathewson
committed
{
client_identitykey = k;
}
/** Returns the current client identity key for use on outgoing TLS
* connections; requires that the key has been set.
get_tlsclient_identity_key(void)
{
tor_assert(client_identitykey);
assert_identity_keys_ok();
return client_identitykey;
}
/** Return true iff the client identity key has been set. */
int
client_identity_key_is_set(void)
{
return client_identitykey != NULL;
/** Return the key certificate for this v3 (voting) authority, or NULL
* if we have no such certificate. */
MOCK_IMPL(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. */
get_my_v3_authority_signing_key(void)
{
return authority_signing_key;
}
/** If we're an authority, and we're using a legacy authority identity key for
* emergency migration purposes, return the certificate associated with that
* key. */
authority_cert_t *
get_my_v3_legacy_cert(void)
{
return legacy_key_certificate;
}
/** If we're an authority, and we're using a legacy authority identity key for
* emergency migration purposes, return that key. */
get_my_v3_legacy_signing_key(void)
{
return legacy_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.

Nick Mathewson
committed
void
rotate_onion_key(void)
char *fname, *fname_prev;
crypto_pk_t *prkey = NULL;
or_state_t *state = get_or_state();
curve25519_keypair_t new_curve25519_keypair;
fname = get_keydir_fname("secret_onion_key");
fname_prev = get_keydir_fname("secret_onion_key.old");
/* There isn't much point replacing an old key with an empty file */
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
goto error;
}
log_err(LD_GENERAL,"Error constructing rotated onion key");
if (crypto_pk_generate_key(prkey)) {
log_err(LD_BUG,"Error generating onion key");
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;
}
tor_free(fname);
tor_free(fname_prev);
fname = get_keydir_fname("secret_onion_key_ntor");
fname_prev = get_keydir_fname("secret_onion_key_ntor.old");
if (curve25519_keypair_generate(&new_curve25519_keypair, 1) < 0)
goto error;
/* There isn't much point replacing an old key with an empty file */

Nick Mathewson
committed
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
goto error;
}
if (curve25519_keypair_write_to_file(&new_curve25519_keypair, fname,
"onion") < 0) {
log_err(LD_FS,"Couldn't write curve25519 onion key to \"%s\".",fname);
log_info(LD_GENERAL, "Rotating onion key");
tor_mutex_acquire(key_lock);

Nick Mathewson
committed
onionkey = prkey;
memcpy(&last_curve25519_onion_key, &curve25519_onion_key,
sizeof(curve25519_keypair_t));
memcpy(&curve25519_onion_key, &new_curve25519_keypair,
sizeof(curve25519_keypair_t));
now = time(NULL);
state->LastRotatedOnionKey = onionkey_set_at = now;
tor_mutex_release(key_lock);
mark_my_descriptor_dirty("rotated onion key");
or_state_mark_dirty(state, get_options()->AvoidDiskWrites ? now+3600 : 0);
log_warn(LD_GENERAL, "Couldn't rotate onion key.");
if (prkey)
memwipe(&new_curve25519_keypair, 0, sizeof(new_curve25519_keypair));
tor_free(fname);
tor_free(fname_prev);
/** Log greeting message that points to new relay lifecycle document the
* first time this function has been called.
*/
static void
log_new_relay_greeting(void)
{
static int already_logged = 0;
if (already_logged)
return;
tor_log(LOG_NOTICE, LD_GENERAL, "You are running a new relay. "
"Thanks for helping the Tor network! If you wish to know "
"what will happen in the upcoming weeks regarding its usage, "
"have a look at https://blog.torproject.org/lifecycle-of-a"
"-new-relay");
already_logged = 1;
}
/** Load a curve25519 keypair from the file <b>fname</b>, writing it into
* <b>keys_out</b>. If the file isn't found, or is empty, and <b>generate</b>
* is true, create a new keypair and write it into the file. If there are
* errors, log them at level <b>severity</b>. Generate files using <b>tag</b>
* in their ASCII wrapper. */
static int
init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
const char *fname,
int generate,
int severity,
const char *tag)
{
switch (file_status(fname)) {
case FN_DIR:
case FN_ERROR:
tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname);
goto error;
/* treat empty key files as if the file doesn't exist, and, if generate
* is set, replace the empty file in curve25519_keypair_write_to_file() */
case FN_NOENT:
if (generate) {
if (!have_lockfile()) {
if (try_locking(get_options(), 0)<0) {
/* Make sure that --list-fingerprint only creates new keys
* if there is no possibility for a deadlock. */
tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". "
"Not writing any new keys.", fname);
/*XXXX The 'other process' might make a key in a second or two;
* maybe we should wait for it. */
goto error;
}
}
log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.",
fname);
if (curve25519_keypair_generate(keys_out, 1) < 0)
goto error;
if (curve25519_keypair_write_to_file(keys_out, fname, tag)<0) {
"Couldn't write generated key to \"%s\".", fname);
memwipe(keys_out, 0, sizeof(*keys_out));
goto error;
}
} else {
log_info(LD_GENERAL, "No key found in \"%s\"", fname);
}
return 0;
case FN_FILE:
{
char *tag_in=NULL;
if (curve25519_keypair_read_from_file(keys_out, &tag_in, fname) < 0) {
tor_log(severity, LD_GENERAL,"Error loading private key.");
tor_free(tag_in);
goto error;
}
if (!tag_in || strcmp(tag_in, tag)) {
tor_log(severity, LD_GENERAL,"Unexpected tag %s on private key.",
escaped(tag_in));
tor_free(tag_in);
goto error;
}
tor_free(tag_in);
return 0;
}
default:
tor_assert(0);
}
error:
return -1;
}
/** Try to load the vote-signing private key and certificate for being a v3
* directory authority, and make sure they match. If <b>legacy</b>, load a
* legacy key/cert set for emergency key migration; otherwise load the regular
* key/cert set. On success, store them into *<b>key_out</b> and
* *<b>cert_out</b> respectively, and return 0. On failure, return -1. */
load_authority_keyset(int legacy, crypto_pk_t **key_out,
authority_cert_t **cert_out)
char *fname = NULL, *cert = NULL;
const char *eos = NULL;
authority_cert_t *parsed = NULL;
legacy ? "legacy_signing_key" : "authority_signing_key");
signing_key = init_key_from_file(fname, 0, LOG_ERR, NULL);
if (!signing_key) {
log_warn(LD_DIR, "No version 3 directory key found in %s", fname);
goto done;
}
legacy ? "legacy_certificate" : "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, strlen(cert), &eos);
if (!parsed) {
log_warn(LD_DIR, "Unable to parse certificate in %s", fname);
goto done;
}
if (!crypto_pk_eq_keys(signing_key, parsed->signing_key)) {
log_warn(LD_DIR, "Stored signing key does not match signing key in "
"certificate");
goto done;
}
authority_cert_free(*cert_out);
*key_out = signing_key;
*cert_out = parsed;
r = 0;
done:
tor_free(fname);
tor_free(cert);
authority_cert_free(parsed);
/** 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)
{
if (load_authority_keyset(0, &authority_signing_key,
&authority_key_certificate)<0)
return -1;
if (get_options()->V3AuthUseLegacyKey &&
load_authority_keyset(1, &legacy_signing_key,
&legacy_key_certificate)<0)
return -1;
return 0;
}
/** 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) {
tor_log(badness, LD_DIR, "Your v3 authority certificate has expired."
} else if (time_left <= 24*60*60) {
tor_log(badness, LD_DIR, "Your v3 authority certificate expires in %d "
"hours; Generate a new one NOW.", time_left/(60*60));
tor_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;
}
/** Get the lifetime of an onion key in days. This value is defined by the
* network consensus parameter "onion-key-rotation-days". Always returns a
* value between <b>MIN_ONION_KEY_LIFETIME_DAYS</b> and
* <b>MAX_ONION_KEY_LIFETIME_DAYS</b>.
*/
static int
get_onion_key_rotation_days_(void)
{
return networkstatus_get_param(NULL,
"onion-key-rotation-days",
DEFAULT_ONION_KEY_LIFETIME_DAYS,
MIN_ONION_KEY_LIFETIME_DAYS,
MAX_ONION_KEY_LIFETIME_DAYS);
}
/** Get the current lifetime of an onion key in seconds. This value is defined
* by the network consensus parameter "onion-key-rotation-days", but the value
* is converted to seconds.
*/
int
get_onion_key_lifetime(void)
{
return get_onion_key_rotation_days_()*24*60*60;
}
/** Get the grace period of an onion key in seconds. This value is defined by
* the network consensus parameter "onion-key-grace-period-days", but the value
* is converted to seconds.
*/
int
get_onion_key_grace_period(void)
{
int grace_period;
grace_period = networkstatus_get_param(NULL,
"onion-key-grace-period-days",
DEFAULT_ONION_KEY_GRACE_PERIOD_DAYS,
MIN_ONION_KEY_GRACE_PERIOD_DAYS,
get_onion_key_rotation_days_());
return grace_period*24*60*60;
}
/** Set up Tor's TLS contexts, based on our configuration and keys. Return 0
* on success, and -1 on failure. */
int
router_initialize_tls_context(void)
{
unsigned int flags = 0;
const or_options_t *options = get_options();
if (public_server_mode(options))
flags |= TOR_TLS_CTX_IS_PUBLIC_SERVER;
if (!lifetime) { /* we should guess a good ssl cert lifetime */
/* choose between 5 and 365 days, and round to the day */
unsigned int five_days = 5*24*3600;
unsigned int one_year = 365*24*3600;
lifetime = crypto_rand_int_range(five_days, one_year);
lifetime -= lifetime % (24*3600);
if (crypto_rand_int(2)) {
/* Half the time we expire at midnight, and half the time we expire
* one second before midnight. (Some CAs wobble their expiry times a
* bit in practice, perhaps to reduce collision attacks; see ticket
* 8443 for details about observed certs in the wild.) */
lifetime--;
}
/* It's ok to pass lifetime in as an unsigned int, since
* config_parse_interval() checked it. */
return tor_tls_context_init(flags,
get_tlsclient_identity_key(),
get_server_identity_key() : NULL,

Alexander Hansen Færøy
committed
/** Announce URL to bridge status page. */
STATIC void
router_announce_bridge_status_page(void)
{
char fingerprint[FINGERPRINT_LEN + 1];
if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(),
fingerprint) < 0) {
// LCOV_EXCL_START
log_err(LD_GENERAL, "Unable to compute bridge fingerprint");
return;
// LCOV_EXCL_STOP
}
log_notice(LD_GENERAL, "You can check the status of your bridge relay at "
"https://bridges.torproject.org/status?id=%s",
fingerprint);
}
/** Compute fingerprint (or hashed fingerprint if hashed is 1) and write
* it to 'fingerprint' (or 'hashed-fingerprint'). Return 0 on success, or
* -1 if Tor should die,
*/
router_write_fingerprint(int hashed, int ed25519_identity)
const char *fname = hashed ? "hashed-fingerprint" :
(ed25519_identity ? "fingerprint-ed25519" :
"fingerprint");
char fingerprint[FINGERPRINT_LEN+1];
const or_options_t *options = get_options();
char *fingerprint_line = NULL;
int result = -1;
keydir = get_datadir_fname(fname);
log_info(LD_GENERAL,"Dumping %s%s to \"%s\"...", hashed ? "hashed " : "",
ed25519_identity ? "ed25519 identity" : "fingerprint", keydir);
if (ed25519_identity) { /* ed25519 identity */
digest256_to_base64(fingerprint, (const char *)
get_master_identity_key()->pubkey);
} else { /* RSA identity */
if (!hashed) {
if (crypto_pk_get_fingerprint(get_server_identity_key(),
fingerprint, 0) < 0) {
log_err(LD_GENERAL,"Error computing fingerprint");
goto done;
}
} else {
if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(),
fingerprint) < 0) {
log_err(LD_GENERAL,"Error computing hashed fingerprint");
goto done;
}
tor_asprintf(&fingerprint_line, "%s %s\n", options->Nickname, fingerprint);
/* Check whether we need to write the (hashed-)fingerprint file. */
if (write_str_to_file_if_not_equal(keydir, fingerprint_line)) {
log_err(LD_FS, "Error writing %s%s line to file",
hashed ? "hashed " : "",
ed25519_identity ? "ed25519 identity" : "fingerprint");
goto done;
log_notice(LD_GENERAL, "Your Tor %s identity key %sfingerprint is '%s %s'",
hashed ? "bridge's hashed" : "server's",
ed25519_identity ? "ed25519 " : "",
options->Nickname, fingerprint);
result = 0;
done:
tor_free(keydir);
tor_free(fingerprint_line);
return result;
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
static int
init_keys_common(void)
{
if (!key_lock)
key_lock = tor_mutex_new();
return 0;
}
int
init_keys_client(void)
{
crypto_pk_t *prkey;
if (init_keys_common() < 0)
return -1;
if (!(prkey = crypto_pk_new()))
return -1;
if (crypto_pk_generate_key(prkey)) {
crypto_pk_free(prkey);
return -1;
}
set_client_identity_key(prkey);
/* Create a TLS context. */
if (router_initialize_tls_context() < 0) {
log_err(LD_GENERAL,"Error creating TLS context for Tor client.");
return -1;
}
return 0;
}
/** 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.

Nick Mathewson
committed
int
init_keys(void)
{
char *keydir;
const char *mydesc;
char digest[DIGEST_LEN];
char v3_digest[DIGEST_LEN];
const or_options_t *options = get_options();
dirinfo_type_t type;
time_t now = time(NULL);
dir_server_t *ds;
int v3_digest_set = 0;
authority_cert_t *cert = NULL;
/* OP's don't need persistent keys; just make up an identity and
* initialize the TLS context. */
if (!server_mode(options) && !(options->command == CMD_KEY_EXPIRATION)) {
return init_keys_client();
if (init_keys_common() < 0)
return -1;
if (create_keys_directory(options) < 0)
return -1;
/* 1a. Read v3 directory authority key/cert information. */
memset(v3_digest, 0, sizeof(v3_digest));
if (authdir_mode_v3(options)) {
if (init_v3_authority_keys()<0) {
log_err(LD_GENERAL, "We're configured as a V3 authority, but we "
"were unable to load our v3 authority keys and certificate! "
"Use tor-gencert to generate them. Dying.");
return -1;
}
cert = get_my_v3_authority_cert();
if (cert) {
if (crypto_pk_get_digest(get_my_v3_authority_cert()->identity_key,
v3_digest) < 0) {
log_err(LD_BUG, "Couldn't compute my v3 authority identity key "