test_hs_control.c (30553B)
1 /* Copyright (c) 2017-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file test_hs_control.c 6 * \brief Unit tests for hidden service control port event and command. 7 **/ 8 9 #define CONTROL_EVENTS_PRIVATE 10 #define CONTROL_CMD_PRIVATE 11 #define HS_CLIENT_PRIVATE 12 #define HS_SERVICE_PRIVATE 13 14 #include "core/or/or.h" 15 #include "test/test.h" 16 #include "test/test_helpers.h" 17 #include "core/mainloop/connection.h" 18 #include "feature/control/control.h" 19 #include "feature/control/control_cmd.h" 20 #include "feature/control/control_events.h" 21 #include "feature/control/control_fmt.h" 22 #include "feature/control/control_connection_st.h" 23 #include "app/config/config.h" 24 #include "feature/hs/hs_common.h" 25 #include "feature/hs/hs_client.h" 26 #include "feature/hs/hs_config.h" 27 #include "feature/hs/hs_control.h" 28 #include "feature/nodelist/nodelist.h" 29 30 #include "feature/nodelist/node_st.h" 31 #include "feature/nodelist/routerstatus_st.h" 32 #include "lib/container/smartlist.h" 33 #include "lib/crypt_ops/crypto_format.h" 34 35 #ifdef HAVE_SYS_STAT_H 36 #include <sys/stat.h> 37 #endif 38 39 #ifdef _WIN32 40 /* For mkdir() */ 41 #include <direct.h> 42 #else 43 #include <dirent.h> 44 #endif /* defined(_WIN32) */ 45 46 /* mock ID digest and longname for node that's in nodelist */ 47 #define HSDIR_EXIST_ID \ 48 "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \ 49 "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" 50 #define STR_HSDIR_EXIST_LONGNAME \ 51 "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir" 52 #define STR_HSDIR_NONE_EXIST_LONGNAME \ 53 "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" 54 55 /* Helper global variable for hidden service descriptor event test. 56 * It's used as a pointer to dynamically created message buffer in 57 * send_control_event_string_replacement function, which mocks 58 * send_control_event_string function. 59 * 60 * Always free it after use! */ 61 static char *received_msg = NULL; 62 63 /** Mock function for send_control_event_string 64 */ 65 static void 66 queue_control_event_string_replacement(uint16_t event, char *msg) 67 { 68 (void) event; 69 tor_free(received_msg); 70 received_msg = msg; 71 } 72 73 /** Mock function for node_describe_longname_by_id, it returns either 74 * STR_HSDIR_EXIST_LONGNAME or STR_HSDIR_NONE_EXIST_LONGNAME 75 */ 76 static const char * 77 node_describe_longname_by_id_replacement(const char *id_digest) 78 { 79 if (!strcmp(id_digest, HSDIR_EXIST_ID)) { 80 return STR_HSDIR_EXIST_LONGNAME; 81 } else { 82 return STR_HSDIR_NONE_EXIST_LONGNAME; 83 } 84 } 85 86 /* HSDir fetch index is a series of 'D' */ 87 #define HSDIR_INDEX_FETCH_HEX \ 88 "4343434343434343434343434343434343434343434343434343434343434343" 89 #define HSDIR_INDEX_STORE_HEX \ 90 "4444444444444444444444444444444444444444444444444444444444444444" 91 92 static const node_t * 93 mock_node_get_by_id(const char *digest) 94 { 95 static node_t node; 96 memcpy(node.identity, digest, DIGEST_LEN); 97 memset(node.hsdir_index.fetch, 'C', DIGEST256_LEN); 98 memset(node.hsdir_index.store_first, 'D', DIGEST256_LEN); 99 return &node; 100 } 101 102 static void 103 test_hs_desc_event(void *arg) 104 { 105 int ret; 106 char *expected_msg = NULL; 107 char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1]; 108 ed25519_keypair_t identity_kp; 109 ed25519_public_key_t blinded_pk; 110 char base64_blinded_pk[ED25519_BASE64_LEN + 1]; 111 routerstatus_t hsdir_rs; 112 hs_ident_dir_conn_t ident; 113 114 (void) arg; 115 MOCK(queue_control_event_string, 116 queue_control_event_string_replacement); 117 MOCK(node_describe_longname_by_id, 118 node_describe_longname_by_id_replacement); 119 MOCK(node_get_by_id, mock_node_get_by_id); 120 121 /* Setup what we need for this test. */ 122 ed25519_keypair_generate(&identity_kp, 0); 123 hs_build_address(&identity_kp.pubkey, HS_VERSION_THREE, onion_address); 124 ret = hs_address_is_valid(onion_address); 125 tt_int_op(ret, OP_EQ, 1); 126 memset(&blinded_pk, 'B', sizeof(blinded_pk)); 127 memset(&hsdir_rs, 0, sizeof(hsdir_rs)); 128 memcpy(hsdir_rs.identity_digest, HSDIR_EXIST_ID, DIGEST_LEN); 129 ed25519_public_to_base64(base64_blinded_pk, &blinded_pk); 130 memcpy(&ident.identity_pk, &identity_kp.pubkey, 131 sizeof(ed25519_public_key_t)); 132 memcpy(&ident.blinded_pk, &blinded_pk, sizeof(blinded_pk)); 133 134 /* HS_DESC REQUESTED ... */ 135 hs_control_desc_event_requested(&identity_kp.pubkey, base64_blinded_pk, 136 &hsdir_rs); 137 tor_asprintf(&expected_msg, "650 HS_DESC REQUESTED %s NO_AUTH " 138 STR_HSDIR_EXIST_LONGNAME " %s HSDIR_INDEX=" 139 HSDIR_INDEX_FETCH_HEX "\r\n", 140 onion_address, base64_blinded_pk); 141 tt_assert(received_msg); 142 tt_str_op(received_msg, OP_EQ, expected_msg); 143 tor_free(received_msg); 144 tor_free(expected_msg); 145 146 /* HS_DESC CREATED... */ 147 hs_control_desc_event_created(onion_address, &blinded_pk); 148 tor_asprintf(&expected_msg, "650 HS_DESC CREATED %s UNKNOWN " 149 "UNKNOWN %s\r\n", 150 onion_address, base64_blinded_pk); 151 tt_assert(received_msg); 152 tt_str_op(received_msg, OP_EQ, expected_msg); 153 tor_free(received_msg); 154 tor_free(expected_msg); 155 156 /* HS_DESC UPLOAD... */ 157 uint8_t hsdir_index_store[DIGEST256_LEN]; 158 memset(hsdir_index_store, 'D', sizeof(hsdir_index_store)); 159 hs_control_desc_event_upload(onion_address, HSDIR_EXIST_ID, 160 &blinded_pk, hsdir_index_store); 161 tor_asprintf(&expected_msg, "650 HS_DESC UPLOAD %s UNKNOWN " 162 STR_HSDIR_EXIST_LONGNAME " %s " 163 "HSDIR_INDEX=" HSDIR_INDEX_STORE_HEX "\r\n", 164 onion_address, base64_blinded_pk); 165 tt_assert(received_msg); 166 tt_str_op(received_msg, OP_EQ, expected_msg); 167 tor_free(received_msg); 168 tor_free(expected_msg); 169 170 /* HS_DESC FAILED... */ 171 hs_control_desc_event_failed(&ident, HSDIR_EXIST_ID, "BAD_DESC"); 172 tor_asprintf(&expected_msg, "650 HS_DESC FAILED %s NO_AUTH " 173 STR_HSDIR_EXIST_LONGNAME " %s " 174 "REASON=BAD_DESC\r\n", 175 onion_address, base64_blinded_pk); 176 tt_assert(received_msg); 177 tt_str_op(received_msg, OP_EQ, expected_msg); 178 tor_free(received_msg); 179 tor_free(expected_msg); 180 181 /* HS_DESC RECEIVED... */ 182 hs_control_desc_event_received(&ident, HSDIR_EXIST_ID); 183 tor_asprintf(&expected_msg, "650 HS_DESC RECEIVED %s NO_AUTH " 184 STR_HSDIR_EXIST_LONGNAME " %s\r\n", 185 onion_address, base64_blinded_pk); 186 tt_assert(received_msg); 187 tt_str_op(received_msg, OP_EQ, expected_msg); 188 tor_free(received_msg); 189 tor_free(expected_msg); 190 191 /* HS_DESC UPLOADED... */ 192 hs_control_desc_event_uploaded(&ident, HSDIR_EXIST_ID); 193 tor_asprintf(&expected_msg, "650 HS_DESC UPLOADED %s UNKNOWN " 194 STR_HSDIR_EXIST_LONGNAME "\r\n", 195 onion_address); 196 tt_assert(received_msg); 197 tt_str_op(received_msg, OP_EQ, expected_msg); 198 tor_free(received_msg); 199 tor_free(expected_msg); 200 201 done: 202 UNMOCK(queue_control_event_string); 203 UNMOCK(node_describe_longname_by_id); 204 UNMOCK(node_get_by_id); 205 tor_free(received_msg); 206 tor_free(expected_msg); 207 } 208 209 /** Test that we can correctly add, remove and view client auth credentials 210 * using the control port. */ 211 static void 212 test_hs_control_good_onion_client_auth_add(void *arg) 213 { 214 (void) arg; 215 216 MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); 217 218 int retval; 219 ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4, 220 service_identity_pk_jam; 221 control_connection_t conn; 222 char *args = NULL; 223 char *cp1 = NULL; 224 size_t sz; 225 226 hs_init(); 227 228 { /* Setup the control conn */ 229 memset(&conn, 0, sizeof(control_connection_t)); 230 TO_CONN(&conn)->outbuf = buf_new(); 231 conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD"); 232 } 233 234 { /* Setup the services */ 235 retval = hs_parse_address( 236 "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd", 237 &service_identity_pk_2fv, 238 NULL, NULL); 239 tt_int_op(retval, OP_EQ, 0); 240 241 retval = hs_parse_address( 242 "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd", 243 &service_identity_pk_jt4, 244 NULL, NULL); 245 tt_int_op(retval, OP_EQ, 0); 246 247 retval = hs_parse_address( 248 "jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd", 249 &service_identity_pk_jam, 250 NULL, NULL); 251 tt_int_op(retval, OP_EQ, 0); 252 } 253 254 digest256map_t *client_auths = get_hs_client_auths_map(); 255 tt_assert(!client_auths); 256 257 /* Register first service */ 258 args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " 259 "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= "); 260 261 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 262 tt_int_op(retval, OP_EQ, 0); 263 264 /* Check contents */ 265 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 266 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 267 268 tor_free(cp1); 269 tor_free(args); 270 271 /* Register second service (even with an unrecognized argument) */ 272 args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " 273 "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA= DropSound=No"); 274 275 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 276 tt_int_op(retval, OP_EQ, 0); 277 278 /* Check contents */ 279 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 280 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 281 tor_free(cp1); 282 tor_free(args); 283 284 /* Register second service (even with an unrecognized argument) */ 285 args = tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " 286 "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " 287 "ClientName=MeganNicole "); 288 289 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 290 tt_int_op(retval, OP_EQ, 0); 291 292 /* Check contents */ 293 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 294 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 295 tor_free(cp1); 296 297 client_auths = get_hs_client_auths_map(); 298 tt_assert(client_auths); 299 tt_uint_op(digest256map_size(client_auths), OP_EQ, 3); 300 301 hs_client_service_authorization_t *client_2fv = 302 digest256map_get(client_auths, service_identity_pk_2fv.pubkey); 303 tt_assert(client_2fv); 304 tt_int_op(client_2fv->flags, OP_EQ, 0); 305 306 hs_client_service_authorization_t *client_jt4 = 307 digest256map_get(client_auths, service_identity_pk_jt4.pubkey); 308 tt_assert(client_jt4); 309 tt_int_op(client_jt4->flags, OP_EQ, 0); 310 311 hs_client_service_authorization_t *client_jam = 312 digest256map_get(client_auths, service_identity_pk_jam.pubkey); 313 tt_assert(client_jam); 314 tt_int_op(client_jam->flags, OP_EQ, 0); 315 316 /* Now let's VIEW the auth credentials */ 317 tor_free(conn.current_cmd); 318 conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW"); 319 320 /* First go with no arguments, so that we view all the credentials */ 321 tor_free(args); 322 args = tor_strdup(""); 323 324 #define VIEW_CORRECT_REPLY_NO_ADDR "250-ONION_CLIENT_AUTH_VIEW\r\n" \ 325 "250-CLIENT 2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " \ 326 "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=\r\n" \ 327 "250-CLIENT jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " \ 328 "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " \ 329 "ClientName=MeganNicole\r\n" \ 330 "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \ 331 "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \ 332 "250 OK\r\n" 333 334 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 335 tt_int_op(retval, OP_EQ, 0); 336 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 337 tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_NO_ADDR); 338 tor_free(cp1); 339 340 /* Now specify an HS addr, and see that we only view those creds */ 341 tor_free(args); 342 args = 343 tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd"); 344 345 #define VIEW_CORRECT_REPLY_JT4 "250-ONION_CLIENT_AUTH_VIEW " \ 346 "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\r\n" \ 347 "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \ 348 "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \ 349 "250 OK\r\n" 350 351 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 352 tt_int_op(retval, OP_EQ, 0); 353 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 354 tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_JT4); 355 tor_free(cp1); 356 357 /* Now try to REMOVE the auth credentials */ 358 tor_free(conn.current_cmd); 359 conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE"); 360 361 /* First try with a wrong addr */ 362 tor_free(args); 363 args = tor_strdup("thatsok"); 364 365 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 366 tt_int_op(retval, OP_EQ, 0); 367 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 368 tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"thatsok\"\r\n"); 369 tor_free(cp1); 370 371 client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey); 372 tt_assert(client_jt4); 373 374 /* Now actually remove them. */ 375 tor_free(args); 376 args =tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd"); 377 378 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 379 tt_int_op(retval, OP_EQ, 0); 380 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 381 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 382 tor_free(cp1); 383 384 client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey); 385 tt_assert(!client_jt4); 386 387 /* Now try another time (we should get 'already removed' msg) */ 388 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 389 tt_int_op(retval, OP_EQ, 0); 390 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 391 tt_str_op(cp1, OP_EQ, "251 No credentials for " 392 "\"jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\"\r\n"); 393 tor_free(cp1); 394 395 client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey); 396 tt_assert(!client_jt4); 397 398 /* Now also remove the other one */ 399 tor_free(args); 400 args = 401 tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd"); 402 403 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 404 tt_int_op(retval, OP_EQ, 0); 405 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 406 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 407 tor_free(cp1); 408 409 /* Now also remove the other one */ 410 tor_free(args); 411 args = 412 tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd"); 413 414 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 415 tt_int_op(retval, OP_EQ, 0); 416 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 417 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 418 tor_free(cp1); 419 420 /* Finally, do another VIEW and see that we get nothing. */ 421 tor_free(conn.current_cmd); 422 conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW"); 423 tor_free(args); 424 args = tor_strdup(""); 425 426 #define VIEW_CORRECT_REPLY_NOTHING "250-ONION_CLIENT_AUTH_VIEW\r\n250 OK\r\n" 427 428 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 429 tt_int_op(retval, OP_EQ, 0); 430 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 431 tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_NOTHING); 432 tor_free(cp1); 433 434 /* And a final VIEW with a wrong HS addr */ 435 tor_free(args); 436 args = tor_strdup("house"); 437 438 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 439 tt_int_op(retval, OP_EQ, 0); 440 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 441 tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"house\"\r\n"); 442 443 done: 444 tor_free(args); 445 tor_free(cp1); 446 buf_free(TO_CONN(&conn)->outbuf); 447 tor_free(conn.current_cmd); 448 hs_client_free_all(); 449 } 450 451 /** Test some error cases of ONION_CLIENT_AUTH_ADD */ 452 static void 453 test_hs_control_bad_onion_client_auth_add(void *arg) 454 { 455 (void) arg; 456 457 MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); 458 459 int retval; 460 control_connection_t conn; 461 char *cp1 = NULL; 462 size_t sz; 463 char *args = NULL; 464 465 hs_init(); 466 467 { /* Setup the control conn */ 468 memset(&conn, 0, sizeof(control_connection_t)); 469 TO_CONN(&conn)->outbuf = buf_new(); 470 conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD"); 471 } 472 473 digest256map_t *client_auths = get_hs_client_auths_map(); 474 tt_assert(!client_auths); 475 476 /* Register first service */ 477 args = tor_strdup( 478 "badaddr x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ="); 479 480 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 481 tt_int_op(retval, OP_EQ, 0); 482 483 /* Check contents */ 484 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 485 tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"badaddr\"\r\n"); 486 487 tor_free(cp1); 488 tor_free(args); 489 490 /* Register second service (even with an unrecognized argument) */ 491 args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " 492 "love:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA="); 493 494 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 495 tt_int_op(retval, OP_EQ, 0); 496 497 /* Check contents */ 498 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 499 tt_str_op(cp1, OP_EQ, "552 Unrecognized key type \"love\"\r\n"); 500 501 tor_free(cp1); 502 tor_free(args); 503 504 /* Register second service (even with an unrecognized argument) */ 505 args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " 506 "x25519:QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEK"); 507 508 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 509 tt_int_op(retval, OP_EQ, 0); 510 511 /* Check contents */ 512 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 513 tt_str_op(cp1, OP_EQ, "512 Failed to decode x25519 private key\r\n"); 514 515 tor_free(cp1); 516 tor_free(args); 517 518 /* Register with an all zero client key */ 519 args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " 520 "x25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); 521 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 522 tt_int_op(retval, OP_EQ, 0); 523 524 /* Check contents */ 525 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 526 tt_str_op(cp1, OP_EQ, "553 Invalid private key \"AAAAAAAAAAAAAAAAAAAA" 527 "AAAAAAAAAAAAAAAAAAAAAAA=\"\r\n"); 528 529 client_auths = get_hs_client_auths_map(); 530 tt_assert(!client_auths); 531 532 done: 533 tor_free(args); 534 tor_free(cp1); 535 buf_free(TO_CONN(&conn)->outbuf); 536 tor_free(conn.current_cmd); 537 hs_client_free_all(); 538 } 539 540 /** Test that we can correctly add permanent client auth credentials using the 541 * control port. */ 542 static void 543 test_hs_control_store_permanent_creds(void *arg) 544 { 545 (void) arg; 546 547 MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); 548 549 int retval; 550 ed25519_public_key_t service_identity_pk_2fv; 551 control_connection_t conn; 552 char *args = NULL; 553 char *cp1 = NULL; 554 char *creds_file_str = NULL; 555 char *creds_fname = NULL; 556 557 size_t sz; 558 559 hs_init(); 560 561 { /* Setup the control conn */ 562 memset(&conn, 0, sizeof(control_connection_t)); 563 TO_CONN(&conn)->outbuf = buf_new(); 564 conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD"); 565 } 566 567 { /* Setup the services */ 568 retval = hs_parse_address( 569 "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd", 570 &service_identity_pk_2fv, 571 NULL, NULL); 572 tt_int_op(retval, OP_EQ, 0); 573 } 574 575 digest256map_t *client_auths = get_hs_client_auths_map(); 576 tt_assert(!client_auths); 577 578 /* Try registering first service with no ClientOnionAuthDir set */ 579 args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " 580 "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= " 581 "Flags=Permanent"); 582 583 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 584 tt_int_op(retval, OP_EQ, 0); 585 586 /* Check control port response. This one should fail. */ 587 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 588 tt_str_op(cp1, OP_EQ, "553 Unable to store creds for " 589 "\"2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd\"\r\n"); 590 591 { /* Setup ClientOnionAuthDir */ 592 int ret; 593 char *perm_creds_dir = tor_strdup(get_fname("permanent_credentials")); 594 get_options_mutable()->ClientOnionAuthDir = perm_creds_dir; 595 596 #ifdef _WIN32 597 ret = mkdir(perm_creds_dir); 598 #else 599 ret = mkdir(perm_creds_dir, 0700); 600 #endif 601 tt_int_op(ret, OP_EQ, 0); 602 } 603 604 tor_free(args); 605 tor_free(cp1); 606 607 /* Try the control port command again. This time it should work! */ 608 args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " 609 "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= " 610 "Flags=Permanent"); 611 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 612 tt_int_op(retval, OP_EQ, 0); 613 614 /* Check control port response */ 615 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 616 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 617 618 /* Check file contents! */ 619 creds_fname = tor_strdup(get_fname("permanent_credentials/" 620 "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd.auth_private")); 621 creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL); 622 623 tt_assert(creds_file_str); 624 tt_str_op(creds_file_str, OP_EQ, 625 "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:" 626 /* base32 representation of the base64 iJ1t... key above */ 627 "x25519:rcow3dfavmyanyqvhwnvnmfdqw34ydtrgv7jnelmqs4wi4uuxrca"); 628 629 tor_free(args); 630 tor_free(cp1); 631 632 /* Overwrite the credentials and check that they got overwritten. */ 633 args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " 634 "x25519:UDRvZLvcJo0QRLvDfkpgbtsqbkhIUQZyeo2FNBrgS18= " 635 "Flags=Permanent"); 636 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 637 tt_int_op(retval, OP_EQ, 0); 638 639 /* Check control port response: we replaced! */ 640 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 641 tt_str_op(cp1, OP_EQ, "251 Client for onion existed and replaced\r\n"); 642 643 tor_free(creds_file_str); 644 645 /* Check creds file contents again. See that the key got updated */ 646 creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL); 647 tt_assert(creds_file_str); 648 tt_str_op(creds_file_str, OP_EQ, 649 "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:" 650 /* base32 representation of the base64 UDRv... key above */ 651 "x25519:ka2g6zf33qti2ecexpbx4stan3nsu3sijbiqm4t2rwctigxajnpq"); 652 653 /* Now for our next act!!! Actually get the HS client subsystem to parse the 654 * whole directory and make sure that it extracted the right credential! */ 655 hs_config_client_authorization(get_options(), 0); 656 657 client_auths = get_hs_client_auths_map(); 658 tt_assert(client_auths); 659 tt_uint_op(digest256map_size(client_auths), OP_EQ, 1); 660 661 hs_client_service_authorization_t *client_2fv = 662 digest256map_get(client_auths, service_identity_pk_2fv.pubkey); 663 tt_assert(client_2fv); 664 tt_int_op(client_2fv->flags, OP_EQ, CLIENT_AUTH_FLAG_IS_PERMANENT); 665 tt_str_op(hex_str((char*)client_2fv->enc_seckey.secret_key, 32), OP_EQ, 666 "50346F64BBDC268D1044BBC37E4A606EDB2A6E48485106727A8D85341AE04B5F"); 667 668 /* And now for the final act! Use the REMOVE control port command to remove 669 the credential, and ensure that the file has also been removed! */ 670 tor_free(conn.current_cmd); 671 tor_free(cp1); 672 tor_free(args); 673 674 /* Ensure that the creds file exists */ 675 tt_int_op(file_status(creds_fname), OP_EQ, FN_FILE); 676 677 /* Do the REMOVE */ 678 conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE"); 679 args =tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd"); 680 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 681 tt_int_op(retval, OP_EQ, 0); 682 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 683 tt_str_op(cp1, OP_EQ, "250 OK\r\n"); 684 685 /* Ensure that the file has been removed and the map is empty */ 686 tt_int_op(file_status(creds_fname), OP_EQ, FN_NOENT); 687 tt_uint_op(digest256map_size(client_auths), OP_EQ, 0); 688 689 done: 690 tor_free(get_options_mutable()->ClientOnionAuthDir); 691 tor_free(args); 692 tor_free(cp1); 693 buf_free(TO_CONN(&conn)->outbuf); 694 tor_free(conn.current_cmd); 695 tor_free(creds_fname); 696 tor_free(creds_file_str); 697 hs_client_free_all(); 698 } 699 700 /** Test that ADD_ONION properly handles an attacker passing it a bad private 701 * key. */ 702 static void 703 test_hs_control_add_onion_with_bad_pubkey(void *arg) 704 { 705 (void) arg; 706 707 MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); 708 709 int retval; 710 control_connection_t conn; 711 char *args = NULL; 712 char *cp1 = NULL; 713 size_t sz; 714 715 hs_init(); 716 717 { /* Setup the control conn */ 718 memset(&conn, 0, sizeof(control_connection_t)); 719 TO_CONN(&conn)->outbuf = buf_new(); 720 conn.current_cmd = tor_strdup("ADD_ONION"); 721 } 722 723 args = tor_strdup("ED25519-V3:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 724 "AAAAAAAAAAAAAAAAAAAAAAA" 725 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " 726 "Port=9735,127.0.0.1 Flags=DiscardPK"); 727 728 retval = handle_control_command(&conn, (uint32_t) strlen(args), args); 729 tt_int_op(retval, OP_EQ, 0); 730 731 /* Check control port response */ 732 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 733 tt_str_op(cp1, OP_EQ, "551 Failed to generate onion address\r\n"); 734 735 done: 736 tor_free(args); 737 tor_free(cp1); 738 buf_free(TO_CONN(&conn)->outbuf); 739 tor_free(conn.current_cmd); 740 } 741 742 /** Test that we can add the service via the control port. */ 743 static void 744 test_hs_control_add_auth_onion_service(void *arg) 745 { 746 control_connection_t conn; 747 char *args = NULL, *cp1 = NULL; 748 size_t sz; 749 750 (void) arg; 751 752 hs_init(); 753 754 memset(&conn, 0, sizeof(control_connection_t)); 755 TO_CONN(&conn)->outbuf = buf_new(); 756 conn.current_cmd = tor_strdup("ADD_ONION"); 757 args = tor_strdup("ED25519-V3:KLMQ4CLKwlDCHuMPn8j3od33cU5LhnrLNoZh7CWChl3VkY" 758 "pNAkeP5dGW8xeKR9HxQBWQ/w7Kr12lA/U8Pd/oxw== " 759 "ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja " 760 "Flags=V3Auth Port=9735,127.0.0.1"); 761 handle_control_command(&conn, (uint32_t) strlen(args), args); 762 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 763 tt_str_op(cp1, OP_EQ, 764 "250-ServiceID=n35etu3yjxrqjpntmfziom5sjwspoydchmelc4xleoy4jk2u4lziz2yd\r\n" 765 "250-ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja\r\n" 766 "250 OK\r\n"); 767 tor_free(args); 768 tor_free(cp1); 769 770 args = tor_strdup("ED25519-V3:iIU8EBi71qE7G6UTsROU1kWN0JMrRP/YukC0Xk5WLGyil3" 771 "gm4u3wEBXr+/TaCpXS+65Pcdqz+PG+4+oWHLN05A== " 772 "ClientAuthV3=dummy Flags=V3Auth Port=9735,127.0.0.1"); 773 handle_control_command(&conn, (uint32_t) strlen(args), args); 774 cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); 775 tt_str_op(cp1, OP_EQ, "512 Cannot decode v3 client auth key\r\n"); 776 777 done: 778 tor_free(args); 779 tor_free(cp1); 780 tor_free(conn.current_cmd); 781 buf_free(TO_CONN(&conn)->outbuf); 782 SMARTLIST_FOREACH(conn.ephemeral_onion_services, char *, 783 service, tor_free(service)); 784 smartlist_free(conn.ephemeral_onion_services); 785 hs_client_free_all(); 786 } 787 788 /** Test that add_onion_helper_add_service can add the service. */ 789 static void 790 test_hs_control_add_onion_helper_add_service(void *arg) 791 { 792 int hs_version_good, hs_version_bad; 793 add_onion_secret_key_t sk_good, sk_bad; 794 ed25519_public_key_t pk_good, pk_bad; 795 char *key_new_blob_good = NULL, *key_new_blob_bad = NULL; 796 const char *key_new_alg_good = NULL, *key_new_alg_bad = NULL; 797 hs_service_authorized_client_t *client_good, *client_bad; 798 smartlist_t *list_good, *list_bad; 799 hs_service_ht *global_map; 800 hs_port_config_t *portcfg; 801 smartlist_t *portcfgs; 802 char *address_out_good = NULL, *address_out_bad = NULL; 803 hs_service_t *service_good = NULL; 804 hs_service_t *service_bad = NULL; 805 806 (void) arg; 807 808 hs_init(); 809 global_map = get_hs_service_map(); 810 811 portcfg = hs_parse_port_config("8080", ",", NULL); 812 portcfgs = smartlist_new(); 813 smartlist_add(portcfgs, portcfg); 814 815 memset(&sk_good, 0, sizeof(sk_good)); 816 memset(&sk_bad, 0, sizeof(sk_bad)); 817 818 add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_good, 819 &key_new_blob_good, &sk_good, &hs_version_good, NULL); 820 add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_bad, 821 &key_new_blob_bad, &sk_bad, &hs_version_bad, NULL); 822 823 ed25519_public_key_generate(&pk_good, sk_good.v3); 824 ed25519_public_key_generate(&pk_bad, sk_bad.v3); 825 826 client_good = parse_authorized_client_key( 827 "N2NU7BSRL6YODZCYPN4CREB54TYLKGIE2KYOQWLFYC23ZJVCE5DQ", LOG_INFO); 828 client_bad = parse_authorized_client_key("dummy", LOG_INFO); 829 830 list_good = smartlist_new(); 831 smartlist_add(list_good, client_good); 832 833 add_onion_helper_add_service( 834 HS_VERSION_THREE, &sk_good, portcfgs, 1, 1, 835 /*pow_defenses_enabled=*/1, 836 /*pow_queue_rate=*/HS_CONFIG_V3_POW_QUEUE_RATE, 837 /*pow_queue_burst=*/HS_CONFIG_V3_POW_QUEUE_BURST, 838 list_good, &address_out_good); 839 840 service_good = find_service(global_map, &pk_good); 841 tt_int_op(smartlist_len(service_good->config.clients), OP_EQ, 1); 842 843 remove_service(global_map, service_good); 844 hs_service_free(service_good); 845 846 list_bad = smartlist_new(); 847 smartlist_add(list_bad, client_bad); 848 849 portcfg = hs_parse_port_config("8080", ",", NULL); 850 portcfgs = smartlist_new(); 851 smartlist_add(portcfgs, portcfg); 852 853 add_onion_helper_add_service( 854 HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1, 855 /*pow_defenses_enabled=*/1, 856 /*pow_queue_rate=*/HS_CONFIG_V3_POW_QUEUE_RATE, 857 /*pow_queue_burst=*/HS_CONFIG_V3_POW_QUEUE_BURST, 858 list_bad, &address_out_bad); 859 860 service_bad = find_service(global_map, &pk_bad); 861 862 tt_int_op(smartlist_len(service_bad->config.clients), OP_EQ, 0); 863 864 done: 865 tor_free(key_new_blob_good); 866 tor_free(key_new_blob_bad); 867 tor_free(address_out_good); 868 tor_free(address_out_bad); 869 870 hs_service_free(service_good); 871 hs_service_free(service_bad); 872 } 873 874 struct testcase_t hs_control_tests[] = { 875 { "hs_desc_event", test_hs_desc_event, TT_FORK, 876 NULL, NULL }, 877 { "hs_control_good_onion_client_auth_add", 878 test_hs_control_good_onion_client_auth_add, TT_FORK, 879 NULL, NULL }, 880 { "hs_control_bad_onion_client_auth_add", 881 test_hs_control_bad_onion_client_auth_add, TT_FORK, 882 NULL, NULL }, 883 { "hs_control_store_permanent_creds", 884 test_hs_control_store_permanent_creds, TT_FORK, NULL, NULL }, 885 { "hs_control_add_onion_with_bad_pubkey", 886 test_hs_control_add_onion_with_bad_pubkey, TT_FORK, NULL, NULL }, 887 { "hs_control_add_auth_onion_service", 888 test_hs_control_add_auth_onion_service, TT_FORK, NULL, NULL}, 889 { "hs_control_add_onion_helper_add_service", 890 test_hs_control_add_onion_helper_add_service, TT_FORK, NULL, NULL}, 891 892 END_OF_TESTCASES 893 };