Browse Source

prop224 client-side: Start validating onion address pubkeys.

Fix the test_build_address() test and its test vectors python script.
They were both using a bogus pubkey for building an HS address which
does not validate anymore.

Also fix a few more unittests that were using bogus onion addresses
and were failing the validation. I replaced the bogus address with
the one generated from the test vector script.
George Kadianakis 6 years ago
parent
commit
0ac2afad0d
4 changed files with 35 additions and 17 deletions
  1. 12 3
      src/or/hs_common.c
  2. 3 2
      src/test/hs_build_address.py
  3. 2 2
      src/test/test_entryconn.c
  4. 18 10
      src/test/test_hs_common.c

+ 12 - 3
src/or/hs_common.c

@@ -914,22 +914,31 @@ hs_address_is_valid(const char *address)
   uint8_t version;
   uint8_t checksum[HS_SERVICE_ADDR_CHECKSUM_LEN_USED];
   uint8_t target_checksum[DIGEST256_LEN];
-  ed25519_public_key_t key;
+  ed25519_public_key_t service_pubkey;
 
   /* Parse the decoded address into the fields we need. */
-  if (hs_parse_address(address, &key, checksum, &version) < 0) {
+  if (hs_parse_address(address, &service_pubkey, checksum, &version) < 0) {
     goto invalid;
   }
 
   /* Get the checksum it's suppose to be and compare it with what we have
    * encoded in the address. */
-  build_hs_checksum(&key, version, target_checksum);
+  build_hs_checksum(&service_pubkey, version, target_checksum);
   if (tor_memcmp(checksum, target_checksum, sizeof(checksum))) {
     log_warn(LD_REND, "Service address %s invalid checksum.",
              escaped_safe_str(address));
     goto invalid;
   }
 
+  /* Validate that this pubkey does not have a torsion component. We need to do
+   * this on the prop224 client-side so that attackers can't give equivalent
+   * forms of an onion address to users. */
+  if (ed25519_validate_pubkey(&service_pubkey) < 0) {
+    log_warn(LD_REND, "Service address %s has bad pubkey .",
+             escaped_safe_str(address));
+    goto invalid;
+  }
+
   /* Valid address. */
   return 1;
  invalid:

+ 3 - 2
src/test/hs_build_address.py

@@ -21,8 +21,9 @@ if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest():
 # Checksum is built like so:
 #   CHECKSUM = SHA3(".onion checksum" || PUBKEY || VERSION)
 PREFIX = ".onion checksum".encode()
-# 32 bytes ed25519 pubkey.
-PUBKEY = ("\x42" * 32).encode()
+# 32 bytes ed25519 pubkey from first test vector of
+# https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02#section-6
+PUBKEY = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".decode('hex')
 # Version 3 is proposal224
 VERSION = 3
 

+ 2 - 2
src/test/test_entryconn.c

@@ -801,7 +801,7 @@ test_entryconn_rewrite_onion_v3(void *arg)
   /* Make a SOCKS request */
   conn->socks_request->command = SOCKS_COMMAND_CONNECT;
   strlcpy(conn->socks_request->address,
-          "git.p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnad.onion",
+          "git.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion",
           sizeof(conn->socks_request->address));
 
   /* Make an onion connection using the SOCKS request */
@@ -818,7 +818,7 @@ test_entryconn_rewrite_onion_v3(void *arg)
   tt_int_op(ENTRY_TO_CONN(conn)->state, OP_EQ, AP_CONN_STATE_CIRCUIT_WAIT);
   /* check that the address got rewritten */
   tt_str_op(conn->socks_request->address, OP_EQ,
-            "p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnad");
+            "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
   /* check that HS information got attached to the connection */
   tt_assert(ENTRY_TO_EDGE_CONN(conn)->hs_ident);
   tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);

+ 18 - 10
src/test/test_hs_common.c

@@ -77,7 +77,7 @@ test_validate_address(void *arg)
 
   /* Valid address. */
   ret = hs_address_is_valid(
-           "p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnad");
+           "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
   tt_int_op(ret, OP_EQ, 1);
 
  done:
@@ -90,19 +90,23 @@ mock_write_str_to_file(const char *path, const char *str, int bin)
   (void)bin;
   tt_str_op(path, OP_EQ, "/double/five"PATH_SEPARATOR"squared");
   tt_str_op(str, OP_EQ,
-           "ijbeeqscijbeeqscijbeeqscijbeeqscijbeeqscijbeeqscijbezhid.onion\n");
+           "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion\n");
 
  done:
   return 0;
 }
 
-/** Test building HS v3 onion addresses */
+/** Test building HS v3 onion addresses. Uses test vectors from the
+ *  ./hs_build_address.py script. */
 static void
 test_build_address(void *arg)
 {
   int ret;
   char onion_addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
   ed25519_public_key_t pubkey;
+  /* hex-encoded ed25519 pubkey used in hs_build_address.py */
+  char pubkey_hex[] =
+    "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
   hs_service_t *service = NULL;
 
   (void) arg;
@@ -112,11 +116,11 @@ test_build_address(void *arg)
   /* The following has been created with hs_build_address.py script that
    * follows proposal 224 specification to build an onion address. */
   static const char *test_addr =
-    "ijbeeqscijbeeqscijbeeqscijbeeqscijbeeqscijbeeqscijbezhid";
+    "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid";
 
-  /* Let's try to build the same onion address that the script can do. Key is
-   * a long set of very random \x42 :). */
-  memset(&pubkey, '\x42', sizeof(pubkey));
+  /* Let's try to build the same onion address as the script */
+  base16_decode((char*)pubkey.pubkey, sizeof(pubkey.pubkey),
+                pubkey_hex, strlen(pubkey_hex));
   hs_build_address(&pubkey, HS_VERSION_THREE, onion_addr);
   tt_str_op(test_addr, OP_EQ, onion_addr);
   /* Validate that address. */
@@ -474,9 +478,13 @@ test_desc_reupload_logic(void *arg)
   /* Let's start by building our descriptor and service */
   hs_service_descriptor_t *desc = service_descriptor_new();
   hs_service_t *service = NULL;
+  /* hex-encoded ed25519 pubkey used in hs_build_address.py */
+  char pubkey_hex[] =
+    "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
   char onion_addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
   ed25519_public_key_t pubkey;
-  memset(&pubkey, '\x42', sizeof(pubkey));
+  base16_decode((char*)pubkey.pubkey, sizeof(pubkey.pubkey),
+                pubkey_hex, strlen(pubkey_hex));
   hs_build_address(&pubkey, HS_VERSION_THREE, onion_addr);
   service = tor_malloc_zero(sizeof(hs_service_t));
   memcpy(service->onion_address, onion_addr, sizeof(service->onion_address));
@@ -758,7 +766,7 @@ test_parse_extended_hostname(void *arg)
   char address6[] = "foo.bar.abcdefghijklmnop.onion";
   char address7[] = ".abcdefghijklmnop.onion";
   char address8[] =
-    "www.p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnad.onion";
+    "www.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
 
   tt_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
   tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address2));
@@ -772,7 +780,7 @@ test_parse_extended_hostname(void *arg)
   tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
   tt_assert(ONION_V3_HOSTNAME == parse_extended_hostname(address8));
   tt_str_op(address8, OP_EQ,
-            "p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnad");
+            "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
 
  done: ;
 }