diff options
author | George Kadianakis <desnacked@riseup.net> | 2016-09-05 19:03:30 +0300 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2016-12-14 15:18:40 -0500 |
commit | 297213825b288c954e13c3bccb3b3210063d244a (patch) | |
tree | cfac842bb072fbdc97629410ca70aad4dfdfaee2 /src | |
parent | 12dfe56b1cf9ec9852f27b8d10f2dcfad354f416 (diff) | |
download | tor-297213825b288c954e13c3bccb3b3210063d244a.tar.gz tor-297213825b288c954e13c3bccb3b3210063d244a.zip |
prop224: Add unittests handling v3 ESTABLISH_INTRO cells.
Test for both v2 and v3 ESTABLISH_INTRO handling.
Diffstat (limited to 'src')
-rw-r--r-- | src/common/crypto_ed25519.c | 10 | ||||
-rw-r--r-- | src/common/crypto_ed25519.h | 11 | ||||
-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_hs_intropoint.c | 360 | ||||
-rw-r--r-- | src/test/test_hs_service.c | 112 |
7 files changed, 490 insertions, 11 deletions
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index 30ed772274..1be225d1a7 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -267,11 +267,11 @@ ed25519_sign(ed25519_signature_t *signature_out, * Like ed25519_sign(), but also prefix <b>msg</b> with <b>prefix_str</b> * before signing. <b>prefix_str</b> must be a NUL-terminated string. */ -int -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) +MOCK_IMPL(int, +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)) { int retval; size_t prefixed_msg_len; diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h index 31afc49ccc..08ba9be2fc 100644 --- a/src/common/crypto_ed25519.h +++ b/src/common/crypto_ed25519.h @@ -55,11 +55,12 @@ int ed25519_checksig(const ed25519_signature_t *signature, const uint8_t *msg, size_t len, const ed25519_public_key_t *pubkey); -int -ed25519_sign_prefixed(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const char *prefix_str, - const ed25519_keypair_t *keypair); +MOCK_DECL(int, +ed25519_sign_prefixed,(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t len, + const char *prefix_str, + const ed25519_keypair_t *keypair)); + int ed25519_checksig_prefixed(const ed25519_signature_t *signature, const uint8_t *msg, size_t len, diff --git a/src/test/include.am b/src/test/include.am index f6e43148f0..6177e5f920 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -96,6 +96,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 b02ecb922d..b49180cbfd 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1204,9 +1204,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 49b4499594..cf4735146f 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -201,6 +201,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_hs_intropoint.c b/src/test/test_hs_intropoint.c new file mode 100644 index 0000000000..76f9dbaea0 --- /dev/null +++ b/src/test/test_hs_intropoint.c @@ -0,0 +1,360 @@ +/* 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; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(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, char *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);; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(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; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(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; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(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; + char circuit_key_material[DIGEST_LEN] = {0}; + + tt_assert(intro_circ); + + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + crypto_rand(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; + char circuit_key_material[DIGEST_LEN] = {0}; + + tt_assert(intro_circ); + + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + crypto_rand(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, + 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..88c7ef2b35 --- /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; + char 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(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; + char circuit_key_material[DIGEST_LEN] = {0}; + + MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed); + + crypto_rand(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 +}; + |