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