diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c index b3653a79e7..6289b4c018 100644 --- a/src/feature/dirparse/routerparse.c +++ b/src/feature/dirparse/routerparse.c @@ -90,7 +90,7 @@ const token_rule_t routerdesc_token_table[] = { T1_START( "router", K_ROUTER, GE(5), NO_OBJ ), T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ), T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ), - T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ), + T01("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ), T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ), T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ), T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), @@ -107,7 +107,7 @@ const token_rule_t routerdesc_token_table[] = { T1("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ), T1("master-key-ed25519", K_MASTER_KEY_ED25519, GE(1), NO_OBJ ), T1("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ), - T1("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), + T01("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), T1("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT, EQ(1), NEED_OBJ ), @@ -595,15 +595,17 @@ router_parse_entry_from_string(const char *s, const char *end, if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0) goto err; - tok = find_by_keyword(tokens, K_ONION_KEY); - if (!crypto_pk_public_exponent_ok(tok->key)) { - log_warn(LD_DIR, - "Relay's onion key had invalid exponent."); - goto err; + tok = find_opt_by_keyword(tokens, K_ONION_KEY); + if (tok) { + if (!crypto_pk_public_exponent_ok(tok->key)) { + log_warn(LD_DIR, + "Relay's onion key had invalid exponent."); + goto err; + } + router->tap_onion_pkey = tor_memdup(tok->object_body, tok->object_size); + router->tap_onion_pkey_len = tok->object_size; + crypto_pk_free(tok->key); } - router->tap_onion_pkey = tor_memdup(tok->object_body, tok->object_size); - router->tap_onion_pkey_len = tok->object_size; - crypto_pk_free(tok->key); if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) { curve25519_public_key_t k; @@ -630,15 +632,65 @@ router_parse_entry_from_string(const char *s, const char *end, ed_sig_tok = find_by_keyword(tokens, K_ROUTER_SIG_ED25519); ed_cert_tok = find_by_keyword(tokens, K_IDENTITY_ED25519); master_key_tok = find_by_keyword(tokens, K_MASTER_KEY_ED25519); - cc_tap_tok = find_opt_by_keyword(tokens, K_ONION_KEY_CROSSCERT); cc_ntor_tok = find_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT); + /* This, and only this, is optional. */ + cc_tap_tok = find_opt_by_keyword(tokens, K_ONION_KEY_CROSSCERT); + + if (bool_neq(cc_tap_tok==NULL, router->tap_onion_pkey==NULL)) { + log_warn(LD_DIR, "Router descriptor had only one of (onion-key, " + "onion-key-crosscert)."); + goto err; + } IF_BUG_ONCE(! (ed_sig_tok && ed_cert_tok&& cc_ntor_tok &&master_key_tok)) { goto err; } - if (ed_sig_tok) { - tor_assert(ed_cert_tok && cc_tap_tok && cc_ntor_tok); + tor_cert_t *cert; + { + /* Parse the identity certificate */ + cert = tor_cert_parse( + (const uint8_t*)ed_cert_tok->object_body, + ed_cert_tok->object_size); + if (! cert) { + log_warn(LD_DIR, "Couldn't parse ed25519 cert"); + goto err; + } + /* makes sure it gets freed. */ + router->cache_info.signing_key_cert = cert; + + if (cert->cert_type != CERT_TYPE_ID_SIGNING || + ! cert->signing_key_included) { + log_warn(LD_DIR, "Invalid form for ed25519 cert"); + goto err; + } + } + + if (cc_tap_tok) { + rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey, + router->tap_onion_pkey_len); + if (rsa_pubkey == NULL) { + log_warn(LD_DIR, "No pubkey for TAP cross-verification."); + goto err; + } + if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) { + log_warn(LD_DIR, "Wrong object type on onion-key-crosscert " + "in descriptor"); + goto err; + } + if (check_tap_onion_key_crosscert( + (const uint8_t*)cc_tap_tok->object_body, + (int)cc_tap_tok->object_size, + rsa_pubkey, + &cert->signing_key, + (const uint8_t*)router->cache_info.identity_digest)<0) { + log_warn(LD_DIR, "Incorrect TAP cross-verification"); + goto err; + } + } + + { + tor_assert(ed_sig_tok && ed_cert_tok && cc_ntor_tok); const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok); if (ed_cert_token_pos == -1 || router_token_pos == -1 || (ed_cert_token_pos != router_token_pos + 1 && @@ -660,35 +712,14 @@ router_parse_entry_from_string(const char *s, const char *end, "in descriptor"); goto err; } - if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) { - log_warn(LD_DIR, "Wrong object type on onion-key-crosscert " - "in descriptor"); - goto err; - } if (strcmp(cc_ntor_tok->args[0], "0") && strcmp(cc_ntor_tok->args[0], "1")) { log_warn(LD_DIR, "Bad sign bit on ntor-onion-key-crosscert"); goto err; } int ntor_cc_sign_bit = !strcmp(cc_ntor_tok->args[0], "1"); - uint8_t d256[DIGEST256_LEN]; const char *signed_start, *signed_end; - tor_cert_t *cert = tor_cert_parse( - (const uint8_t*)ed_cert_tok->object_body, - ed_cert_tok->object_size); - if (! cert) { - log_warn(LD_DIR, "Couldn't parse ed25519 cert"); - goto err; - } - /* makes sure it gets freed. */ - router->cache_info.signing_key_cert = cert; - - if (cert->cert_type != CERT_TYPE_ID_SIGNING || - ! cert->signing_key_included) { - log_warn(LD_DIR, "Invalid form for ed25519 cert"); - goto err; - } if (master_key_tok) { /* This token is optional, but if it's present, it must match @@ -738,6 +769,7 @@ router_parse_entry_from_string(const char *s, const char *end, crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX, strlen(ED_DESC_SIGNATURE_PREFIX)); crypto_digest_add_bytes(d, signed_start, signed_end-signed_start); + crypto_digest_get_digest(d, (char*)d256, sizeof(d256)); crypto_digest_free(d); @@ -768,22 +800,6 @@ router_parse_entry_from_string(const char *s, const char *end, goto err; } - rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey, - router->tap_onion_pkey_len); - if (rsa_pubkey == NULL) { - log_warn(LD_DIR, "No pubkey for TAP cross-verification."); - goto err; - } - if (check_tap_onion_key_crosscert( - (const uint8_t*)cc_tap_tok->object_body, - (int)cc_tap_tok->object_size, - rsa_pubkey, - &cert->signing_key, - (const uint8_t*)router->cache_info.identity_digest)<0) { - log_warn(LD_DIR, "Incorrect TAP cross-verification"); - goto err; - } - /* We check this before adding it to the routerlist. */ router->cert_expiration_time = expires; }