tor

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

test_hs_intropoint.c (32565B)


      1 /* Copyright (c) 2016-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file test_hs_service.c
      6 * \brief Test hidden service functionality.
      7 */
      8 
      9 #define HS_SERVICE_PRIVATE
     10 #define HS_INTROPOINT_PRIVATE
     11 #define RENDSERVICE_PRIVATE
     12 #define CIRCUITLIST_PRIVATE
     13 
     14 #include "test/test.h"
     15 #include "test/log_test_helpers.h"
     16 #include "lib/crypt_ops/crypto_rand.h"
     17 #include "lib/time/compat_time.h"
     18 
     19 #include "core/or/or.h"
     20 #include "core/or/channel.h"
     21 #include "core/or/circuitlist.h"
     22 #include "core/or/circuituse.h"
     23 #include "ht.h"
     24 #include "core/or/relay.h"
     25 
     26 #include "feature/hs/hs_cell.h"
     27 #include "feature/hs/hs_circuitmap.h"
     28 #include "feature/hs/hs_common.h"
     29 #include "feature/hs/hs_config.h"
     30 #include "feature/hs/hs_dos.h"
     31 #include "feature/hs/hs_intropoint.h"
     32 #include "feature/hs/hs_service.h"
     33 
     34 #include "core/or/or_circuit_st.h"
     35 
     36 /* Trunnel. */
     37 #include "trunnel/extension.h"
     38 #include "trunnel/hs/cell_establish_intro.h"
     39 #include "trunnel/hs/cell_introduce1.h"
     40 
     41 static size_t
     42 new_establish_intro_cell(const char *circ_nonce,
     43                         trn_cell_establish_intro_t **cell_out)
     44 {
     45  ssize_t cell_len = 0;
     46  uint8_t buf[RELAY_PAYLOAD_SIZE] = {0};
     47  trn_cell_establish_intro_t *cell = NULL;
     48  hs_service_intro_point_t *ip = NULL;
     49  hs_service_config_t config;
     50 
     51  memset(&config, 0, sizeof(config));
     52 
     53  /* Ensure that *cell_out is NULL such that we can use to check if we need to
     54   * free `cell` in case of an error. */
     55  *cell_out = NULL;
     56 
     57  /* Auth key pair is generated in the constructor so we are all set for
     58   * using this IP object. */
     59  ip = service_intro_point_new(NULL);
     60  tt_assert(ip);
     61  cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, buf);
     62  tt_i64_op(cell_len, OP_GT, 0);
     63 
     64  cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf));
     65  tt_i64_op(cell_len, OP_GT, 0);
     66  tt_assert(cell);
     67  *cell_out = cell;
     68 
     69 done:
     70  if (*cell_out == NULL)
     71    trn_cell_establish_intro_free(cell);
     72 
     73  service_intro_point_free(ip);
     74  return cell_len;
     75 }
     76 
     77 static ssize_t
     78 new_establish_intro_encoded_cell(const char *circ_nonce, uint8_t *cell_out)
     79 {
     80  ssize_t cell_len = 0;
     81  hs_service_intro_point_t *ip = NULL;
     82  hs_service_config_t config;
     83 
     84  memset(&config, 0, sizeof(config));
     85 
     86  /* Auth key pair is generated in the constructor so we are all set for
     87   * using this IP object. */
     88  ip = service_intro_point_new(NULL);
     89  tt_assert(ip);
     90  cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell_out);
     91  tt_i64_op(cell_len, OP_GT, 0);
     92 
     93 done:
     94  service_intro_point_free(ip);
     95  return cell_len;
     96 }
     97 
     98 /* Mock function to avoid networking in unittests */
     99 static int
    100 mock_send_intro_established_cell(or_circuit_t *circ)
    101 {
    102  (void) circ;
    103  return 0;
    104 }
    105 
    106 static int
    107 mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
    108                                  uint8_t relay_command, const char *payload,
    109                                  size_t payload_len,
    110                                  crypt_path_t *cpath_layer,
    111                                  const char *filename, int lineno)
    112 {
    113  (void) stream_id;
    114  (void) circ;
    115  (void) relay_command;
    116  (void) payload;
    117  (void) payload_len;
    118  (void) cpath_layer;
    119  (void) filename;
    120  (void) lineno;
    121  return 0;
    122 }
    123 
    124 static or_circuit_t *
    125 helper_create_intro_circuit(void)
    126 {
    127  or_circuit_t *circ = or_circuit_new(0, NULL);
    128  tt_assert(circ);
    129  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    130  token_bucket_ctr_init(&circ->introduce2_bucket, 100, 100,
    131                       (uint32_t) monotime_coarse_absolute_sec());
    132 done:
    133  return circ;
    134 }
    135 
    136 static trn_cell_introduce1_t *
    137 helper_create_introduce1_cell(void)
    138 {
    139  trn_cell_introduce1_t *cell = NULL;
    140  ed25519_keypair_t auth_key_kp;
    141 
    142  /* Generate the auth_key of the cell. */
    143  if (ed25519_keypair_generate(&auth_key_kp, 0) < 0) {
    144    goto err;
    145  }
    146 
    147  cell = trn_cell_introduce1_new();
    148  tt_assert(cell);
    149 
    150  /* Set the auth key. */
    151  {
    152    size_t auth_key_len = sizeof(auth_key_kp.pubkey);
    153    trn_cell_introduce1_set_auth_key_type(cell,
    154                                     TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
    155    trn_cell_introduce1_set_auth_key_len(cell, auth_key_len);
    156    trn_cell_introduce1_setlen_auth_key(cell, auth_key_len);
    157    uint8_t *auth_key_ptr = trn_cell_introduce1_getarray_auth_key(cell);
    158    memcpy(auth_key_ptr, auth_key_kp.pubkey.pubkey, auth_key_len);
    159  }
    160 
    161  /* Set the cell extensions to none. */
    162  {
    163    trn_extension_t *ext = trn_extension_new();
    164    trn_extension_set_num(ext, 0);
    165    trn_cell_introduce1_set_extensions(cell, ext);
    166  }
    167 
    168  /* Set the encrypted section to some data. */
    169  {
    170    size_t enc_len = 128;
    171    trn_cell_introduce1_setlen_encrypted(cell, enc_len);
    172    uint8_t *enc_ptr = trn_cell_introduce1_getarray_encrypted(cell);
    173    memset(enc_ptr, 'a', enc_len);
    174  }
    175 
    176  return cell;
    177 err:
    178 done:
    179  trn_cell_introduce1_free(cell);
    180  return NULL;
    181 }
    182 
    183 /* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro
    184 * point. Should fail. */
    185 static void
    186 test_establish_intro_wrong_purpose(void *arg)
    187 {
    188  int retval;
    189  ssize_t cell_len = 0;
    190  char circ_nonce[DIGEST_LEN] = {0};
    191  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
    192  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    193 
    194  (void)arg;
    195 
    196  /* Get the auth key of the intro point */
    197  crypto_rand(circ_nonce, sizeof(circ_nonce));
    198  memcpy(intro_circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
    199 
    200  /* Set a bad circuit purpose!! :) */
    201  circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT);
    202 
    203  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
    204     attempt to parse it. */
    205  cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
    206  tt_i64_op(cell_len, OP_GT, 0);
    207 
    208  /* Receive the cell. Should fail. */
    209  setup_full_capture_of_logs(LOG_INFO);
    210  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
    211  expect_log_msg_containing("Rejecting ESTABLISH_INTRO on non-OR circuit.");
    212  teardown_capture_of_logs();
    213  tt_int_op(retval, OP_EQ, -1);
    214 
    215 done:
    216  circuit_free_(TO_CIRCUIT(intro_circ));
    217 }
    218 
    219 /* Prepare a circuit for accepting an ESTABLISH_INTRO cell */
    220 static void
    221 helper_prepare_circ_for_intro(or_circuit_t *circ, const char *circ_nonce)
    222 {
    223  /* Prepare the circuit for the incoming ESTABLISH_INTRO */
    224  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    225  memcpy(circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
    226 }
    227 
    228 /* Send an empty ESTABLISH_INTRO cell. Should fail. */
    229 static void
    230 test_establish_intro_wrong_keytype(void *arg)
    231 {
    232  int retval;
    233  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    234  char circ_nonce[DIGEST_LEN] = {0};
    235 
    236  (void) arg;
    237 
    238  /* Get the auth key of the intro point */
    239  crypto_rand(circ_nonce, sizeof(circ_nonce));
    240  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    241 
    242  /* Receive the cell. Should fail. */
    243  setup_full_capture_of_logs(LOG_INFO);
    244  retval = hs_intro_received_establish_intro(intro_circ, (uint8_t *) "", 0);
    245  expect_log_msg_containing("Empty ESTABLISH_INTRO cell.");
    246  teardown_capture_of_logs();
    247  tt_int_op(retval, OP_EQ, -1);
    248 
    249 done:
    250  circuit_free_(TO_CIRCUIT(intro_circ));
    251 }
    252 
    253 /* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */
    254 static void
    255 test_establish_intro_wrong_keytype2(void *arg)
    256 {
    257  int retval;
    258  char circ_nonce[DIGEST_LEN] = {0};
    259  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
    260  ssize_t cell_len = 0;
    261  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    262 
    263  (void) arg;
    264 
    265  /* Get the auth key of the intro point */
    266  crypto_rand(circ_nonce, sizeof(circ_nonce));
    267  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    268 
    269  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
    270   * attempt to parse it. */
    271  cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
    272  tt_i64_op(cell_len, OP_GT, 0);
    273 
    274  /* Mutate the auth key type! :) */
    275  cell_body[0] = 42;
    276 
    277  /* Receive the cell. Should fail. */
    278  setup_full_capture_of_logs(LOG_INFO);
    279  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
    280  expect_log_msg_containing("Unrecognized AUTH_KEY_TYPE 42.");
    281  teardown_capture_of_logs();
    282  tt_int_op(retval, OP_EQ, -1);
    283 
    284 done:
    285  circuit_free_(TO_CIRCUIT(intro_circ));
    286 }
    287 
    288 /* Send a legit ESTABLISH_INTRO cell but with a wrong MAC. Should fail. */
    289 static void
    290 test_establish_intro_wrong_mac(void *arg)
    291 {
    292  int retval;
    293  char circ_nonce[DIGEST_LEN] = {0};
    294  ssize_t cell_len = 0;
    295  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
    296  trn_cell_establish_intro_t *cell = NULL;
    297  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    298 
    299  (void) arg;
    300 
    301  /* Get the auth key of the intro point */
    302  crypto_rand(circ_nonce, sizeof(circ_nonce));
    303  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    304 
    305  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
    306   * attempt to parse it. */
    307  cell_len = new_establish_intro_cell(circ_nonce, &cell);
    308  tt_i64_op(cell_len, OP_GT, 0);
    309  tt_assert(cell);
    310 
    311  /* Mangle one byte of the MAC. */
    312  uint8_t *handshake_ptr =
    313    trn_cell_establish_intro_getarray_handshake_mac(cell);
    314  handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++;
    315  /* We need to resign the payload with that change. */
    316  {
    317    ed25519_signature_t sig;
    318    ed25519_keypair_t key_struct;
    319    /* New keypair for the signature since we don't have access to the private
    320     * key material generated earlier when creating the cell. */
    321    retval = ed25519_keypair_generate(&key_struct, 0);
    322    tt_int_op(retval, OP_EQ, 0);
    323    uint8_t *auth_key_ptr =
    324      trn_cell_establish_intro_getarray_auth_key(cell);
    325    memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN);
    326    /* Encode payload so we can sign it. */
    327    cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
    328                                               cell);
    329    tt_i64_op(cell_len, OP_GT, 0);
    330 
    331    retval = ed25519_sign_prefixed(&sig, cell_body,
    332                                   cell_len -
    333                                   (ED25519_SIG_LEN + sizeof(cell->sig_len)),
    334                                   ESTABLISH_INTRO_SIG_PREFIX, &key_struct);
    335    tt_int_op(retval, OP_EQ, 0);
    336    /* And write the signature to the cell */
    337    uint8_t *sig_ptr =
    338      trn_cell_establish_intro_getarray_sig(cell);
    339    memcpy(sig_ptr, sig.sig, cell->sig_len);
    340    /* Re-encode with the new signature. */
    341    cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
    342                                               cell);
    343    tt_i64_op(cell_len, OP_GT, 0);
    344  }
    345 
    346  /* Receive the cell. Should fail because our MAC is wrong. */
    347  setup_full_capture_of_logs(LOG_INFO);
    348  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
    349  expect_log_msg_containing("ESTABLISH_INTRO handshake_auth not as expected");
    350  teardown_capture_of_logs();
    351  tt_int_op(retval, OP_EQ, -1);
    352 
    353 done:
    354  trn_cell_establish_intro_free(cell);
    355  circuit_free_(TO_CIRCUIT(intro_circ));
    356 }
    357 
    358 /* Send a legit ESTABLISH_INTRO cell but with a wrong auth key length. Should
    359 * fail. */
    360 static void
    361 test_establish_intro_wrong_auth_key_len(void *arg)
    362 {
    363  int retval;
    364  char circ_nonce[DIGEST_LEN] = {0};
    365  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
    366  ssize_t cell_len = 0;
    367  size_t bad_auth_key_len = ED25519_PUBKEY_LEN - 1;
    368  trn_cell_establish_intro_t *cell = NULL;
    369  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    370 
    371  (void) arg;
    372 
    373  /* Get the auth key of the intro point */
    374  crypto_rand(circ_nonce, sizeof(circ_nonce));
    375  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    376 
    377  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
    378   * attempt to parse it. */
    379  cell_len = new_establish_intro_cell(circ_nonce, &cell);
    380  tt_i64_op(cell_len, OP_GT, 0);
    381  tt_assert(cell);
    382 
    383  /* Mangle the auth key length. */
    384  trn_cell_establish_intro_set_auth_key_len(cell, bad_auth_key_len);
    385  trn_cell_establish_intro_setlen_auth_key(cell, bad_auth_key_len);
    386  /* Encode cell. */
    387  cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
    388                                             cell);
    389  tt_int_op(cell_len, OP_GT, 0);
    390 
    391  /* Receive the cell. Should fail. */
    392  setup_full_capture_of_logs(LOG_INFO);
    393  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
    394  expect_log_msg_containing("ESTABLISH_INTRO auth key length is invalid");
    395  teardown_capture_of_logs();
    396  tt_int_op(retval, OP_EQ, -1);
    397 
    398 done:
    399  trn_cell_establish_intro_free(cell);
    400  circuit_free_(TO_CIRCUIT(intro_circ));
    401 }
    402 
    403 /* Send a legit ESTABLISH_INTRO cell but with a wrong sig length. Should
    404 * fail. */
    405 static void
    406 test_establish_intro_wrong_sig_len(void *arg)
    407 {
    408  int retval;
    409  char circ_nonce[DIGEST_LEN] = {0};
    410  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
    411  ssize_t cell_len = 0;
    412  size_t bad_sig_len = ED25519_SIG_LEN - 1;
    413  trn_cell_establish_intro_t *cell = NULL;
    414  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    415 
    416  (void) arg;
    417 
    418  /* Get the auth key of the intro point */
    419  crypto_rand(circ_nonce, sizeof(circ_nonce));
    420  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    421 
    422  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
    423   * attempt to parse it. */
    424  cell_len = new_establish_intro_cell(circ_nonce, &cell);
    425  tt_i64_op(cell_len, OP_GT, 0);
    426  tt_assert(cell);
    427 
    428  /* Mangle the signature length. */
    429  trn_cell_establish_intro_set_sig_len(cell, bad_sig_len);
    430  trn_cell_establish_intro_setlen_sig(cell, bad_sig_len);
    431  /* Encode cell. */
    432  cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
    433                                             cell);
    434  tt_int_op(cell_len, OP_GT, 0);
    435 
    436  /* Receive the cell. Should fail. */
    437  setup_full_capture_of_logs(LOG_INFO);
    438  retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
    439  expect_log_msg_containing("ESTABLISH_INTRO sig len is invalid");
    440  teardown_capture_of_logs();
    441  tt_int_op(retval, OP_EQ, -1);
    442 
    443 done:
    444  trn_cell_establish_intro_free(cell);
    445  circuit_free_(TO_CIRCUIT(intro_circ));
    446 }
    447 
    448 /* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should
    449 * fail. */
    450 static void
    451 test_establish_intro_wrong_sig(void *arg)
    452 {
    453  int retval;
    454  char circ_nonce[DIGEST_LEN] = {0};
    455  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
    456  ssize_t cell_len = 0;
    457  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    458 
    459  (void) arg;
    460 
    461  /* Get the auth key of the intro point */
    462  crypto_rand(circ_nonce, sizeof(circ_nonce));
    463  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    464 
    465  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
    466     attempt to parse it. */
    467  cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
    468  tt_i64_op(cell_len, OP_GT, 0);
    469 
    470  /* Mutate the last byte (signature)! :) */
    471  cell_body[cell_len - 1]++;
    472 
    473  /* Receive the cell. Should fail. */
    474  setup_full_capture_of_logs(LOG_INFO);
    475  retval = hs_intro_received_establish_intro(intro_circ, cell_body,
    476                                             (size_t)cell_len);
    477  expect_log_msg_containing("Failed to verify ESTABLISH_INTRO cell.");
    478  teardown_capture_of_logs();
    479  tt_int_op(retval, OP_EQ, -1);
    480 
    481 done:
    482  circuit_free_(TO_CIRCUIT(intro_circ));
    483 }
    484 
    485 /* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to
    486 * <b>intro_circ</b>. Return the cell. */
    487 static trn_cell_establish_intro_t *
    488 helper_establish_intro_v3(or_circuit_t *intro_circ)
    489 {
    490  int retval;
    491  char circ_nonce[DIGEST_LEN] = {0};
    492  uint8_t cell_body[RELAY_PAYLOAD_SIZE];
    493  ssize_t cell_len = 0;
    494  trn_cell_establish_intro_t *cell = NULL;
    495 
    496  tt_assert(intro_circ);
    497 
    498  /* Prepare the circuit for the incoming ESTABLISH_INTRO */
    499  crypto_rand(circ_nonce, sizeof(circ_nonce));
    500  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    501 
    502  /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
    503   * attempt to parse it. */
    504  cell_len = new_establish_intro_cell(circ_nonce, &cell);
    505  tt_i64_op(cell_len, OP_GT, 0);
    506  tt_assert(cell);
    507  cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
    508                                             cell);
    509  tt_int_op(cell_len, OP_GT, 0);
    510 
    511  /* Receive the cell */
    512  retval = hs_intro_received_establish_intro(intro_circ, cell_body,
    513                                             (size_t) cell_len);
    514  tt_int_op(retval, OP_EQ, 0);
    515 
    516 done:
    517  return cell;
    518 }
    519 
    520 /* Helper function: test circuitmap free_all function outside of
    521 * test_intro_point_registration to prevent Coverity from seeing a
    522 * double free if the assertion hypothetically fails.
    523 */
    524 static void
    525 test_circuitmap_free_all(void)
    526 {
    527  hs_circuitmap_ht *the_hs_circuitmap = NULL;
    528 
    529  the_hs_circuitmap = get_hs_circuitmap();
    530  tt_assert(the_hs_circuitmap);
    531  hs_circuitmap_free_all();
    532  the_hs_circuitmap = get_hs_circuitmap();
    533  tt_ptr_op(the_hs_circuitmap, OP_EQ, NULL);
    534 done:
    535  ;
    536 }
    537 
    538 /** Successfully register a v3 intro point. Ensure that HS
    539 *  circuitmap is maintained properly. */
    540 static void
    541 test_intro_point_registration(void *arg)
    542 {
    543  hs_circuitmap_ht *the_hs_circuitmap = NULL;
    544 
    545  or_circuit_t *intro_circ = NULL;
    546  trn_cell_establish_intro_t *establish_intro_cell = NULL;
    547  ed25519_public_key_t auth_key = {0};
    548 
    549  or_circuit_t *returned_intro_circ = NULL;
    550 
    551  (void) arg;
    552 
    553  MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);
    554 
    555  hs_circuitmap_init();
    556 
    557  /* Check that the circuitmap is currently empty */
    558  {
    559    the_hs_circuitmap = get_hs_circuitmap();
    560    tt_assert(the_hs_circuitmap);
    561    tt_int_op(0, OP_EQ, HT_SIZE(the_hs_circuitmap));
    562    /* Do a circuitmap query in any case */
    563    returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
    564    tt_ptr_op(returned_intro_circ, OP_EQ, NULL);
    565  }
    566 
    567  /* Create a v3 intro point */
    568  {
    569    intro_circ = or_circuit_new(0, NULL);
    570    tt_assert(intro_circ);
    571    establish_intro_cell = helper_establish_intro_v3(intro_circ);
    572 
    573    /* Check that the intro point was registered on the HS circuitmap */
    574    the_hs_circuitmap = get_hs_circuitmap();
    575    tt_assert(the_hs_circuitmap);
    576    tt_int_op(1, OP_EQ, HT_SIZE(the_hs_circuitmap));
    577    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
    578                           establish_intro_cell);
    579    returned_intro_circ =
    580      hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
    581    tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ);
    582  }
    583 
    584  /* XXX Continue test and try to register a second v3 intro point with the
    585   * same auth key. Make sure that old intro circuit gets closed. */
    586 
    587 done:
    588  circuit_free_(TO_CIRCUIT(intro_circ));
    589  trn_cell_establish_intro_free(establish_intro_cell);
    590  test_circuitmap_free_all();
    591 
    592  UNMOCK(hs_intro_send_intro_established_cell);
    593 }
    594 
    595 static void
    596 test_introduce1_suitable_circuit(void *arg)
    597 {
    598  int ret;
    599  or_circuit_t *circ = NULL;
    600 
    601  (void) arg;
    602 
    603  /* Valid suitable circuit. */
    604  {
    605    circ = or_circuit_new(0, NULL);
    606    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    607    ret = circuit_is_suitable_for_introduce1(circ);
    608    circuit_free_(TO_CIRCUIT(circ));
    609    tt_int_op(ret, OP_EQ, 1);
    610  }
    611 
    612  /* Test if the circuit purpose safeguard works correctly. */
    613  {
    614    circ = or_circuit_new(0, NULL);
    615    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
    616    ret = circuit_is_suitable_for_introduce1(circ);
    617    circuit_free_(TO_CIRCUIT(circ));
    618    tt_int_op(ret, OP_EQ, 0);
    619  }
    620 
    621  /* Test the non-edge circuit safeguard works correctly. */
    622  {
    623    circ = or_circuit_new(0, NULL);
    624    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    625    /* Bogus pointer, the check is against NULL on n_chan. */
    626    circ->base_.n_chan = (channel_t *) circ;
    627    ret = circuit_is_suitable_for_introduce1(circ);
    628    circuit_free_(TO_CIRCUIT(circ));
    629    tt_int_op(ret, OP_EQ, 0);
    630  }
    631 
    632  /* Mangle the circuit a bit more so see if our only one INTRODUCE1 cell
    633   * limit works correctly. */
    634  {
    635    circ = or_circuit_new(0, NULL);
    636    circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
    637    circ->already_received_introduce1 = 1;
    638    ret = circuit_is_suitable_for_introduce1(circ);
    639    circuit_free_(TO_CIRCUIT(circ));
    640    tt_int_op(ret, OP_EQ, 0);
    641  }
    642 
    643  /* Single hop circuit should not be allowed. */
    644  {
    645    circ = or_circuit_new(0, NULL);
    646    circ->p_chan = tor_malloc_zero(sizeof(channel_t));
    647    circ->p_chan->is_client = 1;
    648    ret = circuit_is_suitable_for_introduce1(circ);
    649    tor_free(circ->p_chan);
    650    circuit_free_(TO_CIRCUIT(circ));
    651    tt_int_op(ret, OP_EQ, 0);
    652  }
    653 
    654 done:
    655  ;
    656 }
    657 
    658 static void
    659 test_introduce1_validation(void *arg)
    660 {
    661  int ret;
    662  trn_cell_introduce1_t *cell = NULL;
    663 
    664  (void) arg;
    665 
    666  /* Create our decoy cell that we'll modify as we go to test the validation
    667   * function of that parsed cell. */
    668  cell = helper_create_introduce1_cell();
    669  tt_assert(cell);
    670 
    671  /* Non existing auth key type. */
    672  cell->auth_key_type = 42;
    673  ret = validate_introduce1_parsed_cell(cell);
    674  tt_int_op(ret, OP_EQ, -1);
    675  /* Reset is to correct value and make sure it's correct. */
    676  cell->auth_key_type = TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519;
    677  ret = validate_introduce1_parsed_cell(cell);
    678  tt_int_op(ret, OP_EQ, 0);
    679 
    680  /* Really bad key length. */
    681  cell->auth_key_len = 0;
    682  ret = validate_introduce1_parsed_cell(cell);
    683  tt_int_op(ret, OP_EQ, -1);
    684  cell->auth_key_len = UINT16_MAX;
    685  ret = validate_introduce1_parsed_cell(cell);
    686  tt_int_op(ret, OP_EQ, -1);
    687  /* Correct size, let's try that. */
    688  cell->auth_key_len = sizeof(ed25519_public_key_t);
    689  ret = validate_introduce1_parsed_cell(cell);
    690  tt_int_op(ret, OP_EQ, 0);
    691  /* Set an invalid size of the auth key buffer. */
    692  trn_cell_introduce1_setlen_auth_key(cell, 3);
    693  ret = validate_introduce1_parsed_cell(cell);
    694  tt_int_op(ret, OP_EQ, -1);
    695  /* Reset auth key buffer and make sure it works. */
    696  trn_cell_introduce1_setlen_auth_key(cell, sizeof(ed25519_public_key_t));
    697  ret = validate_introduce1_parsed_cell(cell);
    698  tt_int_op(ret, OP_EQ, 0);
    699 
    700  /* Empty encrypted section. */
    701  trn_cell_introduce1_setlen_encrypted(cell, 0);
    702  ret = validate_introduce1_parsed_cell(cell);
    703  tt_int_op(ret, OP_EQ, -1);
    704  /* Reset it to some non zero bytes and validate. */
    705  trn_cell_introduce1_setlen_encrypted(cell, 1);
    706  ret = validate_introduce1_parsed_cell(cell);
    707  tt_int_op(ret, OP_EQ, 0);
    708 
    709 done:
    710  trn_cell_introduce1_free(cell);
    711 }
    712 
    713 static void
    714 test_received_introduce1_handling(void *arg)
    715 {
    716  int ret;
    717  uint8_t *request = NULL, buf[128];
    718  trn_cell_introduce1_t *cell = NULL;
    719  or_circuit_t *circ = NULL;
    720 
    721  (void) arg;
    722 
    723  MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
    724 
    725  hs_circuitmap_init();
    726 
    727  /* Too small request length. An INTRODUCE1 expect at the very least a
    728   * DIGEST_LEN size. */
    729  {
    730    memset(buf, 0, sizeof(buf));
    731    circ = helper_create_intro_circuit();
    732    ret = hs_intro_received_introduce1(circ, buf, DIGEST_LEN - 1);
    733    tt_int_op(ret, OP_EQ, -1);
    734    circuit_free_(TO_CIRCUIT(circ));
    735  }
    736 
    737  /* We have a unit test only for the suitability of a circuit to receive an
    738   * INTRODUCE1 cell so from now on we'll only test the handling of a cell. */
    739 
    740  /* Bad request. */
    741  {
    742    circ = helper_create_intro_circuit();
    743    uint8_t test[2]; /* Too small request. */
    744    memset(test, 0, sizeof(test));
    745    ret = handle_introduce1(circ, test, sizeof(test));
    746    tor_free(circ->p_chan);
    747    circuit_free_(TO_CIRCUIT(circ));
    748    tt_int_op(ret, OP_EQ, -1);
    749  }
    750 
    751  /* Valid case. */
    752  {
    753    cell = helper_create_introduce1_cell();
    754    ssize_t request_len = trn_cell_introduce1_encoded_len(cell);
    755    tt_int_op((int)request_len, OP_GT, 0);
    756    request = tor_malloc_zero(request_len);
    757    ssize_t encoded_len =
    758      trn_cell_introduce1_encode(request, request_len, cell);
    759    tt_int_op((int)encoded_len, OP_GT, 0);
    760 
    761    circ = helper_create_intro_circuit();
    762    or_circuit_t *service_circ = helper_create_intro_circuit();
    763    circuit_change_purpose(TO_CIRCUIT(service_circ),
    764                           CIRCUIT_PURPOSE_INTRO_POINT);
    765    /* Register the circuit in the map for the auth key of the cell. */
    766    ed25519_public_key_t auth_key;
    767    const uint8_t *cell_auth_key =
    768      trn_cell_introduce1_getconstarray_auth_key(cell);
    769    memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN);
    770    hs_circuitmap_register_intro_circ_v3_relay_side(service_circ, &auth_key);
    771    ret = hs_intro_received_introduce1(circ, request, request_len);
    772    circuit_free_(TO_CIRCUIT(circ));
    773    circuit_free_(TO_CIRCUIT(service_circ));
    774    tt_int_op(ret, OP_EQ, 0);
    775  }
    776 
    777 done:
    778  trn_cell_introduce1_free(cell);
    779  tor_free(request);
    780  hs_circuitmap_free_all();
    781  UNMOCK(relay_send_command_from_edge_);
    782 }
    783 
    784 static void
    785 test_received_establish_intro_dos_ext(void *arg)
    786 {
    787  int ret;
    788  ssize_t cell_len = 0;
    789  uint8_t cell[RELAY_PAYLOAD_SIZE] = {0};
    790  char circ_nonce[DIGEST_LEN] = {0};
    791  hs_service_intro_point_t *ip = NULL;
    792  hs_service_config_t config;
    793  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
    794 
    795  (void) arg;
    796 
    797  MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
    798 
    799  hs_circuitmap_init();
    800 
    801  /* Setup. */
    802  crypto_rand(circ_nonce, sizeof(circ_nonce));
    803  ip = service_intro_point_new(NULL);
    804  tt_assert(ip);
    805  ip->support_intro2_dos_defense = 1;
    806  memset(&config, 0, sizeof(config));
    807  config.has_dos_defense_enabled = 1;
    808  config.intro_dos_rate_per_sec = 13;
    809  config.intro_dos_burst_per_sec = 42;
    810  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    811  /* The INTRO2 bucket should be 0 at this point. */
    812  tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ, 0);
    813  tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ, 0);
    814  tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ, 0);
    815  tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ, 0);
    816 
    817  /* Case 1: Build encoded cell. Usable DoS parameters. */
    818  cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
    819  tt_size_op(cell_len, OP_GT, 0);
    820  /* Pass it to the intro point. */
    821  ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
    822  tt_int_op(ret, OP_EQ, 0);
    823  /* Should be set to the burst value. */
    824  tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ, 42);
    825  /* Validate the config of the intro2 bucket. */
    826  tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ, 13);
    827  tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ, 42);
    828  tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ, 1);
    829 
    830  /* Need to reset the circuit in between test cases. */
    831  circuit_free_(TO_CIRCUIT(intro_circ));
    832  intro_circ = or_circuit_new(0,NULL);
    833  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    834 
    835  /* Case 2: Build encoded cell. Bad DoS parameters. */
    836  config.has_dos_defense_enabled = 1;
    837  config.intro_dos_rate_per_sec = UINT_MAX;
    838  config.intro_dos_burst_per_sec = 13;
    839  cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
    840  tt_size_op(cell_len, OP_GT, 0);
    841  /* Pass it to the intro point. */
    842  ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
    843  tt_int_op(ret, OP_EQ, 0);
    844  tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
    845            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    846  tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
    847            HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
    848  tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
    849            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    850  tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
    851            HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
    852 
    853  /* Need to reset the circuit in between test cases. */
    854  circuit_free_(TO_CIRCUIT(intro_circ));
    855  intro_circ = or_circuit_new(0,NULL);
    856  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    857 
    858  /* Case 3: Build encoded cell. Burst is smaller than rate. Not allowed. */
    859  config.has_dos_defense_enabled = 1;
    860  config.intro_dos_rate_per_sec = 87;
    861  config.intro_dos_burst_per_sec = 45;
    862  cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
    863  tt_size_op(cell_len, OP_GT, 0);
    864  /* Pass it to the intro point. */
    865  ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
    866  tt_int_op(ret, OP_EQ, 0);
    867  tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
    868            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    869  tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
    870            HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
    871  tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
    872            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    873  tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
    874            HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
    875 
    876  /* Need to reset the circuit in between test cases. */
    877  circuit_free_(TO_CIRCUIT(intro_circ));
    878  intro_circ = or_circuit_new(0,NULL);
    879  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    880 
    881  /* Case 4: Build encoded cell. Rate is 0 but burst is not 0. Disables the
    882   * defense. */
    883  config.has_dos_defense_enabled = 1;
    884  config.intro_dos_rate_per_sec = 0;
    885  config.intro_dos_burst_per_sec = 45;
    886  cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
    887  tt_size_op(cell_len, OP_GT, 0);
    888  /* Pass it to the intro point. */
    889  ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
    890  tt_int_op(ret, OP_EQ, 0);
    891  tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
    892            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    893  tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
    894            HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
    895  tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
    896            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    897  tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
    898            HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
    899 
    900  /* Need to reset the circuit in between test cases. */
    901  circuit_free_(TO_CIRCUIT(intro_circ));
    902  intro_circ = or_circuit_new(0,NULL);
    903  helper_prepare_circ_for_intro(intro_circ, circ_nonce);
    904 
    905  /* Case 5: Build encoded cell. Burst is 0 but rate is not 0. Disables the
    906   * defense. */
    907  config.has_dos_defense_enabled = 1;
    908  config.intro_dos_rate_per_sec = 45;
    909  config.intro_dos_burst_per_sec = 0;
    910  cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
    911  tt_size_op(cell_len, OP_GT, 0);
    912  /* Pass it to the intro point. */
    913  ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
    914  tt_int_op(ret, OP_EQ, 0);
    915  tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
    916            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    917  tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
    918            HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
    919  tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
    920            HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
    921  tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
    922            HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
    923 
    924 done:
    925  circuit_free_(TO_CIRCUIT(intro_circ));
    926  service_intro_point_free(ip);
    927  hs_circuitmap_free_all();
    928  UNMOCK(relay_send_command_from_edge_);
    929 }
    930 
    931 static void *
    932 hs_subsystem_setup_fn(const struct testcase_t *tc)
    933 {
    934  (void) tc;
    935 
    936  return NULL;
    937 }
    938 
    939 static int
    940 hs_subsystem_cleanup_fn(const struct testcase_t *tc, void *arg)
    941 {
    942  (void) tc;
    943  (void) arg;
    944 
    945  return 1;
    946 }
    947 
    948 static struct testcase_setup_t test_setup = {
    949  hs_subsystem_setup_fn, hs_subsystem_cleanup_fn
    950 };
    951 
    952 struct testcase_t hs_intropoint_tests[] = {
    953  { "intro_point_registration",
    954    test_intro_point_registration, TT_FORK, NULL, &test_setup},
    955 
    956  { "receive_establish_intro_wrong_keytype",
    957    test_establish_intro_wrong_keytype, TT_FORK, NULL, &test_setup},
    958 
    959  { "receive_establish_intro_wrong_keytype2",
    960    test_establish_intro_wrong_keytype2, TT_FORK, NULL, &test_setup},
    961 
    962  { "receive_establish_intro_wrong_purpose",
    963    test_establish_intro_wrong_purpose, TT_FORK, NULL, &test_setup},
    964 
    965  { "receive_establish_intro_wrong_sig",
    966    test_establish_intro_wrong_sig, TT_FORK, NULL, &test_setup},
    967 
    968  { "receive_establish_intro_wrong_sig_len",
    969    test_establish_intro_wrong_sig_len, TT_FORK, NULL, &test_setup},
    970 
    971  { "receive_establish_intro_wrong_auth_key_len",
    972    test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, &test_setup},
    973 
    974  { "receive_establish_intro_wrong_mac",
    975    test_establish_intro_wrong_mac, TT_FORK, NULL, &test_setup},
    976 
    977  { "introduce1_suitable_circuit",
    978    test_introduce1_suitable_circuit, TT_FORK, NULL, &test_setup},
    979 
    980  { "introduce1_validation",
    981    test_introduce1_validation, TT_FORK, NULL, &test_setup},
    982 
    983  { "received_introduce1_handling",
    984    test_received_introduce1_handling, TT_FORK, NULL, &test_setup},
    985 
    986  { "received_establish_intro_dos_ext",
    987    test_received_establish_intro_dos_ext, TT_FORK, NULL, &test_setup},
    988 
    989  END_OF_TESTCASES
    990 };