[tor-commits] [tor/master] test: Add v3 service load keys and accessors

nickm at torproject.org nickm at torproject.org
Thu Jul 13 21:26:47 UTC 2017


commit 09b12c40947ea496c0bfaeeafba7540925c17a32
Author: David Goulet <dgoulet at torproject.org>
Date:   Thu Feb 2 15:26:04 2017 -0500

    test: Add v3 service load keys and accessors
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/or/hs_service.c        |  27 +++++---
 src/or/hs_service.h        |  14 ++++
 src/test/test_hs_service.c | 166 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 199 insertions(+), 8 deletions(-)

diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 854ce9e..bfce780 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -57,11 +57,6 @@ hs_service_ht_hash(const hs_service_t *service)
                                    sizeof(service->keys.identity_pk.pubkey));
 }
 
-/* For the service global hash map, we define a specific type for it which
- * will make it safe to use and specific to some controlled parameters such as
- * the hashing function and how to compare services. */
-typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht;
-
 /* This is _the_ global hash map of hidden services which indexed the service
  * contained in it by master public identity key which is roughly the onion
  * address of the service. */
@@ -82,7 +77,7 @@ HT_GENERATE2(hs_service_ht, hs_service_t, hs_service_node,
  * if found else NULL. It is also possible to set a directory path in the
  * search query. If pk is NULL, then it will be set to zero indicating the
  * hash table to compare the directory path instead. */
-static hs_service_t *
+STATIC hs_service_t *
 find_service(hs_service_ht *map, const ed25519_public_key_t *pk)
 {
   hs_service_t dummy_service = {0};
@@ -95,7 +90,7 @@ find_service(hs_service_ht *map, const ed25519_public_key_t *pk)
 /* Register the given service in the given map. If the service already exists
  * in the map, -1 is returned. On success, 0 is returned and the service
  * ownership has been transfered to the global map. */
-static int
+STATIC int
 register_service(hs_service_ht *map, hs_service_t *service)
 {
   tor_assert(map);
@@ -113,7 +108,7 @@ register_service(hs_service_ht *map, hs_service_t *service)
 
 /* Remove a given service from the given map. If service is NULL or the
  * service key is unset, return gracefully. */
-static void
+STATIC void
 remove_service(hs_service_ht *map, hs_service_t *service)
 {
   hs_service_t *elm;
@@ -804,5 +799,21 @@ get_hs_service_staging_list_size(void)
   return smartlist_len(hs_service_staging_list);
 }
 
+STATIC hs_service_ht *
+get_hs_service_map(void)
+{
+  return hs_service_map;
+}
+
+STATIC hs_service_t *
+get_first_service(void)
+{
+  hs_service_t **obj = HT_START(hs_service_ht, hs_service_map);
+  if (obj == NULL) {
+    return NULL;
+  }
+  return *obj;
+}
+
 #endif /* TOR_UNIT_TESTS */
 
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index cd154d3..a98884f 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -200,6 +200,11 @@ typedef struct hs_service_t {
 
 } hs_service_t;
 
+/* For the service global hash map, we define a specific type for it which
+ * will make it safe to use and specific to some controlled parameters such as
+ * the hashing function and how to compare services. */
+typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht;
+
 /* API */
 
 /* Global initializer and cleanup function. */
@@ -228,8 +233,17 @@ get_establish_intro_payload(uint8_t *buf, size_t buf_len,
 
 #ifdef TOR_UNIT_TESTS
 
+/* Useful getters for unit tests. */
 STATIC unsigned int get_hs_service_map_size(void);
 STATIC int get_hs_service_staging_list_size(void);
+STATIC hs_service_ht *get_hs_service_map(void);
+STATIC hs_service_t *get_first_service(void);
+
+/* Service accessors. */
+STATIC hs_service_t *find_service(hs_service_ht *map,
+                                  const ed25519_public_key_t *pk);
+STATIC void remove_service(hs_service_ht *map, hs_service_t *service);
+STATIC int register_service(hs_service_ht *map, hs_service_t *service);
 
 #endif /* TOR_UNIT_TESTS */
 
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index e081b7f..c695b90 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -8,14 +8,17 @@
 
 #define CIRCUITBUILD_PRIVATE
 #define CIRCUITLIST_PRIVATE
+#define CONFIG_PRIVATE
 #define CONNECTION_PRIVATE
 #define CRYPTO_PRIVATE
 #define HS_COMMON_PRIVATE
+#define HS_SERVICE_PRIVATE
 #define HS_INTROPOINT_PRIVATE
 #define MAIN_PRIVATE
 #define TOR_CHANNEL_INTERNAL_
 
 #include "test.h"
+#include "test_helpers.h"
 #include "log_test_helpers.h"
 #include "rend_test_helpers.h"
 
@@ -26,8 +29,10 @@
 #include "circuituse.h"
 #include "config.h"
 #include "connection.h"
+#include "crypto.h"
 #include "hs_circuit.h"
 #include "hs_common.h"
+#include "hs_config.h"
 #include "hs_ident.h"
 #include "hs_intropoint.h"
 #include "hs_ntor.h"
@@ -35,6 +40,25 @@
 #include "main.h"
 #include "rendservice.h"
 
+/* Trunnel */
+#include "hs/cell_establish_intro.h"
+
+/* Helper: from a set of options in conf, configure a service which will add
+ * it to the staging list of the HS subsytem. */
+static int
+helper_config_service(const char *conf)
+{
+  int ret = 0;
+  or_options_t *options = NULL;
+  tt_assert(conf);
+  options = helper_parse_options(conf);
+  tt_assert(options);
+  ret = hs_config_service_all(options, 0);
+ done:
+  or_options_free(options);
+  return ret;
+}
+
 /** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
  *  parse it from the receiver side. */
 static void
@@ -394,6 +418,144 @@ test_e2e_rend_circuit_setup(void *arg)
   circuit_free(TO_CIRCUIT(or_circ));
 }
 
+static void
+test_load_keys(void *arg)
+{
+  int ret;
+  char *conf = NULL;
+  char *hsdir_v2 = tor_strdup(get_fname("hs2"));
+  char *hsdir_v3 = tor_strdup(get_fname("hs3"));
+  char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+  (void) arg;
+
+  /* We'll register two services, a v2 and a v3, then we'll load keys and
+   * validate that both are in a correct state. */
+
+  hs_init();
+
+#define conf_fmt \
+  "HiddenServiceDir %s\n" \
+  "HiddenServiceVersion %d\n" \
+  "HiddenServicePort 65535\n"
+
+  /* v2 service. */
+  tor_asprintf(&conf, conf_fmt, hsdir_v2, HS_VERSION_TWO);
+  ret = helper_config_service(conf);
+  tor_free(conf);
+  tt_int_op(ret, OP_EQ, 0);
+  /* This one should now be registered into the v2 list. */
+  tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 0);
+  tt_int_op(num_rend_services(), OP_EQ, 1);
+
+  /* v3 service. */
+  tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
+  ret = helper_config_service(conf);
+  tor_free(conf);
+  tt_int_op(ret, OP_EQ, 0);
+  /* It's in staging? */
+  tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+
+  /* Load the keys for these. After that, the v3 service should be registered
+   * in the global map. */
+  hs_service_load_all_keys();
+  tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+  hs_service_t *s = get_first_service();
+  tt_assert(s);
+
+  /* Ok we have the service object. Validate few things. */
+  tt_assert(!tor_mem_is_zero(s->onion_address, sizeof(s->onion_address)));
+  tt_int_op(hs_address_is_valid(s->onion_address), OP_EQ, 1);
+  tt_assert(!tor_mem_is_zero((char *) s->keys.identity_sk.seckey,
+                             ED25519_SECKEY_LEN));
+  tt_assert(!tor_mem_is_zero((char *) s->keys.identity_pk.pubkey,
+                             ED25519_PUBKEY_LEN));
+  /* Check onion address from identity key. */
+  hs_build_address(&s->keys.identity_pk, s->version, addr);
+  tt_int_op(hs_address_is_valid(addr), OP_EQ, 1);
+  tt_str_op(addr, OP_EQ, s->onion_address);
+
+ done:
+  tor_free(hsdir_v2);
+  tor_free(hsdir_v3);
+  hs_free_all();
+}
+
+static void
+test_access_service(void *arg)
+{
+  int ret;
+  char *conf = NULL;
+  char *hsdir_v3 = tor_strdup(get_fname("hs3"));
+  hs_service_ht *global_map;
+
+  (void) arg;
+
+  /* We'll register two services, a v2 and a v3, then we'll load keys and
+   * validate that both are in a correct state. */
+
+  hs_init();
+
+#define conf_fmt \
+  "HiddenServiceDir %s\n" \
+  "HiddenServiceVersion %d\n" \
+  "HiddenServicePort 65535\n"
+
+  /* v3 service. */
+  tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
+  ret = helper_config_service(conf);
+  tor_free(conf);
+  tt_int_op(ret, OP_EQ, 0);
+  /* It's in staging? */
+  tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+
+  /* Load the keys for these. After that, the v3 service should be registered
+   * in the global map. */
+  hs_service_load_all_keys();
+  tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+  hs_service_t *s = get_first_service();
+  tt_assert(s);
+  global_map = get_hs_service_map();
+  tt_assert(global_map);
+
+  /* From here, we'll try the service accessors. */
+  hs_service_t *query = find_service(global_map, &s->keys.identity_pk);
+  tt_assert(query);
+  tt_mem_op(query, OP_EQ, s, sizeof(hs_service_t));
+  /* Remove service, check if it actually works and then put it back. */
+  remove_service(global_map, s);
+  tt_int_op(get_hs_service_map_size(), OP_EQ, 0);
+  query = find_service(global_map, &s->keys.identity_pk);
+  tt_assert(!query);
+
+  /* Register back the service in the map. */
+  ret = register_service(global_map, s);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+  /* Twice should fail. */
+  ret = register_service(global_map, s);
+  tt_int_op(ret, OP_EQ, -1);
+  /* Modify key of service and we should be able to put it back in. */
+  s->keys.identity_pk.pubkey[1] = '\x42';
+  ret = register_service(global_map, s);
+  tt_int_op(ret, OP_EQ, 0);
+  tt_int_op(get_hs_service_map_size(), OP_EQ, 2);
+  /* Remove service from map so we don't double free on cleanup. */
+  remove_service(global_map, s);
+  tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+  query = find_service(global_map, &s->keys.identity_pk);
+  tt_assert(!query);
+  /* Let's try to remove twice for fun. */
+  setup_full_capture_of_logs(LOG_WARN);
+  remove_service(global_map, s);
+  expect_log_msg_containing("Could not find service in the global map");
+  teardown_capture_of_logs();
+
+ done:
+  tor_free(hsdir_v3);
+  hs_free_all();
+}
+
 struct testcase_t hs_service_tests[] = {
   { "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK,
     NULL, NULL },
@@ -409,6 +571,10 @@ struct testcase_t hs_service_tests[] = {
     NULL, NULL },
   { "validate_address", test_validate_address, TT_FORK,
     NULL, NULL },
+  { "load_keys", test_load_keys, TT_FORK,
+    NULL, NULL },
+  { "access_service", test_access_service, TT_FORK,
+    NULL, NULL },
 
   END_OF_TESTCASES
 };





More information about the tor-commits mailing list