Remove unused function: dns_randfn_() in dns.c.
[tor.git] / src / test / test_hs_intropoint.c
blob9493da2995eb3a15f2f589cf0d598b2b9ef8fa5f
1 /* Copyright (c) 2016-2019, 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"
18 #include "core/or/or.h"
19 #include "core/or/circuitlist.h"
20 #include "core/or/circuituse.h"
21 #include "ht.h"
22 #include "core/or/relay.h"
23 #include "feature/rend/rendservice.h"
25 #include "feature/hs/hs_cell.h"
26 #include "feature/hs/hs_circuitmap.h"
27 #include "feature/hs/hs_common.h"
28 #include "feature/hs/hs_intropoint.h"
29 #include "feature/hs/hs_service.h"
31 #include "core/or/or_circuit_st.h"
33 /* Trunnel. */
34 #include "trunnel/hs/cell_establish_intro.h"
35 #include "trunnel/hs/cell_introduce1.h"
36 #include "trunnel/hs/cell_common.h"
38 static size_t
39 new_establish_intro_cell(const char *circ_nonce,
40 trn_cell_establish_intro_t **cell_out)
42 ssize_t cell_len = 0;
43 uint8_t buf[RELAY_PAYLOAD_SIZE] = {0};
44 trn_cell_establish_intro_t *cell = NULL;
45 hs_service_intro_point_t *ip = NULL;
47 /* Ensure that *cell_out is NULL such that we can use to check if we need to
48 * free `cell` in case of an error. */
49 *cell_out = NULL;
51 /* Auth key pair is generated in the constructor so we are all set for
52 * using this IP object. */
53 ip = service_intro_point_new(NULL, 0, 0);
54 tt_assert(ip);
55 cell_len = hs_cell_build_establish_intro(circ_nonce, ip, buf);
56 tt_i64_op(cell_len, OP_GT, 0);
58 cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf));
59 tt_i64_op(cell_len, OP_GT, 0);
60 tt_assert(cell);
61 *cell_out = cell;
63 done:
64 if (*cell_out == NULL)
65 trn_cell_establish_intro_free(cell);
67 service_intro_point_free(ip);
68 return cell_len;
71 static ssize_t
72 new_establish_intro_encoded_cell(const char *circ_nonce, uint8_t *cell_out)
74 ssize_t cell_len = 0;
75 hs_service_intro_point_t *ip = NULL;
77 /* Auth key pair is generated in the constructor so we are all set for
78 * using this IP object. */
79 ip = service_intro_point_new(NULL, 0, 0);
80 tt_assert(ip);
81 cell_len = hs_cell_build_establish_intro(circ_nonce, ip, cell_out);
82 tt_i64_op(cell_len, OP_GT, 0);
84 done:
85 service_intro_point_free(ip);
86 return cell_len;
89 /* Mock function to avoid networking in unittests */
90 static int
91 mock_send_intro_established_cell(or_circuit_t *circ)
93 (void) circ;
94 return 0;
97 static int
98 mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
99 uint8_t relay_command, const char *payload,
100 size_t payload_len,
101 crypt_path_t *cpath_layer,
102 const char *filename, int lineno)
104 (void) stream_id;
105 (void) circ;
106 (void) relay_command;
107 (void) payload;
108 (void) payload_len;
109 (void) cpath_layer;
110 (void) filename;
111 (void) lineno;
112 return 0;
115 static or_circuit_t *
116 helper_create_intro_circuit(void)
118 or_circuit_t *circ = or_circuit_new(0, NULL);
119 tt_assert(circ);
120 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
121 done:
122 return circ;
125 static trn_cell_introduce1_t *
126 helper_create_introduce1_cell(void)
128 trn_cell_introduce1_t *cell = NULL;
129 ed25519_keypair_t auth_key_kp;
131 /* Generate the auth_key of the cell. */
132 if (ed25519_keypair_generate(&auth_key_kp, 0) < 0) {
133 goto err;
136 cell = trn_cell_introduce1_new();
137 tt_assert(cell);
139 /* Set the auth key. */
141 size_t auth_key_len = sizeof(auth_key_kp.pubkey);
142 trn_cell_introduce1_set_auth_key_type(cell,
143 TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
144 trn_cell_introduce1_set_auth_key_len(cell, auth_key_len);
145 trn_cell_introduce1_setlen_auth_key(cell, auth_key_len);
146 uint8_t *auth_key_ptr = trn_cell_introduce1_getarray_auth_key(cell);
147 memcpy(auth_key_ptr, auth_key_kp.pubkey.pubkey, auth_key_len);
150 /* Set the cell extensions to none. */
152 trn_cell_extension_t *ext = trn_cell_extension_new();
153 trn_cell_extension_set_num(ext, 0);
154 trn_cell_introduce1_set_extensions(cell, ext);
157 /* Set the encrypted section to some data. */
159 size_t enc_len = 128;
160 trn_cell_introduce1_setlen_encrypted(cell, enc_len);
161 uint8_t *enc_ptr = trn_cell_introduce1_getarray_encrypted(cell);
162 memset(enc_ptr, 'a', enc_len);
165 return cell;
166 err:
167 done:
168 trn_cell_introduce1_free(cell);
169 return NULL;
172 /* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro
173 * point. Should fail. */
174 static void
175 test_establish_intro_wrong_purpose(void *arg)
177 int retval;
178 ssize_t cell_len = 0;
179 char circ_nonce[DIGEST_LEN] = {0};
180 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
181 or_circuit_t *intro_circ = or_circuit_new(0,NULL);
183 (void)arg;
185 /* Get the auth key of the intro point */
186 crypto_rand(circ_nonce, sizeof(circ_nonce));
187 memcpy(intro_circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
189 /* Set a bad circuit purpose!! :) */
190 circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT);
192 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
193 attempt to parse it. */
194 cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
195 tt_i64_op(cell_len, OP_GT, 0);
197 /* Receive the cell. Should fail. */
198 setup_full_capture_of_logs(LOG_INFO);
199 retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
200 expect_log_msg_containing("Rejecting ESTABLISH_INTRO on non-OR circuit.");
201 teardown_capture_of_logs();
202 tt_int_op(retval, OP_EQ, -1);
204 done:
205 circuit_free_(TO_CIRCUIT(intro_circ));
208 /* Prepare a circuit for accepting an ESTABLISH_INTRO cell */
209 static void
210 helper_prepare_circ_for_intro(or_circuit_t *circ, const char *circ_nonce)
212 /* Prepare the circuit for the incoming ESTABLISH_INTRO */
213 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
214 memcpy(circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
217 /* Send an empty ESTABLISH_INTRO cell. Should fail. */
218 static void
219 test_establish_intro_wrong_keytype(void *arg)
221 int retval;
222 or_circuit_t *intro_circ = or_circuit_new(0,NULL);
223 char circ_nonce[DIGEST_LEN] = {0};
225 (void) arg;
227 /* Get the auth key of the intro point */
228 crypto_rand(circ_nonce, sizeof(circ_nonce));
229 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
231 /* Receive the cell. Should fail. */
232 setup_full_capture_of_logs(LOG_INFO);
233 retval = hs_intro_received_establish_intro(intro_circ, (uint8_t *) "", 0);
234 expect_log_msg_containing("Empty ESTABLISH_INTRO cell.");
235 teardown_capture_of_logs();
236 tt_int_op(retval, OP_EQ, -1);
238 done:
239 circuit_free_(TO_CIRCUIT(intro_circ));
242 /* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */
243 static void
244 test_establish_intro_wrong_keytype2(void *arg)
246 int retval;
247 char circ_nonce[DIGEST_LEN] = {0};
248 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
249 ssize_t cell_len = 0;
250 or_circuit_t *intro_circ = or_circuit_new(0,NULL);
252 (void) arg;
254 /* Get the auth key of the intro point */
255 crypto_rand(circ_nonce, sizeof(circ_nonce));
256 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
258 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
259 * attempt to parse it. */
260 cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
261 tt_i64_op(cell_len, OP_GT, 0);
263 /* Mutate the auth key type! :) */
264 cell_body[0] = 42;
266 /* Receive the cell. Should fail. */
267 setup_full_capture_of_logs(LOG_INFO);
268 retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
269 expect_log_msg_containing("Unrecognized AUTH_KEY_TYPE 42.");
270 teardown_capture_of_logs();
271 tt_int_op(retval, OP_EQ, -1);
273 done:
274 circuit_free_(TO_CIRCUIT(intro_circ));
277 /* Send a legit ESTABLISH_INTRO cell but with a wrong MAC. Should fail. */
278 static void
279 test_establish_intro_wrong_mac(void *arg)
281 int retval;
282 char circ_nonce[DIGEST_LEN] = {0};
283 ssize_t cell_len = 0;
284 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
285 trn_cell_establish_intro_t *cell = NULL;
286 or_circuit_t *intro_circ = or_circuit_new(0,NULL);
288 (void) arg;
290 /* Get the auth key of the intro point */
291 crypto_rand(circ_nonce, sizeof(circ_nonce));
292 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
294 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
295 * attempt to parse it. */
296 cell_len = new_establish_intro_cell(circ_nonce, &cell);
297 tt_i64_op(cell_len, OP_GT, 0);
298 tt_assert(cell);
300 /* Mangle one byte of the MAC. */
301 uint8_t *handshake_ptr =
302 trn_cell_establish_intro_getarray_handshake_mac(cell);
303 handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++;
304 /* We need to resign the payload with that change. */
306 ed25519_signature_t sig;
307 ed25519_keypair_t key_struct;
308 /* New keypair for the signature since we don't have access to the private
309 * key material generated earlier when creating the cell. */
310 retval = ed25519_keypair_generate(&key_struct, 0);
311 tt_int_op(retval, OP_EQ, 0);
312 uint8_t *auth_key_ptr =
313 trn_cell_establish_intro_getarray_auth_key(cell);
314 memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN);
315 /* Encode payload so we can sign it. */
316 cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
317 cell);
318 tt_i64_op(cell_len, OP_GT, 0);
320 retval = ed25519_sign_prefixed(&sig, cell_body,
321 cell_len -
322 (ED25519_SIG_LEN + sizeof(cell->sig_len)),
323 ESTABLISH_INTRO_SIG_PREFIX, &key_struct);
324 tt_int_op(retval, OP_EQ, 0);
325 /* And write the signature to the cell */
326 uint8_t *sig_ptr =
327 trn_cell_establish_intro_getarray_sig(cell);
328 memcpy(sig_ptr, sig.sig, cell->sig_len);
329 /* Re-encode with the new signature. */
330 cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
331 cell);
332 tt_i64_op(cell_len, OP_GT, 0);
335 /* Receive the cell. Should fail because our MAC is wrong. */
336 setup_full_capture_of_logs(LOG_INFO);
337 retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
338 expect_log_msg_containing("ESTABLISH_INTRO handshake_auth not as expected");
339 teardown_capture_of_logs();
340 tt_int_op(retval, OP_EQ, -1);
342 done:
343 trn_cell_establish_intro_free(cell);
344 circuit_free_(TO_CIRCUIT(intro_circ));
347 /* Send a legit ESTABLISH_INTRO cell but with a wrong auth key length. Should
348 * fail. */
349 static void
350 test_establish_intro_wrong_auth_key_len(void *arg)
352 int retval;
353 char circ_nonce[DIGEST_LEN] = {0};
354 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
355 ssize_t cell_len = 0;
356 size_t bad_auth_key_len = ED25519_PUBKEY_LEN - 1;
357 trn_cell_establish_intro_t *cell = NULL;
358 or_circuit_t *intro_circ = or_circuit_new(0,NULL);
360 (void) arg;
362 /* Get the auth key of the intro point */
363 crypto_rand(circ_nonce, sizeof(circ_nonce));
364 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
366 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
367 * attempt to parse it. */
368 cell_len = new_establish_intro_cell(circ_nonce, &cell);
369 tt_i64_op(cell_len, OP_GT, 0);
370 tt_assert(cell);
372 /* Mangle the auth key length. */
373 trn_cell_establish_intro_set_auth_key_len(cell, bad_auth_key_len);
374 trn_cell_establish_intro_setlen_auth_key(cell, bad_auth_key_len);
375 /* Encode cell. */
376 cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
377 cell);
378 tt_int_op(cell_len, OP_GT, 0);
380 /* Receive the cell. Should fail. */
381 setup_full_capture_of_logs(LOG_INFO);
382 retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
383 expect_log_msg_containing("ESTABLISH_INTRO auth key length is invalid");
384 teardown_capture_of_logs();
385 tt_int_op(retval, OP_EQ, -1);
387 done:
388 trn_cell_establish_intro_free(cell);
389 circuit_free_(TO_CIRCUIT(intro_circ));
392 /* Send a legit ESTABLISH_INTRO cell but with a wrong sig length. Should
393 * fail. */
394 static void
395 test_establish_intro_wrong_sig_len(void *arg)
397 int retval;
398 char circ_nonce[DIGEST_LEN] = {0};
399 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
400 ssize_t cell_len = 0;
401 size_t bad_sig_len = ED25519_SIG_LEN - 1;
402 trn_cell_establish_intro_t *cell = NULL;
403 or_circuit_t *intro_circ = or_circuit_new(0,NULL);
405 (void) arg;
407 /* Get the auth key of the intro point */
408 crypto_rand(circ_nonce, sizeof(circ_nonce));
409 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
411 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
412 * attempt to parse it. */
413 cell_len = new_establish_intro_cell(circ_nonce, &cell);
414 tt_i64_op(cell_len, OP_GT, 0);
415 tt_assert(cell);
417 /* Mangle the signature length. */
418 trn_cell_establish_intro_set_sig_len(cell, bad_sig_len);
419 trn_cell_establish_intro_setlen_sig(cell, bad_sig_len);
420 /* Encode cell. */
421 cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
422 cell);
423 tt_int_op(cell_len, OP_GT, 0);
425 /* Receive the cell. Should fail. */
426 setup_full_capture_of_logs(LOG_INFO);
427 retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
428 expect_log_msg_containing("ESTABLISH_INTRO sig len is invalid");
429 teardown_capture_of_logs();
430 tt_int_op(retval, OP_EQ, -1);
432 done:
433 trn_cell_establish_intro_free(cell);
434 circuit_free_(TO_CIRCUIT(intro_circ));
437 /* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should
438 * fail. */
439 static void
440 test_establish_intro_wrong_sig(void *arg)
442 int retval;
443 char circ_nonce[DIGEST_LEN] = {0};
444 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
445 ssize_t cell_len = 0;
446 or_circuit_t *intro_circ = or_circuit_new(0,NULL);
448 (void) arg;
450 /* Get the auth key of the intro point */
451 crypto_rand(circ_nonce, sizeof(circ_nonce));
452 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
454 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
455 attempt to parse it. */
456 cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
457 tt_i64_op(cell_len, OP_GT, 0);
459 /* Mutate the last byte (signature)! :) */
460 cell_body[cell_len - 1]++;
462 /* Receive the cell. Should fail. */
463 setup_full_capture_of_logs(LOG_INFO);
464 retval = hs_intro_received_establish_intro(intro_circ, cell_body,
465 (size_t)cell_len);
466 expect_log_msg_containing("Failed to verify ESTABLISH_INTRO cell.");
467 teardown_capture_of_logs();
468 tt_int_op(retval, OP_EQ, -1);
470 done:
471 circuit_free_(TO_CIRCUIT(intro_circ));
474 /* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to
475 * <b>intro_circ</b>. Return the cell. */
476 static trn_cell_establish_intro_t *
477 helper_establish_intro_v3(or_circuit_t *intro_circ)
479 int retval;
480 char circ_nonce[DIGEST_LEN] = {0};
481 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
482 ssize_t cell_len = 0;
483 trn_cell_establish_intro_t *cell = NULL;
485 tt_assert(intro_circ);
487 /* Prepare the circuit for the incoming ESTABLISH_INTRO */
488 crypto_rand(circ_nonce, sizeof(circ_nonce));
489 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
491 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
492 * attempt to parse it. */
493 cell_len = new_establish_intro_cell(circ_nonce, &cell);
494 tt_i64_op(cell_len, OP_GT, 0);
495 tt_assert(cell);
496 cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
497 cell);
498 tt_int_op(cell_len, OP_GT, 0);
500 /* Receive the cell */
501 retval = hs_intro_received_establish_intro(intro_circ, cell_body,
502 (size_t) cell_len);
503 tt_int_op(retval, OP_EQ, 0);
505 done:
506 return cell;
509 /* Helper function: test circuitmap free_all function outside of
510 * test_intro_point_registration to prevent Coverity from seeing a
511 * double free if the assertion hypothetically fails.
513 static void
514 test_circuitmap_free_all(void)
516 hs_circuitmap_ht *the_hs_circuitmap = NULL;
518 the_hs_circuitmap = get_hs_circuitmap();
519 tt_assert(the_hs_circuitmap);
520 hs_circuitmap_free_all();
521 the_hs_circuitmap = get_hs_circuitmap();
522 tt_ptr_op(the_hs_circuitmap, OP_EQ, NULL);
523 done:
527 /** Successfully register a v2 intro point and a v3 intro point. Ensure that HS
528 * circuitmap is maintained properly. */
529 static void
530 test_intro_point_registration(void *arg)
532 hs_circuitmap_ht *the_hs_circuitmap = NULL;
534 or_circuit_t *intro_circ = NULL;
535 trn_cell_establish_intro_t *establish_intro_cell = NULL;
536 ed25519_public_key_t auth_key;
538 or_circuit_t *returned_intro_circ = NULL;
540 (void) arg;
542 MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);
544 hs_circuitmap_init();
546 /* Check that the circuitmap is currently empty */
548 the_hs_circuitmap = get_hs_circuitmap();
549 tt_assert(the_hs_circuitmap);
550 tt_int_op(0, OP_EQ, HT_SIZE(the_hs_circuitmap));
551 /* Do a circuitmap query in any case */
552 returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
553 tt_ptr_op(returned_intro_circ, OP_EQ, NULL);
556 /* Create a v3 intro point */
558 intro_circ = or_circuit_new(0, NULL);
559 tt_assert(intro_circ);
560 establish_intro_cell = helper_establish_intro_v3(intro_circ);
562 /* Check that the intro point was registered on the HS circuitmap */
563 the_hs_circuitmap = get_hs_circuitmap();
564 tt_assert(the_hs_circuitmap);
565 tt_int_op(1, OP_EQ, HT_SIZE(the_hs_circuitmap));
566 get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
567 establish_intro_cell);
568 returned_intro_circ =
569 hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
570 tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ);
573 /* XXX Continue test and try to register a second v3 intro point with the
574 * same auth key. Make sure that old intro circuit gets closed. */
576 done:
577 circuit_free_(TO_CIRCUIT(intro_circ));
578 trn_cell_establish_intro_free(establish_intro_cell);
579 test_circuitmap_free_all();
581 UNMOCK(hs_intro_send_intro_established_cell);
584 static void
585 test_introduce1_suitable_circuit(void *arg)
587 int ret;
588 or_circuit_t *circ = NULL;
590 (void) arg;
592 /* Valid suitable circuit. */
594 circ = or_circuit_new(0, NULL);
595 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
596 ret = circuit_is_suitable_for_introduce1(circ);
597 circuit_free_(TO_CIRCUIT(circ));
598 tt_int_op(ret, OP_EQ, 1);
601 /* Test if the circuit purpose safeguard works correctly. */
603 circ = or_circuit_new(0, NULL);
604 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
605 ret = circuit_is_suitable_for_introduce1(circ);
606 circuit_free_(TO_CIRCUIT(circ));
607 tt_int_op(ret, OP_EQ, 0);
610 /* Test the non-edge circuit safeguard works correctly. */
612 circ = or_circuit_new(0, NULL);
613 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
614 /* Bogus pointer, the check is against NULL on n_chan. */
615 circ->base_.n_chan = (channel_t *) circ;
616 ret = circuit_is_suitable_for_introduce1(circ);
617 circuit_free_(TO_CIRCUIT(circ));
618 tt_int_op(ret, OP_EQ, 0);
621 /* Mangle the circuit a bit more so see if our only one INTRODUCE1 cell
622 * limit works correctly. */
624 circ = or_circuit_new(0, NULL);
625 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
626 circ->already_received_introduce1 = 1;
627 ret = circuit_is_suitable_for_introduce1(circ);
628 circuit_free_(TO_CIRCUIT(circ));
629 tt_int_op(ret, OP_EQ, 0);
632 done:
636 static void
637 test_introduce1_is_legacy(void *arg)
639 int ret;
640 uint8_t request[256];
642 (void) arg;
644 /* For a cell to be considered legacy, according to the specification, the
645 * first 20 bytes MUST BE non-zero else it's a v3 cell. */
646 memset(request, 'a', DIGEST_LEN);
647 memset(request + DIGEST_LEN, 0, sizeof(request) - DIGEST_LEN);
648 ret = introduce1_cell_is_legacy(request);
649 tt_int_op(ret, OP_EQ, 1);
651 /* This is a NON legacy cell. */
652 memset(request, 0, DIGEST_LEN);
653 memset(request + DIGEST_LEN, 'a', sizeof(request) - DIGEST_LEN);
654 ret = introduce1_cell_is_legacy(request);
655 tt_int_op(ret, OP_EQ, 0);
657 done:
661 static void
662 test_introduce1_validation(void *arg)
664 int ret;
665 trn_cell_introduce1_t *cell = NULL;
667 (void) arg;
669 /* Create our decoy cell that we'll modify as we go to test the validation
670 * function of that parsed cell. */
671 cell = helper_create_introduce1_cell();
672 tt_assert(cell);
674 /* It should NOT be a legacy cell which will trigger a BUG(). */
675 memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id));
676 tor_capture_bugs_(1);
677 ret = validate_introduce1_parsed_cell(cell);
678 tor_end_capture_bugs_();
679 tt_int_op(ret, OP_EQ, -1);
680 /* Reset legacy ID and make sure it's correct. */
681 memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id));
682 ret = validate_introduce1_parsed_cell(cell);
683 tt_int_op(ret, OP_EQ, 0);
685 /* Non existing auth key type. */
686 cell->auth_key_type = 42;
687 ret = validate_introduce1_parsed_cell(cell);
688 tt_int_op(ret, OP_EQ, -1);
689 /* Reset is to correct value and make sure it's correct. */
690 cell->auth_key_type = TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519;
691 ret = validate_introduce1_parsed_cell(cell);
692 tt_int_op(ret, OP_EQ, 0);
694 /* Really bad key length. */
695 cell->auth_key_len = 0;
696 ret = validate_introduce1_parsed_cell(cell);
697 tt_int_op(ret, OP_EQ, -1);
698 cell->auth_key_len = UINT16_MAX;
699 ret = validate_introduce1_parsed_cell(cell);
700 tt_int_op(ret, OP_EQ, -1);
701 /* Correct size, let's try that. */
702 cell->auth_key_len = sizeof(ed25519_public_key_t);
703 ret = validate_introduce1_parsed_cell(cell);
704 tt_int_op(ret, OP_EQ, 0);
705 /* Set an invalid size of the auth key buffer. */
706 trn_cell_introduce1_setlen_auth_key(cell, 3);
707 ret = validate_introduce1_parsed_cell(cell);
708 tt_int_op(ret, OP_EQ, -1);
709 /* Reset auth key buffer and make sure it works. */
710 trn_cell_introduce1_setlen_auth_key(cell, sizeof(ed25519_public_key_t));
711 ret = validate_introduce1_parsed_cell(cell);
712 tt_int_op(ret, OP_EQ, 0);
714 /* Empty encrypted section. */
715 trn_cell_introduce1_setlen_encrypted(cell, 0);
716 ret = validate_introduce1_parsed_cell(cell);
717 tt_int_op(ret, OP_EQ, -1);
718 /* Reset it to some non zero bytes and validate. */
719 trn_cell_introduce1_setlen_encrypted(cell, 1);
720 ret = validate_introduce1_parsed_cell(cell);
721 tt_int_op(ret, OP_EQ, 0);
723 done:
724 trn_cell_introduce1_free(cell);
727 static void
728 test_received_introduce1_handling(void *arg)
730 int ret;
731 uint8_t *request = NULL, buf[128];
732 trn_cell_introduce1_t *cell = NULL;
733 or_circuit_t *circ = NULL;
735 (void) arg;
737 MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
739 hs_circuitmap_init();
741 /* Too small request length. An INTRODUCE1 expect at the very least a
742 * DIGEST_LEN size. */
744 memset(buf, 0, sizeof(buf));
745 circ = helper_create_intro_circuit();
746 ret = hs_intro_received_introduce1(circ, buf, DIGEST_LEN - 1);
747 tt_int_op(ret, OP_EQ, -1);
748 circuit_free_(TO_CIRCUIT(circ));
751 /* We have a unit test only for the suitability of a circuit to receive an
752 * INTRODUCE1 cell so from now on we'll only test the handling of a cell. */
754 /* Bad request. */
756 circ = helper_create_intro_circuit();
757 uint8_t test[2]; /* Too small request. */
758 memset(test, 0, sizeof(test));
759 ret = handle_introduce1(circ, test, sizeof(test));
760 tor_free(circ->p_chan);
761 circuit_free_(TO_CIRCUIT(circ));
762 tt_int_op(ret, OP_EQ, -1);
765 /* Valid case. */
767 cell = helper_create_introduce1_cell();
768 ssize_t request_len = trn_cell_introduce1_encoded_len(cell);
769 tt_int_op((int)request_len, OP_GT, 0);
770 request = tor_malloc_zero(request_len);
771 ssize_t encoded_len =
772 trn_cell_introduce1_encode(request, request_len, cell);
773 tt_int_op((int)encoded_len, OP_GT, 0);
775 circ = helper_create_intro_circuit();
776 or_circuit_t *service_circ = helper_create_intro_circuit();
777 circuit_change_purpose(TO_CIRCUIT(service_circ),
778 CIRCUIT_PURPOSE_INTRO_POINT);
779 /* Register the circuit in the map for the auth key of the cell. */
780 ed25519_public_key_t auth_key;
781 const uint8_t *cell_auth_key =
782 trn_cell_introduce1_getconstarray_auth_key(cell);
783 memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN);
784 hs_circuitmap_register_intro_circ_v3_relay_side(service_circ, &auth_key);
785 ret = hs_intro_received_introduce1(circ, request, request_len);
786 circuit_free_(TO_CIRCUIT(circ));
787 circuit_free_(TO_CIRCUIT(service_circ));
788 tt_int_op(ret, OP_EQ, 0);
791 /* Valid legacy cell. */
793 tor_free(request);
794 trn_cell_introduce1_free(cell);
795 cell = helper_create_introduce1_cell();
796 uint8_t *legacy_key_id = trn_cell_introduce1_getarray_legacy_key_id(cell);
797 memset(legacy_key_id, 'a', DIGEST_LEN);
798 /* Add an arbitrary amount of data for the payload of a v2 cell. */
799 size_t request_len = trn_cell_introduce1_encoded_len(cell) + 256;
800 tt_size_op(request_len, OP_GT, 0);
801 request = tor_malloc_zero(request_len + 256);
802 ssize_t encoded_len =
803 trn_cell_introduce1_encode(request, request_len, cell);
804 tt_int_op((int)encoded_len, OP_GT, 0);
806 circ = helper_create_intro_circuit();
807 or_circuit_t *service_circ = helper_create_intro_circuit();
808 circuit_change_purpose(TO_CIRCUIT(service_circ),
809 CIRCUIT_PURPOSE_INTRO_POINT);
810 /* Register the circuit in the map for the auth key of the cell. */
811 uint8_t token[REND_TOKEN_LEN];
812 memcpy(token, legacy_key_id, sizeof(token));
813 hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token);
814 ret = hs_intro_received_introduce1(circ, request, request_len);
815 circuit_free_(TO_CIRCUIT(circ));
816 circuit_free_(TO_CIRCUIT(service_circ));
817 tt_int_op(ret, OP_EQ, 0);
820 done:
821 trn_cell_introduce1_free(cell);
822 tor_free(request);
823 hs_circuitmap_free_all();
824 UNMOCK(relay_send_command_from_edge_);
827 struct testcase_t hs_intropoint_tests[] = {
828 { "intro_point_registration",
829 test_intro_point_registration, TT_FORK, NULL, NULL },
831 { "receive_establish_intro_wrong_keytype",
832 test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL },
834 { "receive_establish_intro_wrong_keytype2",
835 test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL },
837 { "receive_establish_intro_wrong_purpose",
838 test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL },
840 { "receive_establish_intro_wrong_sig",
841 test_establish_intro_wrong_sig, TT_FORK, NULL, NULL },
843 { "receive_establish_intro_wrong_sig_len",
844 test_establish_intro_wrong_sig_len, TT_FORK, NULL, NULL },
846 { "receive_establish_intro_wrong_auth_key_len",
847 test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, NULL },
849 { "receive_establish_intro_wrong_mac",
850 test_establish_intro_wrong_mac, TT_FORK, NULL, NULL },
852 { "introduce1_suitable_circuit",
853 test_introduce1_suitable_circuit, TT_FORK, NULL, NULL },
855 { "introduce1_is_legacy",
856 test_introduce1_is_legacy, TT_FORK, NULL, NULL },
858 { "introduce1_validation",
859 test_introduce1_validation, TT_FORK, NULL, NULL },
861 { "received_introduce1_handling",
862 test_received_introduce1_handling, TT_FORK, NULL, NULL },
864 END_OF_TESTCASES