bug#22143/prop#140: identify input diffs by their digest-as-signed

See may 3 changes to prop140 for more background.
This commit is contained in:
Nick Mathewson 2017-05-03 11:48:08 -04:00
parent 77d9dd39c3
commit 5acddbbbf7
6 changed files with 77 additions and 13 deletions

View File

@ -91,6 +91,18 @@ consensus_compute_digest,(const char *cons,
return r; 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 */ /** 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 /* This is a separate, mockable function so that we can override it when
* fuzzing. */ * fuzzing. */
@ -1250,7 +1262,7 @@ consensus_diff_generate(const char *cons1,
int r1, r2; int r1, r2;
char *result = NULL; char *result = NULL;
r1 = consensus_compute_digest(cons1, &d1); r1 = consensus_compute_digest_as_signed(cons1, &d1);
r2 = consensus_compute_digest(cons2, &d2); r2 = consensus_compute_digest(cons2, &d2);
if (BUG(r1 < 0 || r2 < 0)) if (BUG(r1 < 0 || r2 < 0))
return NULL; // LCOV_EXCL_LINE return NULL; // LCOV_EXCL_LINE
@ -1291,7 +1303,7 @@ consensus_diff_apply(const char *consensus,
char *result = NULL; char *result = NULL;
memarea_t *area = memarea_new(); memarea_t *area = memarea_new();
r1 = consensus_compute_digest(consensus, &d1); r1 = consensus_compute_digest_as_signed(consensus, &d1);
if (BUG(r1 < 0)) if (BUG(r1 < 0))
return NULL; // LCOV_EXCL_LINE return NULL; // LCOV_EXCL_LINE

View File

@ -84,6 +84,9 @@ STATIC int line_str_eq(const cdline_t *a, const char *b);
MOCK_DECL(STATIC int, MOCK_DECL(STATIC int,
consensus_compute_digest,(const char *cons, consensus_compute_digest,(const char *cons,
consensus_digest_t *digest_out)); 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, MOCK_DECL(STATIC int,
consensus_digest_eq,(const uint8_t *d1, consensus_digest_eq,(const uint8_t *d1,
const uint8_t *d2)); const uint8_t *d2));

View File

@ -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, static int router_get_hash_impl_helper(const char *s, size_t s_len,
const char *start_str, const char *start_str,
const char *end_str, char end_c, const char *end_str, char end_c,
int log_severity,
const char **start_out, const char **end_out); const char **start_out, const char **end_out);
static int router_get_hash_impl(const char *s, size_t s_len, char *digest, static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
const char *start_str, const char *end_str, 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); 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 /** Set <b>digests</b> to all the digests of the consensus document in
* <b>s</b> */ * <b>s</b> */
int 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 ", if (router_get_hash_impl_helper(s, end-s, "router ",
"\nrouter-sig-ed25519", "\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"); log_warn(LD_DIR, "Can't find ed25519-signed portion of descriptor");
goto err; 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 ", if (router_get_hash_impl_helper(s, end-s, "extra-info ",
"\nrouter-sig-ed25519", "\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"); log_warn(LD_DIR, "Can't find ed25519-signed portion of extrainfo");
goto err; goto err;
} }
@ -4471,16 +4509,18 @@ static int
router_get_hash_impl_helper(const char *s, size_t s_len, router_get_hash_impl_helper(const char *s, size_t s_len,
const char *start_str, const char *start_str,
const char *end_str, char end_c, const char *end_str, char end_c,
int log_severity,
const char **start_out, const char **end_out) const char **start_out, const char **end_out)
{ {
const char *start, *end; const char *start, *end;
start = tor_memstr(s, s_len, start_str); start = tor_memstr(s, s_len, start_str);
if (!start) { 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; return -1;
} }
if (start != s && *(start-1) != '\n') { 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", "first occurrence of \"%s\" is not at the start of a line",
start_str); start_str);
return -1; 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), end = tor_memstr(start+strlen(start_str),
s_len - (start-s) - strlen(start_str), end_str); s_len - (start-s) - strlen(start_str), end_str);
if (!end) { 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; return -1;
} }
end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str)); end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
if (!end) { if (!end) {
log_warn(LD_DIR,"couldn't find EOL"); log_fn(log_severity,LD_DIR,
"couldn't find EOL");
return -1; return -1;
} }
++end; ++end;
@ -4517,7 +4559,7 @@ router_get_hash_impl(const char *s, size_t s_len, char *digest,
digest_algorithm_t alg) digest_algorithm_t alg)
{ {
const char *start=NULL, *end=NULL; 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) &start,&end)<0)
return -1; 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 *end_str, char end_c)
{ {
const char *start=NULL, *end=NULL; 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) &start,&end)<0)
return -1; return -1;

View File

@ -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_dir_hash(const char *s, char *digest);
int router_get_networkstatus_v3_hashes(const char *s, int router_get_networkstatus_v3_hashes(const char *s,
common_digests_t *digests); 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); int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest);
#define DIROBJ_MAX_SIG_LEN 256 #define DIROBJ_MAX_SIG_LEN 256
char *router_get_dirobj_signature(const char *digest, char *router_get_dirobj_signature(const char *digest,

View File

@ -21,6 +21,7 @@ int
fuzz_init(void) fuzz_init(void)
{ {
MOCK(consensus_compute_digest, mock_consensus_compute_digest_); MOCK(consensus_compute_digest, mock_consensus_compute_digest_);
MOCK(consensus_compute_digest_as_signed, mock_consensus_compute_digest_);
return 0; return 0;
} }
@ -28,6 +29,7 @@ int
fuzz_cleanup(void) fuzz_cleanup(void)
{ {
UNMOCK(consensus_compute_digest); UNMOCK(consensus_compute_digest);
UNMOCK(consensus_compute_digest_as_signed);
return 0; return 0;
} }

View File

@ -907,7 +907,7 @@ test_consdiff_gen_diff(void *arg)
); );
tt_int_op(0, OP_EQ, 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, tt_int_op(0, OP_EQ,
consensus_compute_digest(cons2_str, &digests2)); consensus_compute_digest(cons2_str, &digests2));
@ -926,7 +926,7 @@ test_consdiff_gen_diff(void *arg)
"directory-signature foo bar\nbar\n" "directory-signature foo bar\nbar\n"
); );
tt_int_op(0, OP_EQ, tt_int_op(0, OP_EQ,
consensus_compute_digest(cons1_str, &digests1)); consensus_compute_digest_as_signed(cons1_str, &digests1));
smartlist_clear(cons1); smartlist_clear(cons1);
consensus_split_lines(cons1, cons1_str, area); consensus_split_lines(cons1, cons1_str, area);
diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, 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), tt_assert(line_str_eq(smartlist_get(diff, 0),
"network-status-diff-version 1")); "network-status-diff-version 1"));
tt_assert(line_str_eq(smartlist_get(diff, 1), "hash " tt_assert(line_str_eq(smartlist_get(diff, 1), "hash "
"06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4 " "95D70F5A3CC65F920AA8B44C4563D7781A082674329661884E19E94B79D539C2 "
"7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1")); "7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1"));
tt_assert(line_str_eq(smartlist_get(diff, 2), "3,4d")); tt_assert(line_str_eq(smartlist_get(diff, 2), "3,4d"));
tt_assert(line_str_eq(smartlist_get(diff, 3), "1a")); tt_assert(line_str_eq(smartlist_get(diff, 3), "1a"));