1 /* Copyright (c) 2001 Matej Pfajfar.
2  * Copyright (c) 2001-2004, Roger Dingledine.
3  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4  * Copyright (c) 2007-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
7 /**
8  * \file routerparse.c
9  * \brief Code to parse and validate consensus documents and votes.
10  */
11 
12 #define NS_PARSE_PRIVATE
13 
14 #include "core/or/or.h"
15 #include "app/config/config.h"
16 #include "core/or/protover.h"
17 #include "core/or/versions.h"
18 #include "feature/client/entrynodes.h"
19 #include "feature/dirauth/dirvote.h"
20 #include "feature/dirparse/authcert_parse.h"
21 #include "feature/dirparse/ns_parse.h"
22 #include "feature/dirparse/parsecommon.h"
23 #include "feature/dirparse/routerparse.h"
24 #include "feature/dirparse/sigcommon.h"
25 #include "feature/dirparse/unparseable.h"
26 #include "feature/hs_common/shared_random_client.h"
27 #include "feature/nodelist/authcert.h"
28 #include "feature/nodelist/describe.h"
29 #include "feature/nodelist/networkstatus.h"
30 #include "feature/nodelist/nickname.h"
31 #include "lib/crypt_ops/crypto_format.h"
32 #include "lib/memarea/memarea.h"
33 
34 #include "feature/dirauth/vote_microdesc_hash_st.h"
35 #include "feature/nodelist/authority_cert_st.h"
36 #include "feature/nodelist/document_signature_st.h"
37 #include "feature/nodelist/networkstatus_st.h"
38 #include "feature/nodelist/networkstatus_voter_info_st.h"
39 #include "feature/nodelist/vote_routerstatus_st.h"
40 #include "feature/dirparse/authcert_members.h"
41 
42 #undef log
43 #include <math.h>
44 
45 /** List of tokens recognized in the body part of v3 networkstatus
46  * documents. */
47 // clang-format off
48 static token_rule_t rtrstatus_token_table[] = {
49   T01("p",                   K_P,               CONCAT_ARGS, NO_OBJ ),
50   T1( "r",                   K_R,                   GE(7),   NO_OBJ ),
51   T0N("a",                   K_A,                   GE(1),   NO_OBJ ),
52   T1( "s",                   K_S,                   ARGS,    NO_OBJ ),
53   T01("v",                   K_V,               CONCAT_ARGS, NO_OBJ ),
54   T01("w",                   K_W,                   ARGS,    NO_OBJ ),
55   T0N("m",                   K_M,               CONCAT_ARGS, NO_OBJ ),
56   T0N("id",                  K_ID,                  GE(2),   NO_OBJ ),
57   T1("pr",                   K_PROTO,           CONCAT_ARGS, NO_OBJ ),
58   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
59   END_OF_TABLE
60 };
61 // clang-format on
62 
63 /** List of tokens recognized in V3 networkstatus votes. */
64 // clang-format off
65 static token_rule_t networkstatus_token_table[] = {
66   T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
67                                                    GE(1),       NO_OBJ ),
68   T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
69   T1("published",              K_PUBLISHED,        CONCAT_ARGS, NO_OBJ ),
70   T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
71   T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
72   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
73   T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
74   T1("known-flags",            K_KNOWN_FLAGS,      ARGS,        NO_OBJ ),
75   T01("params",                K_PARAMS,           ARGS,        NO_OBJ ),
76   T( "fingerprint",            K_FINGERPRINT,      CONCAT_ARGS, NO_OBJ ),
77   T01("signing-ed25519",       K_SIGNING_CERT_ED,  NO_ARGS ,    NEED_OBJ ),
78   T01("shared-rand-participate",K_SR_FLAG,         NO_ARGS,     NO_OBJ ),
79   T0N("shared-rand-commit",    K_COMMIT,           GE(3),       NO_OBJ ),
80   T01("shared-rand-previous-value", K_PREVIOUS_SRV,EQ(2),       NO_OBJ ),
81   T01("shared-rand-current-value",  K_CURRENT_SRV, EQ(2),       NO_OBJ ),
82   T0N("package",               K_PACKAGE,          CONCAT_ARGS, NO_OBJ ),
83   T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
84       CONCAT_ARGS, NO_OBJ ),
85   T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
86       CONCAT_ARGS, NO_OBJ ),
87   T01("required-client-protocols",    K_REQUIRED_CLIENT_PROTOCOLS,
88       CONCAT_ARGS, NO_OBJ ),
89   T01("required-relay-protocols",    K_REQUIRED_RELAY_PROTOCOLS,
90       CONCAT_ARGS, NO_OBJ ),
91 
92   AUTHCERT_MEMBERS,
93 
94   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
95   T1( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
96   T1( "dir-source",          K_DIR_SOURCE,      GE(6),       NO_OBJ ),
97   T01("legacy-dir-key",      K_LEGACY_DIR_KEY,  GE(1),       NO_OBJ ),
98   T1( "known-flags",         K_KNOWN_FLAGS,     CONCAT_ARGS, NO_OBJ ),
99   T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
100   T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
101   T1( "consensus-methods",   K_CONSENSUS_METHODS, GE(1),     NO_OBJ ),
102 
103   END_OF_TABLE
104 };
105 // clang-format on
106 
107 /** List of tokens recognized in V3 networkstatus consensuses. */
108 // clang-format off
109 static token_rule_t networkstatus_consensus_token_table[] = {
110   T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
111                                                    GE(1),       NO_OBJ ),
112   T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
113   T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
114   T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
115   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
116   T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
117 
118   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
119 
120   T1N("dir-source",          K_DIR_SOURCE,          GE(6),   NO_OBJ ),
121   T1N("contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
122   T1N("vote-digest",         K_VOTE_DIGEST,         GE(1),   NO_OBJ ),
123 
124   T1( "known-flags",         K_KNOWN_FLAGS,     CONCAT_ARGS, NO_OBJ ),
125 
126   T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
127   T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
128   T01("consensus-method",    K_CONSENSUS_METHOD,    EQ(1),   NO_OBJ),
129   T01("params",                K_PARAMS,           ARGS,        NO_OBJ ),
130 
131   T01("shared-rand-previous-value", K_PREVIOUS_SRV, EQ(2),   NO_OBJ ),
132   T01("shared-rand-current-value",  K_CURRENT_SRV,  EQ(2),   NO_OBJ ),
133 
134   T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
135       CONCAT_ARGS, NO_OBJ ),
136   T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
137       CONCAT_ARGS, NO_OBJ ),
138   T01("required-client-protocols",    K_REQUIRED_CLIENT_PROTOCOLS,
139       CONCAT_ARGS, NO_OBJ ),
140   T01("required-relay-protocols",    K_REQUIRED_RELAY_PROTOCOLS,
141       CONCAT_ARGS, NO_OBJ ),
142 
143   END_OF_TABLE
144 };
145 // clang-format on
146 
147 /** List of tokens recognized in the footer of v1 directory footers. */
148 // clang-format off
149 static token_rule_t networkstatus_vote_footer_token_table[] = {
150   T01("directory-footer",    K_DIRECTORY_FOOTER,    NO_ARGS,   NO_OBJ ),
151   T01("bandwidth-weights",   K_BW_WEIGHTS,          ARGS,      NO_OBJ ),
152   T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),     NEED_OBJ ),
153   END_OF_TABLE
154 };
155 // clang-format on
156 
157 /** Try to find the start and end of the signed portion of a networkstatus
158  * document in <b>s</b>. On success, set <b>start_out</b> to the first
159  * character of the document, and <b>end_out</b> to a position one after the
160  * final character of the signed document, and return 0.  On failure, return
161  * -1. */
162 int
router_get_networkstatus_v3_signed_boundaries(const char * s,size_t len,const char ** start_out,const char ** end_out)163 router_get_networkstatus_v3_signed_boundaries(const char *s,
164                                               size_t len,
165                                               const char **start_out,
166                                               const char **end_out)
167 {
168   return router_get_hash_impl_helper(s, len,
169                                      "network-status-version",
170                                      "\ndirectory-signature",
171                                      ' ', LOG_INFO,
172                                      start_out, end_out);
173 }
174 
175 /** Set <b>digest_out</b> to the SHA3-256 digest of the signed portion of the
176  * networkstatus vote in <b>s</b> -- or of the entirety of <b>s</b> if no
177  * signed portion can be identified.  Return 0 on success, -1 on failure. */
178 int
router_get_networkstatus_v3_sha3_as_signed(uint8_t * digest_out,const char * s,size_t len)179 router_get_networkstatus_v3_sha3_as_signed(uint8_t *digest_out,
180                                            const char *s, size_t len)
181 {
182   const char *start, *end;
183   if (router_get_networkstatus_v3_signed_boundaries(s, len,
184                                                     &start, &end) < 0) {
185     start = s;
186     end = s + len;
187   }
188   tor_assert(start);
189   tor_assert(end);
190   return crypto_digest256((char*)digest_out, start, end-start,
191                           DIGEST_SHA3_256);
192 }
193 
194 /** Set <b>digests</b> to all the digests of the consensus document in
195  * <b>s</b> */
196 int
router_get_networkstatus_v3_hashes(const char * s,size_t len,common_digests_t * digests)197 router_get_networkstatus_v3_hashes(const char *s, size_t len,
198                                    common_digests_t *digests)
199 {
200   return router_get_hashes_impl(s, len, digests,
201                                 "network-status-version",
202                                 "\ndirectory-signature",
203                                 ' ');
204 }
205 
206 /** Helper: given a string <b>s</b>, return the start of the next router-status
207  * object (starting with "r " at the start of a line).  If none is found,
208  * return the start of the directory footer, or the next directory signature.
209  * If none is found, return the end of the string. */
210 static inline const char *
find_start_of_next_routerstatus(const char * s,const char * s_eos)211 find_start_of_next_routerstatus(const char *s, const char *s_eos)
212 {
213   const char *eos, *footer, *sig;
214   if ((eos = tor_memstr(s, s_eos - s, "\nr ")))
215     ++eos;
216   else
217     eos = s_eos;
218 
219   footer = tor_memstr(s, eos-s, "\ndirectory-footer");
220   sig = tor_memstr(s, eos-s, "\ndirectory-signature");
221 
222   if (footer && sig)
223     return MIN(footer, sig) + 1;
224   else if (footer)
225     return footer+1;
226   else if (sig)
227     return sig+1;
228   else
229     return eos;
230 }
231 
232 /** Parse the GuardFraction string from a consensus or vote.
233  *
234  *  If <b>vote</b> or <b>vote_rs</b> are set the document getting
235  *  parsed is a vote routerstatus. Otherwise it's a consensus. This is
236  *  the same semantic as in routerstatus_parse_entry_from_string(). */
237 STATIC int
routerstatus_parse_guardfraction(const char * guardfraction_str,networkstatus_t * vote,vote_routerstatus_t * vote_rs,routerstatus_t * rs)238 routerstatus_parse_guardfraction(const char *guardfraction_str,
239                                  networkstatus_t *vote,
240                                  vote_routerstatus_t *vote_rs,
241                                  routerstatus_t *rs)
242 {
243   int ok;
244   const char *end_of_header = NULL;
245   int is_consensus = !vote_rs;
246   uint32_t guardfraction;
247 
248   tor_assert(bool_eq(vote, vote_rs));
249 
250   /* If this info comes from a consensus, but we shouldn't apply
251      guardfraction, just exit. */
252   if (is_consensus && !should_apply_guardfraction(NULL)) {
253     return 0;
254   }
255 
256   end_of_header = strchr(guardfraction_str, '=');
257   if (!end_of_header) {
258     return -1;
259   }
260 
261   guardfraction = (uint32_t)tor_parse_ulong(end_of_header+1,
262                                             10, 0, 100, &ok, NULL);
263   if (!ok) {
264     log_warn(LD_DIR, "Invalid GuardFraction %s", escaped(guardfraction_str));
265     return -1;
266   }
267 
268   log_debug(LD_GENERAL, "[*] Parsed %s guardfraction '%s' for '%s'.",
269             is_consensus ? "consensus" : "vote",
270             guardfraction_str, rs->nickname);
271 
272   if (!is_consensus) { /* We are parsing a vote */
273     vote_rs->status.guardfraction_percentage = guardfraction;
274     vote_rs->status.has_guardfraction = 1;
275   } else {
276     /* We are parsing a consensus. Only apply guardfraction to guards. */
277     if (rs->is_possible_guard) {
278       rs->guardfraction_percentage = guardfraction;
279       rs->has_guardfraction = 1;
280     } else {
281       log_warn(LD_BUG, "Got GuardFraction for non-guard %s. "
282                "This is not supposed to happen. Not applying. ", rs->nickname);
283     }
284   }
285 
286   return 0;
287 }
288 
289 /** Given a string at *<b>s</b>, containing a routerstatus object, and an
290  * empty smartlist at <b>tokens</b>, parse and return the first router status
291  * object in the string, and advance *<b>s</b> to just after the end of the
292  * router status.  Return NULL and advance *<b>s</b> on error.
293  *
294  * If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh
295  * routerstatus but use <b>vote_rs</b> instead.
296  *
297  * If <b>consensus_method</b> is nonzero, this routerstatus is part of a
298  * consensus, and we should parse it according to the method used to
299  * make that consensus.
300  *
301  * Parse according to the syntax used by the consensus flavor <b>flav</b>.
302  **/
303 STATIC routerstatus_t *
routerstatus_parse_entry_from_string(memarea_t * area,const char ** s,const char * s_eos,smartlist_t * tokens,networkstatus_t * vote,vote_routerstatus_t * vote_rs,int consensus_method,consensus_flavor_t flav)304 routerstatus_parse_entry_from_string(memarea_t *area,
305                                      const char **s, const char *s_eos,
306                                      smartlist_t *tokens,
307                                      networkstatus_t *vote,
308                                      vote_routerstatus_t *vote_rs,
309                                      int consensus_method,
310                                      consensus_flavor_t flav)
311 {
312   const char *eos, *s_dup = *s;
313   routerstatus_t *rs = NULL;
314   directory_token_t *tok;
315   char timebuf[ISO_TIME_LEN+1];
316   struct in_addr in;
317   int offset = 0;
318   tor_assert(tokens);
319   tor_assert(bool_eq(vote, vote_rs));
320 
321   if (!consensus_method)
322     flav = FLAV_NS;
323   tor_assert(flav == FLAV_NS || flav == FLAV_MICRODESC);
324 
325   eos = find_start_of_next_routerstatus(*s, s_eos);
326 
327   if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) {
328     log_warn(LD_DIR, "Error tokenizing router status");
329     goto err;
330   }
331   if (smartlist_len(tokens) < 1) {
332     log_warn(LD_DIR, "Impossibly short router status");
333     goto err;
334   }
335   tok = find_by_keyword(tokens, K_R);
336   tor_assert(tok->n_args >= 7); /* guaranteed by GE(7) in K_R setup */
337   if (flav == FLAV_NS) {
338     if (tok->n_args < 8) {
339       log_warn(LD_DIR, "Too few arguments to r");
340       goto err;
341     }
342   } else if (flav == FLAV_MICRODESC) {
343     offset = -1; /* There is no descriptor digest in an md consensus r line */
344   }
345 
346   if (vote_rs) {
347     rs = &vote_rs->status;
348   } else {
349     rs = tor_malloc_zero(sizeof(routerstatus_t));
350   }
351 
352   if (!is_legal_nickname(tok->args[0])) {
353     log_warn(LD_DIR,
354              "Invalid nickname %s in router status; skipping.",
355              escaped(tok->args[0]));
356     goto err;
357   }
358   strlcpy(rs->nickname, tok->args[0], sizeof(rs->nickname));
359 
360   if (digest_from_base64(rs->identity_digest, tok->args[1])) {
361     log_warn(LD_DIR, "Error decoding identity digest %s",
362              escaped(tok->args[1]));
363     goto err;
364   }
365 
366   if (flav == FLAV_NS) {
367     if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
368       log_warn(LD_DIR, "Error decoding descriptor digest %s",
369                escaped(tok->args[2]));
370       goto err;
371     }
372   }
373 
374   if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
375                    tok->args[3+offset], tok->args[4+offset]) < 0 ||
376       parse_iso_time(timebuf, &rs->published_on)<0) {
377     log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]",
378              tok->args[3+offset], tok->args[4+offset],
379              offset, (int)flav);
380     goto err;
381   }
382 
383   if (tor_inet_aton(tok->args[5+offset], &in) == 0) {
384     log_warn(LD_DIR, "Error parsing router address in network-status %s",
385              escaped(tok->args[5+offset]));
386     goto err;
387   }
388   tor_addr_from_in(&rs->ipv4_addr, &in);
389 
390   rs->ipv4_orport = (uint16_t) tor_parse_long(tok->args[6+offset],
391                                               10,0,65535,NULL,NULL);
392   rs->ipv4_dirport = (uint16_t) tor_parse_long(tok->args[7+offset],
393                                                10,0,65535,NULL,NULL);
394 
395   {
396     smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
397     if (a_lines) {
398       find_single_ipv6_orport(a_lines, &rs->ipv6_addr, &rs->ipv6_orport);
399       smartlist_free(a_lines);
400     }
401   }
402 
403   tok = find_opt_by_keyword(tokens, K_S);
404   if (tok && vote) {
405     int i;
406     vote_rs->flags = 0;
407     for (i=0; i < tok->n_args; ++i) {
408       int p = smartlist_string_pos(vote->known_flags, tok->args[i]);
409       if (p >= 0) {
410         vote_rs->flags |= (UINT64_C(1)<<p);
411       } else {
412         log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.",
413                  escaped(tok->args[i]));
414         goto err;
415       }
416     }
417   } else if (tok) {
418     /* This is a consensus, not a vote. */
419     int i;
420     for (i=0; i < tok->n_args; ++i) {
421       if (!strcmp(tok->args[i], "Exit"))
422         rs->is_exit = 1;
423       else if (!strcmp(tok->args[i], "Stable"))
424         rs->is_stable = 1;
425       else if (!strcmp(tok->args[i], "Fast"))
426         rs->is_fast = 1;
427       else if (!strcmp(tok->args[i], "Running"))
428         rs->is_flagged_running = 1;
429       else if (!strcmp(tok->args[i], "Named"))
430         rs->is_named = 1;
431       else if (!strcmp(tok->args[i], "Valid"))
432         rs->is_valid = 1;
433       else if (!strcmp(tok->args[i], "Guard"))
434         rs->is_possible_guard = 1;
435       else if (!strcmp(tok->args[i], "BadExit"))
436         rs->is_bad_exit = 1;
437       else if (!strcmp(tok->args[i], "MiddleOnly"))
438         rs->is_middle_only = 1;
439       else if (!strcmp(tok->args[i], "Authority"))
440         rs->is_authority = 1;
441       else if (!strcmp(tok->args[i], "Unnamed") &&
442                consensus_method >= 2) {
443         /* Unnamed is computed right by consensus method 2 and later. */
444         rs->is_unnamed = 1;
445       } else if (!strcmp(tok->args[i], "HSDir")) {
446         rs->is_hs_dir = 1;
447       } else if (!strcmp(tok->args[i], "V2Dir")) {
448         rs->is_v2_dir = 1;
449       } else if (!strcmp(tok->args[i], "StaleDesc")) {
450         rs->is_staledesc = 1;
451       } else if (!strcmp(tok->args[i], "Sybil")) {
452         rs->is_sybil = 1;
453       }
454     }
455     /* These are implied true by having been included in a consensus made
456      * with a given method */
457     rs->is_flagged_running = 1; /* Starting with consensus method 4. */
458     rs->is_valid = 1; /* Starting with consensus method 24. */
459   }
460   {
461     const char *protocols = NULL, *version = NULL;
462     if ((tok = find_opt_by_keyword(tokens, K_PROTO))) {
463       tor_assert(tok->n_args == 1);
464       protocols = tok->args[0];
465     }
466     if ((tok = find_opt_by_keyword(tokens, K_V))) {
467       tor_assert(tok->n_args == 1);
468       version = tok->args[0];
469       if (vote_rs) {
470         vote_rs->version = tor_strdup(tok->args[0]);
471       }
472     }
473 
474     // If the protover line is malformed, reject this routerstatus.
475     if (protocols && protover_list_is_invalid(protocols)) {
476       goto err;
477     }
478     summarize_protover_flags(&rs->pv, protocols, version);
479   }
480 
481   /* handle weighting/bandwidth info */
482   if ((tok = find_opt_by_keyword(tokens, K_W))) {
483     int i;
484     for (i=0; i < tok->n_args; ++i) {
485       if (!strcmpstart(tok->args[i], "Bandwidth=")) {
486         int ok;
487         rs->bandwidth_kb =
488           (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
489                                     10, 0, UINT32_MAX,
490                                     &ok, NULL);
491         if (!ok) {
492           log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i]));
493           goto err;
494         }
495         rs->has_bandwidth = 1;
496       } else if (!strcmpstart(tok->args[i], "Measured=") && vote_rs) {
497         int ok;
498         vote_rs->measured_bw_kb =
499             (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
500                                       10, 0, UINT32_MAX, &ok, NULL);
501         if (!ok) {
502           log_warn(LD_DIR, "Invalid Measured Bandwidth %s",
503                    escaped(tok->args[i]));
504           goto err;
505         }
506         vote_rs->has_measured_bw = 1;
507         vote->has_measured_bws = 1;
508       } else if (!strcmpstart(tok->args[i], "Unmeasured=1")) {
509         rs->bw_is_unmeasured = 1;
510       } else if (!strcmpstart(tok->args[i], "GuardFraction=")) {
511         if (routerstatus_parse_guardfraction(tok->args[i],
512                                              vote, vote_rs, rs) < 0) {
513           goto err;
514         }
515       }
516     }
517   }
518 
519   /* parse exit policy summaries */
520   if ((tok = find_opt_by_keyword(tokens, K_P))) {
521     tor_assert(tok->n_args == 1);
522     if (strcmpstart(tok->args[0], "accept ") &&
523         strcmpstart(tok->args[0], "reject ")) {
524       log_warn(LD_DIR, "Unknown exit policy summary type %s.",
525                escaped(tok->args[0]));
526       goto err;
527     }
528     /* XXX weasel: parse this into ports and represent them somehow smart,
529      * maybe not here but somewhere on if we need it for the client.
530      * we should still parse it here to check it's valid tho.
531      */
532     rs->exitsummary = tor_strdup(tok->args[0]);
533     rs->has_exitsummary = 1;
534   }
535 
536   if (vote_rs) {
537     SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, t) {
538       if (t->tp == K_M && t->n_args) {
539         vote_microdesc_hash_t *line =
540           tor_malloc(sizeof(vote_microdesc_hash_t));
541         line->next = vote_rs->microdesc;
542         line->microdesc_hash_line = tor_strdup(t->args[0]);
543         vote_rs->microdesc = line;
544       }
545       if (t->tp == K_ID) {
546         tor_assert(t->n_args >= 2);
547         if (!strcmp(t->args[0], "ed25519")) {
548           vote_rs->has_ed25519_listing = 1;
549           if (strcmp(t->args[1], "none") &&
550               digest256_from_base64((char*)vote_rs->ed25519_id,
551                                     t->args[1])<0) {
552             log_warn(LD_DIR, "Bogus ed25519 key in networkstatus vote");
553             goto err;
554           }
555         }
556       }
557       if (t->tp == K_PROTO) {
558         tor_assert(t->n_args == 1);
559         vote_rs->protocols = tor_strdup(t->args[0]);
560       }
561     } SMARTLIST_FOREACH_END(t);
562   } else if (flav == FLAV_MICRODESC) {
563     tok = find_opt_by_keyword(tokens, K_M);
564     if (tok) {
565       tor_assert(tok->n_args);
566       if (digest256_from_base64(rs->descriptor_digest, tok->args[0])) {
567         log_warn(LD_DIR, "Error decoding microdescriptor digest %s",
568                  escaped(tok->args[0]));
569         goto err;
570       }
571     } else {
572       log_info(LD_BUG, "Found an entry in networkstatus with no "
573                "microdescriptor digest. (Router %s ($%s) at %s:%d.)",
574                rs->nickname, hex_str(rs->identity_digest, DIGEST_LEN),
575                fmt_addr(&rs->ipv4_addr), rs->ipv4_orport);
576     }
577   }
578 
579   if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME))
580     rs->is_named = 0;
581 
582   goto done;
583  err:
584   dump_desc(s_dup, "routerstatus entry");
585   if (rs && !vote_rs)
586     routerstatus_free(rs);
587   rs = NULL;
588  done:
589   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
590   smartlist_clear(tokens);
591   if (area) {
592     DUMP_AREA(area, "routerstatus entry");
593     memarea_clear(area);
594   }
595   *s = eos;
596 
597   return rs;
598 }
599 
600 int
compare_vote_routerstatus_entries(const void ** _a,const void ** _b)601 compare_vote_routerstatus_entries(const void **_a, const void **_b)
602 {
603   const vote_routerstatus_t *a = *_a, *b = *_b;
604   return fast_memcmp(a->status.identity_digest, b->status.identity_digest,
605                      DIGEST_LEN);
606 }
607 
608 /** Verify the bandwidth weights of a network status document */
609 int
networkstatus_verify_bw_weights(networkstatus_t * ns,int consensus_method)610 networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method)
611 {
612   int64_t G=0, M=0, E=0, D=0, T=0;
613   double Wgg, Wgm, Wgd, Wmg, Wmm, Wme, Wmd, Weg, Wem, Wee, Wed;
614   double Gtotal=0, Mtotal=0, Etotal=0;
615   const char *casename = NULL;
616   int valid = 1;
617   (void) consensus_method;
618 
619   const int64_t weight_scale = networkstatus_get_weight_scale_param(ns);
620   tor_assert(weight_scale >= 1);
621   Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
622   Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
623   Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
624   Wmg = networkstatus_get_bw_weight(ns, "Wmg", -1);
625   Wmm = networkstatus_get_bw_weight(ns, "Wmm", -1);
626   Wme = networkstatus_get_bw_weight(ns, "Wme", -1);
627   Wmd = networkstatus_get_bw_weight(ns, "Wmd", -1);
628   Weg = networkstatus_get_bw_weight(ns, "Weg", -1);
629   Wem = networkstatus_get_bw_weight(ns, "Wem", -1);
630   Wee = networkstatus_get_bw_weight(ns, "Wee", -1);
631   Wed = networkstatus_get_bw_weight(ns, "Wed", -1);
632 
633   if (Wgg<0 || Wgm<0 || Wgd<0 || Wmg<0 || Wmm<0 || Wme<0 || Wmd<0 || Weg<0
634           || Wem<0 || Wee<0 || Wed<0) {
635     log_warn(LD_BUG, "No bandwidth weights produced in consensus!");
636     return 0;
637   }
638 
639   // First, sanity check basic summing properties that hold for all cases
640   // We use > 1 as the check for these because they are computed as integers.
641   // Sometimes there are rounding errors.
642   if (fabs(Wmm - weight_scale) > 1) {
643     log_warn(LD_BUG, "Wmm=%f != %"PRId64,
644              Wmm, (weight_scale));
645     valid = 0;
646   }
647 
648   if (fabs(Wem - Wee) > 1) {
649     log_warn(LD_BUG, "Wem=%f != Wee=%f", Wem, Wee);
650     valid = 0;
651   }
652 
653   if (fabs(Wgm - Wgg) > 1) {
654     log_warn(LD_BUG, "Wgm=%f != Wgg=%f", Wgm, Wgg);
655     valid = 0;
656   }
657 
658   if (fabs(Weg - Wed) > 1) {
659     log_warn(LD_BUG, "Wed=%f != Weg=%f", Wed, Weg);
660     valid = 0;
661   }
662 
663   if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) {
664     log_warn(LD_BUG, "Wgg=%f != %"PRId64" - Wmg=%f", Wgg,
665              (weight_scale), Wmg);
666     valid = 0;
667   }
668 
669   if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) {
670     log_warn(LD_BUG, "Wee=%f != %"PRId64" - Wme=%f", Wee,
671              (weight_scale), Wme);
672     valid = 0;
673   }
674 
675   if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) {
676     log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != %"PRId64,
677              Wgd, Wmd, Wed, (weight_scale));
678     valid = 0;
679   }
680 
681   Wgg /= weight_scale;
682   Wgm /= weight_scale; (void) Wgm; // unused from here on.
683   Wgd /= weight_scale;
684 
685   Wmg /= weight_scale;
686   Wmm /= weight_scale;
687   Wme /= weight_scale;
688   Wmd /= weight_scale;
689 
690   Weg /= weight_scale; (void) Weg; // unused from here on.
691   Wem /= weight_scale; (void) Wem; // unused from here on.
692   Wee /= weight_scale;
693   Wed /= weight_scale;
694 
695   // Then, gather G, M, E, D, T to determine case
696   SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
697     int is_exit = 0;
698     /* Bug #2203: Don't count bad exits as exits for balancing */
699     is_exit = rs->is_exit && !rs->is_bad_exit;
700     if (rs->has_bandwidth) {
701       T += rs->bandwidth_kb;
702       if (is_exit && rs->is_possible_guard) {
703         D += rs->bandwidth_kb;
704         Gtotal += Wgd*rs->bandwidth_kb;
705         Mtotal += Wmd*rs->bandwidth_kb;
706         Etotal += Wed*rs->bandwidth_kb;
707       } else if (is_exit) {
708         E += rs->bandwidth_kb;
709         Mtotal += Wme*rs->bandwidth_kb;
710         Etotal += Wee*rs->bandwidth_kb;
711       } else if (rs->is_possible_guard) {
712         G += rs->bandwidth_kb;
713         Gtotal += Wgg*rs->bandwidth_kb;
714         Mtotal += Wmg*rs->bandwidth_kb;
715       } else {
716         M += rs->bandwidth_kb;
717         Mtotal += Wmm*rs->bandwidth_kb;
718       }
719     } else {
720       log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
721                routerstatus_describe(rs));
722     }
723   } SMARTLIST_FOREACH_END(rs);
724 
725   // Finally, check equality conditions depending upon case 1, 2 or 3
726   // Full equality cases: 1, 3b
727   // Partial equality cases: 2b (E=G), 3a (M=E)
728   // Fully unknown: 2a
729   if (3*E >= T && 3*G >= T) {
730     // Case 1: Neither are scarce
731     casename = "Case 1";
732     if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
733       log_warn(LD_DIR,
734                "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
735                "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
736                " T=%"PRId64". "
737                "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
738                casename, Etotal, Mtotal,
739                (G), (M), (E),
740                (D), (T),
741                Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
742       valid = 0;
743     }
744     if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
745       log_warn(LD_DIR,
746                "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
747                "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
748                " T=%"PRId64". "
749                "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
750                casename, Etotal, Gtotal,
751                (G), (M), (E),
752                (D), (T),
753                Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
754       valid = 0;
755     }
756     if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
757       log_warn(LD_DIR,
758                "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
759                "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
760                " T=%"PRId64". "
761                "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
762                casename, Mtotal, Gtotal,
763                (G), (M), (E),
764                (D), (T),
765                Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
766       valid = 0;
767     }
768   } else if (3*E < T && 3*G < T) {
769     int64_t R = MIN(E, G);
770     int64_t S = MAX(E, G);
771     /*
772      * Case 2: Both Guards and Exits are scarce
773      * Balance D between E and G, depending upon
774      * D capacity and scarcity. Devote no extra
775      * bandwidth to middle nodes.
776      */
777     if (R+D < S) { // Subcase a
778       double Rtotal, Stotal;
779       if (E < G) {
780         Rtotal = Etotal;
781         Stotal = Gtotal;
782       } else {
783         Rtotal = Gtotal;
784         Stotal = Etotal;
785       }
786       casename = "Case 2a";
787       // Rtotal < Stotal
788       if (Rtotal > Stotal) {
789         log_warn(LD_DIR,
790                    "Bw Weight Failure for %s: Rtotal %f > Stotal %f. "
791                    "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
792                    " T=%"PRId64". "
793                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
794                    casename, Rtotal, Stotal,
795                    (G), (M), (E),
796                    (D), (T),
797                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
798         valid = 0;
799       }
800       // Rtotal < T/3
801       if (3*Rtotal > T) {
802         log_warn(LD_DIR,
803                    "Bw Weight Failure for %s: 3*Rtotal %f > T "
804                    "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
805                    " D=%"PRId64" T=%"PRId64". "
806                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
807                    casename, Rtotal*3, (T),
808                    (G), (M), (E),
809                    (D), (T),
810                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
811         valid = 0;
812       }
813       // Stotal < T/3
814       if (3*Stotal > T) {
815         log_warn(LD_DIR,
816                    "Bw Weight Failure for %s: 3*Stotal %f > T "
817                    "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
818                    " D=%"PRId64" T=%"PRId64". "
819                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
820                    casename, Stotal*3, (T),
821                    (G), (M), (E),
822                    (D), (T),
823                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
824         valid = 0;
825       }
826       // Mtotal > T/3
827       if (3*Mtotal < T) {
828         log_warn(LD_DIR,
829                    "Bw Weight Failure for %s: 3*Mtotal %f < T "
830                    "%"PRId64". "
831                    "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
832                    " T=%"PRId64". "
833                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
834                    casename, Mtotal*3, (T),
835                    (G), (M), (E),
836                    (D), (T),
837                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
838         valid = 0;
839       }
840     } else { // Subcase b: R+D > S
841       casename = "Case 2b";
842 
843       /* Check the rare-M redirect case. */
844       if (D != 0 && 3*M < T) {
845         casename = "Case 2b (balanced)";
846         if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
847           log_warn(LD_DIR,
848                    "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
849                    "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
850                    " T=%"PRId64". "
851                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
852                    casename, Etotal, Mtotal,
853                    (G), (M), (E),
854                    (D), (T),
855                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
856           valid = 0;
857         }
858         if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
859           log_warn(LD_DIR,
860                    "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
861                    "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
862                    " T=%"PRId64". "
863                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
864                    casename, Etotal, Gtotal,
865                    (G), (M), (E),
866                    (D), (T),
867                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
868           valid = 0;
869         }
870         if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
871           log_warn(LD_DIR,
872                    "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
873                    "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
874                    " T=%"PRId64". "
875                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
876                    casename, Mtotal, Gtotal,
877                    (G), (M), (E),
878                    (D), (T),
879                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
880           valid = 0;
881         }
882       } else {
883         if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
884           log_warn(LD_DIR,
885                    "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
886                    "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
887                    " T=%"PRId64". "
888                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
889                    casename, Etotal, Gtotal,
890                    (G), (M), (E),
891                    (D), (T),
892                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
893           valid = 0;
894         }
895       }
896     }
897   } else { // if (E < T/3 || G < T/3) {
898     int64_t S = MIN(E, G);
899     int64_t NS = MAX(E, G);
900     if (3*(S+D) < T) { // Subcase a:
901       double Stotal;
902       double NStotal;
903       if (G < E) {
904         casename = "Case 3a (G scarce)";
905         Stotal = Gtotal;
906         NStotal = Etotal;
907       } else { // if (G >= E) {
908         casename = "Case 3a (E scarce)";
909         NStotal = Gtotal;
910         Stotal = Etotal;
911       }
912       // Stotal < T/3
913       if (3*Stotal > T) {
914         log_warn(LD_DIR,
915                    "Bw Weight Failure for %s: 3*Stotal %f > T "
916                    "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
917                    " D=%"PRId64" T=%"PRId64". "
918                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
919                    casename, Stotal*3, (T),
920                    (G), (M), (E),
921                    (D), (T),
922                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
923         valid = 0;
924       }
925       if (NS >= M) {
926         if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) {
927           log_warn(LD_DIR,
928                    "Bw Weight Failure for %s: NStotal %f != Mtotal %f. "
929                    "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
930                    " T=%"PRId64". "
931                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
932                    casename, NStotal, Mtotal,
933                    (G), (M), (E),
934                    (D), (T),
935                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
936           valid = 0;
937         }
938       } else {
939         // if NS < M, NStotal > T/3 because only one of G or E is scarce
940         if (3*NStotal < T) {
941           log_warn(LD_DIR,
942                      "Bw Weight Failure for %s: 3*NStotal %f < T "
943                      "%"PRId64". G=%"PRId64" M=%"PRId64
944                      " E=%"PRId64" D=%"PRId64" T=%"PRId64". "
945                      "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
946                      casename, NStotal*3, (T),
947                      (G), (M), (E),
948                      (D), (T),
949                      Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
950           valid = 0;
951         }
952       }
953     } else { // Subcase b: S+D >= T/3
954       casename = "Case 3b";
955       if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
956         log_warn(LD_DIR,
957                  "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
958                  "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
959                  " T=%"PRId64". "
960                  "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
961                  casename, Etotal, Mtotal,
962                  (G), (M), (E),
963                  (D), (T),
964                  Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
965         valid = 0;
966       }
967       if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
968         log_warn(LD_DIR,
969                  "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
970                  "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
971                  " T=%"PRId64". "
972                  "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
973                  casename, Etotal, Gtotal,
974                  (G), (M), (E),
975                  (D), (T),
976                  Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
977         valid = 0;
978       }
979       if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
980         log_warn(LD_DIR,
981                  "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
982                  "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
983                  " T=%"PRId64". "
984                  "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
985                  casename, Mtotal, Gtotal,
986                  (G), (M), (E),
987                  (D), (T),
988                  Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
989         valid = 0;
990       }
991     }
992   }
993 
994   if (valid)
995     log_notice(LD_DIR, "Bandwidth-weight %s is verified and valid.",
996                casename);
997 
998   return valid;
999 }
1000 
1001 /** Check if a shared random value of type <b>srv_type</b> is in
1002  *  <b>tokens</b>. If there is, parse it and set it to <b>srv_out</b>. Return
1003  *  -1 on failure, 0 on success. The resulting srv is allocated on the heap and
1004  *  it's the responsibility of the caller to free it. */
1005 static int
extract_one_srv(smartlist_t * tokens,directory_keyword srv_type,sr_srv_t ** srv_out)1006 extract_one_srv(smartlist_t *tokens, directory_keyword srv_type,
1007                 sr_srv_t **srv_out)
1008 {
1009   int ret = -1;
1010   directory_token_t *tok;
1011   sr_srv_t *srv = NULL;
1012   smartlist_t *chunks;
1013 
1014   tor_assert(tokens);
1015 
1016   chunks = smartlist_new();
1017   tok = find_opt_by_keyword(tokens, srv_type);
1018   if (!tok) {
1019     /* That's fine, no SRV is allowed. */
1020     ret = 0;
1021     goto end;
1022   }
1023   for (int i = 0; i < tok->n_args; i++) {
1024     smartlist_add(chunks, tok->args[i]);
1025   }
1026   srv = sr_parse_srv(chunks);
1027   if (srv == NULL) {
1028     log_warn(LD_DIR, "SR: Unparseable SRV %s", escaped(tok->object_body));
1029     goto end;
1030   }
1031   /* All is good. */
1032   *srv_out = srv;
1033   ret = 0;
1034  end:
1035   smartlist_free(chunks);
1036   return ret;
1037 }
1038 
1039 /** Extract any shared random values found in <b>tokens</b> and place them in
1040  *  the networkstatus <b>ns</b>. */
1041 static void
extract_shared_random_srvs(networkstatus_t * ns,smartlist_t * tokens)1042 extract_shared_random_srvs(networkstatus_t *ns, smartlist_t *tokens)
1043 {
1044   const char *voter_identity;
1045   networkstatus_voter_info_t *voter;
1046 
1047   tor_assert(ns);
1048   tor_assert(tokens);
1049   /* Can be only one of them else code flow. */
1050   tor_assert(ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS);
1051 
1052   if (ns->type == NS_TYPE_VOTE) {
1053     voter = smartlist_get(ns->voters, 0);
1054     tor_assert(voter);
1055     voter_identity = hex_str(voter->identity_digest,
1056                              sizeof(voter->identity_digest));
1057   } else {
1058     /* Consensus has multiple voters so no specific voter. */
1059     voter_identity = "consensus";
1060   }
1061 
1062   /* We extract both, and on error everything is stopped because it means
1063    * the vote is malformed for the shared random value(s). */
1064   if (extract_one_srv(tokens, K_PREVIOUS_SRV, &ns->sr_info.previous_srv) < 0) {
1065     log_warn(LD_DIR, "SR: Unable to parse previous SRV from %s",
1066              voter_identity);
1067     /* Maybe we have a chance with the current SRV so let's try it anyway. */
1068   }
1069   if (extract_one_srv(tokens, K_CURRENT_SRV, &ns->sr_info.current_srv) < 0) {
1070     log_warn(LD_DIR, "SR: Unable to parse current SRV from %s",
1071              voter_identity);
1072   }
1073 }
1074 
1075 /** Allocate a copy of a protover line, if present. If present but malformed,
1076  * set *error to true. */
1077 static char *
dup_protocols_string(smartlist_t * tokens,bool * error,directory_keyword kw)1078 dup_protocols_string(smartlist_t *tokens, bool *error, directory_keyword kw)
1079 {
1080   directory_token_t *tok = find_opt_by_keyword(tokens, kw);
1081   if (!tok)
1082     return NULL;
1083   if (protover_list_is_invalid(tok->args[0]))
1084     *error = true;
1085   return tor_strdup(tok->args[0]);
1086 }
1087 
1088 /** Parse a v3 networkstatus vote, opinion, or consensus (depending on
1089  * ns_type), from <b>s</b>, and return the result.  Return NULL on failure. */
1090 networkstatus_t *
networkstatus_parse_vote_from_string(const char * s,size_t s_len,const char ** eos_out,networkstatus_type_t ns_type)1091 networkstatus_parse_vote_from_string(const char *s,
1092                                      size_t s_len,
1093                                      const char **eos_out,
1094                                      networkstatus_type_t ns_type)
1095 {
1096   smartlist_t *tokens = smartlist_new();
1097   smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
1098   networkstatus_voter_info_t *voter = NULL;
1099   networkstatus_t *ns = NULL;
1100   common_digests_t ns_digests;
1101   uint8_t sha3_as_signed[DIGEST256_LEN];
1102   const char *cert, *end_of_header, *end_of_footer, *s_dup = s;
1103   directory_token_t *tok;
1104   struct in_addr in;
1105   int i, inorder, n_signatures = 0;
1106   memarea_t *area = NULL, *rs_area = NULL;
1107   consensus_flavor_t flav = FLAV_NS;
1108   char *last_kwd=NULL;
1109   const char *eos = s + s_len;
1110 
1111   tor_assert(s);
1112 
1113   if (eos_out)
1114     *eos_out = NULL;
1115 
1116   if (router_get_networkstatus_v3_hashes(s, s_len, &ns_digests) ||
1117       router_get_networkstatus_v3_sha3_as_signed(sha3_as_signed,
1118                                                  s, s_len)<0) {
1119     log_warn(LD_DIR, "Unable to compute digest of network-status");
1120     goto err;
1121   }
1122 
1123   area = memarea_new();
1124   end_of_header = find_start_of_next_routerstatus(s, eos);
1125   if (tokenize_string(area, s, end_of_header, tokens,
1126                       (ns_type == NS_TYPE_CONSENSUS) ?
1127                       networkstatus_consensus_token_table :
1128                       networkstatus_token_table, 0)) {
1129     log_warn(LD_DIR, "Error tokenizing network-status header");
1130     goto err;
1131   }
1132 
1133   ns = tor_malloc_zero(sizeof(networkstatus_t));
1134   memcpy(&ns->digests, &ns_digests, sizeof(ns_digests));
1135   memcpy(&ns->digest_sha3_as_signed, sha3_as_signed, sizeof(sha3_as_signed));
1136 
1137   tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
1138   tor_assert(tok);
1139   if (tok->n_args > 1) {
1140     int flavor = networkstatus_parse_flavor_name(tok->args[1]);
1141     if (flavor < 0) {
1142       log_warn(LD_DIR, "Can't parse document with unknown flavor %s",
1143                escaped(tok->args[1]));
1144       goto err;
1145     }
1146     ns->flavor = flav = flavor;
1147   }
1148   if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
1149     log_warn(LD_DIR, "Flavor found on non-consensus networkstatus.");
1150     goto err;
1151   }
1152 
1153   if (ns_type != NS_TYPE_CONSENSUS) {
1154     const char *end_of_cert = NULL;
1155     if (!(cert = tor_memstr(s, end_of_header - s,
1156                             "\ndir-key-certificate-version")))
1157       goto err;
1158     ++cert;
1159     ns->cert = authority_cert_parse_from_string(cert, end_of_header - cert,
1160                                                 &end_of_cert);
1161     if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
1162       goto err;
1163   }
1164 
1165   tok = find_by_keyword(tokens, K_VOTE_STATUS);
1166   tor_assert(tok->n_args);
1167   if (!strcmp(tok->args[0], "vote")) {
1168     ns->type = NS_TYPE_VOTE;
1169   } else if (!strcmp(tok->args[0], "consensus")) {
1170     ns->type = NS_TYPE_CONSENSUS;
1171   } else if (!strcmp(tok->args[0], "opinion")) {
1172     ns->type = NS_TYPE_OPINION;
1173   } else {
1174     log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
1175              escaped(tok->args[0]));
1176     goto err;
1177   }
1178   if (ns_type != ns->type) {
1179     log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
1180     goto err;
1181   }
1182 
1183   if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
1184     tok = find_by_keyword(tokens, K_PUBLISHED);
1185     if (parse_iso_time(tok->args[0], &ns->published))
1186       goto err;
1187 
1188     ns->supported_methods = smartlist_new();
1189     tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
1190     if (tok) {
1191       for (i=0; i < tok->n_args; ++i)
1192         smartlist_add_strdup(ns->supported_methods, tok->args[i]);
1193     } else {
1194       smartlist_add_strdup(ns->supported_methods, "1");
1195     }
1196   } else {
1197     tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
1198     if (tok) {
1199       int num_ok;
1200       ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
1201                                                  &num_ok, NULL);
1202       if (!num_ok)
1203         goto err;
1204     } else {
1205       ns->consensus_method = 1;
1206     }
1207   }
1208 
1209   // Reject the vote if any of the protocols lines are malformed.
1210   bool unparseable = false;
1211   ns->recommended_client_protocols = dup_protocols_string(tokens, &unparseable,
1212                                          K_RECOMMENDED_CLIENT_PROTOCOLS);
1213   ns->recommended_relay_protocols = dup_protocols_string(tokens, &unparseable,
1214                                          K_RECOMMENDED_RELAY_PROTOCOLS);
1215   ns->required_client_protocols = dup_protocols_string(tokens, &unparseable,
1216                                          K_REQUIRED_CLIENT_PROTOCOLS);
1217   ns->required_relay_protocols = dup_protocols_string(tokens, &unparseable,
1218                                          K_REQUIRED_RELAY_PROTOCOLS);
1219   if (unparseable)
1220     goto err;
1221 
1222   tok = find_by_keyword(tokens, K_VALID_AFTER);
1223   if (parse_iso_time(tok->args[0], &ns->valid_after))
1224     goto err;
1225 
1226   tok = find_by_keyword(tokens, K_FRESH_UNTIL);
1227   if (parse_iso_time(tok->args[0], &ns->fresh_until))
1228     goto err;
1229 
1230   tok = find_by_keyword(tokens, K_VALID_UNTIL);
1231   if (parse_iso_time(tok->args[0], &ns->valid_until))
1232     goto err;
1233 
1234   tok = find_by_keyword(tokens, K_VOTING_DELAY);
1235   tor_assert(tok->n_args >= 2);
1236   {
1237     int ok;
1238     ns->vote_seconds =
1239       (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
1240     if (!ok)
1241       goto err;
1242     ns->dist_seconds =
1243       (int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL);
1244     if (!ok)
1245       goto err;
1246   }
1247   if (ns->valid_after +
1248       (get_options()->TestingTorNetwork ?
1249        MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL) > ns->fresh_until) {
1250     log_warn(LD_DIR, "Vote/consensus freshness interval is too short");
1251     goto err;
1252   }
1253   if (ns->valid_after +
1254       (get_options()->TestingTorNetwork ?
1255        MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL)*2 > ns->valid_until) {
1256     log_warn(LD_DIR, "Vote/consensus liveness interval is too short");
1257     goto err;
1258   }
1259   if (ns->vote_seconds < MIN_VOTE_SECONDS) {
1260     log_warn(LD_DIR, "Vote seconds is too short");
1261     goto err;
1262   }
1263   if (ns->dist_seconds < MIN_DIST_SECONDS) {
1264     log_warn(LD_DIR, "Dist seconds is too short");
1265     goto err;
1266   }
1267 
1268   if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
1269     ns->client_versions = tor_strdup(tok->args[0]);
1270   }
1271   if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) {
1272     ns->server_versions = tor_strdup(tok->args[0]);
1273   }
1274 
1275   {
1276     smartlist_t *package_lst = find_all_by_keyword(tokens, K_PACKAGE);
1277     ns->package_lines = smartlist_new();
1278     if (package_lst) {
1279       SMARTLIST_FOREACH(package_lst, directory_token_t *, t,
1280                     smartlist_add_strdup(ns->package_lines, t->args[0]));
1281     }
1282     smartlist_free(package_lst);
1283   }
1284 
1285   tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
1286   ns->known_flags = smartlist_new();
1287   inorder = 1;
1288   for (i = 0; i < tok->n_args; ++i) {
1289     smartlist_add_strdup(ns->known_flags, tok->args[i]);
1290     if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) {
1291       log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
1292       inorder = 0;
1293     }
1294   }
1295   if (!inorder) {
1296     log_warn(LD_DIR, "known-flags not in order");
1297     goto err;
1298   }
1299   if (ns->type != NS_TYPE_CONSENSUS &&
1300       smartlist_len(ns->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
1301     /* If we allowed more than 64 flags in votes, then parsing them would make
1302      * us invoke undefined behavior whenever we used 1<<flagnum to do a
1303      * bit-shift. This is only for votes and opinions: consensus users don't
1304      * care about flags they don't recognize, and so don't build a bitfield
1305      * for them. */
1306     log_warn(LD_DIR, "Too many known-flags in consensus vote or opinion");
1307     goto err;
1308   }
1309 
1310   tok = find_opt_by_keyword(tokens, K_PARAMS);
1311   if (tok) {
1312     int any_dups = 0;
1313     inorder = 1;
1314     ns->net_params = smartlist_new();
1315     for (i = 0; i < tok->n_args; ++i) {
1316       int ok=0;
1317       char *eq = strchr(tok->args[i], '=');
1318       size_t eq_pos;
1319       if (!eq) {
1320         log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1321         goto err;
1322       }
1323       eq_pos = eq-tok->args[i];
1324       tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
1325       if (!ok) {
1326         log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1327         goto err;
1328       }
1329       if (i > 0 && strcmp(tok->args[i-1], tok->args[i]) >= 0) {
1330         log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
1331         inorder = 0;
1332       }
1333       if (last_kwd && eq_pos == strlen(last_kwd) &&
1334           fast_memeq(last_kwd, tok->args[i], eq_pos)) {
1335         log_warn(LD_DIR, "Duplicate value for %s parameter",
1336                  escaped(tok->args[i]));
1337         any_dups = 1;
1338       }
1339       tor_free(last_kwd);
1340       last_kwd = tor_strndup(tok->args[i], eq_pos);
1341       smartlist_add_strdup(ns->net_params, tok->args[i]);
1342     }
1343     if (!inorder) {
1344       log_warn(LD_DIR, "params not in order");
1345       goto err;
1346     }
1347     if (any_dups) {
1348       log_warn(LD_DIR, "Duplicate in parameters");
1349       goto err;
1350     }
1351   }
1352 
1353   ns->voters = smartlist_new();
1354 
1355   SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
1356     tok = _tok;
1357     if (tok->tp == K_DIR_SOURCE) {
1358       tor_assert(tok->n_args >= 6);
1359 
1360       if (voter)
1361         smartlist_add(ns->voters, voter);
1362       voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
1363       voter->sigs = smartlist_new();
1364       if (ns->type != NS_TYPE_CONSENSUS)
1365         memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN);
1366 
1367       voter->nickname = tor_strdup(tok->args[0]);
1368       if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
1369           base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
1370                         tok->args[1], HEX_DIGEST_LEN)
1371                         != sizeof(voter->identity_digest)) {
1372         log_warn(LD_DIR, "Error decoding identity digest %s in "
1373                  "network-status document.", escaped(tok->args[1]));
1374         goto err;
1375       }
1376       if (ns->type != NS_TYPE_CONSENSUS &&
1377           tor_memneq(ns->cert->cache_info.identity_digest,
1378                  voter->identity_digest, DIGEST_LEN)) {
1379         log_warn(LD_DIR,"Mismatch between identities in certificate and vote");
1380         goto err;
1381       }
1382       if (ns->type != NS_TYPE_CONSENSUS) {
1383         if (authority_cert_is_denylisted(ns->cert)) {
1384           log_warn(LD_DIR, "Rejecting vote signature made with denylisted "
1385                    "signing key %s",
1386                    hex_str(ns->cert->signing_key_digest, DIGEST_LEN));
1387           goto err;
1388         }
1389       }
1390       voter->address = tor_strdup(tok->args[2]);
1391       if (!tor_inet_aton(tok->args[3], &in)) {
1392         log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
1393                  escaped(tok->args[3]));
1394         goto err;
1395       }
1396       tor_addr_from_in(&voter->ipv4_addr, &in);
1397       int ok;
1398       voter->ipv4_dirport = (uint16_t)
1399         tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
1400       if (!ok)
1401         goto err;
1402       voter->ipv4_orport = (uint16_t)
1403         tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
1404       if (!ok)
1405         goto err;
1406     } else if (tok->tp == K_CONTACT) {
1407       if (!voter || voter->contact) {
1408         log_warn(LD_DIR, "contact element is out of place.");
1409         goto err;
1410       }
1411       voter->contact = tor_strdup(tok->args[0]);
1412     } else if (tok->tp == K_VOTE_DIGEST) {
1413       tor_assert(ns->type == NS_TYPE_CONSENSUS);
1414       tor_assert(tok->n_args >= 1);
1415       if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
1416         log_warn(LD_DIR, "vote-digest element is out of place.");
1417         goto err;
1418       }
1419       if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
1420         base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
1421                       tok->args[0], HEX_DIGEST_LEN)
1422                       != sizeof(voter->vote_digest)) {
1423         log_warn(LD_DIR, "Error decoding vote digest %s in "
1424                  "network-status consensus.", escaped(tok->args[0]));
1425         goto err;
1426       }
1427     }
1428   } SMARTLIST_FOREACH_END(_tok);
1429   if (voter) {
1430     smartlist_add(ns->voters, voter);
1431     voter = NULL;
1432   }
1433   if (smartlist_len(ns->voters) == 0) {
1434     log_warn(LD_DIR, "Missing dir-source elements in a networkstatus.");
1435     goto err;
1436   } else if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->voters) != 1) {
1437     log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
1438     goto err;
1439   }
1440 
1441   if (ns->type != NS_TYPE_CONSENSUS &&
1442       (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
1443     int bad = 1;
1444     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
1445       networkstatus_voter_info_t *voter_0 = smartlist_get(ns->voters, 0);
1446       if (base16_decode(voter_0->legacy_id_digest, DIGEST_LEN,
1447                         tok->args[0], HEX_DIGEST_LEN) != DIGEST_LEN)
1448         bad = 1;
1449       else
1450         bad = 0;
1451     }
1452     if (bad) {
1453       log_warn(LD_DIR, "Invalid legacy key digest %s on vote.",
1454                escaped(tok->args[0]));
1455     }
1456   }
1457 
1458   /* If this is a vote document, check if information about the shared
1459      randomness protocol is included, and extract it. */
1460   if (ns->type == NS_TYPE_VOTE) {
1461     dirvote_parse_sr_commits(ns, tokens);
1462   }
1463   /* For both a vote and consensus, extract the shared random values. */
1464   if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS) {
1465     extract_shared_random_srvs(ns, tokens);
1466   }
1467 
1468   /* Parse routerstatus lines. */
1469   rs_tokens = smartlist_new();
1470   rs_area = memarea_new();
1471   s = end_of_header;
1472   ns->routerstatus_list = smartlist_new();
1473 
1474   while (eos - s >= 2 && fast_memeq(s, "r ", 2)) {
1475     if (ns->type != NS_TYPE_CONSENSUS) {
1476       vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
1477       if (routerstatus_parse_entry_from_string(rs_area, &s, eos, rs_tokens, ns,
1478                                                rs, 0, 0)) {
1479         smartlist_add(ns->routerstatus_list, rs);
1480       } else {
1481         vote_routerstatus_free(rs);
1482         goto err; // Malformed routerstatus, reject this vote.
1483       }
1484     } else {
1485       routerstatus_t *rs;
1486       if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, eos,
1487                                                      rs_tokens,
1488                                                      NULL, NULL,
1489                                                      ns->consensus_method,
1490                                                      flav))) {
1491         /* Use exponential-backoff scheduling when downloading microdescs */
1492         smartlist_add(ns->routerstatus_list, rs);
1493       } else {
1494         goto err; // Malformed routerstatus, reject this vote.
1495       }
1496     }
1497   }
1498   for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
1499     routerstatus_t *rs1, *rs2;
1500     if (ns->type != NS_TYPE_CONSENSUS) {
1501       vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
1502       vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
1503       rs1 = &a->status; rs2 = &b->status;
1504     } else {
1505       rs1 = smartlist_get(ns->routerstatus_list, i-1);
1506       rs2 = smartlist_get(ns->routerstatus_list, i);
1507     }
1508     if (fast_memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN)
1509         >= 0) {
1510       log_warn(LD_DIR, "Networkstatus entries not sorted by identity digest");
1511       goto err;
1512     }
1513   }
1514   if (ns_type != NS_TYPE_CONSENSUS) {
1515     digest256map_t *ed_id_map = digest256map_new();
1516     SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, vote_routerstatus_t *,
1517                             vrs) {
1518       if (! vrs->has_ed25519_listing ||
1519           fast_mem_is_zero((const char *)vrs->ed25519_id, DIGEST256_LEN))
1520         continue;
1521       if (digest256map_get(ed_id_map, vrs->ed25519_id) != NULL) {
1522         log_warn(LD_DIR, "Vote networkstatus ed25519 identities were not "
1523                  "unique");
1524         digest256map_free(ed_id_map, NULL);
1525         goto err;
1526       }
1527       digest256map_set(ed_id_map, vrs->ed25519_id, (void*)1);
1528     } SMARTLIST_FOREACH_END(vrs);
1529     digest256map_free(ed_id_map, NULL);
1530   }
1531 
1532   /* Parse footer; check signature. */
1533   footer_tokens = smartlist_new();
1534   if ((end_of_footer = tor_memstr(s, eos-s, "\nnetwork-status-version ")))
1535     ++end_of_footer;
1536   else
1537     end_of_footer = eos;
1538   if (tokenize_string(area,s, end_of_footer, footer_tokens,
1539                       networkstatus_vote_footer_token_table, 0)) {
1540     log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
1541     goto err;
1542   }
1543 
1544   {
1545     int found_sig = 0;
1546     SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
1547       tok = _tok;
1548       if (tok->tp == K_DIRECTORY_SIGNATURE)
1549         found_sig = 1;
1550       else if (found_sig) {
1551         log_warn(LD_DIR, "Extraneous token after first directory-signature");
1552         goto err;
1553       }
1554     } SMARTLIST_FOREACH_END(_tok);
1555   }
1556 
1557   if ((tok = find_opt_by_keyword(footer_tokens, K_DIRECTORY_FOOTER))) {
1558     if (tok != smartlist_get(footer_tokens, 0)) {
1559       log_warn(LD_DIR, "Misplaced directory-footer token");
1560       goto err;
1561     }
1562   }
1563 
1564   tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS);
1565   if (tok) {
1566     ns->weight_params = smartlist_new();
1567     for (i = 0; i < tok->n_args; ++i) {
1568       int ok=0;
1569       char *eq = strchr(tok->args[i], '=');
1570       if (!eq) {
1571         log_warn(LD_DIR, "Bad element '%s' in weight params",
1572                  escaped(tok->args[i]));
1573         goto err;
1574       }
1575       tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
1576       if (!ok) {
1577         log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1578         goto err;
1579       }
1580       smartlist_add_strdup(ns->weight_params, tok->args[i]);
1581     }
1582   }
1583 
1584   SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
1585     char declared_identity[DIGEST_LEN];
1586     networkstatus_voter_info_t *v;
1587     document_signature_t *sig;
1588     const char *id_hexdigest = NULL;
1589     const char *sk_hexdigest = NULL;
1590     digest_algorithm_t alg = DIGEST_SHA1;
1591     tok = _tok;
1592     if (tok->tp != K_DIRECTORY_SIGNATURE)
1593       continue;
1594     tor_assert(tok->n_args >= 2);
1595     if (tok->n_args == 2) {
1596       id_hexdigest = tok->args[0];
1597       sk_hexdigest = tok->args[1];
1598     } else {
1599       const char *algname = tok->args[0];
1600       int a;
1601       id_hexdigest = tok->args[1];
1602       sk_hexdigest = tok->args[2];
1603       a = crypto_digest_algorithm_parse_name(algname);
1604       if (a<0) {
1605         log_warn(LD_DIR, "Unknown digest algorithm %s; skipping",
1606                  escaped(algname));
1607         continue;
1608       }
1609       alg = a;
1610     }
1611 
1612     if (!tok->object_type ||
1613         strcmp(tok->object_type, "SIGNATURE") ||
1614         tok->object_size < 128 || tok->object_size > 512) {
1615       log_warn(LD_DIR, "Bad object type or length on directory-signature");
1616       goto err;
1617     }
1618 
1619     if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
1620         base16_decode(declared_identity, sizeof(declared_identity),
1621                       id_hexdigest, HEX_DIGEST_LEN)
1622                       != sizeof(declared_identity)) {
1623       log_warn(LD_DIR, "Error decoding declared identity %s in "
1624                "network-status document.", escaped(id_hexdigest));
1625       goto err;
1626     }
1627     if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
1628       log_warn(LD_DIR, "ID on signature on network-status document does "
1629                "not match any declared directory source.");
1630       goto err;
1631     }
1632     sig = tor_malloc_zero(sizeof(document_signature_t));
1633     memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN);
1634     sig->alg = alg;
1635     if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
1636         base16_decode(sig->signing_key_digest, sizeof(sig->signing_key_digest),
1637                       sk_hexdigest, HEX_DIGEST_LEN)
1638                       != sizeof(sig->signing_key_digest)) {
1639       log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
1640                "network-status document.", escaped(sk_hexdigest));
1641       tor_free(sig);
1642       goto err;
1643     }
1644 
1645     if (ns->type != NS_TYPE_CONSENSUS) {
1646       if (tor_memneq(declared_identity, ns->cert->cache_info.identity_digest,
1647                  DIGEST_LEN)) {
1648         log_warn(LD_DIR, "Digest mismatch between declared and actual on "
1649                  "network-status vote.");
1650         tor_free(sig);
1651         goto err;
1652       }
1653     }
1654 
1655     if (networkstatus_get_voter_sig_by_alg(v, sig->alg)) {
1656       /* We already parsed a vote with this algorithm from this voter. Use the
1657          first one. */
1658       log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus "
1659              "that contains two signatures from the same voter with the same "
1660              "algorithm. Ignoring the second signature.");
1661       tor_free(sig);
1662       continue;
1663     }
1664 
1665     if (ns->type != NS_TYPE_CONSENSUS) {
1666       if (check_signature_token(ns_digests.d[DIGEST_SHA1], DIGEST_LEN,
1667                                 tok, ns->cert->signing_key, 0,
1668                                 "network-status document")) {
1669         tor_free(sig);
1670         goto err;
1671       }
1672       sig->good_signature = 1;
1673     } else {
1674       if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
1675         tor_free(sig);
1676         goto err;
1677       }
1678       sig->signature = tor_memdup(tok->object_body, tok->object_size);
1679       sig->signature_len = (int) tok->object_size;
1680     }
1681     smartlist_add(v->sigs, sig);
1682 
1683     ++n_signatures;
1684   } SMARTLIST_FOREACH_END(_tok);
1685 
1686   if (! n_signatures) {
1687     log_warn(LD_DIR, "No signatures on networkstatus document.");
1688     goto err;
1689   } else if (ns->type == NS_TYPE_VOTE && n_signatures != 1) {
1690     log_warn(LD_DIR, "Received more than one signature on a "
1691              "network-status vote.");
1692     goto err;
1693   }
1694 
1695   if (eos_out)
1696     *eos_out = end_of_footer;
1697 
1698   goto done;
1699  err:
1700   dump_desc(s_dup, "v3 networkstatus");
1701   networkstatus_vote_free(ns);
1702   ns = NULL;
1703  done:
1704   if (tokens) {
1705     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
1706     smartlist_free(tokens);
1707   }
1708   if (voter) {
1709     if (voter->sigs) {
1710       SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig,
1711                         document_signature_free(sig));
1712       smartlist_free(voter->sigs);
1713     }
1714     tor_free(voter->nickname);
1715     tor_free(voter->address);
1716     tor_free(voter->contact);
1717     tor_free(voter);
1718   }
1719   if (rs_tokens) {
1720     SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_clear(t));
1721     smartlist_free(rs_tokens);
1722   }
1723   if (footer_tokens) {
1724     SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t));
1725     smartlist_free(footer_tokens);
1726   }
1727   if (area) {
1728     DUMP_AREA(area, "v3 networkstatus");
1729     memarea_drop_all(area);
1730   }
1731   if (rs_area)
1732     memarea_drop_all(rs_area);
1733   tor_free(last_kwd);
1734 
1735   return ns;
1736 }
1737