diff --git a/src/or/router.c b/src/or/router.c index 6868e7b996..0903eb2082 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -2406,6 +2406,7 @@ router_dump_router_to_string(routerinfo_t *router, if (emit_ed_sigs) { /* Encode ed25519 signing cert */ char ed_cert_base64[256]; + char ed_fp_base64[ED25519_BASE64_LEN+1]; if (base64_encode(ed_cert_base64, sizeof(ed_cert_base64), (const char*)router->signing_key_cert->encoded, router->signing_key_cert->encoded_len, @@ -2413,10 +2414,17 @@ router_dump_router_to_string(routerinfo_t *router, log_err(LD_BUG,"Couldn't base64-encode signing key certificate!"); goto err; } + if (ed25519_public_to_base64(ed_fp_base64, + &router->signing_key_cert->signing_key)<0) { + log_err(LD_BUG,"Couldn't base64-encode identity key\n"); + goto err; + } tor_asprintf(&ed_cert_line, "identity-ed25519\n" "-----BEGIN ED25519 CERT-----\n" "%s" - "-----END ED25519 CERT-----\n", ed_cert_base64); + "-----END ED25519 CERT-----\n" + "master-key-ed25519 %s\n", + ed_cert_base64, ed_fp_base64); } /* PEM-encode the onion key */ diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 1413d40703..ae50cda248 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -89,6 +89,7 @@ typedef enum { K_IPV6_POLICY, K_ROUTER_SIG_ED25519, K_IDENTITY_ED25519, + K_MASTER_KEY_ED25519, K_ONION_KEY_CROSSCERT, K_NTOR_ONION_KEY_CROSSCERT, @@ -302,6 +303,7 @@ static token_rule_t routerdesc_token_table[] = { T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ), T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR, NO_ARGS, NO_OBJ ), T01("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ), + T01("master-key-ed25519", K_MASTER_KEY_ED25519, GE(1), NO_OBJ ), T01("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ), T01("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), T01("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT, @@ -1337,9 +1339,11 @@ router_parse_entry_from_string(const char *s, const char *end, } { - directory_token_t *ed_sig_tok, *ed_cert_tok, *cc_tap_tok, *cc_ntor_tok; + directory_token_t *ed_sig_tok, *ed_cert_tok, *cc_tap_tok, *cc_ntor_tok, + *master_key_tok; ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519); ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519); + master_key_tok = find_opt_by_keyword(tokens, K_MASTER_KEY_ED25519); cc_tap_tok = find_opt_by_keyword(tokens, K_ONION_KEY_CROSSCERT); cc_ntor_tok = find_opt_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT); int n_ed_toks = !!ed_sig_tok + !!ed_cert_tok + @@ -1350,6 +1354,11 @@ router_parse_entry_from_string(const char *s, const char *end, "cross-certification support"); goto err; } + if (master_key_tok && !ed_sig_tok) { + log_warn(LD_DIR, "Router descriptor has ed25519 master key but no " + "certificate"); + goto err; + } if (ed_sig_tok) { tor_assert(ed_cert_tok && cc_tap_tok && cc_ntor_tok); const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok); @@ -1394,12 +1403,30 @@ router_parse_entry_from_string(const char *s, const char *end, goto err; } router->signing_key_cert = cert; /* makes sure it gets freed. */ + 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 + * the signature in the signing cert, or supplant it. */ + tor_assert(master_key_tok->n_args >= 1); + ed25519_public_key_t pkey; + if (ed25519_public_from_base64(&pkey, master_key_tok->args[0])<0) { + log_warn(LD_DIR, "Can't parse ed25519 master key"); + goto err; + } + + if (fast_memneq(&cert->signing_key.pubkey, + pkey.pubkey, ED25519_PUBKEY_LEN)) { + log_warn(LD_DIR, "Ed25519 master key does not match " + "key in certificate"); + goto err; + } + } ntor_cc_cert = tor_cert_parse((const uint8_t*)cc_ntor_tok->object_body, cc_ntor_tok->object_size); if (!ntor_cc_cert) { diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 32ac8d439e..35bd8ea166 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -227,8 +227,16 @@ test_dir_formats(void *arg) "identity-ed25519\n" "-----BEGIN ED25519 CERT-----\n", sizeof(buf2)); strlcat(buf2, cert_buf, sizeof(buf2)); - strlcat(buf2, "-----END ED25519 CERT-----\n" - "platform Tor "VERSION" on ", sizeof(buf2)); + strlcat(buf2, "-----END ED25519 CERT-----\n", sizeof(buf2)); + strlcat(buf2, "master-key-ed25519 ", sizeof(buf2)); + { + char k[ED25519_BASE64_LEN+1]; + tt_assert(ed25519_public_to_base64(k, &r2->signing_key_cert->signing_key) + >= 0); + strlcat(buf2, k, sizeof(buf2)); + strlcat(buf2, "\n", sizeof(buf2)); + } + strlcat(buf2, "platform Tor "VERSION" on ", sizeof(buf2)); strlcat(buf2, get_uname(), sizeof(buf2)); strlcat(buf2, "\n" "protocols Link 1 2 Circuit 1\n"