diff options
author | Nick Mathewson <nickm@torproject.org> | 2009-09-16 17:01:01 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2009-10-15 15:17:13 -0400 |
commit | 3b2fc659a8ef83feedadcda32de49db06b80af10 (patch) | |
tree | 9df2972d2278f44f8e4fcfa6396aa45cc0d2e6db /src/or/routerparse.c | |
parent | e1ddee8bbe724e934fe9a4cb2d290719a7d6105c (diff) | |
download | tor-3b2fc659a8ef83feedadcda32de49db06b80af10.tar.gz tor-3b2fc659a8ef83feedadcda32de49db06b80af10.zip |
Refactor consensus signature storage for multiple digests and flavors.
This patch introduces a new type called document_signature_t to represent the
signature of a consensus document. Now, each consensus document can have up
to one document signature per voter per digest algorithm. Also, each
detached-signatures document can have up to one signature per <voter,
algorithm, flavor>.
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r-- | src/or/routerparse.c | 226 |
1 files changed, 151 insertions, 75 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 277c7c6c91..285a550acd 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -516,6 +516,9 @@ static int router_get_hash_impl(const char *s, char *digest, const char *start_str, const char *end_str, char end_char, digest_algorithm_t alg); +static int router_get_hashes_impl(const char *s, digests_t *digests, + const char *start_str, const char *end_str, + char end_char); static void token_free(directory_token_t *tok); static smartlist_t *find_all_exitpolicy(smartlist_t *s); static directory_token_t *_find_by_keyword(smartlist_t *s, @@ -633,6 +636,16 @@ router_get_networkstatus_v2_hash(const char *s, char *digest) DIGEST_SHA1); } +/** DOCDOC */ +int +router_get_networkstatus_v3_hashes(const char *s, digests_t *digests) +{ + return router_get_hashes_impl(s,digests, + "network-status-version", + "\ndirectory-signature", + ' '); +} + /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status * string in <b>s</b>. Return 0 on success, -1 on failure. */ int @@ -640,7 +653,8 @@ router_get_networkstatus_v3_hash(const char *s, char *digest, digest_algorithm_t alg) { return router_get_hash_impl(s,digest, - "network-status-version","\ndirectory-signature", + "network-status-version", + "\ndirectory-signature", ' ', alg); } @@ -2304,7 +2318,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, smartlist_t *rs_tokens = NULL, *footer_tokens = NULL; networkstatus_voter_info_t *voter = NULL; networkstatus_t *ns = NULL; - char ns_digest[DIGEST_LEN]; + digests_t ns_digests; const char *cert, *end_of_header, *end_of_footer, *s_dup = s; directory_token_t *tok; int ok; @@ -2316,7 +2330,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, if (eos_out) *eos_out = NULL; - if (router_get_networkstatus_v3_hash(s, ns_digest, DIGEST_SHA1)) { + if (router_get_networkstatus_v3_hashes(s, &ns_digests)) { log_warn(LD_DIR, "Unable to compute digest of network-status"); goto err; } @@ -2332,7 +2346,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, } ns = tor_malloc_zero(sizeof(networkstatus_t)); - memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN); + memcpy(&ns->digests, &ns_digests, sizeof(ns_digests)); if (ns_type != NS_TYPE_CONSENSUS) { const char *end_of_cert = NULL; @@ -2486,8 +2500,9 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, if (voter) smartlist_add(ns->voters, voter); voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); + voter->sigs = smartlist_create(); if (ns->type != NS_TYPE_CONSENSUS) - memcpy(voter->vote_digest, ns_digest, DIGEST_LEN); + memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN); voter->nickname = tor_strdup(tok->args[0]); if (strlen(tok->args[1]) != HEX_DIGEST_LEN || @@ -2622,10 +2637,10 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, goto err; } - SMARTLIST_FOREACH(footer_tokens, directory_token_t *, _tok, - { + SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) { char declared_identity[DIGEST_LEN]; networkstatus_voter_info_t *v; + document_signature_t *sig; tok = _tok; if (tok->tp != K_DIRECTORY_SIGNATURE) continue; @@ -2650,11 +2665,15 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, "any declared directory source."); goto err; } + sig = tor_malloc_zero(sizeof(document_signature_t)); + memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN); + sig->alg = DIGEST_SHA1; if (strlen(tok->args[1]) != HEX_DIGEST_LEN || - base16_decode(v->signing_key_digest, sizeof(v->signing_key_digest), + base16_decode(sig->signing_key_digest, sizeof(sig->signing_key_digest), tok->args[1], HEX_DIGEST_LEN) < 0) { log_warn(LD_DIR, "Error decoding declared digest %s in " "network-status vote.", escaped(tok->args[1])); + tor_free(sig); goto err; } @@ -2663,32 +2682,42 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, DIGEST_LEN)) { log_warn(LD_DIR, "Digest mismatch between declared and actual on " "network-status vote."); + tor_free(sig); goto err; } } + if (voter_get_sig_by_algorithm(v, sig->alg)) { + /* We already parsed a vote with this algorithm from this voter. Use the + first one. */ + log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus " + "that contains two votes from the same voter with the same " + "algorithm. Ignoring the second vote."); + tor_free(sig); + continue; + } + if (ns->type != NS_TYPE_CONSENSUS) { - if (check_signature_token(ns_digest, DIGEST_LEN, + if (check_signature_token(ns_digests.d[DIGEST_SHA1], DIGEST_LEN, tok, ns->cert->signing_key, 0, - "network-status vote")) + "network-status vote")) { + tor_free(sig); goto err; - v->good_signature = 1; + } + sig->good_signature = 1; } else { - if (tok->object_size >= INT_MAX) + if (tok->object_size >= INT_MAX) { + tor_free(sig); goto err; - /* We already parsed a vote from this voter. Use the first one. */ - if (v->signature) { - log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus " - "that contains two votes from the same voter. Ignoring " - "the second vote."); - continue; } + sig->signature = tor_memdup(tok->object_body, tok->object_size); + sig->signature_len = (int) tok->object_size; - v->signature = tor_memdup(tok->object_body, tok->object_size); - v->signature_len = (int) tok->object_size; } + smartlist_add(v->sigs, sig); + ++n_signatures; - }); + } SMARTLIST_FOREACH_END(_tok); if (! n_signatures) { log_warn(LD_DIR, "No signatures on networkstatus vote."); @@ -2714,10 +2743,14 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, smartlist_free(tokens); } if (voter) { + if (voter->sigs) { + SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig, + document_signature_free(sig)); + smartlist_free(voter->sigs); + } tor_free(voter->nickname); tor_free(voter->address); tor_free(voter->contact); - tor_free(voter->signature); tor_free(voter); } if (rs_tokens) { @@ -2747,10 +2780,19 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) * networkstatus_parse_vote_from_string(). */ directory_token_t *tok; memarea_t *area = NULL; + const char *flavor = "ns"; + digests_t *digests; + smartlist_t *sig_list; smartlist_t *tokens = smartlist_create(); ns_detached_signatures_t *sigs = tor_malloc_zero(sizeof(ns_detached_signatures_t)); + sigs->digests = strmap_new(); + sigs->signatures = strmap_new(); + digests = tor_malloc_zero(sizeof(digests_t)); + sig_list = smartlist_create(); + strmap_set(sigs->digests, flavor, digests); + strmap_set(sigs->signatures, flavor, sig_list); if (!eos) eos = s + strlen(s); @@ -2768,7 +2810,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) "networkstatus signatures"); goto err; } - if (base16_decode(sigs->networkstatus_digest, DIGEST_LEN, + if (base16_decode(digests->d[DIGEST_SHA1], DIGEST_LEN, tok->args[0], strlen(tok->args[0])) < 0) { log_warn(LD_DIR, "Bad encoding on on consensus-digest in detached " "networkstatus signatures"); @@ -2793,50 +2835,51 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) goto err; } - sigs->signatures = smartlist_create(); - SMARTLIST_FOREACH(tokens, directory_token_t *, _tok, - { - char id_digest[DIGEST_LEN]; - char sk_digest[DIGEST_LEN]; - networkstatus_voter_info_t *voter; - - tok = _tok; - if (tok->tp != K_DIRECTORY_SIGNATURE) - continue; - tor_assert(tok->n_args >= 2); - - if (!tok->object_type || - strcmp(tok->object_type, "SIGNATURE") || - tok->object_size < 128 || tok->object_size > 512) { - log_warn(LD_DIR, "Bad object type or length on directory-signature"); - goto err; - } + SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) { + char id_digest[DIGEST_LEN]; + char sk_digest[DIGEST_LEN]; + document_signature_t *sig; - if (strlen(tok->args[0]) != HEX_DIGEST_LEN || - base16_decode(id_digest, sizeof(id_digest), - tok->args[0], HEX_DIGEST_LEN) < 0) { - log_warn(LD_DIR, "Error decoding declared identity %s in " - "network-status vote.", escaped(tok->args[0])); - goto err; - } - if (strlen(tok->args[1]) != HEX_DIGEST_LEN || - base16_decode(sk_digest, sizeof(sk_digest), - tok->args[1], HEX_DIGEST_LEN) < 0) { - log_warn(LD_DIR, "Error decoding declared digest %s in " - "network-status vote.", escaped(tok->args[1])); - goto err; - } + tok = _tok; + if (tok->tp != K_DIRECTORY_SIGNATURE) + continue; + tor_assert(tok->n_args >= 2); - voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); - memcpy(voter->identity_digest, id_digest, DIGEST_LEN); - memcpy(voter->signing_key_digest, sk_digest, DIGEST_LEN); - if (tok->object_size >= INT_MAX) - goto err; - voter->signature = tor_memdup(tok->object_body, tok->object_size); - voter->signature_len = (int) tok->object_size; + if (!tok->object_type || + strcmp(tok->object_type, "SIGNATURE") || + tok->object_size < 128 || tok->object_size > 512) { + log_warn(LD_DIR, "Bad object type or length on directory-signature"); + goto err; + } + + if (strlen(tok->args[0]) != HEX_DIGEST_LEN || + base16_decode(id_digest, sizeof(id_digest), + tok->args[0], HEX_DIGEST_LEN) < 0) { + log_warn(LD_DIR, "Error decoding declared identity %s in " + "network-status vote.", escaped(tok->args[0])); + goto err; + } + if (strlen(tok->args[1]) != HEX_DIGEST_LEN || + base16_decode(sk_digest, sizeof(sk_digest), + tok->args[1], HEX_DIGEST_LEN) < 0) { + log_warn(LD_DIR, "Error decoding declared digest %s in " + "network-status vote.", escaped(tok->args[1])); + goto err; + } + + sig = tor_malloc_zero(sizeof(document_signature_t)); + sig->alg = DIGEST_SHA1; + memcpy(sig->identity_digest, id_digest, DIGEST_LEN); + memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN); + if (tok->object_size >= INT_MAX) { + tor_free(sig); + goto err; + } + sig->signature = tor_memdup(tok->object_body, tok->object_size); + sig->signature_len = (int) tok->object_size; - smartlist_add(sigs->signatures, voter); - }); + smartlist_add(sig_list, sig); + } SMARTLIST_FOREACH_END(_tok); goto done; err: @@ -3428,18 +3471,11 @@ find_all_exitpolicy(smartlist_t *s) return out; } -/** Compute the digest of the substring of <b>s</b> taken from the first - * occurrence of <b>start_str</b> through the first instance of c after the - * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in - * <b>digest</b>; return 0 on success. - * - * If no such substring exists, return -1. - */ static int -router_get_hash_impl(const char *s, char *digest, - const char *start_str, - const char *end_str, char end_c, - digest_algorithm_t alg) +router_get_hash_impl_helper(const char *s, + const char *start_str, + const char *end_str, char end_c, + const char **start_out, const char **end_out) { char *start, *end; start = strstr(s, start_str); @@ -3465,6 +3501,28 @@ router_get_hash_impl(const char *s, char *digest, } ++end; + *start_out = start; + *end_out = end; + return 0; +} + +/** Compute the digest of the substring of <b>s</b> taken from the first + * occurrence of <b>start_str</b> through the first instance of c after the + * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in + * <b>digest</b>; return 0 on success. + * + * If no such substring exists, return -1. + */ +static int +router_get_hash_impl(const char *s, char *digest, + const char *start_str, + const char *end_str, char end_c, + digest_algorithm_t alg) +{ + const char *start=NULL, *end=NULL; + if (router_get_hash_impl_helper(s,start_str,end_str,end_c,&start,&end)<0) + return -1; + if (alg == DIGEST_SHA1) { if (crypto_digest(digest, start, end-start)) { log_warn(LD_BUG,"couldn't compute digest"); @@ -3480,6 +3538,24 @@ router_get_hash_impl(const char *s, char *digest, return 0; } +/** As router_get_hash_impl, but compute all hashes. */ +static int +router_get_hashes_impl(const char *s, digests_t *digests, + const char *start_str, + const char *end_str, char end_c) +{ + const char *start=NULL, *end=NULL; + if (router_get_hash_impl_helper(s,start_str,end_str,end_c,&start,&end)<0) + return -1; + + if (crypto_digest_all(digests, start, end-start)) { + log_warn(LD_BUG,"couldn't compute digests"); + return -1; + } + + return 0; +} + /** DOCDOC Assuming that s starts with a microdesc, return the start of the * *NEXT* one. */ static const char * |