Merge branch 'maint-0.4.0'
[tor.git] / src / test / test_hs_intropoint.c
blobb7163c5c13eed63cff3a1d63d50efcaa929c4f1d
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);
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);
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 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: Send a well-formed v2 ESTABLISH_INTRO cell to
510 * <b>intro_circ</b>. Return the public key advertised in the cell. */
511 static crypto_pk_t *
512 helper_establish_intro_v2(or_circuit_t *intro_circ)
514 crypto_pk_t *key1 = NULL;
515 int retval;
516 uint8_t cell_body[RELAY_PAYLOAD_SIZE];
517 ssize_t cell_len = 0;
518 char circ_nonce[DIGEST_LEN] = {0};
520 tt_assert(intro_circ);
522 /* Prepare the circuit for the incoming ESTABLISH_INTRO */
523 crypto_rand(circ_nonce, sizeof(circ_nonce));
524 helper_prepare_circ_for_intro(intro_circ, circ_nonce);
526 /* Send legacy establish_intro */
527 key1 = pk_generate(0);
529 /* Use old circ_nonce why not */
530 cell_len = rend_service_encode_establish_intro_cell(
531 (char*)cell_body,
532 sizeof(cell_body), key1,
533 circ_nonce);
534 tt_int_op(cell_len, OP_GT, 0);
536 /* Receive legacy establish_intro */
537 retval = hs_intro_received_establish_intro(intro_circ,
538 cell_body, (size_t) cell_len);
539 tt_int_op(retval, OP_EQ, 0);
541 done:
542 return key1;
545 /* Helper function: test circuitmap free_all function outside of
546 * test_intro_point_registration to prevent Coverity from seeing a
547 * double free if the assertion hypothetically fails.
549 static void
550 test_circuitmap_free_all(void)
552 hs_circuitmap_ht *the_hs_circuitmap = NULL;
554 the_hs_circuitmap = get_hs_circuitmap();
555 tt_assert(the_hs_circuitmap);
556 hs_circuitmap_free_all();
557 the_hs_circuitmap = get_hs_circuitmap();
558 tt_ptr_op(the_hs_circuitmap, OP_EQ, NULL);
559 done:
563 /** Successfully register a v2 intro point and a v3 intro point. Ensure that HS
564 * circuitmap is maintained properly. */
565 static void
566 test_intro_point_registration(void *arg)
568 int retval;
569 hs_circuitmap_ht *the_hs_circuitmap = NULL;
571 or_circuit_t *intro_circ = NULL;
572 trn_cell_establish_intro_t *establish_intro_cell = NULL;
573 ed25519_public_key_t auth_key;
575 crypto_pk_t *legacy_auth_key = NULL;
576 or_circuit_t *legacy_intro_circ = NULL;
578 or_circuit_t *returned_intro_circ = NULL;
580 (void) arg;
582 MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);
584 hs_circuitmap_init();
586 /* Check that the circuitmap is currently empty */
588 the_hs_circuitmap = get_hs_circuitmap();
589 tt_assert(the_hs_circuitmap);
590 tt_int_op(0, OP_EQ, HT_SIZE(the_hs_circuitmap));
591 /* Do a circuitmap query in any case */
592 returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
593 tt_ptr_op(returned_intro_circ, OP_EQ, NULL);
596 /* Create a v3 intro point */
598 intro_circ = or_circuit_new(0, NULL);
599 tt_assert(intro_circ);
600 establish_intro_cell = helper_establish_intro_v3(intro_circ);
602 /* Check that the intro point was registered on the HS circuitmap */
603 the_hs_circuitmap = get_hs_circuitmap();
604 tt_assert(the_hs_circuitmap);
605 tt_int_op(1, OP_EQ, HT_SIZE(the_hs_circuitmap));
606 get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
607 establish_intro_cell);
608 returned_intro_circ =
609 hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
610 tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ);
613 /* Create a v2 intro point */
615 char key_digest[DIGEST_LEN];
617 legacy_intro_circ = or_circuit_new(1, NULL);
618 tt_assert(legacy_intro_circ);
619 legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ);
620 tt_assert(legacy_auth_key);
622 /* Check that the circuitmap now has two elements */
623 the_hs_circuitmap = get_hs_circuitmap();
624 tt_assert(the_hs_circuitmap);
625 tt_int_op(2, OP_EQ, HT_SIZE(the_hs_circuitmap));
627 /* Check that the new element is our legacy intro circuit. */
628 retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
629 tt_int_op(retval, OP_EQ, 0);
630 returned_intro_circ =
631 hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest);
632 tt_ptr_op(legacy_intro_circ, OP_EQ, returned_intro_circ);
635 /* XXX Continue test and try to register a second v3 intro point with the
636 * same auth key. Make sure that old intro circuit gets closed. */
638 done:
639 crypto_pk_free(legacy_auth_key);
640 circuit_free_(TO_CIRCUIT(intro_circ));
641 circuit_free_(TO_CIRCUIT(legacy_intro_circ));
642 trn_cell_establish_intro_free(establish_intro_cell);
643 test_circuitmap_free_all();
645 UNMOCK(hs_intro_send_intro_established_cell);
648 static void
649 test_introduce1_suitable_circuit(void *arg)
651 int ret;
652 or_circuit_t *circ = NULL;
654 (void) arg;
656 /* Valid suitable circuit. */
658 circ = or_circuit_new(0, NULL);
659 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
660 ret = circuit_is_suitable_for_introduce1(circ);
661 circuit_free_(TO_CIRCUIT(circ));
662 tt_int_op(ret, OP_EQ, 1);
665 /* Test if the circuit purpose safeguard works correctly. */
667 circ = or_circuit_new(0, NULL);
668 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
669 ret = circuit_is_suitable_for_introduce1(circ);
670 circuit_free_(TO_CIRCUIT(circ));
671 tt_int_op(ret, OP_EQ, 0);
674 /* Test the non-edge circuit safeguard works correctly. */
676 circ = or_circuit_new(0, NULL);
677 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
678 /* Bogus pointer, the check is against NULL on n_chan. */
679 circ->base_.n_chan = (channel_t *) circ;
680 ret = circuit_is_suitable_for_introduce1(circ);
681 circuit_free_(TO_CIRCUIT(circ));
682 tt_int_op(ret, OP_EQ, 0);
685 /* Mangle the circuit a bit more so see if our only one INTRODUCE1 cell
686 * limit works correctly. */
688 circ = or_circuit_new(0, NULL);
689 circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
690 circ->already_received_introduce1 = 1;
691 ret = circuit_is_suitable_for_introduce1(circ);
692 circuit_free_(TO_CIRCUIT(circ));
693 tt_int_op(ret, OP_EQ, 0);
696 done:
700 static void
701 test_introduce1_is_legacy(void *arg)
703 int ret;
704 uint8_t request[256];
706 (void) arg;
708 /* For a cell to be considered legacy, according to the specification, the
709 * first 20 bytes MUST BE non-zero else it's a v3 cell. */
710 memset(request, 'a', DIGEST_LEN);
711 memset(request + DIGEST_LEN, 0, sizeof(request) - DIGEST_LEN);
712 ret = introduce1_cell_is_legacy(request);
713 tt_int_op(ret, OP_EQ, 1);
715 /* This is a NON legacy cell. */
716 memset(request, 0, DIGEST_LEN);
717 memset(request + DIGEST_LEN, 'a', sizeof(request) - DIGEST_LEN);
718 ret = introduce1_cell_is_legacy(request);
719 tt_int_op(ret, OP_EQ, 0);
721 done:
725 static void
726 test_introduce1_validation(void *arg)
728 int ret;
729 trn_cell_introduce1_t *cell = NULL;
731 (void) arg;
733 /* Create our decoy cell that we'll modify as we go to test the validation
734 * function of that parsed cell. */
735 cell = helper_create_introduce1_cell();
736 tt_assert(cell);
738 /* It should NOT be a legacy cell which will trigger a BUG(). */
739 memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id));
740 tor_capture_bugs_(1);
741 ret = validate_introduce1_parsed_cell(cell);
742 tor_end_capture_bugs_();
743 tt_int_op(ret, OP_EQ, -1);
744 /* Reset legacy ID and make sure it's correct. */
745 memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id));
746 ret = validate_introduce1_parsed_cell(cell);
747 tt_int_op(ret, OP_EQ, 0);
749 /* Non existing auth key type. */
750 cell->auth_key_type = 42;
751 ret = validate_introduce1_parsed_cell(cell);
752 tt_int_op(ret, OP_EQ, -1);
753 /* Reset is to correct value and make sure it's correct. */
754 cell->auth_key_type = HS_INTRO_AUTH_KEY_TYPE_ED25519;
755 ret = validate_introduce1_parsed_cell(cell);
756 tt_int_op(ret, OP_EQ, 0);
758 /* Really bad key length. */
759 cell->auth_key_len = 0;
760 ret = validate_introduce1_parsed_cell(cell);
761 tt_int_op(ret, OP_EQ, -1);
762 cell->auth_key_len = UINT16_MAX;
763 ret = validate_introduce1_parsed_cell(cell);
764 tt_int_op(ret, OP_EQ, -1);
765 /* Correct size, let's try that. */
766 cell->auth_key_len = sizeof(ed25519_public_key_t);
767 ret = validate_introduce1_parsed_cell(cell);
768 tt_int_op(ret, OP_EQ, 0);
769 /* Set an invalid size of the auth key buffer. */
770 trn_cell_introduce1_setlen_auth_key(cell, 3);
771 ret = validate_introduce1_parsed_cell(cell);
772 tt_int_op(ret, OP_EQ, -1);
773 /* Reset auth key buffer and make sure it works. */
774 trn_cell_introduce1_setlen_auth_key(cell, sizeof(ed25519_public_key_t));
775 ret = validate_introduce1_parsed_cell(cell);
776 tt_int_op(ret, OP_EQ, 0);
778 /* Empty encrypted section. */
779 trn_cell_introduce1_setlen_encrypted(cell, 0);
780 ret = validate_introduce1_parsed_cell(cell);
781 tt_int_op(ret, OP_EQ, -1);
782 /* Reset it to some non zero bytes and validate. */
783 trn_cell_introduce1_setlen_encrypted(cell, 1);
784 ret = validate_introduce1_parsed_cell(cell);
785 tt_int_op(ret, OP_EQ, 0);
787 done:
788 trn_cell_introduce1_free(cell);
791 static void
792 test_received_introduce1_handling(void *arg)
794 int ret;
795 uint8_t *request = NULL, buf[128];
796 trn_cell_introduce1_t *cell = NULL;
797 or_circuit_t *circ = NULL;
799 (void) arg;
801 MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
803 hs_circuitmap_init();
805 /* Too small request length. An INTRODUCE1 expect at the very least a
806 * DIGEST_LEN size. */
808 memset(buf, 0, sizeof(buf));
809 circ = helper_create_intro_circuit();
810 ret = hs_intro_received_introduce1(circ, buf, DIGEST_LEN - 1);
811 tt_int_op(ret, OP_EQ, -1);
812 circuit_free_(TO_CIRCUIT(circ));
815 /* We have a unit test only for the suitability of a circuit to receive an
816 * INTRODUCE1 cell so from now on we'll only test the handling of a cell. */
818 /* Bad request. */
820 circ = helper_create_intro_circuit();
821 uint8_t test[2]; /* Too small request. */
822 memset(test, 0, sizeof(test));
823 ret = handle_introduce1(circ, test, sizeof(test));
824 tor_free(circ->p_chan);
825 circuit_free_(TO_CIRCUIT(circ));
826 tt_int_op(ret, OP_EQ, -1);
829 /* Valid case. */
831 cell = helper_create_introduce1_cell();
832 ssize_t request_len = trn_cell_introduce1_encoded_len(cell);
833 tt_int_op((int)request_len, OP_GT, 0);
834 request = tor_malloc_zero(request_len);
835 ssize_t encoded_len =
836 trn_cell_introduce1_encode(request, request_len, cell);
837 tt_int_op((int)encoded_len, OP_GT, 0);
839 circ = helper_create_intro_circuit();
840 or_circuit_t *service_circ = helper_create_intro_circuit();
841 circuit_change_purpose(TO_CIRCUIT(service_circ),
842 CIRCUIT_PURPOSE_INTRO_POINT);
843 /* Register the circuit in the map for the auth key of the cell. */
844 ed25519_public_key_t auth_key;
845 const uint8_t *cell_auth_key =
846 trn_cell_introduce1_getconstarray_auth_key(cell);
847 memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN);
848 hs_circuitmap_register_intro_circ_v3_relay_side(service_circ, &auth_key);
849 ret = hs_intro_received_introduce1(circ, request, request_len);
850 circuit_free_(TO_CIRCUIT(circ));
851 circuit_free_(TO_CIRCUIT(service_circ));
852 tt_int_op(ret, OP_EQ, 0);
855 /* Valid legacy cell. */
857 tor_free(request);
858 trn_cell_introduce1_free(cell);
859 cell = helper_create_introduce1_cell();
860 uint8_t *legacy_key_id = trn_cell_introduce1_getarray_legacy_key_id(cell);
861 memset(legacy_key_id, 'a', DIGEST_LEN);
862 /* Add an arbitrary amount of data for the payload of a v2 cell. */
863 size_t request_len = trn_cell_introduce1_encoded_len(cell) + 256;
864 tt_size_op(request_len, OP_GT, 0);
865 request = tor_malloc_zero(request_len + 256);
866 ssize_t encoded_len =
867 trn_cell_introduce1_encode(request, request_len, cell);
868 tt_int_op((int)encoded_len, OP_GT, 0);
870 circ = helper_create_intro_circuit();
871 or_circuit_t *service_circ = helper_create_intro_circuit();
872 circuit_change_purpose(TO_CIRCUIT(service_circ),
873 CIRCUIT_PURPOSE_INTRO_POINT);
874 /* Register the circuit in the map for the auth key of the cell. */
875 uint8_t token[REND_TOKEN_LEN];
876 memcpy(token, legacy_key_id, sizeof(token));
877 hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token);
878 ret = hs_intro_received_introduce1(circ, request, request_len);
879 circuit_free_(TO_CIRCUIT(circ));
880 circuit_free_(TO_CIRCUIT(service_circ));
881 tt_int_op(ret, OP_EQ, 0);
884 done:
885 trn_cell_introduce1_free(cell);
886 tor_free(request);
887 hs_circuitmap_free_all();
888 UNMOCK(relay_send_command_from_edge_);
891 struct testcase_t hs_intropoint_tests[] = {
892 { "intro_point_registration",
893 test_intro_point_registration, TT_FORK, NULL, NULL },
895 { "receive_establish_intro_wrong_keytype",
896 test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL },
898 { "receive_establish_intro_wrong_keytype2",
899 test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL },
901 { "receive_establish_intro_wrong_purpose",
902 test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL },
904 { "receive_establish_intro_wrong_sig",
905 test_establish_intro_wrong_sig, TT_FORK, NULL, NULL },
907 { "receive_establish_intro_wrong_sig_len",
908 test_establish_intro_wrong_sig_len, TT_FORK, NULL, NULL },
910 { "receive_establish_intro_wrong_auth_key_len",
911 test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, NULL },
913 { "receive_establish_intro_wrong_mac",
914 test_establish_intro_wrong_mac, TT_FORK, NULL, NULL },
916 { "introduce1_suitable_circuit",
917 test_introduce1_suitable_circuit, TT_FORK, NULL, NULL },
919 { "introduce1_is_legacy",
920 test_introduce1_is_legacy, TT_FORK, NULL, NULL },
922 { "introduce1_validation",
923 test_introduce1_validation, TT_FORK, NULL, NULL },
925 { "received_introduce1_handling",
926 test_received_introduce1_handling, TT_FORK, NULL, NULL },
928 END_OF_TESTCASES