Browse Source

test: Move duplicate HS test code and unify it

Create the hs_test_helpers.{c|h} files that contains helper functions to
create introduction point, descriptor and compare descriptor.

Used by both the hs cache and hs descriptor tests. Unify them to avoid code
duplication.

Also, this commit fixes the usage of the signing key that was wrongly used
when creating a cross signed certificate.

Signed-off-by: David Goulet <dgoulet@torproject.org>
David Goulet 7 years ago
parent
commit
0cc18ef64c
5 changed files with 283 additions and 318 deletions
  1. 244 0
      src/test/hs_test_helpers.c
  2. 22 0
      src/test/hs_test_helpers.h
  3. 1 0
      src/test/include.am
  4. 9 94
      src/test/test_hs_cache.c
  5. 7 224
      src/test/test_hs_descriptor.c

+ 244 - 0
src/test/hs_test_helpers.c

@@ -0,0 +1,244 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "crypto_ed25519.h"
+#include "test.h"
+#include "torcert.h"
+
+#include "hs_test_helpers.h"
+
+hs_desc_intro_point_t *
+hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
+                            const char *addr, int legacy)
+{
+  int ret;
+  ed25519_keypair_t auth_kp;
+  hs_desc_intro_point_t *intro_point = NULL;
+  hs_desc_intro_point_t *ip = tor_malloc_zero(sizeof(*ip));
+  ip->link_specifiers = smartlist_new();
+
+  {
+    hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls));
+    if (legacy) {
+      ls->type = LS_LEGACY_ID;
+      memcpy(ls->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8",
+             DIGEST_LEN);
+    } else {
+      ls->u.ap.port = 9001;
+      int family = tor_addr_parse(&ls->u.ap.addr, addr);
+      switch (family) {
+        case AF_INET:
+          ls->type = LS_IPV4;
+          break;
+        case AF_INET6:
+          ls->type = LS_IPV6;
+          break;
+        default:
+          /* Stop the test, not suppose to have an error. */
+          tt_int_op(family, OP_EQ, AF_INET);
+      }
+    }
+    smartlist_add(ip->link_specifiers, ls);
+  }
+
+  ret = ed25519_keypair_generate(&auth_kp, 0);
+  tt_int_op(ret, ==, 0);
+  ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
+                                      &auth_kp.pubkey, now,
+                                      HS_DESC_CERT_LIFETIME,
+                                      CERT_FLAG_INCLUDE_SIGNING_KEY);
+  tt_assert(ip->auth_key_cert);
+
+  if (legacy) {
+    ip->enc_key.legacy = crypto_pk_new();
+    ip->enc_key_type = HS_DESC_KEY_TYPE_LEGACY;
+    tt_assert(ip->enc_key.legacy);
+    ret = crypto_pk_generate_key(ip->enc_key.legacy);
+    tt_int_op(ret, ==, 0);
+  } else {
+    ret = curve25519_keypair_generate(&ip->enc_key.curve25519, 0);
+    tt_int_op(ret, ==, 0);
+    ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519;
+  }
+
+  intro_point = ip;
+ done:
+  return intro_point;
+}
+
+/* Return a valid hs_descriptor_t object. If no_ip is set, no introduction
+ * points are added. */
+static hs_descriptor_t *
+hs_helper_build_hs_desc_impl(unsigned int no_ip,
+                             const ed25519_keypair_t *signing_kp)
+{
+  int ret;
+  time_t now = time(NULL);
+  ed25519_keypair_t blinded_kp;
+  hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));
+
+  desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;
+
+  /* Copy only the public key into the descriptor. */
+  memcpy(&desc->plaintext_data.signing_pubkey, &signing_kp->pubkey,
+         sizeof(ed25519_public_key_t));
+
+  ret = ed25519_keypair_generate(&blinded_kp, 0);
+  tt_int_op(ret, ==, 0);
+  /* Copy only the public key into the descriptor. */
+  memcpy(&desc->plaintext_data.blinded_pubkey, &blinded_kp.pubkey,
+         sizeof(ed25519_public_key_t));
+
+  desc->plaintext_data.signing_key_cert =
+    tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
+                    &signing_kp->pubkey, now, 3600,
+                    CERT_FLAG_INCLUDE_SIGNING_KEY);
+  tt_assert(desc->plaintext_data.signing_key_cert);
+  desc->plaintext_data.revision_counter = 42;
+  desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
+
+  /* Setup encrypted data section. */
+  desc->encrypted_data.create2_ntor = 1;
+  desc->encrypted_data.intro_auth_types = smartlist_new();
+  desc->encrypted_data.single_onion_service = 1;
+  smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
+  desc->encrypted_data.intro_points = smartlist_new();
+  if (!no_ip) {
+    /* Add four intro points. */
+    smartlist_add(desc->encrypted_data.intro_points,
+              hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0));
+    smartlist_add(desc->encrypted_data.intro_points,
+              hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0));
+    smartlist_add(desc->encrypted_data.intro_points,
+              hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1));
+    smartlist_add(desc->encrypted_data.intro_points,
+              hs_helper_build_intro_point(signing_kp, now, "", 1));
+  }
+
+  descp = desc;
+ done:
+  return descp;
+}
+
+/* Build a descriptor with introduction points. */
+hs_descriptor_t *
+hs_helper_build_hs_desc_with_ip(const ed25519_keypair_t *signing_kp)
+{
+  return hs_helper_build_hs_desc_impl(0, signing_kp);
+}
+
+/* Build a descriptor without any introduction points. */
+hs_descriptor_t *
+hs_helper_build_hs_desc_no_ip(const ed25519_keypair_t *signing_kp)
+{
+  return hs_helper_build_hs_desc_impl(1, signing_kp);
+}
+
+void
+hs_helper_desc_equal(const hs_descriptor_t *desc1,
+                     const hs_descriptor_t *desc2)
+{
+  char *addr1 = NULL, *addr2 = NULL;
+  /* Plaintext data section. */
+  tt_int_op(desc1->plaintext_data.version, OP_EQ,
+            desc2->plaintext_data.version);
+  tt_uint_op(desc1->plaintext_data.lifetime_sec, OP_EQ,
+             desc2->plaintext_data.lifetime_sec);
+  tt_assert(tor_cert_eq(desc1->plaintext_data.signing_key_cert,
+                        desc2->plaintext_data.signing_key_cert));
+  tt_mem_op(desc1->plaintext_data.signing_pubkey.pubkey, OP_EQ,
+            desc2->plaintext_data.signing_pubkey.pubkey,
+            ED25519_PUBKEY_LEN);
+  tt_mem_op(desc1->plaintext_data.blinded_pubkey.pubkey, OP_EQ,
+            desc2->plaintext_data.blinded_pubkey.pubkey,
+            ED25519_PUBKEY_LEN);
+  tt_u64_op(desc1->plaintext_data.revision_counter, ==,
+            desc2->plaintext_data.revision_counter);
+
+  /* NOTE: We can't compare the encrypted blob because when encoding the
+   * descriptor, the object is immutable thus we don't update it with the
+   * encrypted blob. As contrast to the decoding process where we populate a
+   * descriptor object. */
+
+  /* Encrypted data section. */
+  tt_uint_op(desc1->encrypted_data.create2_ntor, ==,
+             desc2->encrypted_data.create2_ntor);
+
+  /* Authentication type. */
+  tt_int_op(!!desc1->encrypted_data.intro_auth_types, ==,
+            !!desc2->encrypted_data.intro_auth_types);
+  if (desc1->encrypted_data.intro_auth_types &&
+      desc2->encrypted_data.intro_auth_types) {
+    tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), ==,
+              smartlist_len(desc2->encrypted_data.intro_auth_types));
+    for (int i = 0;
+         i < smartlist_len(desc1->encrypted_data.intro_auth_types);
+         i++) {
+      tt_str_op(smartlist_get(desc1->encrypted_data.intro_auth_types, i),OP_EQ,
+                smartlist_get(desc2->encrypted_data.intro_auth_types, i));
+    }
+  }
+
+  /* Introduction points. */
+  {
+    tt_assert(desc1->encrypted_data.intro_points);
+    tt_assert(desc2->encrypted_data.intro_points);
+    tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), ==,
+              smartlist_len(desc2->encrypted_data.intro_points));
+    for (int i=0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) {
+      hs_desc_intro_point_t *ip1 = smartlist_get(desc1->encrypted_data
+                                                 .intro_points, i),
+                            *ip2 = smartlist_get(desc2->encrypted_data
+                                                 .intro_points, i);
+      tt_assert(tor_cert_eq(ip1->auth_key_cert, ip2->auth_key_cert));
+      tt_int_op(ip1->enc_key_type, OP_EQ, ip2->enc_key_type);
+      tt_assert(ip1->enc_key_type == HS_DESC_KEY_TYPE_LEGACY ||
+                ip1->enc_key_type == HS_DESC_KEY_TYPE_CURVE25519);
+      switch (ip1->enc_key_type) {
+        case HS_DESC_KEY_TYPE_LEGACY:
+          tt_int_op(crypto_pk_cmp_keys(ip1->enc_key.legacy,
+                                       ip2->enc_key.legacy), OP_EQ, 0);
+          break;
+        case HS_DESC_KEY_TYPE_CURVE25519:
+          tt_mem_op(ip1->enc_key.curve25519.pubkey.public_key, OP_EQ,
+                    ip2->enc_key.curve25519.pubkey.public_key,
+                    CURVE25519_PUBKEY_LEN);
+          break;
+      }
+
+      tt_int_op(smartlist_len(ip1->link_specifiers), ==,
+                smartlist_len(ip2->link_specifiers));
+      for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) {
+        hs_desc_link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j),
+                                 *ls2 = smartlist_get(ip2->link_specifiers, j);
+        tt_int_op(ls1->type, ==, ls2->type);
+        switch (ls1->type) {
+          case LS_IPV4:
+          case LS_IPV6:
+            {
+              addr1 = tor_addr_to_str_dup(&ls1->u.ap.addr);
+              addr2 = tor_addr_to_str_dup(&ls2->u.ap.addr);
+              tt_str_op(addr1, OP_EQ, addr2);
+              tor_free(addr1);
+              tor_free(addr2);
+              tt_int_op(ls1->u.ap.port, ==, ls2->u.ap.port);
+            }
+            break;
+          case LS_LEGACY_ID:
+            tt_mem_op(ls1->u.legacy_id, OP_EQ, ls2->u.legacy_id,
+                      sizeof(ls1->u.legacy_id));
+            break;
+          default:
+            /* Unknown type, caught it and print its value. */
+            tt_int_op(ls1->type, OP_EQ, -1);
+        }
+      }
+    }
+  }
+
+ done:
+  tor_free(addr1);
+  tor_free(addr2);
+}
+

+ 22 - 0
src/test/hs_test_helpers.h

@@ -0,0 +1,22 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_HS_TEST_HELPERS_H
+#define TOR_HS_TEST_HELPERS_H
+
+#include "ed25519_cert.h"
+#include "hs_descriptor.h"
+
+/* Set of functions to help build and test descriptors. */
+hs_desc_intro_point_t *hs_helper_build_intro_point(
+                          const ed25519_keypair_t *signing_kp, time_t now,
+                          const char *addr, int legacy);
+hs_descriptor_t *hs_helper_build_hs_desc_no_ip(
+                                 const ed25519_keypair_t *signing_kp);
+hs_descriptor_t *hs_helper_build_hs_desc_with_ip(
+                                 const ed25519_keypair_t *signing_kp);
+void hs_helper_desc_equal(const hs_descriptor_t *desc1,
+                          const hs_descriptor_t *desc2);
+
+#endif /* TOR_HS_TEST_HELPERS_H */
+

+ 1 - 0
src/test/include.am

@@ -69,6 +69,7 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
 
 src_test_test_SOURCES = \
 	src/test/log_test_helpers.c \
+	src/test/hs_test_helpers.c \
 	src/test/rend_test_helpers.c \
 	src/test/test.c \
 	src/test/test_accounting.c \

+ 9 - 94
src/test/test_hs_cache.c

@@ -15,96 +15,10 @@
 #include "directory.h"
 #include "connection.h"
 
+#include "hs_test_helpers.h"
 #include "test_helpers.h"
 #include "test.h"
 
-/* Build an intro point using a blinded key and an address. */
-static hs_desc_intro_point_t *
-helper_build_intro_point(const ed25519_keypair_t *blinded_kp,
-                         const char *addr)
-{
-  int ret;
-  ed25519_keypair_t auth_kp;
-  hs_desc_intro_point_t *intro_point = NULL;
-  hs_desc_intro_point_t *ip = tor_malloc_zero(sizeof(*ip));
-  ip->link_specifiers = smartlist_new();
-
-  {
-    hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls));
-    ls->u.ap.port = 9001;
-    int family = tor_addr_parse(&ls->u.ap.addr, addr);
-    switch (family) {
-    case AF_INET:
-      ls->type = LS_IPV4;
-      break;
-    case AF_INET6:
-      ls->type = LS_IPV6;
-      break;
-    default:
-      /* Stop the test, not suppose to have an error. */
-      tt_int_op(family, OP_EQ, AF_INET);
-    }
-    smartlist_add(ip->link_specifiers, ls);
-  }
-
-  ret = ed25519_keypair_generate(&auth_kp, 0);
-  tt_int_op(ret, ==, 0);
-  ip->auth_key_cert = tor_cert_create(blinded_kp, CERT_TYPE_AUTH_HS_IP_KEY,
-                                      &auth_kp.pubkey, time(NULL),
-                                      HS_DESC_CERT_LIFETIME,
-                                      CERT_FLAG_INCLUDE_SIGNING_KEY);
-  tt_assert(ip->auth_key_cert);
-
-  ret = curve25519_keypair_generate(&ip->enc_key.curve25519, 0);
-  tt_int_op(ret, ==, 0);
-  ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519;
-  intro_point = ip;
- done:
-  return intro_point;
-}
-
-/* Return a valid hs_descriptor_t object. */
-static hs_descriptor_t *
-helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime,
-                     ed25519_public_key_t *signing_pubkey)
-{
-  int ret;
-  ed25519_keypair_t blinded_kp;
-  hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));
-
-  desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;
-
-  /* Copy only the public key into the descriptor. */
-  memcpy(&desc->plaintext_data.signing_pubkey, signing_pubkey,
-         sizeof(ed25519_public_key_t));
-
-  ret = ed25519_keypair_generate(&blinded_kp, 0);
-  tt_int_op(ret, ==, 0);
-  /* Copy only the public key into the descriptor. */
-  memcpy(&desc->plaintext_data.blinded_pubkey, &blinded_kp.pubkey,
-         sizeof(ed25519_public_key_t));
-
-  desc->plaintext_data.signing_key_cert =
-    tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC, signing_pubkey,
-                    time(NULL), 3600, CERT_FLAG_INCLUDE_SIGNING_KEY);
-  tt_assert(desc->plaintext_data.signing_key_cert);
-  desc->plaintext_data.revision_counter = revision_counter;
-  desc->plaintext_data.lifetime_sec = lifetime;
-
-  /* Setup encrypted data section. */
-  desc->encrypted_data.create2_ntor = 1;
-  desc->encrypted_data.intro_auth_types = smartlist_new();
-  smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
-  desc->encrypted_data.intro_points = smartlist_new();
-  /* Add an intro point. */
-  smartlist_add(desc->encrypted_data.intro_points,
-                helper_build_intro_point(&blinded_kp, "1.2.3.4"));
-
-  descp = desc;
- done:
-  return descp;
-}
-
 /* Static variable used to encoded the HSDir query. */
 static char query_b64[256];
 
@@ -141,7 +55,7 @@ test_directory(void *arg)
   /* Generate a valid descriptor with normal values. */
   ret = ed25519_keypair_generate(&signing_kp1, 0);
   tt_int_op(ret, ==, 0);
-  desc1 = helper_build_hs_desc(42, 3 * 60 * 60, &signing_kp1.pubkey);
+  desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1);
   tt_assert(desc1);
   ret = hs_desc_encode_descriptor(desc1, &signing_kp1, &desc1_str);
   tt_int_op(ret, OP_EQ, 0);
@@ -175,8 +89,10 @@ test_directory(void *arg)
     ret = ed25519_keypair_generate(&signing_kp_zero, 0);
     tt_int_op(ret, ==, 0);
     hs_descriptor_t *desc_zero_lifetime;
-    desc_zero_lifetime = helper_build_hs_desc(1, 0, &signing_kp_zero.pubkey);
+    desc_zero_lifetime = hs_helper_build_hs_desc_with_ip(&signing_kp_zero);
     tt_assert(desc_zero_lifetime);
+    desc_zero_lifetime->plaintext_data.revision_counter = 1;
+    desc_zero_lifetime->plaintext_data.lifetime_sec = 0;
     char *desc_zero_lifetime_str;
     ret = hs_desc_encode_descriptor(desc_zero_lifetime, &signing_kp_zero,
                                     &desc_zero_lifetime_str);
@@ -262,7 +178,7 @@ test_clean_as_dir(void *arg)
   /* Generate a valid descriptor with values. */
   ret = ed25519_keypair_generate(&signing_kp1, 0);
   tt_int_op(ret, ==, 0);
-  desc1 = helper_build_hs_desc(42, 3 * 60 * 60, &signing_kp1.pubkey);
+  desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1);
   tt_assert(desc1);
   ret = hs_desc_encode_descriptor(desc1, &signing_kp1, &desc1_str);
   tt_int_op(ret, OP_EQ, 0);
@@ -375,7 +291,7 @@ test_upload_and_download_hs_desc(void *arg)
     ed25519_keypair_t signing_kp;
     retval = ed25519_keypair_generate(&signing_kp, 0);
     tt_int_op(retval, ==, 0);
-    published_desc = helper_build_hs_desc(42, 3 * 60 * 60, &signing_kp.pubkey);
+    published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
     tt_assert(published_desc);
     retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
                                        &published_desc_str);
@@ -438,8 +354,7 @@ test_hsdir_revision_counter_check(void *arg)
   {
     retval = ed25519_keypair_generate(&signing_kp, 0);
     tt_int_op(retval, ==, 0);
-    published_desc = helper_build_hs_desc(1312, 3 * 60 * 60,
-                                          &signing_kp.pubkey);
+    published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
     tt_assert(published_desc);
     retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
                                        &published_desc_str);
@@ -470,7 +385,7 @@ test_hsdir_revision_counter_check(void *arg)
     tt_assert(received_desc);
 
     /* Check that the revision counter is correct */
-    tt_u64_op(received_desc->plaintext_data.revision_counter, ==, 1312);
+    tt_u64_op(received_desc->plaintext_data.revision_counter, ==, 42);
 
     hs_descriptor_free(received_desc);
     received_desc = NULL;

+ 7 - 224
src/test/test_hs_descriptor.c

@@ -15,227 +15,10 @@
 #include "test.h"
 #include "torcert.h"
 
+#include "hs_test_helpers.h"
 #include "test_helpers.h"
 #include "log_test_helpers.h"
 
-static hs_desc_intro_point_t *
-helper_build_intro_point(const ed25519_keypair_t *blinded_kp, time_t now,
-                         const char *addr, int legacy)
-{
-  int ret;
-  ed25519_keypair_t auth_kp;
-  hs_desc_intro_point_t *intro_point = NULL;
-  hs_desc_intro_point_t *ip = tor_malloc_zero(sizeof(*ip));
-  ip->link_specifiers = smartlist_new();
-
-  {
-    hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls));
-    if (legacy) {
-      ls->type = LS_LEGACY_ID;
-      memcpy(ls->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8",
-             DIGEST_LEN);
-    } else {
-      ls->u.ap.port = 9001;
-      int family = tor_addr_parse(&ls->u.ap.addr, addr);
-      switch (family) {
-      case AF_INET:
-        ls->type = LS_IPV4;
-        break;
-      case AF_INET6:
-        ls->type = LS_IPV6;
-        break;
-      default:
-        /* Stop the test, not suppose to have an error. */
-        tt_int_op(family, OP_EQ, AF_INET);
-      }
-    }
-    smartlist_add(ip->link_specifiers, ls);
-  }
-
-  ret = ed25519_keypair_generate(&auth_kp, 0);
-  tt_int_op(ret, ==, 0);
-  ip->auth_key_cert = tor_cert_create(blinded_kp, CERT_TYPE_AUTH_HS_IP_KEY,
-                                      &auth_kp.pubkey, now,
-                                      HS_DESC_CERT_LIFETIME,
-                                      CERT_FLAG_INCLUDE_SIGNING_KEY);
-  tt_assert(ip->auth_key_cert);
-
-  if (legacy) {
-    ip->enc_key.legacy = crypto_pk_new();
-    ip->enc_key_type = HS_DESC_KEY_TYPE_LEGACY;
-    tt_assert(ip->enc_key.legacy);
-    ret = crypto_pk_generate_key(ip->enc_key.legacy);
-    tt_int_op(ret, ==, 0);
-  } else {
-    ret = curve25519_keypair_generate(&ip->enc_key.curve25519, 0);
-    tt_int_op(ret, ==, 0);
-    ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519;
-  }
-
-  intro_point = ip;
- done:
-  return intro_point;
-}
-
-/* Return a valid hs_descriptor_t object. If no_ip is set, no introduction
- * points are added. */
-static hs_descriptor_t *
-helper_build_hs_desc(unsigned int no_ip, ed25519_public_key_t *signing_pubkey)
-{
-  int ret;
-  time_t now = time(NULL);
-  ed25519_keypair_t blinded_kp;
-  hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));
-
-  desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;
-
-  /* Copy only the public key into the descriptor. */
-  memcpy(&desc->plaintext_data.signing_pubkey, signing_pubkey,
-         sizeof(ed25519_public_key_t));
-
-  ret = ed25519_keypair_generate(&blinded_kp, 0);
-  tt_int_op(ret, ==, 0);
-  /* Copy only the public key into the descriptor. */
-  memcpy(&desc->plaintext_data.blinded_pubkey, &blinded_kp.pubkey,
-         sizeof(ed25519_public_key_t));
-
-  desc->plaintext_data.signing_key_cert =
-    tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC, signing_pubkey,
-                    now, 3600, CERT_FLAG_INCLUDE_SIGNING_KEY);
-  tt_assert(desc->plaintext_data.signing_key_cert);
-  desc->plaintext_data.revision_counter = 42;
-  desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
-
-  /* Setup encrypted data section. */
-  desc->encrypted_data.create2_ntor = 1;
-  desc->encrypted_data.intro_auth_types = smartlist_new();
-  desc->encrypted_data.single_onion_service = 1;
-  smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
-  desc->encrypted_data.intro_points = smartlist_new();
-  if (!no_ip) {
-    /* Add four intro points. */
-    smartlist_add(desc->encrypted_data.intro_points,
-                helper_build_intro_point(&blinded_kp, now, "1.2.3.4", 0));
-    smartlist_add(desc->encrypted_data.intro_points,
-                helper_build_intro_point(&blinded_kp, now, "[2600::1]", 0));
-    smartlist_add(desc->encrypted_data.intro_points,
-                helper_build_intro_point(&blinded_kp, now, "3.2.1.4", 1));
-    smartlist_add(desc->encrypted_data.intro_points,
-                helper_build_intro_point(&blinded_kp, now, "", 1));
-  }
-
-  descp = desc;
- done:
-  return descp;
-}
-
-static void
-helper_compare_hs_desc(const hs_descriptor_t *desc1,
-                       const hs_descriptor_t *desc2)
-{
-  char *addr1 = NULL, *addr2 = NULL;
-  /* Plaintext data section. */
-  tt_int_op(desc1->plaintext_data.version, OP_EQ,
-            desc2->plaintext_data.version);
-  tt_uint_op(desc1->plaintext_data.lifetime_sec, OP_EQ,
-             desc2->plaintext_data.lifetime_sec);
-  tt_assert(tor_cert_eq(desc1->plaintext_data.signing_key_cert,
-                        desc2->plaintext_data.signing_key_cert));
-  tt_mem_op(desc1->plaintext_data.signing_pubkey.pubkey, OP_EQ,
-            desc2->plaintext_data.signing_pubkey.pubkey,
-            ED25519_PUBKEY_LEN);
-  tt_mem_op(desc1->plaintext_data.blinded_pubkey.pubkey, OP_EQ,
-            desc2->plaintext_data.blinded_pubkey.pubkey,
-            ED25519_PUBKEY_LEN);
-  tt_u64_op(desc1->plaintext_data.revision_counter, ==,
-             desc2->plaintext_data.revision_counter);
-
-  /* NOTE: We can't compare the encrypted blob because when encoding the
-   * descriptor, the object is immutable thus we don't update it with the
-   * encrypted blob. As contrast to the decoding process where we populate a
-   * descriptor object. */
-
-  /* Encrypted data section. */
-  tt_uint_op(desc1->encrypted_data.create2_ntor, ==,
-             desc2->encrypted_data.create2_ntor);
-
-  /* Authentication type. */
-  tt_int_op(!!desc1->encrypted_data.intro_auth_types, ==,
-            !!desc2->encrypted_data.intro_auth_types);
-  if (desc1->encrypted_data.intro_auth_types &&
-      desc2->encrypted_data.intro_auth_types) {
-    tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), ==,
-              smartlist_len(desc2->encrypted_data.intro_auth_types));
-    for (int i = 0;
-         i < smartlist_len(desc1->encrypted_data.intro_auth_types);
-         i++) {
-      tt_str_op(smartlist_get(desc1->encrypted_data.intro_auth_types, i),OP_EQ,
-                smartlist_get(desc2->encrypted_data.intro_auth_types, i));
-    }
-  }
-
-  /* Introduction points. */
-  {
-    tt_assert(desc1->encrypted_data.intro_points);
-    tt_assert(desc2->encrypted_data.intro_points);
-    tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), ==,
-              smartlist_len(desc2->encrypted_data.intro_points));
-    for (int i=0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) {
-      hs_desc_intro_point_t *ip1 = smartlist_get(desc1->encrypted_data
-                                                 .intro_points, i),
-                            *ip2 = smartlist_get(desc2->encrypted_data
-                                                 .intro_points, i);
-      tt_assert(tor_cert_eq(ip1->auth_key_cert, ip2->auth_key_cert));
-      tt_int_op(ip1->enc_key_type, OP_EQ, ip2->enc_key_type);
-      tt_assert(ip1->enc_key_type == HS_DESC_KEY_TYPE_LEGACY ||
-                ip1->enc_key_type == HS_DESC_KEY_TYPE_CURVE25519);
-      switch (ip1->enc_key_type) {
-      case HS_DESC_KEY_TYPE_LEGACY:
-        tt_int_op(crypto_pk_cmp_keys(ip1->enc_key.legacy, ip2->enc_key.legacy),
-                  OP_EQ, 0);
-        break;
-      case HS_DESC_KEY_TYPE_CURVE25519:
-        tt_mem_op(ip1->enc_key.curve25519.pubkey.public_key, OP_EQ,
-                  ip2->enc_key.curve25519.pubkey.public_key,
-                  CURVE25519_PUBKEY_LEN);
-        break;
-      }
-
-      tt_int_op(smartlist_len(ip1->link_specifiers), ==,
-                smartlist_len(ip2->link_specifiers));
-      for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) {
-        hs_desc_link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j),
-                                 *ls2 = smartlist_get(ip2->link_specifiers, j);
-        tt_int_op(ls1->type, ==, ls2->type);
-        switch (ls1->type) {
-        case LS_IPV4:
-        case LS_IPV6:
-        {
-          addr1 = tor_addr_to_str_dup(&ls1->u.ap.addr);
-          addr2 = tor_addr_to_str_dup(&ls2->u.ap.addr);
-          tt_str_op(addr1, OP_EQ, addr2);
-          tor_free(addr1);
-          tor_free(addr2);
-          tt_int_op(ls1->u.ap.port, ==, ls2->u.ap.port);
-        }
-        break;
-        case LS_LEGACY_ID:
-          tt_mem_op(ls1->u.legacy_id, OP_EQ, ls2->u.legacy_id,
-                    sizeof(ls1->u.legacy_id));
-          break;
-        default:
-          /* Unknown type, caught it and print its value. */
-          tt_int_op(ls1->type, OP_EQ, -1);
-        }
-      }
-    }
-  }
-
- done:
-  tor_free(addr1);
-  tor_free(addr2);
-}
-
 /* Test certificate encoding put in a descriptor. */
 static void
 test_cert_encoding(void *arg)
@@ -494,7 +277,7 @@ test_encode_descriptor(void *arg)
 
   ret = ed25519_keypair_generate(&signing_kp, 0);
   tt_int_op(ret, ==, 0);
-  desc = helper_build_hs_desc(0, &signing_kp.pubkey);
+  desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
   ret = hs_desc_encode_descriptor(desc, &signing_kp, &encoded);
   tt_int_op(ret, ==, 0);
   tt_assert(encoded);
@@ -518,7 +301,7 @@ test_decode_descriptor(void *arg)
 
   ret = ed25519_keypair_generate(&signing_kp, 0);
   tt_int_op(ret, ==, 0);
-  desc = helper_build_hs_desc(0, &signing_kp.pubkey);
+  desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
 
   /* Give some bad stuff to the decoding function. */
   ret = hs_desc_decode_descriptor("hladfjlkjadf", NULL, &decoded);
@@ -532,14 +315,14 @@ test_decode_descriptor(void *arg)
   tt_int_op(ret, ==, 0);
   tt_assert(decoded);
 
-  helper_compare_hs_desc(desc, decoded);
+  hs_helper_desc_equal(desc, decoded);
 
   /* Decode a descriptor with _no_ introduction points. */
   {
     ed25519_keypair_t signing_kp_no_ip;
     ret = ed25519_keypair_generate(&signing_kp_no_ip, 0);
     tt_int_op(ret, ==, 0);
-    desc_no_ip = helper_build_hs_desc(1, &signing_kp_no_ip.pubkey);
+    desc_no_ip = hs_helper_build_hs_desc_no_ip(&signing_kp_no_ip);
     tt_assert(desc_no_ip);
     tor_free(encoded);
     ret = hs_desc_encode_descriptor(desc_no_ip, &signing_kp_no_ip, &encoded);
@@ -660,7 +443,7 @@ test_decode_intro_point(void *arg)
     char *line;
     ret = ed25519_keypair_generate(&signing_kp, 0);
     tt_int_op(ret, ==, 0);
-    desc = helper_build_hs_desc(0, &signing_kp.pubkey);
+    desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
     tt_assert(desc);
     /* Only try to decode an incomplete introduction point section. */
     tor_asprintf(&line, "\n%s", intro_point);
@@ -690,7 +473,7 @@ test_decode_intro_point(void *arg)
     desc = NULL;
     ret = ed25519_keypair_generate(&signing_kp, 0);
     tt_int_op(ret, ==, 0);
-    desc = helper_build_hs_desc(0, &signing_kp.pubkey);
+    desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
     const char *junk = "this is not a descriptor";
     ip = decode_introduction_point(desc, junk);
     tt_assert(!ip);