commit 5acddbbbf74199b46eef75cbbeb11ea6aad9326f Author: Nick Mathewson nickm@torproject.org Date: Wed May 3 11:48:08 2017 -0400
bug#22143/prop#140: identify input diffs by their digest-as-signed
See may 3 changes to prop140 for more background. --- src/or/consdiff.c | 16 +++++++++++-- src/or/consdiff.h | 3 +++ src/or/routerparse.c | 58 ++++++++++++++++++++++++++++++++++++++++------- src/or/routerparse.h | 5 ++++ src/test/fuzz/fuzz_diff.c | 2 ++ src/test/test_consdiff.c | 6 ++--- 6 files changed, 77 insertions(+), 13 deletions(-)
diff --git a/src/or/consdiff.c b/src/or/consdiff.c index c0fe979..e4f7872 100644 --- a/src/or/consdiff.c +++ b/src/or/consdiff.c @@ -91,6 +91,18 @@ consensus_compute_digest,(const char *cons, return r; }
+/** Compute the digest-as-signed of <b>cons</b>, and store the result in + * <b>digest_out</b>. Return 0 on success, -1 on failure. */ +/* This is a separate, mockable function so that we can override it when + * fuzzing. */ +MOCK_IMPL(STATIC int, +consensus_compute_digest_as_signed,(const char *cons, + consensus_digest_t *digest_out)) +{ + return router_get_networkstatus_v3_sha3_as_signed(digest_out->sha3_256, + cons); +} + /** Return true iff <b>d1</b> and <b>d2</b> contain the same digest */ /* This is a separate, mockable function so that we can override it when * fuzzing. */ @@ -1250,7 +1262,7 @@ consensus_diff_generate(const char *cons1, int r1, r2; char *result = NULL;
- r1 = consensus_compute_digest(cons1, &d1); + r1 = consensus_compute_digest_as_signed(cons1, &d1); r2 = consensus_compute_digest(cons2, &d2); if (BUG(r1 < 0 || r2 < 0)) return NULL; // LCOV_EXCL_LINE @@ -1291,7 +1303,7 @@ consensus_diff_apply(const char *consensus, char *result = NULL; memarea_t *area = memarea_new();
- r1 = consensus_compute_digest(consensus, &d1); + r1 = consensus_compute_digest_as_signed(consensus, &d1); if (BUG(r1 < 0)) return NULL; // LCOV_EXCL_LINE
diff --git a/src/or/consdiff.h b/src/or/consdiff.h index e9d1751..284a576 100644 --- a/src/or/consdiff.h +++ b/src/or/consdiff.h @@ -85,6 +85,9 @@ MOCK_DECL(STATIC int, consensus_compute_digest,(const char *cons, consensus_digest_t *digest_out)); MOCK_DECL(STATIC int, + consensus_compute_digest_as_signed,(const char *cons, + consensus_digest_t *digest_out)); +MOCK_DECL(STATIC int, consensus_digest_eq,(const uint8_t *d1, const uint8_t *d2)); #endif diff --git a/src/or/routerparse.c b/src/or/routerparse.c index fc0a4ab..f39c332 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -359,6 +359,7 @@ static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok); static int router_get_hash_impl_helper(const char *s, size_t s_len, const char *start_str, const char *end_str, char end_c, + int log_severity, const char **start_out, const char **end_out); static int router_get_hash_impl(const char *s, size_t s_len, char *digest, const char *start_str, const char *end_str, @@ -988,6 +989,41 @@ router_get_router_hash(const char *s, size_t s_len, char *digest) DIGEST_SHA1); }
+/** Try to find the start and end of the signed portion of a networkstatus + * document in <b>s</b>. On success, set <b>start_out</b> to the first + * character of the document, and <b>end_out</b> to a position one after the + * final character of the signed document, and return 0. On failure, return + * -1. */ +int +router_get_networkstatus_v3_signed_boundaries(const char *s, + const char **start_out, + const char **end_out) +{ + return router_get_hash_impl_helper(s, strlen(s), + "network-status-version", + "\ndirectory-signature", + ' ', LOG_INFO, + start_out, end_out); +} + +/** Set <b>digest_out</b> to the SHA3-256 digest of the signed portion of the + * networkstatus vote in <b>s</b> -- or of the entirety of <b>s</b> if no + * signed portion can be identified. Return 0 on success, -1 on failure. */ +int +router_get_networkstatus_v3_sha3_as_signed(uint8_t *digest_out, + const char *s) +{ + const char *start, *end; + if (router_get_networkstatus_v3_signed_boundaries(s, &start, &end) < 0) { + start = s; + end = s + strlen(s); + } + tor_assert(start); + tor_assert(end); + return crypto_digest256((char*)digest_out, start, end-start, + DIGEST_SHA3_256); +} + /** Set <b>digests</b> to all the digests of the consensus document in * <b>s</b> */ int @@ -1787,7 +1823,8 @@ router_parse_entry_from_string(const char *s, const char *end,
if (router_get_hash_impl_helper(s, end-s, "router ", "\nrouter-sig-ed25519", - ' ', &signed_start, &signed_end) < 0) { + ' ', LOG_WARN, + &signed_start, &signed_end) < 0) { log_warn(LD_DIR, "Can't find ed25519-signed portion of descriptor"); goto err; } @@ -2140,7 +2177,8 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
if (router_get_hash_impl_helper(s, end-s, "extra-info ", "\nrouter-sig-ed25519", - ' ', &signed_start, &signed_end) < 0) { + ' ', LOG_WARN, + &signed_start, &signed_end) < 0) { log_warn(LD_DIR, "Can't find ed25519-signed portion of extrainfo"); goto err; } @@ -4471,16 +4509,18 @@ static int router_get_hash_impl_helper(const char *s, size_t s_len, const char *start_str, const char *end_str, char end_c, + int log_severity, const char **start_out, const char **end_out) { const char *start, *end; start = tor_memstr(s, s_len, start_str); if (!start) { - log_warn(LD_DIR,"couldn't find start of hashed material "%s"",start_str); + log_fn(log_severity,LD_DIR, + "couldn't find start of hashed material "%s"",start_str); return -1; } if (start != s && *(start-1) != '\n') { - log_warn(LD_DIR, + log_fn(log_severity,LD_DIR, "first occurrence of "%s" is not at the start of a line", start_str); return -1; @@ -4488,12 +4528,14 @@ router_get_hash_impl_helper(const char *s, size_t s_len, end = tor_memstr(start+strlen(start_str), s_len - (start-s) - strlen(start_str), end_str); if (!end) { - log_warn(LD_DIR,"couldn't find end of hashed material "%s"",end_str); + log_fn(log_severity,LD_DIR, + "couldn't find end of hashed material "%s"",end_str); return -1; } end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str)); if (!end) { - log_warn(LD_DIR,"couldn't find EOL"); + log_fn(log_severity,LD_DIR, + "couldn't find EOL"); return -1; } ++end; @@ -4517,7 +4559,7 @@ router_get_hash_impl(const char *s, size_t s_len, char *digest, digest_algorithm_t alg) { const char *start=NULL, *end=NULL; - if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c, + if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN, &start,&end)<0) return -1;
@@ -4554,7 +4596,7 @@ router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests, const char *end_str, char end_c) { const char *start=NULL, *end=NULL; - if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c, + if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN, &start,&end)<0) return -1;
diff --git a/src/or/routerparse.h b/src/or/routerparse.h index e8d71b6..088f773 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -16,6 +16,11 @@ int router_get_router_hash(const char *s, size_t s_len, char *digest); int router_get_dir_hash(const char *s, char *digest); int router_get_networkstatus_v3_hashes(const char *s, common_digests_t *digests); +int router_get_networkstatus_v3_signed_boundaries(const char *s, + const char **start_out, + const char **end_out); +int router_get_networkstatus_v3_sha3_as_signed(uint8_t *digest_out, + const char *s); int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest); #define DIROBJ_MAX_SIG_LEN 256 char *router_get_dirobj_signature(const char *digest, diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c index c241f63..642380b 100644 --- a/src/test/fuzz/fuzz_diff.c +++ b/src/test/fuzz/fuzz_diff.c @@ -21,6 +21,7 @@ int fuzz_init(void) { MOCK(consensus_compute_digest, mock_consensus_compute_digest_); + MOCK(consensus_compute_digest_as_signed, mock_consensus_compute_digest_); return 0; }
@@ -28,6 +29,7 @@ int fuzz_cleanup(void) { UNMOCK(consensus_compute_digest); + UNMOCK(consensus_compute_digest_as_signed); return 0; }
diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c index 2f826b5..2e78672 100644 --- a/src/test/test_consdiff.c +++ b/src/test/test_consdiff.c @@ -907,7 +907,7 @@ test_consdiff_gen_diff(void *arg) );
tt_int_op(0, OP_EQ, - consensus_compute_digest(cons1_str, &digests1)); + consensus_compute_digest_as_signed(cons1_str, &digests1)); tt_int_op(0, OP_EQ, consensus_compute_digest(cons2_str, &digests2));
@@ -926,7 +926,7 @@ test_consdiff_gen_diff(void *arg) "directory-signature foo bar\nbar\n" ); tt_int_op(0, OP_EQ, - consensus_compute_digest(cons1_str, &digests1)); + consensus_compute_digest_as_signed(cons1_str, &digests1)); smartlist_clear(cons1); consensus_split_lines(cons1, cons1_str, area); diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area); @@ -935,7 +935,7 @@ test_consdiff_gen_diff(void *arg) tt_assert(line_str_eq(smartlist_get(diff, 0), "network-status-diff-version 1")); tt_assert(line_str_eq(smartlist_get(diff, 1), "hash " - "06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4 " + "95D70F5A3CC65F920AA8B44C4563D7781A082674329661884E19E94B79D539C2 " "7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1")); tt_assert(line_str_eq(smartlist_get(diff, 2), "3,4d")); tt_assert(line_str_eq(smartlist_get(diff, 3), "1a"));