mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-09-22 05:54:58 +02:00
Write unittest that covers cases of INTRODUCE1 handling.
Also fix some memleaks of other OB unittests.
This commit is contained in:
parent
635f58bad2
commit
ba99287d13
@ -2819,8 +2819,8 @@ extend_info_dup(extend_info_t *info)
|
|||||||
* If there is no chosen exit, or if we don't know the node_t for
|
* If there is no chosen exit, or if we don't know the node_t for
|
||||||
* the chosen exit, return NULL.
|
* the chosen exit, return NULL.
|
||||||
*/
|
*/
|
||||||
const node_t *
|
MOCK_IMPL(const node_t *,
|
||||||
build_state_get_exit_node(cpath_build_state_t *state)
|
build_state_get_exit_node,(cpath_build_state_t *state))
|
||||||
{
|
{
|
||||||
if (!state || !state->chosen_exit)
|
if (!state || !state->chosen_exit)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -66,7 +66,8 @@ int circuit_can_use_tap(const origin_circuit_t *circ);
|
|||||||
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
|
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
|
||||||
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
|
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
|
||||||
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
|
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
|
||||||
const node_t *build_state_get_exit_node(cpath_build_state_t *state);
|
MOCK_DECL(const node_t *,
|
||||||
|
build_state_get_exit_node,(cpath_build_state_t *state));
|
||||||
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
||||||
|
|
||||||
struct circuit_guard_state_t;
|
struct circuit_guard_state_t;
|
||||||
|
@ -368,10 +368,10 @@ get_service_anonymity_string(const hs_service_t *service)
|
|||||||
* success, a circuit identifier is attached to the circuit with the needed
|
* success, a circuit identifier is attached to the circuit with the needed
|
||||||
* data. This function will try to open a circuit for a maximum value of
|
* data. This function will try to open a circuit for a maximum value of
|
||||||
* MAX_REND_FAILURES then it will give up. */
|
* MAX_REND_FAILURES then it will give up. */
|
||||||
static void
|
MOCK_IMPL(STATIC void,
|
||||||
launch_rendezvous_point_circuit(const hs_service_t *service,
|
launch_rendezvous_point_circuit,(const hs_service_t *service,
|
||||||
const hs_service_intro_point_t *ip,
|
const hs_service_intro_point_t *ip,
|
||||||
const hs_cell_introduce2_data_t *data)
|
const hs_cell_introduce2_data_t *data))
|
||||||
{
|
{
|
||||||
int circ_needs_uptime;
|
int circ_needs_uptime;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
@ -79,6 +79,12 @@ create_rp_circuit_identifier(const hs_service_t *service,
|
|||||||
const curve25519_public_key_t *server_pk,
|
const curve25519_public_key_t *server_pk,
|
||||||
const struct hs_ntor_rend_cell_keys_t *keys);
|
const struct hs_ntor_rend_cell_keys_t *keys);
|
||||||
|
|
||||||
|
struct hs_cell_introduce2_data_t;
|
||||||
|
MOCK_DECL(STATIC void,
|
||||||
|
launch_rendezvous_point_circuit,(const hs_service_t *service,
|
||||||
|
const hs_service_intro_point_t *ip,
|
||||||
|
const struct hs_cell_introduce2_data_t *data));
|
||||||
|
|
||||||
#endif /* defined(HS_CIRCUIT_PRIVATE) */
|
#endif /* defined(HS_CIRCUIT_PRIVATE) */
|
||||||
|
|
||||||
#endif /* !defined(TOR_HS_CIRCUIT_H) */
|
#endif /* !defined(TOR_HS_CIRCUIT_H) */
|
||||||
|
@ -1213,8 +1213,8 @@ node_get_rsa_id_digest(const node_t *node)
|
|||||||
* If node is NULL, returns an empty smartlist.
|
* If node is NULL, returns an empty smartlist.
|
||||||
*
|
*
|
||||||
* The smartlist must be freed using link_specifier_smartlist_free(). */
|
* The smartlist must be freed using link_specifier_smartlist_free(). */
|
||||||
smartlist_t *
|
MOCK_IMPL(smartlist_t *,
|
||||||
node_get_link_specifier_smartlist(const node_t *node, bool direct_conn)
|
node_get_link_specifier_smartlist,(const node_t *node, bool direct_conn))
|
||||||
{
|
{
|
||||||
link_specifier_t *ls;
|
link_specifier_t *ls;
|
||||||
tor_addr_port_t ap;
|
tor_addr_port_t ap;
|
||||||
|
@ -78,8 +78,8 @@ int node_supports_ed25519_hs_intro(const node_t *node);
|
|||||||
int node_supports_v3_rendezvous_point(const node_t *node);
|
int node_supports_v3_rendezvous_point(const node_t *node);
|
||||||
int node_supports_establish_intro_dos_extension(const node_t *node);
|
int node_supports_establish_intro_dos_extension(const node_t *node);
|
||||||
const uint8_t *node_get_rsa_id_digest(const node_t *node);
|
const uint8_t *node_get_rsa_id_digest(const node_t *node);
|
||||||
smartlist_t *node_get_link_specifier_smartlist(const node_t *node,
|
MOCK_DECL(smartlist_t *,node_get_link_specifier_smartlist,(const node_t *node,
|
||||||
bool direct_conn);
|
bool direct_conn));
|
||||||
void link_specifier_smartlist_free_(smartlist_t *ls_list);
|
void link_specifier_smartlist_free_(smartlist_t *ls_list);
|
||||||
#define link_specifier_smartlist_free(ls_list) \
|
#define link_specifier_smartlist_free(ls_list) \
|
||||||
FREE_AND_NULL(smartlist_t, link_specifier_smartlist_free_, (ls_list))
|
FREE_AND_NULL(smartlist_t, link_specifier_smartlist_free_, (ls_list))
|
||||||
|
@ -13,9 +13,22 @@
|
|||||||
#include "feature/hs/hs_service.h"
|
#include "feature/hs/hs_service.h"
|
||||||
#include "test/hs_test_helpers.h"
|
#include "test/hs_test_helpers.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an introduction point taken straight out of an HSv3 descriptor.
|
||||||
|
*
|
||||||
|
* Use 'signing_kp' to sign the introduction point certificates.
|
||||||
|
*
|
||||||
|
* If 'intro_auth_kp' is provided use that as the introduction point
|
||||||
|
* authentication keypair, otherwise generate one on the fly.
|
||||||
|
*
|
||||||
|
* If 'intro_enc_kp' is provided use that as the introduction point encryption
|
||||||
|
* keypair, otherwise generate one on the fly.
|
||||||
|
*/
|
||||||
hs_desc_intro_point_t *
|
hs_desc_intro_point_t *
|
||||||
hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
|
hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
|
||||||
const char *addr, int legacy)
|
const char *addr, int legacy,
|
||||||
|
const ed25519_keypair_t *intro_auth_kp,
|
||||||
|
const curve25519_keypair_t *intro_enc_kp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
ed25519_keypair_t auth_kp;
|
ed25519_keypair_t auth_kp;
|
||||||
@ -56,8 +69,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
|
|||||||
smartlist_add(ip->link_specifiers, ls_ip);
|
smartlist_add(ip->link_specifiers, ls_ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (intro_auth_kp) {
|
||||||
|
memcpy(&auth_kp, intro_auth_kp, sizeof(ed25519_keypair_t));
|
||||||
|
} else {
|
||||||
ret = ed25519_keypair_generate(&auth_kp, 0);
|
ret = ed25519_keypair_generate(&auth_kp, 0);
|
||||||
tt_int_op(ret, OP_EQ, 0);
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
}
|
||||||
ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
|
ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
|
||||||
&auth_kp.pubkey, now,
|
&auth_kp.pubkey, now,
|
||||||
HS_DESC_CERT_LIFETIME,
|
HS_DESC_CERT_LIFETIME,
|
||||||
@ -85,8 +102,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
|
|||||||
ed25519_keypair_t ed25519_kp;
|
ed25519_keypair_t ed25519_kp;
|
||||||
tor_cert_t *cross_cert;
|
tor_cert_t *cross_cert;
|
||||||
|
|
||||||
|
if (intro_enc_kp) {
|
||||||
|
memcpy(&curve25519_kp, intro_enc_kp, sizeof(curve25519_keypair_t));
|
||||||
|
} else {
|
||||||
ret = curve25519_keypair_generate(&curve25519_kp, 0);
|
ret = curve25519_keypair_generate(&curve25519_kp, 0);
|
||||||
tt_int_op(ret, OP_EQ, 0);
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
}
|
||||||
ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
|
ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
|
||||||
&curve25519_kp);
|
&curve25519_kp);
|
||||||
cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
|
cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
|
||||||
@ -95,6 +116,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
|
|||||||
CERT_FLAG_INCLUDE_SIGNING_KEY);
|
CERT_FLAG_INCLUDE_SIGNING_KEY);
|
||||||
tt_assert(cross_cert);
|
tt_assert(cross_cert);
|
||||||
ip->enc_key_cert = cross_cert;
|
ip->enc_key_cert = cross_cert;
|
||||||
|
memcpy(ip->enc_key.public_key, curve25519_kp.pubkey.public_key,
|
||||||
|
CURVE25519_PUBKEY_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
intro_point = ip;
|
intro_point = ip;
|
||||||
@ -165,13 +188,17 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
|
|||||||
if (!no_ip) {
|
if (!no_ip) {
|
||||||
/* Add four intro points. */
|
/* Add four intro points. */
|
||||||
smartlist_add(desc->encrypted_data.intro_points,
|
smartlist_add(desc->encrypted_data.intro_points,
|
||||||
hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0));
|
hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0,
|
||||||
|
NULL, NULL));
|
||||||
smartlist_add(desc->encrypted_data.intro_points,
|
smartlist_add(desc->encrypted_data.intro_points,
|
||||||
hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0));
|
hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0,
|
||||||
|
NULL, NULL));
|
||||||
smartlist_add(desc->encrypted_data.intro_points,
|
smartlist_add(desc->encrypted_data.intro_points,
|
||||||
hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1));
|
hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1,
|
||||||
|
NULL, NULL));
|
||||||
smartlist_add(desc->encrypted_data.intro_points,
|
smartlist_add(desc->encrypted_data.intro_points,
|
||||||
hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1));
|
hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1,
|
||||||
|
NULL, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
descp = desc;
|
descp = desc;
|
||||||
|
@ -8,9 +8,11 @@
|
|||||||
#include "feature/hs/hs_descriptor.h"
|
#include "feature/hs/hs_descriptor.h"
|
||||||
|
|
||||||
/* Set of functions to help build and test descriptors. */
|
/* Set of functions to help build and test descriptors. */
|
||||||
hs_desc_intro_point_t *hs_helper_build_intro_point(
|
hs_desc_intro_point_t *
|
||||||
const ed25519_keypair_t *signing_kp, time_t now,
|
hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
|
||||||
const char *addr, int legacy);
|
const char *addr, int legacy,
|
||||||
|
const ed25519_keypair_t *intro_auth_kp,
|
||||||
|
const curve25519_keypair_t *intro_enc_kp);
|
||||||
hs_descriptor_t *hs_helper_build_hs_desc_no_ip(
|
hs_descriptor_t *hs_helper_build_hs_desc_no_ip(
|
||||||
const ed25519_keypair_t *signing_kp);
|
const ed25519_keypair_t *signing_kp);
|
||||||
hs_descriptor_t *hs_helper_build_hs_desc_with_ip(
|
hs_descriptor_t *hs_helper_build_hs_desc_with_ip(
|
||||||
|
@ -169,6 +169,7 @@ static void
|
|||||||
test_get_subcredentials(void *arg)
|
test_get_subcredentials(void *arg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
hs_service_t *service = NULL;
|
||||||
hs_service_config_t config;
|
hs_service_config_t config;
|
||||||
|
|
||||||
(void) arg;
|
(void) arg;
|
||||||
@ -192,7 +193,7 @@ test_get_subcredentials(void *arg)
|
|||||||
smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey);
|
smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey);
|
||||||
|
|
||||||
/* Set up an instance */
|
/* Set up an instance */
|
||||||
hs_service_t *service = tor_malloc_zero(sizeof(hs_service_t));
|
service = tor_malloc_zero(sizeof(hs_service_t));
|
||||||
service->config = config;
|
service->config = config;
|
||||||
service->desc_current = service_descriptor_new();
|
service->desc_current = service_descriptor_new();
|
||||||
service->desc_next = service_descriptor_new();
|
service->desc_next = service_descriptor_new();
|
||||||
@ -234,7 +235,12 @@ test_get_subcredentials(void *arg)
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
tor_free(subcreds);
|
tor_free(subcreds);
|
||||||
|
|
||||||
smartlist_free(config.ob_master_pubkeys);
|
smartlist_free(config.ob_master_pubkeys);
|
||||||
|
if (service) {
|
||||||
|
memset(&service->config, 0, sizeof(hs_service_config_t));
|
||||||
|
hs_service_free(service);
|
||||||
|
}
|
||||||
|
|
||||||
UNMOCK(networkstatus_get_live_consensus);
|
UNMOCK(networkstatus_get_live_consensus);
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,8 @@
|
|||||||
#include "feature/hs/hs_common.h"
|
#include "feature/hs/hs_common.h"
|
||||||
#include "feature/hs/hs_config.h"
|
#include "feature/hs/hs_config.h"
|
||||||
#include "feature/hs/hs_ident.h"
|
#include "feature/hs/hs_ident.h"
|
||||||
|
#include "feature/hs/hs_ob.h"
|
||||||
|
#include "feature/hs/hs_cell.h"
|
||||||
#include "feature/hs/hs_intropoint.h"
|
#include "feature/hs/hs_intropoint.h"
|
||||||
#include "feature/hs/hs_service.h"
|
#include "feature/hs/hs_service.h"
|
||||||
#include "feature/nodelist/networkstatus.h"
|
#include "feature/nodelist/networkstatus.h"
|
||||||
@ -109,6 +111,9 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t relay_payload_len;
|
||||||
|
static char relay_payload[RELAY_PAYLOAD_SIZE];
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
|
mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
|
||||||
uint8_t relay_command, const char *payload,
|
uint8_t relay_command, const char *payload,
|
||||||
@ -124,6 +129,10 @@ mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
|
|||||||
(void) cpath_layer;
|
(void) cpath_layer;
|
||||||
(void) filename;
|
(void) filename;
|
||||||
(void) lineno;
|
(void) lineno;
|
||||||
|
|
||||||
|
memcpy(relay_payload, payload, payload_len);
|
||||||
|
relay_payload_len = payload_len;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1160,7 +1169,7 @@ test_closing_intro_circs(void *arg)
|
|||||||
|
|
||||||
/** Test sending and receiving introduce2 cells */
|
/** Test sending and receiving introduce2 cells */
|
||||||
static void
|
static void
|
||||||
test_introduce2(void *arg)
|
test_bad_introduce2(void *arg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
|
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
|
||||||
@ -2169,6 +2178,348 @@ test_export_client_circuit_id(void *arg)
|
|||||||
tor_free(cp2);
|
tor_free(cp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static smartlist_t *
|
||||||
|
mock_node_get_link_specifier_smartlist(const node_t *node, bool direct_conn)
|
||||||
|
{
|
||||||
|
(void) node;
|
||||||
|
(void) direct_conn;
|
||||||
|
|
||||||
|
smartlist_t *lspecs = smartlist_new();
|
||||||
|
link_specifier_t *ls_legacy = link_specifier_new();
|
||||||
|
smartlist_add(lspecs, ls_legacy);
|
||||||
|
|
||||||
|
return lspecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static node_t *fake_node = NULL;
|
||||||
|
|
||||||
|
static const node_t *
|
||||||
|
mock_build_state_get_exit_node(cpath_build_state_t *state)
|
||||||
|
{
|
||||||
|
(void) state;
|
||||||
|
|
||||||
|
if (!fake_node) {
|
||||||
|
curve25519_secret_key_t seckey;
|
||||||
|
curve25519_secret_key_generate(&seckey, 0);
|
||||||
|
|
||||||
|
fake_node = tor_malloc_zero(sizeof(node_t));
|
||||||
|
fake_node->ri = tor_malloc_zero(sizeof(routerinfo_t));
|
||||||
|
fake_node->ri->onion_curve25519_pkey =
|
||||||
|
tor_malloc_zero(sizeof(curve25519_public_key_t));
|
||||||
|
curve25519_public_key_generate(fake_node->ri->onion_curve25519_pkey,
|
||||||
|
&seckey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fake_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mock_launch_rendezvous_point_circuit(const hs_service_t *service,
|
||||||
|
const hs_service_intro_point_t *ip,
|
||||||
|
const hs_cell_introduce2_data_t *data)
|
||||||
|
{
|
||||||
|
(void) service;
|
||||||
|
(void) ip;
|
||||||
|
(void) data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that INTRO2 cells are handled well by onion services in the normal
|
||||||
|
* case and also when onionbalance is enabled.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_intro2_handling(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
MOCK(build_state_get_exit_node, mock_build_state_get_exit_node);
|
||||||
|
MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
|
||||||
|
MOCK(node_get_link_specifier_smartlist,
|
||||||
|
mock_node_get_link_specifier_smartlist);
|
||||||
|
MOCK(launch_rendezvous_point_circuit, mock_launch_rendezvous_point_circuit);
|
||||||
|
|
||||||
|
memset(relay_payload, 0, sizeof(relay_payload));
|
||||||
|
|
||||||
|
int retval;
|
||||||
|
time_t now = 0101010101;
|
||||||
|
update_approx_time(now);
|
||||||
|
|
||||||
|
/** OK this is the play:
|
||||||
|
*
|
||||||
|
* In Act I, we have a standalone onion service X (without onionbalance
|
||||||
|
* enabled). We test that X can properly handle INTRO2 cells sent by a
|
||||||
|
* client Alice.
|
||||||
|
*
|
||||||
|
* In Act II, we create an onionbalance setup with frontend being Z which
|
||||||
|
* includes instances X and Y. We then setup onionbalance on X and test that
|
||||||
|
* Alice who addresses Z can communicate with X through INTRO2 cells.
|
||||||
|
*
|
||||||
|
* In Act III, we test that Alice can also communicate with X
|
||||||
|
* directly even tho onionbalance is enabled.
|
||||||
|
*
|
||||||
|
* And finally in Act IV, we check various cases where the INTRO2 cell
|
||||||
|
* should not go through because the subcredentials don't line up
|
||||||
|
* (e.g. Alice sends INTRO2 to X using Y's subcredential).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Let's start with some setup! Create the instances and the frontend
|
||||||
|
service, create Alice, etc: */
|
||||||
|
|
||||||
|
/* Create instance X */
|
||||||
|
hs_service_t x_service;
|
||||||
|
memset(&x_service, 0, sizeof(hs_service_t));
|
||||||
|
/* Disable onionbalance */
|
||||||
|
x_service.config.ob_master_pubkeys = NULL;
|
||||||
|
x_service.state.replay_cache_rend_cookie = replaycache_new(0,0);
|
||||||
|
|
||||||
|
/* Create subcredential for x: */
|
||||||
|
ed25519_keypair_t x_identity_keypair;
|
||||||
|
hs_subcredential_t x_subcred;
|
||||||
|
ed25519_keypair_generate(&x_identity_keypair, 0);
|
||||||
|
hs_helper_get_subcred_from_identity_keypair(&x_identity_keypair,
|
||||||
|
&x_subcred);
|
||||||
|
|
||||||
|
/* Create the x instance's intro point */
|
||||||
|
hs_service_intro_point_t *x_ip = NULL;
|
||||||
|
{
|
||||||
|
curve25519_secret_key_t seckey;
|
||||||
|
curve25519_public_key_t pkey;
|
||||||
|
curve25519_secret_key_generate(&seckey, 0);
|
||||||
|
curve25519_public_key_generate(&pkey, &seckey);
|
||||||
|
|
||||||
|
node_t intro_node;
|
||||||
|
memset(&intro_node, 0, sizeof(intro_node));
|
||||||
|
routerinfo_t ri;
|
||||||
|
memset(&ri, 0, sizeof(routerinfo_t));
|
||||||
|
ri.onion_curve25519_pkey = &pkey;
|
||||||
|
intro_node.ri = &ri;
|
||||||
|
|
||||||
|
x_ip = service_intro_point_new(&intro_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create z frontend's subcredential */
|
||||||
|
ed25519_keypair_t z_identity_keypair;
|
||||||
|
hs_subcredential_t z_subcred;
|
||||||
|
ed25519_keypair_generate(&z_identity_keypair, 0);
|
||||||
|
hs_helper_get_subcred_from_identity_keypair(&z_identity_keypair,
|
||||||
|
&z_subcred);
|
||||||
|
|
||||||
|
/* Create y instance's subcredential */
|
||||||
|
ed25519_keypair_t y_identity_keypair;
|
||||||
|
hs_subcredential_t y_subcred;
|
||||||
|
ed25519_keypair_generate(&y_identity_keypair, 0);
|
||||||
|
hs_helper_get_subcred_from_identity_keypair(&y_identity_keypair,
|
||||||
|
&y_subcred);
|
||||||
|
|
||||||
|
/* Create Alice's intro point */
|
||||||
|
hs_desc_intro_point_t *alice_ip;
|
||||||
|
ed25519_keypair_t signing_kp;
|
||||||
|
ed25519_keypair_generate(&signing_kp, 0);
|
||||||
|
alice_ip = hs_helper_build_intro_point(&signing_kp, now, "1.2.3.4", 0,
|
||||||
|
&x_ip->auth_key_kp,
|
||||||
|
&x_ip->enc_key_kp);
|
||||||
|
|
||||||
|
/* Create Alice's intro and rend circuits */
|
||||||
|
origin_circuit_t *intro_circ = origin_circuit_new();
|
||||||
|
intro_circ->cpath = tor_malloc_zero(sizeof(crypt_path_t));
|
||||||
|
intro_circ->cpath->prev = intro_circ->cpath;
|
||||||
|
intro_circ->hs_ident = tor_malloc_zero(sizeof(*intro_circ->hs_ident));
|
||||||
|
origin_circuit_t rend_circ;
|
||||||
|
rend_circ.hs_ident = tor_malloc_zero(sizeof(*rend_circ.hs_ident));
|
||||||
|
curve25519_keypair_generate(&rend_circ.hs_ident->rendezvous_client_kp, 0);
|
||||||
|
memset(rend_circ.hs_ident->rendezvous_cookie, 'r', HS_REND_COOKIE_LEN);
|
||||||
|
|
||||||
|
/* ************************************************************ */
|
||||||
|
|
||||||
|
/* Act I:
|
||||||
|
*
|
||||||
|
* Where Alice connects to X without onionbalance in the picture */
|
||||||
|
|
||||||
|
/* Create INTRODUCE1 */
|
||||||
|
tt_assert(fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
|
||||||
|
retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
|
||||||
|
alice_ip, &x_subcred);
|
||||||
|
|
||||||
|
/* Check that the payload was written successfully */
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
|
||||||
|
tt_int_op(relay_payload_len, OP_NE, 0);
|
||||||
|
|
||||||
|
/* Handle the cell */
|
||||||
|
retval = hs_circ_handle_introduce2(&x_service,
|
||||||
|
intro_circ, x_ip,
|
||||||
|
&x_subcred,
|
||||||
|
(uint8_t*)relay_payload,relay_payload_len);
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* ************************************************************ */
|
||||||
|
|
||||||
|
/* Act II:
|
||||||
|
*
|
||||||
|
* We now create an onionbalance setup with Z being the frontend and X and Y
|
||||||
|
* being the backend instances. Make sure that Alice can talk with the
|
||||||
|
* backend instance X even tho she thinks she is talking to the frontend Z.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Now configure the X instance to do onionbalance with Z as the frontend */
|
||||||
|
x_service.config.ob_master_pubkeys = smartlist_new();
|
||||||
|
smartlist_add(x_service.config.ob_master_pubkeys,
|
||||||
|
&z_identity_keypair.pubkey);
|
||||||
|
|
||||||
|
/* Create descriptors for x and load next descriptor with the x's
|
||||||
|
* subcredential so that it can accept connections for itself. */
|
||||||
|
x_service.desc_current = service_descriptor_new();
|
||||||
|
memset(x_service.desc_current->desc->subcredential.subcred, 'C',SUBCRED_LEN);
|
||||||
|
x_service.desc_next = service_descriptor_new();
|
||||||
|
memcpy(&x_service.desc_next->desc->subcredential, &x_subcred, SUBCRED_LEN);
|
||||||
|
|
||||||
|
/* Refresh OB keys */
|
||||||
|
hs_ob_refresh_keys(&x_service);
|
||||||
|
|
||||||
|
/* Create INTRODUCE1 from Alice to X through Z */
|
||||||
|
memset(relay_payload, 0, sizeof(relay_payload));
|
||||||
|
retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
|
||||||
|
alice_ip, &z_subcred);
|
||||||
|
|
||||||
|
/* Check that the payload was written successfully */
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
|
||||||
|
tt_int_op(relay_payload_len, OP_NE, 0);
|
||||||
|
|
||||||
|
/* Deliver INTRODUCE1 to X even tho it carries Z's subcredential */
|
||||||
|
replaycache_free(x_service.state.replay_cache_rend_cookie);
|
||||||
|
x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
|
||||||
|
|
||||||
|
retval = hs_circ_handle_introduce2(&x_service,
|
||||||
|
intro_circ, x_ip,
|
||||||
|
&z_subcred,
|
||||||
|
(uint8_t*)relay_payload, relay_payload_len);
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
|
||||||
|
replaycache_free(x_ip->replay_cache);
|
||||||
|
x_ip->replay_cache = replaycache_new(0, 0);
|
||||||
|
|
||||||
|
replaycache_free(x_service.state.replay_cache_rend_cookie);
|
||||||
|
x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
|
||||||
|
|
||||||
|
/* ************************************************************ */
|
||||||
|
|
||||||
|
/* Act III:
|
||||||
|
*
|
||||||
|
* Now send a direct INTRODUCE cell from Alice to X using X's subcredential
|
||||||
|
* and check that it succeeds even with onionbalance enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Refresh OB keys (just to check for memleaks) */
|
||||||
|
hs_ob_refresh_keys(&x_service);
|
||||||
|
|
||||||
|
/* Create INTRODUCE1 from Alice to X using X's subcred. */
|
||||||
|
memset(relay_payload, 0, sizeof(relay_payload));
|
||||||
|
retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
|
||||||
|
alice_ip, &x_subcred);
|
||||||
|
|
||||||
|
/* Check that the payload was written successfully */
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
|
||||||
|
tt_int_op(relay_payload_len, OP_NE, 0);
|
||||||
|
|
||||||
|
/* Send INTRODUCE1 to X with X's subcredential (should succeed) */
|
||||||
|
replaycache_free(x_service.state.replay_cache_rend_cookie);
|
||||||
|
x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
|
||||||
|
|
||||||
|
retval = hs_circ_handle_introduce2(&x_service,
|
||||||
|
intro_circ, x_ip,
|
||||||
|
&x_subcred,
|
||||||
|
(uint8_t*)relay_payload, relay_payload_len);
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* ************************************************************ */
|
||||||
|
|
||||||
|
/* Act IV:
|
||||||
|
*
|
||||||
|
* Test cases where the INTRO2 cell should not be able to decode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Try sending the exact same INTRODUCE2 cell again and see that the intro
|
||||||
|
* point replay cache triggers: */
|
||||||
|
setup_full_capture_of_logs(LOG_WARN);
|
||||||
|
retval = hs_circ_handle_introduce2(&x_service,
|
||||||
|
intro_circ, x_ip,
|
||||||
|
&x_subcred,
|
||||||
|
(uint8_t*)relay_payload, relay_payload_len);
|
||||||
|
tt_int_op(retval, OP_EQ, -1);
|
||||||
|
expect_log_msg_containing("with the same ENCRYPTED section");
|
||||||
|
teardown_capture_of_logs();
|
||||||
|
|
||||||
|
/* Now cleanup the intro point replay cache but not the service replay cache
|
||||||
|
and see that this one triggers this time. */
|
||||||
|
replaycache_free(x_ip->replay_cache);
|
||||||
|
x_ip->replay_cache = replaycache_new(0, 0);
|
||||||
|
setup_full_capture_of_logs(LOG_INFO);
|
||||||
|
retval = hs_circ_handle_introduce2(&x_service,
|
||||||
|
intro_circ, x_ip,
|
||||||
|
&x_subcred,
|
||||||
|
(uint8_t*)relay_payload, relay_payload_len);
|
||||||
|
tt_int_op(retval, OP_EQ, -1);
|
||||||
|
expect_log_msg_containing("with same REND_COOKIE");
|
||||||
|
teardown_capture_of_logs();
|
||||||
|
|
||||||
|
/* Now just to make sure cleanup both replay caches and make sure that the
|
||||||
|
cell gets through */
|
||||||
|
replaycache_free(x_ip->replay_cache);
|
||||||
|
x_ip->replay_cache = replaycache_new(0, 0);
|
||||||
|
replaycache_free(x_service.state.replay_cache_rend_cookie);
|
||||||
|
x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
|
||||||
|
retval = hs_circ_handle_introduce2(&x_service,
|
||||||
|
intro_circ, x_ip,
|
||||||
|
&x_subcred,
|
||||||
|
(uint8_t*)relay_payload, relay_payload_len);
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* As a final thing, create an INTRODUCE1 cell from Alice to X using Y's
|
||||||
|
* subcred (should fail since Y is just another instance and not the frontend
|
||||||
|
* service!) */
|
||||||
|
memset(relay_payload, 0, sizeof(relay_payload));
|
||||||
|
retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
|
||||||
|
alice_ip, &y_subcred);
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* Check that the payload was written successfully */
|
||||||
|
tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
|
||||||
|
tt_int_op(relay_payload_len, OP_NE, 0);
|
||||||
|
|
||||||
|
retval = hs_circ_handle_introduce2(&x_service,
|
||||||
|
intro_circ, x_ip,
|
||||||
|
&y_subcred,
|
||||||
|
(uint8_t*)relay_payload, relay_payload_len);
|
||||||
|
tt_int_op(retval, OP_EQ, -1);
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* Start cleaning up X */
|
||||||
|
replaycache_free(x_service.state.replay_cache_rend_cookie);
|
||||||
|
smartlist_free(x_service.config.ob_master_pubkeys);
|
||||||
|
tor_free(x_service.ob_subcreds);
|
||||||
|
service_descriptor_free(x_service.desc_current);
|
||||||
|
service_descriptor_free(x_service.desc_next);
|
||||||
|
service_intro_point_free(x_ip);
|
||||||
|
|
||||||
|
/* Clean up Alice */
|
||||||
|
hs_desc_intro_point_free(alice_ip);
|
||||||
|
tor_free(rend_circ.hs_ident);
|
||||||
|
|
||||||
|
if (fake_node) {
|
||||||
|
tor_free(fake_node->ri->onion_curve25519_pkey);
|
||||||
|
tor_free(fake_node->ri);
|
||||||
|
tor_free(fake_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNMOCK(build_state_get_exit_node);
|
||||||
|
UNMOCK(relay_send_command_from_edge_);
|
||||||
|
UNMOCK(node_get_link_specifier_smartlist);
|
||||||
|
UNMOCK(launch_rendezvous_point_circuit);
|
||||||
|
}
|
||||||
|
|
||||||
struct testcase_t hs_service_tests[] = {
|
struct testcase_t hs_service_tests[] = {
|
||||||
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
|
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
@ -2194,7 +2545,7 @@ struct testcase_t hs_service_tests[] = {
|
|||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "rdv_circuit_opened", test_rdv_circuit_opened, TT_FORK,
|
{ "rdv_circuit_opened", test_rdv_circuit_opened, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "introduce2", test_introduce2, TT_FORK,
|
{ "bad_introduce2", test_bad_introduce2, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "service_event", test_service_event, TT_FORK,
|
{ "service_event", test_service_event, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
@ -2212,6 +2563,7 @@ struct testcase_t hs_service_tests[] = {
|
|||||||
TT_FORK, NULL, NULL },
|
TT_FORK, NULL, NULL },
|
||||||
{ "export_client_circuit_id", test_export_client_circuit_id, TT_FORK,
|
{ "export_client_circuit_id", test_export_client_circuit_id, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
|
{ "intro2_handling", test_intro2_handling, TT_FORK, NULL, NULL },
|
||||||
|
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user