test_hs_client.c (52553B)
1 /* Copyright (c) 2016-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file test_hs_client.c 6 * \brief Test prop224 HS client functionality. 7 */ 8 9 #define CONFIG_PRIVATE 10 #define CRYPTO_PRIVATE 11 #define MAINLOOP_PRIVATE 12 #define HS_CLIENT_PRIVATE 13 #define CHANNEL_OBJECT_PRIVATE 14 #define CIRCUITBUILD_PRIVATE 15 #define CIRCUITLIST_PRIVATE 16 #define CONNECTION_PRIVATE 17 #define CRYPT_PATH_PRIVATE 18 #define TOR_CONGESTION_CONTROL_COMMON_PRIVATE 19 20 #include "test/test.h" 21 #include "test/test_helpers.h" 22 #include "test/log_test_helpers.h" 23 #include "test/hs_test_helpers.h" 24 25 #include "app/config/config.h" 26 #include "lib/crypt_ops/crypto_cipher.h" 27 #include "lib/crypt_ops/crypto_dh.h" 28 #include "lib/crypt_ops/crypto_rand.h" 29 #include "core/or/channeltls.h" 30 #include "feature/dircommon/directory.h" 31 #include "core/mainloop/mainloop.h" 32 #include "feature/nodelist/nodelist.h" 33 #include "feature/nodelist/routerset.h" 34 35 #include "feature/hs/hs_circuit.h" 36 #include "feature/hs/hs_circuitmap.h" 37 #include "feature/hs/hs_client.h" 38 #include "feature/hs/hs_config.h" 39 #include "feature/hs/hs_ident.h" 40 #include "feature/hs/hs_cache.h" 41 #include "core/or/circuitlist.h" 42 #include "core/or/circuitbuild.h" 43 #include "core/or/extendinfo.h" 44 #include "core/mainloop/connection.h" 45 #include "core/or/connection_edge.h" 46 #include "feature/nodelist/networkstatus.h" 47 48 #include "core/or/cpath_build_state_st.h" 49 #include "core/or/crypt_path_st.h" 50 #include "core/or/crypt_path.h" 51 #include "feature/dircommon/dir_connection_st.h" 52 #include "core/or/entry_connection_st.h" 53 #include "core/or/extend_info_st.h" 54 #include "feature/nodelist/networkstatus_st.h" 55 #include "core/or/origin_circuit_st.h" 56 #include "core/or/socks_request_st.h" 57 58 #include "core/or/congestion_control_st.h" 59 #include "core/or/congestion_control_common.h" 60 61 static int 62 mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn) 63 { 64 (void) ap_conn; 65 return 0; 66 } 67 68 static networkstatus_t mock_ns; 69 70 /* Always return NULL. */ 71 static networkstatus_t * 72 mock_networkstatus_get_reasonably_live_consensus_false(time_t now, int flavor) 73 { 74 (void) now; 75 (void) flavor; 76 return NULL; 77 } 78 79 static networkstatus_t * 80 mock_networkstatus_get_reasonably_live_consensus(time_t now, int flavor) 81 { 82 (void) now; 83 (void) flavor; 84 return &mock_ns; 85 } 86 87 static int 88 mock_write_str_to_file(const char *path, const char *str, int bin) 89 { 90 (void) bin; 91 (void) path; 92 (void) str; 93 return 0; 94 } 95 96 static or_options_t mocked_options; 97 98 static const or_options_t * 99 mock_get_options(void) 100 { 101 return &mocked_options; 102 } 103 104 static int 105 helper_config_client(const char *conf, int validate_only) 106 { 107 int ret = 0; 108 or_options_t *options = NULL; 109 tt_assert(conf); 110 options = helper_parse_options(conf); 111 tt_assert(options); 112 ret = hs_config_client_auth_all(options, validate_only); 113 done: 114 or_options_free(options); 115 return ret; 116 } 117 118 static void 119 helper_add_random_client_auth(const ed25519_public_key_t *service_pk) 120 { 121 char *conf = NULL; 122 #define conf_fmt "ClientOnionAuthDir %s\n" 123 tor_asprintf(&conf, conf_fmt, get_fname("auth_keys")); 124 #undef conf_fmt 125 helper_config_client(conf, 0); 126 tor_free(conf); 127 128 digest256map_t *client_auths = get_hs_client_auths_map(); 129 hs_client_service_authorization_t *auth = 130 tor_malloc_zero(sizeof(hs_client_service_authorization_t)); 131 curve25519_secret_key_generate(&auth->enc_seckey, 0); 132 hs_build_address(service_pk, HS_VERSION_THREE, auth->onion_address); 133 digest256map_set(client_auths, service_pk->pubkey, auth); 134 } 135 136 /* Test helper function: Setup a circuit and a stream with the same hidden 137 * service destination, and put them in <b>circ_out</b> and 138 * <b>conn_out</b>. Make the stream wait for circuits to be established to the 139 * hidden service. */ 140 static int 141 helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out, 142 connection_t **conn_out) 143 { 144 channel_tls_t *n_chan=NULL; 145 origin_circuit_t *or_circ = NULL; 146 connection_t *conn = NULL; 147 ed25519_public_key_t service_pk; 148 149 /* Make a dummy connection stream and make it wait for our circuit */ 150 conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT, 151 CONN_TYPE_AP /* ??? */, 152 0); 153 /* prop224: Setup hs conn identifier on the stream */ 154 ed25519_secret_key_t sk; 155 tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0)); 156 tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk)); 157 158 /* Setup hs_conn_identifier of stream */ 159 TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk); 160 161 /* Make it wait for circuit */ 162 connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn)); 163 164 /* This is needed to silence a BUG warning from 165 connection_edge_update_circuit_isolation() */ 166 TO_ENTRY_CONN(conn)->original_dest_address = 167 tor_strdup(TO_ENTRY_CONN(conn)->socks_request->address); 168 169 /****************************************************/ 170 171 /* Now make dummy circuit */ 172 or_circ = origin_circuit_new(); 173 174 or_circ->base_.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED; 175 176 or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); 177 or_circ->build_state->is_internal = 1; 178 179 /* prop224: Setup hs ident on the circuit */ 180 or_circ->hs_ident = hs_ident_circuit_new(&service_pk); 181 or_circ->hs_ident->intro_auth_pk.pubkey[0] = 42; 182 183 TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN; 184 185 /* fake n_chan */ 186 n_chan = tor_malloc_zero(sizeof(channel_tls_t)); 187 n_chan->base_.global_identifier = 1; 188 or_circ->base_.n_chan = &(n_chan->base_); 189 190 *circ_out = or_circ; 191 *conn_out = conn; 192 193 return 0; 194 195 done: 196 /* something failed */ 197 return -1; 198 } 199 200 /* Test: Ensure that setting up v3 rendezvous circuits works correctly. */ 201 static void 202 test_e2e_rend_circuit_setup(void *arg) 203 { 204 uint8_t ntor_key_seed[DIGEST256_LEN] = {0}; 205 origin_circuit_t *or_circ = NULL; 206 int retval; 207 connection_t *conn = NULL; 208 209 (void) arg; 210 211 /** In this test we create a prop224 v3 HS stream and a circuit with the same 212 * hidden service destination. We make the stream wait for circuits to be 213 * established to the hidden service, and then we complete the circuit using 214 * the hs_circuit_setup_e2e_rend_circ() function. We then check that the 215 * end-to-end cpath was setup correctly and that the stream was attached to 216 * the circuit as expected. */ 217 218 MOCK(connection_ap_handshake_send_begin, 219 mock_connection_ap_handshake_send_begin); 220 221 /* Setup */ 222 retval = helper_get_circ_and_stream_for_test(&or_circ, &conn); 223 tt_int_op(retval, OP_EQ, 0); 224 tt_assert(or_circ); 225 tt_assert(conn); 226 227 /* Check number of hops: There should be no hops yet to this circ */ 228 retval = cpath_get_n_hops(&or_circ->cpath); 229 tt_int_op(retval, OP_EQ, 0); 230 tt_ptr_op(or_circ->cpath, OP_EQ, NULL); 231 232 /* Check that our stream is not attached on any circuits */ 233 tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, NULL); 234 235 /**********************************************/ 236 237 /* Setup the circuit */ 238 retval = hs_circuit_setup_e2e_rend_circ(or_circ, ntor_key_seed, 239 sizeof(ntor_key_seed), 0); 240 tt_int_op(retval, OP_EQ, 0); 241 242 /**********************************************/ 243 244 /* See that a hop was added to the circuit's cpath */ 245 retval = cpath_get_n_hops(&or_circ->cpath); 246 tt_int_op(retval, OP_EQ, 1); 247 248 /* Check that the crypt path has prop224 algorithm parameters */ 249 tt_int_op(crypto_digest_get_algorithm( 250 or_circ->cpath->pvt_crypto.c.tor1.f_digest), 251 OP_EQ, DIGEST_SHA3_256); 252 tt_int_op(crypto_digest_get_algorithm( 253 or_circ->cpath->pvt_crypto.c.tor1.b_digest), 254 OP_EQ, DIGEST_SHA3_256); 255 tt_assert(or_circ->cpath->pvt_crypto.c.tor1.f_crypto); 256 tt_assert(or_circ->cpath->pvt_crypto.c.tor1.b_crypto); 257 258 /* Ensure that circ purpose was changed */ 259 tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED); 260 261 /* Test that stream got attached */ 262 tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ)); 263 264 done: 265 connection_free_minimal(conn); 266 if (or_circ) 267 tor_free(TO_CIRCUIT(or_circ)->n_chan); 268 circuit_free_(TO_CIRCUIT(or_circ)); 269 } 270 271 /** Test client logic for picking intro points from a descriptor. Also test how 272 * ExcludeNodes and intro point failures affect picking intro points. */ 273 static void 274 test_client_pick_intro(void *arg) 275 { 276 int ret; 277 ed25519_keypair_t service_kp; 278 hs_descriptor_t *desc = NULL; 279 280 MOCK(networkstatus_get_reasonably_live_consensus, 281 mock_networkstatus_get_reasonably_live_consensus); 282 283 (void) arg; 284 285 hs_init(); 286 287 /* Generate service keypair */ 288 tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); 289 290 /* Set time */ 291 ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", 292 &mock_ns.valid_after); 293 tt_int_op(ret, OP_EQ, 0); 294 ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", 295 &mock_ns.fresh_until); 296 tt_int_op(ret, OP_EQ, 0); 297 298 update_approx_time(mock_ns.fresh_until-10); 299 time_t now = approx_time(); 300 301 /* Test logic: 302 * 303 * 1) Add our desc with intro points to the HS cache. 304 * 305 * 2) Mark all descriptor intro points except _the chosen one_ as 306 * failed. Then query the desc to get a random intro: check that we got 307 * _the chosen one_. Then fail the chosen one as well, and see that no 308 * intros are returned. 309 * 310 * 3) Then clean the intro state cache and get an intro point. 311 * 312 * 4) Try fetching an intro with the wrong service key: shouldn't work 313 * 314 * 5) Set StrictNodes and put all our intro points in ExcludeNodes: see that 315 * nothing is returned. 316 */ 317 318 /* 1) Add desc to HS cache */ 319 { 320 char *encoded = NULL; 321 desc = hs_helper_build_hs_desc_with_ip(&service_kp); 322 ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &encoded); 323 tt_int_op(ret, OP_EQ, 0); 324 tt_assert(encoded); 325 326 /* store it */ 327 ret = hs_cache_store_as_client(encoded, &service_kp.pubkey); 328 tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); 329 330 /* fetch it to make sure it works */ 331 const hs_descriptor_t *fetched_desc = 332 hs_cache_lookup_as_client(&service_kp.pubkey); 333 tt_assert(fetched_desc); 334 tt_mem_op(fetched_desc->subcredential.subcred, 335 OP_EQ, desc->subcredential.subcred, 336 SUBCRED_LEN); 337 tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential.subcred, 338 DIGEST256_LEN)); 339 tor_free(encoded); 340 } 341 342 /* 2) Mark all intro points except _the chosen one_ as failed. Then query the 343 * desc and get a random intro: check that we got _the chosen one_. */ 344 { 345 /* Tell hs_get_extend_info_from_lspecs() to skip the private address check. 346 */ 347 get_options_mutable()->ExtendAllowPrivateAddresses = 1; 348 /* Pick the chosen intro point and get its ei */ 349 hs_desc_intro_point_t *chosen_intro_point = 350 smartlist_get(desc->encrypted_data.intro_points, 0); 351 extend_info_t *chosen_intro_ei = 352 desc_intro_point_to_extend_info(chosen_intro_point); 353 tt_assert(chosen_intro_point); 354 tt_assert(chosen_intro_ei); 355 356 /* Now mark all other intro points as failed */ 357 SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, 358 hs_desc_intro_point_t *, ip) { 359 /* Skip the chosen intro point */ 360 if (ip == chosen_intro_point) { 361 continue; 362 } 363 ed25519_public_key_t *intro_auth_key = &ip->auth_key_cert->signed_key; 364 hs_cache_client_intro_state_note(&service_kp.pubkey, 365 intro_auth_key, 366 INTRO_POINT_FAILURE_GENERIC); 367 } SMARTLIST_FOREACH_END(ip); 368 369 /* Try to get a random intro: Should return the chosen one! */ 370 /* (We try several times, to make sure this behavior is consistent, and to 371 * cover the different cases of client_get_random_intro().) */ 372 for (int i = 0; i < 64; ++i) { 373 extend_info_t *ip = client_get_random_intro(&service_kp.pubkey); 374 tor_assert(ip); 375 tt_assert(!fast_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN)); 376 tt_mem_op(ip->identity_digest, OP_EQ, chosen_intro_ei->identity_digest, 377 DIGEST_LEN); 378 extend_info_free(ip); 379 } 380 381 extend_info_free(chosen_intro_ei); 382 383 /* Now also mark the chosen one as failed: See that we can't get any intro 384 points anymore. */ 385 hs_cache_client_intro_state_note(&service_kp.pubkey, 386 &chosen_intro_point->auth_key_cert->signed_key, 387 INTRO_POINT_FAILURE_TIMEOUT); 388 extend_info_t *ip = client_get_random_intro(&service_kp.pubkey); 389 tor_assert(!ip); 390 } 391 392 /* 3) Clean the intro state cache and get an intro point */ 393 { 394 /* Pretend we are 5 mins in the future and order a cleanup of the intro 395 * state. This should clean up the intro point failures and allow us to get 396 * an intro. */ 397 hs_cache_client_intro_state_clean(now + 5*60); 398 399 /* Get an intro. It should work! */ 400 extend_info_t *ip = client_get_random_intro(&service_kp.pubkey); 401 tor_assert(ip); 402 extend_info_free(ip); 403 } 404 405 /* 4) Try fetching an intro with the wrong service key: shouldn't work */ 406 { 407 ed25519_keypair_t dummy_kp; 408 tt_int_op(0, OP_EQ, ed25519_keypair_generate(&dummy_kp, 0)); 409 extend_info_t *ip = client_get_random_intro(&dummy_kp.pubkey); 410 tor_assert(!ip); 411 } 412 413 /* 5) Set StrictNodes and put all our intro points in ExcludeNodes: see that 414 * nothing is returned. */ 415 { 416 get_options_mutable()->ExcludeNodes = routerset_new(); 417 get_options_mutable()->StrictNodes = 1; 418 SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, 419 hs_desc_intro_point_t *, ip) { 420 extend_info_t *intro_ei = desc_intro_point_to_extend_info(ip); 421 /* desc_intro_point_to_extend_info() doesn't return IPv6 intro points 422 * yet, because we can't extend to them. See #24404, #24451, and #24181. 423 */ 424 if (intro_ei == NULL) { 425 /* Pretend we're making a direct connection, and that we can use IPv6 426 */ 427 get_options_mutable()->ClientUseIPv6 = 1; 428 intro_ei = hs_get_extend_info_from_lspecs(ip->link_specifiers, 429 &ip->onion_key, 1); 430 tt_assert(tor_addr_family(&intro_ei->orports[0].addr) == AF_INET6); 431 } 432 tt_assert(intro_ei); 433 if (intro_ei) { 434 const char *ptr; 435 char ip_addr[TOR_ADDR_BUF_LEN]; 436 /* We need to decorate in case it is an IPv6 else routerset_parse() 437 * doesn't like it. */ 438 ptr = tor_addr_to_str(ip_addr, &intro_ei->orports[0].addr, 439 sizeof(ip_addr), 1); 440 tt_assert(ptr == ip_addr); 441 ret = routerset_parse(get_options_mutable()->ExcludeNodes, 442 ip_addr, ""); 443 tt_int_op(ret, OP_EQ, 0); 444 extend_info_free(intro_ei); 445 } 446 } SMARTLIST_FOREACH_END(ip); 447 448 extend_info_t *ip = client_get_random_intro(&service_kp.pubkey); 449 tt_assert(!ip); 450 } 451 452 done: 453 hs_descriptor_free(desc); 454 } 455 456 static int 457 mock_router_have_minimum_dir_info_false(void) 458 { 459 return 0; 460 } 461 static int 462 mock_router_have_minimum_dir_info_true(void) 463 { 464 return 1; 465 } 466 467 static hs_client_fetch_status_t 468 mock_fetch_v3_desc_error(const ed25519_public_key_t *key) 469 { 470 (void) key; 471 return HS_CLIENT_FETCH_ERROR; 472 } 473 474 static void 475 mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason, 476 int line, const char *file) 477 { 478 (void) line; 479 (void) file; 480 conn->edge_.end_reason = endreason; 481 /* This function ultimately will flag this so make sure we do also in the 482 * MOCK one so we can assess closed connections vs open ones. */ 483 conn->edge_.base_.marked_for_close = 1; 484 } 485 486 static void 487 mock_connection_mark_unattached_ap_no_close(entry_connection_t *conn, 488 int endreason, int line, 489 const char *file) 490 { 491 (void) conn; 492 (void) endreason; 493 (void) line; 494 (void) file; 495 } 496 497 static void 498 test_descriptor_fetch(void *arg) 499 { 500 int ret; 501 entry_connection_t *ec = NULL; 502 ed25519_public_key_t service_pk; 503 ed25519_secret_key_t service_sk; 504 505 (void) arg; 506 507 hs_init(); 508 memset(&service_sk, 'A', sizeof(service_sk)); 509 ret = ed25519_public_key_generate(&service_pk, &service_sk); 510 tt_int_op(ret, OP_EQ, 0); 511 512 /* Initialize this so get_voting_interval() doesn't freak out. */ 513 ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", 514 &mock_ns.valid_after); 515 tt_int_op(ret, OP_EQ, 0); 516 ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", 517 &mock_ns.fresh_until); 518 tt_int_op(ret, OP_EQ, 0); 519 520 ec = entry_connection_new(CONN_TYPE_AP, AF_INET); 521 tt_assert(ec); 522 ENTRY_TO_EDGE_CONN(ec)->hs_ident = hs_ident_edge_conn_new(&service_pk); 523 tt_assert(ENTRY_TO_EDGE_CONN(ec)->hs_ident); 524 TO_CONN(ENTRY_TO_EDGE_CONN(ec))->state = AP_CONN_STATE_RENDDESC_WAIT; 525 smartlist_add(get_connection_array(), &ec->edge_.base_); 526 527 /* 1. FetchHidServDescriptors is false so we shouldn't be able to fetch. */ 528 get_options_mutable()->FetchHidServDescriptors = 0; 529 ret = hs_client_refetch_hsdesc(&service_pk); 530 tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_NOT_ALLOWED); 531 get_options_mutable()->FetchHidServDescriptors = 1; 532 533 /* 2. We don't have a live consensus. */ 534 MOCK(networkstatus_get_reasonably_live_consensus, 535 mock_networkstatus_get_reasonably_live_consensus_false); 536 ret = hs_client_refetch_hsdesc(&service_pk); 537 UNMOCK(networkstatus_get_reasonably_live_consensus); 538 tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_MISSING_INFO); 539 540 /* From now on, return a live consensus. */ 541 MOCK(networkstatus_get_reasonably_live_consensus, 542 mock_networkstatus_get_reasonably_live_consensus); 543 544 /* 3. Not enough dir information. */ 545 MOCK(router_have_minimum_dir_info, 546 mock_router_have_minimum_dir_info_false); 547 ret = hs_client_refetch_hsdesc(&service_pk); 548 UNMOCK(router_have_minimum_dir_info); 549 tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_MISSING_INFO); 550 551 /* From now on, we do have enough directory information. */ 552 MOCK(router_have_minimum_dir_info, 553 mock_router_have_minimum_dir_info_true); 554 555 /* 4. We do have a pending directory request. */ 556 { 557 dir_connection_t *dir_conn = dir_connection_new(AF_INET); 558 dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t)); 559 TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC; 560 ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_pk); 561 smartlist_add(get_connection_array(), TO_CONN(dir_conn)); 562 ret = hs_client_refetch_hsdesc(&service_pk); 563 smartlist_remove(get_connection_array(), TO_CONN(dir_conn)); 564 connection_free_minimal(TO_CONN(dir_conn)); 565 tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_PENDING); 566 } 567 568 /* 5. We'll trigger an error on the fetch_desc_v3 and force to close all 569 * pending SOCKS request. */ 570 MOCK(router_have_minimum_dir_info, 571 mock_router_have_minimum_dir_info_true); 572 MOCK(fetch_v3_desc, mock_fetch_v3_desc_error); 573 MOCK(connection_mark_unattached_ap_, 574 mock_connection_mark_unattached_ap_); 575 ret = hs_client_refetch_hsdesc(&service_pk); 576 UNMOCK(fetch_v3_desc); 577 UNMOCK(connection_mark_unattached_ap_); 578 tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_ERROR); 579 /* The close waiting for descriptor function has been called. */ 580 tt_int_op(ec->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED); 581 582 done: 583 connection_free_minimal(ENTRY_TO_CONN(ec)); 584 UNMOCK(networkstatus_get_reasonably_live_consensus); 585 UNMOCK(router_have_minimum_dir_info); 586 hs_free_all(); 587 } 588 589 static void 590 test_auth_key_filename_is_valid(void *arg) 591 { 592 (void) arg; 593 594 /* Valid file name. */ 595 tt_assert(auth_key_filename_is_valid("a.auth_private")); 596 /* Valid file name with special character. */ 597 tt_assert(auth_key_filename_is_valid("a-.auth_private")); 598 /* Invalid extension. */ 599 tt_assert(!auth_key_filename_is_valid("a.ath_private")); 600 /* Nothing before the extension. */ 601 tt_assert(!auth_key_filename_is_valid(".auth_private")); 602 603 done: 604 ; 605 } 606 607 static void 608 test_parse_auth_file_content(void *arg) 609 { 610 hs_client_service_authorization_t *auth = NULL; 611 612 (void) arg; 613 614 /* Valid authorized client. */ 615 auth = parse_auth_file_content( 616 "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:descriptor:" 617 "x25519:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq"); 618 tt_assert(auth); 619 620 /* Wrong number of fields. */ 621 tt_assert(!parse_auth_file_content("a:b")); 622 /* Wrong auth type. */ 623 tt_assert(!parse_auth_file_content( 624 "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:x:" 625 "x25519:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq")); 626 /* Wrong key type. */ 627 tt_assert(!parse_auth_file_content( 628 "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:descriptor:" 629 "x:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq")); 630 /* Some malformed string. */ 631 tt_assert(!parse_auth_file_content("xx:descriptor:x25519:aa==")); 632 /* Bigger key than it should be */ 633 tt_assert(!parse_auth_file_content("xx:descriptor:x25519:" 634 "vjqea4jbhwwc4hto7ekyvqfbeodghbaq6nxi45hz4wr3qvhqv3yqa")); 635 /* All-zeroes key */ 636 tt_assert(!parse_auth_file_content("xx:descriptor:x25519:" 637 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); 638 639 done: 640 tor_free(auth); 641 } 642 643 static char * 644 mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out) 645 { 646 char *ret = NULL; 647 648 (void) flags; 649 (void) stat_out; 650 651 if (!strcmp(filename, get_fname("auth_keys" PATH_SEPARATOR 652 "client1.auth_private"))) { 653 ret = tor_strdup( 654 "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad:descriptor:" 655 "x25519:zdsyvn2jq534ugyiuzgjy4267jbtzcjbsgedhshzx5mforyxtryq"); 656 goto done; 657 } 658 659 if (!strcmp(filename, get_fname("auth_keys" PATH_SEPARATOR "dummy.xxx"))) { 660 ret = tor_strdup( 661 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:descriptor:" 662 "x25519:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); 663 goto done; 664 } 665 666 if (!strcmp(filename, get_fname("auth_keys" PATH_SEPARATOR 667 "client2.auth_private"))) { 668 ret = tor_strdup( 669 "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid:descriptor:" 670 "x25519:fdreqzjqso7d2ac7qscrxfl5qfpamdvgy5d6cxejcgzc3hvhurmq"); 671 goto done; 672 } 673 674 done: 675 return ret; 676 } 677 678 static int 679 mock_check_private_dir(const char *dirname, cpd_check_t check, 680 const char *effective_user) 681 { 682 (void) dirname; 683 (void) check; 684 (void) effective_user; 685 686 return 0; 687 } 688 689 static smartlist_t * 690 mock_tor_listdir(const char *dirname) 691 { 692 smartlist_t *file_list = smartlist_new(); 693 694 (void) dirname; 695 696 smartlist_add(file_list, tor_strdup("client1.auth_private")); 697 smartlist_add(file_list, tor_strdup("dummy.xxx")); 698 smartlist_add(file_list, tor_strdup("client2.auth_private")); 699 700 return file_list; 701 } 702 703 static void 704 test_config_client_authorization(void *arg) 705 { 706 int ret; 707 char *conf = NULL; 708 ed25519_public_key_t pk1, pk2; 709 digest256map_t *global_map = NULL; 710 char *key_dir = tor_strdup(get_fname("auth_keys")); 711 712 (void) arg; 713 714 MOCK(read_file_to_str, mock_read_file_to_str); 715 MOCK(tor_listdir, mock_tor_listdir); 716 MOCK(check_private_dir, mock_check_private_dir); 717 718 #define conf_fmt \ 719 "ClientOnionAuthDir %s\n" 720 721 tor_asprintf(&conf, conf_fmt, key_dir); 722 ret = helper_config_client(conf, 0); 723 tor_free(conf); 724 tt_int_op(ret, OP_EQ, 0); 725 726 #undef conf_fmt 727 728 global_map = get_hs_client_auths_map(); 729 tt_int_op(digest256map_size(global_map), OP_EQ, 2); 730 731 hs_parse_address("4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad", 732 &pk1, NULL, NULL); 733 hs_parse_address("25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid", 734 &pk2, NULL, NULL); 735 736 tt_assert(digest256map_get(global_map, pk1.pubkey)); 737 tt_assert(digest256map_get(global_map, pk2.pubkey)); 738 739 done: 740 tor_free(key_dir); 741 hs_free_all(); 742 UNMOCK(read_file_to_str); 743 UNMOCK(tor_listdir); 744 UNMOCK(check_private_dir); 745 } 746 747 static entry_connection_t * 748 helper_build_socks_connection(const ed25519_public_key_t *service_pk, 749 int conn_state) 750 { 751 entry_connection_t *socks = entry_connection_new(CONN_TYPE_AP, AF_INET); 752 ENTRY_TO_EDGE_CONN(socks)->hs_ident = hs_ident_edge_conn_new(service_pk); 753 TO_CONN(ENTRY_TO_EDGE_CONN(socks))->state = conn_state; 754 smartlist_add(get_connection_array(), &socks->edge_.base_); 755 return socks; 756 } 757 758 static void 759 test_desc_has_arrived_cleanup(void *arg) 760 { 761 /* The goal of this test is to make sure we clean up everything in between 762 * two descriptors from the same .onion. Because intro points can change 763 * from one descriptor to another, once we received a new descriptor, we 764 * need to cleanup the remaining circuits so they aren't used or selected 765 * when establishing a connection with the newly stored descriptor. 766 * 767 * This test was created because of #27410. */ 768 769 int ret; 770 char *desc_str = NULL; 771 hs_descriptor_t *desc = NULL; 772 const hs_descriptor_t *cached_desc; 773 ed25519_keypair_t signing_kp; 774 entry_connection_t *socks1 = NULL, *socks2 = NULL; 775 hs_ident_dir_conn_t hs_dir_ident; 776 dir_connection_t *dir_conn = NULL; 777 778 (void) arg; 779 780 hs_init(); 781 congestion_control_set_cc_enabled(); 782 783 MOCK(networkstatus_get_reasonably_live_consensus, 784 mock_networkstatus_get_reasonably_live_consensus); 785 MOCK(connection_mark_unattached_ap_, 786 mock_connection_mark_unattached_ap_); 787 MOCK(router_have_minimum_dir_info, 788 mock_router_have_minimum_dir_info_true); 789 790 /* Set consensus time before our time so the cache lookup can always 791 * validate that the entry is not expired. */ 792 parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", &mock_ns.valid_after); 793 parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", &mock_ns.fresh_until); 794 parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", &mock_ns.valid_until); 795 796 /* Build a descriptor for a specific .onion. */ 797 ret = ed25519_keypair_generate(&signing_kp, 0); 798 tt_int_op(ret, OP_EQ, 0); 799 desc = hs_helper_build_hs_desc_with_ip(&signing_kp); 800 tt_assert(desc); 801 ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &desc_str); 802 tt_int_op(ret, OP_EQ, 0); 803 804 /* Store in the client cache. */ 805 ret = hs_cache_store_as_client(desc_str, &signing_kp.pubkey); 806 tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); 807 cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey); 808 tt_assert(cached_desc); 809 hs_helper_desc_equal(desc, cached_desc); 810 811 /* Create two SOCKS connection for the same .onion both in the waiting for a 812 * descriptor state. */ 813 socks1 = helper_build_socks_connection(&signing_kp.pubkey, 814 AP_CONN_STATE_RENDDESC_WAIT); 815 tt_assert(socks1); 816 socks2 = helper_build_socks_connection(&signing_kp.pubkey, 817 AP_CONN_STATE_RENDDESC_WAIT); 818 tt_assert(socks2); 819 820 /* Now, we'll make the intro points in the current descriptor unusable so 821 * the hs_client_desc_has_arrived() will take the right code path that we 822 * want to test that is the fetched descriptor has bad intro points. */ 823 SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, 824 hs_desc_intro_point_t *, ip) { 825 hs_cache_client_intro_state_note(&signing_kp.pubkey, 826 &ip->auth_key_cert->signed_key, 827 INTRO_POINT_FAILURE_GENERIC); 828 } SMARTLIST_FOREACH_END(ip); 829 830 /* Simulate that a new descriptor just arrived. We should have both of our 831 * SOCKS connection to be ended with a resolved failed. */ 832 hs_ident_dir_conn_init(&signing_kp.pubkey, 833 &desc->plaintext_data.blinded_pubkey, &hs_dir_ident); 834 dir_conn = dir_connection_new(AF_INET); 835 dir_conn->hs_ident = hs_ident_dir_conn_dup(&hs_dir_ident); 836 hs_client_dir_fetch_done(dir_conn, "A reason", desc_str, 200); 837 connection_free_minimal(TO_CONN(dir_conn)); 838 tt_int_op(socks1->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED); 839 tt_int_op(socks2->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED); 840 841 /* Now let say tor cleans up the intro state cache which resets all intro 842 * point failure count. */ 843 hs_cache_client_intro_state_purge(); 844 845 /* Retrying all SOCKS which should basically do nothing since we don't have 846 * any pending SOCKS connection in AP_CONN_STATE_RENDDESC_WAIT state. */ 847 retry_all_socks_conn_waiting_for_desc(); 848 849 done: 850 connection_free_minimal(ENTRY_TO_CONN(socks1)); 851 connection_free_minimal(ENTRY_TO_CONN(socks2)); 852 hs_descriptor_free(desc); 853 tor_free(desc_str); 854 hs_free_all(); 855 856 UNMOCK(networkstatus_get_reasonably_live_consensus); 857 UNMOCK(connection_mark_unattached_ap_); 858 UNMOCK(router_have_minimum_dir_info); 859 } 860 861 static void 862 test_close_intro_circuits_new_desc(void *arg) 863 { 864 int ret; 865 ed25519_keypair_t service_kp; 866 circuit_t *circ = NULL; 867 origin_circuit_t *ocirc = NULL; 868 hs_descriptor_t *desc1 = NULL, *desc2 = NULL; 869 870 (void) arg; 871 872 hs_init(); 873 874 /* This is needed because of the client cache expiration timestamp is based 875 * on having a consensus. See cached_client_descriptor_has_expired(). */ 876 MOCK(networkstatus_get_reasonably_live_consensus, 877 mock_networkstatus_get_reasonably_live_consensus); 878 879 /* Set consensus time */ 880 parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", 881 &mock_ns.valid_after); 882 parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", 883 &mock_ns.fresh_until); 884 parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", 885 &mock_ns.valid_until); 886 887 /* Generate service keypair */ 888 tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); 889 890 /* Create and add to the global list a dummy client introduction circuits. 891 * We'll then make sure the hs_ident is attached to a dummy descriptor. */ 892 circ = dummy_origin_circuit_new(0); 893 tt_assert(circ); 894 circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING; 895 ocirc = TO_ORIGIN_CIRCUIT(circ); 896 897 /* Build a descriptor _without_ client authorization and thus not 898 * decryptable. Make sure the close circuit code path is not triggered. */ 899 { 900 char *desc_encoded = NULL; 901 uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN]; 902 curve25519_keypair_t client_kp; 903 hs_descriptor_t *desc = NULL; 904 905 tt_int_op(0, OP_EQ, curve25519_keypair_generate(&client_kp, 0)); 906 crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie)); 907 908 desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie, 909 &client_kp.pubkey, 910 &service_kp); 911 tt_assert(desc); 912 ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie, 913 &desc_encoded); 914 tt_int_op(ret, OP_EQ, 0); 915 /* Associate descriptor intro key with the dummy circuit. */ 916 const hs_desc_intro_point_t *ip = 917 smartlist_get(desc->encrypted_data.intro_points, 0); 918 tt_assert(ip); 919 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 920 ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, 921 &ip->auth_key_cert->signed_key); 922 hs_descriptor_free(desc); 923 tt_assert(desc_encoded); 924 /* Put it in the cache. Should not be decrypted since the client 925 * authorization creds were not added to the global map. */ 926 ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey); 927 tor_free(desc_encoded); 928 tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH); 929 930 /* Clean cache with a future timestamp. It will trigger the clean up and 931 * attempt to close the circuit but only if the descriptor is decryptable. 932 * Cache object should be removed and circuit untouched. */ 933 hs_cache_clean_as_client(mock_ns.valid_after + (60 * 60 * 24)); 934 tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey)); 935 936 /* Make sure the circuit still there. */ 937 tt_assert(circuit_get_next_intro_circ(NULL, true)); 938 /* Get rid of the ident, it will be replaced in the next tests. */ 939 hs_ident_circuit_free(ocirc->hs_ident); 940 } 941 942 /* Build the first descriptor and cache it. */ 943 { 944 char *encoded; 945 desc1 = hs_helper_build_hs_desc_with_ip(&service_kp); 946 tt_assert(desc1); 947 ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded); 948 tt_int_op(ret, OP_EQ, 0); 949 tt_assert(encoded); 950 951 /* Store it */ 952 ret = hs_cache_store_as_client(encoded, &service_kp.pubkey); 953 tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); 954 tor_free(encoded); 955 tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey)); 956 } 957 958 /* We'll pick one introduction point and associate it with the circuit. */ 959 { 960 const hs_desc_intro_point_t *ip = 961 smartlist_get(desc1->encrypted_data.intro_points, 0); 962 tt_assert(ip); 963 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 964 ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, 965 &ip->auth_key_cert->signed_key); 966 } 967 968 /* Before we are about to clean up the intro circuits, make sure it is 969 * actually there. */ 970 tt_assert(circuit_get_next_intro_circ(NULL, true)); 971 972 /* Build the second descriptor for the same service and cache it. */ 973 { 974 char *encoded; 975 desc2 = hs_helper_build_hs_desc_with_ip(&service_kp); 976 tt_assert(desc2); 977 tt_mem_op(&desc1->plaintext_data.signing_pubkey, OP_EQ, 978 &desc2->plaintext_data.signing_pubkey, ED25519_PUBKEY_LEN); 979 /* To replace the existing descriptor, the revision counter needs to be 980 * bigger. */ 981 desc2->plaintext_data.revision_counter = 982 desc1->plaintext_data.revision_counter + 1; 983 984 ret = hs_desc_encode_descriptor(desc2, &service_kp, NULL, &encoded); 985 tt_int_op(ret, OP_EQ, 0); 986 tt_assert(encoded); 987 988 ret = hs_cache_store_as_client(encoded, &service_kp.pubkey); 989 tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); 990 tor_free(encoded); 991 tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey)); 992 } 993 994 /* Once stored, our intro circuit should be closed because it is related to 995 * an old introduction point that doesn't exists anymore. */ 996 tt_assert(!circuit_get_next_intro_circ(NULL, true)); 997 998 done: 999 circuit_free(circ); 1000 hs_descriptor_free(desc1); 1001 hs_descriptor_free(desc2); 1002 hs_free_all(); 1003 UNMOCK(networkstatus_get_reasonably_live_consensus); 1004 } 1005 1006 static void 1007 test_close_intro_circuits_cache_clean(void *arg) 1008 { 1009 int ret; 1010 ed25519_keypair_t service_kp; 1011 circuit_t *circ = NULL; 1012 origin_circuit_t *ocirc = NULL; 1013 hs_descriptor_t *desc1 = NULL; 1014 1015 (void) arg; 1016 1017 hs_init(); 1018 1019 /* This is needed because of the client cache expiration timestamp is based 1020 * on having a consensus. See cached_client_descriptor_has_expired(). */ 1021 MOCK(networkstatus_get_reasonably_live_consensus, 1022 mock_networkstatus_get_reasonably_live_consensus); 1023 1024 /* Set consensus time */ 1025 parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", 1026 &mock_ns.valid_after); 1027 parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", 1028 &mock_ns.fresh_until); 1029 parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", 1030 &mock_ns.valid_until); 1031 1032 /* Generate service keypair */ 1033 tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); 1034 1035 /* Create and add to the global list a dummy client introduction circuits. 1036 * We'll then make sure the hs_ident is attached to a dummy descriptor. */ 1037 circ = dummy_origin_circuit_new(0); 1038 tt_assert(circ); 1039 circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING; 1040 ocirc = TO_ORIGIN_CIRCUIT(circ); 1041 1042 /* Build the first descriptor and cache it. */ 1043 { 1044 char *encoded; 1045 desc1 = hs_helper_build_hs_desc_with_ip(&service_kp); 1046 tt_assert(desc1); 1047 ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded); 1048 tt_int_op(ret, OP_EQ, 0); 1049 tt_assert(encoded); 1050 1051 /* Store it */ 1052 ret = hs_cache_store_as_client(encoded, &service_kp.pubkey); 1053 tt_int_op(ret, OP_EQ, 0); 1054 tor_free(encoded); 1055 tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey)); 1056 } 1057 1058 /* We'll pick one introduction point and associate it with the circuit. */ 1059 { 1060 const hs_desc_intro_point_t *ip = 1061 smartlist_get(desc1->encrypted_data.intro_points, 0); 1062 tt_assert(ip); 1063 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 1064 ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, 1065 &ip->auth_key_cert->signed_key); 1066 } 1067 1068 /* Before we are about to clean up the intro circuits, make sure it is 1069 * actually there. */ 1070 tt_assert(circuit_get_next_intro_circ(NULL, true)); 1071 1072 /* Cleanup the client cache. The ns valid after time is what decides if the 1073 * descriptor has expired so put it in the future enough (72h) so we are 1074 * sure to always expire. */ 1075 mock_ns.valid_after = approx_time() + (72 * 24 * 60 * 60); 1076 hs_cache_clean_as_client(0); 1077 1078 /* Once stored, our intro circuit should be closed because it is related to 1079 * an old introduction point that doesn't exists anymore. */ 1080 tt_assert(!circuit_get_next_intro_circ(NULL, true)); 1081 1082 done: 1083 circuit_free(circ); 1084 hs_descriptor_free(desc1); 1085 hs_free_all(); 1086 UNMOCK(networkstatus_get_reasonably_live_consensus); 1087 } 1088 1089 static void 1090 test_socks_hs_errors(void *arg) 1091 { 1092 int ret; 1093 char digest[DIGEST_LEN]; 1094 char *desc_encoded = NULL; 1095 circuit_t *circ = NULL; 1096 origin_circuit_t *ocirc = NULL; 1097 tor_addr_t addr = TOR_ADDR_NULL; 1098 ed25519_keypair_t service_kp; 1099 ed25519_keypair_t signing_kp; 1100 entry_connection_t *socks_conn = NULL; 1101 dir_connection_t *dir_conn = NULL; 1102 hs_descriptor_t *desc = NULL; 1103 uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN]; 1104 1105 (void) arg; 1106 1107 MOCK(networkstatus_get_reasonably_live_consensus, 1108 mock_networkstatus_get_reasonably_live_consensus); 1109 MOCK(connection_mark_unattached_ap_, 1110 mock_connection_mark_unattached_ap_no_close); 1111 MOCK(read_file_to_str, mock_read_file_to_str); 1112 MOCK(tor_listdir, mock_tor_listdir); 1113 MOCK(check_private_dir, mock_check_private_dir); 1114 1115 /* Set consensus time */ 1116 parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", 1117 &mock_ns.valid_after); 1118 parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", 1119 &mock_ns.fresh_until); 1120 parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", 1121 &mock_ns.valid_until); 1122 1123 hs_init(); 1124 1125 ret = ed25519_keypair_generate(&service_kp, 0); 1126 tt_int_op(ret, OP_EQ, 0); 1127 ret = ed25519_keypair_generate(&signing_kp, 0); 1128 tt_int_op(ret, OP_EQ, 0); 1129 1130 socks_conn = helper_build_socks_connection(&service_kp.pubkey, 1131 AP_CONN_STATE_RENDDESC_WAIT); 1132 tt_assert(socks_conn); 1133 1134 /* Create directory connection. */ 1135 dir_conn = dir_connection_new(AF_INET); 1136 dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t)); 1137 TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC; 1138 ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_kp.pubkey); 1139 1140 /* Encode descriptor so we can decode it. */ 1141 desc = hs_helper_build_hs_desc_with_ip(&service_kp); 1142 tt_assert(desc); 1143 1144 /* Before testing the client authentication error code, encode the 1145 * descriptor with no client auth. */ 1146 ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &desc_encoded); 1147 tt_int_op(ret, OP_EQ, 0); 1148 tt_assert(desc_encoded); 1149 1150 /* 1151 * Test the introduction failure codes (X'F2' and X'F7') 1152 */ 1153 1154 /* First, we have to put all the IPs in the failure cache. */ 1155 SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, 1156 hs_desc_intro_point_t *, ip) { 1157 hs_cache_client_intro_state_note(&service_kp.pubkey, 1158 &ip->auth_key_cert->signed_key, 1159 INTRO_POINT_FAILURE_GENERIC); 1160 } SMARTLIST_FOREACH_END(ip); 1161 1162 hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200); 1163 tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, 1164 SOCKS5_HS_INTRO_FAILED); 1165 1166 /* Purge client cache of the descriptor so we can go again. */ 1167 hs_cache_purge_as_client(); 1168 1169 /* Second, set all failures to be time outs. */ 1170 SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, 1171 hs_desc_intro_point_t *, ip) { 1172 hs_cache_client_intro_state_note(&service_kp.pubkey, 1173 &ip->auth_key_cert->signed_key, 1174 INTRO_POINT_FAILURE_TIMEOUT); 1175 } SMARTLIST_FOREACH_END(ip); 1176 1177 hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200); 1178 tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, 1179 SOCKS5_HS_INTRO_TIMEDOUT); 1180 1181 /* Purge client cache of the descriptor so we can go again. */ 1182 hs_cache_purge_as_client(); 1183 1184 /* 1185 * Test the rendezvous failure codes (X'F3') 1186 */ 1187 1188 circ = dummy_origin_circuit_new(0); 1189 tt_assert(circ); 1190 circ->purpose = CIRCUIT_PURPOSE_C_REND_READY; 1191 ocirc = TO_ORIGIN_CIRCUIT(circ); 1192 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 1193 ocirc->hs_ident->intro_auth_pk.pubkey[0] = 42; 1194 ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); 1195 /* Code path will log this exit so build it. */ 1196 ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, 1197 NULL, NULL, &addr, 1198 4242, NULL, false); 1199 /* Attach socks connection to this rendezvous circuit. */ 1200 ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn); 1201 /* Trigger the rendezvous failure. Timeout the circuit and free. */ 1202 circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT); 1203 1204 tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, 1205 SOCKS5_HS_REND_FAILED); 1206 1207 /* 1208 * Test client authorization codes. 1209 */ 1210 1211 tor_free(desc_encoded); 1212 crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie)); 1213 ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie, 1214 &desc_encoded); 1215 tt_int_op(ret, OP_EQ, 0); 1216 tt_assert(desc_encoded); 1217 1218 /* Try decoding. Point this to an existing descriptor. The following should 1219 * fail thus the desc_out should be set to NULL. */ 1220 hs_descriptor_t *desc_out = desc; 1221 ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey, 1222 &desc_out); 1223 tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH); 1224 tt_assert(desc_out == NULL); 1225 1226 /* The caching will fail to decrypt because the descriptor_cookie used above 1227 * is not known to the HS subsystem. This will lead to a missing client 1228 * auth. */ 1229 hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200); 1230 1231 tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, 1232 SOCKS5_HS_MISSING_CLIENT_AUTH); 1233 1234 /* Add in the global client auth list bad creds for this service. */ 1235 helper_add_random_client_auth(&service_kp.pubkey); 1236 1237 ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey, 1238 &desc_out); 1239 tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH); 1240 tt_assert(desc_out == NULL); 1241 1242 /* Simmulate a fetch done again. This should replace the cached descriptor 1243 * and signal a bad client authorization. */ 1244 hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200); 1245 tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ, 1246 SOCKS5_HS_BAD_CLIENT_AUTH); 1247 1248 done: 1249 connection_free_minimal(ENTRY_TO_CONN(socks_conn)); 1250 connection_free_minimal(TO_CONN(dir_conn)); 1251 hs_descriptor_free(desc); 1252 tor_free(desc_encoded); 1253 circuit_free(circ); 1254 1255 hs_free_all(); 1256 1257 UNMOCK(networkstatus_get_reasonably_live_consensus); 1258 UNMOCK(connection_mark_unattached_ap_); 1259 UNMOCK(read_file_to_str); 1260 UNMOCK(tor_listdir); 1261 UNMOCK(check_private_dir); 1262 } 1263 1264 static void 1265 test_close_intro_circuit_failure(void *arg) 1266 { 1267 char digest[DIGEST_LEN]; 1268 circuit_t *circ = NULL; 1269 ed25519_keypair_t service_kp, intro_kp; 1270 origin_circuit_t *ocirc = NULL; 1271 tor_addr_t addr = TOR_ADDR_NULL; 1272 const hs_cache_intro_state_t *entry; 1273 1274 (void) arg; 1275 1276 hs_init(); 1277 1278 /* Generate service keypair */ 1279 tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); 1280 tt_int_op(0, OP_EQ, ed25519_keypair_generate(&intro_kp, 0)); 1281 1282 /* Create and add to the global list a dummy client introduction circuit at 1283 * the ACK WAIT state. */ 1284 circ = dummy_origin_circuit_new(0); 1285 tt_assert(circ); 1286 circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT; 1287 ocirc = TO_ORIGIN_CIRCUIT(circ); 1288 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 1289 ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); 1290 /* Code path will log this exit so build it. */ 1291 ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, 1292 NULL, NULL, &addr, 1293 4242, NULL, false); 1294 ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); 1295 1296 /* We'll make for close the circuit for a timeout failure. It should _NOT_ 1297 * end up in the failure cache just yet. We do that on free() only. */ 1298 circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT); 1299 tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey, 1300 &intro_kp.pubkey)); 1301 /* Time to free. It should get removed. */ 1302 circuit_free(circ); 1303 entry = hs_cache_client_intro_state_find(&service_kp.pubkey, 1304 &intro_kp.pubkey); 1305 tt_assert(entry); 1306 tt_uint_op(entry->timed_out, OP_EQ, 1); 1307 hs_cache_client_intro_state_purge(); 1308 1309 /* Again, create and add to the global list a dummy client introduction 1310 * circuit at the INTRODUCING state. */ 1311 circ = dummy_origin_circuit_new(0); 1312 tt_assert(circ); 1313 circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING; 1314 ocirc = TO_ORIGIN_CIRCUIT(circ); 1315 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 1316 ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); 1317 /* Code path will log this exit so build it. */ 1318 ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, 1319 NULL, NULL, &addr, 1320 4242, NULL, false); 1321 ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); 1322 1323 /* On free, we should get an unreachable failure. */ 1324 circuit_free(circ); 1325 entry = hs_cache_client_intro_state_find(&service_kp.pubkey, 1326 &intro_kp.pubkey); 1327 tt_assert(entry); 1328 tt_uint_op(entry->unreachable_count, OP_EQ, 1); 1329 hs_cache_client_intro_state_purge(); 1330 1331 /* Again, create and add to the global list a dummy client introduction 1332 * circuit at the INTRODUCING state but we'll close it for timeout. It 1333 * should not be noted as a timeout failure. */ 1334 circ = dummy_origin_circuit_new(0); 1335 tt_assert(circ); 1336 circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING; 1337 ocirc = TO_ORIGIN_CIRCUIT(circ); 1338 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 1339 ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); 1340 /* Code path will log this exit so build it. */ 1341 ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, 1342 NULL, NULL, &addr, 1343 4242, NULL, false); 1344 ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); 1345 1346 circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT); 1347 circuit_free(circ); 1348 tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey, 1349 &intro_kp.pubkey)); 1350 1351 /* Again, create and add to the global list a dummy client introduction 1352 * circuit at the INTRODUCING state but without a chosen_exit. In theory, it 1353 * can not happen but we'll make sure it doesn't end up in the failure cache 1354 * anyway. */ 1355 circ = dummy_origin_circuit_new(0); 1356 tt_assert(circ); 1357 circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING; 1358 ocirc = TO_ORIGIN_CIRCUIT(circ); 1359 ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); 1360 ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); 1361 1362 circuit_free(circ); 1363 tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey, 1364 &intro_kp.pubkey)); 1365 1366 done: 1367 circuit_free(circ); 1368 hs_free_all(); 1369 } 1370 1371 static void 1372 test_purge_ephemeral_client_auth(void *arg) 1373 { 1374 ed25519_keypair_t service_kp; 1375 hs_client_service_authorization_t *auth = NULL; 1376 hs_client_register_auth_status_t status; 1377 1378 (void) arg; 1379 1380 /* We will try to write on disk client credentials. */ 1381 MOCK(check_private_dir, mock_check_private_dir); 1382 MOCK(get_options, mock_get_options); 1383 MOCK(write_str_to_file, mock_write_str_to_file); 1384 1385 /* Bogus directory so when we try to write the permanent client 1386 * authorization data to disk, we don't fail. See 1387 * store_permanent_client_auth_credentials() for more details. */ 1388 mocked_options.ClientOnionAuthDir = tor_strdup("auth_dir"); 1389 1390 hs_init(); 1391 1392 /* Generate service keypair */ 1393 tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); 1394 1395 /* Generate a client authorization object. */ 1396 auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); 1397 1398 /* Set it up. No flags meaning it is ephemeral. */ 1399 curve25519_secret_key_generate(&auth->enc_seckey, 0); 1400 hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address); 1401 auth->flags = 0; 1402 1403 /* Confirm that there is nothing in the client auth map. It is unallocated 1404 * until we add the first entry. */ 1405 tt_assert(!get_hs_client_auths_map()); 1406 1407 /* Add an entry to the client auth list. We loose ownership of the auth 1408 * object so nullify it. */ 1409 status = hs_client_register_auth_credentials(auth); 1410 auth = NULL; 1411 tt_int_op(status, OP_EQ, REGISTER_SUCCESS); 1412 1413 /* We should have the entry now. */ 1414 digest256map_t *client_auths = get_hs_client_auths_map(); 1415 tt_assert(client_auths); 1416 tt_int_op(digest256map_size(client_auths), OP_EQ, 1); 1417 1418 /* Purge the cache that should remove all ephemeral values. */ 1419 purge_ephemeral_client_auth(); 1420 tt_int_op(digest256map_size(client_auths), OP_EQ, 0); 1421 1422 /* Now add a new authorization object but permanent. */ 1423 /* Generate a client authorization object. */ 1424 auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); 1425 curve25519_secret_key_generate(&auth->enc_seckey, 0); 1426 hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address); 1427 auth->flags = CLIENT_AUTH_FLAG_IS_PERMANENT; 1428 1429 /* Add an entry to the client auth list. We loose ownership of the auth 1430 * object so nullify it. */ 1431 status = hs_client_register_auth_credentials(auth); 1432 auth = NULL; 1433 tt_int_op(status, OP_EQ, REGISTER_SUCCESS); 1434 tt_int_op(digest256map_size(client_auths), OP_EQ, 1); 1435 1436 /* Purge again, the entry should still be there. */ 1437 purge_ephemeral_client_auth(); 1438 tt_int_op(digest256map_size(client_auths), OP_EQ, 1); 1439 1440 done: 1441 client_service_authorization_free(auth); 1442 hs_free_all(); 1443 tor_free(mocked_options.ClientOnionAuthDir); 1444 1445 UNMOCK(check_private_dir); 1446 UNMOCK(get_options); 1447 UNMOCK(write_str_to_file); 1448 } 1449 1450 struct testcase_t hs_client_tests[] = { 1451 { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, 1452 TT_FORK, NULL, NULL }, 1453 { "client_pick_intro", test_client_pick_intro, 1454 TT_FORK, NULL, NULL }, 1455 { "descriptor_fetch", test_descriptor_fetch, 1456 TT_FORK, NULL, NULL }, 1457 { "auth_key_filename_is_valid", test_auth_key_filename_is_valid, TT_FORK, 1458 NULL, NULL }, 1459 { "parse_auth_file_content", test_parse_auth_file_content, TT_FORK, 1460 NULL, NULL }, 1461 { "config_client_authorization", test_config_client_authorization, 1462 TT_FORK, NULL, NULL }, 1463 { "desc_has_arrived_cleanup", test_desc_has_arrived_cleanup, 1464 TT_FORK, NULL, NULL }, 1465 { "close_intro_circuit_failure", test_close_intro_circuit_failure, 1466 TT_FORK, NULL, NULL }, 1467 { "close_intro_circuits_new_desc", test_close_intro_circuits_new_desc, 1468 TT_FORK, NULL, NULL }, 1469 { "close_intro_circuits_cache_clean", test_close_intro_circuits_cache_clean, 1470 TT_FORK, NULL, NULL }, 1471 1472 /* SOCKS5 Extended Error Code. */ 1473 { "socks_hs_errors", test_socks_hs_errors, TT_FORK, NULL, NULL }, 1474 1475 /* Client authorization. */ 1476 { "purge_ephemeral_client_auth", test_purge_ephemeral_client_auth, TT_FORK, 1477 NULL, NULL }, 1478 1479 END_OF_TESTCASES 1480 };