]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
hs_pow: Add CompiledProofOfWorkHash torrc option
authorMicah Elizabeth Scott <beth@torproject.org>
Mon, 29 May 2023 02:45:41 +0000 (19:45 -0700)
committerMicah Elizabeth Scott <beth@torproject.org>
Mon, 29 May 2023 03:02:03 +0000 (20:02 -0700)
This exposes the new fallback behavior in hashx via a new AUTOBOOL
configuration option, available to both clients and services. The
default should be fine for nearly everyone, but it might be necessary
to enable or disable the compiler manually for diagnostic purposes.

Signed-off-by: Micah Elizabeth Scott <beth@torproject.org>
doc/man/tor.1.txt
src/app/config/config.c
src/app/config/or_options_st.h
src/feature/hs/hs_client.c
src/feature/hs/hs_pow.c
src/feature/hs/hs_pow.h
src/test/test_hs_pow_slow.c

index 19fdf90c903d14548e3645d4c7d353eb7498fe23..1589809b1af6ac26f54e316ae1b2bc36310d07e8 100644 (file)
@@ -3119,6 +3119,21 @@ The following options are per onion service:
     The maximum burst size for rendezvous requests handled from the
     priority queue at once. (Default: 2500)
 
+These options are applicable to both onion services and their clients:
+
+[[CompiledProofOfWorkHash]] **CompiledProofOfWorkHash** **0**|**1**|**auto**::
+    When proof-of-work DoS mitigation is active, both the services themselves
+    and the clients which connect will use a dynamically generated hash
+    function as part of the puzzle computation.
+     +
+    If this option is set to 1, puzzles will only be solved and verified using
+    the compiled implementation (about 20x faster) and we choose to fail rather
+    than using a slower fallback. If it's 0, the compiler will never be used.
+    By default, the compiler is always tried if possible but the interpreter is
+    available as a fallback. (Default: auto)
+
+See also <<opt-list-modules,`--list-modules`>>, these proof of work options
+have no effect unless the "`pow`" module is enabled at compile time.
 
 == DIRECTORY AUTHORITY SERVER OPTIONS
 
index 10090f273d3469109d9b437dc114f2ad27391d21..4a703abaa338d411fd96922667c0c44947b872e5 100644 (file)
@@ -380,6 +380,7 @@ static const config_var_t option_vars_[] = {
   V(ClientTransportPlugin,       LINELIST, NULL),
   V(ClientUseIPv6,               BOOL,     "1"),
   V(ClientUseIPv4,               BOOL,     "1"),
+  V(CompiledProofOfWorkHash,     AUTOBOOL, "auto"),
   V(ConfluxEnabled,              AUTOBOOL, "auto"),
   VAR("ConfluxClientUX",         STRING,   ConfluxClientUX_option,
           "throughput"),
index c8680bb49e25a94ac258bd63c2d620f926a3cf63..36b00662b5af1e281973d4a4c631b8fd9c89e810 100644 (file)
@@ -723,6 +723,11 @@ struct or_options_t {
    * accessing this value directly.  */
   int ClientPreferIPv6DirPort;
 
+  /** If true, always use the compiled hash implementation. If false, always
+   * the interpreter. Default of "auto" allows a dynamic fallback from
+   * copmiler to interpreter. */
+  int CompiledProofOfWorkHash;
+
   /** If true, the tor client will use conflux for its general purpose
    * circuits which excludes onion service traffic. */
   int ConfluxEnabled;
index 0e4b3ca0c39fdbd61a37f87b152f9170b604f2cc..2bb59f078e8d814c5c845b5cfb8c4ef136e9f048 100644 (file)
@@ -750,7 +750,8 @@ consider_sending_introduce1(origin_circuit_t *intro_circ,
    */
   if (have_module_pow() && desc->encrypted_data.pow_params) {
     hs_pow_solver_inputs_t pow_inputs = {
-      .effort = desc->encrypted_data.pow_params->suggested_effort
+      .effort = desc->encrypted_data.pow_params->suggested_effort,
+      .CompiledProofOfWorkHash = get_options()->CompiledProofOfWorkHash
     };
     ed25519_pubkey_copy(&pow_inputs.service_blinded_id,
                         &desc->plaintext_data.blinded_pubkey);
index 27d09cb0b4c3a4a48a4e46d5e5de0e62f72e4cc3..5cee3b00d7796dabcf3f6bbef5da7aebbda52d69 100644 (file)
@@ -175,9 +175,24 @@ unpack_equix_solution(const uint8_t *bytes_in,
   }
 }
 
+/** Helper: Map the CompiledProofOfWorkHash configuration option to its
+ * corresponding equix_ctx_flags bit. */
+static equix_ctx_flags
+hs_pow_equix_option_flags(int CompiledProofOfWorkHash)
+{
+  if (CompiledProofOfWorkHash == 0) {
+    return 0;
+  } else if (CompiledProofOfWorkHash == 1) {
+    return EQUIX_CTX_MUST_COMPILE;
+  } else {
+    tor_assert_nonfatal(CompiledProofOfWorkHash == -1);
+    return EQUIX_CTX_TRY_COMPILE;
+  }
+}
+
 /** Solve the EquiX/blake2b PoW scheme using the parameters in pow_params, and
  * store the solution in pow_solution_out. Returns 0 on success and -1
- * otherwise. Called by a client. */
+ * otherwise. Called by a client, from a cpuworker thread. */
 int
 hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
              hs_pow_solution_t *pow_solution_out)
@@ -198,7 +213,10 @@ hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
   challenge = build_equix_challenge(&pow_inputs->service_blinded_id,
                                     pow_inputs->seed, nonce, effort);
 
-  ctx = equix_alloc(EQUIX_CTX_SOLVE | EQUIX_CTX_TRY_COMPILE);
+  /* This runs on a cpuworker, let's not access global get_options().
+   * Instead, the particular options we need are captured in pow_inputs. */
+  ctx = equix_alloc(EQUIX_CTX_SOLVE |
+    hs_pow_equix_option_flags(pow_inputs->CompiledProofOfWorkHash));
   if (!ctx) {
     goto end;
   }
@@ -339,7 +357,8 @@ hs_pow_verify(const ed25519_public_key_t *service_blinded_id,
     goto done;
   }
 
-  ctx = equix_alloc(EQUIX_CTX_VERIFY | EQUIX_CTX_TRY_COMPILE);
+  ctx = equix_alloc(EQUIX_CTX_VERIFY |
+    hs_pow_equix_option_flags(get_options()->CompiledProofOfWorkHash));
   if (!ctx) {
     goto done;
   }
@@ -428,7 +447,6 @@ pow_worker_threadfn(void *state_, void *work_)
   job->pow_solution_out = tor_malloc_zero(sizeof(hs_pow_solution_t));
 
   if (hs_pow_solve(&job->pow_inputs, job->pow_solution_out)) {
-    log_warn(LD_REND, "Failed to run the proof of work solver");
     tor_free(job->pow_solution_out);
     job->pow_solution_out = NULL; /* how we signal that we came up empty */
   }
index b5949b79166accabf9737529eb1380e2db37237e..d47eba82ab52b28efeaf62ad34d97332588b58d6 100644 (file)
@@ -84,6 +84,8 @@ typedef struct hs_pow_solver_inputs_t {
   /** Effort chosen by the client. May be higher or lower than
    * suggested_effort in the descriptor. */
   uint32_t effort;
+  /** Configuration option, choice of hash implementation. AUTOBOOL. */
+  int CompiledProofOfWorkHash;
 } hs_pow_solver_inputs_t;
 
 /** State and parameters of PoW defenses, stored in the service state. */
index e21eee33954f9c2b96ea553e1258d9b3973fb585..ff715cf53e7f92eea7074df5d924e4b93ab55a80 100644 (file)
@@ -218,6 +218,7 @@ test_hs_pow_vectors(void *arg)
     hs_pow_solution_t solution = { 0 };
     hs_pow_solver_inputs_t input = {
       .effort = vectors[vec_i].effort,
+      .CompiledProofOfWorkHash = -1
     };
 
     tt_int_op(strlen(service_blinded_id_hex), OP_EQ, 2 * HS_POW_ID_LEN);