diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/include.am | 2 | ||||
-rw-r--r-- | src/test/test.c | 4 | ||||
-rw-r--r-- | src/test/test.h | 2 | ||||
-rw-r--r-- | src/test/test_circuitlist.c | 63 | ||||
-rw-r--r-- | src/test/test_crypto.c | 49 | ||||
-rw-r--r-- | src/test/test_hs_intropoint.c | 361 | ||||
-rw-r--r-- | src/test/test_hs_service.c | 112 |
7 files changed, 563 insertions, 30 deletions
diff --git a/src/test/include.am b/src/test/include.am index 8d0fc2ff6b..d406d6d324 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -97,6 +97,8 @@ src_test_test_SOURCES = \ src/test/test_guardfraction.c \ src/test/test_extorport.c \ src/test/test_hs.c \ + src/test/test_hs_service.c \ + src/test/test_hs_intropoint.c \ src/test/test_handles.c \ src/test/test_hs_cache.c \ src/test/test_hs_descriptor.c \ diff --git a/src/test/test.c b/src/test/test.c index 750d8b00e4..866408e856 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1205,9 +1205,11 @@ struct testgroup_t testgroups[] = { { "entrynodes/", entrynodes_tests }, { "guardfraction/", guardfraction_tests }, { "extorport/", extorport_tests }, - { "hs/", hs_tests }, + { "legacy_hs/", hs_tests }, { "hs_cache/", hs_cache }, { "hs_descriptor/", hs_descriptor }, + { "hs_service/", hs_service_tests }, + { "hs_intropoint/", hs_intropoint_tests }, { "introduce/", introduce_tests }, { "keypin/", keypin_tests }, { "link-handshake/", link_handshake_tests }, diff --git a/src/test/test.h b/src/test/test.h index 2fa73592ef..2bd58f51c8 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -202,6 +202,8 @@ extern struct testcase_t extorport_tests[]; extern struct testcase_t hs_tests[]; extern struct testcase_t hs_cache[]; extern struct testcase_t hs_descriptor[]; +extern struct testcase_t hs_service_tests[]; +extern struct testcase_t hs_intropoint_tests[]; extern struct testcase_t introduce_tests[]; extern struct testcase_t keypin_tests[]; extern struct testcase_t link_handshake_tests[]; diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index e996c42115..7eed5fe225 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -4,10 +4,12 @@ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITBUILD_PRIVATE #define CIRCUITLIST_PRIVATE +#define HS_CIRCUITMAP_PRIVATE #include "or.h" #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "hs_circuitmap.h" #include "test.h" #include "log_test_helpers.h" @@ -185,6 +187,9 @@ test_rend_token_maps(void *arg) (void)arg; (void)tok1; //xxxx + + hs_circuitmap_init(); + c1 = or_circuit_new(0, NULL); c2 = or_circuit_new(0, NULL); c3 = or_circuit_new(0, NULL); @@ -196,68 +201,68 @@ test_rend_token_maps(void *arg) tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.'); /* No maps; nothing there. */ - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1)); - circuit_set_rendezvous_cookie(c1, tok1); - circuit_set_intro_point_digest(c2, tok2); + hs_circuitmap_register_rend_circ(c1, tok1); + hs_circuitmap_register_intro_circ_v2(c2, tok2); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok3)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3)); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1)); /* Without purpose set, we don't get the circuits */ - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; /* Okay, make sure they show up now. */ - tt_ptr_op(c1, OP_EQ, circuit_get_rendezvous(tok1)); - tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2)); + tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); + tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); /* Two items at the same place with the same token. */ c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; - circuit_set_rendezvous_cookie(c3, tok2); - tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2)); - tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2)); + hs_circuitmap_register_rend_circ(c3, tok2); + tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); /* Marking a circuit makes it not get returned any more */ circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); circuit_free(TO_CIRCUIT(c1)); c1 = NULL; /* Freeing a circuit makes it not get returned any more. */ circuit_free(TO_CIRCUIT(c2)); c2 = NULL; - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); /* c3 -- are you still there? */ - tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); /* Change its cookie. This never happens in Tor per se, but hey. */ c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - circuit_set_intro_point_digest(c3, tok3); + hs_circuitmap_register_intro_circ_v2(c3, tok3); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2)); - tt_ptr_op(c3, OP_EQ, circuit_get_intro_point(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); /* Now replace c3 with c4. */ c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - circuit_set_intro_point_digest(c4, tok3); + hs_circuitmap_register_intro_circ_v2(c4, tok3); - tt_ptr_op(c4, OP_EQ, circuit_get_intro_point(tok3)); + tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); - tt_ptr_op(c3->rendinfo, OP_EQ, NULL); - tt_ptr_op(c4->rendinfo, OP_NE, NULL); - tt_mem_op(c4->rendinfo, OP_EQ, tok3, REND_TOKEN_LEN); + tt_ptr_op(c3->hs_token, OP_EQ, NULL); + tt_ptr_op(c4->hs_token, OP_NE, NULL); + tt_mem_op(c4->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN); /* Now clear c4's cookie. */ - circuit_set_intro_point_digest(c4, NULL); - tt_ptr_op(c4->rendinfo, OP_EQ, NULL); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3)); + hs_circuitmap_remove_circuit(c4); + tt_ptr_op(c4->hs_token, OP_EQ, NULL); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); done: if (c1) diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 64a46f7914..d66ddccd4f 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1135,6 +1135,54 @@ test_crypto_sha3_xof(void *arg) tor_free(mem_op_hex_tmp); } +/* Test our MAC-SHA3 function. There are not actually any MAC-SHA3 test + * vectors out there for our H(len(k) || k || m) construction. Hence what we + * are gonna do is test our crypto_mac_sha3_256() function against manually + * doing H(len(k) || k||m). If in the future the Keccak group decides to + * standarize an MAC construction and make test vectors, we should + * incorporate them here. */ +static void +test_crypto_mac_sha3(void *arg) +{ + const char msg[] = "i am in a library somewhere using my computer"; + const char key[] = "i'm from the past talking to the future."; + + uint8_t hmac_test[DIGEST256_LEN]; + char hmac_manual[DIGEST256_LEN]; + + (void) arg; + + /* First let's use our nice HMAC-SHA3 function */ + crypto_mac_sha3_256(hmac_test, sizeof(hmac_test), + (uint8_t *) key, strlen(key), + (uint8_t *) msg, strlen(msg)); + + /* Now let's try a manual H(len(k) || k || m) construction */ + { + char *key_msg_concat = NULL, *all = NULL; + int result; + const uint64_t key_len_netorder = tor_htonll(strlen(key)); + size_t all_len; + + tor_asprintf(&key_msg_concat, "%s%s", key, msg); + all_len = sizeof(key_len_netorder) + strlen(key_msg_concat); + all = tor_malloc_zero(all_len); + memcpy(all, &key_len_netorder, sizeof(key_len_netorder)); + memcpy(all + sizeof(key_len_netorder), key_msg_concat, + strlen(key_msg_concat)); + + result = crypto_digest256(hmac_manual, all, all_len, DIGEST_SHA3_256); + tor_free(key_msg_concat); + tor_free(all); + tt_int_op(result, ==, 0); + } + + /* Now compare the two results */ + tt_mem_op(hmac_test, OP_EQ, hmac_manual, DIGEST256_LEN); + + done: ; +} + /** Run unit tests for our public key crypto functions */ static void test_crypto_pk(void *arg) @@ -2918,6 +2966,7 @@ struct testcase_t crypto_tests[] = { { "digest_names", test_crypto_digest_names, 0, NULL, NULL }, { "sha3", test_crypto_sha3, TT_FORK, NULL, NULL}, { "sha3_xof", test_crypto_sha3_xof, TT_FORK, NULL, NULL}, + { "mac_sha3", test_crypto_mac_sha3, TT_FORK, NULL, NULL}, CRYPTO_LEGACY(dh), { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &passthrough_setup, (void*)"aes" }, diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c new file mode 100644 index 0000000000..608988ba9a --- /dev/null +++ b/src/test/test_hs_intropoint.c @@ -0,0 +1,361 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_service.c + * \brief Test hidden service functionality. + */ + +#define HS_SERVICE_PRIVATE +#define HS_INTROPOINT_PRIVATE +#define RENDSERVICE_PRIVATE +#define CIRCUITLIST_PRIVATE + +#include "test.h" +#include "crypto.h" + +#include "or.h" +#include "ht.h" + +#include "hs/cell_establish_intro.h" +#include "hs_service.h" +#include "hs_circuitmap.h" +#include "hs_intropoint.h" + +#include "circuitlist.h" +#include "circuituse.h" +#include "rendservice.h" + +/* Mock function to avoid networking in unittests */ +static int +mock_send_intro_established_cell(or_circuit_t *circ) +{ + (void) circ; + return 0; +} + +/* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro + * point. Should fail. */ +static void +test_establish_intro_wrong_purpose(void *arg) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + memcpy(intro_circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN); + + /* Set a bad circuit purpose!! :) */ + circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Receive the cell */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, -1); + + done: + hs_cell_establish_intro_free(establish_intro_cell); + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Prepare a circuit for accepting an ESTABLISH_INTRO cell */ +static void +helper_prepare_circ_for_intro(or_circuit_t *circ, + uint8_t *circuit_key_material) +{ + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR); + memcpy(circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN); +} + +/* Send an empty ESTABLISH_INTRO cell. Should fail. */ +static void +test_establish_intro_wrong_keytype(void *arg) +{ + int retval; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Receive the cell. Should fail. */ + retval = hs_intro_received_establish_intro(intro_circ, (uint8_t*)"", 0); + tt_int_op(retval, ==, -1); + + done: + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */ +static void +test_establish_intro_wrong_keytype2(void *arg) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Mutate the auth key type! :) */ + cell_body[0] = 42; + + /* Receive the cell. Should fail. */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, -1); + + done: + hs_cell_establish_intro_free(establish_intro_cell); + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should + * fail. */ +static void +test_establish_intro_wrong_sig(void *arg) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Mutate the last byte (signature)! :) */ + cell_body[cell_len-1]++; + + /* Receive the cell. Should fail. */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, -1); + + done: + hs_cell_establish_intro_free(establish_intro_cell); + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to + * <b>intro_circ</b>. Return the cell. */ +static hs_cell_establish_intro_t * +helper_establish_intro_v3(or_circuit_t *intro_circ) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + + tt_assert(intro_circ); + + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Receive the cell */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, 0); + + done: + return establish_intro_cell; +} + +/* Helper function: Send a well-formed v2 ESTABLISH_INTRO cell to + * <b>intro_circ</b>. Return the public key advertised in the cell. */ +static crypto_pk_t * +helper_establish_intro_v2(or_circuit_t *intro_circ) +{ + crypto_pk_t *key1 = NULL; + int retval; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + + tt_assert(intro_circ); + + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Send legacy establish_intro */ + key1 = pk_generate(0); + + /* Use old circuit_key_material why not */ + cell_len = encode_establish_intro_cell_legacy((char*)cell_body, + key1, + (char *) circuit_key_material); + tt_int_op(cell_len, >, 0); + + /* Receive legacy establish_intro */ + retval = hs_intro_received_establish_intro(intro_circ, + cell_body, cell_len); + tt_int_op(retval, ==, 0); + + done: + return key1; +} + +/** Successfuly register a v2 intro point and a v3 intro point. Ensure that HS + * circuitmap is maintained properly. */ +static void +test_intro_point_registration(void *arg) +{ + int retval; + hs_circuitmap_ht *the_hs_circuitmap = NULL; + + or_circuit_t *intro_circ = NULL; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + ed25519_public_key_t auth_key; + + crypto_pk_t *legacy_auth_key = NULL; + or_circuit_t *legacy_intro_circ = NULL; + + or_circuit_t *returned_intro_circ = NULL; + + (void) arg; + + MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell); + + hs_circuitmap_init(); + + /* Check that the circuitmap is currently empty */ + { + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + tt_int_op(0, ==, HT_SIZE(the_hs_circuitmap)); + /* Do a circuitmap query in any case */ + returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key); + tt_ptr_op(returned_intro_circ, ==, NULL); + } + + /* Create a v3 intro point */ + { + intro_circ = or_circuit_new(0, NULL); + tt_assert(intro_circ); + establish_intro_cell = helper_establish_intro_v3(intro_circ); + + /* Check that the intro point was registered on the HS circuitmap */ + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + tt_int_op(1, ==, HT_SIZE(the_hs_circuitmap)); + get_auth_key_from_establish_intro_cell(&auth_key, establish_intro_cell); + returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key); + tt_ptr_op(intro_circ, ==, returned_intro_circ); + } + + /* Create a v2 intro point */ + { + char key_digest[DIGEST_LEN]; + + legacy_intro_circ = or_circuit_new(1, NULL); + tt_assert(legacy_intro_circ); + legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ); + tt_assert(legacy_auth_key); + + /* Check that the circuitmap now has two elements */ + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + tt_int_op(2, ==, HT_SIZE(the_hs_circuitmap)); + + /* Check that the new element is our legacy intro circuit. */ + retval = crypto_pk_get_digest(legacy_auth_key, key_digest); + tt_int_op(retval, ==, 0); + returned_intro_circ= hs_circuitmap_get_intro_circ_v2((uint8_t*)key_digest); + tt_ptr_op(legacy_intro_circ, ==, returned_intro_circ); + } + + /* XXX Continue test and try to register a second v3 intro point with the + * same auth key. Make sure that old intro circuit gets closed. */ + + done: + crypto_pk_free(legacy_auth_key); + circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free(TO_CIRCUIT(legacy_intro_circ)); + hs_cell_establish_intro_free(establish_intro_cell); + + { /* Test circuitmap free_all function. */ + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + hs_circuitmap_free_all(); + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(!the_hs_circuitmap); + } + + UNMOCK(hs_intro_send_intro_established_cell); +} + +struct testcase_t hs_intropoint_tests[] = { + { "intro_point_registration", + test_intro_point_registration, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_keytype", + test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_keytype2", + test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_purpose", + test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_sig", + test_establish_intro_wrong_sig, TT_FORK, NULL, NULL }, + + END_OF_TESTCASES +}; + diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c new file mode 100644 index 0000000000..195e5069cb --- /dev/null +++ b/src/test/test_hs_service.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_service.c + * \brief Test hidden service functionality. + */ + +#define HS_SERVICE_PRIVATE +#define HS_INTROPOINT_PRIVATE + +#include "test.h" +#include "log_test_helpers.h" +#include "crypto.h" + +#include "hs/cell_establish_intro.h" +#include "hs_service.h" +#include "hs_intropoint.h" + +/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we + * parse it from the receiver side. */ +static void +test_gen_establish_intro_cell(void *arg) +{ + (void) arg; + int retval; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + uint8_t buf[RELAY_PAYLOAD_SIZE]; + hs_cell_establish_intro_t *cell_out = NULL; + hs_cell_establish_intro_t *cell_in = NULL; + + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + { + cell_out = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(cell_out); + + retval = get_establish_intro_payload(buf, sizeof(buf), cell_out); + tt_int_op(retval, >=, 0); + } + + /* Parse it as the receiver */ + { + ssize_t parse_result = hs_cell_establish_intro_parse(&cell_in, + buf, sizeof(buf)); + tt_int_op(parse_result, >=, 0); + + retval = verify_establish_intro_cell(cell_in, + circuit_key_material, + sizeof(circuit_key_material)); + tt_int_op(retval, >=, 0); + } + + done: + hs_cell_establish_intro_free(cell_out); + hs_cell_establish_intro_free(cell_in); +} + +/* Mocked ed25519_sign_prefixed() function that always fails :) */ +static int +mock_ed25519_sign_prefixed(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t msg_len, + const char *prefix_str, + const ed25519_keypair_t *keypair) { + (void) signature_out; + (void) msg; + (void) msg_len; + (void) prefix_str; + (void) keypair; + return -1; +} + +/** We simulate a failure to create an ESTABLISH_INTRO cell */ +static void +test_gen_establish_intro_cell_bad(void *arg) +{ + (void) arg; + hs_cell_establish_intro_t *cell = NULL; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; + + MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed); + + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); + + setup_full_capture_of_logs(LOG_WARN); + /* Easiest way to make that function fail is to mock the + ed25519_sign_prefixed() function and make it fail. */ + cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + expect_log_msg_containing("Unable to gen signature for " + "ESTABLISH_INTRO cell."); + teardown_capture_of_logs(); + tt_assert(!cell); + + done: + hs_cell_establish_intro_free(cell); + UNMOCK(ed25519_sign_prefixed); +} + +struct testcase_t hs_service_tests[] = { + { "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK, + NULL, NULL }, + { "gen_establish_intro_cell_bad", test_gen_establish_intro_cell_bad, TT_FORK, + NULL, NULL }, + + + END_OF_TESTCASES +}; + |