[or-cvs] [tor/master] Parse detached signatures and microdesc networkstatuses correctly.

Nick Mathewson nickm at seul.org
Mon Oct 19 04:48:28 UTC 2009


Author: Nick Mathewson <nickm at torproject.org>
Date: Wed, 23 Sep 2009 15:23:04 -0400
Subject: Parse detached signatures and microdesc networkstatuses correctly.
Commit: a19981725d167927d32ef2a31c7a7968be3d95b6

---
 src/or/networkstatus.c |   12 +++++
 src/or/or.h            |    1 +
 src/or/routerparse.c   |  115 ++++++++++++++++++++++++++++++++++++------------
 src/test/test_dir.c    |   87 +++++++++++++++++++++++++++++-------
 4 files changed, 170 insertions(+), 45 deletions(-)

diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 6167265..93a21eb 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1983,6 +1983,18 @@ networkstatus_get_flavor_name(consensus_flavor_t flav)
   }
 }
 
+/** DOCDOC return -1 on unknown */
+int
+networkstatus_parse_flavor_name(const char *flavname)
+{
+  if (!strcmp(flavname, "ns"))
+    return FLAV_NS;
+  else if (!strcmp(flavname, "microdesc"))
+    return FLAV_MICRODESC;
+  else
+    return -1;
+}
+
 /** If <b>question</b> is a string beginning with "ns/" in a format the
  * control interface expects for a GETINFO question, set *<b>answer</b> to a
  * newly-allocated string containing networkstatus lines for the appropriate
diff --git a/src/or/or.h b/src/or/or.h
index d9b10c6..a92b0b5 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -4211,6 +4211,7 @@ int32_t networkstatus_get_param(networkstatus_t *ns, const char *param_name,
 int getinfo_helper_networkstatus(control_connection_t *conn,
                                  const char *question, char **answer);
 const char *networkstatus_get_flavor_name(consensus_flavor_t flav);
+int networkstatus_parse_flavor_name(const char *flavname);
 void document_signature_free(document_signature_t *sig);
 document_signature_t *document_signature_dup(const document_signature_t *sig);
 void networkstatus_free_all(void);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 21fe5f7..c6278c6 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -321,7 +321,7 @@ static token_rule_t extrainfo_token_table[] = {
  * documents. */
 static token_rule_t rtrstatus_token_table[] = {
   T01("p",                   K_P,               CONCAT_ARGS, NO_OBJ ),
-  T1( "r",                   K_R,                   GE(8),   NO_OBJ ),
+  T1( "r",                   K_R,                   GE(7),   NO_OBJ ),
   T1( "s",                   K_S,                   ARGS,    NO_OBJ ),
   T01("v",                   K_V,               CONCAT_ARGS, NO_OBJ ),
   T01("w",                   K_W,                   ARGS,    NO_OBJ ),
@@ -1900,22 +1900,29 @@ find_start_of_next_routerstatus(const char *s)
  * If <b>consensus_method</b> is nonzero, this routerstatus is part of a
  * consensus, and we should parse it according to the method used to
  * make that consensus.
+ *
+ * DOCDOC flav
  **/
 static routerstatus_t *
 routerstatus_parse_entry_from_string(memarea_t *area,
                                      const char **s, smartlist_t *tokens,
                                      networkstatus_t *vote,
                                      vote_routerstatus_t *vote_rs,
-                                     int consensus_method)
+                                     int consensus_method,
+                                     consensus_flavor_t flav)
 {
   const char *eos, *s_dup = *s;
   routerstatus_t *rs = NULL;
   directory_token_t *tok;
   char timebuf[ISO_TIME_LEN+1];
   struct in_addr in;
+  int offset = 0;
   tor_assert(tokens);
   tor_assert(bool_eq(vote, vote_rs));
 
+  if (!consensus_method)
+    flav = FLAV_NS;
+
   eos = find_start_of_next_routerstatus(*s);
 
   if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) {
@@ -1927,7 +1934,15 @@ routerstatus_parse_entry_from_string(memarea_t *area,
     goto err;
   }
   tok = find_by_keyword(tokens, K_R);
-  tor_assert(tok->n_args >= 8);
+  tor_assert(tok->n_args >= 7);
+  if (flav == FLAV_NS) {
+    if (tok->n_args < 8) {
+      log_warn(LD_DIR, "Too few arguments to r");
+      goto err;
+    }
+  } else {
+    offset = -1;
+  }
   if (vote_rs) {
     rs = &vote_rs->status;
   } else {
@@ -1948,29 +1963,34 @@ routerstatus_parse_entry_from_string(memarea_t *area,
     goto err;
   }
 
-  if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
-    log_warn(LD_DIR, "Error decoding descriptor digest %s",
-             escaped(tok->args[2]));
-    goto err;
+  if (flav == FLAV_NS) {
+    if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
+      log_warn(LD_DIR, "Error decoding descriptor digest %s",
+               escaped(tok->args[2]));
+      goto err;
+    }
   }
 
   if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
-                   tok->args[3], tok->args[4]) < 0 ||
+                   tok->args[3+offset], tok->args[4+offset]) < 0 ||
       parse_iso_time(timebuf, &rs->published_on)<0) {
-    log_warn(LD_DIR, "Error parsing time '%s %s'",
-             tok->args[3], tok->args[4]);
+    log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]",
+             tok->args[3+offset], tok->args[4+offset],
+             offset, (int)flav);
     goto err;
   }
 
-  if (tor_inet_aton(tok->args[5], &in) == 0) {
+  if (tor_inet_aton(tok->args[5+offset], &in) == 0) {
     log_warn(LD_DIR, "Error parsing router address in network-status %s",
-             escaped(tok->args[5]));
+             escaped(tok->args[5+offset]));
     goto err;
   }
   rs->addr = ntohl(in.s_addr);
 
-  rs->or_port =(uint16_t) tor_parse_long(tok->args[6],10,0,65535,NULL,NULL);
-  rs->dir_port = (uint16_t) tor_parse_long(tok->args[7],10,0,65535,NULL,NULL);
+  rs->or_port = (uint16_t) tor_parse_long(tok->args[6+offset],
+                                         10,0,65535,NULL,NULL);
+  rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset],
+                                           10,0,65535,NULL,NULL);
 
   tok = find_opt_by_keyword(tokens, K_S);
   if (tok && vote) {
@@ -2267,7 +2287,7 @@ networkstatus_v2_parse_from_string(const char *s)
   while (!strcmpstart(s, "r ")) {
     routerstatus_t *rs;
     if ((rs = routerstatus_parse_entry_from_string(area, &s, tokens,
-                                                   NULL, NULL, 0)))
+                                                   NULL, NULL, 0, 0)))
       smartlist_add(ns->entries, rs);
   }
   smartlist_sort(ns->entries, compare_routerstatus_entries);
@@ -2329,6 +2349,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
   struct in_addr in;
   int i, inorder, n_signatures = 0;
   memarea_t *area = NULL, *rs_area = NULL;
+  consensus_flavor_t flav = FLAV_NS;
+
   tor_assert(s);
 
   if (eos_out)
@@ -2352,6 +2374,22 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
   ns = tor_malloc_zero(sizeof(networkstatus_t));
   memcpy(&ns->digests, &ns_digests, sizeof(ns_digests));
 
+  tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
+  tor_assert(tok);
+  if (tok->n_args > 1) {
+    int flavor = networkstatus_parse_flavor_name(tok->args[1]);
+    if (flavor < 0) {
+      log_warn(LD_DIR, "Can't parse document with unknown flavor %s",
+               escaped(tok->args[2]));
+      goto err;
+    }
+    ns->flavor = flav = flavor;
+  }
+  if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
+    log_warn(LD_DIR, "Flavor found on non-consenus networkstatus.");
+    goto err;
+  }
+
   if (ns_type != NS_TYPE_CONSENSUS) {
     const char *end_of_cert = NULL;
     if (!(cert = strstr(s, "\ndir-key-certificate-version")))
@@ -2598,7 +2636,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
     if (ns->type != NS_TYPE_CONSENSUS) {
       vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
       if (routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, ns,
-                                               rs, 0))
+                                               rs, 0, 0))
         smartlist_add(ns->routerstatus_list, rs);
       else {
         tor_free(rs->version);
@@ -2608,7 +2646,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
       routerstatus_t *rs;
       if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens,
                                                      NULL, NULL,
-                                                     ns->consensus_method)))
+                                                     ns->consensus_method,
+                                                     flav)))
         smartlist_add(ns->routerstatus_list, rs);
     }
   }
@@ -2645,10 +2684,29 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
     char declared_identity[DIGEST_LEN];
     networkstatus_voter_info_t *v;
     document_signature_t *sig;
+    const char *id_hexdigest = NULL;
+    const char *sk_hexdigest = NULL;
+    digest_algorithm_t alg = DIGEST_SHA1;
     tok = _tok;
     if (tok->tp != K_DIRECTORY_SIGNATURE)
       continue;
     tor_assert(tok->n_args >= 2);
+    if (tok->n_args == 2) {
+      id_hexdigest = tok->args[0];
+      sk_hexdigest = tok->args[1];
+    } else {
+      const char *algname = tok->args[0];
+      int a;
+      id_hexdigest = tok->args[1];
+      sk_hexdigest = tok->args[2];
+      a = crypto_digest_algorithm_parse_name(algname);
+      if (a<0) {
+        log_warn(LD_DIR, "Unknown digest algorithm %s; skipping",
+                 escaped(algname));
+        continue;
+      }
+      alg = a;
+    }
 
     if (!tok->object_type ||
         strcmp(tok->object_type, "SIGNATURE") ||
@@ -2657,11 +2715,11 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
       goto err;
     }
 
-    if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
+    if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
         base16_decode(declared_identity, sizeof(declared_identity),
-                      tok->args[0], HEX_DIGEST_LEN) < 0) {
+                      id_hexdigest, HEX_DIGEST_LEN) < 0) {
       log_warn(LD_DIR, "Error decoding declared identity %s in "
-               "network-status vote.", escaped(tok->args[0]));
+               "network-status vote.", escaped(id_hexdigest));
       goto err;
     }
     if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
@@ -2671,12 +2729,12 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
     }
     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 ||
+    sig->alg = alg;
+    if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
         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]));
+                      sk_hexdigest, HEX_DIGEST_LEN) < 0) {
+      log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
+               "network-status vote.", escaped(sk_hexdigest));
       tor_free(sig);
       goto err;
     }
@@ -2716,7 +2774,6 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
       }
       sig->signature = tor_memdup(tok->object_body, tok->object_size);
       sig->signature_len = (int) tok->object_size;
-
     }
     smartlist_add(v->sigs, sig);
 
@@ -2950,10 +3007,10 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
                "network-status vote.", escaped(id_hexdigest));
       goto err;
     }
-    if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
+    if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
         base16_decode(sk_digest, sizeof(sk_digest),
                       sk_hexdigest, HEX_DIGEST_LEN) < 0) {
-      log_warn(LD_DIR, "Error decoding declared digest %s in "
+      log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
                "network-status vote.", escaped(sk_hexdigest));
       goto err;
     }
@@ -2974,7 +3031,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
     }
 
     sig = tor_malloc_zero(sizeof(document_signature_t));
-    sig->alg = DIGEST_SHA1;
+    sig->alg = alg;
     memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
     memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN);
     if (tok->object_size >= INT_MAX) {
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 13b46c6..68dbbb4 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -559,16 +559,18 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
   return r;
 }
 
-/** Helper: get a detached signatures document for a single FLAV_NS
- * consensus. */
+/** Helper: get a detached signatures document for one or two
+ * consensuses. */
 static char *
-get_detached_sigs(networkstatus_t *ns)
+get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2)
 {
   char *r;
   smartlist_t *sl;
   tor_assert(ns && ns->flavor == FLAV_NS);
   sl = smartlist_create();
   smartlist_add(sl,ns);
+  if (ns2)
+    smartlist_add(sl,ns2);
   r = networkstatus_get_detached_signatures(sl);
   smartlist_free(sl);
   return r;
@@ -587,7 +589,8 @@ test_dir_v3_networkstatus(void)
   time_t now = time(NULL);
   networkstatus_voter_info_t *voter;
   document_signature_t *sig;
-  networkstatus_t *vote=NULL, *v1=NULL, *v2=NULL, *v3=NULL, *con=NULL;
+  networkstatus_t *vote=NULL, *v1=NULL, *v2=NULL, *v3=NULL, *con=NULL,
+    *con_md=NULL;
   vote_routerstatus_t *vrs;
   routerstatus_t *rs;
   char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp;
@@ -596,7 +599,9 @@ test_dir_v3_networkstatus(void)
   /* For generating the two other consensuses. */
   char *detached_text1=NULL, *detached_text2=NULL;
   char *consensus_text2=NULL, *consensus_text3=NULL;
-  networkstatus_t *con2=NULL, *con3=NULL;
+  char *consensus_text_md2=NULL, *consensus_text_md3=NULL;
+  char *consensus_text_md=NULL;
+  networkstatus_t *con2=NULL, *con_md2=NULL, *con3=NULL, *con_md3=NULL;
   ns_detached_signatures_t *dsig1=NULL, *dsig2=NULL;
 
   /* Parse certificates and keys. */
@@ -882,6 +887,17 @@ test_dir_v3_networkstatus(void)
   test_assert(con);
   //log_notice(LD_GENERAL, "<<%s>>\n<<%s>>\n<<%s>>\n",
   //           v1_text, v2_text, v3_text);
+  consensus_text_md = networkstatus_compute_consensus(votes, 3,
+                                                   cert3->identity_key,
+                                                   sign_skey_3,
+                                                   "AAAAAAAAAAAAAAAAAAAA",
+                                                   sign_skey_leg1,
+                                                   FLAV_MICRODESC);
+  test_assert(consensus_text_md);
+  con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL,
+                                                NS_TYPE_CONSENSUS);
+  test_assert(con_md);
+  test_eq(con_md->flavor, FLAV_MICRODESC);
 
   /* Check consensus contents. */
   test_assert(con->type == NS_TYPE_CONSENSUS);
@@ -956,19 +972,11 @@ test_dir_v3_networkstatus(void)
   test_assert(rs->is_valid);
   test_assert(!rs->is_named);
   /* XXXX check version */
-  // x231
-  // x213
 
   /* Check signatures.  the first voter is a pseudo-entry with a legacy key.
    * The second one hasn't signed.  The fourth one has signed: validate it. */
   voter = smartlist_get(con->voters, 1);
   test_eq(smartlist_len(voter->sigs), 0);
-#if 0
-  sig = smartlist_get(voter->sigs, 1);
-  test_assert(!sig->signature);
-  test_assert(!sig->good_signature);
-  test_assert(!sig->bad_signature);
-#endif
 
   voter = smartlist_get(con->voters, 3);
   test_eq(smartlist_len(voter->sigs), 1);
@@ -990,26 +998,45 @@ test_dir_v3_networkstatus(void)
                                                       cert2->identity_key,
                                                       sign_skey_2, NULL,NULL,
                                                       FLAV_NS);
+    consensus_text_md2 = networkstatus_compute_consensus(votes, 3,
+                                                      cert2->identity_key,
+                                                      sign_skey_2, NULL,NULL,
+                                                      FLAV_MICRODESC);
     smartlist_shuffle(votes);
     consensus_text3 = networkstatus_compute_consensus(votes, 3,
                                                       cert1->identity_key,
                                                       sign_skey_1, NULL,NULL,
                                                       FLAV_NS);
+    consensus_text_md3 = networkstatus_compute_consensus(votes, 3,
+                                                      cert1->identity_key,
+                                                      sign_skey_1, NULL,NULL,
+                                                      FLAV_MICRODESC);
     test_assert(consensus_text2);
     test_assert(consensus_text3);
+    test_assert(consensus_text_md2);
+    test_assert(consensus_text_md3);
     con2 = networkstatus_parse_vote_from_string(consensus_text2, NULL,
                                                 NS_TYPE_CONSENSUS);
     con3 = networkstatus_parse_vote_from_string(consensus_text3, NULL,
                                                 NS_TYPE_CONSENSUS);
+    con_md2 = networkstatus_parse_vote_from_string(consensus_text_md2, NULL,
+                                                NS_TYPE_CONSENSUS);
+    con_md3 = networkstatus_parse_vote_from_string(consensus_text_md3, NULL,
+                                                NS_TYPE_CONSENSUS);
     test_assert(con2);
     test_assert(con3);
+    test_assert(con_md2);
+    test_assert(con_md3);
 
     /* All three should have the same digest. */
     test_memeq(&con->digests, &con2->digests, sizeof(digests_t));
     test_memeq(&con->digests, &con3->digests, sizeof(digests_t));
 
+    test_memeq(&con_md->digests, &con_md2->digests, sizeof(digests_t));
+    test_memeq(&con_md->digests, &con_md3->digests, sizeof(digests_t));
+
     /* Extract a detached signature from con3. */
-    detached_text1 = get_detached_sigs(con3);
+    detached_text1 = get_detached_sigs(con3, con_md3);
     tor_assert(detached_text1);
     /* Try to parse it. */
     dsig1 = networkstatus_parse_detached_signatures(detached_text1, NULL);
@@ -1024,6 +1051,11 @@ test_dir_v3_networkstatus(void)
       test_assert(dsig_digests);
       test_memeq(dsig_digests->d[DIGEST_SHA1], con3->digests.d[DIGEST_SHA1],
                  DIGEST_LEN);
+      dsig_digests = strmap_get(dsig1->digests, "microdesc");
+      test_assert(dsig_digests);
+      test_memeq(dsig_digests->d[DIGEST_SHA256],
+                 con_md3->digests.d[DIGEST_SHA256],
+                 DIGEST256_LEN);
     }
     {
       smartlist_t *dsig_signatures = strmap_get(dsig1->signatures, "ns");
@@ -1032,13 +1064,24 @@ test_dir_v3_networkstatus(void)
       sig = smartlist_get(dsig_signatures, 0);
       test_memeq(sig->identity_digest, cert1->cache_info.identity_digest,
                  DIGEST_LEN);
+      test_eq(sig->alg, DIGEST_SHA1);
+
+      dsig_signatures = strmap_get(dsig1->signatures, "microdesc");
+      test_assert(dsig_signatures);
+      test_eq(1, smartlist_len(dsig_signatures));
+      sig = smartlist_get(dsig_signatures, 0);
+      test_memeq(sig->identity_digest, cert1->cache_info.identity_digest,
+                 DIGEST_LEN);
+      test_eq(sig->alg, DIGEST_SHA256);
     }
 
     /* Try adding it to con2. */
-    detached_text2 = get_detached_sigs(con2);
+    detached_text2 = get_detached_sigs(con2,con_md2);
     test_eq(1, networkstatus_add_detached_signatures(con2, dsig1, &msg));
     tor_free(detached_text2);
-    detached_text2 = get_detached_sigs(con2);
+    test_eq(1, networkstatus_add_detached_signatures(con_md2, dsig1, &msg));
+    tor_free(detached_text2);
+    detached_text2 = get_detached_sigs(con2,con_md2);
     //printf("\n<%s>\n", detached_text2);
     dsig2 = networkstatus_parse_detached_signatures(detached_text2, NULL);
     test_assert(dsig2);
@@ -1052,6 +1095,9 @@ test_dir_v3_networkstatus(void)
     */
     test_eq(2,
             smartlist_len((smartlist_t*)strmap_get(dsig2->signatures, "ns")));
+    test_eq(2,
+            smartlist_len((smartlist_t*)strmap_get(dsig2->signatures,
+                                                   "microdesc")));
 
     /* Try adding to con2 twice; verify that nothing changes. */
     test_eq(0, networkstatus_add_detached_signatures(con2, dsig1, &msg));
@@ -1075,6 +1121,7 @@ test_dir_v3_networkstatus(void)
   tor_free(v2_text);
   tor_free(v3_text);
   tor_free(consensus_text);
+  tor_free(consensus_text_md);
 
   if (vote)
     networkstatus_vote_free(vote);
@@ -1086,6 +1133,8 @@ test_dir_v3_networkstatus(void)
     networkstatus_vote_free(v3);
   if (con)
     networkstatus_vote_free(con);
+  if (con_md)
+    networkstatus_vote_free(con_md);
   if (sign_skey_1)
     crypto_free_pk_env(sign_skey_1);
   if (sign_skey_2)
@@ -1103,12 +1152,18 @@ test_dir_v3_networkstatus(void)
 
   tor_free(consensus_text2);
   tor_free(consensus_text3);
+  tor_free(consensus_text_md2);
+  tor_free(consensus_text_md3);
   tor_free(detached_text1);
   tor_free(detached_text2);
   if (con2)
     networkstatus_vote_free(con2);
   if (con3)
     networkstatus_vote_free(con3);
+  if (con_md2)
+    networkstatus_vote_free(con_md2);
+  if (con_md3)
+    networkstatus_vote_free(con_md3);
   if (dsig1)
     ns_detached_signatures_free(dsig1);
   if (dsig2)
-- 
1.5.6.5




More information about the tor-commits mailing list