]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Routerparse: accept routerdescs without TAP keys.
authorNick Mathewson <nickm@torproject.org>
Mon, 24 Jun 2024 18:55:27 +0000 (14:55 -0400)
committerNick Mathewson <nickm@torproject.org>
Wed, 26 Jun 2024 15:42:36 +0000 (11:42 -0400)
src/feature/dirparse/routerparse.c

index b3653a79e715e9626392aa3e0b71cc409d35ac08..6289b4c0181da952fd504e91877be2b2ced47f4d 100644 (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;
     }