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], "Authority"))
438 rs->is_authority = 1;
439 else if (!strcmp(tok->args[i], "Unnamed") &&
440 consensus_method >= 2) {
441 /* Unnamed is computed right by consensus method 2 and later. */
442 rs->is_unnamed = 1;
443 } else if (!strcmp(tok->args[i], "HSDir")) {
444 rs->is_hs_dir = 1;
445 } else if (!strcmp(tok->args[i], "V2Dir")) {
446 rs->is_v2_dir = 1;
447 } else if (!strcmp(tok->args[i], "StaleDesc")) {
448 rs->is_staledesc = 1;
449 } else if (!strcmp(tok->args[i], "Sybil")) {
450 rs->is_sybil = 1;
451 }
452 }
453 /* These are implied true by having been included in a consensus made
454 * with a given method */
455 rs->is_flagged_running = 1; /* Starting with consensus method 4. */
456 rs->is_valid = 1; /* Starting with consensus method 24. */
457 }
458 {
459 const char *protocols = NULL, *version = NULL;
460 if ((tok = find_opt_by_keyword(tokens, K_PROTO))) {
461 tor_assert(tok->n_args == 1);
462 protocols = tok->args[0];
463 }
464 if ((tok = find_opt_by_keyword(tokens, K_V))) {
465 tor_assert(tok->n_args == 1);
466 version = tok->args[0];
467 if (vote_rs) {
468 vote_rs->version = tor_strdup(tok->args[0]);
469 }
470 }
471
472 // If the protover line is malformed, reject this routerstatus.
473 if (protocols && protover_list_is_invalid(protocols)) {
474 goto err;
475 }
476 summarize_protover_flags(&rs->pv, protocols, version);
477 }
478
479 /* handle weighting/bandwidth info */
480 if ((tok = find_opt_by_keyword(tokens, K_W))) {
481 int i;
482 for (i=0; i < tok->n_args; ++i) {
483 if (!strcmpstart(tok->args[i], "Bandwidth=")) {
484 int ok;
485 rs->bandwidth_kb =
486 (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
487 10, 0, UINT32_MAX,
488 &ok, NULL);
489 if (!ok) {
490 log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i]));
491 goto err;
492 }
493 rs->has_bandwidth = 1;
494 } else if (!strcmpstart(tok->args[i], "Measured=") && vote_rs) {
495 int ok;
496 vote_rs->measured_bw_kb =
497 (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
498 10, 0, UINT32_MAX, &ok, NULL);
499 if (!ok) {
500 log_warn(LD_DIR, "Invalid Measured Bandwidth %s",
501 escaped(tok->args[i]));
502 goto err;
503 }
504 vote_rs->has_measured_bw = 1;
505 vote->has_measured_bws = 1;
506 } else if (!strcmpstart(tok->args[i], "Unmeasured=1")) {
507 rs->bw_is_unmeasured = 1;
508 } else if (!strcmpstart(tok->args[i], "GuardFraction=")) {
509 if (routerstatus_parse_guardfraction(tok->args[i],
510 vote, vote_rs, rs) < 0) {
511 goto err;
512 }
513 }
514 }
515 }
516
517 /* parse exit policy summaries */
518 if ((tok = find_opt_by_keyword(tokens, K_P))) {
519 tor_assert(tok->n_args == 1);
520 if (strcmpstart(tok->args[0], "accept ") &&
521 strcmpstart(tok->args[0], "reject ")) {
522 log_warn(LD_DIR, "Unknown exit policy summary type %s.",
523 escaped(tok->args[0]));
524 goto err;
525 }
526 /* XXX weasel: parse this into ports and represent them somehow smart,
527 * maybe not here but somewhere on if we need it for the client.
528 * we should still parse it here to check it's valid tho.
529 */
530 rs->exitsummary = tor_strdup(tok->args[0]);
531 rs->has_exitsummary = 1;
532 }
533
534 if (vote_rs) {
535 SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, t) {
536 if (t->tp == K_M && t->n_args) {
537 vote_microdesc_hash_t *line =
538 tor_malloc(sizeof(vote_microdesc_hash_t));
539 line->next = vote_rs->microdesc;
540 line->microdesc_hash_line = tor_strdup(t->args[0]);
541 vote_rs->microdesc = line;
542 }
543 if (t->tp == K_ID) {
544 tor_assert(t->n_args >= 2);
545 if (!strcmp(t->args[0], "ed25519")) {
546 vote_rs->has_ed25519_listing = 1;
547 if (strcmp(t->args[1], "none") &&
548 digest256_from_base64((char*)vote_rs->ed25519_id,
549 t->args[1])<0) {
550 log_warn(LD_DIR, "Bogus ed25519 key in networkstatus vote");
551 goto err;
552 }
553 }
554 }
555 if (t->tp == K_PROTO) {
556 tor_assert(t->n_args == 1);
557 vote_rs->protocols = tor_strdup(t->args[0]);
558 }
559 } SMARTLIST_FOREACH_END(t);
560 } else if (flav == FLAV_MICRODESC) {
561 tok = find_opt_by_keyword(tokens, K_M);
562 if (tok) {
563 tor_assert(tok->n_args);
564 if (digest256_from_base64(rs->descriptor_digest, tok->args[0])) {
565 log_warn(LD_DIR, "Error decoding microdescriptor digest %s",
566 escaped(tok->args[0]));
567 goto err;
568 }
569 } else {
570 log_info(LD_BUG, "Found an entry in networkstatus with no "
571 "microdescriptor digest. (Router %s ($%s) at %s:%d.)",
572 rs->nickname, hex_str(rs->identity_digest, DIGEST_LEN),
573 fmt_addr(&rs->ipv4_addr), rs->ipv4_orport);
574 }
575 }
576
577 if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME))
578 rs->is_named = 0;
579
580 goto done;
581 err:
582 dump_desc(s_dup, "routerstatus entry");
583 if (rs && !vote_rs)
584 routerstatus_free(rs);
585 rs = NULL;
586 done:
587 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
588 smartlist_clear(tokens);
589 if (area) {
590 DUMP_AREA(area, "routerstatus entry");
591 memarea_clear(area);
592 }
593 *s = eos;
594
595 return rs;
596 }
597
598 int
compare_vote_routerstatus_entries(const void ** _a,const void ** _b)599 compare_vote_routerstatus_entries(const void **_a, const void **_b)
600 {
601 const vote_routerstatus_t *a = *_a, *b = *_b;
602 return fast_memcmp(a->status.identity_digest, b->status.identity_digest,
603 DIGEST_LEN);
604 }
605
606 /** Verify the bandwidth weights of a network status document */
607 int
networkstatus_verify_bw_weights(networkstatus_t * ns,int consensus_method)608 networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method)
609 {
610 int64_t G=0, M=0, E=0, D=0, T=0;
611 double Wgg, Wgm, Wgd, Wmg, Wmm, Wme, Wmd, Weg, Wem, Wee, Wed;
612 double Gtotal=0, Mtotal=0, Etotal=0;
613 const char *casename = NULL;
614 int valid = 1;
615 (void) consensus_method;
616
617 const int64_t weight_scale = networkstatus_get_weight_scale_param(ns);
618 tor_assert(weight_scale >= 1);
619 Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
620 Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
621 Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
622 Wmg = networkstatus_get_bw_weight(ns, "Wmg", -1);
623 Wmm = networkstatus_get_bw_weight(ns, "Wmm", -1);
624 Wme = networkstatus_get_bw_weight(ns, "Wme", -1);
625 Wmd = networkstatus_get_bw_weight(ns, "Wmd", -1);
626 Weg = networkstatus_get_bw_weight(ns, "Weg", -1);
627 Wem = networkstatus_get_bw_weight(ns, "Wem", -1);
628 Wee = networkstatus_get_bw_weight(ns, "Wee", -1);
629 Wed = networkstatus_get_bw_weight(ns, "Wed", -1);
630
631 if (Wgg<0 || Wgm<0 || Wgd<0 || Wmg<0 || Wmm<0 || Wme<0 || Wmd<0 || Weg<0
632 || Wem<0 || Wee<0 || Wed<0) {
633 log_warn(LD_BUG, "No bandwidth weights produced in consensus!");
634 return 0;
635 }
636
637 // First, sanity check basic summing properties that hold for all cases
638 // We use > 1 as the check for these because they are computed as integers.
639 // Sometimes there are rounding errors.
640 if (fabs(Wmm - weight_scale) > 1) {
641 log_warn(LD_BUG, "Wmm=%f != %"PRId64,
642 Wmm, (weight_scale));
643 valid = 0;
644 }
645
646 if (fabs(Wem - Wee) > 1) {
647 log_warn(LD_BUG, "Wem=%f != Wee=%f", Wem, Wee);
648 valid = 0;
649 }
650
651 if (fabs(Wgm - Wgg) > 1) {
652 log_warn(LD_BUG, "Wgm=%f != Wgg=%f", Wgm, Wgg);
653 valid = 0;
654 }
655
656 if (fabs(Weg - Wed) > 1) {
657 log_warn(LD_BUG, "Wed=%f != Weg=%f", Wed, Weg);
658 valid = 0;
659 }
660
661 if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) {
662 log_warn(LD_BUG, "Wgg=%f != %"PRId64" - Wmg=%f", Wgg,
663 (weight_scale), Wmg);
664 valid = 0;
665 }
666
667 if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) {
668 log_warn(LD_BUG, "Wee=%f != %"PRId64" - Wme=%f", Wee,
669 (weight_scale), Wme);
670 valid = 0;
671 }
672
673 if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) {
674 log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != %"PRId64,
675 Wgd, Wmd, Wed, (weight_scale));
676 valid = 0;
677 }
678
679 Wgg /= weight_scale;
680 Wgm /= weight_scale; (void) Wgm; // unused from here on.
681 Wgd /= weight_scale;
682
683 Wmg /= weight_scale;
684 Wmm /= weight_scale;
685 Wme /= weight_scale;
686 Wmd /= weight_scale;
687
688 Weg /= weight_scale; (void) Weg; // unused from here on.
689 Wem /= weight_scale; (void) Wem; // unused from here on.
690 Wee /= weight_scale;
691 Wed /= weight_scale;
692
693 // Then, gather G, M, E, D, T to determine case
694 SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
695 int is_exit = 0;
696 /* Bug #2203: Don't count bad exits as exits for balancing */
697 is_exit = rs->is_exit && !rs->is_bad_exit;
698 if (rs->has_bandwidth) {
699 T += rs->bandwidth_kb;
700 if (is_exit && rs->is_possible_guard) {
701 D += rs->bandwidth_kb;
702 Gtotal += Wgd*rs->bandwidth_kb;
703 Mtotal += Wmd*rs->bandwidth_kb;
704 Etotal += Wed*rs->bandwidth_kb;
705 } else if (is_exit) {
706 E += rs->bandwidth_kb;
707 Mtotal += Wme*rs->bandwidth_kb;
708 Etotal += Wee*rs->bandwidth_kb;
709 } else if (rs->is_possible_guard) {
710 G += rs->bandwidth_kb;
711 Gtotal += Wgg*rs->bandwidth_kb;
712 Mtotal += Wmg*rs->bandwidth_kb;
713 } else {
714 M += rs->bandwidth_kb;
715 Mtotal += Wmm*rs->bandwidth_kb;
716 }
717 } else {
718 log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
719 routerstatus_describe(rs));
720 }
721 } SMARTLIST_FOREACH_END(rs);
722
723 // Finally, check equality conditions depending upon case 1, 2 or 3
724 // Full equality cases: 1, 3b
725 // Partial equality cases: 2b (E=G), 3a (M=E)
726 // Fully unknown: 2a
727 if (3*E >= T && 3*G >= T) {
728 // Case 1: Neither are scarce
729 casename = "Case 1";
730 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
731 log_warn(LD_DIR,
732 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
733 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
734 " T=%"PRId64". "
735 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
736 casename, Etotal, Mtotal,
737 (G), (M), (E),
738 (D), (T),
739 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
740 valid = 0;
741 }
742 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
743 log_warn(LD_DIR,
744 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
745 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
746 " T=%"PRId64". "
747 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
748 casename, Etotal, Gtotal,
749 (G), (M), (E),
750 (D), (T),
751 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
752 valid = 0;
753 }
754 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
755 log_warn(LD_DIR,
756 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
757 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
758 " T=%"PRId64". "
759 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
760 casename, Mtotal, Gtotal,
761 (G), (M), (E),
762 (D), (T),
763 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
764 valid = 0;
765 }
766 } else if (3*E < T && 3*G < T) {
767 int64_t R = MIN(E, G);
768 int64_t S = MAX(E, G);
769 /*
770 * Case 2: Both Guards and Exits are scarce
771 * Balance D between E and G, depending upon
772 * D capacity and scarcity. Devote no extra
773 * bandwidth to middle nodes.
774 */
775 if (R+D < S) { // Subcase a
776 double Rtotal, Stotal;
777 if (E < G) {
778 Rtotal = Etotal;
779 Stotal = Gtotal;
780 } else {
781 Rtotal = Gtotal;
782 Stotal = Etotal;
783 }
784 casename = "Case 2a";
785 // Rtotal < Stotal
786 if (Rtotal > Stotal) {
787 log_warn(LD_DIR,
788 "Bw Weight Failure for %s: Rtotal %f > Stotal %f. "
789 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
790 " T=%"PRId64". "
791 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
792 casename, Rtotal, Stotal,
793 (G), (M), (E),
794 (D), (T),
795 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
796 valid = 0;
797 }
798 // Rtotal < T/3
799 if (3*Rtotal > T) {
800 log_warn(LD_DIR,
801 "Bw Weight Failure for %s: 3*Rtotal %f > T "
802 "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
803 " D=%"PRId64" T=%"PRId64". "
804 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
805 casename, Rtotal*3, (T),
806 (G), (M), (E),
807 (D), (T),
808 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
809 valid = 0;
810 }
811 // Stotal < T/3
812 if (3*Stotal > T) {
813 log_warn(LD_DIR,
814 "Bw Weight Failure for %s: 3*Stotal %f > T "
815 "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
816 " D=%"PRId64" T=%"PRId64". "
817 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
818 casename, Stotal*3, (T),
819 (G), (M), (E),
820 (D), (T),
821 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
822 valid = 0;
823 }
824 // Mtotal > T/3
825 if (3*Mtotal < T) {
826 log_warn(LD_DIR,
827 "Bw Weight Failure for %s: 3*Mtotal %f < T "
828 "%"PRId64". "
829 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
830 " T=%"PRId64". "
831 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
832 casename, Mtotal*3, (T),
833 (G), (M), (E),
834 (D), (T),
835 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
836 valid = 0;
837 }
838 } else { // Subcase b: R+D > S
839 casename = "Case 2b";
840
841 /* Check the rare-M redirect case. */
842 if (D != 0 && 3*M < T) {
843 casename = "Case 2b (balanced)";
844 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
845 log_warn(LD_DIR,
846 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
847 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
848 " T=%"PRId64". "
849 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
850 casename, Etotal, Mtotal,
851 (G), (M), (E),
852 (D), (T),
853 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
854 valid = 0;
855 }
856 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
857 log_warn(LD_DIR,
858 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
859 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
860 " T=%"PRId64". "
861 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
862 casename, Etotal, Gtotal,
863 (G), (M), (E),
864 (D), (T),
865 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
866 valid = 0;
867 }
868 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
869 log_warn(LD_DIR,
870 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
871 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
872 " T=%"PRId64". "
873 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
874 casename, Mtotal, Gtotal,
875 (G), (M), (E),
876 (D), (T),
877 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
878 valid = 0;
879 }
880 } else {
881 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
882 log_warn(LD_DIR,
883 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
884 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
885 " T=%"PRId64". "
886 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
887 casename, Etotal, Gtotal,
888 (G), (M), (E),
889 (D), (T),
890 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
891 valid = 0;
892 }
893 }
894 }
895 } else { // if (E < T/3 || G < T/3) {
896 int64_t S = MIN(E, G);
897 int64_t NS = MAX(E, G);
898 if (3*(S+D) < T) { // Subcase a:
899 double Stotal;
900 double NStotal;
901 if (G < E) {
902 casename = "Case 3a (G scarce)";
903 Stotal = Gtotal;
904 NStotal = Etotal;
905 } else { // if (G >= E) {
906 casename = "Case 3a (E scarce)";
907 NStotal = Gtotal;
908 Stotal = Etotal;
909 }
910 // Stotal < T/3
911 if (3*Stotal > T) {
912 log_warn(LD_DIR,
913 "Bw Weight Failure for %s: 3*Stotal %f > T "
914 "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
915 " D=%"PRId64" T=%"PRId64". "
916 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
917 casename, Stotal*3, (T),
918 (G), (M), (E),
919 (D), (T),
920 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
921 valid = 0;
922 }
923 if (NS >= M) {
924 if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) {
925 log_warn(LD_DIR,
926 "Bw Weight Failure for %s: NStotal %f != Mtotal %f. "
927 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
928 " T=%"PRId64". "
929 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
930 casename, NStotal, Mtotal,
931 (G), (M), (E),
932 (D), (T),
933 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
934 valid = 0;
935 }
936 } else {
937 // if NS < M, NStotal > T/3 because only one of G or E is scarce
938 if (3*NStotal < T) {
939 log_warn(LD_DIR,
940 "Bw Weight Failure for %s: 3*NStotal %f < T "
941 "%"PRId64". G=%"PRId64" M=%"PRId64
942 " E=%"PRId64" D=%"PRId64" T=%"PRId64". "
943 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
944 casename, NStotal*3, (T),
945 (G), (M), (E),
946 (D), (T),
947 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
948 valid = 0;
949 }
950 }
951 } else { // Subcase b: S+D >= T/3
952 casename = "Case 3b";
953 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
954 log_warn(LD_DIR,
955 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
956 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
957 " T=%"PRId64". "
958 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
959 casename, Etotal, Mtotal,
960 (G), (M), (E),
961 (D), (T),
962 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
963 valid = 0;
964 }
965 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
966 log_warn(LD_DIR,
967 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
968 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
969 " T=%"PRId64". "
970 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
971 casename, Etotal, Gtotal,
972 (G), (M), (E),
973 (D), (T),
974 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
975 valid = 0;
976 }
977 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
978 log_warn(LD_DIR,
979 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
980 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
981 " T=%"PRId64". "
982 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
983 casename, Mtotal, Gtotal,
984 (G), (M), (E),
985 (D), (T),
986 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
987 valid = 0;
988 }
989 }
990 }
991
992 if (valid)
993 log_notice(LD_DIR, "Bandwidth-weight %s is verified and valid.",
994 casename);
995
996 return valid;
997 }
998
999 /** Check if a shared random value of type <b>srv_type</b> is in
1000 * <b>tokens</b>. If there is, parse it and set it to <b>srv_out</b>. Return
1001 * -1 on failure, 0 on success. The resulting srv is allocated on the heap and
1002 * it's the responsibility of the caller to free it. */
1003 static int
extract_one_srv(smartlist_t * tokens,directory_keyword srv_type,sr_srv_t ** srv_out)1004 extract_one_srv(smartlist_t *tokens, directory_keyword srv_type,
1005 sr_srv_t **srv_out)
1006 {
1007 int ret = -1;
1008 directory_token_t *tok;
1009 sr_srv_t *srv = NULL;
1010 smartlist_t *chunks;
1011
1012 tor_assert(tokens);
1013
1014 chunks = smartlist_new();
1015 tok = find_opt_by_keyword(tokens, srv_type);
1016 if (!tok) {
1017 /* That's fine, no SRV is allowed. */
1018 ret = 0;
1019 goto end;
1020 }
1021 for (int i = 0; i < tok->n_args; i++) {
1022 smartlist_add(chunks, tok->args[i]);
1023 }
1024 srv = sr_parse_srv(chunks);
1025 if (srv == NULL) {
1026 log_warn(LD_DIR, "SR: Unparseable SRV %s", escaped(tok->object_body));
1027 goto end;
1028 }
1029 /* All is good. */
1030 *srv_out = srv;
1031 ret = 0;
1032 end:
1033 smartlist_free(chunks);
1034 return ret;
1035 }
1036
1037 /** Extract any shared random values found in <b>tokens</b> and place them in
1038 * the networkstatus <b>ns</b>. */
1039 static void
extract_shared_random_srvs(networkstatus_t * ns,smartlist_t * tokens)1040 extract_shared_random_srvs(networkstatus_t *ns, smartlist_t *tokens)
1041 {
1042 const char *voter_identity;
1043 networkstatus_voter_info_t *voter;
1044
1045 tor_assert(ns);
1046 tor_assert(tokens);
1047 /* Can be only one of them else code flow. */
1048 tor_assert(ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS);
1049
1050 if (ns->type == NS_TYPE_VOTE) {
1051 voter = smartlist_get(ns->voters, 0);
1052 tor_assert(voter);
1053 voter_identity = hex_str(voter->identity_digest,
1054 sizeof(voter->identity_digest));
1055 } else {
1056 /* Consensus has multiple voters so no specific voter. */
1057 voter_identity = "consensus";
1058 }
1059
1060 /* We extract both, and on error everything is stopped because it means
1061 * the vote is malformed for the shared random value(s). */
1062 if (extract_one_srv(tokens, K_PREVIOUS_SRV, &ns->sr_info.previous_srv) < 0) {
1063 log_warn(LD_DIR, "SR: Unable to parse previous SRV from %s",
1064 voter_identity);
1065 /* Maybe we have a chance with the current SRV so let's try it anyway. */
1066 }
1067 if (extract_one_srv(tokens, K_CURRENT_SRV, &ns->sr_info.current_srv) < 0) {
1068 log_warn(LD_DIR, "SR: Unable to parse current SRV from %s",
1069 voter_identity);
1070 }
1071 }
1072
1073 /** Allocate a copy of a protover line, if present. If present but malformed,
1074 * set *error to true. */
1075 static char *
dup_protocols_string(smartlist_t * tokens,bool * error,directory_keyword kw)1076 dup_protocols_string(smartlist_t *tokens, bool *error, directory_keyword kw)
1077 {
1078 directory_token_t *tok = find_opt_by_keyword(tokens, kw);
1079 if (!tok)
1080 return NULL;
1081 if (protover_list_is_invalid(tok->args[0]))
1082 *error = true;
1083 return tor_strdup(tok->args[0]);
1084 }
1085
1086 /** Parse a v3 networkstatus vote, opinion, or consensus (depending on
1087 * ns_type), from <b>s</b>, and return the result. Return NULL on failure. */
1088 networkstatus_t *
networkstatus_parse_vote_from_string(const char * s,size_t s_len,const char ** eos_out,networkstatus_type_t ns_type)1089 networkstatus_parse_vote_from_string(const char *s,
1090 size_t s_len,
1091 const char **eos_out,
1092 networkstatus_type_t ns_type)
1093 {
1094 smartlist_t *tokens = smartlist_new();
1095 smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
1096 networkstatus_voter_info_t *voter = NULL;
1097 networkstatus_t *ns = NULL;
1098 common_digests_t ns_digests;
1099 uint8_t sha3_as_signed[DIGEST256_LEN];
1100 const char *cert, *end_of_header, *end_of_footer, *s_dup = s;
1101 directory_token_t *tok;
1102 struct in_addr in;
1103 int i, inorder, n_signatures = 0;
1104 memarea_t *area = NULL, *rs_area = NULL;
1105 consensus_flavor_t flav = FLAV_NS;
1106 char *last_kwd=NULL;
1107 const char *eos = s + s_len;
1108
1109 tor_assert(s);
1110
1111 if (eos_out)
1112 *eos_out = NULL;
1113
1114 if (router_get_networkstatus_v3_hashes(s, s_len, &ns_digests) ||
1115 router_get_networkstatus_v3_sha3_as_signed(sha3_as_signed,
1116 s, s_len)<0) {
1117 log_warn(LD_DIR, "Unable to compute digest of network-status");
1118 goto err;
1119 }
1120
1121 area = memarea_new();
1122 end_of_header = find_start_of_next_routerstatus(s, eos);
1123 if (tokenize_string(area, s, end_of_header, tokens,
1124 (ns_type == NS_TYPE_CONSENSUS) ?
1125 networkstatus_consensus_token_table :
1126 networkstatus_token_table, 0)) {
1127 log_warn(LD_DIR, "Error tokenizing network-status header");
1128 goto err;
1129 }
1130
1131 ns = tor_malloc_zero(sizeof(networkstatus_t));
1132 memcpy(&ns->digests, &ns_digests, sizeof(ns_digests));
1133 memcpy(&ns->digest_sha3_as_signed, sha3_as_signed, sizeof(sha3_as_signed));
1134
1135 tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
1136 tor_assert(tok);
1137 if (tok->n_args > 1) {
1138 int flavor = networkstatus_parse_flavor_name(tok->args[1]);
1139 if (flavor < 0) {
1140 log_warn(LD_DIR, "Can't parse document with unknown flavor %s",
1141 escaped(tok->args[1]));
1142 goto err;
1143 }
1144 ns->flavor = flav = flavor;
1145 }
1146 if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
1147 log_warn(LD_DIR, "Flavor found on non-consensus networkstatus.");
1148 goto err;
1149 }
1150
1151 if (ns_type != NS_TYPE_CONSENSUS) {
1152 const char *end_of_cert = NULL;
1153 if (!(cert = tor_memstr(s, end_of_header - s,
1154 "\ndir-key-certificate-version")))
1155 goto err;
1156 ++cert;
1157 ns->cert = authority_cert_parse_from_string(cert, end_of_header - cert,
1158 &end_of_cert);
1159 if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
1160 goto err;
1161 }
1162
1163 tok = find_by_keyword(tokens, K_VOTE_STATUS);
1164 tor_assert(tok->n_args);
1165 if (!strcmp(tok->args[0], "vote")) {
1166 ns->type = NS_TYPE_VOTE;
1167 } else if (!strcmp(tok->args[0], "consensus")) {
1168 ns->type = NS_TYPE_CONSENSUS;
1169 } else if (!strcmp(tok->args[0], "opinion")) {
1170 ns->type = NS_TYPE_OPINION;
1171 } else {
1172 log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
1173 escaped(tok->args[0]));
1174 goto err;
1175 }
1176 if (ns_type != ns->type) {
1177 log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
1178 goto err;
1179 }
1180
1181 if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
1182 tok = find_by_keyword(tokens, K_PUBLISHED);
1183 if (parse_iso_time(tok->args[0], &ns->published))
1184 goto err;
1185
1186 ns->supported_methods = smartlist_new();
1187 tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
1188 if (tok) {
1189 for (i=0; i < tok->n_args; ++i)
1190 smartlist_add_strdup(ns->supported_methods, tok->args[i]);
1191 } else {
1192 smartlist_add_strdup(ns->supported_methods, "1");
1193 }
1194 } else {
1195 tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
1196 if (tok) {
1197 int num_ok;
1198 ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
1199 &num_ok, NULL);
1200 if (!num_ok)
1201 goto err;
1202 } else {
1203 ns->consensus_method = 1;
1204 }
1205 }
1206
1207 // Reject the vote if any of the protocols lines are malformed.
1208 bool unparseable = false;
1209 ns->recommended_client_protocols = dup_protocols_string(tokens, &unparseable,
1210 K_RECOMMENDED_CLIENT_PROTOCOLS);
1211 ns->recommended_relay_protocols = dup_protocols_string(tokens, &unparseable,
1212 K_RECOMMENDED_RELAY_PROTOCOLS);
1213 ns->required_client_protocols = dup_protocols_string(tokens, &unparseable,
1214 K_REQUIRED_CLIENT_PROTOCOLS);
1215 ns->required_relay_protocols = dup_protocols_string(tokens, &unparseable,
1216 K_REQUIRED_RELAY_PROTOCOLS);
1217 if (unparseable)
1218 goto err;
1219
1220 tok = find_by_keyword(tokens, K_VALID_AFTER);
1221 if (parse_iso_time(tok->args[0], &ns->valid_after))
1222 goto err;
1223
1224 tok = find_by_keyword(tokens, K_FRESH_UNTIL);
1225 if (parse_iso_time(tok->args[0], &ns->fresh_until))
1226 goto err;
1227
1228 tok = find_by_keyword(tokens, K_VALID_UNTIL);
1229 if (parse_iso_time(tok->args[0], &ns->valid_until))
1230 goto err;
1231
1232 tok = find_by_keyword(tokens, K_VOTING_DELAY);
1233 tor_assert(tok->n_args >= 2);
1234 {
1235 int ok;
1236 ns->vote_seconds =
1237 (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
1238 if (!ok)
1239 goto err;
1240 ns->dist_seconds =
1241 (int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL);
1242 if (!ok)
1243 goto err;
1244 }
1245 if (ns->valid_after +
1246 (get_options()->TestingTorNetwork ?
1247 MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL) > ns->fresh_until) {
1248 log_warn(LD_DIR, "Vote/consensus freshness interval is too short");
1249 goto err;
1250 }
1251 if (ns->valid_after +
1252 (get_options()->TestingTorNetwork ?
1253 MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL)*2 > ns->valid_until) {
1254 log_warn(LD_DIR, "Vote/consensus liveness interval is too short");
1255 goto err;
1256 }
1257 if (ns->vote_seconds < MIN_VOTE_SECONDS) {
1258 log_warn(LD_DIR, "Vote seconds is too short");
1259 goto err;
1260 }
1261 if (ns->dist_seconds < MIN_DIST_SECONDS) {
1262 log_warn(LD_DIR, "Dist seconds is too short");
1263 goto err;
1264 }
1265
1266 if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
1267 ns->client_versions = tor_strdup(tok->args[0]);
1268 }
1269 if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) {
1270 ns->server_versions = tor_strdup(tok->args[0]);
1271 }
1272
1273 {
1274 smartlist_t *package_lst = find_all_by_keyword(tokens, K_PACKAGE);
1275 ns->package_lines = smartlist_new();
1276 if (package_lst) {
1277 SMARTLIST_FOREACH(package_lst, directory_token_t *, t,
1278 smartlist_add_strdup(ns->package_lines, t->args[0]));
1279 }
1280 smartlist_free(package_lst);
1281 }
1282
1283 tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
1284 ns->known_flags = smartlist_new();
1285 inorder = 1;
1286 for (i = 0; i < tok->n_args; ++i) {
1287 smartlist_add_strdup(ns->known_flags, tok->args[i]);
1288 if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) {
1289 log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
1290 inorder = 0;
1291 }
1292 }
1293 if (!inorder) {
1294 log_warn(LD_DIR, "known-flags not in order");
1295 goto err;
1296 }
1297 if (ns->type != NS_TYPE_CONSENSUS &&
1298 smartlist_len(ns->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
1299 /* If we allowed more than 64 flags in votes, then parsing them would make
1300 * us invoke undefined behavior whenever we used 1<<flagnum to do a
1301 * bit-shift. This is only for votes and opinions: consensus users don't
1302 * care about flags they don't recognize, and so don't build a bitfield
1303 * for them. */
1304 log_warn(LD_DIR, "Too many known-flags in consensus vote or opinion");
1305 goto err;
1306 }
1307
1308 tok = find_opt_by_keyword(tokens, K_PARAMS);
1309 if (tok) {
1310 int any_dups = 0;
1311 inorder = 1;
1312 ns->net_params = smartlist_new();
1313 for (i = 0; i < tok->n_args; ++i) {
1314 int ok=0;
1315 char *eq = strchr(tok->args[i], '=');
1316 size_t eq_pos;
1317 if (!eq) {
1318 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1319 goto err;
1320 }
1321 eq_pos = eq-tok->args[i];
1322 tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
1323 if (!ok) {
1324 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1325 goto err;
1326 }
1327 if (i > 0 && strcmp(tok->args[i-1], tok->args[i]) >= 0) {
1328 log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
1329 inorder = 0;
1330 }
1331 if (last_kwd && eq_pos == strlen(last_kwd) &&
1332 fast_memeq(last_kwd, tok->args[i], eq_pos)) {
1333 log_warn(LD_DIR, "Duplicate value for %s parameter",
1334 escaped(tok->args[i]));
1335 any_dups = 1;
1336 }
1337 tor_free(last_kwd);
1338 last_kwd = tor_strndup(tok->args[i], eq_pos);
1339 smartlist_add_strdup(ns->net_params, tok->args[i]);
1340 }
1341 if (!inorder) {
1342 log_warn(LD_DIR, "params not in order");
1343 goto err;
1344 }
1345 if (any_dups) {
1346 log_warn(LD_DIR, "Duplicate in parameters");
1347 goto err;
1348 }
1349 }
1350
1351 ns->voters = smartlist_new();
1352
1353 SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
1354 tok = _tok;
1355 if (tok->tp == K_DIR_SOURCE) {
1356 tor_assert(tok->n_args >= 6);
1357
1358 if (voter)
1359 smartlist_add(ns->voters, voter);
1360 voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
1361 voter->sigs = smartlist_new();
1362 if (ns->type != NS_TYPE_CONSENSUS)
1363 memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN);
1364
1365 voter->nickname = tor_strdup(tok->args[0]);
1366 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
1367 base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
1368 tok->args[1], HEX_DIGEST_LEN)
1369 != sizeof(voter->identity_digest)) {
1370 log_warn(LD_DIR, "Error decoding identity digest %s in "
1371 "network-status document.", escaped(tok->args[1]));
1372 goto err;
1373 }
1374 if (ns->type != NS_TYPE_CONSENSUS &&
1375 tor_memneq(ns->cert->cache_info.identity_digest,
1376 voter->identity_digest, DIGEST_LEN)) {
1377 log_warn(LD_DIR,"Mismatch between identities in certificate and vote");
1378 goto err;
1379 }
1380 if (ns->type != NS_TYPE_CONSENSUS) {
1381 if (authority_cert_is_denylisted(ns->cert)) {
1382 log_warn(LD_DIR, "Rejecting vote signature made with denylisted "
1383 "signing key %s",
1384 hex_str(ns->cert->signing_key_digest, DIGEST_LEN));
1385 goto err;
1386 }
1387 }
1388 voter->address = tor_strdup(tok->args[2]);
1389 if (!tor_inet_aton(tok->args[3], &in)) {
1390 log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
1391 escaped(tok->args[3]));
1392 goto err;
1393 }
1394 tor_addr_from_in(&voter->ipv4_addr, &in);
1395 int ok;
1396 voter->ipv4_dirport = (uint16_t)
1397 tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
1398 if (!ok)
1399 goto err;
1400 voter->ipv4_orport = (uint16_t)
1401 tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
1402 if (!ok)
1403 goto err;
1404 } else if (tok->tp == K_CONTACT) {
1405 if (!voter || voter->contact) {
1406 log_warn(LD_DIR, "contact element is out of place.");
1407 goto err;
1408 }
1409 voter->contact = tor_strdup(tok->args[0]);
1410 } else if (tok->tp == K_VOTE_DIGEST) {
1411 tor_assert(ns->type == NS_TYPE_CONSENSUS);
1412 tor_assert(tok->n_args >= 1);
1413 if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
1414 log_warn(LD_DIR, "vote-digest element is out of place.");
1415 goto err;
1416 }
1417 if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
1418 base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
1419 tok->args[0], HEX_DIGEST_LEN)
1420 != sizeof(voter->vote_digest)) {
1421 log_warn(LD_DIR, "Error decoding vote digest %s in "
1422 "network-status consensus.", escaped(tok->args[0]));
1423 goto err;
1424 }
1425 }
1426 } SMARTLIST_FOREACH_END(_tok);
1427 if (voter) {
1428 smartlist_add(ns->voters, voter);
1429 voter = NULL;
1430 }
1431 if (smartlist_len(ns->voters) == 0) {
1432 log_warn(LD_DIR, "Missing dir-source elements in a networkstatus.");
1433 goto err;
1434 } else if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->voters) != 1) {
1435 log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
1436 goto err;
1437 }
1438
1439 if (ns->type != NS_TYPE_CONSENSUS &&
1440 (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
1441 int bad = 1;
1442 if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
1443 networkstatus_voter_info_t *voter_0 = smartlist_get(ns->voters, 0);
1444 if (base16_decode(voter_0->legacy_id_digest, DIGEST_LEN,
1445 tok->args[0], HEX_DIGEST_LEN) != DIGEST_LEN)
1446 bad = 1;
1447 else
1448 bad = 0;
1449 }
1450 if (bad) {
1451 log_warn(LD_DIR, "Invalid legacy key digest %s on vote.",
1452 escaped(tok->args[0]));
1453 }
1454 }
1455
1456 /* If this is a vote document, check if information about the shared
1457 randomness protocol is included, and extract it. */
1458 if (ns->type == NS_TYPE_VOTE) {
1459 dirvote_parse_sr_commits(ns, tokens);
1460 }
1461 /* For both a vote and consensus, extract the shared random values. */
1462 if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS) {
1463 extract_shared_random_srvs(ns, tokens);
1464 }
1465
1466 /* Parse routerstatus lines. */
1467 rs_tokens = smartlist_new();
1468 rs_area = memarea_new();
1469 s = end_of_header;
1470 ns->routerstatus_list = smartlist_new();
1471
1472 while (eos - s >= 2 && fast_memeq(s, "r ", 2)) {
1473 if (ns->type != NS_TYPE_CONSENSUS) {
1474 vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
1475 if (routerstatus_parse_entry_from_string(rs_area, &s, eos, rs_tokens, ns,
1476 rs, 0, 0)) {
1477 smartlist_add(ns->routerstatus_list, rs);
1478 } else {
1479 vote_routerstatus_free(rs);
1480 goto err; // Malformed routerstatus, reject this vote.
1481 }
1482 } else {
1483 routerstatus_t *rs;
1484 if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, eos,
1485 rs_tokens,
1486 NULL, NULL,
1487 ns->consensus_method,
1488 flav))) {
1489 /* Use exponential-backoff scheduling when downloading microdescs */
1490 smartlist_add(ns->routerstatus_list, rs);
1491 } else {
1492 goto err; // Malformed routerstatus, reject this vote.
1493 }
1494 }
1495 }
1496 for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
1497 routerstatus_t *rs1, *rs2;
1498 if (ns->type != NS_TYPE_CONSENSUS) {
1499 vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
1500 vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
1501 rs1 = &a->status; rs2 = &b->status;
1502 } else {
1503 rs1 = smartlist_get(ns->routerstatus_list, i-1);
1504 rs2 = smartlist_get(ns->routerstatus_list, i);
1505 }
1506 if (fast_memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN)
1507 >= 0) {
1508 log_warn(LD_DIR, "Networkstatus entries not sorted by identity digest");
1509 goto err;
1510 }
1511 }
1512 if (ns_type != NS_TYPE_CONSENSUS) {
1513 digest256map_t *ed_id_map = digest256map_new();
1514 SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, vote_routerstatus_t *,
1515 vrs) {
1516 if (! vrs->has_ed25519_listing ||
1517 fast_mem_is_zero((const char *)vrs->ed25519_id, DIGEST256_LEN))
1518 continue;
1519 if (digest256map_get(ed_id_map, vrs->ed25519_id) != NULL) {
1520 log_warn(LD_DIR, "Vote networkstatus ed25519 identities were not "
1521 "unique");
1522 digest256map_free(ed_id_map, NULL);
1523 goto err;
1524 }
1525 digest256map_set(ed_id_map, vrs->ed25519_id, (void*)1);
1526 } SMARTLIST_FOREACH_END(vrs);
1527 digest256map_free(ed_id_map, NULL);
1528 }
1529
1530 /* Parse footer; check signature. */
1531 footer_tokens = smartlist_new();
1532 if ((end_of_footer = tor_memstr(s, eos-s, "\nnetwork-status-version ")))
1533 ++end_of_footer;
1534 else
1535 end_of_footer = eos;
1536 if (tokenize_string(area,s, end_of_footer, footer_tokens,
1537 networkstatus_vote_footer_token_table, 0)) {
1538 log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
1539 goto err;
1540 }
1541
1542 {
1543 int found_sig = 0;
1544 SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
1545 tok = _tok;
1546 if (tok->tp == K_DIRECTORY_SIGNATURE)
1547 found_sig = 1;
1548 else if (found_sig) {
1549 log_warn(LD_DIR, "Extraneous token after first directory-signature");
1550 goto err;
1551 }
1552 } SMARTLIST_FOREACH_END(_tok);
1553 }
1554
1555 if ((tok = find_opt_by_keyword(footer_tokens, K_DIRECTORY_FOOTER))) {
1556 if (tok != smartlist_get(footer_tokens, 0)) {
1557 log_warn(LD_DIR, "Misplaced directory-footer token");
1558 goto err;
1559 }
1560 }
1561
1562 tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS);
1563 if (tok) {
1564 ns->weight_params = smartlist_new();
1565 for (i = 0; i < tok->n_args; ++i) {
1566 int ok=0;
1567 char *eq = strchr(tok->args[i], '=');
1568 if (!eq) {
1569 log_warn(LD_DIR, "Bad element '%s' in weight params",
1570 escaped(tok->args[i]));
1571 goto err;
1572 }
1573 tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
1574 if (!ok) {
1575 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1576 goto err;
1577 }
1578 smartlist_add_strdup(ns->weight_params, tok->args[i]);
1579 }
1580 }
1581
1582 SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
1583 char declared_identity[DIGEST_LEN];
1584 networkstatus_voter_info_t *v;
1585 document_signature_t *sig;
1586 const char *id_hexdigest = NULL;
1587 const char *sk_hexdigest = NULL;
1588 digest_algorithm_t alg = DIGEST_SHA1;
1589 tok = _tok;
1590 if (tok->tp != K_DIRECTORY_SIGNATURE)
1591 continue;
1592 tor_assert(tok->n_args >= 2);
1593 if (tok->n_args == 2) {
1594 id_hexdigest = tok->args[0];
1595 sk_hexdigest = tok->args[1];
1596 } else {
1597 const char *algname = tok->args[0];
1598 int a;
1599 id_hexdigest = tok->args[1];
1600 sk_hexdigest = tok->args[2];
1601 a = crypto_digest_algorithm_parse_name(algname);
1602 if (a<0) {
1603 log_warn(LD_DIR, "Unknown digest algorithm %s; skipping",
1604 escaped(algname));
1605 continue;
1606 }
1607 alg = a;
1608 }
1609
1610 if (!tok->object_type ||
1611 strcmp(tok->object_type, "SIGNATURE") ||
1612 tok->object_size < 128 || tok->object_size > 512) {
1613 log_warn(LD_DIR, "Bad object type or length on directory-signature");
1614 goto err;
1615 }
1616
1617 if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
1618 base16_decode(declared_identity, sizeof(declared_identity),
1619 id_hexdigest, HEX_DIGEST_LEN)
1620 != sizeof(declared_identity)) {
1621 log_warn(LD_DIR, "Error decoding declared identity %s in "
1622 "network-status document.", escaped(id_hexdigest));
1623 goto err;
1624 }
1625 if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
1626 log_warn(LD_DIR, "ID on signature on network-status document does "
1627 "not match any declared directory source.");
1628 goto err;
1629 }
1630 sig = tor_malloc_zero(sizeof(document_signature_t));
1631 memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN);
1632 sig->alg = alg;
1633 if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
1634 base16_decode(sig->signing_key_digest, sizeof(sig->signing_key_digest),
1635 sk_hexdigest, HEX_DIGEST_LEN)
1636 != sizeof(sig->signing_key_digest)) {
1637 log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
1638 "network-status document.", escaped(sk_hexdigest));
1639 tor_free(sig);
1640 goto err;
1641 }
1642
1643 if (ns->type != NS_TYPE_CONSENSUS) {
1644 if (tor_memneq(declared_identity, ns->cert->cache_info.identity_digest,
1645 DIGEST_LEN)) {
1646 log_warn(LD_DIR, "Digest mismatch between declared and actual on "
1647 "network-status vote.");
1648 tor_free(sig);
1649 goto err;
1650 }
1651 }
1652
1653 if (networkstatus_get_voter_sig_by_alg(v, sig->alg)) {
1654 /* We already parsed a vote with this algorithm from this voter. Use the
1655 first one. */
1656 log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus "
1657 "that contains two signatures from the same voter with the same "
1658 "algorithm. Ignoring the second signature.");
1659 tor_free(sig);
1660 continue;
1661 }
1662
1663 if (ns->type != NS_TYPE_CONSENSUS) {
1664 if (check_signature_token(ns_digests.d[DIGEST_SHA1], DIGEST_LEN,
1665 tok, ns->cert->signing_key, 0,
1666 "network-status document")) {
1667 tor_free(sig);
1668 goto err;
1669 }
1670 sig->good_signature = 1;
1671 } else {
1672 if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
1673 tor_free(sig);
1674 goto err;
1675 }
1676 sig->signature = tor_memdup(tok->object_body, tok->object_size);
1677 sig->signature_len = (int) tok->object_size;
1678 }
1679 smartlist_add(v->sigs, sig);
1680
1681 ++n_signatures;
1682 } SMARTLIST_FOREACH_END(_tok);
1683
1684 if (! n_signatures) {
1685 log_warn(LD_DIR, "No signatures on networkstatus document.");
1686 goto err;
1687 } else if (ns->type == NS_TYPE_VOTE && n_signatures != 1) {
1688 log_warn(LD_DIR, "Received more than one signature on a "
1689 "network-status vote.");
1690 goto err;
1691 }
1692
1693 if (eos_out)
1694 *eos_out = end_of_footer;
1695
1696 goto done;
1697 err:
1698 dump_desc(s_dup, "v3 networkstatus");
1699 networkstatus_vote_free(ns);
1700 ns = NULL;
1701 done:
1702 if (tokens) {
1703 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
1704 smartlist_free(tokens);
1705 }
1706 if (voter) {
1707 if (voter->sigs) {
1708 SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig,
1709 document_signature_free(sig));
1710 smartlist_free(voter->sigs);
1711 }
1712 tor_free(voter->nickname);
1713 tor_free(voter->address);
1714 tor_free(voter->contact);
1715 tor_free(voter);
1716 }
1717 if (rs_tokens) {
1718 SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_clear(t));
1719 smartlist_free(rs_tokens);
1720 }
1721 if (footer_tokens) {
1722 SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t));
1723 smartlist_free(footer_tokens);
1724 }
1725 if (area) {
1726 DUMP_AREA(area, "v3 networkstatus");
1727 memarea_drop_all(area);
1728 }
1729 if (rs_area)
1730 memarea_drop_all(rs_area);
1731 tor_free(last_kwd);
1732
1733 return ns;
1734 }
1735