tor

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

test_hs_ob.c (7760B)


      1 /* Copyright (c) 2020-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file test_hs_ob.c
      6 * \brief Test hidden service onion balance functionality.
      7 */
      8 
      9 #define CONFIG_PRIVATE
     10 #define HS_SERVICE_PRIVATE
     11 #define HS_OB_PRIVATE
     12 
     13 #include "test/test.h"
     14 #include "test/test_helpers.h"
     15 #include "test/log_test_helpers.h"
     16 
     17 #include "app/config/config.h"
     18 #include "feature/hs/hs_config.h"
     19 #include "feature/hs/hs_ob.h"
     20 #include "feature/hs/hs_service.h"
     21 #include "feature/nodelist/networkstatus.h"
     22 #include "feature/nodelist/networkstatus_st.h"
     23 
     24 static ed25519_keypair_t onion_addr_kp_1;
     25 static char onion_addr_1[HS_SERVICE_ADDR_LEN_BASE32 + 1];
     26 
     27 static ed25519_keypair_t onion_addr_kp_2;
     28 static char onion_addr_2[HS_SERVICE_ADDR_LEN_BASE32 + 1];
     29 
     30 static bool config_is_good = true;
     31 
     32 static int
     33 helper_tor_config(const char *conf)
     34 {
     35  int ret = -1;
     36  or_options_t *options = helper_parse_options(conf);
     37  tt_assert(options);
     38  ret = hs_config_service_all(options, 0);
     39 done:
     40  or_options_free(options);
     41  return ret;
     42 }
     43 
     44 static networkstatus_t mock_ns;
     45 
     46 static networkstatus_t *
     47 mock_networkstatus_get_live_consensus(time_t now)
     48 {
     49  (void) now;
     50  return &mock_ns;
     51 }
     52 
     53 static char *
     54 mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out)
     55 {
     56  char *ret = NULL;
     57 
     58  (void) flags;
     59  (void) stat_out;
     60 
     61  if (!strcmp(filename, get_fname("hs3" PATH_SEPARATOR "ob_config"))) {
     62    if (config_is_good) {
     63      tor_asprintf(&ret, "MasterOnionAddress %s.onion\n"
     64                         "MasterOnionAddress %s.onion\n",
     65                         onion_addr_1, onion_addr_2);
     66    } else {
     67      tor_asprintf(&ret, "MasterOnionAddress JUNKJUNKJUNK.onion\n"
     68                         "UnknownOption BLAH\n");
     69    }
     70    goto done;
     71  }
     72 
     73 done:
     74  return ret;
     75 }
     76 
     77 static void
     78 test_parse_config_file(void *arg)
     79 {
     80  int ret;
     81  char *conf = NULL;
     82  const ed25519_public_key_t *pkey;
     83 
     84  (void) arg;
     85 
     86  hs_init();
     87 
     88  MOCK(read_file_to_str, mock_read_file_to_str);
     89 
     90 #define fmt_conf            \
     91  "HiddenServiceDir %s\n"   \
     92  "HiddenServicePort 22\n"  \
     93  "HiddenServiceOnionBalanceInstance 1\n"
     94  tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
     95 #undef fmt_conf
     96 
     97  /* Build the OB frontend onion addresses. */
     98  ed25519_keypair_generate(&onion_addr_kp_1, 0);
     99  hs_build_address(&onion_addr_kp_1.pubkey, HS_VERSION_THREE, onion_addr_1);
    100  ed25519_keypair_generate(&onion_addr_kp_2, 0);
    101  hs_build_address(&onion_addr_kp_2.pubkey, HS_VERSION_THREE, onion_addr_2);
    102 
    103  ret = helper_tor_config(conf);
    104  tor_free(conf);
    105  tt_int_op(ret, OP_EQ, 0);
    106 
    107  /* Load the keys for the service. After that, the v3 service should be
    108   * registered in the global map and we'll be able to access it. */
    109  tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
    110  hs_service_load_all_keys();
    111  tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
    112  const hs_service_t *s = get_first_service();
    113  tt_assert(s);
    114  tt_assert(s->config.ob_master_pubkeys);
    115  tt_assert(hs_ob_service_is_instance(s));
    116  tt_assert(smartlist_len(s->config.ob_master_pubkeys) == 2);
    117 
    118  /* Test the public keys we've added. */
    119  pkey = smartlist_get(s->config.ob_master_pubkeys, 0);
    120  tt_mem_op(&onion_addr_kp_1.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
    121  pkey = smartlist_get(s->config.ob_master_pubkeys, 1);
    122  tt_mem_op(&onion_addr_kp_2.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
    123 
    124 done:
    125  hs_free_all();
    126 
    127  UNMOCK(read_file_to_str);
    128 }
    129 
    130 static void
    131 test_parse_config_file_bad(void *arg)
    132 {
    133  int ret;
    134  char *conf = NULL;
    135 
    136  (void) arg;
    137 
    138  hs_init();
    139 
    140  MOCK(read_file_to_str, mock_read_file_to_str);
    141 
    142  /* Indicate mock_read_file_to_str() to use the bad config. */
    143  config_is_good = false;
    144 
    145 #define fmt_conf            \
    146  "HiddenServiceDir %s\n"   \
    147  "HiddenServicePort 22\n"  \
    148  "HiddenServiceOnionBalanceInstance 1\n"
    149  tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
    150 #undef fmt_conf
    151 
    152  setup_full_capture_of_logs(LOG_INFO);
    153  ret = helper_tor_config(conf);
    154  tor_free(conf);
    155  tt_int_op(ret, OP_EQ, -1);
    156  expect_log_msg_containing("OnionBalance: MasterOnionAddress "
    157                            "JUNKJUNKJUNK.onion is invalid");
    158  expect_log_msg_containing("Found unrecognized option \'UnknownOption\'; "
    159                            "saving it.");
    160  teardown_capture_of_logs();
    161 
    162 done:
    163  hs_free_all();
    164 
    165  UNMOCK(read_file_to_str);
    166 }
    167 
    168 static void
    169 test_get_subcredentials(void *arg)
    170 {
    171  int ret;
    172  hs_service_t *service = NULL;
    173  hs_service_config_t config;
    174  hs_subcredential_t *subcreds = NULL;
    175 
    176  (void) arg;
    177  memset(&config, 0, sizeof(config));
    178 
    179  MOCK(networkstatus_get_live_consensus,
    180       mock_networkstatus_get_live_consensus);
    181 
    182  /* Setup consensus with proper time so we can compute the time period. */
    183  ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
    184                           &mock_ns.valid_after);
    185  tt_int_op(ret, OP_EQ, 0);
    186  ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
    187                           &mock_ns.fresh_until);
    188  tt_int_op(ret, OP_EQ, 0);
    189 
    190  config.ob_master_pubkeys = smartlist_new();
    191  tt_assert(config.ob_master_pubkeys);
    192 
    193  /* Set up an instance */
    194  service = tor_malloc_zero(sizeof(hs_service_t));
    195  service->config = config;
    196  /* Setup the service descriptors */
    197  service->desc_current = service_descriptor_new();
    198  service->desc_next = service_descriptor_new();
    199 
    200  /* First try to compute subcredentials but with no OB keys. Make sure that
    201   * subcreds get NULLed. To do this check we first poison subcreds. */
    202  subcreds = (void*)999;
    203  tt_ptr_op(subcreds, OP_NE, NULL);
    204  size_t num = compute_subcredentials(service, &subcreds);
    205  tt_ptr_op(subcreds, OP_EQ, NULL);
    206 
    207  /* Generate a keypair to add to the OB keys list. */
    208  ed25519_keypair_generate(&onion_addr_kp_1, 0);
    209  smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey);
    210 
    211  /* Set up the instance subcredentials */
    212  char current_subcred[SUBCRED_LEN];
    213  char next_subcred[SUBCRED_LEN];
    214  memset(current_subcred, 'C', SUBCRED_LEN);
    215  memset(next_subcred, 'N', SUBCRED_LEN);
    216  memcpy(service->desc_current->desc->subcredential.subcred, current_subcred,
    217         SUBCRED_LEN);
    218  memcpy(service->desc_next->desc->subcredential.subcred, next_subcred,
    219         SUBCRED_LEN);
    220 
    221  /* See that subcreds are computed properly */
    222  num = compute_subcredentials(service, &subcreds);
    223  /* 5 subcredentials: 3 for the frontend, 2 for the instance */
    224  tt_uint_op(num, OP_EQ, 5);
    225  tt_ptr_op(subcreds, OP_NE, NULL);
    226 
    227  /* Validate the subcredentials we just got. We'll build them oursevles with
    228   * the right time period steps and compare. */
    229  const uint64_t tp = hs_get_time_period_num(0);
    230  const int steps[3] = {0, -1, 1};
    231 
    232  unsigned int i;
    233  for (i = 0; i < 3; i++) {
    234    hs_subcredential_t subcredential;
    235    ed25519_public_key_t blinded_pubkey;
    236    hs_build_blinded_pubkey(&onion_addr_kp_1.pubkey, NULL, 0, tp + steps[i],
    237                            &blinded_pubkey);
    238    hs_get_subcredential(&onion_addr_kp_1.pubkey, &blinded_pubkey,
    239                         &subcredential);
    240    tt_mem_op(subcreds[i].subcred, OP_EQ, subcredential.subcred,
    241              SUBCRED_LEN);
    242  }
    243 
    244  tt_mem_op(subcreds[i++].subcred, OP_EQ, current_subcred, SUBCRED_LEN);
    245  tt_mem_op(subcreds[i++].subcred, OP_EQ, next_subcred, SUBCRED_LEN);
    246 
    247 done:
    248  tor_free(subcreds);
    249 
    250  smartlist_free(config.ob_master_pubkeys);
    251  if (service) {
    252    memset(&service->config, 0, sizeof(hs_service_config_t));
    253    hs_service_free(service);
    254  }
    255 
    256  UNMOCK(networkstatus_get_live_consensus);
    257 }
    258 
    259 struct testcase_t hs_ob_tests[] = {
    260  { "parse_config_file", test_parse_config_file, TT_FORK,
    261    NULL, NULL },
    262  { "parse_config_file_bad", test_parse_config_file_bad, TT_FORK,
    263    NULL, NULL },
    264 
    265  { "get_subcredentials", test_get_subcredentials, TT_FORK,
    266    NULL, NULL },
    267 
    268  END_OF_TESTCASES
    269 };