tor

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

hs_ob.c (12636B)


      1 /* Copyright (c) 2017-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file hs_ob.c
      6 * \brief Implement Onion Balance specific code.
      7 **/
      8 
      9 #define HS_OB_PRIVATE
     10 
     11 #include "feature/hs/hs_service.h"
     12 
     13 #include "feature/nodelist/networkstatus.h"
     14 #include "feature/nodelist/networkstatus_st.h"
     15 
     16 #include "lib/confmgt/confmgt.h"
     17 #include "lib/encoding/confline.h"
     18 
     19 #include "feature/hs/hs_ob.h"
     20 
     21 /* Options config magic number. */
     22 #define OB_OPTIONS_MAGIC 0x631DE7EA
     23 
     24 /* Helper macros. */
     25 #define VAR(varname, conftype, member, initvalue)                          \
     26  CONFIG_VAR_ETYPE(ob_options_t, varname, conftype, member, 0, initvalue)
     27 #define V(member,conftype,initvalue)        \
     28  VAR(#member, conftype, member, initvalue)
     29 
     30 /* Dummy instance of ob_options_t, used for type-checking its members with
     31 * CONF_CHECK_VAR_TYPE. */
     32 DUMMY_TYPECHECK_INSTANCE(ob_options_t);
     33 
     34 /* Array of variables for the config file options. */
     35 static const config_var_t config_vars[] = {
     36  V(MasterOnionAddress, LINELIST, NULL),
     37 
     38  END_OF_CONFIG_VARS
     39 };
     40 
     41 /* "Extra" variable in the state that receives lines we can't parse. This
     42 * lets us preserve options from versions of Tor newer than us. */
     43 static const struct_member_t config_extra_vars = {
     44  .name = "__extra",
     45  .type = CONFIG_TYPE_LINELIST,
     46  .offset = offsetof(ob_options_t, ExtraLines),
     47 };
     48 
     49 /* Configuration format of ob_options_t. */
     50 static const config_format_t config_format = {
     51  .size = sizeof(ob_options_t),
     52  .magic = {
     53     "ob_options_t",
     54     OB_OPTIONS_MAGIC,
     55     offsetof(ob_options_t, magic_),
     56  },
     57  .vars = config_vars,
     58  .extra = &config_extra_vars,
     59 };
     60 
     61 /* Global configuration manager for the config file. */
     62 static config_mgr_t *config_options_mgr = NULL;
     63 
     64 /* Return the configuration manager for the config file. */
     65 static const config_mgr_t *
     66 get_config_options_mgr(void)
     67 {
     68  if (PREDICT_UNLIKELY(config_options_mgr == NULL)) {
     69    config_options_mgr = config_mgr_new(&config_format);
     70    config_mgr_freeze(config_options_mgr);
     71  }
     72  return config_options_mgr;
     73 }
     74 
     75 #define ob_option_free(val) \
     76  FREE_AND_NULL(ob_options_t, ob_option_free_, (val))
     77 
     78 /** Helper: Free a config options object. */
     79 static void
     80 ob_option_free_(ob_options_t *opts)
     81 {
     82  if (opts == NULL) {
     83    return;
     84  }
     85  config_free(get_config_options_mgr(), opts);
     86 }
     87 
     88 /** Return an allocated config options object. */
     89 static ob_options_t *
     90 ob_option_new(void)
     91 {
     92  ob_options_t *opts = config_new(get_config_options_mgr());
     93  config_init(get_config_options_mgr(), opts);
     94  return opts;
     95 }
     96 
     97 /** Helper function: From the configuration line value which is an onion
     98 * address with the ".onion" extension, find the public key and put it in
     99 * pkey_out.
    100 *
    101 * On success, true is returned. Else, false and pkey is untouched. */
    102 static bool
    103 get_onion_public_key(const char *value, ed25519_public_key_t *pkey_out)
    104 {
    105  char address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
    106 
    107  tor_assert(value);
    108  tor_assert(pkey_out);
    109 
    110  if (strcmpend(value, ".onion")) {
    111    /* Not a .onion extension, bad format. */
    112    return false;
    113  }
    114 
    115  /* Length validation. The -1 is because sizeof() counts the NUL byte. */
    116  if (strlen(value) >
    117      (HS_SERVICE_ADDR_LEN_BASE32 + sizeof(".onion") - 1)) {
    118    /* Too long, bad format. */
    119    return false;
    120  }
    121 
    122  /* We don't want the .onion so we add 2 because size - 1 is copied with
    123   * strlcpy() in order to accommodate the NUL byte and sizeof() counts the NUL
    124   * byte so we need to remove them from the equation. */
    125  strlcpy(address, value, strlen(value) - sizeof(".onion") + 2);
    126 
    127  if (hs_parse_address_no_log(address, pkey_out, NULL, NULL, NULL) < 0) {
    128    return false;
    129  }
    130 
    131  /* Success. */
    132  return true;
    133 }
    134 
    135 /** Parse the given ob options in opts and set the service config object
    136 * accordingly.
    137 *
    138 * Return 1 on success else 0. */
    139 static int
    140 ob_option_parse(hs_service_config_t *config, const ob_options_t *opts)
    141 {
    142  int ret = 0;
    143  config_line_t *line;
    144 
    145  tor_assert(config);
    146  tor_assert(opts);
    147 
    148  for (line = opts->MasterOnionAddress; line; line = line->next) {
    149    /* Allocate config list if need be. */
    150    if (!config->ob_master_pubkeys) {
    151      config->ob_master_pubkeys = smartlist_new();
    152    }
    153    ed25519_public_key_t *pubkey = tor_malloc_zero(sizeof(*pubkey));
    154 
    155    if (!get_onion_public_key(line->value, pubkey)) {
    156      log_warn(LD_REND, "OnionBalance: MasterOnionAddress %s is invalid",
    157               line->value);
    158      tor_free(pubkey);
    159      goto end;
    160    }
    161    smartlist_add(config->ob_master_pubkeys, pubkey);
    162    log_notice(LD_REND, "OnionBalance: MasterOnionAddress %s registered",
    163               line->value);
    164  }
    165  /* Success. */
    166  ret = 1;
    167 
    168 end:
    169  /* No keys added, we free the list since no list means no onion balance
    170   * support for this tor instance. */
    171  if (smartlist_len(config->ob_master_pubkeys) == 0) {
    172    smartlist_free(config->ob_master_pubkeys);
    173  }
    174  return ret;
    175 }
    176 
    177 /** For the given master public key and time period, compute the subcredential
    178 * and put them into subcredential. The subcredential parameter needs to be at
    179 * least DIGEST256_LEN in size. */
    180 static void
    181 build_subcredential(const ed25519_public_key_t *pkey, uint64_t tp,
    182                    hs_subcredential_t *subcredential)
    183 {
    184  ed25519_public_key_t blinded_pubkey;
    185 
    186  tor_assert(pkey);
    187  tor_assert(subcredential);
    188 
    189  hs_build_blinded_pubkey(pkey, NULL, 0, tp, &blinded_pubkey);
    190  hs_get_subcredential(pkey, &blinded_pubkey, subcredential);
    191 }
    192 
    193 /*
    194 * Public API.
    195 */
    196 
    197 /** Return true iff the given service is configured as an onion balance
    198 * instance. To satisfy that condition, there must at least be one master
    199 * ed25519 public key configured. */
    200 bool
    201 hs_ob_service_is_instance(const hs_service_t *service)
    202 {
    203  if (BUG(service == NULL)) {
    204    return false;
    205  }
    206 
    207  /* No list, we are not an instance. */
    208  if (!service->config.ob_master_pubkeys) {
    209    return false;
    210  }
    211 
    212  return smartlist_len(service->config.ob_master_pubkeys) > 0;
    213 }
    214 
    215 /** Read and parse the config file at fname on disk. The service config object
    216 * is populated with the options if any.
    217 *
    218 * Return 1 on success else 0. This is to follow the "ok" convention in
    219 * hs_config.c. */
    220 int
    221 hs_ob_parse_config_file(hs_service_config_t *config)
    222 {
    223  static const char *fname = "ob_config";
    224  int ret = 0;
    225  char *content = NULL, *errmsg = NULL, *config_file_path = NULL;
    226  ob_options_t *options = NULL;
    227  config_line_t *lines = NULL;
    228 
    229  tor_assert(config);
    230 
    231  /* Read file from disk. */
    232  config_file_path = hs_path_from_filename(config->directory_path, fname);
    233  content = read_file_to_str(config_file_path, 0, NULL);
    234  if (!content) {
    235    log_warn(LD_FS, "OnionBalance: Unable to read config file %s",
    236             escaped(config_file_path));
    237    goto end;
    238  }
    239 
    240  /* Parse lines. */
    241  if (config_get_lines(content, &lines, 0) < 0) {
    242    goto end;
    243  }
    244 
    245  options = ob_option_new();
    246  config_assign(get_config_options_mgr(), options, lines, 0, &errmsg);
    247  if (errmsg) {
    248    log_warn(LD_REND, "OnionBalance: Unable to parse config file: %s",
    249             errmsg);
    250    tor_free(errmsg);
    251    goto end;
    252  }
    253 
    254  /* Parse the options and set the service config object with the details. */
    255  ret = ob_option_parse(config, options);
    256 
    257 end:
    258  config_free_lines(lines);
    259  ob_option_free(options);
    260  tor_free(content);
    261  tor_free(config_file_path);
    262  return ret;
    263 }
    264 
    265 /** Compute all possible subcredentials for every onion master key in the given
    266 * service config object. subcredentials_out is allocated and set as an
    267 * continuous array containing all possible values.
    268 *
    269 * On success, return the number of subcredential put in the array which will
    270 * correspond to an array of size: n * DIGEST256_LEN where DIGEST256_LEN is the
    271 * length of a single subcredential.
    272 *
    273 * If the given configuration object has no OB master keys configured, 0 is
    274 * returned and subcredentials_out is set to NULL.
    275 *
    276 * Otherwise, this can't fail. */
    277 STATIC size_t
    278 compute_subcredentials(const hs_service_t *service,
    279                       hs_subcredential_t **subcredentials_out)
    280 {
    281  unsigned int num_pkeys, idx = 0;
    282  hs_subcredential_t *subcreds = NULL;
    283  const int steps[3] = {0, -1, 1};
    284  const unsigned int num_steps = ARRAY_LENGTH(steps);
    285  const uint64_t tp = hs_get_time_period_num(0);
    286 
    287  tor_assert(service);
    288  tor_assert(subcredentials_out);
    289  /* Our caller has checked these too */
    290  tor_assert(service->desc_current);
    291  tor_assert(service->desc_next);
    292 
    293  /* Make sure we are an OB instance, or bail out. */
    294  num_pkeys = smartlist_len(service->config.ob_master_pubkeys);
    295  if (!num_pkeys) {
    296    *subcredentials_out = NULL;
    297    return 0;
    298  }
    299 
    300  /* Time to build all the subcredentials for each time period: two for each
    301   * instance descriptor plus three for the onionbalance frontend service: the
    302   * previous one (-1), the current one (0) and the next one (1) for each
    303   * configured key in order to accommodate client and service consensus skew.
    304   *
    305   * If the client consensus after_time is at 23:00 but the service one is at
    306   * 01:00, the client will be using the previous time period where the
    307   * service will think it is the client next time period. Thus why we have
    308   * to try them all.
    309   *
    310   * The normal use case works because the service gets the descriptor object
    311   * that corresponds to the intro point's request, and because each
    312   * descriptor corresponds to a specific subcredential, we get the right
    313   * subcredential out of it, and use that to do the decryption.
    314   *
    315   * As a slight optimization, statistically, the current time period (0) will
    316   * be the one to work first so we'll put them first in the array to maximize
    317   * our chance of success. */
    318 
    319  /* We use a flat array, not a smartlist_t, in order to minimize memory
    320   * allocation.
    321   *
    322   * Size of array is: length of a single subcredential multiplied by the
    323   * number of time period we need to compute and finally multiplied by the
    324   * total number of keys we are about to process. In other words, for each
    325   * key, we allocate 3 subcredential slots. Then in the end we also add two
    326   * subcredentials for this instance's active descriptors. */
    327  subcreds =
    328    tor_calloc((num_steps * num_pkeys) + 2, sizeof(hs_subcredential_t));
    329 
    330  /* For each master pubkey we add 3 subcredentials: */
    331  for (unsigned int i = 0; i < num_steps; i++) {
    332    SMARTLIST_FOREACH_BEGIN(service->config.ob_master_pubkeys,
    333                            const ed25519_public_key_t *, pkey) {
    334      build_subcredential(pkey, tp + steps[i], &subcreds[idx]);
    335      idx++;
    336    } SMARTLIST_FOREACH_END(pkey);
    337  }
    338 
    339  /* And then in the end we add the two subcredentials of the current active
    340   * instance descriptors */
    341  memcpy(&subcreds[idx++], &service->desc_current->desc->subcredential,
    342         sizeof(hs_subcredential_t));
    343  memcpy(&subcreds[idx++], &service->desc_next->desc->subcredential,
    344         sizeof(hs_subcredential_t));
    345 
    346  log_info(LD_REND, "Refreshing %u onionbalance keys (TP #%d).",
    347             idx, (int)tp);
    348 
    349  *subcredentials_out = subcreds;
    350  return idx;
    351 }
    352 
    353 /**
    354 *  If we are an Onionbalance instance, refresh our keys.
    355 *
    356 *  If we are not an Onionbalance instance or we are not ready to do so, this
    357 *  is a NOP.
    358 *
    359 *  This function is called every time we build a new descriptor. That's
    360 *  because we want our Onionbalance keys to always use up-to-date
    361 *  subcredentials both for the instance (ourselves) and for the onionbalance
    362 *  frontend.
    363 */
    364 void
    365 hs_ob_refresh_keys(hs_service_t *service)
    366 {
    367  hs_subcredential_t *ob_subcreds = NULL;
    368  size_t num_subcreds;
    369 
    370  tor_assert(service);
    371 
    372  /* Don't do any of this if we are not configured as an OB instance */
    373  if (!hs_ob_service_is_instance(service)) {
    374    return;
    375  }
    376 
    377  /* We need both service descriptors created to make onionbalance keys.
    378   *
    379   * That's because we fetch our own (the instance's) subcredentials from our
    380   * own descriptors which should always include the latest subcredentials that
    381   * clients would use.
    382   *
    383   * This function is called with each descriptor build, so we will be
    384   * eventually be called when both descriptors are created. */
    385  if (!service->desc_current || !service->desc_next) {
    386    return;
    387  }
    388 
    389  /* Get a new set of subcreds */
    390  num_subcreds = compute_subcredentials(service, &ob_subcreds);
    391  if (BUG(!num_subcreds)) {
    392    return;
    393  }
    394 
    395  /* Delete old subcredentials if any */
    396  if (service->state.ob_subcreds) {
    397    tor_free(service->state.ob_subcreds);
    398  }
    399 
    400  service->state.ob_subcreds = ob_subcreds;
    401  service->state.n_ob_subcreds = num_subcreds;
    402 }
    403 
    404 /** Free any memory allocated by the onionblance subsystem. */
    405 void
    406 hs_ob_free_all(void)
    407 {
    408  config_mgr_free(config_options_mgr);
    409 }