aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/or/dirserv.c3
-rw-r--r--src/or/dirvote.c9
-rw-r--r--src/or/dirvote.h6
-rw-r--r--src/or/microdesc.c1
-rw-r--r--src/or/or.h5
-rw-r--r--src/or/router.c212
-rw-r--r--src/or/router.h5
-rw-r--r--src/or/routerlist.c1
-rw-r--r--src/or/routerparse.c34
9 files changed, 270 insertions, 6 deletions
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index c1ddf73ee..de4d63fa1 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -74,7 +74,8 @@ static const struct consensus_method_range_t {
} microdesc_consensus_methods[] = {
{MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1},
{MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1},
- {MIN_METHOD_FOR_P6_LINES, MAX_SUPPORTED_CONSENSUS_METHOD},
+ {MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
+ {MIN_METHOD_FOR_NTOR_KEY, MAX_SUPPORTED_CONSENSUS_METHOD},
{-1, -1}
};
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 836349375..6236d2a02 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -3554,6 +3554,15 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
smartlist_add_asprintf(chunks, "onion-key\n%s", key);
+ if (consensus_method >= MIN_METHOD_FOR_NTOR_KEY &&
+ ri->onion_curve25519_pkey) {
+ char kbuf[128];
+ base64_encode(kbuf, sizeof(kbuf),
+ (const char*)ri->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
+ smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
+ }
+
if (consensus_method >= MIN_METHOD_FOR_A_LINES &&
!tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport)
smartlist_add_asprintf(chunks, "a %s\n",
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index d14a37516..19444c370 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -20,7 +20,7 @@
#define MIN_VOTE_INTERVAL 300
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 15
+#define MAX_SUPPORTED_CONSENSUS_METHOD 16
/** Lowest consensus method that contains a 'directory-footer' marker */
#define MIN_METHOD_FOR_FOOTER 9
@@ -48,6 +48,10 @@
/** Lowest consensus method where microdescs may include a "p6" line. */
#define MIN_METHOD_FOR_P6_LINES 15
+/** Lowest consensus method where microdescs may include an onion-key-ntor
+ * line */
+#define MIN_METHOD_FOR_NTOR_KEY 16
+
void dirvote_free_all(void);
/* vote manipulation */
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index 7602a9345..93cf3edbd 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -575,6 +575,7 @@ microdesc_free(microdesc_t *md)
if (md->onion_pkey)
crypto_pk_free(md->onion_pkey);
+ tor_free(md->onion_curve25519_pkey);
if (md->body && md->saved_location != SAVED_IN_CACHE)
tor_free(md->body);
diff --git a/src/or/or.h b/src/or/or.h
index 2ac9f6bde..219336bf7 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -99,6 +99,7 @@
#include "compat_libevent.h"
#include "ht.h"
#include "replaycache.h"
+#include "crypto_curve25519.h"
/* These signals are defined to help handle_control_signal work.
*/
@@ -1893,6 +1894,8 @@ typedef struct {
crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */
crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */
+ /** Public curve25519 key for onions */
+ curve25519_public_key_t *onion_curve25519_pkey;
char *platform; /**< What software/operating system is this OR using? */
@@ -2106,6 +2109,8 @@ typedef struct microdesc_t {
/** As routerinfo_t.onion_pkey */
crypto_pk_t *onion_pkey;
+ /** As routerinfo_t.onion_curve25519_pkey */
+ curve25519_public_key_t *onion_curve25519_pkey;
/** As routerinfo_t.ipv6_add */
tor_addr_t ipv6_addr;
/** As routerinfo_t.ipv6_orport */
diff --git a/src/or/router.c b/src/or/router.c
index d5ffb36fd..954304dd2 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);
diff --git a/src/or/router.h b/src/or/router.h
index b641c1cc6..85c7d351d 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -30,6 +30,11 @@ crypto_pk_t *init_key_from_file(const char *fname, int generate,
int severity);
void v3_authority_check_key_expiry(void);
+#ifdef CURVE25519_ENABLED
+di_digest256_map_t *construct_ntor_key_map(void);
+void ntor_key_map_free(di_digest256_map_t *map);
+#endif
+
int router_initialize_tls_context(void);
int init_keys(void);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 173583787..0508e4174 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -2395,6 +2395,7 @@ routerinfo_free(routerinfo_t *router)
tor_free(router->contact_info);
if (router->onion_pkey)
crypto_pk_free(router->onion_pkey);
+ tor_free(router->onion_curve25519_pkey);
if (router->identity_pkey)
crypto_pk_free(router->identity_pkey);
if (router->declared_family) {
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 0ab99a09c..17902d9d0 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -43,6 +43,7 @@ typedef enum {
K_SIGNED_DIRECTORY,
K_SIGNING_KEY,
K_ONION_KEY,
+ K_ONION_KEY_NTOR,
K_ROUTER_SIGNATURE,
K_PUBLISHED,
K_RUNNING_ROUTERS,
@@ -276,6 +277,7 @@ static token_rule_t routerdesc_token_table[] = {
T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ),
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
+ T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T01("uptime", K_UPTIME, GE(1), NO_OBJ ),
@@ -527,6 +529,7 @@ static token_rule_t networkstatus_detached_signature_token_table[] = {
/** List of tokens recognized in microdescriptors */
static token_rule_t microdesc_token_table[] = {
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
+ T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
T0N("a", K_A, GE(1), NO_OBJ ),
T01("family", K_FAMILY, ARGS, NO_OBJ ),
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
@@ -1516,6 +1519,21 @@ router_parse_entry_from_string(const char *s, const char *end,
router->onion_pkey = tok->key;
tok->key = NULL; /* Prevent free */
+ if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
+ uint8_t k[CURVE25519_PUBKEY_LEN+32];
+ int r;
+ tor_assert(tok->n_args >= 1);
+ r = base64_decode((char*)k, sizeof(k), tok->args[0], strlen(tok->args[0]));
+ if (r != CURVE25519_PUBKEY_LEN) {
+ log_warn(LD_DIR, "Bogus onion-key-ntor in routerinfo");
+ goto err;
+ }
+ router->onion_curve25519_pkey =
+ tor_malloc(sizeof(curve25519_public_key_t));
+ memcpy(router->onion_curve25519_pkey->public_key,
+ k, CURVE25519_PUBKEY_LEN);
+ }
+
tok = find_by_keyword(tokens, K_SIGNING_KEY);
router->identity_pkey = tok->key;
tok->key = NULL; /* Prevent free */
@@ -4475,6 +4493,22 @@ microdescs_parse_from_string(const char *s, const char *eos,
md->onion_pkey = tok->key;
tok->key = NULL;
+ if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
+ uint8_t k[CURVE25519_PUBKEY_LEN+32];
+ int r;
+ tor_assert(tok->n_args >= 1);
+ r = base64_decode((char*)k, sizeof(k),
+ tok->args[0], strlen(tok->args[0]));
+ if (r != CURVE25519_PUBKEY_LEN) {
+ log_warn(LD_DIR, "Bogus onion-key-ntor in microdesc");
+ goto next;
+ }
+ md->onion_curve25519_pkey =
+ tor_malloc(sizeof(curve25519_public_key_t));
+ memcpy(md->onion_curve25519_pkey->public_key,
+ k, CURVE25519_PUBKEY_LEN);
+ }
+
{
smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
if (a_lines) {