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