From fb2f3c035b503ed9de3ad9612b12481ee162f718 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 26 Jul 2007 20:26:59 +0000 Subject: [PATCH] r13921@catbus: nickm | 2007-07-26 16:26:48 -0400 Code to add signatures to a pending consensus directory. svn:r10936 --- src/or/dirvote.c | 113 +++++++++++++++++++++++++++++++++++++++++-- src/or/or.h | 10 +++- src/or/routerlist.c | 17 +++++++ src/or/routerparse.c | 4 +- src/or/test.c | 6 +-- 5 files changed, 139 insertions(+), 11 deletions(-) diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 06c90f80f9..f8df2c74bb 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -698,15 +698,17 @@ networkstatus_check_voter_signature(networkstatus_vote_t *consensus, signed_digest = tor_malloc(signed_digest_len); if (crypto_pk_public_checksig(cert->signing_key, signed_digest, - voter->pending_signature, - voter->pending_signature_len) != DIGEST_LEN || + voter->signature, + voter->signature_len) != DIGEST_LEN || memcmp(signed_digest, consensus->networkstatus_digest, DIGEST_LEN)) { log_warn(LD_DIR, "Got a bad signature."); /*XXXX020 say more*/ voter->bad_signature = 1; } else { voter->good_signature = 1; } - tor_free(voter->pending_signature); + /* XXXX020 did anything rely on this? + * also, rename so it's no longer called "pending". */ + // tor_free(voter->signature); return 0; } @@ -730,7 +732,7 @@ networkstatus_check_consensus_signature(networkstatus_vote_t *consensus) ++n_unknown; continue; } - if (voter->pending_signature) { + if (voter->signature) { tor_assert(!voter->good_signature && !voter->bad_signature); if (!ds->v3_cert || networkstatus_check_voter_signature(consensus, voter, @@ -752,6 +754,93 @@ networkstatus_check_consensus_signature(networkstatus_vote_t *consensus) return 0; } +/** DOCDOC */ +int +networkstatus_add_consensus_signatures(networkstatus_vote_t *target, + networkstatus_vote_t *src, + char **new_signatures_out) +{ + smartlist_t *added_signatures, *sigs; + int r; + tor_assert(target); + tor_assert(src); + tor_assert(! target->is_vote); + tor_assert(! src->is_vote); + tor_assert(new_signatures_out); + + *new_signatures_out = NULL; + + /* Are they the same consensus? */ + if (memcmp(target->networkstatus_digest, src->networkstatus_digest, + DIGEST_LEN)) + return -1; + if (target == src) + return 0; + + added_signatures = smartlist_create(); + + /* For each voter in src... */ + SMARTLIST_FOREACH(src->voters, networkstatus_voter_info_t *, src_voter, + { + networkstatus_voter_info_t *target_voter = + networkstatus_get_voter_by_id(target, src_voter->identity_digest); + authority_cert_t *cert; + /* If the target a doesn't know about this voter, then forget it. */ + if (!target_voter) + continue; + + /* If the target already has a good signature from this voter, then skip + * this one. */ + if (target_voter->good_signature) + continue; + + /* If this signature is no good, then skip. */ + cert = authority_cert_get_by_digests(src_voter->identity_digest, + src_voter->signing_key_digest); + if (cert) { + networkstatus_check_voter_signature(target, src_voter, cert); + } + /* If this signature is good, then replace and add. */ + if (src_voter->good_signature || !target_voter->signature) { + tor_free(target_voter->signature); + target_voter->signature = + tor_memdup(src_voter->signature, src_voter->signature_len); + memcpy(target_voter->signing_key_digest, src_voter->signing_key_digest, + DIGEST_LEN); + target_voter->signature_len = src_voter->signature_len; + target_voter->good_signature = 1; + target_voter->bad_signature = 0; + smartlist_add(added_signatures, target_voter); + } + }); + + sigs = smartlist_create(); + SMARTLIST_FOREACH(added_signatures, networkstatus_voter_info_t *, v, + { + char buf[4096]; + char sk[HEX_DIGEST_LEN+1]; + char ik[HEX_DIGEST_LEN+1]; + tor_assert(v->signature); + + base16_encode(sk, sizeof(sk), v->signing_key_digest, DIGEST_LEN); + base16_encode(ik, sizeof(ik), v->identity_digest, DIGEST_LEN); + tor_snprintf(buf, sizeof(buf), "directory-signature %s %s\n" + "-----BEGIN SIGNATURE-----", ik, sk); + smartlist_add(sigs, tor_strdup(buf)); + base64_encode(buf, sizeof(buf), v->signature, v->signature_len); + strlcat(buf, "-----END SIGNATURE-----", sizeof(buf)); + smartlist_add(sigs, tor_strdup(buf)); + }); + + *new_signatures_out = smartlist_join_strings(sigs, "", 0, NULL); + SMARTLIST_FOREACH(sigs, char *, cp, tor_free(cp)); + smartlist_free(sigs); + r = smartlist_len(added_signatures); + smartlist_free(added_signatures); + return r; +} + + /* ===== * Certificate functions * ===== */ @@ -876,6 +965,8 @@ typedef struct pending_vote_t { static smartlist_t *pending_vote_list = NULL; /** DOCDOC */ static char *pending_consensus_body = NULL; +/** DOCDOC */ +static networkstatus_vote_t *pending_consensus = NULL; /** DOCDOC */ void @@ -988,6 +1079,7 @@ dirvote_compute_consensus(void) int n_votes, n_voters; smartlist_t *votes = NULL; char *consensus_body = NULL; + networkstatus_vote_t *consensus = NULL; authority_cert_t *my_cert; if (!pending_vote_list) @@ -1011,13 +1103,26 @@ dirvote_compute_consensus(void) my_cert->identity_key, get_my_v3_authority_signing_key()); + consensus = networkstatus_parse_vote_from_string(consensus_body, 0); + if (!consensus) { + log_warn(LD_DIR, "Couldn't parse consensus we generated!"); + goto err; + } + tor_free(pending_consensus_body); pending_consensus_body = consensus_body; + if (pending_consensus) + networkstatus_vote_free(pending_consensus); + pending_consensus = consensus; + return 0; err: if (votes) smartlist_free(votes); + tor_free(consensus_body); + networkstatus_vote_free(consensus); + return -1; } diff --git a/src/or/or.h b/src/or/or.h index d60fa07037..755c69e7df 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1330,8 +1330,8 @@ typedef struct networkstatus_voter_info_t { char vote_digest[DIGEST_LEN]; char signing_key_digest[DIGEST_LEN]; /* This part is _not_ signed. */ - char *pending_signature; - int pending_signature_len; + char *signature; + int signature_len; unsigned int bad_signature : 1; unsigned int good_signature : 1; } networkstatus_voter_info_t; @@ -2792,6 +2792,9 @@ networkstatus_voter_info_t *networkstatus_get_voter_by_id( networkstatus_vote_t *vote, const char *identity); int networkstatus_check_consensus_signature(networkstatus_vote_t *consensus); +int networkstatus_add_consensus_signatures(networkstatus_vote_t *target, + networkstatus_vote_t *src, + char **new_signatures_out); /* cert manipulation */ void authority_cert_free(authority_cert_t *cert); @@ -3272,6 +3275,7 @@ typedef struct trusted_dir_server_t { /** What kind of authority is this? (Bitfield.) */ authority_type_t type; + /* XXXX020 this should be a list. */ authority_cert_t *v3_cert; /**< V3 key certificate for this authority */ int n_networkstatus_failures; /**< How many times have we asked for this @@ -3299,6 +3303,8 @@ trusted_dir_server_t *router_get_trusteddirserver_by_digest( const char *digest); trusted_dir_server_t *trusteddirserver_get_by_v3_auth_digest( const char *digest); +authority_cert_t *authority_cert_get_by_digests(const char *id_digest, + const char *sk_digest); void routerlist_add_family(smartlist_t *sl, routerinfo_t *router); void add_nickname_list_to_smartlist(smartlist_t *sl, const char *list, int must_be_running); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 352c144e5a..5c327073bf 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -266,6 +266,23 @@ trusted_dirs_flush_certs_to_disk(void) trusted_dir_servers_certs_changed = 0; } +/** DOCDOC */ +authority_cert_t * +authority_cert_get_by_digests(const char *id_digest, + const char *sk_digest) +{ + char d[DIGEST_LEN]; + trusted_dir_server_t *ds = trusteddirserver_get_by_v3_auth_digest(id_digest); + + if (!ds || !ds->v3_cert) + return NULL; + crypto_pk_get_digest(ds->v3_cert->signing_key, d); + if (memcmp(d, sk_digest, DIGEST_LEN)) + return NULL; + + return ds->v3_cert; +} + /* Router descriptor storage. * * Routerdescs are stored in a big file, named "cached-routers". As new diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 3967f7fd90..8c025668a3 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -2046,9 +2046,9 @@ networkstatus_parse_vote_from_string(const char *s, int is_vote) goto err; v->good_signature = 1; } else { - v->pending_signature = tor_memdup(tok->object_body, + v->signature = tor_memdup(tok->object_body, tok->object_size); - v->pending_signature_len = tok->object_size; + v->signature_len = tok->object_size; } }); /* XXXX020 enforce: vote must have at least one signature. */ diff --git a/src/or/test.c b/src/or/test.c index 408adaf8d8..2776fcbfc1 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -2672,18 +2672,18 @@ test_v3_networkstatus(void) /* Check signatures. the first voter hasn't got one. The second one * does: validate it. */ voter = smartlist_get(con->voters, 0); - test_assert(!voter->pending_signature); + test_assert(!voter->signature); test_assert(!voter->good_signature); test_assert(!voter->bad_signature); voter = smartlist_get(con->voters, 1); - test_assert(voter->pending_signature); + test_assert(voter->signature); test_assert(!voter->good_signature); test_assert(!voter->bad_signature); test_assert(!networkstatus_check_voter_signature(con, smartlist_get(con->voters, 1), cert3)); - test_assert(!voter->pending_signature); + test_assert(voter->signature); test_assert(voter->good_signature); test_assert(!voter->bad_signature);