summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2008-05-12 02:14:15 +0000
committerNick Mathewson <nickm@torproject.org>2008-05-12 02:14:15 +0000
commitbefa56c72e612ac2cb234e7d924511645d6a0a93 (patch)
tree485329c9471430cfcb03cd4bd336d3ea9b57240b
parent89f452d07780864a6e16a2841bb748a121da02f5 (diff)
downloadtor-befa56c72e612ac2cb234e7d924511645d6a0a93.tar.gz
tor-befa56c72e612ac2cb234e7d924511645d6a0a93.zip
r19691@catbus: nickm | 2008-05-11 22:13:41 -0400
Backport: Implement a proposal to let a directory authority migrate its identity key without ceasing to sign consensuses. svn:r14585
-rw-r--r--ChangeLog6
-rw-r--r--configure.in2
-rw-r--r--contrib/tor-mingw.nsi.in2
-rw-r--r--src/or/config.c1
-rw-r--r--src/or/dirserv.c7
-rw-r--r--src/or/dirvote.c126
-rw-r--r--src/or/or.h7
-rw-r--r--src/or/router.c69
-rw-r--r--src/or/routerparse.c19
-rw-r--r--src/win32/orconfig.h2
10 files changed, 195 insertions, 46 deletions
diff --git a/ChangeLog b/ChangeLog
index a098b3e0a4..feab0f0930 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Changes in version 0.2.0.26-rc - 2008-05-??
+ o Minor features:
+ - Add a new V3AuthUseLegacyKey option to make it easier for authorities
+ to change their identity keys if they have to.
+
+
Changes in version 0.2.0.25-rc - 2008-04-23
Tor 0.2.0.25-rc makes Tor work again on OS X and certain BSDs.
diff --git a/configure.in b/configure.in
index 4967b1f4d7..b423e4cecb 100644
--- a/configure.in
+++ b/configure.in
@@ -5,7 +5,7 @@ dnl Copyright (c) 2007-2008, The Tor Project, Inc.
dnl See LICENSE for licensing information
AC_INIT
-AM_INIT_AUTOMAKE(tor, 0.2.0.25-rc)
+AM_INIT_AUTOMAKE(tor, 0.2.0.25-rc-dev)
AM_CONFIG_HEADER(orconfig.h)
AC_CANONICAL_HOST
diff --git a/contrib/tor-mingw.nsi.in b/contrib/tor-mingw.nsi.in
index 17032d5248..4d0548c786 100644
--- a/contrib/tor-mingw.nsi.in
+++ b/contrib/tor-mingw.nsi.in
@@ -9,7 +9,7 @@
!include "FileFunc.nsh"
!insertmacro GetParameters
-!define VERSION "0.2.0.25-rc"
+!define VERSION "0.2.0.25-rc-dev"
!define INSTALLER "tor-${VERSION}-win32.exe"
!define WEBSITE "https://www.torproject.org/"
!define LICENSE "LICENSE"
diff --git a/src/or/config.c b/src/or/config.c
index 5d69cadf1d..a413f91957 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -301,6 +301,7 @@ static config_var_t _option_vars[] = {
V(V3AuthVoteDelay, INTERVAL, "5 minutes"),
V(V3AuthDistDelay, INTERVAL, "5 minutes"),
V(V3AuthNIntervalsValid, UINT, "3"),
+ V(V3AuthUseLegacyKey, BOOL, "0"),
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
V(VirtualAddrNetwork, STRING, "127.192.0.0/10"),
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 81181f7741..b6a47411b2 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -2285,6 +2285,13 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
voter->or_port = options->ORPort;
voter->contact = tor_strdup(contact);
memcpy(voter->signing_key_digest, signing_key_digest, DIGEST_LEN);
+ if (options->V3AuthUseLegacyKey) {
+ authority_cert_t *c = get_my_v3_legacy_cert();
+ if (c) {
+ crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest);
+ }
+ }
+
v3_out->voters = smartlist_create();
smartlist_add(v3_out->voters, voter);
v3_out->cert = authority_cert_dup(cert);
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index e4afacc61d..683389341d 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -105,7 +105,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
tor_snprintf(status, len,
"network-status-version 3\n"
"vote-status vote\n"
- "consensus-methods 1 2\n"
+ "consensus-methods 1 2 3\n"
"published %s\n"
"valid-after %s\n"
"fresh-until %s\n"
@@ -125,6 +125,14 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
tor_free(flags);
outp = status + strlen(status);
endp = status + len;
+
+ if (!tor_digest_is_zero(voter->legacy_id_digest)) {
+ char fpbuf[HEX_DIGEST_LEN+1];
+ base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN);
+ tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf);
+ outp += strlen(outp);
+ }
+
tor_assert(outp + cert->cache_info.signed_descriptor_len < endp);
memcpy(outp, cert->cache_info.signed_descriptor_body,
cert->cache_info.signed_descriptor_len);
@@ -207,6 +215,12 @@ get_voter(const networkstatus_t *vote)
return smartlist_get(vote->voters, 0);
}
+typedef struct {
+ networkstatus_t *v;
+ const char *digest;
+ int is_legacy;
+} dir_src_ent_t;
+
/** Helper for sorting networkstatus_t votes (not consensuses) by the
* hash of their voters' identity digests. */
static int
@@ -217,6 +231,19 @@ _compare_votes_by_authority_id(const void **_a, const void **_b)
get_voter(b)->identity_digest, DIGEST_LEN);
}
+static int
+_compare_dir_src_ents_by_authority_id(const void **_a, const void **_b)
+{
+ const dir_src_ent_t *a = *_a, *b = *_b;
+ const networkstatus_voter_info_t *a_v = get_voter(a->v),
+ *b_v = get_voter(b->v);
+ const char *a_id, *b_id;
+ a_id = a->is_legacy ? a_v->legacy_id_digest : a_v->identity_digest;
+ b_id = b->is_legacy ? b_v->legacy_id_digest : b_v->identity_digest;
+
+ return memcmp(a_id, b_id, DIGEST_LEN);
+}
+
/** Given a sorted list of strings <b>in</b>, add every member to <b>out</b>
* that occurs more than <b>min</b> times. */
static void
@@ -416,7 +443,7 @@ compute_consensus_method(smartlist_t *votes)
static int
consensus_method_is_supported(int method)
{
- return (method >= 1) && (method <= 2);
+ return (method >= 1) && (method <= 3);
}
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
@@ -581,33 +608,64 @@ networkstatus_compute_consensus(smartlist_t *votes,
/* Sort the votes. */
smartlist_sort(votes, _compare_votes_by_authority_id);
/* Add the authority sections. */
- SMARTLIST_FOREACH(votes, networkstatus_t *, v,
{
- char buf[1024];
- struct in_addr in;
- char ip[INET_NTOA_BUF_LEN];
- char fingerprint[HEX_DIGEST_LEN+1];
- char votedigest[HEX_DIGEST_LEN+1];
- networkstatus_voter_info_t *voter = get_voter(v);
+ smartlist_t *dir_sources = smartlist_create();
+ SMARTLIST_FOREACH(votes, networkstatus_t *, v,
+ {
+ dir_src_ent_t *e = tor_malloc_zero(sizeof(dir_src_ent_t));
+ e->v = v;
+ e->digest = get_voter(v)->identity_digest;
+ e->is_legacy = 0;
+ smartlist_add(dir_sources, e);
+ if (consensus_method >= 3 &&
+ !tor_digest_is_zero(get_voter(v)->legacy_id_digest)) {
+ dir_src_ent_t *e_legacy = tor_malloc_zero(sizeof(dir_src_ent_t));
+ e_legacy->v = v;
+ e_legacy->digest = get_voter(v)->legacy_id_digest;
+ e_legacy->is_legacy = 1;
+ smartlist_add(dir_sources, e);
+ }
+ });
+ smartlist_sort(dir_sources, _compare_dir_src_ents_by_authority_id);
- in.s_addr = htonl(voter->addr);
- tor_inet_ntoa(&in, ip, sizeof(ip));
- base16_encode(fingerprint, sizeof(fingerprint), voter->identity_digest,
- DIGEST_LEN);
- base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
- DIGEST_LEN);
+ SMARTLIST_FOREACH(dir_sources, const dir_src_ent_t *, e,
+ {
+ char buf[1024];
+ struct in_addr in;
+ char ip[INET_NTOA_BUF_LEN];
+ char fingerprint[HEX_DIGEST_LEN+1];
+ char votedigest[HEX_DIGEST_LEN+1];
+ networkstatus_t *v = e->v;
+ networkstatus_voter_info_t *voter = get_voter(v);
+
+ if (e->is_legacy)
+ tor_assert(consensus_method >= 2);
+
+ in.s_addr = htonl(voter->addr);
+ tor_inet_ntoa(&in, ip, sizeof(ip));
+ base16_encode(fingerprint, sizeof(fingerprint), e->digest, DIGEST_LEN);
+ base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
+ DIGEST_LEN);
- tor_snprintf(buf, sizeof(buf),
- "dir-source %s %s %s %s %d %d\n"
- "contact %s\n"
- "vote-digest %s\n",
- voter->nickname, fingerprint, voter->address, ip,
- voter->dir_port,
- voter->or_port,
- voter->contact,
- votedigest);
- smartlist_add(chunks, tor_strdup(buf));
- });
+ tor_snprintf(buf, sizeof(buf),
+ "dir-source %s%s %s %s %s %d %d\n",
+ voter->nickname, e->is_legacy ? "-legacy" : "",
+ fingerprint, voter->address, ip,
+ voter->dir_port,
+ voter->or_port);
+ smartlist_add(chunks, tor_strdup(buf));
+ if (! e->is_legacy) {
+ tor_snprintf(buf, sizeof(buf),
+ "contact %s\n"
+ "vote-digest %s\n",
+ voter->contact,
+ votedigest);
+ smartlist_add(chunks, tor_strdup(buf));
+ }
+ });
+ SMARTLIST_FOREACH(dir_sources, dir_src_ent_t *, e, tor_free(e));
+ smartlist_free(dir_sources);
+ }
/* Add the actual router entries. */
{
@@ -904,6 +962,22 @@ networkstatus_compute_consensus(smartlist_t *votes,
return NULL; /* This leaks, but it should never happen. */
}
smartlist_add(chunks, tor_strdup(buf));
+
+ if (get_options()->V3AuthUseLegacyKey && consensus_method >= 3) {
+ crypto_pk_env_t *legacy_key = get_my_v3_legacy_signing_key();
+ authority_cert_t *legacy_cert = get_my_v3_legacy_cert();
+ smartlist_add(chunks, tor_strdup("directory-signature "));
+ crypto_pk_get_fingerprint(legacy_cert->identity_key, fingerprint, 0);
+ crypto_pk_get_fingerprint(legacy_key, signing_key_fingerprint, 0);
+ tor_snprintf(buf, sizeof(buf), "%s %s\n", fingerprint,
+ signing_key_fingerprint);
+ if (router_append_dirobj_signature(buf, sizeof(buf), digest,
+ signing_key)) {
+ log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
+ return NULL; /* This leaks, but it should never happen. */
+ }
+ smartlist_add(chunks, tor_strdup(buf));
+ }
}
result = smartlist_join_strings(chunks, "", 0, NULL);
diff --git a/src/or/or.h b/src/or/or.h
index 9c91a55fe9..bb19a144c3 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1452,6 +1452,7 @@ typedef struct networkstatus_voter_info_t {
uint16_t or_port; /**< OR port of this voter */
char *contact; /**< Contact information for this voter. */
char vote_digest[DIGEST_LEN]; /**< Digest of this voter's vote, as signed. */
+ char legacy_id_digest[DIGEST_LEN]; /**< From vote only. DOCDOC */
/* Nothing from here on is signed. */
char signing_key_digest[DIGEST_LEN]; /**< Declared digest of signing key
@@ -2330,6 +2331,10 @@ typedef struct {
/** The number of intervals we think a consensus should be valid. */
int V3AuthNIntervalsValid;
+ /** Should advertise and sign consensuses with a legacy key, for key
+ * migration purposes? */
+ int V3AuthUseLegacyKey;
+
/** File to check for a consensus networkstatus, if we don't have one
* cached. */
char *FallbackNetworkstatusFile;
@@ -3751,6 +3756,8 @@ crypto_pk_env_t *get_identity_key(void);
int identity_key_is_set(void);
authority_cert_t *get_my_v3_authority_cert(void);
crypto_pk_env_t *get_my_v3_authority_signing_key(void);
+authority_cert_t *get_my_v3_legacy_cert(void);
+crypto_pk_env_t *get_my_v3_legacy_signing_key(void);
void dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last);
void rotate_onion_key(void);
crypto_pk_env_t *init_key_from_file(const char *fname, int generate,
diff --git a/src/or/router.c b/src/or/router.c
index 91518141cf..6695989b1f 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -45,6 +45,9 @@ static crypto_pk_env_t *authority_signing_key = NULL;
* authorities. */
static authority_cert_t *authority_key_certificate = NULL;
+static crypto_pk_env_t *legacy_signing_key = NULL;
+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
@@ -144,6 +147,18 @@ get_my_v3_authority_signing_key(void)
return authority_signing_key;
}
+authority_cert_t *
+get_my_v3_legacy_cert(void)
+{
+ return legacy_key_certificate;
+}
+
+crypto_pk_env_t *
+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:
@@ -258,26 +273,26 @@ init_key_from_file(const char *fname, int generate, int severity)
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)
+load_authority_keyset(int legacy, crypto_pk_env_t **key_out,
+ authority_cert_t **cert_out)
{
+ int r = -1;
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");
+ fname = get_datadir_fname2("keys",
+ legacy ? "legacy_signing_key" : "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");
+ fname = get_datadir_fname2("keys",
+ 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",
@@ -298,18 +313,16 @@ init_v3_authority_keys(void)
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;
+ if (*key_out)
+ crypto_free_pk_env(*key_out);
+ if (*cert_out)
+ authority_cert_free(*cert_out);
+ *key_out = signing_key;
+ *cert_out = parsed;
+ r = 0;
signing_key = NULL;
+ parsed = NULL;
- r = 0;
done:
tor_free(fname);
tor_free(cert);
@@ -320,6 +333,24 @@ init_v3_authority_keys(void)
return r;
}
+/** 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(0, &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
@@ -1956,6 +1987,10 @@ router_free_all(void)
crypto_free_pk_env(authority_signing_key);
if (authority_key_certificate)
authority_cert_free(authority_key_certificate);
+ if (legacy_signing_key)
+ crypto_free_pk_env(legacy_signing_key);
+ if (legacy_key_certificate)
+ authority_cert_free(legacy_key_certificate);
if (warned_nonexistent_family) {
SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp));
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 31b10baf30..1520dc32fa 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -78,6 +78,7 @@ typedef enum {
K_CONSENSUS_DIGEST,
K_CONSENSUS_METHODS,
K_CONSENSUS_METHOD,
+ K_LEGACY_DIR_KEY,
A_PURPOSE,
_A_UNKNOWN,
@@ -358,6 +359,7 @@ static token_rule_t networkstatus_token_table[] = {
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
T1( "dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ),
+ T01("legacy-dir-key", K_LEGACY_DIR_KEY, GE(1), NO_OBJ ),
T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
@@ -2213,6 +2215,23 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
goto err;
}
+ if (is_vote &&
+ (tok = find_first_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
+ int bad = 1;
+ if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
+ networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
+ if (base16_decode(voter->legacy_id_digest, DIGEST_LEN,
+ tok->args[0], HEX_DIGEST_LEN)<0)
+ bad = 1;
+ else
+ bad = 0;
+ }
+ if (bad) {
+ log_warn(LD_DIR, "Invalid legacy key digest %s on vote.",
+ escaped(tok->args[0]));
+ }
+ }
+
/* Parse routerstatus lines. */
rs_tokens = smartlist_create();
s = end_of_header;
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index bf6a31f40b..938c47f128 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -227,6 +227,6 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.2.0.25-rc"
+#define VERSION "0.2.0.25-rc-dev"