mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-24 06:48:05 +01:00
Implement signatures for microdesc consensuses right.
This means we need to handle the existence of multiple flavors of signature in a detached signatures document, generate them correctly, and so on.
This commit is contained in:
parent
d9c71816b1
commit
3471057486
4 changed files with 183 additions and 57 deletions
|
@ -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
|
||||
*/
|
||||
|
|
216
src/or/dirvote.c
216
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);
|
||||
char *result = NULL, *sigs = NULL;
|
||||
networkstatus_t *consensus_ns = NULL;
|
||||
tor_assert(consensuses);
|
||||
|
||||
tor_assert(consensus->flavor == FLAV_NS);
|
||||
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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue