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