[tor-commits] [tor/master] hsv3: Implement permanent storage of auth credentials.

dgoulet at torproject.org dgoulet at torproject.org
Tue Dec 3 14:28:38 UTC 2019


commit 70572b9abd660448777ebbee3dc71d7d70b37d8c
Author: George Kadianakis <desnacked at riseup.net>
Date:   Mon Nov 25 15:55:12 2019 +0200

    hsv3: Implement permanent storage of auth credentials.
    
    - See hs_client_register_auth_credentials() for the entry point.
    - Also set the permanent flag for credentials we read from the filesystem.
    - Also add some missing documentation.
---
 src/feature/control/control_hs.c |  4 ++
 src/feature/hs/hs_client.c       | 95 +++++++++++++++++++++++++++++++++++++++-
 src/feature/hs/hs_client.h       |  2 +
 3 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c
index 4c1d16a8c..97938211d 100644
--- a/src/feature/control/control_hs.c
+++ b/src/feature/control/control_hs.c
@@ -145,6 +145,10 @@ handle_control_onion_client_auth_add(control_connection_t *conn,
     /* It's a bug because the service addr has already been validated above */
     control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"", hsaddress);
     break;
+  case REGISTER_FAIL_PERMANENT_STORAGE:
+    control_printf_endreply(conn, 553, "Unable to store creds for \"%s\"",
+                            hsaddress);
+    break;
   case REGISTER_SUCCESS_ALREADY_EXISTS:
     control_printf_endreply(conn, 251,"Client for onion existed and replaced");
     break;
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index 787b29b57..3c681dd85 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -1445,6 +1445,80 @@ client_dir_fetch_unexpected(dir_connection_t *dir_conn, const char *reason,
                                 NULL);
 }
 
+/** Get the full filename for storing the client auth credentials for the
+ *  service in <b>onion_address</b>. The base directory is <b>dir</b>.
+ *  This function never returns NULL. */
+static char *
+get_client_auth_creds_filename(const char *onion_address,
+                               const char *dir)
+{
+  char *full_fname = NULL;
+  char *fname;
+
+  tor_asprintf(&fname, "%s.auth_private", onion_address);
+  full_fname = hs_path_from_filename(dir, fname);
+  tor_free(fname);
+
+  return full_fname;
+}
+
+/** Permanently store the credentials in <b>creds</b> to disk.
+ *
+ *  Return -1 if there was an error while storing the credentials, otherwise
+ *  return 0.
+ */
+static int
+store_permanent_client_auth_credentials(
+                              const hs_client_service_authorization_t *creds)
+{
+  const or_options_t *options = get_options();
+  char *full_fname = NULL;
+  char *file_contents = NULL;
+  char priv_key_b32[BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)+1];
+  int retval = -1;
+
+  tor_assert(creds->flags & CLIENT_AUTH_FLAG_IS_PERMANENT);
+
+  /* We need ClientOnionAuthDir to be set, otherwise we can't proceed */
+  if (!options->ClientOnionAuthDir) {
+    log_warn(LD_GENERAL, "Can't register permanent client auth credentials "
+             "for %s without ClientOnionAuthDir option. Discarding.",
+             creds->onion_address);
+    goto err;
+  }
+
+  /* Make sure the directory exists and is private enough. */
+  if (check_private_dir(options->ClientOnionAuthDir, 0, options->User) < 0) {
+    goto err;
+  }
+
+  /* Get filename that we should store the credentials */
+  full_fname = get_client_auth_creds_filename(creds->onion_address,
+                                              options->ClientOnionAuthDir);
+
+  /* Encode client private key */
+  base32_encode(priv_key_b32, sizeof(priv_key_b32),
+                (char*)creds->enc_seckey.secret_key,
+                sizeof(creds->enc_seckey.secret_key));
+
+  /* Get the full file contents and write it to disk! */
+  tor_asprintf(&file_contents, "%s:descriptor:x25519:%s",
+               creds->onion_address, priv_key_b32);
+  if (write_str_to_file(full_fname, file_contents, 0) < 0) {
+    log_warn(LD_GENERAL, "Failed to write client auth creds file for %s!",
+             creds->onion_address);
+    goto err;
+  }
+
+  retval = 0;
+
+ err:
+  tor_free(file_contents);
+  tor_free(full_fname);
+
+  return retval;
+}
+
 /** Register the credential <b>creds</b> as part of the client auth subsystem.
  *
  * Takes ownership of <b>creds</b>.
@@ -1468,6 +1542,15 @@ hs_client_register_auth_credentials(hs_client_service_authorization_t *creds)
     return REGISTER_FAIL_BAD_ADDRESS;
   }
 
+  /* If we reach this point, the credentials will be stored one way or another:
+   * Make them permanent if the user asked us to. */
+  if (creds->flags & CLIENT_AUTH_FLAG_IS_PERMANENT) {
+    if (store_permanent_client_auth_credentials(creds) < 0) {
+      client_service_authorization_free(creds);
+      return REGISTER_FAIL_PERMANENT_STORAGE;
+    }
+  }
+
   old_creds = digest256map_get(client_auths, service_identity_pk.pubkey);
   if (old_creds) {
     digest256map_remove(client_auths, service_identity_pk.pubkey);
@@ -1795,6 +1878,13 @@ auth_key_filename_is_valid(const char *filename)
   return ret;
 }
 
+/** Parse the client auth credentials off a string in <b>client_key_str</b>
+ *  based on the file format documented in the "Client side configuration"
+ *  section of rend-spec-v3.txt.
+ *
+ *  Return NULL if there was an error, otherwise return a newly allocated
+ *  hs_client_service_authorization_t structure.
+ */
 STATIC hs_client_service_authorization_t *
 parse_auth_file_content(const char *client_key_str)
 {
@@ -1825,7 +1915,7 @@ parse_auth_file_content(const char *client_key_str)
     goto err;
   }
 
-  if (strlen(seckey_b32) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) {
+  if (strlen(seckey_b32) != BASE32_NOPAD_LEN(CURVE25519_SECKEY_LEN)) {
     log_warn(LD_REND, "Client authorization encoded base32 private key "
                       "length is invalid: %s", seckey_b32);
     goto err;
@@ -1842,6 +1932,9 @@ parse_auth_file_content(const char *client_key_str)
   }
   strncpy(auth->onion_address, onion_address, HS_SERVICE_ADDR_LEN_BASE32);
 
+  /* We are reading this from the disk, so set the permanent flag anyway. */
+  auth->flags |= CLIENT_AUTH_FLAG_IS_PERMANENT;
+
   /* Success. */
   goto done;
 
diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h
index 04827ea92..75a911107 100644
--- a/src/feature/hs/hs_client.h
+++ b/src/feature/hs/hs_client.h
@@ -43,6 +43,8 @@ typedef enum {
   REGISTER_SUCCESS_AND_DECRYPTED,
   /* We failed to register these credentials, because of a bad HS address. */
   REGISTER_FAIL_BAD_ADDRESS,
+  /* We failed to register these credentials, because of a bad HS address. */
+  REGISTER_FAIL_PERMANENT_STORAGE,
 } hs_client_register_auth_status_t;
 
 /* Status code of client auth credential removal */





More information about the tor-commits mailing list