Browse Source

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

See may 3 changes to prop140 for more background.
Nick Mathewson 7 years ago
parent
commit
5acddbbbf7
6 changed files with 77 additions and 13 deletions
  1. 14 2
      src/or/consdiff.c
  2. 3 0
      src/or/consdiff.h
  3. 50 8
      src/or/routerparse.c
  4. 5 0
      src/or/routerparse.h
  5. 2 0
      src/test/fuzz/fuzz_diff.c
  6. 3 3
      src/test/test_consdiff.c

+ 14 - 2
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
 

+ 3 - 0
src/or/consdiff.h

@@ -84,6 +84,9 @@ STATIC int line_str_eq(const cdline_t *a, const char *b);
 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));

+ 50 - 8
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;
 

+ 5 - 0
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,

+ 2 - 0
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;
 }
 

+ 3 - 3
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"));