aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2016-11-04 13:26:37 -0400
committerNick Mathewson <nickm@torproject.org>2016-11-04 13:26:37 -0400
commitc35c43d7d9df793c890deb14800e24327fbca452 (patch)
tree3f6f3623c301b1900fbf58bb84ec86657baebce0 /src/test
parentbd6aa4f3d19a571adeaa956728f7e842d847c4ee (diff)
parentc189cb5cc29e92e55f8e94b5531d2626eff71d63 (diff)
downloadtor-c35c43d7d9df793c890deb14800e24327fbca452.tar.gz
tor-c35c43d7d9df793c890deb14800e24327fbca452.zip
Merge branch 'ticket17238_029_02-resquash'
Conflicts: src/or/rendclient.c src/or/rendcommon.c src/or/routerparse.c src/test/test_dir.c src/trunnel/ed25519_cert.h
Diffstat (limited to 'src/test')
-rw-r--r--src/test/include.am2
-rw-r--r--src/test/test.c2
-rw-r--r--src/test/test.h2
-rw-r--r--src/test/test_connection.c12
-rw-r--r--src/test/test_dir.c62
-rw-r--r--src/test/test_dir_handle_get.c13
-rw-r--r--src/test/test_helpers.c13
-rw-r--r--src/test/test_helpers.h4
-rw-r--r--src/test/test_hs.c103
-rw-r--r--src/test/test_hs_cache.c479
-rw-r--r--src/test/test_hs_descriptor.c1130
-rw-r--r--src/test/test_rendcache.c57
12 files changed, 1774 insertions, 105 deletions
diff --git a/src/test/include.am b/src/test/include.am
index 4af48cfbc1..f6e43148f0 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -97,6 +97,8 @@ src_test_test_SOURCES = \
src/test/test_extorport.c \
src/test/test_hs.c \
src/test/test_handles.c \
+ src/test/test_hs_cache.c \
+ src/test/test_hs_descriptor.c \
src/test/test_introduce.c \
src/test/test_keypin.c \
src/test/test_link_handshake.c \
diff --git a/src/test/test.c b/src/test/test.c
index 9a41b976b8..b02ecb922d 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1205,6 +1205,8 @@ struct testgroup_t testgroups[] = {
{ "guardfraction/", guardfraction_tests },
{ "extorport/", extorport_tests },
{ "hs/", hs_tests },
+ { "hs_cache/", hs_cache },
+ { "hs_descriptor/", hs_descriptor },
{ "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
{ "link-handshake/", link_handshake_tests },
diff --git a/src/test/test.h b/src/test/test.h
index b7c769fe0d..15ccf5c379 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -198,6 +198,8 @@ extern struct testcase_t entrynodes_tests[];
extern struct testcase_t guardfraction_tests[];
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 introduce_tests[];
extern struct testcase_t keypin_tests[];
extern struct testcase_t link_handshake_tests[];
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index d394fc9852..5cda4f3175 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -10,6 +10,7 @@
#include "test.h"
#include "connection.h"
+#include "hs_common.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -265,13 +266,9 @@ test_conn_get_rend_setup(const struct testcase_t *tc)
rend_cache_init();
/* TODO: use directory_initiate_command_rend() to do this - maybe? */
- conn->rend_data = tor_malloc_zero(sizeof(rend_data_t));
tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32);
- memcpy(conn->rend_data->onion_address,
- TEST_CONN_REND_ADDR,
- REND_SERVICE_ID_LEN_BASE32+1);
- conn->rend_data->hsdirs_fp = smartlist_new();
-
+ conn->rend_data = rend_data_client_create(TEST_CONN_REND_ADDR, NULL, NULL,
+ REND_NO_AUTH);
assert_connection_ok(&conn->base_, time(NULL));
return conn;
@@ -551,7 +548,8 @@ test_conn_get_rend(void *arg)
tt_assert(connection_get_by_type_state_rendquery(
conn->base_.type,
conn->base_.state,
- conn->rend_data->onion_address)
+ rend_data_get_address(
+ conn->rend_data))
== TO_CONN(conn));
tt_assert(connection_get_by_type_state_rendquery(
TEST_CONN_TYPE,
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index cf0b94c574..c8daa18653 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -5740,6 +5740,67 @@ test_dir_assumed_flags(void *arg)
routerstatus_free(rs);
}
+static void
+test_dir_post_parsing(void *arg)
+{
+ (void) arg;
+
+ /* Test the version parsing from an HS descriptor publish request. */
+ {
+ const char *end;
+ const char *prefix = "/tor/hs/";
+ int version = parse_hs_version_from_post("/tor/hs//publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/a/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 3);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("/tor/hs/42/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 42);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("/tor/hs/18163/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 18163);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("JUNKJUNKJUNK", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish", "blah", &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ /* Missing the '/' at the end of the prefix. */
+ version = parse_hs_version_from_post("/tor/hs/3/publish", "/tor/hs", &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/random/blah/tor/hs/3/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish/random/junk",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, 3);
+ tt_str_op(end, OP_EQ, "/publish/random/junk");
+ version = parse_hs_version_from_post("/tor/hs/-1/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ /* INT_MAX */
+ version = parse_hs_version_from_post("/tor/hs/2147483647/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, INT_MAX);
+ tt_str_op(end, OP_EQ, "/publish");
+ /* INT_MAX + 1*/
+ version = parse_hs_version_from_post("/tor/hs/2147483648/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ }
+
+ done:
+ ;
+}
+
#define DIR_LEGACY(name) \
{ #name, test_dir_ ## name , TT_FORK, NULL, NULL }
@@ -5778,6 +5839,7 @@ struct testcase_t dir_tests[] = {
DIR(purpose_needs_anonymity_returns_true_by_default, 0),
DIR(purpose_needs_anonymity_returns_true_for_sensitive_purpose, 0),
DIR(purpose_needs_anonymity_ret_false_for_non_sensitive_conn, 0),
+ DIR(post_parsing, 0),
DIR(fetch_type, 0),
DIR(packages, 0),
DIR(download_status_schedule, 0),
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index a0f22f1f0c..c215feee26 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -50,19 +50,6 @@ ENABLE_GCC_WARNING(overlength-strings)
#define NS_MODULE dir_handle_get
-static void
-connection_write_to_buf_mock(const char *string, size_t len,
- connection_t *conn, int zlib)
-{
- (void) zlib;
-
- tor_assert(string);
- tor_assert(conn);
-
- write_to_buf(string, len, conn->outbuf);
-}
-
-#define GET(path) "GET " path " HTTP/1.0\r\n\r\n"
#define NOT_FOUND "HTTP/1.0 404 Not found\r\n\r\n"
#define BAD_REQUEST "HTTP/1.0 400 Bad request\r\n\r\n"
#define SERVER_BUSY "HTTP/1.0 503 Directory busy, try again later\r\n\r\n"
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index ae9fc7a243..130ec43a3a 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -12,6 +12,7 @@
#include "routerlist.h"
#include "nodelist.h"
+#include "buffers.h"
#include "test.h"
#include "test_helpers.h"
@@ -92,3 +93,15 @@ helper_setup_fake_routerlist(void)
UNMOCK(router_descriptor_is_older_than);
}
+void
+connection_write_to_buf_mock(const char *string, size_t len,
+ connection_t *conn, int zlib)
+{
+ (void) zlib;
+
+ tor_assert(string);
+ tor_assert(conn);
+
+ write_to_buf(string, len, conn->outbuf);
+}
+
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index 684375e1b1..b77a459256 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -11,6 +11,10 @@ const char *get_yesterday_date_str(void);
void helper_setup_fake_routerlist(void);
+#define GET(path) "GET " path " HTTP/1.0\r\n\r\n"
+void connection_write_to_buf_mock(const char *string, size_t len,
+ connection_t *conn, int zlib);
+
extern const char TEST_DESCRIPTORS[];
#endif
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index fd5ab15643..67ce1cfaed 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -14,6 +14,7 @@
#include "test.h"
#include "control.h"
#include "config.h"
+#include "hs_common.h"
#include "rendcommon.h"
#include "rendservice.h"
#include "routerset.h"
@@ -136,7 +137,7 @@ test_hs_desc_event(void *arg)
#define STR_DESC_ID_BASE32 "hba3gmcgpfivzfhx5rtfqkfdhv65yrj3"
int ret;
- rend_data_t rend_query;
+ rend_data_v2_t rend_query;
const char *expected_msg;
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
@@ -148,12 +149,13 @@ test_hs_desc_event(void *arg)
/* setup rend_query struct */
memset(&rend_query, 0, sizeof(rend_query));
+ rend_query.base_.version = 2;
strncpy(rend_query.onion_address, STR_HS_ADDR,
REND_SERVICE_ID_LEN_BASE32+1);
rend_query.auth_type = REND_NO_AUTH;
- rend_query.hsdirs_fp = smartlist_new();
- smartlist_add(rend_query.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID,
- DIGEST_LEN));
+ rend_query.base_.hsdirs_fp = smartlist_new();
+ smartlist_add(rend_query.base_.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID,
+ DIGEST_LEN));
/* Compute descriptor ID for replica 0, should be STR_DESC_ID_BASE32. */
ret = rend_compute_v2_desc_id(rend_query.descriptor_id[0],
@@ -167,7 +169,7 @@ test_hs_desc_event(void *arg)
sizeof(desc_id_base32));
/* test request event */
- control_event_hs_descriptor_requested(&rend_query, HSDIR_EXIST_ID,
+ control_event_hs_descriptor_requested(&rend_query.base_, HSDIR_EXIST_ID,
STR_DESC_ID_BASE32);
expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n";
@@ -178,7 +180,7 @@ test_hs_desc_event(void *arg)
/* test received event */
rend_query.auth_type = REND_BASIC_AUTH;
control_event_hs_descriptor_received(rend_query.onion_address,
- &rend_query, HSDIR_EXIST_ID);
+ &rend_query.base_, HSDIR_EXIST_ID);
expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n";
tt_assert(received_msg);
@@ -187,7 +189,7 @@ test_hs_desc_event(void *arg)
/* test failed event */
rend_query.auth_type = REND_STEALTH_AUTH;
- control_event_hs_descriptor_failed(&rend_query,
+ control_event_hs_descriptor_failed(&rend_query.base_,
HSDIR_NONE_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\
@@ -198,7 +200,7 @@ test_hs_desc_event(void *arg)
/* test invalid auth type */
rend_query.auth_type = 999;
- control_event_hs_descriptor_failed(&rend_query,
+ control_event_hs_descriptor_failed(&rend_query.base_,
HSDIR_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\
@@ -221,8 +223,8 @@ test_hs_desc_event(void *arg)
tt_str_op(received_msg, OP_EQ, exp_msg);
tor_free(received_msg);
tor_free(exp_msg);
- SMARTLIST_FOREACH(rend_query.hsdirs_fp, char *, d, tor_free(d));
- smartlist_free(rend_query.hsdirs_fp);
+ SMARTLIST_FOREACH(rend_query.base_.hsdirs_fp, char *, d, tor_free(d));
+ smartlist_free(rend_query.base_.hsdirs_fp);
done:
UNMOCK(queue_control_event_string);
@@ -322,42 +324,46 @@ test_hs_rend_data(void *arg)
client = rend_data_client_create(STR_HS_ADDR, desc_id, client_cookie,
REND_NO_AUTH);
tt_assert(client);
- tt_int_op(client->auth_type, ==, REND_NO_AUTH);
- tt_str_op(client->onion_address, OP_EQ, STR_HS_ADDR);
- tt_mem_op(client->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
- tt_mem_op(client->descriptor_cookie, OP_EQ, client_cookie,
+ rend_data_v2_t *client_v2 = TO_REND_DATA_V2(client);
+ tt_int_op(client_v2->auth_type, ==, REND_NO_AUTH);
+ tt_str_op(client_v2->onion_address, OP_EQ, STR_HS_ADDR);
+ tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
+ tt_mem_op(client_v2->descriptor_cookie, OP_EQ, client_cookie,
sizeof(client_cookie));
tt_assert(client->hsdirs_fp);
tt_int_op(smartlist_len(client->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- int ret = rend_compute_v2_desc_id(desc_id, client->onion_address,
- client->descriptor_cookie, now, rep);
+ int ret = rend_compute_v2_desc_id(desc_id, client_v2->onion_address,
+ client_v2->descriptor_cookie, now, rep);
/* That shouldn't never fail. */
tt_int_op(ret, ==, 0);
- tt_mem_op(client->descriptor_id[rep], OP_EQ, desc_id, sizeof(desc_id));
+ tt_mem_op(client_v2->descriptor_id[rep], OP_EQ, desc_id,
+ sizeof(desc_id));
}
/* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client->rend_pk_digest), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client->rend_cookie), ==, 1);
/* Test dup(). */
client_dup = rend_data_dup(client);
tt_assert(client_dup);
- tt_int_op(client_dup->auth_type, ==, client->auth_type);
- tt_str_op(client_dup->onion_address, OP_EQ, client->onion_address);
- tt_mem_op(client_dup->desc_id_fetch, OP_EQ, client->desc_id_fetch,
- sizeof(client_dup->desc_id_fetch));
- tt_mem_op(client_dup->descriptor_cookie, OP_EQ, client->descriptor_cookie,
- sizeof(client_dup->descriptor_cookie));
+ rend_data_v2_t *client_dup_v2 = TO_REND_DATA_V2(client_dup);
+ tt_int_op(client_dup_v2->auth_type, ==, client_v2->auth_type);
+ tt_str_op(client_dup_v2->onion_address, OP_EQ, client_v2->onion_address);
+ tt_mem_op(client_dup_v2->desc_id_fetch, OP_EQ, client_v2->desc_id_fetch,
+ sizeof(client_dup_v2->desc_id_fetch));
+ tt_mem_op(client_dup_v2->descriptor_cookie, OP_EQ,
+ client_v2->descriptor_cookie,
+ sizeof(client_dup_v2->descriptor_cookie));
tt_assert(client_dup->hsdirs_fp);
tt_int_op(smartlist_len(client_dup->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_mem_op(client_dup->descriptor_id[rep], OP_EQ,
- client->descriptor_id[rep], DIGEST_LEN);
+ tt_mem_op(client_dup_v2->descriptor_id[rep], OP_EQ,
+ client_v2->descriptor_id[rep], DIGEST_LEN);
}
/* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client_dup->rend_pk_digest), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_dup_v2->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client_dup->rend_cookie), ==, 1);
rend_data_free(client);
client = NULL;
@@ -373,18 +379,19 @@ test_hs_rend_data(void *arg)
* zeroed out. */
client = rend_data_client_create(NULL, desc_id, NULL, REND_BASIC_AUTH);
tt_assert(client);
- tt_int_op(client->auth_type, ==, REND_BASIC_AUTH);
- tt_int_op(strlen(client->onion_address), ==, 0);
- tt_mem_op(client->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
- tt_int_op(tor_mem_is_zero(client->descriptor_cookie,
- sizeof(client->descriptor_cookie)), ==, 1);
+ client_v2 = TO_REND_DATA_V2(client);
+ tt_int_op(client_v2->auth_type, ==, REND_BASIC_AUTH);
+ tt_int_op(strlen(client_v2->onion_address), ==, 0);
+ tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
+ tt_int_op(tor_mem_is_zero(client_v2->descriptor_cookie,
+ sizeof(client_v2->descriptor_cookie)), ==, 1);
tt_assert(client->hsdirs_fp);
tt_int_op(smartlist_len(client->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(client->descriptor_id[rep]), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_v2->descriptor_id[rep]), ==, 1);
}
/* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client->rend_pk_digest), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client->rend_cookie), ==, 1);
rend_data_free(client);
client = NULL;
@@ -398,37 +405,39 @@ test_hs_rend_data(void *arg)
service = rend_data_service_create(STR_HS_ADDR, rend_pk_digest,
rend_cookie, REND_NO_AUTH);
tt_assert(service);
- tt_int_op(service->auth_type, ==, REND_NO_AUTH);
- tt_str_op(service->onion_address, OP_EQ, STR_HS_ADDR);
- tt_mem_op(service->rend_pk_digest, OP_EQ, rend_pk_digest,
+ rend_data_v2_t *service_v2 = TO_REND_DATA_V2(service);
+ tt_int_op(service_v2->auth_type, ==, REND_NO_AUTH);
+ tt_str_op(service_v2->onion_address, OP_EQ, STR_HS_ADDR);
+ tt_mem_op(service_v2->rend_pk_digest, OP_EQ, rend_pk_digest,
sizeof(rend_pk_digest));
tt_mem_op(service->rend_cookie, OP_EQ, rend_cookie, sizeof(rend_cookie));
tt_assert(service->hsdirs_fp);
tt_int_op(smartlist_len(service->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(service->descriptor_id[rep]), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_v2->descriptor_id[rep]), ==, 1);
}
/* The rest should be zeroed because this is a service request. */
- tt_int_op(tor_digest_is_zero(service->descriptor_cookie), ==, 1);
- tt_int_op(tor_digest_is_zero(service->desc_id_fetch), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_v2->descriptor_cookie), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_v2->desc_id_fetch), ==, 1);
/* Test dup(). */
service_dup = rend_data_dup(service);
+ rend_data_v2_t *service_dup_v2 = TO_REND_DATA_V2(service_dup);
tt_assert(service_dup);
- tt_int_op(service_dup->auth_type, ==, service->auth_type);
- tt_str_op(service_dup->onion_address, OP_EQ, service->onion_address);
- tt_mem_op(service_dup->rend_pk_digest, OP_EQ, service->rend_pk_digest,
- sizeof(service_dup->rend_pk_digest));
+ tt_int_op(service_dup_v2->auth_type, ==, service_v2->auth_type);
+ tt_str_op(service_dup_v2->onion_address, OP_EQ, service_v2->onion_address);
+ tt_mem_op(service_dup_v2->rend_pk_digest, OP_EQ, service_v2->rend_pk_digest,
+ sizeof(service_dup_v2->rend_pk_digest));
tt_mem_op(service_dup->rend_cookie, OP_EQ, service->rend_cookie,
sizeof(service_dup->rend_cookie));
tt_assert(service_dup->hsdirs_fp);
tt_int_op(smartlist_len(service_dup->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(service_dup->descriptor_id[rep]), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_dup_v2->descriptor_id[rep]), ==, 1);
}
/* The rest should be zeroed because this is a service request. */
- tt_int_op(tor_digest_is_zero(service_dup->descriptor_cookie), ==, 1);
- tt_int_op(tor_digest_is_zero(service_dup->desc_id_fetch), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_dup_v2->descriptor_cookie), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_dup_v2->desc_id_fetch), ==, 1);
done:
rend_data_free(service);
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
new file mode 100644
index 0000000000..e3a3fda8bb
--- /dev/null
+++ b/src/test/test_hs_cache.c
@@ -0,0 +1,479 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_cache.c
+ * \brief Test hidden service caches.
+ */
+
+#define HS_CACHE_PRIVATE
+
+#include "ed25519_cert.h"
+#include "hs_cache.h"
+#include "rendcache.h"
+#include "directory.h"
+#include "connection.h"
+
+#include "test_helpers.h"
+#include "test.h"
+
+/* Build an intro point using a blinded key and an address. */
+static hs_desc_intro_point_t *
+helper_build_intro_point(const ed25519_keypair_t *blinded_kp,
+ const char *addr)
+{
+ int ret;
+ ed25519_keypair_t auth_kp;
+ hs_desc_intro_point_t *intro_point = NULL;
+ hs_desc_intro_point_t *ip = tor_malloc_zero(sizeof(*ip));
+ ip->link_specifiers = smartlist_new();
+
+ {
+ hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls));
+ ls->u.ap.port = 9001;
+ int family = tor_addr_parse(&ls->u.ap.addr, addr);
+ switch (family) {
+ case AF_INET:
+ ls->type = LS_IPV4;
+ break;
+ case AF_INET6:
+ ls->type = LS_IPV6;
+ break;
+ default:
+ /* Stop the test, not suppose to have an error. */
+ tt_int_op(family, OP_EQ, AF_INET);
+ }
+ smartlist_add(ip->link_specifiers, ls);
+ }
+
+ ret = ed25519_keypair_generate(&auth_kp, 0);
+ tt_int_op(ret, ==, 0);
+ ip->auth_key_cert = tor_cert_create(blinded_kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ &auth_kp.pubkey, time(NULL),
+ HS_DESC_CERT_LIFETIME,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(ip->auth_key_cert);
+
+ ret = curve25519_keypair_generate(&ip->enc_key.curve25519, 0);
+ tt_int_op(ret, ==, 0);
+ ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519;
+ intro_point = ip;
+ done:
+ return intro_point;
+}
+
+/* Return a valid hs_descriptor_t object. */
+static hs_descriptor_t *
+helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime,
+ ed25519_keypair_t *blinded_kp)
+{
+ int ret;
+ hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));
+
+ desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;
+ ret = ed25519_keypair_generate(&desc->plaintext_data.signing_kp, 0);
+ tt_int_op(ret, ==, 0);
+ if (blinded_kp) {
+ memcpy(&desc->plaintext_data.blinded_kp, blinded_kp,
+ sizeof(ed25519_keypair_t));
+ } else {
+ ret = ed25519_keypair_generate(&desc->plaintext_data.blinded_kp, 0);
+ tt_int_op(ret, ==, 0);
+ }
+
+ desc->plaintext_data.signing_key_cert =
+ tor_cert_create(&desc->plaintext_data.blinded_kp,
+ CERT_TYPE_SIGNING_HS_DESC,
+ &desc->plaintext_data.signing_kp.pubkey, time(NULL),
+ 3600, CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(desc->plaintext_data.signing_key_cert);
+ desc->plaintext_data.revision_counter = revision_counter;
+ desc->plaintext_data.lifetime_sec = lifetime;
+
+ /* Setup encrypted data section. */
+ desc->encrypted_data.create2_ntor = 1;
+ desc->encrypted_data.auth_types = smartlist_new();
+ smartlist_add(desc->encrypted_data.auth_types, strdup("ed25519"));
+ desc->encrypted_data.intro_points = smartlist_new();
+ /* Add an intro point. */
+ smartlist_add(desc->encrypted_data.intro_points,
+ helper_build_intro_point(&desc->plaintext_data.blinded_kp,
+ "1.2.3.4"));
+
+ descp = desc;
+ done:
+ return descp;
+}
+
+/* Static variable used to encoded the HSDir query. */
+static char query_b64[256];
+
+/* Build an HSDir query using a ed25519 keypair. */
+static const char *
+helper_get_hsdir_query(const hs_descriptor_t *desc)
+{
+ ed25519_public_to_base64(query_b64,
+ &desc->plaintext_data.blinded_kp.pubkey);
+ return query_b64;
+}
+
+static void
+init_test(void)
+{
+ /* Always needed. Initialize the subsystem. */
+ hs_cache_init();
+ /* We need the v2 cache since our OOM and cache cleanup does poke at it. */
+ rend_cache_init();
+}
+
+static void
+test_directory(void *arg)
+{
+ int ret;
+ size_t oom_size;
+ char *desc1_str;
+ const char *desc_out;
+ hs_descriptor_t *desc1;
+
+ (void) arg;
+
+ init_test();
+ /* Generate a valid descriptor with normal values. */
+ desc1 = helper_build_hs_desc(42, 3 * 60 * 60, NULL);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Very first basic test, should be able to be stored, survive a
+ * clean, found with a lookup and then cleaned by our OOM. */
+ {
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Re-add, it should fail since we already have it. */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, -1);
+ /* Try to clean now which should be fine, there is at worst few seconds
+ * between the store and this call. */
+ hs_cache_clean_as_dir(time(NULL));
+ /* We should find it in our cache. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(desc_out, OP_EQ, desc1_str);
+ /* Tell our OOM to run and to at least remove a byte which will result in
+ * removing the descriptor from our cache. */
+ oom_size = hs_cache_handle_oom(time(NULL), 1);
+ tt_int_op(oom_size, >=, 1);
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Store two descriptors and remove the expiring one only. */
+ {
+ hs_descriptor_t *desc_zero_lifetime = helper_build_hs_desc(1, 0, NULL);
+ tt_assert(desc_zero_lifetime);
+ char *desc_zero_lifetime_str;
+ ret = hs_desc_encode_descriptor(desc_zero_lifetime,
+ &desc_zero_lifetime_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_store_as_dir(desc_zero_lifetime_str);
+ tt_int_op(ret, OP_EQ, 0);
+ /* This one should clear out our zero lifetime desc. */
+ hs_cache_clean_as_dir(time(NULL));
+ /* We should find desc1 in our cache. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(desc_out, OP_EQ, desc1_str);
+ /* We should NOT find our zero lifetime desc in our cache. */
+ ret = hs_cache_lookup_as_dir(3,
+ helper_get_hsdir_query(desc_zero_lifetime),
+ NULL);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Cleanup our entire cache. */
+ oom_size = hs_cache_handle_oom(time(NULL), 1);
+ tt_int_op(oom_size, >=, 1);
+ }
+
+ /* Throw junk at it. */
+ {
+ ret = hs_cache_store_as_dir("blah");
+ tt_int_op(ret, OP_EQ, -1);
+ /* Poor attempt at tricking the decoding. */
+ ret = hs_cache_store_as_dir("hs-descriptor 3\nJUNK");
+ tt_int_op(ret, OP_EQ, -1);
+ /* Undecodable base64 query. */
+ ret = hs_cache_lookup_as_dir(3, "blah", NULL);
+ tt_int_op(ret, OP_EQ, -1);
+ /* Decodable base64 query but wrong ed25519 size. */
+ ret = hs_cache_lookup_as_dir(3, "dW5pY29ybg==", NULL);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Test descriptor replacement with revision counter. */
+ {
+ char *new_desc_str;
+
+ /* Add a descriptor. */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ /* Bump revision counter. */
+ desc1->plaintext_data.revision_counter++;
+ ret = hs_desc_encode_descriptor(desc1, &new_desc_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_store_as_dir(new_desc_str);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Look it up, it should have been replaced. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(desc_out, OP_EQ, new_desc_str);
+ tor_free(new_desc_str);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_clean_as_dir(void *arg)
+{
+ size_t ret;
+ char *desc1_str = NULL;
+ time_t now = time(NULL);
+ hs_descriptor_t *desc1 = NULL;
+
+ (void) arg;
+
+ init_test();
+
+ /* Generate a valid descriptor with values. */
+ desc1 = helper_build_hs_desc(42, 3 * 60 * 60, NULL);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* With the lifetime being 3 hours, a cleanup shouldn't remove it. */
+ ret = cache_clean_v3_as_dir(now, 0);
+ tt_int_op(ret, ==, 0);
+ /* Should be present after clean up. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 1);
+ /* Set a cutoff 100 seconds in the past. It should not remove the entry
+ * since the entry is still recent enough. */
+ ret = cache_clean_v3_as_dir(now, now - 100);
+ tt_int_op(ret, ==, 0);
+ /* Should be present after clean up. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 1);
+ /* Set a cutoff of 100 seconds in the future. It should remove the entry
+ * that we've just added since it's not too old for the cutoff. */
+ ret = cache_clean_v3_as_dir(now, now + 100);
+ tt_int_op(ret, >, 0);
+ /* Shouldn't be present after clean up. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ hs_descriptor_free(desc1);
+ tor_free(desc1_str);
+}
+
+/* Test helper: Fetch an HS descriptor from an HSDir (for the hidden service
+ with <b>blinded_key</b>. Return the received descriptor string. */
+static char *
+helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
+{
+ int retval;
+
+ char *received_desc = NULL;
+ char *hsdir_query_str = NULL;
+
+ /* The dir conn we are going to simulate */
+ dir_connection_t *conn = NULL;
+ tor_addr_t mock_tor_addr;
+
+ /* First extract the blinded public key that we are going to use in our
+ query, and then build the actual query string. */
+ {
+ char hsdir_cache_key[ED25519_BASE64_LEN+1];
+
+ retval = ed25519_public_to_base64(hsdir_cache_key,
+ blinded_key);
+ tt_int_op(retval, ==, 0);
+ tor_asprintf(&hsdir_query_str, GET("/tor/hs/3/%s"), hsdir_cache_key);
+ }
+
+ /* Simulate an HTTP GET request to the HSDir */
+ conn = dir_connection_new(tor_addr_family(&mock_tor_addr));
+ TO_CONN(conn)->linked = 1;/* Pretend the conn is encrypted :) */
+ retval = directory_handle_command_get(conn, hsdir_query_str,
+ NULL, 0);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Read the descriptor that the HSDir just served us */
+ {
+ char *headers = NULL;
+ size_t body_used = 0;
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &headers, MAX_HEADERS_SIZE,
+ &received_desc, &body_used, 10000, 0);
+ }
+
+ done:
+ tor_free(hsdir_query_str);
+
+ return received_desc;
+}
+
+/* Publish a descriptor to the HSDir, then fetch it. Check that the received
+ descriptor matches the published one. */
+static void
+test_upload_and_download_hs_desc(void *arg)
+{
+ int retval;
+ hs_descriptor_t *published_desc;
+
+ char *published_desc_str = NULL;
+ char *received_desc_str = NULL;
+
+ (void) arg;
+
+ /* Initialize HSDir cache subsystem */
+ init_test();
+
+ /* Generate a valid descriptor with normal values. */
+ {
+ published_desc = helper_build_hs_desc(42, 3 * 60 * 60, NULL);
+ tt_assert(published_desc);
+ retval = hs_desc_encode_descriptor(published_desc, &published_desc_str);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ /* Publish descriptor to the HSDir */
+ {
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, ==, 200);
+ }
+
+ /* Simulate a fetch of the previously published descriptor */
+ {
+ const ed25519_public_key_t *blinded_key;
+ blinded_key = &published_desc->plaintext_data.blinded_kp.pubkey;
+ received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
+ }
+
+ /* Verify we received the exact same descriptor we published earlier */
+ tt_str_op(received_desc_str, OP_EQ, published_desc_str);
+
+ done:
+ tor_free(received_desc_str);
+ tor_free(published_desc_str);
+}
+
+/* Test that HSDirs reject outdated descriptors based on their revision
+ * counter. Also test that HSDirs correctly replace old descriptors with newer
+ * descriptors. */
+static void
+test_hsdir_revision_counter_check(void *arg)
+{
+ int retval;
+
+ hs_descriptor_t *published_desc;
+ char *published_desc_str = NULL;
+
+ char *received_desc_str = NULL;
+ hs_descriptor_t *received_desc = NULL;
+
+ (void) arg;
+
+ /* Initialize HSDir cache subsystem */
+ init_test();
+
+ /* Generate a valid descriptor with normal values. */
+ {
+ published_desc = helper_build_hs_desc(1312, 3 * 60 * 60, NULL);
+ tt_assert(published_desc);
+ retval = hs_desc_encode_descriptor(published_desc, &published_desc_str);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ /* Publish descriptor to the HSDir */
+ {
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, ==, 200);
+ }
+
+ /* Try publishing again with the same revision counter: Should fail. */
+ {
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, ==, 400);
+ }
+
+ /* Fetch the published descriptor and validate the revision counter. */
+ {
+ const ed25519_public_key_t *blinded_key;
+
+ blinded_key = &published_desc->plaintext_data.blinded_kp.pubkey;
+ received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
+
+ retval = hs_desc_decode_descriptor(received_desc_str,NULL, &received_desc);
+ tt_int_op(retval, ==, 0);
+ tt_assert(received_desc);
+
+ /* Check that the revision counter is correct */
+ tt_int_op(received_desc->plaintext_data.revision_counter, ==, 1312);
+ }
+
+ /* Increment the revision counter and try again. Should work. */
+ {
+ published_desc->plaintext_data.revision_counter = 1313;
+ tor_free(published_desc_str);
+ retval = hs_desc_encode_descriptor(published_desc, &published_desc_str);
+ tt_int_op(retval, OP_EQ, 0);
+
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, ==, 200);
+ }
+
+ /* Again, fetch the published descriptor and perform the revision counter
+ validation. The revision counter must have changed. */
+ {
+ const ed25519_public_key_t *blinded_key;
+
+ blinded_key = &published_desc->plaintext_data.blinded_kp.pubkey;
+ received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
+
+ retval = hs_desc_decode_descriptor(received_desc_str,NULL, &received_desc);
+ tt_int_op(retval, ==, 0);
+ tt_assert(received_desc);
+
+ /* Check that the revision counter is the latest */
+ tt_int_op(received_desc->plaintext_data.revision_counter, ==, 1313);
+ }
+
+ done:
+ hs_descriptor_free(published_desc);
+ hs_descriptor_free(received_desc);
+ tor_free(received_desc_str);
+ tor_free(published_desc_str);
+}
+
+struct testcase_t hs_cache[] = {
+ /* Encoding tests. */
+ { "directory", test_directory, TT_FORK,
+ NULL, NULL },
+ { "clean_as_dir", test_clean_as_dir, TT_FORK,
+ NULL, NULL },
+ { "hsdir_revision_counter_check", test_hsdir_revision_counter_check, TT_FORK,
+ NULL, NULL },
+ { "upload_and_download_hs_desc", test_upload_and_download_hs_desc, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
new file mode 100644
index 0000000000..dec5268b09
--- /dev/null
+++ b/src/test/test_hs_descriptor.c
@@ -0,0 +1,1130 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_descriptor.c
+ * \brief Test hidden service descriptor encoding and decoding.
+ */
+
+#define HS_DESCRIPTOR_PRIVATE
+
+#include "crypto_ed25519.h"
+#include "ed25519_cert.h"
+#include "or.h"
+#include "hs_descriptor.h"
+#include "test.h"
+#include "torcert.h"
+
+static hs_desc_intro_point_t *
+helper_build_intro_point(const ed25519_keypair_t *blinded_kp, time_t now,
+ const char *addr, int legacy)
+{
+ int ret;
+ ed25519_keypair_t auth_kp;
+ hs_desc_intro_point_t *intro_point = NULL;
+ hs_desc_intro_point_t *ip = tor_malloc_zero(sizeof(*ip));
+ ip->link_specifiers = smartlist_new();
+
+ {
+ hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls));
+ if (legacy) {
+ ls->type = LS_LEGACY_ID;
+ memcpy(ls->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8",
+ DIGEST_LEN);
+ } else {
+ ls->u.ap.port = 9001;
+ int family = tor_addr_parse(&ls->u.ap.addr, addr);
+ switch (family) {
+ case AF_INET:
+ ls->type = LS_IPV4;
+ break;
+ case AF_INET6:
+ ls->type = LS_IPV6;
+ break;
+ default:
+ /* Stop the test, not suppose to have an error. */
+ tt_int_op(family, OP_EQ, AF_INET);
+ }
+ }
+ smartlist_add(ip->link_specifiers, ls);
+ }
+
+ ret = ed25519_keypair_generate(&auth_kp, 0);
+ tt_int_op(ret, ==, 0);
+ ip->auth_key_cert = tor_cert_create(blinded_kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ &auth_kp.pubkey, now,
+ HS_DESC_CERT_LIFETIME,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(ip->auth_key_cert);
+
+ if (legacy) {
+ ip->enc_key.legacy = crypto_pk_new();
+ ip->enc_key_type = HS_DESC_KEY_TYPE_LEGACY;
+ tt_assert(ip->enc_key.legacy);
+ ret = crypto_pk_generate_key(ip->enc_key.legacy);
+ tt_int_op(ret, ==, 0);
+ } else {
+ ret = curve25519_keypair_generate(&ip->enc_key.curve25519, 0);
+ tt_int_op(ret, ==, 0);
+ ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519;
+ }
+
+ intro_point = ip;
+ done:
+ return intro_point;
+}
+
+/* Return a valid hs_descriptor_t object. If no_ip is set, no introduction
+ * points are added. */
+static hs_descriptor_t *
+helper_build_hs_desc(unsigned int no_ip)
+{
+ int ret;
+ time_t now = time(NULL);
+ hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));
+
+ desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;
+ ret = ed25519_keypair_generate(&desc->plaintext_data.signing_kp, 0);
+ tt_int_op(ret, ==, 0);
+ ret = ed25519_keypair_generate(&desc->plaintext_data.blinded_kp, 0);
+ tt_int_op(ret, ==, 0);
+
+ desc->plaintext_data.signing_key_cert =
+ tor_cert_create(&desc->plaintext_data.blinded_kp,
+ CERT_TYPE_SIGNING_HS_DESC,
+ &desc->plaintext_data.signing_kp.pubkey, now,
+ 3600,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(desc->plaintext_data.signing_key_cert);
+ desc->plaintext_data.revision_counter = 42;
+ desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
+
+ /* Setup encrypted data section. */
+ desc->encrypted_data.create2_ntor = 1;
+ desc->encrypted_data.auth_types = smartlist_new();
+ smartlist_add(desc->encrypted_data.auth_types, strdup("ed25519"));
+ desc->encrypted_data.intro_points = smartlist_new();
+ if (!no_ip) {
+ /* Add four intro points. */
+ smartlist_add(desc->encrypted_data.intro_points,
+ helper_build_intro_point(&desc->plaintext_data.blinded_kp, now,
+ "1.2.3.4", 0));
+ smartlist_add(desc->encrypted_data.intro_points,
+ helper_build_intro_point(&desc->plaintext_data.blinded_kp, now,
+ "[2600::1]", 0));
+ smartlist_add(desc->encrypted_data.intro_points,
+ helper_build_intro_point(&desc->plaintext_data.blinded_kp, now,
+ "3.2.1.4", 1));
+ smartlist_add(desc->encrypted_data.intro_points,
+ helper_build_intro_point(&desc->plaintext_data.blinded_kp, now,
+ "", 1));
+ }
+
+ descp = desc;
+ done:
+ return descp;
+}
+
+static void
+helper_compare_hs_desc(const hs_descriptor_t *desc1,
+ const hs_descriptor_t *desc2)
+{
+ /* Plaintext data section. */
+ tt_int_op(desc1->plaintext_data.version, OP_EQ,
+ desc2->plaintext_data.version);
+ tt_uint_op(desc1->plaintext_data.lifetime_sec, OP_EQ,
+ desc2->plaintext_data.lifetime_sec);
+ tt_assert(tor_cert_eq(desc1->plaintext_data.signing_key_cert,
+ desc2->plaintext_data.signing_key_cert));
+ tt_mem_op(desc1->plaintext_data.signing_kp.pubkey.pubkey, OP_EQ,
+ desc2->plaintext_data.signing_kp.pubkey.pubkey,
+ ED25519_PUBKEY_LEN);
+ tt_mem_op(desc1->plaintext_data.blinded_kp.pubkey.pubkey, OP_EQ,
+ desc2->plaintext_data.blinded_kp.pubkey.pubkey,
+ ED25519_PUBKEY_LEN);
+ tt_uint_op(desc1->plaintext_data.revision_counter, ==,
+ desc2->plaintext_data.revision_counter);
+
+ /* NOTE: We can't compare the encrypted blob because when encoding the
+ * descriptor, the object is immutable thus we don't update it with the
+ * encrypted blob. As contrast to the decoding process where we populate a
+ * descriptor object. */
+
+ /* Encrypted data section. */
+ tt_uint_op(desc1->encrypted_data.create2_ntor, ==,
+ desc2->encrypted_data.create2_ntor);
+
+ /* Authentication type. */
+ tt_int_op(!!desc1->encrypted_data.auth_types, ==,
+ !!desc2->encrypted_data.auth_types);
+ if (desc1->encrypted_data.auth_types && desc2->encrypted_data.auth_types) {
+ tt_int_op(smartlist_len(desc1->encrypted_data.auth_types), ==,
+ smartlist_len(desc2->encrypted_data.auth_types));
+ for (int i = 0; i < smartlist_len(desc1->encrypted_data.auth_types); i++) {
+ tt_str_op(smartlist_get(desc1->encrypted_data.auth_types, i), OP_EQ,
+ smartlist_get(desc2->encrypted_data.auth_types, i));
+ }
+ }
+
+ /* Introduction points. */
+ {
+ tt_assert(desc1->encrypted_data.intro_points);
+ tt_assert(desc2->encrypted_data.intro_points);
+ tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), ==,
+ smartlist_len(desc2->encrypted_data.intro_points));
+ for (int i=0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) {
+ hs_desc_intro_point_t *ip1 = smartlist_get(desc1->encrypted_data
+ .intro_points, i),
+ *ip2 = smartlist_get(desc2->encrypted_data
+ .intro_points, i);
+ tt_assert(tor_cert_eq(ip1->auth_key_cert, ip2->auth_key_cert));
+ tt_int_op(ip1->enc_key_type, OP_EQ, ip2->enc_key_type);
+ tt_assert(ip1->enc_key_type == HS_DESC_KEY_TYPE_LEGACY ||
+ ip1->enc_key_type == HS_DESC_KEY_TYPE_CURVE25519);
+ switch (ip1->enc_key_type) {
+ case HS_DESC_KEY_TYPE_LEGACY:
+ tt_int_op(crypto_pk_cmp_keys(ip1->enc_key.legacy, ip2->enc_key.legacy),
+ OP_EQ, 0);
+ break;
+ case HS_DESC_KEY_TYPE_CURVE25519:
+ tt_mem_op(ip1->enc_key.curve25519.pubkey.public_key, OP_EQ,
+ ip2->enc_key.curve25519.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
+ break;
+ }
+
+ tt_int_op(smartlist_len(ip1->link_specifiers), ==,
+ smartlist_len(ip2->link_specifiers));
+ for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) {
+ hs_desc_link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j),
+ *ls2 = smartlist_get(ip2->link_specifiers, j);
+ tt_int_op(ls1->type, ==, ls2->type);
+ switch (ls1->type) {
+ case LS_IPV4:
+ case LS_IPV6:
+ {
+ char *addr1 = tor_addr_to_str_dup(&ls1->u.ap.addr),
+ *addr2 = tor_addr_to_str_dup(&ls2->u.ap.addr);
+ tt_str_op(addr1, OP_EQ, addr2);
+ tor_free(addr1);
+ tor_free(addr2);
+ tt_int_op(ls1->u.ap.port, ==, ls2->u.ap.port);
+ }
+ break;
+ case LS_LEGACY_ID:
+ tt_mem_op(ls1->u.legacy_id, OP_EQ, ls2->u.legacy_id,
+ sizeof(ls1->u.legacy_id));
+ break;
+ default:
+ /* Unknown type, caught it and print its value. */
+ tt_int_op(ls1->type, OP_EQ, -1);
+ }
+ }
+ }
+ }
+
+ done:
+ ;
+}
+
+/* Test certificate encoding put in a descriptor. */
+static void
+test_cert_encoding(void *arg)
+{
+ int ret;
+ char *encoded = NULL;
+ time_t now = time(NULL);
+ ed25519_keypair_t kp;
+ ed25519_public_key_t signed_key;
+ ed25519_secret_key_t secret_key;
+ tor_cert_t *cert = NULL;
+
+ (void) arg;
+
+ ret = ed25519_keypair_generate(&kp, 0);
+ tt_int_op(ret, == , 0);
+ ret = ed25519_secret_key_generate(&secret_key, 0);
+ tt_int_op(ret, == , 0);
+ ret = ed25519_public_key_generate(&signed_key, &secret_key);
+ tt_int_op(ret, == , 0);
+
+ cert = tor_cert_create(&kp, CERT_TYPE_SIGNING_AUTH, &signed_key,
+ now, 3600 * 2, CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(cert);
+
+ /* Test the certificate encoding function. */
+ ret = encode_cert(cert, &encoded);
+ tt_int_op(ret, ==, 0);
+
+ /* Validated the certificate string. */
+ {
+ char *end, *pos = encoded;
+ char *b64_cert, buf[256];
+ size_t b64_cert_len;
+ tor_cert_t *parsed_cert;
+
+ tt_int_op(strcmpstart(pos, "-----BEGIN ED25519 CERT-----\n"), ==, 0);
+ pos += strlen("-----BEGIN ED25519 CERT-----\n");
+
+ /* Isolate the base64 encoded certificate and try to decode it. */
+ end = strstr(pos, "-----END ED25519 CERT-----");
+ tt_assert(end);
+ b64_cert = pos;
+ b64_cert_len = end - pos;
+ ret = base64_decode(buf, sizeof(buf), b64_cert, b64_cert_len);
+ tt_int_op(ret, >, 0);
+ /* Parseable? */
+ parsed_cert = tor_cert_parse((uint8_t *) buf, ret);
+ tt_assert(parsed_cert);
+ /* Signature is valid? */
+ ret = tor_cert_checksig(parsed_cert, &kp.pubkey, now + 10);
+ tt_int_op(ret, ==, 0);
+ ret = tor_cert_eq(cert, parsed_cert);
+ tt_int_op(ret, ==, 1);
+ /* The cert did have the signing key? */
+ ret= ed25519_pubkey_eq(&parsed_cert->signing_key, &kp.pubkey);
+ tt_int_op(ret, ==, 1);
+ tor_cert_free(parsed_cert);
+
+ /* Get to the end part of the certificate. */
+ pos += b64_cert_len;
+ tt_int_op(strcmpstart(pos, "-----END ED25519 CERT-----"), ==, 0);
+ pos += strlen("-----END ED25519 CERT-----");
+ }
+
+ done:
+ tor_cert_free(cert);
+ free(encoded);
+}
+
+/* Test the descriptor padding. */
+static void
+test_descriptor_padding(void *arg)
+{
+ char *plaintext;
+ size_t plaintext_len, padded_len;
+ uint8_t *padded_plaintext = NULL;
+
+/* Example: if l = 129, the ceiled division gives 2 and then multiplied by 128
+ * to give 256. With l = 127, ceiled division gives 1 then times 128. */
+#define PADDING_EXPECTED_LEN(l) \
+ CEIL_DIV(l, HS_DESC_PLAINTEXT_PADDING_MULTIPLE) * \
+ HS_DESC_PLAINTEXT_PADDING_MULTIPLE
+
+ (void) arg;
+
+ { /* test #1: no padding */
+ plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE;
+ plaintext = tor_malloc(plaintext_len);
+ padded_len = build_plaintext_padding(plaintext, plaintext_len,
+ &padded_plaintext);
+ tt_assert(padded_plaintext);
+ tor_free(plaintext);
+ /* Make sure our padding has been zeroed. */
+ tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ padded_len - plaintext_len), OP_EQ, 1);
+ tor_free(padded_plaintext);
+ /* Never never have a padded length smaller than the plaintext. */
+ tt_int_op(padded_len, OP_GE, plaintext_len);
+ tt_int_op(padded_len, OP_EQ, PADDING_EXPECTED_LEN(plaintext_len));
+ }
+
+ { /* test #2: one byte padding? */
+ plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE - 1;
+ plaintext = tor_malloc(plaintext_len);
+ padded_plaintext = NULL;
+ padded_len = build_plaintext_padding(plaintext, plaintext_len,
+ &padded_plaintext);
+ tt_assert(padded_plaintext);
+ tor_free(plaintext);
+ /* Make sure our padding has been zeroed. */
+ tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ padded_len - plaintext_len), OP_EQ, 1);
+ tor_free(padded_plaintext);
+ /* Never never have a padded length smaller than the plaintext. */
+ tt_int_op(padded_len, OP_GE, plaintext_len);
+ tt_int_op(padded_len, OP_EQ, PADDING_EXPECTED_LEN(plaintext_len));
+ }
+
+ { /* test #3: Lots more bytes of padding? */
+ plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE + 1;
+ plaintext = tor_malloc(plaintext_len);
+ padded_plaintext = NULL;
+ padded_len = build_plaintext_padding(plaintext, plaintext_len,
+ &padded_plaintext);
+ tt_assert(padded_plaintext);
+ tor_free(plaintext);
+ /* Make sure our padding has been zeroed. */
+ tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ padded_len - plaintext_len), OP_EQ, 1);
+ tor_free(padded_plaintext);
+ /* Never never have a padded length smaller than the plaintext. */
+ tt_int_op(padded_len, OP_GE, plaintext_len);
+ tt_int_op(padded_len, OP_EQ, PADDING_EXPECTED_LEN(plaintext_len));
+ }
+
+ done:
+ return;
+}
+
+static void
+test_link_specifier(void *arg)
+{
+ ssize_t ret;
+ hs_desc_link_specifier_t spec;
+ smartlist_t *link_specifiers = smartlist_new();
+
+ (void) arg;
+
+ /* Always this port. */
+ spec.u.ap.port = 42;
+ smartlist_add(link_specifiers, &spec);
+
+ /* Test IPv4 for starter. */
+ {
+ char *b64, buf[256];
+ uint32_t ipv4;
+ link_specifier_t *ls;
+
+ spec.type = LS_IPV4;
+ ret = tor_addr_parse(&spec.u.ap.addr, "1.2.3.4");
+ tt_int_op(ret, ==, AF_INET);
+ b64 = encode_link_specifiers(link_specifiers);
+ tt_assert(b64);
+
+ /* Decode it and validate the format. */
+ ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
+ tt_int_op(ret, >, 0);
+ /* First byte is the number of link specifier. */
+ tt_int_op(get_uint8(buf), ==, 1);
+ ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
+ tt_int_op(ret, ==, 8);
+ /* Should be 2 bytes for port and 4 bytes for IPv4. */
+ tt_int_op(link_specifier_get_ls_len(ls), ==, 6);
+ ipv4 = link_specifier_get_un_ipv4_addr(ls);
+ tt_int_op(tor_addr_to_ipv4h(&spec.u.ap.addr), ==, ipv4);
+ tt_int_op(link_specifier_get_un_ipv4_port(ls), ==, spec.u.ap.port);
+
+ link_specifier_free(ls);
+ tor_free(b64);
+ }
+
+ /* Test IPv6. */
+ {
+ char *b64, buf[256];
+ uint8_t ipv6[16];
+ link_specifier_t *ls;
+
+ spec.type = LS_IPV6;
+ ret = tor_addr_parse(&spec.u.ap.addr, "[1:2:3:4::]");
+ tt_int_op(ret, ==, AF_INET6);
+ b64 = encode_link_specifiers(link_specifiers);
+ tt_assert(b64);
+
+ /* Decode it and validate the format. */
+ ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
+ tt_int_op(ret, >, 0);
+ /* First byte is the number of link specifier. */
+ tt_int_op(get_uint8(buf), ==, 1);
+ ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
+ tt_int_op(ret, ==, 20);
+ /* Should be 2 bytes for port and 16 bytes for IPv6. */
+ tt_int_op(link_specifier_get_ls_len(ls), ==, 18);
+ for (unsigned int i = 0; i < sizeof(ipv6); i++) {
+ ipv6[i] = link_specifier_get_un_ipv6_addr(ls, i);
+ }
+ tt_mem_op(tor_addr_to_in6_addr8(&spec.u.ap.addr), ==, ipv6, sizeof(ipv6));
+ tt_int_op(link_specifier_get_un_ipv6_port(ls), ==, spec.u.ap.port);
+
+ link_specifier_free(ls);
+ tor_free(b64);
+ }
+
+ /* Test legacy. */
+ {
+ char *b64, buf[256];
+ uint8_t *id;
+ link_specifier_t *ls;
+
+ spec.type = LS_LEGACY_ID;
+ memset(spec.u.legacy_id, 'Y', sizeof(spec.u.legacy_id));
+ b64 = encode_link_specifiers(link_specifiers);
+ tt_assert(b64);
+
+ /* Decode it and validate the format. */
+ ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
+ tt_int_op(ret, >, 0);
+ /* First byte is the number of link specifier. */
+ tt_int_op(get_uint8(buf), ==, 1);
+ ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
+ /* 20 bytes digest + 1 byte type + 1 byte len. */
+ tt_int_op(ret, ==, 22);
+ tt_int_op(link_specifier_getlen_un_legacy_id(ls), OP_EQ, DIGEST_LEN);
+ /* Digest length is 20 bytes. */
+ tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, DIGEST_LEN);
+ id = link_specifier_getarray_un_legacy_id(ls);
+ tt_mem_op(spec.u.legacy_id, OP_EQ, id, DIGEST_LEN);
+
+ link_specifier_free(ls);
+ tor_free(b64);
+ }
+
+ done:
+ return;
+}
+
+static void
+test_encode_descriptor(void *arg)
+{
+ int ret;
+ char *encoded = NULL;
+ hs_descriptor_t *desc = helper_build_hs_desc(0);
+
+ (void) arg;
+
+ ret = hs_desc_encode_descriptor(desc, &encoded);
+ tt_int_op(ret, ==, 0);
+ tt_assert(encoded);
+
+ done:
+ hs_descriptor_free(desc);
+ tor_free(encoded);
+}
+
+static void
+test_decode_descriptor(void *arg)
+{
+ int ret;
+ char *encoded = NULL;
+ hs_descriptor_t *desc = helper_build_hs_desc(0);
+ hs_descriptor_t *decoded = NULL;
+
+ (void) arg;
+
+ /* Give some bad stuff to the decoding function. */
+ ret = hs_desc_decode_descriptor("hladfjlkjadf", NULL, &decoded);
+ tt_int_op(ret, OP_EQ, -1);
+
+ ret = hs_desc_encode_descriptor(desc, &encoded);
+ tt_int_op(ret, ==, 0);
+ tt_assert(encoded);
+
+ ret = hs_desc_decode_descriptor(encoded, NULL, &decoded);
+ tt_int_op(ret, ==, 0);
+ tt_assert(decoded);
+
+ helper_compare_hs_desc(desc, decoded);
+
+ /* Decode a descriptor with _no_ introduction points. */
+ {
+ hs_descriptor_t *desc_no_ip = helper_build_hs_desc(1);
+ tt_assert(desc_no_ip);
+ tor_free(encoded);
+ ret = hs_desc_encode_descriptor(desc_no_ip, &encoded);
+ tt_int_op(ret, ==, 0);
+ tt_assert(encoded);
+ hs_descriptor_free(decoded);
+ ret = hs_desc_decode_descriptor(encoded, NULL, &decoded);
+ tt_int_op(ret, ==, 0);
+ tt_assert(decoded);
+ }
+
+ done:
+ hs_descriptor_free(desc);
+ hs_descriptor_free(decoded);
+ tor_free(encoded);
+}
+
+static void
+test_supported_version(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* Unsupported. */
+ ret = hs_desc_is_supported_version(42);
+ tt_int_op(ret, OP_EQ, 0);
+ /* To early. */
+ ret = hs_desc_is_supported_version(HS_DESC_SUPPORTED_FORMAT_VERSION_MIN - 1);
+ tt_int_op(ret, OP_EQ, 0);
+ /* One too new. */
+ ret = hs_desc_is_supported_version(HS_DESC_SUPPORTED_FORMAT_VERSION_MAX + 1);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Valid version. */
+ ret = hs_desc_is_supported_version(3);
+ tt_int_op(ret, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+static void
+test_encrypted_data_len(void *arg)
+{
+ int ret;
+ size_t value;
+
+ (void) arg;
+
+ /* No length, error. */
+ ret = encrypted_data_length_is_valid(0);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Not a multiple of our encryption algorithm (thus no padding). It's
+ * suppose to be aligned on HS_DESC_PLAINTEXT_PADDING_MULTIPLE. */
+ value = HS_DESC_PLAINTEXT_PADDING_MULTIPLE * 10 - 1;
+ ret = encrypted_data_length_is_valid(value);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Valid value. */
+ value = HS_DESC_PADDED_PLAINTEXT_MAX_LEN + HS_DESC_ENCRYPTED_SALT_LEN +
+ DIGEST256_LEN;
+ ret = encrypted_data_length_is_valid(value);
+ tt_int_op(ret, OP_EQ, 1);
+
+ /* XXX: Test maximum possible size. */
+
+ done:
+ ;
+}
+
+static void
+test_decode_intro_point(void *arg)
+{
+ int ret;
+ char *encoded_ip = NULL;
+ size_t len_out;
+ hs_desc_intro_point_t *ip;
+ hs_descriptor_t *desc = NULL;
+
+ (void) arg;
+
+ /* The following certificate expires in 2036. After that, one of the test
+ * will fail because of the expiry time. */
+
+ /* Seperate pieces of a valid encoded introduction point. */
+ const char *intro_point =
+ "introduction-point AQIUMDI5OUYyNjhGQ0E5RDU1Q0QxNTc=";
+ const char *auth_key =
+ "auth-key\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQkACOhAAQW8ltYZMIWpyrfyE/b4Iyi8CNybCwYs6ADk7XfBaxsFAQAgBAD3/BE4\n"
+ "XojGE/N2bW/wgnS9r2qlrkydGyuCKIGayYx3haZ39LD4ZTmSMRxwmplMAqzG/XNP\n"
+ "0Kkpg4p2/VnLFJRdU1SMFo1lgQ4P0bqw7Tgx200fulZ4KUM5z5V7m+a/mgY=\n"
+ "-----END ED25519 CERT-----";
+ const char *enc_key =
+ "enc-key ntor bpZKLsuhxP6woDQ3yVyjm5gUKSk7RjfAijT2qrzbQk0=";
+ const char *enc_key_legacy =
+ "enc-key legacy\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAO4bATcW8kW4h6RQQAKEgg+aXCpF4JwbcO6vGZtzXTDB+HdPVQzwqkbh\n"
+ "XzFM6VGArhYw4m31wcP1Z7IwULir7UMnAFd7Zi62aYfU6l+Y1yAoZ1wzu1XBaAMK\n"
+ "ejpwQinW9nzJn7c2f69fVke3pkhxpNdUZ+vplSA/l9iY+y+v+415AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----";
+ const char *enc_key_cert =
+ "enc-key-certification\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQsACOhZAUpNvCZ1aJaaR49lS6MCdsVkhVGVrRqoj0Y2T4SzroAtAQAgBABFOcGg\n"
+ "lbTt1DF5nKTE/gU3Fr8ZtlCIOhu1A+F5LM7fqCUupfesg0KTHwyIZOYQbJuM5/he\n"
+ "/jDNyLy9woPJdjkxywaY2RPUxGjLYtMQV0E8PUxWyICV+7y52fTCYaKpYQw=\n"
+ "-----END ED25519 CERT-----";
+ const char *enc_key_cert_legacy =
+ "enc-key-certification\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "Sk28JnVolppHj2VLowJ2xWSFUZWtGqiPRjZPhLOugC0ACOhZgFPA5egeRDUXMM1U\n"
+ "Fn3c7Je0gJS6mVma5FzwlgwggeriF13UZcaT71vEAN/ZJXbxOfQVGMZ0rXuFpjUq\n"
+ "C8CvqmZIwEUaPE1nDFtmnTcucvNS1YQl9nsjH3ejbxc+4yqps/cXh46FmXsm5yz7\n"
+ "NZjBM9U1fbJhlNtOvrkf70K8bLk6\n"
+ "-----END CROSSCERT-----";
+
+ (void) enc_key_legacy;
+ (void) enc_key_cert_legacy;
+
+ /* Start by testing the "decode all intro points" function. */
+ {
+ char *line;
+ desc = helper_build_hs_desc(0);
+ tt_assert(desc);
+ /* Only try to decode an incomplete introduction point section. */
+ tor_asprintf(&line, "\n%s", intro_point);
+ ret = decode_intro_points(desc, &desc->encrypted_data, line);
+ tor_free(line);
+ tt_int_op(ret, ==, -1);
+
+ /* Decode one complete intro point. */
+ smartlist_t *lines = smartlist_new();
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) enc_key);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ tor_asprintf(&line, "\n%s", encoded_ip);
+ tor_free(encoded_ip);
+ ret = decode_intro_points(desc, &desc->encrypted_data, line);
+ tor_free(line);
+ smartlist_free(lines);
+ tt_int_op(ret, ==, 0);
+ }
+
+ /* Try to decode a junk string. */
+ {
+ hs_descriptor_free(desc);
+ desc = helper_build_hs_desc(0);
+ const char *junk = "this is not a descriptor";
+ ip = decode_introduction_point(desc, junk);
+ tt_assert(!ip);
+ }
+
+ /* Invalid link specifiers. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "introduction-point blah";
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) enc_key);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_assert(!ip);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid auth key type. */
+ {
+ smartlist_t *lines = smartlist_new();
+ /* Try to put a valid object that our tokenize function will be able to
+ * parse but that has nothing to do with the auth_key. */
+ const char *bad_line =
+ "auth-key\n"
+ "-----BEGIN UNICORN CERT-----\n"
+ "MIGJAoGBAO4bATcW8kW4h6RQQAKEgg+aXCpF4JwbcO6vGZtzXTDB+HdPVQzwqkbh\n"
+ "XzFM6VGArhYw4m31wcP1Z7IwULir7UMnAFd7Zi62aYfU6l+Y1yAoZ1wzu1XBaAMK\n"
+ "ejpwQinW9nzJn7c2f69fVke3pkhxpNdUZ+vplSA/l9iY+y+v+415AgMBAAE=\n"
+ "-----END UNICORN CERT-----";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_assert(!ip);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line =
+ "enc-key unicorn bpZKLsuhxP6woDQ3yVyjm5gUKSk7RjfAijT2qrzbQk0=";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_assert(!ip);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key object. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "enc-key ntor";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_assert(!ip);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key base64 curv25519 key. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "enc-key ntor blah===";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_assert(!ip);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key invalid legacy. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "enc-key legacy blah===";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_assert(!ip);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Valid object. */
+ {
+ smartlist_t *lines = smartlist_new();
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) enc_key);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_assert(ip);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ done:
+ hs_descriptor_free(desc);
+}
+
+const char encrypted_desc_portion[] = "create2-formats 2\n"
+ "authentication-required ed25519\n"
+ "introduction-point AQAGAQIDBCMp\n"
+ "auth-key\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQkABmRZASMANx4sbMyDd4i+MciVUw29vPQ/nOFrLwUdTGEBXSXrAQAgBABo2zfd\n"
+ "wyqAdzSeaIzH1TUcV3u8nAG2YhNCRw2/2vVWuD6Z4Fn0aNHnh1FONNkbismC9t1X\n"
+ "Rf07hdZkVYEbOaPsHnFwhJULVSUo8YYuL19jghRjwMqPGeGfD4iuQqdo3QA=\n"
+ "-----END ED25519 CERT-----\n"
+ "enc-key ntor xo2n5anLMoyIMuhcKSLdVZISyISBW8j1vXRbpdbK+lU=\n"
+ "enc-key-certification\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQsABmRZATUYQypFY7pr8FpmV61pcqUylt5fEr/QLfavfcwbzlA7AQAgBADSI5Ie\n"
+ "Ekdy+qeHngLmz6Gr7fQ5xvilhxB91UDIjwRfP0ufoVF+HalsyXKskYvcYhH67+lw\n"
+ "D947flCHzeJyfAT38jO/Cw42qM7H+SObBMcsTB93J0lPNBy4OHosH9ybtwA=\n"
+ "-----END ED25519 CERT-----\n"
+ "introduction-point AQESJgAAAAAAAAAAAAAAAAAAASMp\n"
+ "auth-key\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQkABmRZAVdPeZyzfCyUDC1fnYyom8eOS2O1opzTytEU7dlOf9brAQAgBABo2zfd\n"
+ "wyqAdzSeaIzH1TUcV3u8nAG2YhNCRw2/2vVWuHVSGTrO1EM6Eu1jyOw/qtSS6Exf\n"
+ "omV417y8uK2gHQ+1FWqg/KaogELYzDG6pcj2NkziovnIfET0W7nZB85YjwQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "enc-key ntor MbxzxI1K+zcl7e+wysLK96UZWwFEJQqI0G7b0muRXx4=\n"
+ "enc-key-certification\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQsABmRZATUYQypFY7pr8FpmV61pcqUylt5fEr/QLfavfcwbzlA7AQAgBADimELh\n"
+ "lLZvy/LjXnCdpvaVRhiGBeIRAGIDGz1SY/zD6BAnpDL420ha2TdvdGsg8cgfTcJZ\n"
+ "g84x85+zhuh8kkdgt7bOmjOXLlButDCfTarMgCfy6pSI/hUckk+j5Q43uws=\n"
+ "-----END ED25519 CERT-----\n"
+ "introduction-point AQIUMDI5OUYyNjhGQ0E5RDU1Q0QxNTc=\n"
+ "auth-key\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQkABmRZASnpBjHsw0Gpvi+KNlW4ouXegIsUBHMvJN1CQHDTLdfnAQAgBABo2zfd\n"
+ "wyqAdzSeaIzH1TUcV3u8nAG2YhNCRw2/2vVWuOlbHs8s8LAeEb36urVKTJ5exgss\n"
+ "V+ylIwHSWF0qanCnnTnDyNg/3YRUo0AZr0d/CoiNV+XsGE4Vuho/TBVC+wY=\n"
+ "-----END ED25519 CERT-----\n"
+ "enc-key legacy\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALttUA1paMCQiuIZeCp26REztziej5dN0o6/kTU//ItT4MGxTfmnLmcq\n"
+ "WpvK4jdX1h2OlDCZmtA7sb0HOkjELgrDU0ATVwOaeG+3icSddmQyaeT8+cxQEktj\n"
+ "SXMQ+iJDxJIIWFPmLmWWQHqb4IRfl021l3iTErhtZKBz37JNK7E/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "enc-key-certification\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "NRhDKkVjumvwWmZXrWlypTKW3l8Sv9At9q99zBvOUDsABmRZgBROMZr2Mhj8H8zd\n"
+ "xbU6ZvDUwD9xkptNHq0W04CyWb8p0y56y89y2kBF6RrSrVBJCyaHyph6Bmi5z0Lc\n"
+ "f4jjakRlHwB7oYqSo7l8EE9DGE0rEat3hNhN+tBIAJL5gKOL4dgfD5gMi51zzSFl\n"
+ "epv8idTwhqZ/sxRMUIQrb9AB8sOD\n"
+ "-----END CROSSCERT-----\n"
+ "introduction-point AQIUMDI5OUYyNjhGQ0E5RDU1Q0QxNTc=\n"
+ "auth-key\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQkABmRZAdBFQcE23cIoCMFTycnQ1st2752vdjGME+QPMTTxvqZhAQAgBABo2zfd\n"
+ "wyqAdzSeaIzH1TUcV3u8nAG2YhNCRw2/2vVWuOGXGPnb3g9J8aSyN7jYs71ET0wC\n"
+ "TlDLcXCgAMnKA6of/a4QceFfAFsCnI3qCd8YUo5NYCMh2d5mtFpLK41Wpwo=\n"
+ "-----END ED25519 CERT-----\n"
+ "enc-key legacy\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALuyEVMz4GwZ8LnBYxLZDHNg1DHUZJZNmE7HsQDcM/FYeZ1LjYLe/K8s\n"
+ "BFzgFmjMU1ondIWGWpRCLYcZxQMZaSU0ObdezDwelTkHo/u7K2fQTLmI9EofcsK0\n"
+ "4OkY6eo8BFtXXoQJhAw5WatRpzah2sGqMPXs2jr7Ku4Pd8JuRd35AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "enc-key-certification\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "NRhDKkVjumvwWmZXrWlypTKW3l8Sv9At9q99zBvOUDsABmRZgGwpo67ybC7skFYk\n"
+ "JjvqcbrKg8Fwrvue9yF66p1O90fqziVsvpKGcsr3tcIJHtNsrWVRDpyFwnc1wlVE\n"
+ "O7rHftF4GUsKaoz3wxxmb0YyyYVQvLpH0Y6lFIvw8nGurnsMefQWLcxuEX7xZOPl\n"
+ "VAlVp+XtJE1ZNQ62hpnNgBDi1ikJ\n"
+ "-----END CROSSCERT-----";
+
+static void
+test_decode_multiple_intro_points(void *arg)
+{
+ int ret;
+ hs_descriptor_t *desc = NULL;
+
+ (void) arg;
+
+ {
+ /* Build a descriptor with no intro points. */
+ desc = helper_build_hs_desc(1);
+ tt_assert(desc);
+ }
+
+ ret = decode_intro_points(desc, &desc->encrypted_data,
+ encrypted_desc_portion);
+ tt_int_op(ret, ==, 0);
+
+ tt_int_op(smartlist_len(desc->encrypted_data.intro_points), ==, 4);
+
+ done:
+ ;
+}
+
+static void
+test_free_objects(void *arg)
+{
+ (void) arg;
+
+ {
+ const char u[] = { 'U', 'U', 'U', 'U' };
+ hs_desc_plaintext_data_t *data = tor_malloc_zero(sizeof(*data));
+ /* Set a memory marker so we know if the data was properly wiped. */
+ memset(&data->version, 'U', sizeof(data->version));
+ hs_desc_plaintext_data_free(data);
+ tt_mem_op(&data->version, OP_NE, u, sizeof(u));
+ }
+
+ {
+ hs_desc_encrypted_data_t *data = tor_malloc_zero(sizeof(*data));
+ /* Set a memory marker so we know if the data was properly wiped. */
+ data->create2_ntor = 1;
+ hs_desc_encrypted_data_free(data);
+ tt_int_op(data->create2_ntor, OP_NE, 1);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_decode_plaintext(void *arg)
+{
+ int ret;
+ hs_desc_plaintext_data_t desc_plaintext;
+ const char *bad_value = "unicorn";
+
+ (void) arg;
+
+#define template \
+ "hs-descriptor %s\n" \
+ "descriptor-lifetime %s\n" \
+ "descriptor-signing-key-cert\n" \
+ "-----BEGIN ED25519 CERT-----\n" \
+ "AQgABjvPAQaG3g+dc6oV/oJV4ODAtkvx56uBnPtBT9mYVuHVOhn7AQAgBABUg3mQ\n" \
+ "myBr4bu5LCr53wUEbW2EXui01CbUgU7pfo9LvJG3AcXRojj6HlfsUs9BkzYzYdjF\n" \
+ "A69Apikgu0ewHYkFFASt7Il+gB3w6J8YstQJZT7dtbtl+doM7ug8B68Qdg8=\n" \
+ "-----END ED25519 CERT-----\n" \
+ "revision-counter %s\n" \
+ "encrypted\n" \
+ "-----BEGIN %s-----\n" \
+ "UNICORN\n" \
+ "-----END MESSAGE-----\n" \
+ "signature m20WJH5agqvwhq7QeuEZ1mYyPWQDO+eJOZUjLhAiKu8DbL17DsDfJE6kXbWy" \
+ "HimbNj2we0enV3cCOOAsmPOaAw\n"
+
+ /* Invalid version. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, bad_value, "180", "42", "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Missing fields. */
+ {
+ const char *plaintext = "hs-descriptor 3\n";
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Max length. */
+ {
+ size_t big = 64000;
+ /* Must always be bigger than HS_DESC_MAX_LEN. */
+ tt_int_op(HS_DESC_MAX_LEN, <, big);
+ char *plaintext = tor_malloc_zero(big);
+ memset(plaintext, 'a', big);
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Bad lifetime value. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", bad_value, "42", "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Huge lifetime value. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", "7181615", "42", "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Invalid encrypted section. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", "180", "42", bad_value);
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Invalid revision counter. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", "180", bad_value, "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_validate_cert(void *arg)
+{
+ int ret;
+ time_t now = time(NULL);
+ ed25519_keypair_t kp;
+
+ (void) arg;
+
+ ret = ed25519_keypair_generate(&kp, 0);
+ tt_int_op(ret, ==, 0);
+
+ /* Cert of type CERT_TYPE_AUTH_HS_IP_KEY. */
+ tor_cert_t *cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ &kp.pubkey, now, 3600,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(cert);
+ /* Test with empty certificate. */
+ ret = cert_is_valid(NULL, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+ /* Test with a bad type. */
+ ret = cert_is_valid(cert, CERT_TYPE_SIGNING_HS_DESC, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+ /* Normal validation. */
+ ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 1);
+ /* Break signing key so signature verification will fails. */
+ memset(&cert->signing_key, 0, sizeof(cert->signing_key));
+ ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+ tor_cert_free(cert);
+
+ /* Try a cert without including the signing key. */
+ cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY, &kp.pubkey, now, 3600, 0);
+ tt_assert(cert);
+ /* Test with a bad type. */
+ ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+static void
+test_desc_signature(void *arg)
+{
+ int ret;
+ char *data, *desc;
+ char sig_b64[ED25519_SIG_BASE64_LEN + 1];
+ ed25519_keypair_t kp;
+ ed25519_signature_t sig;
+
+ (void) arg;
+
+ ed25519_keypair_generate(&kp, 0);
+ /* Setup a phoony descriptor but with a valid signature token that is the
+ * signature is verifiable. */
+ tor_asprintf(&data, "This is a signed descriptor\n");
+ ret = ed25519_sign_prefixed(&sig, (const uint8_t *) data, strlen(data),
+ "Tor onion service descriptor sig v3", &kp);
+ tt_int_op(ret, ==, 0);
+ ret = ed25519_signature_to_base64(sig_b64, &sig);
+ tt_int_op(ret, ==, 0);
+ /* Build the descriptor that should be valid. */
+ tor_asprintf(&desc, "%ssignature %s\n", data, sig_b64);
+ ret = desc_sig_is_valid(sig_b64, &kp, desc, strlen(desc));
+ tt_int_op(ret, ==, 1);
+ /* Junk signature. */
+ ret = desc_sig_is_valid("JUNK", &kp, desc, strlen(desc));
+ tt_int_op(ret, ==, 0);
+
+ done:
+ tor_free(desc);
+ tor_free(data);
+}
+
+struct testcase_t hs_descriptor[] = {
+ /* Encoding tests. */
+ { "cert_encoding", test_cert_encoding, TT_FORK,
+ NULL, NULL },
+ { "link_specifier", test_link_specifier, TT_FORK,
+ NULL, NULL },
+ { "encode_descriptor", test_encode_descriptor, TT_FORK,
+ NULL, NULL },
+ { "descriptor_padding", test_descriptor_padding, TT_FORK,
+ NULL, NULL },
+
+ /* Decoding tests. */
+ { "decode_descriptor", test_decode_descriptor, TT_FORK,
+ NULL, NULL },
+ { "encrypted_data_len", test_encrypted_data_len, TT_FORK,
+ NULL, NULL },
+ { "decode_intro_point", test_decode_intro_point, TT_FORK,
+ NULL, NULL },
+ { "decode_multiple_intro_points", test_decode_multiple_intro_points, TT_FORK,
+ NULL, NULL },
+ { "decode_plaintext", test_decode_plaintext, TT_FORK,
+ NULL, NULL },
+
+ /* Misc. */
+ { "version", test_supported_version, TT_FORK,
+ NULL, NULL },
+ { "free_objects", test_free_objects, TT_FORK,
+ NULL, NULL },
+ { "validate_cert", test_validate_cert, TT_FORK,
+ NULL, NULL },
+ { "desc_signature", test_desc_signature, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c
index a5d3f351f8..7f72e441ee 100644
--- a/src/test/test_rendcache.c
+++ b/src/test/test_rendcache.c
@@ -10,6 +10,7 @@
#include "router.h"
#include "routerlist.h"
#include "config.h"
+#include "hs_common.h"
#include <openssl/rsa.h>
#include "rend_test_helpers.h"
#include "log_test_helpers.h"
@@ -24,15 +25,16 @@ static const int TIME_IN_THE_FUTURE = REND_CACHE_MAX_SKEW + 60;
static rend_data_t *
mock_rend_data(const char *onion_address)
{
- rend_data_t *rend_query = tor_malloc_zero(sizeof(rend_data_t));
+ rend_data_v2_t *v2_data = tor_malloc_zero(sizeof(*v2_data));
+ rend_data_t *rend_query = &v2_data->base_;
+ rend_query->version = 2;
- strlcpy(rend_query->onion_address, onion_address,
- sizeof(rend_query->onion_address));
- rend_query->auth_type = REND_NO_AUTH;
+ strlcpy(v2_data->onion_address, onion_address,
+ sizeof(v2_data->onion_address));
+ v2_data->auth_type = REND_NO_AUTH;
rend_query->hsdirs_fp = smartlist_new();
smartlist_add(rend_query->hsdirs_fp, tor_memdup("aaaaaaaaaaaaaaaaaaaaaaaa",
DIGEST_LEN));
-
return rend_query;
}
@@ -144,7 +146,8 @@ test_rend_cache_store_v2_desc_as_client(void *data)
// Test mismatch between service ID and onion address
rend_cache_init();
- strncpy(mock_rend_query->onion_address, "abc", REND_SERVICE_ID_LEN_BASE32+1);
+ strncpy(TO_REND_DATA_V2(mock_rend_query)->onion_address, "abc",
+ REND_SERVICE_ID_LEN_BASE32+1);
ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
desc_id_base32,
mock_rend_query, NULL);
@@ -230,9 +233,9 @@ test_rend_cache_store_v2_desc_as_client(void *data)
generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
mock_rend_query = mock_rend_data(service_id);
- mock_rend_query->auth_type = REND_BASIC_AUTH;
+ TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
client_cookie[0] = 'A';
- memcpy(mock_rend_query->descriptor_cookie, client_cookie,
+ memcpy(TO_REND_DATA_V2(mock_rend_query)->descriptor_cookie, client_cookie,
REND_DESC_COOKIE_LEN);
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
DIGEST_LEN);
@@ -250,7 +253,7 @@ test_rend_cache_store_v2_desc_as_client(void *data)
generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
mock_rend_query = mock_rend_data(service_id);
- mock_rend_query->auth_type = REND_BASIC_AUTH;
+ TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
DIGEST_LEN);
ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
@@ -1078,9 +1081,10 @@ static void
test_rend_cache_clean_v2_descs_as_dir(void *data)
{
rend_cache_entry_t *e;
- time_t now;
+ time_t now, cutoff;
rend_service_descriptor_t *desc;
now = time(NULL);
+ cutoff = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW);
const char key[DIGEST_LEN] = "abcde";
(void)data;
@@ -1088,7 +1092,7 @@ test_rend_cache_clean_v2_descs_as_dir(void *data)
rend_cache_init();
// Test running with an empty cache
- rend_cache_clean_v2_descs_as_dir(now, 0);
+ rend_cache_clean_v2_descs_as_dir(cutoff);
tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
// Test with only one new entry
@@ -1100,38 +1104,15 @@ test_rend_cache_clean_v2_descs_as_dir(void *data)
e->parsed = desc;
digestmap_set(rend_cache_v2_dir, key, e);
- rend_cache_clean_v2_descs_as_dir(now, 0);
+ /* Set the cutoff to minus 10 seconds. */
+ rend_cache_clean_v2_descs_as_dir(cutoff - 10);
tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 1);
// Test with one old entry
- desc->timestamp = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW + 1000);
- rend_cache_clean_v2_descs_as_dir(now, 0);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
-
- // Test with one entry that has an old last served
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- e->last_served = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW + 1000);
- desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc->timestamp = now;
- desc->pk = pk_generate(0);
- e->parsed = desc;
- digestmap_set(rend_cache_v2_dir, key, e);
-
- rend_cache_clean_v2_descs_as_dir(now, 0);
+ desc->timestamp = cutoff - 1000;
+ rend_cache_clean_v2_descs_as_dir(cutoff);
tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
- // Test a run through asking for a large force_remove
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- e->last_served = now;
- desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc->timestamp = now;
- desc->pk = pk_generate(0);
- e->parsed = desc;
- digestmap_set(rend_cache_v2_dir, key, e);
-
- rend_cache_clean_v2_descs_as_dir(now, 20000);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 1);
-
done:
rend_cache_free_all();
}