summaryrefslogtreecommitdiff
path: root/src/or/router.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/router.c')
-rw-r--r--src/or/router.c212
1 files changed, 208 insertions, 4 deletions
diff --git a/src/or/router.c b/src/or/router.c
index d5ffb36fd2..954304dd26 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -13,6 +13,7 @@
#include "config.h"
#include "connection.h"
#include "control.h"
+#include "crypto_curve25519.h"
#include "directory.h"
#include "dirserv.h"
#include "dns.h"
@@ -54,6 +55,11 @@ static crypto_pk_t *onionkey=NULL;
/** 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;
+#ifdef CURVE25519_ENABLED
+/**DOCDOC*/
+static curve25519_keypair_t curve25519_onion_key;
+static curve25519_keypair_t last_curve25519_onion_key;
+#endif
/** Private server "identity key": used to sign directory info and TLS
* certificates. Never changes. */
static crypto_pk_t *server_identitykey=NULL;
@@ -99,6 +105,20 @@ set_onion_key(crypto_pk_t *k)
mark_my_descriptor_dirty("set onion key");
}
+#if 0
+/**DOCDOC*/
+static void
+set_curve25519_onion_key(const curve25519_keypair_t *kp)
+{
+ if (tor_memeq(&curve25519_onion_key, kp, sizeof(curve25519_keypair_t)))
+ return;
+
+ tor_mutex_acquire(key_lock);
+ memcpy(&curve25519_onion_key, kp, sizeof(curve25519_keypair_t));
+ tor_mutex_release(key_lock);
+}
+#endif
+
/** Return the current onion key. Requires that the onion key has been
* loaded or generated. */
crypto_pk_t *
@@ -126,6 +146,47 @@ dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last)
tor_mutex_release(key_lock);
}
+#ifdef CURVE25519_ENABLED
+/**DOCDOC only in main thread*/
+static const curve25519_keypair_t *
+get_current_curve25519_keypair(void)
+{
+ return &curve25519_onion_key;
+}
+di_digest256_map_t *
+construct_ntor_key_map(void)
+{
+ di_digest256_map_t *m = NULL;
+
+ dimap_add_entry(&m,
+ curve25519_onion_key.pubkey.public_key,
+ tor_memdup(&curve25519_onion_key,
+ sizeof(curve25519_keypair_t)));
+ if (!tor_mem_is_zero((const char*)
+ last_curve25519_onion_key.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN)) {
+ dimap_add_entry(&m,
+ last_curve25519_onion_key.pubkey.public_key,
+ tor_memdup(&last_curve25519_onion_key,
+ sizeof(curve25519_keypair_t)));
+ }
+
+ return m;
+}
+static void
+ntor_key_map_free_helper(void *arg)
+{
+ curve25519_keypair_t *k = arg;
+ memwipe(k, 0, sizeof(*k));
+ tor_free(k);
+}
+void
+ntor_key_map_free(di_digest256_map_t *map)
+{
+ dimap_free(map, ntor_key_map_free_helper);
+}
+#endif
+
/** 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.
@@ -253,11 +314,18 @@ void
rotate_onion_key(void)
{
char *fname, *fname_prev;
- crypto_pk_t *prkey;
+ crypto_pk_t *prkey = NULL;
or_state_t *state = get_or_state();
+#ifdef CURVE25519_ENABLED
+ curve25519_keypair_t new_curve25519_keypair;
+#endif
time_t now;
fname = get_datadir_fname2("keys", "secret_onion_key");
fname_prev = get_datadir_fname2("keys", "secret_onion_key.old");
+ if (file_status(fname) == FN_FILE) {
+ if (replace_file(fname, fname_prev))
+ goto error;
+ }
if (!(prkey = crypto_pk_new())) {
log_err(LD_GENERAL,"Error constructing rotated onion key");
goto error;
@@ -266,19 +334,37 @@ rotate_onion_key(void)
log_err(LD_BUG,"Error generating onion key");
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;
+ }
+#ifdef CURVE25519_ENABLED
+ tor_free(fname);
+ tor_free(fname_prev);
+ fname = get_datadir_fname2("keys", "secret_onion_key_ntor");
+ fname_prev = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
+ curve25519_keypair_generate(&new_curve25519_keypair, 1);
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);
+ 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);
goto error;
}
+#endif
log_info(LD_GENERAL, "Rotating onion key");
tor_mutex_acquire(key_lock);
crypto_pk_free(lastonionkey);
lastonionkey = onionkey;
onionkey = prkey;
+#ifdef CURVE25519_ENABLED
+ memcpy(&last_curve25519_onion_key, &curve25519_onion_key,
+ sizeof(curve25519_keypair_t));
+ memcpy(&curve25519_onion_key, &new_curve25519_keypair,
+ sizeof(curve25519_keypair_t));
+#endif
now = time(NULL);
state->LastRotatedOnionKey = onionkey_set_at = now;
tor_mutex_release(key_lock);
@@ -290,6 +376,9 @@ rotate_onion_key(void)
if (prkey)
crypto_pk_free(prkey);
done:
+#ifdef CURVE25519_ENABLED
+ memwipe(&new_curve25519_keypair, 0, sizeof(new_curve25519_keypair));
+#endif
tor_free(fname);
tor_free(fname_prev);
}
@@ -363,6 +452,72 @@ init_key_from_file(const char *fname, int generate, int severity)
return NULL;
}
+#ifdef CURVE25519_ENABLED
+/** DOCDOC */
+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:
+ log(severity, LD_FS,"Can't read key from \"%s\"", fname);
+ goto error;
+ 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. */
+ 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);
+ curve25519_keypair_generate(keys_out, 1);
+ if (curve25519_keypair_write_to_file(keys_out, fname, tag)<0) {
+ log(severity, LD_FS,
+ "Couldn't write generated key to \"%s\".", fname);
+ memset(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) {
+ log(severity, LD_GENERAL,"Error loading private key.");
+ tor_free(tag_in);
+ goto error;
+ }
+ if (!tag_in || strcmp(tag_in, tag)) {
+ 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;
+}
+#endif
+
/** 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
@@ -630,12 +785,35 @@ init_keys(void)
keydir = get_datadir_fname2("keys", "secret_onion_key.old");
if (!lastonionkey && file_status(keydir) == FN_FILE) {
- prkey = init_key_from_file(keydir, 1, LOG_ERR);
+ prkey = init_key_from_file(keydir, 1, LOG_ERR); /* XXXX Why 1? */
if (prkey)
lastonionkey = prkey;
}
tor_free(keydir);
+#ifdef CURVE25519_ENABLED
+ {
+ /* 2b. Load curve25519 onion keys. */
+ int r;
+ keydir = get_datadir_fname2("keys", "secret_onion_key_ntor");
+ r = init_curve25519_keypair_from_file(&curve25519_onion_key,
+ keydir, 1, LOG_ERR, "onion");
+ tor_free(keydir);
+ if (r<0)
+ return -1;
+
+ keydir = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
+ if (tor_mem_is_zero((const char *)
+ last_curve25519_onion_key.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN) &&
+ file_status(keydir) == FN_FILE) {
+ init_curve25519_keypair_from_file(&last_curve25519_onion_key,
+ keydir, 0, LOG_ERR, "onion");
+ }
+ tor_free(keydir);
+ }
+#endif
+
/* 3. Initialize link key and TLS context. */
if (router_initialize_tls_context() < 0) {
log_err(LD_GENERAL,"Error initializing TLS context");
@@ -1566,6 +1744,11 @@ router_rebuild_descriptor(int force)
ri->cache_info.published_on = time(NULL);
ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
* main thread */
+#ifdef CURVE25519_ENABLED
+ ri->onion_curve25519_pkey =
+ tor_memdup(&get_current_curve25519_keypair()->pubkey,
+ sizeof(curve25519_public_key_t));
+#endif
/* For now, at most one IPv6 or-address is being advertised. */
{
@@ -2146,6 +2329,22 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
written += result;
}
+#ifdef CURVE25519_ENABLED
+ if (router->onion_curve25519_pkey) {
+ char kbuf[128];
+ base64_encode(kbuf, sizeof(kbuf),
+ (const char *)router->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
+ result = tor_snprintf(s+written,maxlen-written, "ntor-onion-key %s",
+ kbuf);
+ if (result<0) {
+ log_warn(LD_BUG,"descriptor snprintf ran out of room!");
+ return -1;
+ }
+ written += result;
+ }
+#endif
+
/* Write the exit policy to the end of 's'. */
if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
strlcat(s+written, "reject *:*\n", maxlen-written);
@@ -2794,6 +2993,11 @@ router_free_all(void)
crypto_pk_free(legacy_signing_key);
authority_cert_free(legacy_key_certificate);
+#ifdef CURVE25519_ENABLED
+ memwipe(&curve25519_onion_key, 0, sizeof(curve25519_onion_key));
+ memwipe(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key));
+#endif
+
if (warned_nonexistent_family) {
SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp));
smartlist_free(warned_nonexistent_family);