aboutsummaryrefslogtreecommitdiff
path: root/src/test/test_hs_intropoint.c
diff options
context:
space:
mode:
authorGeorge Kadianakis <desnacked@riseup.net>2016-09-05 19:03:30 +0300
committerNick Mathewson <nickm@torproject.org>2016-12-14 15:18:40 -0500
commit297213825b288c954e13c3bccb3b3210063d244a (patch)
treecfac842bb072fbdc97629410ca70aad4dfdfaee2 /src/test/test_hs_intropoint.c
parent12dfe56b1cf9ec9852f27b8d10f2dcfad354f416 (diff)
downloadtor-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/test/test_hs_intropoint.c')
-rw-r--r--src/test/test_hs_intropoint.c360
1 files changed, 360 insertions, 0 deletions
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
+};
+