mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
test: Add v3 service load keys and accessors
Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
418059dd96
commit
09b12c4094
@ -57,11 +57,6 @@ hs_service_ht_hash(const hs_service_t *service)
|
|||||||
sizeof(service->keys.identity_pk.pubkey));
|
sizeof(service->keys.identity_pk.pubkey));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For the service global hash map, we define a specific type for it which
|
|
||||||
* will make it safe to use and specific to some controlled parameters such as
|
|
||||||
* the hashing function and how to compare services. */
|
|
||||||
typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht;
|
|
||||||
|
|
||||||
/* This is _the_ global hash map of hidden services which indexed the service
|
/* This is _the_ global hash map of hidden services which indexed the service
|
||||||
* contained in it by master public identity key which is roughly the onion
|
* contained in it by master public identity key which is roughly the onion
|
||||||
* address of the service. */
|
* address of the service. */
|
||||||
@ -82,7 +77,7 @@ HT_GENERATE2(hs_service_ht, hs_service_t, hs_service_node,
|
|||||||
* if found else NULL. It is also possible to set a directory path in the
|
* if found else NULL. It is also possible to set a directory path in the
|
||||||
* search query. If pk is NULL, then it will be set to zero indicating the
|
* search query. If pk is NULL, then it will be set to zero indicating the
|
||||||
* hash table to compare the directory path instead. */
|
* hash table to compare the directory path instead. */
|
||||||
static hs_service_t *
|
STATIC hs_service_t *
|
||||||
find_service(hs_service_ht *map, const ed25519_public_key_t *pk)
|
find_service(hs_service_ht *map, const ed25519_public_key_t *pk)
|
||||||
{
|
{
|
||||||
hs_service_t dummy_service = {0};
|
hs_service_t dummy_service = {0};
|
||||||
@ -95,7 +90,7 @@ find_service(hs_service_ht *map, const ed25519_public_key_t *pk)
|
|||||||
/* Register the given service in the given map. If the service already exists
|
/* Register the given service in the given map. If the service already exists
|
||||||
* in the map, -1 is returned. On success, 0 is returned and the service
|
* in the map, -1 is returned. On success, 0 is returned and the service
|
||||||
* ownership has been transfered to the global map. */
|
* ownership has been transfered to the global map. */
|
||||||
static int
|
STATIC int
|
||||||
register_service(hs_service_ht *map, hs_service_t *service)
|
register_service(hs_service_ht *map, hs_service_t *service)
|
||||||
{
|
{
|
||||||
tor_assert(map);
|
tor_assert(map);
|
||||||
@ -113,7 +108,7 @@ register_service(hs_service_ht *map, hs_service_t *service)
|
|||||||
|
|
||||||
/* Remove a given service from the given map. If service is NULL or the
|
/* Remove a given service from the given map. If service is NULL or the
|
||||||
* service key is unset, return gracefully. */
|
* service key is unset, return gracefully. */
|
||||||
static void
|
STATIC void
|
||||||
remove_service(hs_service_ht *map, hs_service_t *service)
|
remove_service(hs_service_ht *map, hs_service_t *service)
|
||||||
{
|
{
|
||||||
hs_service_t *elm;
|
hs_service_t *elm;
|
||||||
@ -804,5 +799,21 @@ get_hs_service_staging_list_size(void)
|
|||||||
return smartlist_len(hs_service_staging_list);
|
return smartlist_len(hs_service_staging_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC hs_service_ht *
|
||||||
|
get_hs_service_map(void)
|
||||||
|
{
|
||||||
|
return hs_service_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC hs_service_t *
|
||||||
|
get_first_service(void)
|
||||||
|
{
|
||||||
|
hs_service_t **obj = HT_START(hs_service_ht, hs_service_map);
|
||||||
|
if (obj == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return *obj;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* TOR_UNIT_TESTS */
|
#endif /* TOR_UNIT_TESTS */
|
||||||
|
|
||||||
|
@ -200,6 +200,11 @@ typedef struct hs_service_t {
|
|||||||
|
|
||||||
} hs_service_t;
|
} hs_service_t;
|
||||||
|
|
||||||
|
/* For the service global hash map, we define a specific type for it which
|
||||||
|
* will make it safe to use and specific to some controlled parameters such as
|
||||||
|
* the hashing function and how to compare services. */
|
||||||
|
typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht;
|
||||||
|
|
||||||
/* API */
|
/* API */
|
||||||
|
|
||||||
/* Global initializer and cleanup function. */
|
/* Global initializer and cleanup function. */
|
||||||
@ -228,8 +233,17 @@ get_establish_intro_payload(uint8_t *buf, size_t buf_len,
|
|||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
|
||||||
|
/* Useful getters for unit tests. */
|
||||||
STATIC unsigned int get_hs_service_map_size(void);
|
STATIC unsigned int get_hs_service_map_size(void);
|
||||||
STATIC int get_hs_service_staging_list_size(void);
|
STATIC int get_hs_service_staging_list_size(void);
|
||||||
|
STATIC hs_service_ht *get_hs_service_map(void);
|
||||||
|
STATIC hs_service_t *get_first_service(void);
|
||||||
|
|
||||||
|
/* Service accessors. */
|
||||||
|
STATIC hs_service_t *find_service(hs_service_ht *map,
|
||||||
|
const ed25519_public_key_t *pk);
|
||||||
|
STATIC void remove_service(hs_service_ht *map, hs_service_t *service);
|
||||||
|
STATIC int register_service(hs_service_ht *map, hs_service_t *service);
|
||||||
|
|
||||||
#endif /* TOR_UNIT_TESTS */
|
#endif /* TOR_UNIT_TESTS */
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@
|
|||||||
|
|
||||||
#define CIRCUITBUILD_PRIVATE
|
#define CIRCUITBUILD_PRIVATE
|
||||||
#define CIRCUITLIST_PRIVATE
|
#define CIRCUITLIST_PRIVATE
|
||||||
|
#define CONFIG_PRIVATE
|
||||||
#define CONNECTION_PRIVATE
|
#define CONNECTION_PRIVATE
|
||||||
#define CRYPTO_PRIVATE
|
#define CRYPTO_PRIVATE
|
||||||
#define HS_COMMON_PRIVATE
|
#define HS_COMMON_PRIVATE
|
||||||
|
#define HS_SERVICE_PRIVATE
|
||||||
#define HS_INTROPOINT_PRIVATE
|
#define HS_INTROPOINT_PRIVATE
|
||||||
#define MAIN_PRIVATE
|
#define MAIN_PRIVATE
|
||||||
#define TOR_CHANNEL_INTERNAL_
|
#define TOR_CHANNEL_INTERNAL_
|
||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
#include "test_helpers.h"
|
||||||
#include "log_test_helpers.h"
|
#include "log_test_helpers.h"
|
||||||
#include "rend_test_helpers.h"
|
#include "rend_test_helpers.h"
|
||||||
|
|
||||||
@ -26,8 +29,10 @@
|
|||||||
#include "circuituse.h"
|
#include "circuituse.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
#include "crypto.h"
|
||||||
#include "hs_circuit.h"
|
#include "hs_circuit.h"
|
||||||
#include "hs_common.h"
|
#include "hs_common.h"
|
||||||
|
#include "hs_config.h"
|
||||||
#include "hs_ident.h"
|
#include "hs_ident.h"
|
||||||
#include "hs_intropoint.h"
|
#include "hs_intropoint.h"
|
||||||
#include "hs_ntor.h"
|
#include "hs_ntor.h"
|
||||||
@ -35,6 +40,25 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "rendservice.h"
|
#include "rendservice.h"
|
||||||
|
|
||||||
|
/* Trunnel */
|
||||||
|
#include "hs/cell_establish_intro.h"
|
||||||
|
|
||||||
|
/* Helper: from a set of options in conf, configure a service which will add
|
||||||
|
* it to the staging list of the HS subsytem. */
|
||||||
|
static int
|
||||||
|
helper_config_service(const char *conf)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
or_options_t *options = NULL;
|
||||||
|
tt_assert(conf);
|
||||||
|
options = helper_parse_options(conf);
|
||||||
|
tt_assert(options);
|
||||||
|
ret = hs_config_service_all(options, 0);
|
||||||
|
done:
|
||||||
|
or_options_free(options);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
|
/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
|
||||||
* parse it from the receiver side. */
|
* parse it from the receiver side. */
|
||||||
static void
|
static void
|
||||||
@ -394,6 +418,144 @@ test_e2e_rend_circuit_setup(void *arg)
|
|||||||
circuit_free(TO_CIRCUIT(or_circ));
|
circuit_free(TO_CIRCUIT(or_circ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_load_keys(void *arg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *conf = NULL;
|
||||||
|
char *hsdir_v2 = tor_strdup(get_fname("hs2"));
|
||||||
|
char *hsdir_v3 = tor_strdup(get_fname("hs3"));
|
||||||
|
char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
/* We'll register two services, a v2 and a v3, then we'll load keys and
|
||||||
|
* validate that both are in a correct state. */
|
||||||
|
|
||||||
|
hs_init();
|
||||||
|
|
||||||
|
#define conf_fmt \
|
||||||
|
"HiddenServiceDir %s\n" \
|
||||||
|
"HiddenServiceVersion %d\n" \
|
||||||
|
"HiddenServicePort 65535\n"
|
||||||
|
|
||||||
|
/* v2 service. */
|
||||||
|
tor_asprintf(&conf, conf_fmt, hsdir_v2, HS_VERSION_TWO);
|
||||||
|
ret = helper_config_service(conf);
|
||||||
|
tor_free(conf);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
/* This one should now be registered into the v2 list. */
|
||||||
|
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 0);
|
||||||
|
tt_int_op(num_rend_services(), OP_EQ, 1);
|
||||||
|
|
||||||
|
/* v3 service. */
|
||||||
|
tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
|
||||||
|
ret = helper_config_service(conf);
|
||||||
|
tor_free(conf);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
/* It's in staging? */
|
||||||
|
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
|
||||||
|
|
||||||
|
/* Load the keys for these. After that, the v3 service should be registered
|
||||||
|
* in the global map. */
|
||||||
|
hs_service_load_all_keys();
|
||||||
|
tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
|
||||||
|
hs_service_t *s = get_first_service();
|
||||||
|
tt_assert(s);
|
||||||
|
|
||||||
|
/* Ok we have the service object. Validate few things. */
|
||||||
|
tt_assert(!tor_mem_is_zero(s->onion_address, sizeof(s->onion_address)));
|
||||||
|
tt_int_op(hs_address_is_valid(s->onion_address), OP_EQ, 1);
|
||||||
|
tt_assert(!tor_mem_is_zero((char *) s->keys.identity_sk.seckey,
|
||||||
|
ED25519_SECKEY_LEN));
|
||||||
|
tt_assert(!tor_mem_is_zero((char *) s->keys.identity_pk.pubkey,
|
||||||
|
ED25519_PUBKEY_LEN));
|
||||||
|
/* Check onion address from identity key. */
|
||||||
|
hs_build_address(&s->keys.identity_pk, s->version, addr);
|
||||||
|
tt_int_op(hs_address_is_valid(addr), OP_EQ, 1);
|
||||||
|
tt_str_op(addr, OP_EQ, s->onion_address);
|
||||||
|
|
||||||
|
done:
|
||||||
|
tor_free(hsdir_v2);
|
||||||
|
tor_free(hsdir_v3);
|
||||||
|
hs_free_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_access_service(void *arg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *conf = NULL;
|
||||||
|
char *hsdir_v3 = tor_strdup(get_fname("hs3"));
|
||||||
|
hs_service_ht *global_map;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
/* We'll register two services, a v2 and a v3, then we'll load keys and
|
||||||
|
* validate that both are in a correct state. */
|
||||||
|
|
||||||
|
hs_init();
|
||||||
|
|
||||||
|
#define conf_fmt \
|
||||||
|
"HiddenServiceDir %s\n" \
|
||||||
|
"HiddenServiceVersion %d\n" \
|
||||||
|
"HiddenServicePort 65535\n"
|
||||||
|
|
||||||
|
/* v3 service. */
|
||||||
|
tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
|
||||||
|
ret = helper_config_service(conf);
|
||||||
|
tor_free(conf);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
/* It's in staging? */
|
||||||
|
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
|
||||||
|
|
||||||
|
/* Load the keys for these. After that, the v3 service should be registered
|
||||||
|
* in the global map. */
|
||||||
|
hs_service_load_all_keys();
|
||||||
|
tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
|
||||||
|
hs_service_t *s = get_first_service();
|
||||||
|
tt_assert(s);
|
||||||
|
global_map = get_hs_service_map();
|
||||||
|
tt_assert(global_map);
|
||||||
|
|
||||||
|
/* From here, we'll try the service accessors. */
|
||||||
|
hs_service_t *query = find_service(global_map, &s->keys.identity_pk);
|
||||||
|
tt_assert(query);
|
||||||
|
tt_mem_op(query, OP_EQ, s, sizeof(hs_service_t));
|
||||||
|
/* Remove service, check if it actually works and then put it back. */
|
||||||
|
remove_service(global_map, s);
|
||||||
|
tt_int_op(get_hs_service_map_size(), OP_EQ, 0);
|
||||||
|
query = find_service(global_map, &s->keys.identity_pk);
|
||||||
|
tt_assert(!query);
|
||||||
|
|
||||||
|
/* Register back the service in the map. */
|
||||||
|
ret = register_service(global_map, s);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
|
||||||
|
/* Twice should fail. */
|
||||||
|
ret = register_service(global_map, s);
|
||||||
|
tt_int_op(ret, OP_EQ, -1);
|
||||||
|
/* Modify key of service and we should be able to put it back in. */
|
||||||
|
s->keys.identity_pk.pubkey[1] = '\x42';
|
||||||
|
ret = register_service(global_map, s);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
tt_int_op(get_hs_service_map_size(), OP_EQ, 2);
|
||||||
|
/* Remove service from map so we don't double free on cleanup. */
|
||||||
|
remove_service(global_map, s);
|
||||||
|
tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
|
||||||
|
query = find_service(global_map, &s->keys.identity_pk);
|
||||||
|
tt_assert(!query);
|
||||||
|
/* Let's try to remove twice for fun. */
|
||||||
|
setup_full_capture_of_logs(LOG_WARN);
|
||||||
|
remove_service(global_map, s);
|
||||||
|
expect_log_msg_containing("Could not find service in the global map");
|
||||||
|
teardown_capture_of_logs();
|
||||||
|
|
||||||
|
done:
|
||||||
|
tor_free(hsdir_v3);
|
||||||
|
hs_free_all();
|
||||||
|
}
|
||||||
|
|
||||||
struct testcase_t hs_service_tests[] = {
|
struct testcase_t hs_service_tests[] = {
|
||||||
{ "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK,
|
{ "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
@ -409,6 +571,10 @@ struct testcase_t hs_service_tests[] = {
|
|||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "validate_address", test_validate_address, TT_FORK,
|
{ "validate_address", test_validate_address, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
|
{ "load_keys", test_load_keys, TT_FORK,
|
||||||
|
NULL, NULL },
|
||||||
|
{ "access_service", test_access_service, TT_FORK,
|
||||||
|
NULL, NULL },
|
||||||
|
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user