test: Add HS onion balance tests

Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
David Goulet 2020-01-14 11:29:08 -05:00 committed by Nick Mathewson
parent faada6af8d
commit 7c18860c3e
4 changed files with 234 additions and 0 deletions

View File

@ -167,6 +167,7 @@ src_test_test_SOURCES += \
src/test/test_hs_client.c \ src/test/test_hs_client.c \
src/test/test_hs_intropoint.c \ src/test/test_hs_intropoint.c \
src/test/test_hs_control.c \ src/test/test_hs_control.c \
src/test/test_hs_ob.c \
src/test/test_handles.c \ src/test/test_handles.c \
src/test/test_hs_cache.c \ src/test/test_hs_cache.c \
src/test/test_hs_descriptor.c \ src/test/test_hs_descriptor.c \

View File

@ -721,6 +721,7 @@ struct testgroup_t testgroups[] = {
{ "hs_dos/", hs_dos_tests }, { "hs_dos/", hs_dos_tests },
{ "hs_intropoint/", hs_intropoint_tests }, { "hs_intropoint/", hs_intropoint_tests },
{ "hs_ntor/", hs_ntor_tests }, { "hs_ntor/", hs_ntor_tests },
{ "hs_ob/", hs_ob_tests },
{ "hs_service/", hs_service_tests }, { "hs_service/", hs_service_tests },
{ "introduce/", introduce_tests }, { "introduce/", introduce_tests },
{ "keypin/", keypin_tests }, { "keypin/", keypin_tests },

View File

@ -141,6 +141,7 @@ extern struct testcase_t hs_descriptor[];
extern struct testcase_t hs_dos_tests[]; extern struct testcase_t hs_dos_tests[];
extern struct testcase_t hs_intropoint_tests[]; extern struct testcase_t hs_intropoint_tests[];
extern struct testcase_t hs_ntor_tests[]; extern struct testcase_t hs_ntor_tests[];
extern struct testcase_t hs_ob_tests[];
extern struct testcase_t hs_service_tests[]; extern struct testcase_t hs_service_tests[];
extern struct testcase_t hs_tests[]; extern struct testcase_t hs_tests[];
extern struct testcase_t introduce_tests[]; extern struct testcase_t introduce_tests[];

231
src/test/test_hs_ob.c Normal file
View File

@ -0,0 +1,231 @@
/* Copyright (c) 2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file test_hs_ob.c
* \brief Test hidden service onion balance functionality.
*/
#define CONFIG_PRIVATE
#define HS_SERVICE_PRIVATE
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
#include "app/config/config.h"
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_service.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/networkstatus_st.h"
static ed25519_keypair_t onion_addr_kp_1;
static char onion_addr_1[HS_SERVICE_ADDR_LEN_BASE32 + 1];
static ed25519_keypair_t onion_addr_kp_2;
static char onion_addr_2[HS_SERVICE_ADDR_LEN_BASE32 + 1];
static bool config_is_good = true;
static int
helper_tor_config(const char *conf)
{
int ret = -1;
or_options_t *options = helper_parse_options(conf);
tt_assert(options);
ret = hs_config_service_all(options, 0);
done:
or_options_free(options);
return ret;
}
static networkstatus_t mock_ns;
static networkstatus_t *
mock_networkstatus_get_live_consensus(time_t now)
{
(void) now;
return &mock_ns;
}
static char *
mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out)
{
char *ret = NULL;
(void) flags;
(void) stat_out;
if (!strcmp(filename, get_fname("hs3" PATH_SEPARATOR "ob_config"))) {
if (config_is_good) {
tor_asprintf(&ret, "MasterOnionAddress %s.onion\n"
"MasterOnionAddress %s.onion\n",
onion_addr_1, onion_addr_2);
} else {
tor_asprintf(&ret, "MasterOnionAddress JUNKJUNKJUNK.onion\n"
"UnknownOption BLAH\n");
}
goto done;
}
done:
return ret;
}
static void
test_parse_config_file(void *arg)
{
int ret;
char *conf = NULL;
const ed25519_public_key_t *pkey;
(void) arg;
hs_init();
MOCK(read_file_to_str, mock_read_file_to_str);
#define fmt_conf \
"HiddenServiceDir %s\n" \
"HiddenServicePort 22\n" \
"HiddenServiceOnionBalanceInstance 1\n"
tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
#undef fmt_conf
/* Build the OB frontend onion addresses. */
ed25519_keypair_generate(&onion_addr_kp_1, 0);
hs_build_address(&onion_addr_kp_1.pubkey, HS_VERSION_THREE, onion_addr_1);
ed25519_keypair_generate(&onion_addr_kp_2, 0);
hs_build_address(&onion_addr_kp_2.pubkey, HS_VERSION_THREE, onion_addr_2);
ret = helper_tor_config(conf);
tor_free(conf);
tt_int_op(ret, OP_EQ, 0);
/* Load the keys for the service. After that, the v3 service should be
* registered in the global map and we'll be able to access it. */
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
hs_service_load_all_keys();
tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
const hs_service_t *s = get_first_service();
tt_assert(s);
tt_assert(s->config.ob_master_pubkeys);
tt_assert(hs_ob_service_is_instance(s));
tt_assert(smartlist_len(s->config.ob_master_pubkeys) == 2);
/* Test the public keys we've added. */
pkey = smartlist_get(s->config.ob_master_pubkeys, 0);
tt_mem_op(&onion_addr_kp_1.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
pkey = smartlist_get(s->config.ob_master_pubkeys, 1);
tt_mem_op(&onion_addr_kp_2.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
done:
hs_free_all();
UNMOCK(read_file_to_str);
}
static void
test_parse_config_file_bad(void *arg)
{
int ret;
char *conf = NULL;
(void) arg;
hs_init();
MOCK(read_file_to_str, mock_read_file_to_str);
/* Indicate mock_read_file_to_str() to use the bad config. */
config_is_good = false;
#define fmt_conf \
"HiddenServiceDir %s\n" \
"HiddenServicePort 22\n" \
"HiddenServiceOnionBalanceInstance 1\n"
tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
#undef fmt_conf
setup_full_capture_of_logs(LOG_INFO);
ret = helper_tor_config(conf);
tor_free(conf);
tt_int_op(ret, OP_EQ, -1);
expect_log_msg_containing("OnionBalance: MasterOnionAddress "
"JUNKJUNKJUNK.onion is invalid");
expect_log_msg_containing("Found unrecognized option \'UnknownOption\'; "
"saving it.");
teardown_capture_of_logs();
done:
hs_free_all();
UNMOCK(read_file_to_str);
}
static void
test_get_subcredentials(void *arg)
{
int ret;
hs_service_config_t config;
(void) arg;
MOCK(networkstatus_get_live_consensus,
mock_networkstatus_get_live_consensus);
/* Setup consensus with proper time so we can compute the time period. */
ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
&mock_ns.valid_after);
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
config.ob_master_pubkeys = smartlist_new();
tt_assert(config.ob_master_pubkeys);
/* Generate a keypair to add to the list. */
ed25519_keypair_generate(&onion_addr_kp_1, 0);
smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey);
uint8_t *subcreds = NULL;
size_t num = hs_ob_get_subcredentials(&config, &subcreds);
tt_uint_op(num, OP_EQ, 3);
/* Validate the subcredentials we just got. We'll build them oursevles with
* the right time period steps and compare. */
const uint64_t tp = hs_get_time_period_num(0);
const int steps[3] = {0, -1, 1};
for (unsigned int i = 0; i < num; i++) {
uint8_t subcredential[DIGEST256_LEN];
ed25519_public_key_t blinded_pubkey;
hs_build_blinded_pubkey(&onion_addr_kp_1.pubkey, NULL, 0, tp + steps[i],
&blinded_pubkey);
hs_get_subcredential(&onion_addr_kp_1.pubkey, &blinded_pubkey,
subcredential);
tt_mem_op(&(subcreds[i * sizeof(subcredential)]), OP_EQ, subcredential,
sizeof(subcredential));
}
done:
tor_free(subcreds);
smartlist_free(config.ob_master_pubkeys);
UNMOCK(networkstatus_get_live_consensus);
}
struct testcase_t hs_ob_tests[] = {
{ "parse_config_file", test_parse_config_file, TT_FORK,
NULL, NULL },
{ "parse_config_file_bad", test_parse_config_file_bad, TT_FORK,
NULL, NULL },
{ "get_subcredentials", test_get_subcredentials, TT_FORK,
NULL, NULL },
END_OF_TESTCASES
};