tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

hs_pow.h (7758B)


      1 /* Copyright (c) 2019-2020, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file hs_pow.h
      6 * \brief Header file containing PoW denial of service defenses for the HS
      7 *        subsystem for all versions.
      8 **/
      9 
     10 #ifndef TOR_HS_POW_H
     11 #define TOR_HS_POW_H
     12 
     13 #include "lib/evloop/compat_libevent.h"
     14 #include "lib/evloop/token_bucket.h"
     15 #include "lib/smartlist_core/smartlist_core.h"
     16 #include "lib/crypt_ops/crypto_ed25519.h"
     17 
     18 /* Service updates the suggested effort every HS_UPDATE_PERIOD seconds.
     19 * This parameter controls how often we can change hs descriptor data to
     20 * update suggested_effort, but it also controls the frequency of our
     21 * opportunities to increase or decrease effort. Lower values react to
     22 * attacks faster, higher values may be more stable.
     23 * Can this move to torrc? (Or the consensus?) The hs_cache timings are
     24 * related, and they're also hardcoded.
     25 */
     26 #define HS_UPDATE_PERIOD 300
     27 
     28 /** Length of random nonce (N) used in the PoW scheme. */
     29 #define HS_POW_NONCE_LEN 16
     30 /** Length of an E-quiX solution (S) in bytes. */
     31 #define HS_POW_EQX_SOL_LEN 16
     32 /** Length of blake2b hash result (R) used in the PoW scheme. */
     33 #define HS_POW_HASH_LEN 4
     34 /** Length of algorithm personalization string (P) used in the PoW scheme */
     35 #define HS_POW_PSTRING_LEN 16
     36 /** Algorithm personalization string (P) */
     37 #define HS_POW_PSTRING "Tor hs intro v1\0"
     38 /** Length of the blinded public ID for the onion service (ID) */
     39 #define HS_POW_ID_LEN 32
     40 /** Length of random seed used in the PoW scheme. */
     41 #define HS_POW_SEED_LEN 32
     42 /** Length of seed identification heading in the PoW scheme. */
     43 #define HS_POW_SEED_HEAD_LEN 4
     44 /** Length of an effort value */
     45 #define HS_POW_EFFORT_LEN sizeof(uint32_t)
     46 /** Offset of the nonce value within the challenge string */
     47 #define HS_POW_NONCE_OFFSET \
     48  (HS_POW_PSTRING_LEN + HS_POW_ID_LEN + HS_POW_SEED_LEN)
     49 /** Length of a PoW challenge. Construction as per prop327 is:
     50 *    (P || ID || C || N || INT_32(E))
     51 */
     52 #define HS_POW_CHALLENGE_LEN \
     53  (HS_POW_PSTRING_LEN + HS_POW_ID_LEN + \
     54  HS_POW_SEED_LEN + HS_POW_NONCE_LEN + HS_POW_EFFORT_LEN)
     55 
     56 /** Type of PoW in the descriptor. */
     57 typedef enum {
     58  HS_POW_DESC_V1 = 1,
     59 } hs_pow_desc_type_t;
     60 
     61 /** Proof-of-Work parameters for DoS defense located in a descriptor. */
     62 typedef struct hs_pow_desc_params_t {
     63  /** Type of PoW system being used. */
     64  hs_pow_desc_type_t type;
     65 
     66  /** Random 32-byte seed used as input the the PoW hash function */
     67  uint8_t seed[HS_POW_SEED_LEN];
     68 
     69  /** Specifies effort value that clients should aim for when contacting the
     70   * service. */
     71  uint32_t suggested_effort;
     72 
     73  /** Timestamp after which the above seed expires. */
     74  time_t expiration_time;
     75 } hs_pow_desc_params_t;
     76 
     77 /** The inputs to the PoW solver, derived from the descriptor data and the
     78  * client's per-connection effort choices. */
     79 typedef struct hs_pow_solver_inputs_t {
     80  /** Seed value from a current descriptor */
     81  uint8_t seed[HS_POW_SEED_LEN];
     82  /** Blinded public ID for the onion service this puzzle is bound to */
     83  ed25519_public_key_t service_blinded_id;
     84  /** Effort chosen by the client. May be higher or lower than
     85   * suggested_effort in the descriptor. */
     86  uint32_t effort;
     87  /** Configuration option, choice of hash implementation. AUTOBOOL. */
     88  int CompiledProofOfWorkHash;
     89 } hs_pow_solver_inputs_t;
     90 
     91 /** State and parameters of PoW defenses, stored in the service state. */
     92 typedef struct hs_pow_service_state_t {
     93  /* If PoW defenses are enabled this is a priority queue containing acceptable
     94   * requests that are awaiting rendezvous circuits to built, where priority is
     95   * based on the amount of effort that was exerted in the PoW. */
     96  smartlist_t *rend_request_pqueue;
     97 
     98  /* Low level mark for pqueue size. Below this length it's considered to be
     99   * effectively empty when calculating effort adjustments. */
    100  int pqueue_low_level;
    101 
    102  /* High level mark for pqueue size. When the queue is this length we will
    103   * trim it down to pqueue_high_level/2. */
    104  int pqueue_high_level;
    105 
    106  /* Event callback for dequeueing rend requests, paused when the queue is
    107   * empty or rate limited. */
    108  mainloop_event_t *pop_pqueue_ev;
    109 
    110  /* Token bucket for rate limiting the priority queue */
    111  token_bucket_ctr_t pqueue_bucket;
    112 
    113  /* The current seed being used in the PoW defenses. */
    114  uint8_t seed_current[HS_POW_SEED_LEN];
    115 
    116  /* The previous seed that was used in the PoW defenses. We accept solutions
    117   * for both the current and previous seed.  */
    118  uint8_t seed_previous[HS_POW_SEED_LEN];
    119 
    120  /* The time at which the current seed expires and rotates for a new one. */
    121  time_t expiration_time;
    122 
    123  /* The suggested effort that clients should use in order for their request to
    124   * be serviced in a timely manner. */
    125  uint32_t suggested_effort;
    126 
    127  /* The maximum effort of a request we've had to trim, this update period */
    128  uint32_t max_trimmed_effort;
    129 
    130  /* The following values are used when calculating and updating the suggested
    131   * effort every HS_UPDATE_PERIOD seconds. */
    132 
    133  /* Number of intro requests the service handled since last update. */
    134  uint32_t rend_handled;
    135  /* The next time at which to update the suggested effort. */
    136  time_t next_effort_update;
    137  /* Sum of effort of all valid requests received since the last update. */
    138  uint64_t total_effort;
    139 
    140  /* Did we have elements waiting in the queue during this period? */
    141  bool had_queue;
    142  /* Are we using pqueue_bucket to rate limit the pqueue? */
    143  bool using_pqueue_bucket;
    144 
    145 } hs_pow_service_state_t;
    146 
    147 /* Struct to store a solution to the PoW challenge. */
    148 typedef struct hs_pow_solution_t {
    149  /* The nonce chosen to satisfy the PoW challenge's conditions. */
    150  uint8_t nonce[HS_POW_NONCE_LEN];
    151 
    152  /* The effort used in this solution. */
    153  uint32_t effort;
    154 
    155  /* A prefix of the seed used in this solution, so it can be identified. */
    156  uint8_t seed_head[HS_POW_SEED_HEAD_LEN];
    157 
    158  /* The Equi-X solution used in this PoW solution. */
    159  uint8_t equix_solution[HS_POW_EQX_SOL_LEN];
    160 } hs_pow_solution_t;
    161 
    162 #ifdef HAVE_MODULE_POW
    163 #define have_module_pow() (1)
    164 
    165 /* API */
    166 int hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
    167                 hs_pow_solution_t *pow_solution_out);
    168 
    169 int hs_pow_verify(const ed25519_public_key_t *service_blinded_id,
    170                  const hs_pow_service_state_t *pow_state,
    171                  const hs_pow_solution_t *pow_solution);
    172 
    173 void hs_pow_remove_seed_from_cache(const uint8_t *seed_head);
    174 void hs_pow_free_service_state(hs_pow_service_state_t *state);
    175 
    176 int hs_pow_queue_work(uint32_t intro_circ_identifier,
    177                      const uint8_t *rend_circ_cookie,
    178                      const hs_pow_solver_inputs_t *pow_inputs);
    179 
    180 #else /* !defined(HAVE_MODULE_POW) */
    181 #define have_module_pow() (0)
    182 
    183 static inline int
    184 hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
    185             hs_pow_solution_t *pow_solution_out)
    186 {
    187  (void)pow_inputs;
    188  (void)pow_solution_out;
    189  return -1;
    190 }
    191 
    192 static inline int
    193 hs_pow_verify(const ed25519_public_key_t *service_blinded_id,
    194              const hs_pow_service_state_t *pow_state,
    195              const hs_pow_solution_t *pow_solution)
    196 {
    197  (void)service_blinded_id;
    198  (void)pow_state;
    199  (void)pow_solution;
    200  return -1;
    201 }
    202 
    203 static inline void
    204 hs_pow_remove_seed_from_cache(const uint8_t *seed_head)
    205 {
    206  (void)seed_head;
    207 }
    208 
    209 static inline void
    210 hs_pow_free_service_state(hs_pow_service_state_t *state)
    211 {
    212  (void)state;
    213 }
    214 
    215 static inline int
    216 hs_pow_queue_work(uint32_t intro_circ_identifier,
    217                  const uint8_t *rend_circ_cookie,
    218                  const hs_pow_solver_inputs_t *pow_inputs)
    219 {
    220  (void)intro_circ_identifier;
    221  (void)rend_circ_cookie;
    222  (void)pow_inputs;
    223  return -1;
    224 }
    225 
    226 #endif /* defined(HAVE_MODULE_POW) */
    227 
    228 #endif /* !defined(TOR_HS_POW_H) */