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