Routerparse: accept routerdescs without TAP keys.

This commit is contained in:
Nick Mathewson 2024-06-24 14:55:27 -04:00
parent 6c3dd44762
commit 73b73c07e1

View File

@ -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;
}