[tor-commits] [tor/master] hs: Learn service version by trying to load the keys

nickm at torproject.org nickm at torproject.org
Tue Aug 28 19:58:20 UTC 2018


commit 61ad81c36e46d7b05b66601520c7ff42469f24d7
Author: David Goulet <dgoulet at torproject.org>
Date:   Wed Aug 22 11:38:28 2018 -0400

    hs: Learn service version by trying to load the keys
    
    In order to switch the default HS version from 2 to 3, we need tor to be smart
    and be able to decide on the version by trying to load the service keys during
    configuration validation.
    
    Part of #27215
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/feature/hs/hs_config.c     | 24 +++++++++++++++++++
 src/feature/hs/hs_service.c    | 53 ++++++++++++++++++++++++++++++++++++++++++
 src/feature/hs/hs_service.h    |  1 +
 src/feature/rend/rendservice.c | 23 ++++++++++++++++++
 src/feature/rend/rendservice.h |  1 +
 5 files changed, 102 insertions(+)

diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c
index 2c25a168a..e97257648 100644
--- a/src/feature/hs/hs_config.c
+++ b/src/feature/hs/hs_config.c
@@ -143,6 +143,24 @@ helper_parse_uint64(const char *opt, const char *value, uint64_t min,
   return ret;
 }
 
+/* Return the service version by trying to learn it from the key on disk if
+ * any. If nothing is found, the current service configured version is
+ * returned. */
+static int
+config_learn_service_version(hs_service_t *service)
+{
+  int version;
+
+  tor_assert(service);
+
+  version = hs_service_get_version_from_key(service);
+  if (version < 0) {
+    version = service->config.version;
+  }
+
+  return version;
+}
+
 /* Return true iff the given options starting at line_ for a hidden service
  * contains at least one invalid option. Each hidden service option don't
  * apply to all versions so this function can find out. The line_ MUST start
@@ -490,6 +508,12 @@ config_service(const config_line_t *line, const or_options_t *options,
                                    0) < 0) {
     goto err;
   }
+  /* We'll try to learn the service version here by loading the key(s) if
+   * present. Depending on the key format, we can figure out the service
+   * version. If we can't find a key, the configuration version will be used
+   * which has been set previously. */
+  service->config.version = config_learn_service_version(service);
+
   /* Different functions are in charge of specific options for a version. We
    * start just after the service directory line so once we hit another
    * directory line, the function knows that it has to stop parsing. */
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index a9364a751..fd981f8e1 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -2884,6 +2884,29 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list)
   smartlist_add(list, hs_path_from_filename(s_dir, fname));
 }
 
+/* Return true iff the given service identity key is present on disk. */
+static int
+service_key_on_disk(const char *directory_path)
+{
+  int ret = 0;
+  char *fname;
+  ed25519_keypair_t *kp = NULL;
+
+  tor_assert(directory_path);
+
+  /* Build the v3 key path name and then try to load it. */
+  fname = hs_path_from_filename(directory_path, fname_keyfile_prefix);
+  kp = ed_key_init_from_file(fname, INIT_ED_KEY_SPLIT,
+                             LOG_DEBUG, NULL, 0, 0, 0, NULL, NULL);
+  if (kp) {
+    ret = 1;
+  }
+
+  ed25519_keypair_free(kp);
+  tor_free(fname);
+  return ret;
+}
+
 /* ========== */
 /* Public API */
 /* ========== */
@@ -3375,6 +3398,36 @@ hs_service_circuit_has_opened(origin_circuit_t *circ)
   }
 }
 
+/* Return the service version by looking at the key in the service directory.
+ * If the key is not found or unrecognized, -1 is returned. Else, the service
+ * version is returned. */
+int
+hs_service_get_version_from_key(const hs_service_t *service)
+{
+  int version = -1; /* Unknown version. */
+  const char *directory_path;
+
+  tor_assert(service);
+
+  /* We'll try to load the key for version 3. If not found, we'll try version
+   * 2 and if not found, we'll send back an unknown version (0). */
+  directory_path = service->config.directory_path;
+
+  /* Version 3 check. */
+  if (service_key_on_disk(directory_path)) {
+    version = HS_VERSION_THREE;
+    goto end;
+  }
+  /* Version 2 check. */
+  if (rend_service_key_on_disk(directory_path)) {
+    version = HS_VERSION_TWO;
+    goto end;
+  }
+
+ end:
+  return version;
+}
+
 /* Load and/or generate keys for all onion services including the client
  * authorization if any. Return 0 on success, -1 on failure. */
 int
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index 5c5443a35..6ccd93551 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -262,6 +262,7 @@ void hs_service_free_(hs_service_t *service);
 unsigned int hs_service_get_num_services(void);
 void hs_service_stage_services(const smartlist_t *service_list);
 int hs_service_load_all_keys(void);
+int hs_service_get_version_from_key(const hs_service_t *service);
 void hs_service_lists_fnames_for_sandbox(smartlist_t *file_list,
                                          smartlist_t *dir_list);
 int hs_service_set_conn_addr_port(const origin_circuit_t *circ,
diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c
index 1a99bd56e..1af9117aa 100644
--- a/src/feature/rend/rendservice.c
+++ b/src/feature/rend/rendservice.c
@@ -1341,6 +1341,29 @@ rend_service_poison_new_single_onion_dir(const rend_service_t *s,
   return 0;
 }
 
+/* Return true iff the given service identity key is present on disk. This is
+ * used to try to learn the service version during configuration time. */
+int
+rend_service_key_on_disk(const char *directory_path)
+{
+  int ret = 0;
+  char *fname;
+  crypto_pk_t *pk = NULL;
+
+  tor_assert(directory_path);
+
+  /* Load key */
+  fname = hs_path_from_filename(directory_path, private_key_fname);
+  pk = init_key_from_file(fname, 0, LOG_DEBUG, 0);
+  if (pk) {
+    ret = 1;
+  }
+
+  crypto_pk_free(pk);
+  tor_free(fname);
+  return ret;
+}
+
 /** Load and/or generate private keys for all hidden services, possibly
  * including keys for client authorization.
  * If a <b>service_list</b> is provided, treat it as the list of hidden
diff --git a/src/feature/rend/rendservice.h b/src/feature/rend/rendservice.h
index 709678962..7186289fc 100644
--- a/src/feature/rend/rendservice.h
+++ b/src/feature/rend/rendservice.h
@@ -145,6 +145,7 @@ int rend_config_service(const struct config_line_t *line_,
 void rend_service_prune_list(void);
 void rend_service_free_staging_list(void);
 int rend_service_load_all_keys(const smartlist_t *service_list);
+int rend_service_key_on_disk(const char *directory_path);
 void rend_services_add_filenames_to_lists(smartlist_t *open_lst,
                                           smartlist_t *stat_lst);
 void rend_consider_services_intro_points(time_t now);





More information about the tor-commits mailing list