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