aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/ticket208956
-rw-r--r--src/or/circuitbuild.c4
-rw-r--r--src/or/connection_or.c2
-rw-r--r--src/or/dirserv.c4
-rw-r--r--src/or/hs_service.c2
-rw-r--r--src/or/nodelist.c20
-rw-r--r--src/or/nodelist.h3
-rw-r--r--src/or/or.h8
-rw-r--r--src/or/protover.c36
-rw-r--r--src/or/protover.h3
-rw-r--r--src/or/routerparse.c4
-rw-r--r--src/test/test_protover.c30
12 files changed, 105 insertions, 17 deletions
diff --git a/changes/ticket20895 b/changes/ticket20895
new file mode 100644
index 0000000000..a1d8204997
--- /dev/null
+++ b/changes/ticket20895
@@ -0,0 +1,6 @@
+ o Minor features (forward-compatibility):
+ - If a relay supports some link authentication protocol that we do not
+ recognize, then include that relay's ed25519 key when telling other
+ relays to extend to it. Previously, we treated future versions as if
+ they were too old to support ed25519 link authentication.
+ Closes ticket 20895.
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index b36fed63b3..7f0bcc4150 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1290,7 +1290,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
const node_t *node = node_get_by_id((const char*)ec.node_id);
const ed25519_public_key_t *node_ed_id = NULL;
if (node &&
- node_supports_ed25519_link_authentication(node) &&
+ node_supports_ed25519_link_authentication(node, 1) &&
(node_ed_id = node_get_ed25519_id(node))) {
ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id);
}
@@ -2698,7 +2698,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
/* Don't send the ed25519 pubkey unless the target node actually supports
* authenticating with it. */
- if (node_supports_ed25519_link_authentication(node)) {
+ if (node_supports_ed25519_link_authentication(node, 0)) {
log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
ed_pubkey = node_get_ed25519_id(node);
} else if (node_get_ed25519_id(node)) {
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 9e34063609..7af1f2b645 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -886,7 +886,7 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
const node_t *r = node_get_by_id(id_digest);
if (r &&
- node_supports_ed25519_link_authentication(r) &&
+ node_supports_ed25519_link_authentication(r, 1) &&
! node_ed25519_id_matches(r, ed_id)) {
/* If this node is capable of proving an ed25519 ID,
* we can't call this a canonical connection unless both IDs match. */
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index ddee92da55..293a6e15d6 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -3284,7 +3284,7 @@ dirserv_orconn_tls_done(const tor_addr_t *addr,
ri = node->ri;
if (get_options()->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node) &&
+ node_supports_ed25519_link_authentication(node, 1) &&
ri->cache_info.signing_key_cert) {
/* We allow the node to have an ed25519 key if we haven't been told one in
* the routerinfo, but if we *HAVE* been told one in the routerinfo, it
@@ -3367,7 +3367,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
tor_assert(node);
if (options->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node)) {
+ node_supports_ed25519_link_authentication(node, 1)) {
ed_id_key = &router->cache_info.signing_key_cert->signing_key;
} else {
ed_id_key = NULL;
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index a2082b3914..8e2f52dcf0 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -1572,7 +1572,7 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes)
/* Let's do a basic sanity check here so that we don't end up advertising the
* ed25519 identity key of relays that don't actually support the link
* protocol */
- if (!node_supports_ed25519_link_authentication(node)) {
+ if (!node_supports_ed25519_link_authentication(node, 0)) {
tor_assert_nonfatal(ed25519_public_key_is_zero(&info->ed_identity));
} else {
/* Make sure we *do* have an ed key if we support the link authentication.
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index f2e979be8b..30ffd9a637 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -951,23 +951,29 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
}
/** Return true iff <b>node</b> supports authenticating itself
- * by ed25519 ID during the link handshake in a way that we can understand
- * when we probe it. */
+ * by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
+ * it needs to be using a link authentication method that we understand.
+ * If not, any plausible link authentication method will do. */
int
-node_supports_ed25519_link_authentication(const node_t *node)
+node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us)
{
- /* XXXX Oh hm. What if some day in the future there are link handshake
- * versions that aren't 3 but which are ed25519 */
if (! node_get_ed25519_id(node))
return 0;
if (node->ri) {
const char *protos = node->ri->protocol_list;
if (protos == NULL)
return 0;
- return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3);
+ if (compatible_with_us)
+ return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3);
+ else
+ return protocol_list_supports_protocol_or_later(protos, PRT_LINKAUTH, 3);
}
if (node->rs) {
- return node->rs->supports_ed25519_link_handshake;
+ if (compatible_with_us)
+ return node->rs->supports_ed25519_link_handshake_compat;
+ else
+ return node->rs->supports_ed25519_link_handshake_any;
}
tor_assert_nonfatal_unreached_once();
return 0;
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 754990ac8d..a41748cb3a 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -65,7 +65,8 @@ const smartlist_t *node_get_declared_family(const node_t *node);
const ed25519_public_key_t *node_get_ed25519_id(const node_t *node);
int node_ed25519_id_matches(const node_t *node,
const ed25519_public_key_t *id);
-int node_supports_ed25519_link_authentication(const node_t *node);
+int node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us);
int node_supports_v3_hsdir(const node_t *node);
int node_supports_ed25519_hs_intro(const node_t *node);
int node_supports_v3_rendezvous_point(const node_t *node);
diff --git a/src/or/or.h b/src/or/or.h
index a68f1c3c47..fa5268ac59 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2316,8 +2316,12 @@ typedef struct routerstatus_t {
unsigned int supports_extend2_cells:1;
/** True iff this router has a protocol list that allows it to negotiate
- * ed25519 identity keys on a link handshake. */
- unsigned int supports_ed25519_link_handshake:1;
+ * ed25519 identity keys on a link handshake with us. */
+ unsigned int supports_ed25519_link_handshake_compat:1;
+
+ /** True iff this router has a protocol list that allows it to negotiate
+ * ed25519 identity keys on a link handshake, at all. */
+ unsigned int supports_ed25519_link_handshake_any:1;
/** True iff this router has a protocol list that allows it to be an
* introduction point supporting ed25519 authentication key which is part of
diff --git a/src/or/protover.c b/src/or/protover.c
index 0e74deb112..8b61d96630 100644
--- a/src/or/protover.c
+++ b/src/or/protover.c
@@ -282,6 +282,42 @@ protocol_list_supports_protocol(const char *list, protocol_type_t tp,
return contains;
}
+/**
+ * Return true iff "list" encodes a protocol list that includes support for
+ * the indicated protocol and version, or some later version.
+ */
+int
+protocol_list_supports_protocol_or_later(const char *list,
+ protocol_type_t tp,
+ uint32_t version)
+{
+ /* NOTE: This is a pretty inefficient implementation. If it ever shows
+ * up in profiles, we should memoize it.
+ */
+ smartlist_t *protocols = parse_protocol_list(list);
+ if (!protocols) {
+ return 0;
+ }
+ const char *pr_name = protocol_type_to_str(tp);
+
+ int contains = 0;
+ SMARTLIST_FOREACH_BEGIN(protocols, proto_entry_t *, proto) {
+ if (strcasecmp(proto->name, pr_name))
+ continue;
+ SMARTLIST_FOREACH_BEGIN(proto->ranges, const proto_range_t *, range) {
+ if (range->high >= version) {
+ contains = 1;
+ goto found;
+ }
+ } SMARTLIST_FOREACH_END(range);
+ } SMARTLIST_FOREACH_END(proto);
+
+ found:
+ SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent));
+ smartlist_free(protocols);
+ return contains;
+}
+
/** Return the canonical string containing the list of protocols
* that we support. */
const char *
diff --git a/src/or/protover.h b/src/or/protover.h
index 7f1938e0c9..5884585ea6 100644
--- a/src/or/protover.h
+++ b/src/or/protover.h
@@ -47,6 +47,9 @@ char *protover_compute_vote(const smartlist_t *list_of_proto_strings,
const char *protover_compute_for_old_tor(const char *version);
int protocol_list_supports_protocol(const char *list, protocol_type_t tp,
uint32_t version);
+int protocol_list_supports_protocol_or_later(const char *list,
+ protocol_type_t tp,
+ uint32_t version);
void protover_free_all(void);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 65874ae068..f1895ce313 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -2701,8 +2701,10 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->protocols_known = 1;
rs->supports_extend2_cells =
protocol_list_supports_protocol(tok->args[0], PRT_RELAY, 2);
- rs->supports_ed25519_link_handshake =
+ rs->supports_ed25519_link_handshake_compat =
protocol_list_supports_protocol(tok->args[0], PRT_LINKAUTH, 3);
+ rs->supports_ed25519_link_handshake_any =
+ protocol_list_supports_protocol_or_later(tok->args[0], PRT_LINKAUTH, 3);
rs->supports_ed25519_hs_intro =
protocol_list_supports_protocol(tok->args[0], PRT_HSINTRO, 4);
rs->supports_v3_hsdir =
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 9ae907183b..6865362115 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -221,6 +221,35 @@ test_protover_list_supports_protocol_for_unsupported_returns_false(void *arg)
;
}
+static void
+test_protover_supports_version(void *arg)
+{
+ (void)arg;
+
+ tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK, 3));
+ tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK, 6));
+ tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINK, 7));
+ tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINKAUTH, 3));
+
+ tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 2));
+ tt_assert(protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 3));
+ tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 4));
+ tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 4));
+ tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 3));
+ tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 2));
+
+ tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_DESC, 2));
+ done:
+ ;
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -231,6 +260,7 @@ struct testcase_t protover_tests[] = {
PV_TEST(all_supported, 0),
PV_TEST(list_supports_protocol_for_unsupported_returns_false, 0),
PV_TEST(list_supports_protocol_returns_true, 0),
+ PV_TEST(supports_version, 0),
END_OF_TESTCASES
};