tor

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

test_hs_client.c (52553B)


      1 /* Copyright (c) 2016-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file test_hs_client.c
      6 * \brief Test prop224 HS client functionality.
      7 */
      8 
      9 #define CONFIG_PRIVATE
     10 #define CRYPTO_PRIVATE
     11 #define MAINLOOP_PRIVATE
     12 #define HS_CLIENT_PRIVATE
     13 #define CHANNEL_OBJECT_PRIVATE
     14 #define CIRCUITBUILD_PRIVATE
     15 #define CIRCUITLIST_PRIVATE
     16 #define CONNECTION_PRIVATE
     17 #define CRYPT_PATH_PRIVATE
     18 #define TOR_CONGESTION_CONTROL_COMMON_PRIVATE
     19 
     20 #include "test/test.h"
     21 #include "test/test_helpers.h"
     22 #include "test/log_test_helpers.h"
     23 #include "test/hs_test_helpers.h"
     24 
     25 #include "app/config/config.h"
     26 #include "lib/crypt_ops/crypto_cipher.h"
     27 #include "lib/crypt_ops/crypto_dh.h"
     28 #include "lib/crypt_ops/crypto_rand.h"
     29 #include "core/or/channeltls.h"
     30 #include "feature/dircommon/directory.h"
     31 #include "core/mainloop/mainloop.h"
     32 #include "feature/nodelist/nodelist.h"
     33 #include "feature/nodelist/routerset.h"
     34 
     35 #include "feature/hs/hs_circuit.h"
     36 #include "feature/hs/hs_circuitmap.h"
     37 #include "feature/hs/hs_client.h"
     38 #include "feature/hs/hs_config.h"
     39 #include "feature/hs/hs_ident.h"
     40 #include "feature/hs/hs_cache.h"
     41 #include "core/or/circuitlist.h"
     42 #include "core/or/circuitbuild.h"
     43 #include "core/or/extendinfo.h"
     44 #include "core/mainloop/connection.h"
     45 #include "core/or/connection_edge.h"
     46 #include "feature/nodelist/networkstatus.h"
     47 
     48 #include "core/or/cpath_build_state_st.h"
     49 #include "core/or/crypt_path_st.h"
     50 #include "core/or/crypt_path.h"
     51 #include "feature/dircommon/dir_connection_st.h"
     52 #include "core/or/entry_connection_st.h"
     53 #include "core/or/extend_info_st.h"
     54 #include "feature/nodelist/networkstatus_st.h"
     55 #include "core/or/origin_circuit_st.h"
     56 #include "core/or/socks_request_st.h"
     57 
     58 #include "core/or/congestion_control_st.h"
     59 #include "core/or/congestion_control_common.h"
     60 
     61 static int
     62 mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
     63 {
     64  (void) ap_conn;
     65  return 0;
     66 }
     67 
     68 static networkstatus_t mock_ns;
     69 
     70 /* Always return NULL. */
     71 static networkstatus_t *
     72 mock_networkstatus_get_reasonably_live_consensus_false(time_t now, int flavor)
     73 {
     74  (void) now;
     75  (void) flavor;
     76  return NULL;
     77 }
     78 
     79 static networkstatus_t *
     80 mock_networkstatus_get_reasonably_live_consensus(time_t now, int flavor)
     81 {
     82  (void) now;
     83  (void) flavor;
     84  return &mock_ns;
     85 }
     86 
     87 static int
     88 mock_write_str_to_file(const char *path, const char *str, int bin)
     89 {
     90  (void) bin;
     91  (void) path;
     92  (void) str;
     93  return 0;
     94 }
     95 
     96 static or_options_t mocked_options;
     97 
     98 static const or_options_t *
     99 mock_get_options(void)
    100 {
    101  return &mocked_options;
    102 }
    103 
    104 static int
    105 helper_config_client(const char *conf, int validate_only)
    106 {
    107  int ret = 0;
    108  or_options_t *options = NULL;
    109  tt_assert(conf);
    110  options = helper_parse_options(conf);
    111  tt_assert(options);
    112  ret = hs_config_client_auth_all(options, validate_only);
    113 done:
    114  or_options_free(options);
    115  return ret;
    116 }
    117 
    118 static void
    119 helper_add_random_client_auth(const ed25519_public_key_t *service_pk)
    120 {
    121  char *conf = NULL;
    122 #define conf_fmt "ClientOnionAuthDir %s\n"
    123  tor_asprintf(&conf, conf_fmt, get_fname("auth_keys"));
    124 #undef conf_fmt
    125  helper_config_client(conf, 0);
    126  tor_free(conf);
    127 
    128  digest256map_t *client_auths = get_hs_client_auths_map();
    129  hs_client_service_authorization_t *auth =
    130    tor_malloc_zero(sizeof(hs_client_service_authorization_t));
    131  curve25519_secret_key_generate(&auth->enc_seckey, 0);
    132  hs_build_address(service_pk, HS_VERSION_THREE, auth->onion_address);
    133  digest256map_set(client_auths, service_pk->pubkey, auth);
    134 }
    135 
    136 /* Test helper function: Setup a circuit and a stream with the same hidden
    137 * service destination, and put them in <b>circ_out</b> and
    138 * <b>conn_out</b>. Make the stream wait for circuits to be established to the
    139 * hidden service. */
    140 static int
    141 helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
    142                                    connection_t **conn_out)
    143 {
    144  channel_tls_t *n_chan=NULL;
    145  origin_circuit_t *or_circ = NULL;
    146  connection_t *conn = NULL;
    147  ed25519_public_key_t service_pk;
    148 
    149  /* Make a dummy connection stream and make it wait for our circuit */
    150  conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT,
    151                                  CONN_TYPE_AP /* ??? */,
    152                                  0);
    153  /* prop224: Setup hs conn identifier on the stream */
    154  ed25519_secret_key_t sk;
    155  tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
    156  tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
    157 
    158  /* Setup hs_conn_identifier of stream */
    159  TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk);
    160 
    161  /* Make it wait for circuit */
    162  connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn));
    163 
    164  /* This is needed to silence a BUG warning from
    165     connection_edge_update_circuit_isolation() */
    166  TO_ENTRY_CONN(conn)->original_dest_address =
    167    tor_strdup(TO_ENTRY_CONN(conn)->socks_request->address);
    168 
    169  /****************************************************/
    170 
    171  /* Now make dummy circuit */
    172  or_circ = origin_circuit_new();
    173 
    174  or_circ->base_.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
    175 
    176  or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
    177  or_circ->build_state->is_internal = 1;
    178 
    179  /* prop224: Setup hs ident on the circuit */
    180  or_circ->hs_ident = hs_ident_circuit_new(&service_pk);
    181  or_circ->hs_ident->intro_auth_pk.pubkey[0] = 42;
    182 
    183  TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
    184 
    185  /* fake n_chan */
    186  n_chan = tor_malloc_zero(sizeof(channel_tls_t));
    187  n_chan->base_.global_identifier = 1;
    188  or_circ->base_.n_chan = &(n_chan->base_);
    189 
    190  *circ_out = or_circ;
    191  *conn_out = conn;
    192 
    193  return 0;
    194 
    195 done:
    196  /* something failed */
    197  return -1;
    198 }
    199 
    200 /* Test: Ensure that setting up v3 rendezvous circuits works correctly. */
    201 static void
    202 test_e2e_rend_circuit_setup(void *arg)
    203 {
    204  uint8_t ntor_key_seed[DIGEST256_LEN] = {0};
    205  origin_circuit_t *or_circ = NULL;
    206  int retval;
    207  connection_t *conn = NULL;
    208 
    209  (void) arg;
    210 
    211  /** In this test we create a prop224 v3 HS stream and a circuit with the same
    212   *  hidden service destination. We make the stream wait for circuits to be
    213   *  established to the hidden service, and then we complete the circuit using
    214   *  the hs_circuit_setup_e2e_rend_circ() function. We then check that the
    215   *  end-to-end cpath was setup correctly and that the stream was attached to
    216   *  the circuit as expected. */
    217 
    218  MOCK(connection_ap_handshake_send_begin,
    219       mock_connection_ap_handshake_send_begin);
    220 
    221  /* Setup */
    222  retval = helper_get_circ_and_stream_for_test(&or_circ, &conn);
    223  tt_int_op(retval, OP_EQ, 0);
    224  tt_assert(or_circ);
    225  tt_assert(conn);
    226 
    227  /* Check number of hops: There should be no hops yet to this circ */
    228  retval = cpath_get_n_hops(&or_circ->cpath);
    229  tt_int_op(retval, OP_EQ, 0);
    230  tt_ptr_op(or_circ->cpath, OP_EQ, NULL);
    231 
    232  /* Check that our stream is not attached on any circuits */
    233  tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, NULL);
    234 
    235  /**********************************************/
    236 
    237  /* Setup the circuit */
    238  retval = hs_circuit_setup_e2e_rend_circ(or_circ, ntor_key_seed,
    239                                          sizeof(ntor_key_seed), 0);
    240  tt_int_op(retval, OP_EQ, 0);
    241 
    242  /**********************************************/
    243 
    244  /* See that a hop was added to the circuit's cpath */
    245  retval = cpath_get_n_hops(&or_circ->cpath);
    246  tt_int_op(retval, OP_EQ, 1);
    247 
    248  /* Check that the crypt path has prop224 algorithm parameters */
    249  tt_int_op(crypto_digest_get_algorithm(
    250                             or_circ->cpath->pvt_crypto.c.tor1.f_digest),
    251            OP_EQ, DIGEST_SHA3_256);
    252  tt_int_op(crypto_digest_get_algorithm(
    253                             or_circ->cpath->pvt_crypto.c.tor1.b_digest),
    254            OP_EQ, DIGEST_SHA3_256);
    255  tt_assert(or_circ->cpath->pvt_crypto.c.tor1.f_crypto);
    256  tt_assert(or_circ->cpath->pvt_crypto.c.tor1.b_crypto);
    257 
    258  /* Ensure that circ purpose was changed */
    259  tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
    260 
    261  /* Test that stream got attached */
    262  tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ));
    263 
    264 done:
    265  connection_free_minimal(conn);
    266  if (or_circ)
    267    tor_free(TO_CIRCUIT(or_circ)->n_chan);
    268  circuit_free_(TO_CIRCUIT(or_circ));
    269 }
    270 
    271 /** Test client logic for picking intro points from a descriptor. Also test how
    272 *  ExcludeNodes and intro point failures affect picking intro points. */
    273 static void
    274 test_client_pick_intro(void *arg)
    275 {
    276  int ret;
    277  ed25519_keypair_t service_kp;
    278  hs_descriptor_t *desc = NULL;
    279 
    280  MOCK(networkstatus_get_reasonably_live_consensus,
    281       mock_networkstatus_get_reasonably_live_consensus);
    282 
    283  (void) arg;
    284 
    285  hs_init();
    286 
    287  /* Generate service keypair */
    288  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
    289 
    290  /* Set time */
    291  ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
    292                           &mock_ns.valid_after);
    293  tt_int_op(ret, OP_EQ, 0);
    294  ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
    295                           &mock_ns.fresh_until);
    296  tt_int_op(ret, OP_EQ, 0);
    297 
    298  update_approx_time(mock_ns.fresh_until-10);
    299  time_t now = approx_time();
    300 
    301  /* Test logic:
    302   *
    303   * 1) Add our desc with intro points to the HS cache.
    304   *
    305   * 2) Mark all descriptor intro points except _the chosen one_ as
    306   *    failed. Then query the desc to get a random intro: check that we got
    307   *    _the chosen one_. Then fail the chosen one as well, and see that no
    308   *    intros are returned.
    309   *
    310   * 3) Then clean the intro state cache and get an intro point.
    311   *
    312   * 4) Try fetching an intro with the wrong service key: shouldn't work
    313   *
    314   * 5) Set StrictNodes and put all our intro points in ExcludeNodes: see that
    315   *    nothing is returned.
    316   */
    317 
    318  /* 1) Add desc to HS cache */
    319  {
    320    char *encoded = NULL;
    321    desc = hs_helper_build_hs_desc_with_ip(&service_kp);
    322    ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &encoded);
    323    tt_int_op(ret, OP_EQ, 0);
    324    tt_assert(encoded);
    325 
    326    /* store it */
    327    ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
    328    tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
    329 
    330    /* fetch it to make sure it works */
    331    const hs_descriptor_t *fetched_desc =
    332      hs_cache_lookup_as_client(&service_kp.pubkey);
    333    tt_assert(fetched_desc);
    334    tt_mem_op(fetched_desc->subcredential.subcred,
    335              OP_EQ, desc->subcredential.subcred,
    336              SUBCRED_LEN);
    337    tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential.subcred,
    338                               DIGEST256_LEN));
    339    tor_free(encoded);
    340  }
    341 
    342  /* 2) Mark all intro points except _the chosen one_ as failed. Then query the
    343   *   desc and get a random intro: check that we got _the chosen one_. */
    344  {
    345    /* Tell hs_get_extend_info_from_lspecs() to skip the private address check.
    346     */
    347    get_options_mutable()->ExtendAllowPrivateAddresses = 1;
    348    /* Pick the chosen intro point and get its ei */
    349    hs_desc_intro_point_t *chosen_intro_point =
    350      smartlist_get(desc->encrypted_data.intro_points, 0);
    351    extend_info_t *chosen_intro_ei =
    352      desc_intro_point_to_extend_info(chosen_intro_point);
    353    tt_assert(chosen_intro_point);
    354    tt_assert(chosen_intro_ei);
    355 
    356    /* Now mark all other intro points as failed */
    357    SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
    358                            hs_desc_intro_point_t *, ip) {
    359      /* Skip the chosen intro point */
    360      if (ip == chosen_intro_point) {
    361        continue;
    362      }
    363      ed25519_public_key_t *intro_auth_key = &ip->auth_key_cert->signed_key;
    364      hs_cache_client_intro_state_note(&service_kp.pubkey,
    365                                       intro_auth_key,
    366                                       INTRO_POINT_FAILURE_GENERIC);
    367    } SMARTLIST_FOREACH_END(ip);
    368 
    369    /* Try to get a random intro: Should return the chosen one! */
    370    /* (We try several times, to make sure this behavior is consistent, and to
    371     * cover the different cases of client_get_random_intro().) */
    372    for (int i = 0; i < 64; ++i) {
    373      extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
    374      tor_assert(ip);
    375      tt_assert(!fast_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN));
    376      tt_mem_op(ip->identity_digest, OP_EQ, chosen_intro_ei->identity_digest,
    377                DIGEST_LEN);
    378      extend_info_free(ip);
    379    }
    380 
    381    extend_info_free(chosen_intro_ei);
    382 
    383    /* Now also mark the chosen one as failed: See that we can't get any intro
    384       points anymore. */
    385    hs_cache_client_intro_state_note(&service_kp.pubkey,
    386                                &chosen_intro_point->auth_key_cert->signed_key,
    387                                     INTRO_POINT_FAILURE_TIMEOUT);
    388    extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
    389    tor_assert(!ip);
    390  }
    391 
    392  /* 3) Clean the intro state cache and get an intro point */
    393  {
    394    /* Pretend we are 5 mins in the future and order a cleanup of the intro
    395     * state. This should clean up the intro point failures and allow us to get
    396     * an intro. */
    397    hs_cache_client_intro_state_clean(now + 5*60);
    398 
    399    /* Get an intro. It should work! */
    400    extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
    401    tor_assert(ip);
    402    extend_info_free(ip);
    403  }
    404 
    405  /* 4) Try fetching an intro with the wrong service key: shouldn't work */
    406  {
    407    ed25519_keypair_t dummy_kp;
    408    tt_int_op(0, OP_EQ, ed25519_keypair_generate(&dummy_kp, 0));
    409    extend_info_t *ip = client_get_random_intro(&dummy_kp.pubkey);
    410    tor_assert(!ip);
    411  }
    412 
    413  /* 5) Set StrictNodes and put all our intro points in ExcludeNodes: see that
    414   *    nothing is returned. */
    415  {
    416    get_options_mutable()->ExcludeNodes = routerset_new();
    417    get_options_mutable()->StrictNodes = 1;
    418    SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
    419                            hs_desc_intro_point_t *, ip) {
    420      extend_info_t *intro_ei = desc_intro_point_to_extend_info(ip);
    421      /* desc_intro_point_to_extend_info() doesn't return IPv6 intro points
    422       * yet, because we can't extend to them. See #24404, #24451, and #24181.
    423       */
    424      if (intro_ei == NULL) {
    425        /* Pretend we're making a direct connection, and that we can use IPv6
    426         */
    427        get_options_mutable()->ClientUseIPv6 = 1;
    428        intro_ei = hs_get_extend_info_from_lspecs(ip->link_specifiers,
    429                                                  &ip->onion_key, 1);
    430        tt_assert(tor_addr_family(&intro_ei->orports[0].addr) == AF_INET6);
    431      }
    432      tt_assert(intro_ei);
    433      if (intro_ei) {
    434        const char *ptr;
    435        char ip_addr[TOR_ADDR_BUF_LEN];
    436        /* We need to decorate in case it is an IPv6 else routerset_parse()
    437         * doesn't like it. */
    438        ptr = tor_addr_to_str(ip_addr, &intro_ei->orports[0].addr,
    439                              sizeof(ip_addr), 1);
    440        tt_assert(ptr == ip_addr);
    441        ret = routerset_parse(get_options_mutable()->ExcludeNodes,
    442                              ip_addr, "");
    443        tt_int_op(ret, OP_EQ, 0);
    444        extend_info_free(intro_ei);
    445      }
    446    } SMARTLIST_FOREACH_END(ip);
    447 
    448    extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
    449    tt_assert(!ip);
    450  }
    451 
    452 done:
    453  hs_descriptor_free(desc);
    454 }
    455 
    456 static int
    457 mock_router_have_minimum_dir_info_false(void)
    458 {
    459  return 0;
    460 }
    461 static int
    462 mock_router_have_minimum_dir_info_true(void)
    463 {
    464  return 1;
    465 }
    466 
    467 static hs_client_fetch_status_t
    468 mock_fetch_v3_desc_error(const ed25519_public_key_t *key)
    469 {
    470  (void) key;
    471  return HS_CLIENT_FETCH_ERROR;
    472 }
    473 
    474 static void
    475 mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
    476                                    int line, const char *file)
    477 {
    478  (void) line;
    479  (void) file;
    480  conn->edge_.end_reason = endreason;
    481  /* This function ultimately will flag this so make sure we do also in the
    482   * MOCK one so we can assess closed connections vs open ones. */
    483  conn->edge_.base_.marked_for_close = 1;
    484 }
    485 
    486 static void
    487 mock_connection_mark_unattached_ap_no_close(entry_connection_t *conn,
    488                                            int endreason, int line,
    489                                            const char *file)
    490 {
    491  (void) conn;
    492  (void) endreason;
    493  (void) line;
    494  (void) file;
    495 }
    496 
    497 static void
    498 test_descriptor_fetch(void *arg)
    499 {
    500  int ret;
    501  entry_connection_t *ec = NULL;
    502  ed25519_public_key_t service_pk;
    503  ed25519_secret_key_t service_sk;
    504 
    505  (void) arg;
    506 
    507  hs_init();
    508  memset(&service_sk, 'A', sizeof(service_sk));
    509  ret = ed25519_public_key_generate(&service_pk, &service_sk);
    510  tt_int_op(ret, OP_EQ, 0);
    511 
    512  /* Initialize this so get_voting_interval() doesn't freak out. */
    513  ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
    514                           &mock_ns.valid_after);
    515  tt_int_op(ret, OP_EQ, 0);
    516  ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
    517                           &mock_ns.fresh_until);
    518  tt_int_op(ret, OP_EQ, 0);
    519 
    520  ec = entry_connection_new(CONN_TYPE_AP, AF_INET);
    521  tt_assert(ec);
    522  ENTRY_TO_EDGE_CONN(ec)->hs_ident = hs_ident_edge_conn_new(&service_pk);
    523  tt_assert(ENTRY_TO_EDGE_CONN(ec)->hs_ident);
    524  TO_CONN(ENTRY_TO_EDGE_CONN(ec))->state = AP_CONN_STATE_RENDDESC_WAIT;
    525  smartlist_add(get_connection_array(), &ec->edge_.base_);
    526 
    527  /* 1. FetchHidServDescriptors is false so we shouldn't be able to fetch. */
    528  get_options_mutable()->FetchHidServDescriptors = 0;
    529  ret = hs_client_refetch_hsdesc(&service_pk);
    530  tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_NOT_ALLOWED);
    531  get_options_mutable()->FetchHidServDescriptors = 1;
    532 
    533  /* 2. We don't have a live consensus. */
    534  MOCK(networkstatus_get_reasonably_live_consensus,
    535       mock_networkstatus_get_reasonably_live_consensus_false);
    536  ret = hs_client_refetch_hsdesc(&service_pk);
    537  UNMOCK(networkstatus_get_reasonably_live_consensus);
    538  tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_MISSING_INFO);
    539 
    540  /* From now on, return a live consensus. */
    541  MOCK(networkstatus_get_reasonably_live_consensus,
    542       mock_networkstatus_get_reasonably_live_consensus);
    543 
    544  /* 3. Not enough dir information. */
    545  MOCK(router_have_minimum_dir_info,
    546       mock_router_have_minimum_dir_info_false);
    547  ret = hs_client_refetch_hsdesc(&service_pk);
    548  UNMOCK(router_have_minimum_dir_info);
    549  tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_MISSING_INFO);
    550 
    551  /* From now on, we do have enough directory information. */
    552  MOCK(router_have_minimum_dir_info,
    553       mock_router_have_minimum_dir_info_true);
    554 
    555  /* 4. We do have a pending directory request. */
    556  {
    557    dir_connection_t *dir_conn = dir_connection_new(AF_INET);
    558    dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
    559    TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC;
    560    ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_pk);
    561    smartlist_add(get_connection_array(), TO_CONN(dir_conn));
    562    ret = hs_client_refetch_hsdesc(&service_pk);
    563    smartlist_remove(get_connection_array(), TO_CONN(dir_conn));
    564    connection_free_minimal(TO_CONN(dir_conn));
    565    tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_PENDING);
    566  }
    567 
    568  /* 5. We'll trigger an error on the fetch_desc_v3 and force to close all
    569   *    pending SOCKS request. */
    570  MOCK(router_have_minimum_dir_info,
    571       mock_router_have_minimum_dir_info_true);
    572  MOCK(fetch_v3_desc, mock_fetch_v3_desc_error);
    573  MOCK(connection_mark_unattached_ap_,
    574       mock_connection_mark_unattached_ap_);
    575  ret = hs_client_refetch_hsdesc(&service_pk);
    576  UNMOCK(fetch_v3_desc);
    577  UNMOCK(connection_mark_unattached_ap_);
    578  tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_ERROR);
    579  /* The close waiting for descriptor function has been called. */
    580  tt_int_op(ec->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
    581 
    582 done:
    583  connection_free_minimal(ENTRY_TO_CONN(ec));
    584  UNMOCK(networkstatus_get_reasonably_live_consensus);
    585  UNMOCK(router_have_minimum_dir_info);
    586  hs_free_all();
    587 }
    588 
    589 static void
    590 test_auth_key_filename_is_valid(void *arg)
    591 {
    592  (void) arg;
    593 
    594  /* Valid file name. */
    595  tt_assert(auth_key_filename_is_valid("a.auth_private"));
    596  /* Valid file name with special character. */
    597  tt_assert(auth_key_filename_is_valid("a-.auth_private"));
    598  /* Invalid extension. */
    599  tt_assert(!auth_key_filename_is_valid("a.ath_private"));
    600  /* Nothing before the extension. */
    601  tt_assert(!auth_key_filename_is_valid(".auth_private"));
    602 
    603 done:
    604  ;
    605 }
    606 
    607 static void
    608 test_parse_auth_file_content(void *arg)
    609 {
    610  hs_client_service_authorization_t *auth = NULL;
    611 
    612  (void) arg;
    613 
    614  /* Valid authorized client. */
    615  auth = parse_auth_file_content(
    616      "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:descriptor:"
    617      "x25519:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq");
    618  tt_assert(auth);
    619 
    620  /* Wrong number of fields. */
    621  tt_assert(!parse_auth_file_content("a:b"));
    622  /* Wrong auth type. */
    623  tt_assert(!parse_auth_file_content(
    624      "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:x:"
    625      "x25519:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq"));
    626  /* Wrong key type. */
    627  tt_assert(!parse_auth_file_content(
    628      "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:descriptor:"
    629      "x:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq"));
    630  /* Some malformed string. */
    631  tt_assert(!parse_auth_file_content("xx:descriptor:x25519:aa=="));
    632  /* Bigger key than it should be */
    633  tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
    634                     "vjqea4jbhwwc4hto7ekyvqfbeodghbaq6nxi45hz4wr3qvhqv3yqa"));
    635  /* All-zeroes key */
    636  tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
    637            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
    638 
    639 done:
    640  tor_free(auth);
    641 }
    642 
    643 static char *
    644 mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out)
    645 {
    646  char *ret = NULL;
    647 
    648  (void) flags;
    649  (void) stat_out;
    650 
    651  if (!strcmp(filename, get_fname("auth_keys" PATH_SEPARATOR
    652                                              "client1.auth_private"))) {
    653    ret = tor_strdup(
    654        "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:descriptor:"
    655        "x25519:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq");
    656    goto done;
    657  }
    658 
    659  if (!strcmp(filename, get_fname("auth_keys" PATH_SEPARATOR "dummy.xxx"))) {
    660    ret = tor_strdup(
    661        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:descriptor:"
    662        "x25519:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    663    goto done;
    664  }
    665 
    666  if (!strcmp(filename, get_fname("auth_keys" PATH_SEPARATOR
    667                                              "client2.auth_private"))) {
    668    ret = tor_strdup(
    669        "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid:descriptor:"
    670        "x25519:fdreqzjqso7d2ac7qscrxfl5qfpamdvgy5d6cxejcgzc3hvhurmq");
    671    goto done;
    672  }
    673 
    674 done:
    675  return ret;
    676 }
    677 
    678 static int
    679 mock_check_private_dir(const char *dirname, cpd_check_t check,
    680                       const char *effective_user)
    681 {
    682  (void) dirname;
    683  (void) check;
    684  (void) effective_user;
    685 
    686  return 0;
    687 }
    688 
    689 static smartlist_t *
    690 mock_tor_listdir(const char *dirname)
    691 {
    692  smartlist_t *file_list = smartlist_new();
    693 
    694  (void) dirname;
    695 
    696  smartlist_add(file_list, tor_strdup("client1.auth_private"));
    697  smartlist_add(file_list, tor_strdup("dummy.xxx"));
    698  smartlist_add(file_list, tor_strdup("client2.auth_private"));
    699 
    700  return file_list;
    701 }
    702 
    703 static void
    704 test_config_client_authorization(void *arg)
    705 {
    706  int ret;
    707  char *conf = NULL;
    708  ed25519_public_key_t pk1, pk2;
    709  digest256map_t *global_map = NULL;
    710  char *key_dir = tor_strdup(get_fname("auth_keys"));
    711 
    712  (void) arg;
    713 
    714  MOCK(read_file_to_str, mock_read_file_to_str);
    715  MOCK(tor_listdir, mock_tor_listdir);
    716  MOCK(check_private_dir, mock_check_private_dir);
    717 
    718 #define conf_fmt \
    719  "ClientOnionAuthDir %s\n"
    720 
    721  tor_asprintf(&conf, conf_fmt, key_dir);
    722  ret = helper_config_client(conf, 0);
    723  tor_free(conf);
    724  tt_int_op(ret, OP_EQ, 0);
    725 
    726 #undef conf_fmt
    727 
    728  global_map = get_hs_client_auths_map();
    729  tt_int_op(digest256map_size(global_map), OP_EQ, 2);
    730 
    731  hs_parse_address("4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad",
    732                   &pk1, NULL, NULL);
    733  hs_parse_address("25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid",
    734                   &pk2, NULL, NULL);
    735 
    736  tt_assert(digest256map_get(global_map, pk1.pubkey));
    737  tt_assert(digest256map_get(global_map, pk2.pubkey));
    738 
    739 done:
    740  tor_free(key_dir);
    741  hs_free_all();
    742  UNMOCK(read_file_to_str);
    743  UNMOCK(tor_listdir);
    744  UNMOCK(check_private_dir);
    745 }
    746 
    747 static entry_connection_t *
    748 helper_build_socks_connection(const ed25519_public_key_t *service_pk,
    749                              int conn_state)
    750 {
    751  entry_connection_t *socks = entry_connection_new(CONN_TYPE_AP, AF_INET);
    752  ENTRY_TO_EDGE_CONN(socks)->hs_ident = hs_ident_edge_conn_new(service_pk);
    753  TO_CONN(ENTRY_TO_EDGE_CONN(socks))->state = conn_state;
    754  smartlist_add(get_connection_array(), &socks->edge_.base_);
    755  return socks;
    756 }
    757 
    758 static void
    759 test_desc_has_arrived_cleanup(void *arg)
    760 {
    761  /* The goal of this test is to make sure we clean up everything in between
    762   * two descriptors from the same .onion. Because intro points can change
    763   * from one descriptor to another, once we received a new descriptor, we
    764   * need to cleanup the remaining circuits so they aren't used or selected
    765   * when establishing a connection with the newly stored descriptor.
    766   *
    767   * This test was created because of #27410. */
    768 
    769  int ret;
    770  char *desc_str = NULL;
    771  hs_descriptor_t *desc = NULL;
    772  const hs_descriptor_t *cached_desc;
    773  ed25519_keypair_t signing_kp;
    774  entry_connection_t *socks1 = NULL, *socks2 = NULL;
    775  hs_ident_dir_conn_t hs_dir_ident;
    776  dir_connection_t *dir_conn = NULL;
    777 
    778  (void) arg;
    779 
    780  hs_init();
    781  congestion_control_set_cc_enabled();
    782 
    783  MOCK(networkstatus_get_reasonably_live_consensus,
    784       mock_networkstatus_get_reasonably_live_consensus);
    785  MOCK(connection_mark_unattached_ap_,
    786       mock_connection_mark_unattached_ap_);
    787  MOCK(router_have_minimum_dir_info,
    788       mock_router_have_minimum_dir_info_true);
    789 
    790  /* Set consensus time before our time so the cache lookup can always
    791   * validate that the entry is not expired. */
    792  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", &mock_ns.valid_after);
    793  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", &mock_ns.fresh_until);
    794  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", &mock_ns.valid_until);
    795 
    796  /* Build a descriptor for a specific .onion. */
    797  ret = ed25519_keypair_generate(&signing_kp, 0);
    798  tt_int_op(ret, OP_EQ, 0);
    799  desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
    800  tt_assert(desc);
    801  ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &desc_str);
    802  tt_int_op(ret, OP_EQ, 0);
    803 
    804  /* Store in the client cache. */
    805  ret = hs_cache_store_as_client(desc_str, &signing_kp.pubkey);
    806  tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
    807  cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
    808  tt_assert(cached_desc);
    809  hs_helper_desc_equal(desc, cached_desc);
    810 
    811  /* Create two SOCKS connection for the same .onion both in the waiting for a
    812   * descriptor state. */
    813  socks1 = helper_build_socks_connection(&signing_kp.pubkey,
    814                                         AP_CONN_STATE_RENDDESC_WAIT);
    815  tt_assert(socks1);
    816  socks2 = helper_build_socks_connection(&signing_kp.pubkey,
    817                                         AP_CONN_STATE_RENDDESC_WAIT);
    818  tt_assert(socks2);
    819 
    820  /* Now, we'll make the intro points in the current descriptor unusable so
    821   * the hs_client_desc_has_arrived() will take the right code path that we
    822   * want to test that is the fetched descriptor has bad intro points. */
    823  SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
    824                        hs_desc_intro_point_t *, ip) {
    825    hs_cache_client_intro_state_note(&signing_kp.pubkey,
    826                                     &ip->auth_key_cert->signed_key,
    827                                     INTRO_POINT_FAILURE_GENERIC);
    828  } SMARTLIST_FOREACH_END(ip);
    829 
    830  /* Simulate that a new descriptor just arrived. We should have both of our
    831   * SOCKS connection to be ended with a resolved failed. */
    832  hs_ident_dir_conn_init(&signing_kp.pubkey,
    833                         &desc->plaintext_data.blinded_pubkey, &hs_dir_ident);
    834  dir_conn = dir_connection_new(AF_INET);
    835  dir_conn->hs_ident = hs_ident_dir_conn_dup(&hs_dir_ident);
    836  hs_client_dir_fetch_done(dir_conn, "A reason", desc_str, 200);
    837  connection_free_minimal(TO_CONN(dir_conn));
    838  tt_int_op(socks1->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
    839  tt_int_op(socks2->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
    840 
    841  /* Now let say tor cleans up the intro state cache which resets all intro
    842   * point failure count. */
    843  hs_cache_client_intro_state_purge();
    844 
    845  /* Retrying all SOCKS which should basically do nothing since we don't have
    846   * any pending SOCKS connection in AP_CONN_STATE_RENDDESC_WAIT state. */
    847  retry_all_socks_conn_waiting_for_desc();
    848 
    849 done:
    850  connection_free_minimal(ENTRY_TO_CONN(socks1));
    851  connection_free_minimal(ENTRY_TO_CONN(socks2));
    852  hs_descriptor_free(desc);
    853  tor_free(desc_str);
    854  hs_free_all();
    855 
    856  UNMOCK(networkstatus_get_reasonably_live_consensus);
    857  UNMOCK(connection_mark_unattached_ap_);
    858  UNMOCK(router_have_minimum_dir_info);
    859 }
    860 
    861 static void
    862 test_close_intro_circuits_new_desc(void *arg)
    863 {
    864  int ret;
    865  ed25519_keypair_t service_kp;
    866  circuit_t *circ = NULL;
    867  origin_circuit_t *ocirc = NULL;
    868  hs_descriptor_t *desc1 = NULL, *desc2 = NULL;
    869 
    870  (void) arg;
    871 
    872  hs_init();
    873 
    874  /* This is needed because of the client cache expiration timestamp is based
    875   * on having a consensus. See cached_client_descriptor_has_expired(). */
    876  MOCK(networkstatus_get_reasonably_live_consensus,
    877       mock_networkstatus_get_reasonably_live_consensus);
    878 
    879  /* Set consensus time */
    880  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
    881                           &mock_ns.valid_after);
    882  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
    883                           &mock_ns.fresh_until);
    884  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
    885                           &mock_ns.valid_until);
    886 
    887  /* Generate service keypair */
    888  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
    889 
    890  /* Create and add to the global list a dummy client introduction circuits.
    891   * We'll then make sure the hs_ident is attached to a dummy descriptor. */
    892  circ = dummy_origin_circuit_new(0);
    893  tt_assert(circ);
    894  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
    895  ocirc = TO_ORIGIN_CIRCUIT(circ);
    896 
    897  /* Build a descriptor _without_ client authorization and thus not
    898   * decryptable. Make sure the close circuit code path is not triggered. */
    899  {
    900    char *desc_encoded = NULL;
    901    uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
    902    curve25519_keypair_t client_kp;
    903    hs_descriptor_t *desc = NULL;
    904 
    905    tt_int_op(0, OP_EQ, curve25519_keypair_generate(&client_kp, 0));
    906    crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
    907 
    908    desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie,
    909                                                    &client_kp.pubkey,
    910                                                    &service_kp);
    911    tt_assert(desc);
    912    ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
    913                                    &desc_encoded);
    914    tt_int_op(ret, OP_EQ, 0);
    915    /* Associate descriptor intro key with the dummy circuit. */
    916    const hs_desc_intro_point_t *ip =
    917      smartlist_get(desc->encrypted_data.intro_points, 0);
    918    tt_assert(ip);
    919    ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
    920    ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
    921                        &ip->auth_key_cert->signed_key);
    922    hs_descriptor_free(desc);
    923    tt_assert(desc_encoded);
    924    /* Put it in the cache. Should not be decrypted since the client
    925     * authorization creds were not added to the global map. */
    926    ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey);
    927    tor_free(desc_encoded);
    928    tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
    929 
    930    /* Clean cache with a future timestamp. It will trigger the clean up and
    931     * attempt to close the circuit but only if the descriptor is decryptable.
    932     * Cache object should be removed and circuit untouched. */
    933    hs_cache_clean_as_client(mock_ns.valid_after + (60 * 60 * 24));
    934    tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey));
    935 
    936    /* Make sure the circuit still there. */
    937    tt_assert(circuit_get_next_intro_circ(NULL, true));
    938    /* Get rid of the ident, it will be replaced in the next tests. */
    939    hs_ident_circuit_free(ocirc->hs_ident);
    940  }
    941 
    942  /* Build the first descriptor and cache it. */
    943  {
    944    char *encoded;
    945    desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
    946    tt_assert(desc1);
    947    ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
    948    tt_int_op(ret, OP_EQ, 0);
    949    tt_assert(encoded);
    950 
    951    /* Store it */
    952    ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
    953    tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
    954    tor_free(encoded);
    955    tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
    956  }
    957 
    958  /* We'll pick one introduction point and associate it with the circuit. */
    959  {
    960    const hs_desc_intro_point_t *ip =
    961      smartlist_get(desc1->encrypted_data.intro_points, 0);
    962    tt_assert(ip);
    963    ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
    964    ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
    965                        &ip->auth_key_cert->signed_key);
    966  }
    967 
    968  /* Before we are about to clean up the intro circuits, make sure it is
    969   * actually there. */
    970  tt_assert(circuit_get_next_intro_circ(NULL, true));
    971 
    972  /* Build the second descriptor for the same service and cache it. */
    973  {
    974    char *encoded;
    975    desc2 = hs_helper_build_hs_desc_with_ip(&service_kp);
    976    tt_assert(desc2);
    977    tt_mem_op(&desc1->plaintext_data.signing_pubkey, OP_EQ,
    978              &desc2->plaintext_data.signing_pubkey, ED25519_PUBKEY_LEN);
    979    /* To replace the existing descriptor, the revision counter needs to be
    980     * bigger. */
    981    desc2->plaintext_data.revision_counter =
    982      desc1->plaintext_data.revision_counter + 1;
    983 
    984    ret = hs_desc_encode_descriptor(desc2, &service_kp, NULL, &encoded);
    985    tt_int_op(ret, OP_EQ, 0);
    986    tt_assert(encoded);
    987 
    988    ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
    989    tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
    990    tor_free(encoded);
    991    tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
    992  }
    993 
    994  /* Once stored, our intro circuit should be closed because it is related to
    995   * an old introduction point that doesn't exists anymore. */
    996  tt_assert(!circuit_get_next_intro_circ(NULL, true));
    997 
    998 done:
    999  circuit_free(circ);
   1000  hs_descriptor_free(desc1);
   1001  hs_descriptor_free(desc2);
   1002  hs_free_all();
   1003  UNMOCK(networkstatus_get_reasonably_live_consensus);
   1004 }
   1005 
   1006 static void
   1007 test_close_intro_circuits_cache_clean(void *arg)
   1008 {
   1009  int ret;
   1010  ed25519_keypair_t service_kp;
   1011  circuit_t *circ = NULL;
   1012  origin_circuit_t *ocirc = NULL;
   1013  hs_descriptor_t *desc1 = NULL;
   1014 
   1015  (void) arg;
   1016 
   1017  hs_init();
   1018 
   1019  /* This is needed because of the client cache expiration timestamp is based
   1020   * on having a consensus. See cached_client_descriptor_has_expired(). */
   1021  MOCK(networkstatus_get_reasonably_live_consensus,
   1022       mock_networkstatus_get_reasonably_live_consensus);
   1023 
   1024  /* Set consensus time */
   1025  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
   1026                     &mock_ns.valid_after);
   1027  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
   1028                     &mock_ns.fresh_until);
   1029  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
   1030                     &mock_ns.valid_until);
   1031 
   1032  /* Generate service keypair */
   1033  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
   1034 
   1035  /* Create and add to the global list a dummy client introduction circuits.
   1036   * We'll then make sure the hs_ident is attached to a dummy descriptor. */
   1037  circ = dummy_origin_circuit_new(0);
   1038  tt_assert(circ);
   1039  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
   1040  ocirc = TO_ORIGIN_CIRCUIT(circ);
   1041 
   1042  /* Build the first descriptor and cache it. */
   1043  {
   1044    char *encoded;
   1045    desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
   1046    tt_assert(desc1);
   1047    ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
   1048    tt_int_op(ret, OP_EQ, 0);
   1049    tt_assert(encoded);
   1050 
   1051    /* Store it */
   1052    ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
   1053    tt_int_op(ret, OP_EQ, 0);
   1054    tor_free(encoded);
   1055    tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
   1056  }
   1057 
   1058  /* We'll pick one introduction point and associate it with the circuit. */
   1059  {
   1060    const hs_desc_intro_point_t *ip =
   1061      smartlist_get(desc1->encrypted_data.intro_points, 0);
   1062    tt_assert(ip);
   1063    ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
   1064    ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
   1065                        &ip->auth_key_cert->signed_key);
   1066  }
   1067 
   1068  /* Before we are about to clean up the intro circuits, make sure it is
   1069   * actually there. */
   1070  tt_assert(circuit_get_next_intro_circ(NULL, true));
   1071 
   1072  /* Cleanup the client cache. The ns valid after time is what decides if the
   1073   * descriptor has expired so put it in the future enough (72h) so we are
   1074   * sure to always expire. */
   1075  mock_ns.valid_after = approx_time() + (72 * 24 * 60 * 60);
   1076  hs_cache_clean_as_client(0);
   1077 
   1078  /* Once stored, our intro circuit should be closed because it is related to
   1079   * an old introduction point that doesn't exists anymore. */
   1080  tt_assert(!circuit_get_next_intro_circ(NULL, true));
   1081 
   1082 done:
   1083  circuit_free(circ);
   1084  hs_descriptor_free(desc1);
   1085  hs_free_all();
   1086  UNMOCK(networkstatus_get_reasonably_live_consensus);
   1087 }
   1088 
   1089 static void
   1090 test_socks_hs_errors(void *arg)
   1091 {
   1092  int ret;
   1093  char digest[DIGEST_LEN];
   1094  char *desc_encoded = NULL;
   1095  circuit_t *circ = NULL;
   1096  origin_circuit_t *ocirc = NULL;
   1097  tor_addr_t addr = TOR_ADDR_NULL;
   1098  ed25519_keypair_t service_kp;
   1099  ed25519_keypair_t signing_kp;
   1100  entry_connection_t *socks_conn = NULL;
   1101  dir_connection_t *dir_conn = NULL;
   1102  hs_descriptor_t *desc = NULL;
   1103  uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
   1104 
   1105  (void) arg;
   1106 
   1107  MOCK(networkstatus_get_reasonably_live_consensus,
   1108       mock_networkstatus_get_reasonably_live_consensus);
   1109  MOCK(connection_mark_unattached_ap_,
   1110       mock_connection_mark_unattached_ap_no_close);
   1111  MOCK(read_file_to_str, mock_read_file_to_str);
   1112  MOCK(tor_listdir, mock_tor_listdir);
   1113  MOCK(check_private_dir, mock_check_private_dir);
   1114 
   1115    /* Set consensus time */
   1116  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
   1117                           &mock_ns.valid_after);
   1118  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
   1119                           &mock_ns.fresh_until);
   1120  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
   1121                           &mock_ns.valid_until);
   1122 
   1123  hs_init();
   1124 
   1125  ret = ed25519_keypair_generate(&service_kp, 0);
   1126  tt_int_op(ret, OP_EQ, 0);
   1127  ret = ed25519_keypair_generate(&signing_kp, 0);
   1128  tt_int_op(ret, OP_EQ, 0);
   1129 
   1130  socks_conn = helper_build_socks_connection(&service_kp.pubkey,
   1131                                             AP_CONN_STATE_RENDDESC_WAIT);
   1132  tt_assert(socks_conn);
   1133 
   1134  /* Create directory connection. */
   1135  dir_conn = dir_connection_new(AF_INET);
   1136  dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
   1137  TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC;
   1138  ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_kp.pubkey);
   1139 
   1140  /* Encode descriptor so we can decode it. */
   1141  desc = hs_helper_build_hs_desc_with_ip(&service_kp);
   1142  tt_assert(desc);
   1143 
   1144  /* Before testing the client authentication error code, encode the
   1145   * descriptor with no client auth. */
   1146  ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &desc_encoded);
   1147  tt_int_op(ret, OP_EQ, 0);
   1148  tt_assert(desc_encoded);
   1149 
   1150  /*
   1151   * Test the introduction failure codes (X'F2' and X'F7')
   1152   */
   1153 
   1154  /* First, we have to put all the IPs in the failure cache. */
   1155  SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
   1156                          hs_desc_intro_point_t *, ip) {
   1157    hs_cache_client_intro_state_note(&service_kp.pubkey,
   1158                                     &ip->auth_key_cert->signed_key,
   1159                                     INTRO_POINT_FAILURE_GENERIC);
   1160  } SMARTLIST_FOREACH_END(ip);
   1161 
   1162  hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
   1163  tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
   1164            SOCKS5_HS_INTRO_FAILED);
   1165 
   1166  /* Purge client cache of the descriptor so we can go again. */
   1167  hs_cache_purge_as_client();
   1168 
   1169  /* Second, set all failures to be time outs. */
   1170  SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
   1171                          hs_desc_intro_point_t *, ip) {
   1172    hs_cache_client_intro_state_note(&service_kp.pubkey,
   1173                                     &ip->auth_key_cert->signed_key,
   1174                                     INTRO_POINT_FAILURE_TIMEOUT);
   1175  } SMARTLIST_FOREACH_END(ip);
   1176 
   1177  hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
   1178  tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
   1179            SOCKS5_HS_INTRO_TIMEDOUT);
   1180 
   1181  /* Purge client cache of the descriptor so we can go again. */
   1182  hs_cache_purge_as_client();
   1183 
   1184  /*
   1185   * Test the rendezvous failure codes (X'F3')
   1186   */
   1187 
   1188  circ = dummy_origin_circuit_new(0);
   1189  tt_assert(circ);
   1190  circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
   1191  ocirc = TO_ORIGIN_CIRCUIT(circ);
   1192  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
   1193  ocirc->hs_ident->intro_auth_pk.pubkey[0] = 42;
   1194  ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
   1195  /* Code path will log this exit so build it. */
   1196  ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
   1197                                                    NULL, NULL, &addr,
   1198                                                    4242, NULL, false);
   1199  /* Attach socks connection to this rendezvous circuit. */
   1200  ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn);
   1201  /* Trigger the rendezvous failure. Timeout the circuit and free. */
   1202  circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
   1203 
   1204  tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
   1205            SOCKS5_HS_REND_FAILED);
   1206 
   1207  /*
   1208   * Test client authorization codes.
   1209   */
   1210 
   1211  tor_free(desc_encoded);
   1212  crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
   1213  ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
   1214                                  &desc_encoded);
   1215  tt_int_op(ret, OP_EQ, 0);
   1216  tt_assert(desc_encoded);
   1217 
   1218  /* Try decoding. Point this to an existing descriptor. The following should
   1219   * fail thus the desc_out should be set to NULL. */
   1220  hs_descriptor_t *desc_out = desc;
   1221  ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
   1222                                    &desc_out);
   1223  tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
   1224  tt_assert(desc_out == NULL);
   1225 
   1226  /* The caching will fail to decrypt because the descriptor_cookie used above
   1227   * is not known to the HS subsystem. This will lead to a missing client
   1228   * auth. */
   1229  hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
   1230 
   1231  tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
   1232            SOCKS5_HS_MISSING_CLIENT_AUTH);
   1233 
   1234  /* Add in the global client auth list bad creds for this service. */
   1235  helper_add_random_client_auth(&service_kp.pubkey);
   1236 
   1237  ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
   1238                                    &desc_out);
   1239  tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
   1240  tt_assert(desc_out == NULL);
   1241 
   1242  /* Simmulate a fetch done again. This should replace the cached descriptor
   1243   * and signal a bad client authorization. */
   1244  hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
   1245  tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
   1246            SOCKS5_HS_BAD_CLIENT_AUTH);
   1247 
   1248 done:
   1249  connection_free_minimal(ENTRY_TO_CONN(socks_conn));
   1250  connection_free_minimal(TO_CONN(dir_conn));
   1251  hs_descriptor_free(desc);
   1252  tor_free(desc_encoded);
   1253  circuit_free(circ);
   1254 
   1255  hs_free_all();
   1256 
   1257  UNMOCK(networkstatus_get_reasonably_live_consensus);
   1258  UNMOCK(connection_mark_unattached_ap_);
   1259  UNMOCK(read_file_to_str);
   1260  UNMOCK(tor_listdir);
   1261  UNMOCK(check_private_dir);
   1262 }
   1263 
   1264 static void
   1265 test_close_intro_circuit_failure(void *arg)
   1266 {
   1267  char digest[DIGEST_LEN];
   1268  circuit_t *circ = NULL;
   1269  ed25519_keypair_t service_kp, intro_kp;
   1270  origin_circuit_t *ocirc = NULL;
   1271  tor_addr_t addr = TOR_ADDR_NULL;
   1272  const hs_cache_intro_state_t *entry;
   1273 
   1274  (void) arg;
   1275 
   1276  hs_init();
   1277 
   1278  /* Generate service keypair */
   1279  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
   1280  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&intro_kp, 0));
   1281 
   1282  /* Create and add to the global list a dummy client introduction circuit at
   1283   * the ACK WAIT state. */
   1284  circ = dummy_origin_circuit_new(0);
   1285  tt_assert(circ);
   1286  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
   1287  ocirc = TO_ORIGIN_CIRCUIT(circ);
   1288  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
   1289  ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
   1290  /* Code path will log this exit so build it. */
   1291  ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
   1292                                                    NULL, NULL, &addr,
   1293                                                    4242, NULL, false);
   1294  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
   1295 
   1296  /* We'll make for close the circuit for a timeout failure. It should _NOT_
   1297   * end up in the failure cache just yet. We do that on free() only. */
   1298  circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
   1299  tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
   1300                                              &intro_kp.pubkey));
   1301  /* Time to free. It should get removed. */
   1302  circuit_free(circ);
   1303  entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
   1304                                           &intro_kp.pubkey);
   1305  tt_assert(entry);
   1306  tt_uint_op(entry->timed_out, OP_EQ, 1);
   1307  hs_cache_client_intro_state_purge();
   1308 
   1309  /* Again, create and add to the global list a dummy client introduction
   1310   * circuit at the INTRODUCING state. */
   1311  circ = dummy_origin_circuit_new(0);
   1312  tt_assert(circ);
   1313  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
   1314  ocirc = TO_ORIGIN_CIRCUIT(circ);
   1315  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
   1316  ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
   1317  /* Code path will log this exit so build it. */
   1318  ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
   1319                                                    NULL, NULL, &addr,
   1320                                                    4242, NULL, false);
   1321  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
   1322 
   1323  /* On free, we should get an unreachable failure. */
   1324  circuit_free(circ);
   1325  entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
   1326                                           &intro_kp.pubkey);
   1327  tt_assert(entry);
   1328  tt_uint_op(entry->unreachable_count, OP_EQ, 1);
   1329  hs_cache_client_intro_state_purge();
   1330 
   1331  /* Again, create and add to the global list a dummy client introduction
   1332   * circuit at the INTRODUCING state but we'll close it for timeout. It
   1333   * should not be noted as a timeout failure. */
   1334  circ = dummy_origin_circuit_new(0);
   1335  tt_assert(circ);
   1336  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
   1337  ocirc = TO_ORIGIN_CIRCUIT(circ);
   1338  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
   1339  ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
   1340  /* Code path will log this exit so build it. */
   1341  ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
   1342                                                    NULL, NULL, &addr,
   1343                                                    4242, NULL, false);
   1344  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
   1345 
   1346  circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
   1347  circuit_free(circ);
   1348  tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
   1349                                              &intro_kp.pubkey));
   1350 
   1351  /* Again, create and add to the global list a dummy client introduction
   1352   * circuit at the INTRODUCING state but without a chosen_exit. In theory, it
   1353   * can not happen but we'll make sure it doesn't end up in the failure cache
   1354   * anyway. */
   1355  circ = dummy_origin_circuit_new(0);
   1356  tt_assert(circ);
   1357  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
   1358  ocirc = TO_ORIGIN_CIRCUIT(circ);
   1359  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
   1360  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
   1361 
   1362  circuit_free(circ);
   1363  tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
   1364                                              &intro_kp.pubkey));
   1365 
   1366 done:
   1367  circuit_free(circ);
   1368  hs_free_all();
   1369 }
   1370 
   1371 static void
   1372 test_purge_ephemeral_client_auth(void *arg)
   1373 {
   1374  ed25519_keypair_t service_kp;
   1375  hs_client_service_authorization_t *auth = NULL;
   1376  hs_client_register_auth_status_t status;
   1377 
   1378  (void) arg;
   1379 
   1380  /* We will try to write on disk client credentials. */
   1381  MOCK(check_private_dir, mock_check_private_dir);
   1382  MOCK(get_options, mock_get_options);
   1383  MOCK(write_str_to_file, mock_write_str_to_file);
   1384 
   1385  /* Bogus directory so when we try to write the permanent client
   1386   * authorization data to disk, we don't fail. See
   1387   * store_permanent_client_auth_credentials() for more details. */
   1388  mocked_options.ClientOnionAuthDir = tor_strdup("auth_dir");
   1389 
   1390  hs_init();
   1391 
   1392  /* Generate service keypair */
   1393  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
   1394 
   1395  /* Generate a client authorization object. */
   1396  auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
   1397 
   1398  /* Set it up. No flags meaning it is ephemeral. */
   1399  curve25519_secret_key_generate(&auth->enc_seckey, 0);
   1400  hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
   1401  auth->flags = 0;
   1402 
   1403  /* Confirm that there is nothing in the client auth map. It is unallocated
   1404   * until we add the first entry. */
   1405  tt_assert(!get_hs_client_auths_map());
   1406 
   1407  /* Add an entry to the client auth list. We loose ownership of the auth
   1408   * object so nullify it. */
   1409  status = hs_client_register_auth_credentials(auth);
   1410  auth = NULL;
   1411  tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
   1412 
   1413  /* We should have the entry now. */
   1414  digest256map_t *client_auths = get_hs_client_auths_map();
   1415  tt_assert(client_auths);
   1416  tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
   1417 
   1418  /* Purge the cache that should remove all ephemeral values. */
   1419  purge_ephemeral_client_auth();
   1420  tt_int_op(digest256map_size(client_auths), OP_EQ, 0);
   1421 
   1422  /* Now add a new authorization object but permanent. */
   1423  /* Generate a client authorization object. */
   1424  auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
   1425  curve25519_secret_key_generate(&auth->enc_seckey, 0);
   1426  hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
   1427  auth->flags = CLIENT_AUTH_FLAG_IS_PERMANENT;
   1428 
   1429  /* Add an entry to the client auth list. We loose ownership of the auth
   1430   * object so nullify it. */
   1431  status = hs_client_register_auth_credentials(auth);
   1432  auth = NULL;
   1433  tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
   1434  tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
   1435 
   1436  /* Purge again, the entry should still be there. */
   1437  purge_ephemeral_client_auth();
   1438  tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
   1439 
   1440 done:
   1441  client_service_authorization_free(auth);
   1442  hs_free_all();
   1443  tor_free(mocked_options.ClientOnionAuthDir);
   1444 
   1445  UNMOCK(check_private_dir);
   1446  UNMOCK(get_options);
   1447  UNMOCK(write_str_to_file);
   1448 }
   1449 
   1450 struct testcase_t hs_client_tests[] = {
   1451  { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup,
   1452    TT_FORK, NULL, NULL },
   1453  { "client_pick_intro", test_client_pick_intro,
   1454    TT_FORK, NULL, NULL },
   1455  { "descriptor_fetch", test_descriptor_fetch,
   1456    TT_FORK, NULL, NULL },
   1457  { "auth_key_filename_is_valid", test_auth_key_filename_is_valid, TT_FORK,
   1458    NULL, NULL },
   1459  { "parse_auth_file_content", test_parse_auth_file_content, TT_FORK,
   1460    NULL, NULL },
   1461  { "config_client_authorization", test_config_client_authorization,
   1462    TT_FORK, NULL, NULL },
   1463  { "desc_has_arrived_cleanup", test_desc_has_arrived_cleanup,
   1464    TT_FORK, NULL, NULL },
   1465  { "close_intro_circuit_failure", test_close_intro_circuit_failure,
   1466    TT_FORK, NULL, NULL },
   1467  { "close_intro_circuits_new_desc", test_close_intro_circuits_new_desc,
   1468    TT_FORK, NULL, NULL },
   1469  { "close_intro_circuits_cache_clean", test_close_intro_circuits_cache_clean,
   1470    TT_FORK, NULL, NULL },
   1471 
   1472  /* SOCKS5 Extended Error Code. */
   1473  { "socks_hs_errors", test_socks_hs_errors, TT_FORK, NULL, NULL },
   1474 
   1475  /* Client authorization. */
   1476  { "purge_ephemeral_client_auth", test_purge_ephemeral_client_auth, TT_FORK,
   1477    NULL, NULL },
   1478 
   1479  END_OF_TESTCASES
   1480 };