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