Browse Source

Merge branch 'ticket20895'

Nick Mathewson 6 years ago
parent
commit
0626031564

+ 6 - 0
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.

+ 2 - 2
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)) {

+ 1 - 1
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. */

+ 2 - 2
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;

+ 1 - 1
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.

+ 13 - 7
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;

+ 2 - 1
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);

+ 6 - 2
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

+ 36 - 0
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 *

+ 3 - 0
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);
 

+ 3 - 1
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 =

+ 30 - 0
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
 };