[or-cvs] r10491: Adapt code to parse v3 networkstatus votes so it can also pa (in tor/trunk: . doc doc/spec src/or)

nickm at seul.org nickm at seul.org
Mon Jun 4 22:29:00 UTC 2007


Author: nickm
Date: 2007-06-04 18:29:00 -0400 (Mon, 04 Jun 2007)
New Revision: 10491

Modified:
   tor/trunk/
   tor/trunk/doc/TODO
   tor/trunk/doc/spec/dir-spec.txt
   tor/trunk/src/or/dirserv.c
   tor/trunk/src/or/dirvote.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/routerparse.c
Log:
 r13250 at catbus:  nickm | 2007-06-04 18:28:55 -0400
 Adapt code to parse v3 networkstatus votes so it can also parse a consensus.  Make networkstatus_vote_t the catch-all type for votes and conensuses.  Correct/clarify the second argument to directory-signature.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r13250] on 8246c3cf-6607-4228-993b-4d95d33730f1

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-06-04 19:54:02 UTC (rev 10490)
+++ tor/trunk/doc/TODO	2007-06-04 22:29:00 UTC (rev 10491)
@@ -66,7 +66,7 @@
       - Get authorities voting
         . Implement parsing for new document formats
           o Parse key certificates
-          - Parse votes and consensuses
+          o Parse votes and consensuses
           - Unit tests for above
         . Code to manage key certificates
           o Generate certificates
@@ -77,7 +77,7 @@
           o Avoid double-checking signatures every time we get a vote.
           - Warn about expired stuff.
         o Code to generate votes
-        - Code to generate consensus from a list of votes
+        o Code to generate consensus from a list of votes
         - Add a signature to a consensus.
         - Code to check signatures on a consensus
         - Push/pull documents as appropriate.

Modified: tor/trunk/doc/spec/dir-spec.txt
===================================================================
--- tor/trunk/doc/spec/dir-spec.txt	2007-06-04 19:54:02 UTC (rev 10490)
+++ tor/trunk/doc/spec/dir-spec.txt	2007-06-04 22:29:00 UTC (rev 10491)
@@ -759,10 +759,10 @@
         [Exactly once, at start]
 
         Describes this authority.  The nickname is a convenient identifier
-        for the authority.  The identity is an uppercase hex fingerprint of the
-        authority's current identity key.  The address is the server's
-        hostname.  The IP is the server's current IP address, and dirport
-        is its current directory port.
+        for the authority.  The identity is an uppercase hex fingerprint of
+        the authority's current (v3 authority) identity key.  The address is
+        the server's hostname.  The IP is the server's current IP address,
+        and dirport is its current directory port. XXXXorport
 
     "contact" SP string NL
 
@@ -788,13 +788,6 @@
 
         As in the authority section of a vote.
 
-    "fingerprint" SP fingerprint NL
-
-        [Exactly once.]
-
-        An upper-case hex fingerprint, without spaces, of the authority's
-        current identity key.
-
     "vote-digest" SP digest NL
 
         [Exactly once.]
@@ -861,17 +854,16 @@
    The signature section contains the following item, which appears
    Exactly Once for a vote, and At Least Once for a consensus.
 
-    "directory-signature" SP identity SP digest NL Signature
+    "directory-signature" SP identity SP signing-key-digest NL Signature
 
         This is a signature of the status document, with the initial item
         "network-status-version", and the signature item
-        "directory-signature", using the signing key.  (In this case, we
-        take the hash through the _space_ after directory-signature, not
-        the newline: this ensures that all authorities sign the same
-        thing.)  "identity" is the hex-encoded digest of the authority
-        identity key of the signing authority, and "digest" is the
-        hex-encoded digest of the current authority signing key of the
-        signing authority.
+        "directory-signature", using the signing key.  (In this case, we take
+        the hash through the _space_ after directory-signature, not the
+        newline: this ensures that all authorities sign the same thing.)
+        "identity" is the hex-encoded digest of the authority identity key of
+        the signing authority, and "signing-key-digest" is the hex-encoded
+        digest of the current authority signing key of the signing authority.
 
 3.3. Deciding how to vote.
 

Modified: tor/trunk/src/or/dirserv.c
===================================================================
--- tor/trunk/src/or/dirserv.c	2007-06-04 19:54:02 UTC (rev 10490)
+++ tor/trunk/src/or/dirserv.c	2007-06-04 22:29:00 UTC (rev 10491)
@@ -1897,19 +1897,19 @@
     }
     outp += strlen(outp);
   } else {
-    char hex_digest[HEX_DIGEST_LEN+1];
-    if (tor_snprintf(outp, endp-outp, "directory-signature %s ",
-                     fingerprint)<0) {
+    char signing_key_fingerprint[FINGERPRINT_LEN+1];
+    if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
       log_warn(LD_BUG, "Unable to start signature line.");
       goto done;
     }
-    if (router_get_networkstatus_v3_hash(status, digest)<0) {
-      log_warn(LD_BUG, "Unable to hash network status vote");
+    outp += strlen(outp);
+
+    if (crypto_pk_get_fingerprint(private_key, signing_key_fingerprint, 0)<0) {
+      log_warn(LD_BUG, "Unable to get fingerprint for signing key");
       goto done;
     }
-    base16_encode(hex_digest, sizeof(hex_digest), digest, DIGEST_LEN);
-    outp += strlen(outp);
-    if (tor_snprintf(outp, endp-outp, "%s\n", hex_digest)<0) {
+    if (tor_snprintf(outp, endp-outp, "%s %s\n", fingerprint,
+                     signing_key_fingerprint)<0) {
       log_warn(LD_BUG, "Unable to end signature line.");
       goto done;
     }

Modified: tor/trunk/src/or/dirvote.c
===================================================================
--- tor/trunk/src/or/dirvote.c	2007-06-04 19:54:02 UTC (rev 10490)
+++ tor/trunk/src/or/dirvote.c	2007-06-04 22:29:00 UTC (rev 10491)
@@ -26,9 +26,15 @@
       tor_free(ns->known_flags[i]);
     tor_free(ns->known_flags);
   }
-  tor_free(ns->nickname);
-  tor_free(ns->address);
-  tor_free(ns->contact);
+  if (ns->voters) {
+    SMARTLIST_FOREACH(ns->voters, networkstatus_voter_info_t *, voter,
+    {
+      tor_free(voter->nickname);
+      tor_free(voter->address);
+      tor_free(voter->contact);
+    });
+    smartlist_free(ns->voters);
+  }
   if (ns->cert)
     authority_cert_free(ns->cert);
 
@@ -47,6 +53,19 @@
 }
 
 /** DOCDOC */
+networkstatus_voter_info_t *
+networkstatus_get_voter_by_id(networkstatus_vote_t *vote,
+                              const char *identity)
+{
+  if (!vote || !vote->voters)
+    return NULL;
+  SMARTLIST_FOREACH(vote->voters, networkstatus_voter_info_t *, voter,
+    if (!memcmp(voter->identity_digest, identity, DIGEST_LEN))
+      return voter);
+  return NULL;
+}
+
+/** DOCDOC */
 static int
 _compare_times(const void **_a, const void **_b)
 {
@@ -92,12 +111,23 @@
   return *(time_t*)smartlist_get(ints, idx);
 }
 
+static networkstatus_voter_info_t *
+get_voter(const networkstatus_vote_t *vote)
+{
+  tor_assert(vote);
+  tor_assert(vote->is_vote);
+  tor_assert(vote->voters);
+  tor_assert(smartlist_len(vote->voters) == 1);
+  return smartlist_get(vote->voters, 0);
+}
+
 /** DOCDOC */
 static int
 _compare_votes_by_authority_id(const void **_a, const void **_b)
 {
   const networkstatus_vote_t *a = *_a, *b = *_b;
-  return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
+  return memcmp(get_voter(a)->identity_digest,
+                get_voter(b)->identity_digest, DIGEST_LEN);
 }
 
 /** DOCDOC */
@@ -193,7 +223,8 @@
       ++cur_n;
     } else {
       if (cur_n > most_n ||
-          (cur && cur_n == most_n && cur->status.published_on > most_published)) {
+          (cur && cur_n == most_n &&
+           cur->status.published_on > most_published)) {
         most = cur;
         most_n = cur_n;
         most_published = cur->status.published_on;
@@ -246,7 +277,6 @@
   }
   /* XXXX020 somebody needs to check vote authority. It could be this
    * function, it could be somebody else. */
-
   flags = smartlist_create();
 
   /* Compute medians of time-related things, and figure out how many
@@ -363,20 +393,23 @@
     char ip[INET_NTOA_BUF_LEN];
     char fingerprint[HEX_DIGEST_LEN+1];
     char votedigest[HEX_DIGEST_LEN+1];
+    networkstatus_voter_info_t *voter = get_voter(v);
 
-    in.s_addr = htonl(v->addr);
+    in.s_addr = htonl(voter->addr);
     tor_inet_ntoa(&in, ip, sizeof(ip));
-    base16_encode(fingerprint, sizeof(fingerprint), v->identity_digest,
+    base16_encode(fingerprint, sizeof(fingerprint), voter->identity_digest,
                   DIGEST_LEN);
-    base16_encode(votedigest, sizeof(votedigest), v->vote_digest, DIGEST_LEN);
+    base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
+                  DIGEST_LEN);
 
     tor_snprintf(buf, sizeof(buf),
                  "dir-source %s %s %s %s %d %d\n"
                  "contact %s\n"
                  "vote-digest %s\n",
-                 v->nickname, fingerprint, v->address, ip, v->dir_port,
-                    v->or_port,
-                 v->contact,
+                 voter->nickname, fingerprint, voter->address, ip,
+                    voter->dir_port,
+                    voter->or_port,
+                 voter->contact,
                  votedigest);
     smartlist_add(chunks, tor_strdup(buf));
   });
@@ -564,19 +597,21 @@
   {
     char digest[DIGEST_LEN];
     char fingerprint[HEX_DIGEST_LEN+1];
-    char hex_digest[HEX_DIGEST_LEN+1];
+    char signing_key_fingerprint[HEX_DIGEST_LEN+1];
+
     char buf[4096];
     smartlist_add(chunks, tor_strdup("directory-signature "));
 
     /* Compute the hash of the chunks. */
     hash_list_members(digest, chunks);
 
-    /* Get hex stuff as needed. */
-    base16_encode(hex_digest, sizeof(hex_digest), digest, DIGEST_LEN);
+    /* Get the fingerprints */
     crypto_pk_get_fingerprint(identity_key, fingerprint, 0);
+    crypto_pk_get_fingerprint(signing_key, signing_key_fingerprint, 0);
 
     /* add the junk that will go at the end of the line. */
-    tor_snprintf(buf, sizeof(buf), "%s %s\n", hex_digest, fingerprint);
+    tor_snprintf(buf, sizeof(buf), "%s %s\n", fingerprint,
+                 signing_key_fingerprint);
     /* And the signature. */
     /* XXXX020 check return */
     router_append_dirobj_signature(buf, sizeof(buf), digest, signing_key);
@@ -593,3 +628,4 @@
 
   return result;
 }
+

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-06-04 19:54:02 UTC (rev 10490)
+++ tor/trunk/src/or/or.h	2007-06-04 22:29:00 UTC (rev 10491)
@@ -1300,9 +1300,28 @@
   char *version;
 } vote_routerstatus_t;
 
-/** DOCDOC */
+/* DOCDOC */
+typedef struct networkstatus_voter_info_t {
+  char *nickname;
+  char identity_digest[DIGEST_LEN];
+  char *address;
+  uint32_t addr;
+  uint16_t dir_port;
+  uint16_t or_port;
+  char *contact;
+  char vote_digest[DIGEST_LEN]; /* consensus only. */
+  char signing_key_digest[DIGEST_LEN]; /* This part is _not_ signed. */
+
+  char *pending_signature;
+  int pending_signature_len;
+  int bad_signature;
+} networkstatus_voter_info_t;
+
+/*XXXX020 rename to networkstatus_t once it works. */
+/** DOCDOC is vote or consensus. */
 typedef struct networkstatus_vote_t {
-  time_t published;
+  int is_vote;
+  time_t published; /* vote only. */
   time_t valid_after;
   time_t fresh_until;
   time_t valid_until;
@@ -1313,20 +1332,12 @@
   char *server_versions;
   char **known_flags; /* NULL-terminated */
 
-  char *nickname;
-  char identity_digest[DIGEST_LEN];
-  char *address;
-  uint32_t addr;
-  uint16_t dir_port;
-  uint16_t or_port;
+  smartlist_t *voters; /* list of networkstatus_voter_info_t */
 
-  struct authority_cert_t *cert;
+  struct authority_cert_t *cert; /* vote only. */
 
-  char *contact;
-
-  char vote_digest[DIGEST_LEN];
-
-  smartlist_t *routerstatus_list;
+  smartlist_t *routerstatus_list; /* holds vote_routerstatus_t if is_vote,
+                                   * otherwise just routerstatus_t. */
 } networkstatus_vote_t;
 
 /** Contents of a directory of onion routers. */
@@ -2718,6 +2729,9 @@
 char *networkstatus_compute_consensus(smartlist_t *votes,
                                       crypto_pk_env_t *identity_key,
                                       crypto_pk_env_t *signing_key);
+networkstatus_voter_info_t *networkstatus_get_voter_by_id(
+                                       networkstatus_vote_t *vote,
+                                       const char *identity);
 
 /********************************* dns.c ***************************/
 
@@ -3383,7 +3397,8 @@
 void dump_distinct_digest_count(int severity);
 
 networkstatus_t *networkstatus_parse_from_string(const char *s);
-networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s);
+networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s,
+                                                           int is_vote);
 
 void authority_cert_free(authority_cert_t *cert);
 authority_cert_t *authority_cert_parse_from_string(const char *s,

Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c	2007-06-04 19:54:02 UTC (rev 10490)
+++ tor/trunk/src/or/routerparse.c	2007-06-04 22:29:00 UTC (rev 10491)
@@ -311,12 +311,7 @@
 
   END_OF_TABLE
 };
-
-#if 0
-/* XXXX This stuff is commented out for now so we can avoid warnings about
- * unused variables. */
-
-static token_rule_t status_consensus_table[] = {
+static token_rule_t networkstatus_consensus_token_table[] = {
   T1("network-status-version", K_NETWORK_STATUS_VERSION,
                                                    GE(1),       NO_OBJ ),
   T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
@@ -325,26 +320,19 @@
   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
   T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
 
-  CERTIFICATE_MEMBERS
-
   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
 
   T1N("dir-source",          K_DIR_SOURCE,          GE(3),   NO_OBJ ),
-  T1N("fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
   T1N("contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
   T1N("vote-digest",         K_VOTE_DIGEST,         GE(1),   NO_OBJ ),
 
-#if 0
-  T1( "dir-options",         K_DIR_OPTIONS,     ARGS,        NO_OBJ ),
   T1( "known-flags",         K_KNOWN_FLAGS,     CONCAT_ARGS, NO_OBJ ),
-#endif
 
   T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
   T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS,    NO_OBJ ),
 
   END_OF_TABLE
 };
-#endif
 
 static token_rule_t networkstatus_vote_footer_token_table[] = {
   T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
@@ -1786,14 +1774,14 @@
 
 /** DOCDOC */
 networkstatus_vote_t *
-networkstatus_parse_vote_from_string(const char *s)
+networkstatus_parse_vote_from_string(const char *s, int is_vote)
 {
   smartlist_t *tokens = smartlist_create();
   smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
+  networkstatus_voter_info_t *voter = NULL;
   networkstatus_vote_t *ns = NULL;
-  char ns_digest[DIGEST_LEN], declared_identity[DIGEST_LEN],
-    declared_digest[DIGEST_LEN];
-  const char *cert, *end_of_cert = NULL, *end_of_header, *end_of_footer;
+  char ns_digest[DIGEST_LEN];
+  const char *cert, *end_of_header, *end_of_footer;
   directory_token_t *tok;
   int ok;
   struct in_addr in;
@@ -1806,32 +1794,47 @@
 
   end_of_header = find_start_of_next_routerstatus(s);
   if (tokenize_string(s, end_of_header, tokens,
-                      networkstatus_vote_token_table)) {
+                      is_vote ? networkstatus_vote_token_table :
+                                networkstatus_consensus_token_table)) {
     log_warn(LD_DIR, "Error tokenizing network-status vote header.");
     goto err;
   }
 
   ns = tor_malloc_zero(sizeof(networkstatus_vote_t));
-  if (!(cert = strstr(s, "\ndir-key-certificate-version")))
-    goto err;
-  ++cert;
-  ns->cert = authority_cert_parse_from_string(cert, &end_of_cert);
-  if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
-    goto err;
 
+  if (is_vote) {
+    const char *end_of_cert = NULL;
+    if (!(cert = strstr(s, "\ndir-key-certificate-version")))
+      goto err;
+    ++cert;
+    ns->cert = authority_cert_parse_from_string(cert, &end_of_cert);
+    if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
+      goto err;
+  }
+
   tok = find_first_by_keyword(tokens, K_VOTE_STATUS);
   tor_assert(tok);
   tor_assert(tok->n_args);
-  if (strcmp(tok->args[0], "vote")) {
-    log_warn(LD_DIR, "Unrecognized vote status %s in network-status vote.",
+  if (!strcmp(tok->args[0], "vote")) {
+    ns->is_vote = 1;
+  } else if (!strcmp(tok->args[0], "consensus")) {
+    ns->is_vote = 0;
+  } else {
+    log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
              escaped(tok->args[0]));
     goto err;
   }
-
-  tok = find_first_by_keyword(tokens, K_PUBLISHED);
-  if (parse_iso_time(tok->args[0], &ns->published))
+  if (!bool_eq(ns->is_vote, is_vote)) {
+    log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
     goto err;
+  }
 
+  if (ns->is_vote) {
+    tok = find_first_by_keyword(tokens, K_PUBLISHED);
+    if (parse_iso_time(tok->args[0], &ns->published))
+      goto err;
+  }
+
   tok = find_first_by_keyword(tokens, K_VALID_AFTER);
   if (parse_iso_time(tok->args[0], &ns->valid_after))
     goto err;
@@ -1870,55 +1873,105 @@
   ns->known_flags[tok->n_args] = NULL;
   tok->n_args = 0; /* suppress free of args members, but not of args itself. */
 
-  tok = find_first_by_keyword(tokens, K_DIR_SOURCE);
-  tor_assert(tok);
-  tor_assert(tok->n_args >= 6);
-  ns->nickname = tor_strdup(tok->args[0]);
-  if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
-      base16_decode(ns->identity_digest, sizeof(ns->identity_digest),
-                    tok->args[1], HEX_DIGEST_LEN) < 0) {
-    log_warn(LD_DIR, "Error decoding identity digest %s in "
-             "network-status vote.", escaped(tok->args[1]));
-    goto err;
+  ns->voters = smartlist_create();
+
+  SMARTLIST_FOREACH(tokens, directory_token_t *, _tok,
+  {
+    tok = _tok;
+    if (tok->tp == K_DIR_SOURCE) {
+      tor_assert(tok->n_args >= 6);
+
+      if (voter)
+        smartlist_add(ns->voters, voter);
+      voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
+
+      voter->nickname = tor_strdup(tok->args[0]);
+      if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
+          base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
+                        tok->args[1], HEX_DIGEST_LEN) < 0) {
+        log_warn(LD_DIR, "Error decoding identity digest %s in "
+                 "network-status vote.", escaped(tok->args[1]));
+        goto err;
+      }
+      voter->address = tor_strdup(tok->args[2]);
+      if (!tor_inet_aton(tok->args[3], &in)) {
+        log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
+                 escaped(tok->args[3]));
+        goto err;
+      }
+      voter->dir_port = (uint64_t)
+        (int) tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
+      if (!ok)
+        goto err;
+      voter->or_port = (uint64_t)
+        (int) tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
+      if (!ok)
+        goto err;
+    } else if (tok->tp == K_CONTACT) {
+      if (!voter || voter->contact) {
+        log_warn(LD_DIR, "contact element is out of place.");
+        goto err;
+      }
+      voter->contact = tor_strdup(tok->args[0]);
+    } else if (tok->tp == K_VOTE_DIGEST) {
+      tor_assert(!is_vote);
+      tor_assert(tok->n_args >= 1);
+      if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
+        log_warn(LD_DIR, "vote-digest element is out of place.");
+        goto err;
+      }
+      if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
+        base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
+                      tok->args[0], HEX_DIGEST_LEN) < 0) {
+        log_warn(LD_DIR, "Error decoding vote digest %s in "
+                 "network-status consensus.", escaped(tok->args[1]));
+        goto err;
+      }
+    }
+  });
+  if (voter) {
+    smartlist_add(ns->voters, voter);
+    voter = NULL;
   }
-  ns->address = tor_strdup(tok->args[2]);
-  if (!tor_inet_aton(tok->args[3], &in)) {
-    log_warn(LD_DIR, "Error decoding IP address %s in network-status vote.",
-             escaped(tok->args[3]));
+  if (smartlist_len(ns->voters) == 0) {
+    log_warn(LD_DIR, "Missing dir-source elements in a vote networkstatus.");
     goto err;
-  }
-  ns->dir_port = (uint64_t)
-    (int) tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
-  if (!ok)
+  } else if (is_vote && smartlist_len(ns->voters) != 1) {
+    log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
     goto err;
-  ns->or_port = (uint64_t)
-    (int) tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
-  if (!ok)
-    goto err;
-
-  tok = find_first_by_keyword(tokens, K_CONTACT);
-  if (tok) {
-    ns->contact = tor_strdup(tok->args[0]);
   }
 
   /* Parse routerstatus lines. */
   rs_tokens = smartlist_create();
   s = end_of_header;
   ns->routerstatus_list = smartlist_create();
+
   while (!strcmpstart(s, "r ")) {
-    vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
-    if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs))
-      smartlist_add(ns->routerstatus_list, rs);
-    else {
-      tor_free(rs->version);
-      tor_free(rs);
+    if (is_vote) {
+      vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+      if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs))
+        smartlist_add(ns->routerstatus_list, rs);
+      else {
+        tor_free(rs->version);
+        tor_free(rs);
+      }
+    } else {
+      routerstatus_t *rs;
+      if ((rs =routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL)))
+        smartlist_add(ns->routerstatus_list, rs);
     }
   }
   for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
-    vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
-    vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
-    if (memcmp(a->status.identity_digest, b->status.identity_digest,
-               DIGEST_LEN) >= 0) {
+    routerstatus_t *rs1, *rs2;
+    if (is_vote) {
+      vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
+      vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
+      rs1 = &a->status; rs2 = &b->status;
+    } else {
+      rs1 = smartlist_get(ns->routerstatus_list, i-1);
+      rs2 = smartlist_get(ns->routerstatus_list, i);
+    }
+    if (memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN) >= 0) {
       log_warn(LD_DIR, "Vote networkstatus entries not sorted by identity "
                "digest");
       goto err;
@@ -1933,41 +1986,63 @@
     log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
     goto err;
   }
-  if (!(tok = find_first_by_keyword(footer_tokens, K_DIRECTORY_SIGNATURE))) {
-    log_warn(LD_DIR, "No signature on network-status vote.");
-    goto err;
-  }
-  tor_assert(tok->n_args >= 2);
-  if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
-      base16_decode(declared_identity, sizeof(ns->identity_digest),
-                    tok->args[0], HEX_DIGEST_LEN) < 0) {
-    log_warn(LD_DIR, "Error decoding declared identity %s in "
-             "network-status vote.", escaped(tok->args[1]));
-    goto err;
-  }
-  if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
-      base16_decode(declared_digest, sizeof(ns->identity_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;
-  }
-  memcpy(ns->vote_digest, declared_digest, DIGEST_LEN);
-  if (memcmp(declared_identity, ns->cert->cache_info.identity_digest,
-             DIGEST_LEN)) {
-    log_warn(LD_DIR, "Digest mismatch between declared and actual on "
-             "network-status vote.");
-    goto err;
-  }
-  if (memcmp(declared_digest, ns_digest, DIGEST_LEN)) {
-    log_warn(LD_DIR, "Digest mismatch between declared and actual on "
-             "network-status vote.");
-    goto err;
-  }
-  if (check_signature_token(ns_digest, tok, ns->cert->signing_key, 0,
-                            "network-status vote"))
-    goto err;
 
+  SMARTLIST_FOREACH(footer_tokens, directory_token_t *, _tok,
+  {
+    char declared_identity[DIGEST_LEN];
+    networkstatus_voter_info_t *v;
+    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;
+    }
+
+    if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
+        base16_decode(declared_identity, sizeof(declared_identity),
+                      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 (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
+      log_warn(LD_DIR, "ID on signature on network-status vote does not match"
+               "any declared directory source.");
+      goto err;
+    }
+    if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
+        base16_decode(v->signing_key_digest, sizeof(v->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]));
+      goto err;
+    }
+
+    if (is_vote &&
+        memcmp(declared_identity, ns->cert->cache_info.identity_digest,
+               DIGEST_LEN)) {
+      log_warn(LD_DIR, "Digest mismatch between declared and actual on "
+               "network-status vote.");
+      goto err;
+      /* XXXX020 also check cert against dir-source line. */
+    }
+
+    if (is_vote) {
+      if (check_signature_token(ns_digest, tok, ns->cert->signing_key, 0,
+                                "network-status vote"))
+        goto err;
+    } else {
+      v->pending_signature = tor_memdup(tok->object_body,
+                                        tok->object_size);
+      v->pending_signature_len = tok->object_size;
+    }
+  });
+
   /* XXXX020 check dates for plausibility.  ??? */
 
   goto done;
@@ -1980,6 +2055,12 @@
     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
     smartlist_free(tokens);
   }
+  if (voter) {
+    tor_free(voter->nickname);
+    tor_free(voter->address);
+    tor_free(voter->contact);
+    tor_free(voter);
+  }
   if (rs_tokens) {
     SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_free(t));
     smartlist_free(rs_tokens);



More information about the tor-commits mailing list