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