[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] [tor/master] Implement signatures for microdesc consensuses right.
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Wed, 23 Sep 2009 03:02:32 -0400
Subject: Implement signatures for microdesc consensuses right.
Commit: 3471057486a8aef0be6e74b090a3173e0794c84b
This means we need to handle the existence of multiple flavors of signature
in a detached signatures document, generate them correctly, and so on.
---
src/or/dirserv.c | 1 +
src/or/dirvote.c | 218 ++++++++++++++++++++++++++++++++++++++-------------
src/or/or.h | 2 +-
src/test/test_dir.c | 21 ++++-
4 files changed, 184 insertions(+), 58 deletions(-)
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 326a801..17fff61 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1876,6 +1876,7 @@ version_from_platform(const char *platform)
* The format argument has three possible values:
* NS_V2 - Output an entry suitable for a V2 NS opinion document
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
+ * NS_V3_CONSENSUS_MICRODESC - DOCDOC
* NS_V3_VOTE - Output a complete V3 NS vote
* NS_CONTROL_PORT - Output a NS document for the control port
*/
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index e361102..d64e4d5 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -11,7 +11,14 @@
* \brief Functions to compute directory consensus, and schedule voting.
**/
-typedef struct pending_consensus_t pending_consensus_t;
+/** DOCDOC*/
+typedef struct pending_consensus_t {
+ /** The body of the consensus that we're currently building. Once we
+ * have it built, it goes into dirserv.c */
+ char *body;
+ /** The parsed in-progress consensus document. */
+ networkstatus_t *consensus;
+} pending_consensus_t;
static int dirvote_add_signatures_to_all_pending_consensuses(
const char *detached_signatures_body,
@@ -148,7 +155,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
flags,
params,
voter->nickname, fingerprint, voter->address,
- ipaddr, voter->dir_port, voter->or_port, voter->contact);
+ ipaddr, voter->dir_port, voter->or_port, voter->contact);
tor_free(params);
tor_free(flags);
@@ -433,14 +440,20 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
}
/** Given a list of strings in <b>lst</b>, set the DIGEST_LEN-byte digest at
- * <b>digest_out</b> to the hash of the concatenation of those strings. */
+ * <b>digest_out</b> to the hash of the concatenation of those strings. DOCDOC
+ * new arguments. */
static void
-hash_list_members(char *digest_out, smartlist_t *lst)
+hash_list_members(char *digest_out, size_t len_out,
+ smartlist_t *lst, digest_algorithm_t alg)
{
- crypto_digest_env_t *d = crypto_new_digest_env();
+ crypto_digest_env_t *d;
+ if (alg == DIGEST_SHA1)
+ d = crypto_new_digest_env();
+ else
+ d = crypto_new_digest256_env(alg);
SMARTLIST_FOREACH(lst, const char *, cp,
crypto_digest_add_bytes(d, cp, strlen(cp)));
- crypto_digest_get_digest(d, digest_out, DIGEST_LEN);
+ crypto_digest_get_digest(d, digest_out, len_out);
crypto_free_digest_env(d);
}
@@ -655,12 +668,15 @@ networkstatus_compute_consensus(smartlist_t *votes,
int vote_seconds, dist_seconds;
char *client_versions = NULL, *server_versions = NULL;
smartlist_t *flags;
+ const char *flavor_name;
const routerstatus_format_type_t rs_format =
flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC;
tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
tor_assert(total_authorities >= smartlist_len(votes));
+ flavor_name = networkstatus_get_flavor_name(flavor);
+
if (!smartlist_len(votes)) {
log_warn(LD_DIR, "Can't compute a consensus from no votes.");
return NULL;
@@ -762,8 +778,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
format_iso_time(vu_buf, valid_until);
flaglist = smartlist_join_strings(flags, " ", 0, NULL);
- smartlist_add(chunks, tor_strdup("network-status-version 3\n"
- "vote-status consensus\n"));
+ tor_snprintf(buf, sizeof(buf), "network-status-version 3%s%s\n"
+ "vote-status consensus\n",
+ flavor == FLAV_NS ? "" : " ",
+ flavor == FLAV_NS ? "" : flavor_name);
+
+ smartlist_add(chunks, tor_strdup(buf));
if (consensus_method >= 2) {
tor_snprintf(buf, sizeof(buf), "consensus-method %d\n",
@@ -1285,25 +1305,36 @@ networkstatus_compute_consensus(smartlist_t *votes,
/* Add a signature. */
{
- char digest[DIGEST_LEN];
+ char digest[DIGEST256_LEN];
char fingerprint[HEX_DIGEST_LEN+1];
char signing_key_fingerprint[HEX_DIGEST_LEN+1];
+ digest_algorithm_t digest_alg =
+ flavor == FLAV_NS ? DIGEST_SHA1 : DIGEST_SHA256;
+ size_t digest_len =
+ flavor == FLAV_NS ? DIGEST_LEN : DIGEST256_LEN;
+ const char *algname = crypto_digest_algorithm_get_name(digest_alg);
char buf[4096];
smartlist_add(chunks, tor_strdup("directory-signature "));
/* Compute the hash of the chunks. */
- hash_list_members(digest, chunks);
+ hash_list_members(digest, digest_len, chunks, digest_alg);
/* Get the fingerprints */
crypto_pk_get_fingerprint(identity_key, fingerprint, 0);
crypto_pk_get_fingerprint(signing_key, signing_key_fingerprint, 0);
/* add the junk that will go at the end of the line. */
- tor_snprintf(buf, sizeof(buf), "%s %s\n", fingerprint,
- signing_key_fingerprint);
+ if (flavor == FLAV_NS) {
+ tor_snprintf(buf, sizeof(buf), "%s %s\n", fingerprint,
+ signing_key_fingerprint);
+ } else {
+ tor_snprintf(buf, sizeof(buf), "%s %s %s\n",
+ algname, fingerprint,
+ signing_key_fingerprint);
+ }
/* And the signature. */
- if (router_append_dirobj_signature(buf, sizeof(buf), digest, DIGEST_LEN,
+ if (router_append_dirobj_signature(buf, sizeof(buf), digest, digest_len,
signing_key)) {
log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
return NULL; /* This leaks, but it should never happen. */
@@ -1316,9 +1347,15 @@ networkstatus_compute_consensus(smartlist_t *votes,
legacy_id_key_digest, DIGEST_LEN);
crypto_pk_get_fingerprint(legacy_signing_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, DIGEST_LEN,
+ if (flavor == FLAV_NS) {
+ tor_snprintf(buf, sizeof(buf), "%s %s\n", fingerprint,
+ signing_key_fingerprint);
+ } else {
+ tor_snprintf(buf, sizeof(buf), "%s %s %s\n",
+ algname, fingerprint,
+ signing_key_fingerprint);
+ }
+ if (router_append_dirobj_signature(buf, sizeof(buf), digest, digest_len,
legacy_signing_key)) {
log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
return NULL; /* This leaks, but it should never happen. */
@@ -1488,12 +1525,21 @@ networkstatus_add_detached_signatures(networkstatus_t *target,
/** DOCDOC */
static char *
-networkstatus_format_signatures(networkstatus_t *consensus)
+networkstatus_format_signatures(networkstatus_t *consensus,
+ int for_detached_signatures)
{
smartlist_t *elements;
char buf[4096];
char *result = NULL;
int n_sigs = 0;
+ const consensus_flavor_t flavor = consensus->flavor;
+ const char *flavor_name = networkstatus_get_flavor_name(flavor);
+ const char *keyword;
+
+ if (for_detached_signatures && flavor != FLAV_NS)
+ keyword = "additional-signature";
+ else
+ keyword = "directory-signature";
elements = smartlist_create();
@@ -1501,14 +1547,25 @@ networkstatus_format_signatures(networkstatus_t *consensus)
SMARTLIST_FOREACH_BEGIN(v->sigs, document_signature_t *, sig) {
char sk[HEX_DIGEST_LEN+1];
char id[HEX_DIGEST_LEN+1];
- if (!sig->signature || sig->bad_signature || sig->alg != DIGEST_SHA1)
+ if (!sig->signature || sig->bad_signature)
continue;
++n_sigs;
base16_encode(sk, sizeof(sk), sig->signing_key_digest, DIGEST_LEN);
base16_encode(id, sizeof(id), sig->identity_digest, DIGEST_LEN);
- tor_snprintf(buf, sizeof(buf),
- "directory-signature %s %s\n-----BEGIN SIGNATURE-----\n",
- id, sk);
+ if (flavor == FLAV_NS) {
+ tor_snprintf(buf, sizeof(buf),
+ "%s %s %s\n-----BEGIN SIGNATURE-----\n",
+ keyword, id, sk);
+ } else {
+ const char *digest_name =
+ crypto_digest_algorithm_get_name(sig->alg);
+ tor_snprintf(buf, sizeof(buf),
+ "%s%s%s %s %s %s\n-----BEGIN SIGNATURE-----\n",
+ keyword,
+ for_detached_signatures ? " " : "",
+ for_detached_signatures ? flavor_name : "",
+ digest_name, id, sk);
+ }
smartlist_add(elements, tor_strdup(buf));
base64_encode(buf, sizeof(buf), sig->signature, sig->signature_len);
strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));
@@ -1525,17 +1582,28 @@ networkstatus_format_signatures(networkstatus_t *consensus)
}
/** Return a newly allocated string holding the detached-signatures document
- * corresponding to the signatures on <b>consensus</b>. */
+ * corresponding to the signatures on <b>consensuses</b>, which must contain
+ * exactly one FLAV_NS consensus, and no more than one consensus for each
+ * other flavor. */
char *
-networkstatus_get_detached_signatures(networkstatus_t *consensus)
+networkstatus_get_detached_signatures(smartlist_t *consensuses)
{
smartlist_t *elements;
char buf[4096];
- char *result = NULL;
- tor_assert(consensus);
- tor_assert(consensus->type == NS_TYPE_CONSENSUS);
-
- tor_assert(consensus->flavor == FLAV_NS);
+ char *result = NULL, *sigs = NULL;
+ networkstatus_t *consensus_ns = NULL;
+ tor_assert(consensuses);
+
+ SMARTLIST_FOREACH(consensuses, networkstatus_t *, ns, {
+ tor_assert(ns);
+ tor_assert(ns->type == NS_TYPE_CONSENSUS);
+ if (ns && ns->flavor == FLAV_NS)
+ consensus_ns = ns;
+ });
+ if (!consensus_ns) {
+ log_warn(LD_BUG, "No NS consensus given.");
+ return NULL;
+ }
elements = smartlist_create();
@@ -1544,10 +1612,11 @@ networkstatus_get_detached_signatures(networkstatus_t *consensus)
vu_buf[ISO_TIME_LEN+1];
char d[HEX_DIGEST_LEN+1];
- base16_encode(d, sizeof(d), consensus->digests.d[DIGEST_SHA1], DIGEST_LEN);
- format_iso_time(va_buf, consensus->valid_after);
- format_iso_time(fu_buf, consensus->fresh_until);
- format_iso_time(vu_buf, consensus->valid_until);
+ base16_encode(d, sizeof(d),
+ consensus_ns->digests.d[DIGEST_SHA1], DIGEST_LEN);
+ format_iso_time(va_buf, consensus_ns->valid_after);
+ format_iso_time(fu_buf, consensus_ns->fresh_until);
+ format_iso_time(vu_buf, consensus_ns->valid_until);
tor_snprintf(buf, sizeof(buf),
"consensus-digest %s\n"
@@ -1557,12 +1626,46 @@ networkstatus_get_detached_signatures(networkstatus_t *consensus)
smartlist_add(elements, tor_strdup(buf));
}
- {
- char *sigs = networkstatus_format_signatures(consensus);
- if (!sigs)
+ /* Get all the digests for the non-FLAV_NS consensuses */
+ SMARTLIST_FOREACH_BEGIN(consensuses, networkstatus_t *, ns) {
+ const char *flavor_name = networkstatus_get_flavor_name(ns->flavor);
+ int alg;
+ if (ns->flavor == FLAV_NS)
+ continue;
+
+ /* start with SHA256; we don't include SHA1 for anything but the basic
+ * consensus. */
+ for (alg = DIGEST_SHA256; alg < N_DIGEST_ALGORITHMS; ++alg) {
+ char d[HEX_DIGEST256_LEN+1];
+ const char *alg_name =
+ crypto_digest_algorithm_get_name(alg);
+ if (tor_mem_is_zero(ns->digests.d[alg], DIGEST256_LEN))
+ continue;
+ base16_encode(d, sizeof(d), ns->digests.d[alg], DIGEST256_LEN);
+ tor_snprintf(buf, sizeof(buf), "additional-digest %s %s %s\n",
+ flavor_name, alg_name, d);
+ smartlist_add(elements, tor_strdup(buf));
+ }
+ } SMARTLIST_FOREACH_END(ns);
+
+ /* Now get all the sigs for non-FLAV_NS consensuses */
+ SMARTLIST_FOREACH_BEGIN(consensuses, networkstatus_t *, ns) {
+ char *sigs;
+ if (ns->flavor == FLAV_NS)
+ continue;
+ sigs = networkstatus_format_signatures(ns, 1);
+ if (!sigs) {
+ log_warn(LD_DIR, "Couldn't format signatures");
goto err;
+ }
smartlist_add(elements, sigs);
- }
+ } SMARTLIST_FOREACH_END(ns);
+
+ /* Now add the FLAV_NS consensus signatrures. */
+ sigs = networkstatus_format_signatures(consensus_ns, 1);
+ if (!sigs)
+ goto err;
+ smartlist_add(elements, sigs);
result = smartlist_join_strings(elements, "", 0, NULL);
err:
@@ -1571,6 +1674,23 @@ networkstatus_get_detached_signatures(networkstatus_t *consensus)
return result;
}
+/** DOCDOC */
+static char *
+get_detached_signatures_from_pending_consensuses(pending_consensus_t *pending,
+ int n_flavors)
+{
+ int flav;
+ char *signatures;
+ smartlist_t *c = smartlist_create();
+ for (flav = 0; flav < n_flavors; ++flav) {
+ if (pending[flav].consensus)
+ smartlist_add(c, pending[flav].consensus);
+ }
+ signatures = networkstatus_get_detached_signatures(c);
+ smartlist_free(c);
+ return signatures;
+}
+
/** Release all storage held in <b>s</b>. */
void
ns_detached_signatures_free(ns_detached_signatures_t *s)
@@ -1812,15 +1932,6 @@ static smartlist_t *pending_vote_list = NULL;
* build a consensus, the votes go here for the next period. */
static smartlist_t *previous_vote_list = NULL;
-/** DOCDOC*/
-struct pending_consensus_t {
- /** The body of the consensus that we're currently building. Once we
- * have it built, it goes into dirserv.c */
- char *body;
- /** The parsed in-progress consensus document. */
- networkstatus_t *consensus;
-};
-
static pending_consensus_t pending_consensuses[N_CONSENSUS_FLAVORS];
/** The detached signatures for the consensus that we're currently
@@ -2277,9 +2388,8 @@ dirvote_compute_consensuses(void)
}
}
- /* XXXX NMNM NM NM wrong. */
- signatures =
- networkstatus_get_detached_signatures(pending[FLAV_NS].consensus);
+ signatures = get_detached_signatures_from_pending_consensuses(
+ pending, N_CONSENSUS_FLAVORS);
if (!signatures) {
log_warn(LD_DIR, "Couldn't extract signatures.");
@@ -2364,7 +2474,7 @@ dirvote_add_signatures_to_pending_consensus(
if (r >= 1) {
char *new_signatures =
- networkstatus_format_signatures(pc->consensus);
+ networkstatus_format_signatures(pc->consensus, 0);
char *dst, *dst_end;
size_t new_consensus_len;
if (!new_signatures) {
@@ -2389,7 +2499,6 @@ dirvote_add_signatures_to_pending_consensus(
tor_assert(v);
networkstatus_vote_free(v);
}
- tor_free(pending_consensus_signatures);
*msg_out = "Signatures added";
} else if (r == 0) {
*msg_out = "Signatures ignored";
@@ -2414,6 +2523,7 @@ dirvote_add_signatures_to_all_pending_consensuses(
ns_detached_signatures_t *sigs;
tor_assert(detached_signatures_body);
tor_assert(msg_out);
+ tor_assert(pending_consensus_signatures);
if (!(sigs = networkstatus_parse_detached_signatures(
detached_signatures_body, NULL))) {
@@ -2438,10 +2548,10 @@ dirvote_add_signatures_to_all_pending_consensuses(
goto err;
}
- /* Still not right XXXX NM NM*/
- if (pending_consensuses[FLAV_NS].consensus) {
- char *new_detached = networkstatus_get_detached_signatures(
- pending_consensuses[FLAV_NS].consensus);
+ if (n_added && pending_consensuses[FLAV_NS].consensus) {
+ char *new_detached =
+ get_detached_signatures_from_pending_consensuses(
+ pending_consensuses, N_CONSENSUS_FLAVORS);
if (new_detached) {
tor_free(pending_consensus_signatures);
pending_consensus_signatures = new_detached;
diff --git a/src/or/or.h b/src/or/or.h
index b8ccac9..d9b10c6 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3838,7 +3838,7 @@ char *networkstatus_compute_consensus(smartlist_t *votes,
int networkstatus_add_detached_signatures(networkstatus_t *target,
ns_detached_signatures_t *sigs,
const char **msg_out);
-char *networkstatus_get_detached_signatures(networkstatus_t *consensus);
+char *networkstatus_get_detached_signatures(smartlist_t *consensuses);
void ns_detached_signatures_free(ns_detached_signatures_t *s);
/* cert manipulation */
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index b1fac68..13b46c6 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -559,6 +559,21 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
return r;
}
+/** Helper: get a detached signatures document for a single FLAV_NS
+ * consensus. */
+static char *
+get_detached_sigs(networkstatus_t *ns)
+{
+ char *r;
+ smartlist_t *sl;
+ tor_assert(ns && ns->flavor == FLAV_NS);
+ sl = smartlist_create();
+ smartlist_add(sl,ns);
+ r = networkstatus_get_detached_signatures(sl);
+ smartlist_free(sl);
+ return r;
+}
+
/** Run unit tests for generating and parsing V3 consensus networkstatus
* documents. */
static void
@@ -994,7 +1009,7 @@ test_dir_v3_networkstatus(void)
test_memeq(&con->digests, &con3->digests, sizeof(digests_t));
/* Extract a detached signature from con3. */
- detached_text1 = networkstatus_get_detached_signatures(con3);
+ detached_text1 = get_detached_sigs(con3);
tor_assert(detached_text1);
/* Try to parse it. */
dsig1 = networkstatus_parse_detached_signatures(detached_text1, NULL);
@@ -1020,10 +1035,10 @@ test_dir_v3_networkstatus(void)
}
/* Try adding it to con2. */
- detached_text2 = networkstatus_get_detached_signatures(con2);
+ detached_text2 = get_detached_sigs(con2);
test_eq(1, networkstatus_add_detached_signatures(con2, dsig1, &msg));
tor_free(detached_text2);
- detached_text2 = networkstatus_get_detached_signatures(con2);
+ detached_text2 = get_detached_sigs(con2);
//printf("\n<%s>\n", detached_text2);
dsig2 = networkstatus_parse_detached_signatures(detached_text2, NULL);
test_assert(dsig2);
--
1.5.6.5