tor

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

test_hs_cache.c (25501B)


      1 /* Copyright (c) 2016-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file test_hs_cache.c
      6 * \brief Test hidden service caches.
      7 */
      8 
      9 #define CONNECTION_PRIVATE
     10 #define DIRCACHE_PRIVATE
     11 #define DIRCLIENT_PRIVATE
     12 #define HS_CACHE_PRIVATE
     13 #define CHANNEL_OBJECT_PRIVATE
     14 
     15 #include "trunnel/ed25519_cert.h"
     16 #include "feature/hs/hs_cache.h"
     17 #include "feature/dircache/dircache.h"
     18 #include "feature/dirclient/dirclient.h"
     19 #include "feature/nodelist/networkstatus.h"
     20 #include "core/mainloop/connection.h"
     21 #include "core/proto/proto_http.h"
     22 #include "core/or/circuitlist.h"
     23 #include "core/or/channel.h"
     24 #include "lib/crypt_ops/crypto_format.h"
     25 #include "lib/crypt_ops/crypto_rand.h"
     26 
     27 #include "core/or/edge_connection_st.h"
     28 #include "core/or/or_circuit_st.h"
     29 #include "core/or/or_connection_st.h"
     30 #include "feature/dircommon/dir_connection_st.h"
     31 #include "feature/nodelist/networkstatus_st.h"
     32 
     33 #include "test/hs_test_helpers.h"
     34 #include "test/test_helpers.h"
     35 #include "test/test.h"
     36 
     37 /* Static variable used to encoded the HSDir query. */
     38 static char query_b64[256];
     39 
     40 /* Build an HSDir query using a ed25519 public key. */
     41 static const char *
     42 helper_get_hsdir_query(const hs_descriptor_t *desc)
     43 {
     44  ed25519_public_to_base64(query_b64, &desc->plaintext_data.blinded_pubkey);
     45  return query_b64;
     46 }
     47 
     48 static void
     49 init_test(void)
     50 {
     51  /* Always needed. Initialize the subsystem. */
     52  hs_cache_init();
     53 }
     54 
     55 static void
     56 test_directory(void *arg)
     57 {
     58  int ret;
     59  size_t oom_size;
     60  char *desc1_str = NULL;
     61  const char *desc_out;
     62  ed25519_keypair_t signing_kp1;
     63  hs_descriptor_t *desc1 = NULL;
     64 
     65  (void) arg;
     66 
     67  init_test();
     68  /* Generate a valid descriptor with normal values. */
     69  ret = ed25519_keypair_generate(&signing_kp1, 0);
     70  tt_int_op(ret, OP_EQ, 0);
     71  desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1);
     72  tt_assert(desc1);
     73  ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str);
     74  tt_int_op(ret, OP_EQ, 0);
     75 
     76  /* Very first basic test, should be able to be stored, survive a
     77   * clean, found with a lookup and then cleaned by our OOM. */
     78  {
     79    ret = hs_cache_store_as_dir(desc1_str);
     80    tt_int_op(ret, OP_EQ, 0);
     81    /* Re-add, it should fail since we already have it. */
     82    ret = hs_cache_store_as_dir(desc1_str);
     83    tt_int_op(ret, OP_EQ, -1);
     84    /* Try to clean now which should be fine, there is at worst few seconds
     85     * between the store and this call. */
     86    hs_cache_clean_as_dir(time(NULL));
     87    /* We should find it in our cache. */
     88    ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
     89    tt_int_op(ret, OP_EQ, 1);
     90    tt_str_op(desc_out, OP_EQ, desc1_str);
     91    /* Tell our OOM to run and to at least remove a byte which will result in
     92     * removing the descriptor from our cache. */
     93    oom_size = hs_cache_handle_oom(1);
     94    tt_int_op(oom_size, OP_GE, 1);
     95    ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
     96    tt_int_op(ret, OP_EQ, 0);
     97  }
     98 
     99  /* Store two descriptors and remove the expiring one only. */
    100  {
    101    ed25519_keypair_t signing_kp_zero;
    102    ret = ed25519_keypair_generate(&signing_kp_zero, 0);
    103    tt_int_op(ret, OP_EQ, 0);
    104    hs_descriptor_t *desc_zero_lifetime;
    105    desc_zero_lifetime = hs_helper_build_hs_desc_with_ip(&signing_kp_zero);
    106    tt_assert(desc_zero_lifetime);
    107    desc_zero_lifetime->plaintext_data.revision_counter = 1;
    108    desc_zero_lifetime->plaintext_data.lifetime_sec = 0;
    109    char *desc_zero_lifetime_str;
    110    ret = hs_desc_encode_descriptor(desc_zero_lifetime, &signing_kp_zero,
    111                                    NULL, &desc_zero_lifetime_str);
    112    tt_int_op(ret, OP_EQ, 0);
    113 
    114    ret = hs_cache_store_as_dir(desc1_str);
    115    tt_int_op(ret, OP_EQ, 0);
    116    ret = hs_cache_store_as_dir(desc_zero_lifetime_str);
    117    tt_int_op(ret, OP_EQ, 0);
    118    /* This one should clear out our zero lifetime desc. */
    119    hs_cache_clean_as_dir(time(NULL));
    120    /* We should find desc1 in our cache. */
    121    ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
    122    tt_int_op(ret, OP_EQ, 1);
    123    tt_str_op(desc_out, OP_EQ, desc1_str);
    124    /* We should NOT find our zero lifetime desc in our cache. */
    125    ret = hs_cache_lookup_as_dir(3,
    126                                 helper_get_hsdir_query(desc_zero_lifetime),
    127                                 NULL);
    128    tt_int_op(ret, OP_EQ, 0);
    129    /* Cleanup our entire cache. */
    130    oom_size = hs_cache_handle_oom(1);
    131    tt_int_op(oom_size, OP_GE, 1);
    132    hs_descriptor_free(desc_zero_lifetime);
    133    tor_free(desc_zero_lifetime_str);
    134  }
    135 
    136  /* Throw junk at it. */
    137  {
    138    ret = hs_cache_store_as_dir("blah");
    139    tt_int_op(ret, OP_EQ, -1);
    140    /* Poor attempt at tricking the decoding. */
    141    ret = hs_cache_store_as_dir("hs-descriptor 3\nJUNK");
    142    tt_int_op(ret, OP_EQ, -1);
    143    /* Undecodable base64 query. */
    144    ret = hs_cache_lookup_as_dir(3, "blah", NULL);
    145    tt_int_op(ret, OP_EQ, -1);
    146    /* Decodable base64 query but wrong ed25519 size. */
    147    ret = hs_cache_lookup_as_dir(3, "dW5pY29ybg==", NULL);
    148    tt_int_op(ret, OP_EQ, -1);
    149  }
    150 
    151  /* Test descriptor replacement with revision counter. */
    152  {
    153    char *new_desc_str;
    154 
    155    /* Add a descriptor. */
    156    ret = hs_cache_store_as_dir(desc1_str);
    157    tt_int_op(ret, OP_EQ, 0);
    158    ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
    159    tt_int_op(ret, OP_EQ, 1);
    160    /* Bump revision counter. */
    161    desc1->plaintext_data.revision_counter++;
    162    ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &new_desc_str);
    163    tt_int_op(ret, OP_EQ, 0);
    164    ret = hs_cache_store_as_dir(new_desc_str);
    165    tt_int_op(ret, OP_EQ, 0);
    166    /* Look it up, it should have been replaced. */
    167    ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
    168    tt_int_op(ret, OP_EQ, 1);
    169    tt_str_op(desc_out, OP_EQ, new_desc_str);
    170    tor_free(new_desc_str);
    171  }
    172 
    173 done:
    174  hs_descriptor_free(desc1);
    175  tor_free(desc1_str);
    176 }
    177 
    178 static void
    179 test_clean_as_dir(void *arg)
    180 {
    181  size_t ret;
    182  char *desc1_str = NULL;
    183  time_t now = time(NULL);
    184  hs_descriptor_t *desc1 = NULL;
    185  ed25519_keypair_t signing_kp1;
    186 
    187  (void) arg;
    188 
    189  init_test();
    190 
    191  /* Generate a valid descriptor with values. */
    192  ret = ed25519_keypair_generate(&signing_kp1, 0);
    193  tt_int_op(ret, OP_EQ, 0);
    194  desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1);
    195  tt_assert(desc1);
    196  ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str);
    197  tt_int_op(ret, OP_EQ, 0);
    198  ret = hs_cache_store_as_dir(desc1_str);
    199  tt_int_op(ret, OP_EQ, 0);
    200 
    201  /* With the lifetime being 3 hours, a cleanup shouldn't remove it. */
    202  ret = cache_clean_v3_as_dir(now, 0);
    203  tt_int_op(ret, OP_EQ, 0);
    204  /* Should be present after clean up. */
    205  ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
    206  tt_int_op(ret, OP_EQ, 1);
    207  /* Set a cutoff 100 seconds in the past. It should not remove the entry
    208   * since the entry is still recent enough. */
    209  ret = cache_clean_v3_as_dir(now, now - 100);
    210  tt_int_op(ret, OP_EQ, 0);
    211  /* Should be present after clean up. */
    212  ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
    213  tt_int_op(ret, OP_EQ, 1);
    214  /* Set a cutoff of 100 seconds in the future. It should remove the entry
    215   * that we've just added since it's not too old for the cutoff. */
    216  ret = cache_clean_v3_as_dir(now, now + 100);
    217  tt_int_op(ret, OP_GT, 0);
    218  /* Shouldn't be present after clean up. */
    219  ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
    220  tt_int_op(ret, OP_EQ, 0);
    221 
    222 done:
    223  hs_descriptor_free(desc1);
    224  tor_free(desc1_str);
    225 }
    226 
    227 static void
    228 test_clean_oom_as_dir(void *arg)
    229 {
    230  size_t ret;
    231  char *desc1_str = NULL, *desc2_str = NULL;
    232  hs_descriptor_t *desc1 = NULL, *desc2 = NULL;
    233  ed25519_keypair_t signing_kp1, signing_kp2;
    234 
    235  (void) arg;
    236 
    237  init_test();
    238 
    239  /* Generate two valid descriptors. */
    240  ret = ed25519_keypair_generate(&signing_kp1, 0);
    241  tt_int_op(ret, OP_EQ, 0);
    242  ret = ed25519_keypair_generate(&signing_kp2, 0);
    243  tt_int_op(ret, OP_EQ, 0);
    244  desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1);
    245  tt_assert(desc1);
    246  desc2 = hs_helper_build_hs_desc_with_ip(&signing_kp2);
    247  tt_assert(desc2);
    248  ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str);
    249  tt_int_op(ret, OP_EQ, 0);
    250  ret = hs_cache_store_as_dir(desc1_str);
    251  tt_int_op(ret, OP_EQ, 0);
    252  ret = hs_desc_encode_descriptor(desc2, &signing_kp2, NULL, &desc2_str);
    253  tt_int_op(ret, OP_EQ, 0);
    254  ret = hs_cache_store_as_dir(desc2_str);
    255  tt_int_op(ret, OP_EQ, 0);
    256 
    257  /* Set the downloaded count to 42 for the second one. */
    258  dir_set_downloaded(&desc2->plaintext_data.blinded_pubkey, 42);
    259  const hs_cache_dir_descriptor_t *entry =
    260    lookup_v3_desc_as_dir(desc2->plaintext_data.blinded_pubkey.pubkey);
    261  tt_u64_op(entry->n_downloaded, OP_EQ, 42);
    262 
    263  /* Spin the OOM cleanup for only 1 descriptor (very low amount of bytes). We
    264   * expect desc1 to be cleaned up because its downloaded counter is 0. */
    265  size_t removed = hs_cache_handle_oom(1);
    266  tt_size_op(removed, OP_GT, 0);
    267 
    268  /* Desc1 is gone. */
    269  entry = lookup_v3_desc_as_dir(desc1->plaintext_data.blinded_pubkey.pubkey);
    270  tt_assert(!entry);
    271  /* Desc2 is still there. */
    272  entry = lookup_v3_desc_as_dir(desc2->plaintext_data.blinded_pubkey.pubkey);
    273  tt_assert(entry);
    274 
    275 done:
    276  hs_descriptor_free(desc1);
    277  hs_descriptor_free(desc2);
    278  tor_free(desc1_str);
    279  tor_free(desc2_str);
    280 }
    281 
    282 /* Test helper: Fetch an HS descriptor from an HSDir (for the hidden service
    283   with <b>blinded_key</b>. Return the received descriptor string. */
    284 static char *
    285 helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
    286 {
    287  int retval;
    288 
    289  char *received_desc = NULL;
    290  char *hsdir_query_str = NULL;
    291 
    292  /* The dir conn we are going to simulate */
    293  dir_connection_t *conn = NULL;
    294  edge_connection_t *edge_conn = NULL;
    295  or_circuit_t *or_circ = NULL;
    296 
    297  /* First extract the blinded public key that we are going to use in our
    298     query, and then build the actual query string. */
    299  {
    300    char hsdir_cache_key[ED25519_BASE64_LEN+1];
    301 
    302    ed25519_public_to_base64(hsdir_cache_key, blinded_key);
    303    tor_asprintf(&hsdir_query_str, GET("/tor/hs/3/%s"), hsdir_cache_key);
    304  }
    305 
    306  /* Simulate an HTTP GET request to the HSDir */
    307  conn = dir_connection_new(AF_INET);
    308  tt_assert(conn);
    309  TO_CONN(conn)->linked = 1; /* Signal that it is encrypted. */
    310  tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001);
    311 
    312  /* Pretend this conn is anonymous. */
    313  edge_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
    314  TO_CONN(conn)->linked_conn = TO_CONN(edge_conn);
    315  or_circ = or_circuit_new(0, NULL);
    316  or_circ->p_chan = tor_malloc_zero(sizeof(channel_t));
    317  edge_conn->on_circuit = TO_CIRCUIT(or_circ);
    318 
    319  retval = directory_handle_command_get(conn, hsdir_query_str,
    320                                        NULL, 0);
    321  tt_int_op(retval, OP_EQ, 0);
    322 
    323  /* Read the descriptor that the HSDir just served us */
    324  {
    325    char *headers = NULL;
    326    size_t body_used = 0;
    327 
    328    fetch_from_buf_http(TO_CONN(conn)->outbuf, &headers, MAX_HEADERS_SIZE,
    329                        &received_desc, &body_used, HS_DESC_MAX_LEN, 0);
    330    tor_free(headers);
    331  }
    332 
    333 done:
    334  tor_free(hsdir_query_str);
    335  if (conn) {
    336    tor_free(or_circ->p_chan);
    337    connection_free_minimal(TO_CONN(conn)->linked_conn);
    338    connection_free_minimal(TO_CONN(conn));
    339  }
    340 
    341  return received_desc;
    342 }
    343 
    344 /* Publish a descriptor to the HSDir, then fetch it. Check that the received
    345   descriptor matches the published one. */
    346 static void
    347 test_upload_and_download_hs_desc(void *arg)
    348 {
    349  int retval;
    350  hs_descriptor_t *published_desc = NULL;
    351 
    352  char *published_desc_str = NULL;
    353  char *received_desc_str = NULL;
    354 
    355  (void) arg;
    356 
    357  /* Initialize HSDir cache subsystem */
    358  init_test();
    359 
    360  /* Test a descriptor not found in the directory cache. */
    361  {
    362    ed25519_public_key_t blinded_key;
    363    memset(&blinded_key.pubkey, 'A', sizeof(blinded_key.pubkey));
    364    received_desc_str = helper_fetch_desc_from_hsdir(&blinded_key);
    365    tt_int_op(strlen(received_desc_str), OP_EQ, 0);
    366    tor_free(received_desc_str);
    367  }
    368 
    369  /* Generate a valid descriptor with normal values. */
    370  {
    371    ed25519_keypair_t signing_kp;
    372    retval = ed25519_keypair_generate(&signing_kp, 0);
    373    tt_int_op(retval, OP_EQ, 0);
    374    published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
    375    tt_assert(published_desc);
    376    retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
    377                                       NULL, &published_desc_str);
    378    tt_int_op(retval, OP_EQ, 0);
    379  }
    380 
    381  /* Publish descriptor to the HSDir */
    382  {
    383    retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
    384    tt_int_op(retval, OP_EQ, 200);
    385  }
    386 
    387  /* Simulate a fetch of the previously published descriptor */
    388  {
    389    const ed25519_public_key_t *blinded_key;
    390    blinded_key = &published_desc->plaintext_data.blinded_pubkey;
    391    received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
    392  }
    393 
    394  /* Verify we received the exact same descriptor we published earlier */
    395  tt_str_op(received_desc_str, OP_EQ, published_desc_str);
    396  tor_free(received_desc_str);
    397 
    398  /* With a valid descriptor in the directory cache, try again an invalid. */
    399  {
    400    ed25519_public_key_t blinded_key;
    401    memset(&blinded_key.pubkey, 'A', sizeof(blinded_key.pubkey));
    402    received_desc_str = helper_fetch_desc_from_hsdir(&blinded_key);
    403    tt_int_op(strlen(received_desc_str), OP_EQ, 0);
    404  }
    405 
    406 done:
    407  tor_free(received_desc_str);
    408  tor_free(published_desc_str);
    409  hs_descriptor_free(published_desc);
    410 }
    411 
    412 /* Test that HSDirs reject outdated descriptors based on their revision
    413 * counter. Also test that HSDirs correctly replace old descriptors with newer
    414 * descriptors. */
    415 static void
    416 test_hsdir_revision_counter_check(void *arg)
    417 {
    418  int retval;
    419 
    420  ed25519_keypair_t signing_kp;
    421 
    422  hs_descriptor_t *published_desc = NULL;
    423  char *published_desc_str = NULL;
    424 
    425  hs_subcredential_t subcredential;
    426  char *received_desc_str = NULL;
    427  hs_descriptor_t *received_desc = NULL;
    428 
    429  (void) arg;
    430 
    431  /* Initialize HSDir cache subsystem */
    432  init_test();
    433 
    434  /* Generate a valid descriptor with normal values. */
    435  {
    436    retval = ed25519_keypair_generate(&signing_kp, 0);
    437    tt_int_op(retval, OP_EQ, 0);
    438    published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
    439    tt_assert(published_desc);
    440    retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
    441                                       NULL, &published_desc_str);
    442    tt_int_op(retval, OP_EQ, 0);
    443  }
    444 
    445  /* Publish descriptor to the HSDir */
    446  {
    447    retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
    448    tt_int_op(retval, OP_EQ, 200);
    449  }
    450 
    451  /* Try publishing again with the same revision counter: Should fail. */
    452  {
    453    retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
    454    tt_int_op(retval, OP_EQ, 400);
    455  }
    456 
    457  /* Fetch the published descriptor and validate the revision counter. */
    458  {
    459    const ed25519_public_key_t *blinded_key;
    460 
    461    blinded_key = &published_desc->plaintext_data.blinded_pubkey;
    462    hs_get_subcredential(&signing_kp.pubkey, blinded_key, &subcredential);
    463    received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
    464 
    465    retval = hs_desc_decode_descriptor(received_desc_str,
    466                                       &subcredential, NULL, &received_desc);
    467    tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
    468    tt_assert(received_desc);
    469 
    470    /* Check that the revision counter is correct */
    471    tt_u64_op(received_desc->plaintext_data.revision_counter, OP_EQ, 42);
    472 
    473    hs_descriptor_free(received_desc);
    474    received_desc = NULL;
    475    tor_free(received_desc_str);
    476  }
    477 
    478  /* Increment the revision counter and try again. Should work. */
    479  {
    480    published_desc->plaintext_data.revision_counter = 1313;
    481    tor_free(published_desc_str);
    482    retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
    483                                       NULL, &published_desc_str);
    484    tt_int_op(retval, OP_EQ, 0);
    485 
    486    retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
    487    tt_int_op(retval, OP_EQ, 200);
    488  }
    489 
    490  /* Again, fetch the published descriptor and perform the revision counter
    491     validation. The revision counter must have changed. */
    492  {
    493    const ed25519_public_key_t *blinded_key;
    494 
    495    blinded_key = &published_desc->plaintext_data.blinded_pubkey;
    496    received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
    497 
    498    retval = hs_desc_decode_descriptor(received_desc_str,
    499                                       &subcredential, NULL, &received_desc);
    500    tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
    501    tt_assert(received_desc);
    502 
    503    /* Check that the revision counter is the latest */
    504    tt_u64_op(received_desc->plaintext_data.revision_counter, OP_EQ, 1313);
    505  }
    506 
    507 done:
    508  hs_descriptor_free(published_desc);
    509  hs_descriptor_free(received_desc);
    510  tor_free(received_desc_str);
    511  tor_free(published_desc_str);
    512 }
    513 
    514 static networkstatus_t mock_ns;
    515 
    516 static networkstatus_t *
    517 mock_networkstatus_get_reasonably_live_consensus(time_t now, int flavor)
    518 {
    519  (void) now;
    520  (void) flavor;
    521  return &mock_ns;
    522 }
    523 
    524 /** Test that we can store HS descriptors in the client HS cache. */
    525 static void
    526 test_client_cache(void *arg)
    527 {
    528  int retval;
    529  ed25519_keypair_t signing_kp;
    530  hs_descriptor_t *published_desc = NULL;
    531  char *published_desc_str = NULL;
    532  hs_subcredential_t wanted_subcredential;
    533  response_handler_args_t *args = NULL;
    534  dir_connection_t *conn = NULL;
    535 
    536  (void) arg;
    537 
    538  /* Initialize HSDir cache subsystem */
    539  init_test();
    540 
    541  MOCK(networkstatus_get_reasonably_live_consensus,
    542       mock_networkstatus_get_reasonably_live_consensus);
    543 
    544  /* Set consensus time */
    545  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
    546                           &mock_ns.valid_after);
    547  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
    548                           &mock_ns.fresh_until);
    549  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
    550                           &mock_ns.valid_until);
    551 
    552  /* Generate a valid descriptor with normal values. */
    553  {
    554    retval = ed25519_keypair_generate(&signing_kp, 0);
    555    tt_int_op(retval, OP_EQ, 0);
    556    published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
    557    tt_assert(published_desc);
    558    retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
    559                                       NULL, &published_desc_str);
    560    tt_int_op(retval, OP_EQ, 0);
    561    memcpy(&wanted_subcredential, &published_desc->subcredential,
    562           sizeof(hs_subcredential_t));
    563    tt_assert(!fast_mem_is_zero((char*)wanted_subcredential.subcred,
    564                                DIGEST256_LEN));
    565  }
    566 
    567  /* Test handle_response_fetch_hsdesc_v3() */
    568  {
    569    args = tor_malloc_zero(sizeof(response_handler_args_t));
    570    args->status_code = 200;
    571    args->reason = NULL;
    572    args->body = published_desc_str;
    573    args->body_len = strlen(published_desc_str);
    574 
    575    conn = tor_malloc_zero(sizeof(dir_connection_t));
    576    conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
    577    ed25519_pubkey_copy(&conn->hs_ident->identity_pk, &signing_kp.pubkey);
    578  }
    579 
    580  /* store the descriptor! */
    581  retval = handle_response_fetch_hsdesc_v3(conn, args);
    582  tt_int_op(retval, == , 0);
    583 
    584  /* Progress time a bit and attempt to clean cache: our desc should not be
    585   * cleaned since we still in the same TP. */
    586  {
    587    parse_rfc1123_time("Sat, 27 Oct 1985 02:00:00 UTC",
    588                       &mock_ns.valid_after);
    589    parse_rfc1123_time("Sat, 27 Oct 1985 03:00:00 UTC",
    590                       &mock_ns.fresh_until);
    591    parse_rfc1123_time("Sat, 27 Oct 1985 05:00:00 UTC",
    592                       &mock_ns.valid_until);
    593 
    594    /* fetch the descriptor and make sure it's there */
    595    const hs_descriptor_t *cached_desc = NULL;
    596    cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
    597    tt_assert(cached_desc);
    598    tt_mem_op(cached_desc->subcredential.subcred,
    599              OP_EQ, wanted_subcredential.subcred,
    600              SUBCRED_LEN);
    601  }
    602 
    603  /* Progress time to next TP and check that desc was cleaned */
    604  {
    605    parse_rfc1123_time("Sat, 27 Oct 1985 12:00:00 UTC",
    606                       &mock_ns.valid_after);
    607    parse_rfc1123_time("Sat, 27 Oct 1985 13:00:00 UTC",
    608                       &mock_ns.fresh_until);
    609    parse_rfc1123_time("Sat, 27 Oct 1985 15:00:00 UTC",
    610                       &mock_ns.valid_until);
    611 
    612    const hs_descriptor_t *cached_desc = NULL;
    613    cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
    614    tt_assert(!cached_desc);
    615  }
    616 
    617 done:
    618  tor_free(args);
    619  hs_descriptor_free(published_desc);
    620  tor_free(published_desc_str);
    621  if (conn) {
    622    tor_free(conn->hs_ident);
    623    tor_free(conn);
    624  }
    625 }
    626 
    627 /** Test that we can store HS descriptors in the client HS cache. */
    628 static void
    629 test_client_cache_decrypt(void *arg)
    630 {
    631  int ret;
    632  char *desc_encoded = NULL;
    633  uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
    634  curve25519_keypair_t client_kp;
    635  ed25519_keypair_t service_kp;
    636  hs_descriptor_t *desc = NULL;
    637  const hs_descriptor_t *search_desc;
    638  const char *search_desc_encoded;
    639 
    640  (void) arg;
    641 
    642  /* Initialize HSDir cache subsystem */
    643  hs_init();
    644 
    645  MOCK(networkstatus_get_reasonably_live_consensus,
    646       mock_networkstatus_get_reasonably_live_consensus);
    647 
    648  /* Set consensus time */
    649  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
    650                     &mock_ns.valid_after);
    651  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
    652                     &mock_ns.fresh_until);
    653  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
    654                     &mock_ns.valid_until);
    655 
    656  /* Generate a valid descriptor with normal values. */
    657  {
    658    ret = ed25519_keypair_generate(&service_kp, 0);
    659    tt_int_op(ret, OP_EQ, 0);
    660    ret = curve25519_keypair_generate(&client_kp, 0);
    661    tt_int_op(ret, OP_EQ, 0);
    662    crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
    663 
    664    desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie,
    665                                                    &client_kp.pubkey,
    666                                                    &service_kp);
    667    tt_assert(desc);
    668    ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
    669                                    &desc_encoded);
    670    tt_int_op(ret, OP_EQ, 0);
    671  }
    672 
    673  /* Put it in the cache. Should not be decrypted since the client
    674   * authorization creds were not added to the global map. */
    675  ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey);
    676  tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
    677 
    678  /* We should not be able to decrypt anything. */
    679  ret = hs_cache_client_new_auth_parse(&service_kp.pubkey);
    680  tt_int_op(ret, OP_EQ, false);
    681 
    682  /* Add client auth to global map. */
    683  hs_helper_add_client_auth(&service_kp.pubkey, &client_kp.seckey);
    684 
    685  /* We should not be able to decrypt anything. */
    686  ret = hs_cache_client_new_auth_parse(&service_kp.pubkey);
    687  tt_int_op(ret, OP_EQ, true);
    688 
    689  /* Lookup the cache to make sure it is usable and there. */
    690  search_desc = hs_cache_lookup_as_client(&service_kp.pubkey);
    691  tt_assert(search_desc);
    692  search_desc_encoded = hs_cache_lookup_encoded_as_client(&service_kp.pubkey);
    693  tt_mem_op(search_desc_encoded, OP_EQ, desc_encoded, strlen(desc_encoded));
    694 
    695 done:
    696  hs_descriptor_free(desc);
    697  tor_free(desc_encoded);
    698 
    699  hs_free_all();
    700 
    701  UNMOCK(networkstatus_get_reasonably_live_consensus);
    702 }
    703 
    704 static void
    705 test_client_cache_remove(void *arg)
    706 {
    707  int ret;
    708  ed25519_keypair_t service_kp;
    709  hs_descriptor_t *desc1 = NULL;
    710 
    711  (void) arg;
    712 
    713  hs_init();
    714 
    715  MOCK(networkstatus_get_reasonably_live_consensus,
    716       mock_networkstatus_get_reasonably_live_consensus);
    717 
    718  /* Set consensus time. Lookup will not return the entry if it has expired
    719   * and it is checked against the consensus valid_after time. */
    720  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
    721                     &mock_ns.valid_after);
    722  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
    723                     &mock_ns.fresh_until);
    724  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
    725                     &mock_ns.valid_until);
    726 
    727  /* Generate service keypair */
    728  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
    729 
    730  /* Build a descriptor and cache it. */
    731  {
    732    char *encoded;
    733    desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
    734    tt_assert(desc1);
    735    ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
    736    tt_int_op(ret, OP_EQ, 0);
    737    tt_assert(encoded);
    738 
    739    /* Store it */
    740    ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
    741    tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
    742    tor_free(encoded);
    743    tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
    744  }
    745 
    746  /* Remove the cached entry. */
    747  hs_cache_remove_as_client(&service_kp.pubkey);
    748  tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey));
    749 
    750 done:
    751  hs_descriptor_free(desc1);
    752  hs_free_all();
    753 
    754  UNMOCK(networkstatus_get_reasonably_live_consensus);
    755 }
    756 
    757 struct testcase_t hs_cache[] = {
    758  /* Encoding tests. */
    759  { "directory", test_directory, TT_FORK,
    760    NULL, NULL },
    761  { "clean_as_dir", test_clean_as_dir, TT_FORK,
    762    NULL, NULL },
    763  { "clean_oom_as_dir", test_clean_oom_as_dir, TT_FORK,
    764    NULL, NULL },
    765  { "hsdir_revision_counter_check", test_hsdir_revision_counter_check, TT_FORK,
    766    NULL, NULL },
    767  { "upload_and_download_hs_desc", test_upload_and_download_hs_desc, TT_FORK,
    768    NULL, NULL },
    769  { "client_cache", test_client_cache, TT_FORK,
    770    NULL, NULL },
    771  { "client_cache_decrypt", test_client_cache_decrypt, TT_FORK,
    772    NULL, NULL },
    773  { "client_cache_remove", test_client_cache_remove, TT_FORK,
    774    NULL, NULL },
    775 
    776  END_OF_TESTCASES
    777 };