[tor-commits] [tor/master] hs-v3: Republish descriptors if client auth changes

nickm at torproject.org nickm at torproject.org
Fri Sep 7 19:06:18 UTC 2018


commit 8f64931d67df2f4b6811b0244bef8d1ea04d8330
Author: Suphanat Chunhapanya <haxx.pop at gmail.com>
Date:   Thu May 10 03:35:29 2018 +0700

    hs-v3: Republish descriptors if client auth changes
    
    When reloading tor, check if our the configured client authorization have
    changed from what we previously had. If so, republish the updated descriptor.
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/feature/hs/hs_service.c | 142 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 140 insertions(+), 2 deletions(-)

diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index c1dc12dde..042880992 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -107,6 +107,8 @@ static int consider_republishing_hs_descriptors = 0;
 static int load_client_keys(hs_service_t *service);
 static void set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc,
                                             time_t now, bool is_current);
+static int build_service_desc_superencrypted(const hs_service_t *service,
+                                             hs_service_descriptor_t *desc);
 static void move_descriptors(hs_service_t *src, hs_service_t *dst);
 static int service_encode_descriptor(const hs_service_t *service,
                                      const hs_service_descriptor_t *desc,
@@ -1321,8 +1323,113 @@ service_descriptor_new(void)
   return sdesc;
 }
 
-/* Move descriptor(s) from the src service to the dst service. We do this
- * during SIGHUP when we re-create our hidden services. */
+/* Allocate and return a deep copy of client. */
+static hs_service_authorized_client_t *
+service_authorized_client_dup(const hs_service_authorized_client_t *client)
+{
+  hs_service_authorized_client_t *client_dup = NULL;
+
+  tor_assert(client);
+
+  client_dup = tor_malloc_zero(sizeof(hs_service_authorized_client_t));
+  /* Currently, the public key is the only component of
+   * hs_service_authorized_client_t. */
+  memcpy(client_dup->client_pk.public_key,
+         client->client_pk.public_key,
+         CURVE25519_PUBKEY_LEN);
+
+  return client_dup;
+}
+
+/* If two authorized clients are equal, return 0. If the first one should come
+ * before the second, return less than zero. If the first should come after
+ * the second, return greater than zero. */
+static int
+service_authorized_client_cmp(const hs_service_authorized_client_t *client1,
+                              const hs_service_authorized_client_t *client2)
+{
+  tor_assert(client1);
+  tor_assert(client2);
+
+  /* Currently, the public key is the only component of
+   * hs_service_authorized_client_t. */
+  return tor_memcmp(client1->client_pk.public_key,
+                    client2->client_pk.public_key,
+                    CURVE25519_PUBKEY_LEN);
+}
+
+/* Helper for sorting authorized clients. */
+static int
+compare_service_authorzized_client_(const void **_a, const void **_b)
+{
+  const hs_service_authorized_client_t *a = *_a, *b = *_b;
+  return service_authorized_client_cmp(a, b);
+}
+
+/* If the list of hs_service_authorized_client_t's is different between
+ * src and dst, return 1. Otherwise, return 0. */
+static int
+service_authorized_client_config_equal(const hs_service_config_t *config1,
+                                       const hs_service_config_t *config2)
+{
+  int ret = 0;
+  int i;
+  smartlist_t *sl1 = smartlist_new();
+  smartlist_t *sl2 = smartlist_new();
+
+  tor_assert(config1);
+  tor_assert(config2);
+  tor_assert(config1->clients);
+  tor_assert(config2->clients);
+
+  /* If the number of clients is different, it is obvious that the list
+   * changes. */
+  if (smartlist_len(config1->clients) != smartlist_len(config2->clients)) {
+    goto done;
+  }
+
+  /* We do not want to mutate config1 and config2, so we will duplicate both
+   * entire client lists here. */
+  SMARTLIST_FOREACH(config1->clients,
+              hs_service_authorized_client_t *, client,
+              smartlist_add(sl1, service_authorized_client_dup(client)));
+
+  SMARTLIST_FOREACH(config2->clients,
+              hs_service_authorized_client_t *, client,
+              smartlist_add(sl2, service_authorized_client_dup(client)));
+
+  smartlist_sort(sl1, compare_service_authorzized_client_);
+  smartlist_sort(sl2, compare_service_authorzized_client_);
+
+  for (i = 0; i < smartlist_len(sl1); i++) {
+    /* If the clients at index i in both lists differ, the whole configs
+     * differ. */
+    if (service_authorized_client_cmp(smartlist_get(sl1, i),
+                                      smartlist_get(sl2, i))) {
+      goto done;
+    }
+  }
+
+  /* Success. */
+  ret = 1;
+
+ done:
+  if (sl1) {
+    SMARTLIST_FOREACH(sl1, hs_service_authorized_client_t *, p,
+                      service_authorized_client_free(p));
+    smartlist_free(sl1);
+  }
+  if (sl2) {
+    SMARTLIST_FOREACH(sl2, hs_service_authorized_client_t *, p,
+                      service_authorized_client_free(p));
+    smartlist_free(sl2);
+  }
+  return ret;
+}
+
+/* Move descriptor(s) from the src service to the dst service and modify their
+ * content if necessary. We do this during SIGHUP when we re-create our
+ * hidden services. */
 static void
 move_descriptors(hs_service_t *src, hs_service_t *dst)
 {
@@ -1346,6 +1453,37 @@ move_descriptors(hs_service_t *src, hs_service_t *dst)
     dst->desc_next = src->desc_next;
     src->desc_next = NULL;
   }
+
+  /* If the client authorization changes, we must rebuild the superencrypted
+   * section and republish the descriptors. */
+  int client_auth_changed =
+    !service_authorized_client_config_equal(&src->config, &dst->config);
+  if (client_auth_changed && dst->desc_current) {
+    /* We have to clear the superencrypted content first. */
+    hs_desc_superencrypted_data_free_contents(
+                                &dst->desc_current->desc->superencrypted_data);
+    if (build_service_desc_superencrypted(dst, dst->desc_current) < 0) {
+      goto err;
+    }
+    service_desc_schedule_upload(dst->desc_current, time(NULL), 1);
+  }
+  if (client_auth_changed && dst->desc_next) {
+    /* We have to clear the superencrypted content first. */
+    hs_desc_superencrypted_data_free_contents(
+                                &dst->desc_next->desc->superencrypted_data);
+    if (build_service_desc_superencrypted(dst, dst->desc_next) < 0) {
+      goto err;
+    }
+    service_desc_schedule_upload(dst->desc_next, time(NULL), 1);
+  }
+
+  return;
+
+ err:
+  /* If there is an error, free all descriptors to make it clean and generate
+   * them later. */
+  service_descriptor_free(dst->desc_current);
+  service_descriptor_free(dst->desc_next);
 }
 
 /* From the given service, remove all expired failing intro points for each





More information about the tor-commits mailing list