|
@@ -0,0 +1,293 @@
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ * \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 "test.h"
|
|
|
+
|
|
|
+
|
|
|
+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:
|
|
|
+
|
|
|
+ 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_HS_IP_AUTH,
|
|
|
+ &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;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+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_HS_DESC_SIGN,
|
|
|
+ &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;
|
|
|
+
|
|
|
+
|
|
|
+ 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();
|
|
|
+
|
|
|
+ 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 char query_b64[256];
|
|
|
+
|
|
|
+
|
|
|
+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)
|
|
|
+{
|
|
|
+
|
|
|
+ hs_cache_init();
|
|
|
+
|
|
|
+ rend_cache_init();
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+test_directory(void *arg)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ size_t oom_size;
|
|
|
+ char *desc_out, *desc1_str;
|
|
|
+ hs_descriptor_t *desc1;
|
|
|
+
|
|
|
+ (void) arg;
|
|
|
+
|
|
|
+ init_test();
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+
|
|
|
+ * 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);
|
|
|
+
|
|
|
+ ret = hs_cache_store_as_dir(desc1_str);
|
|
|
+ tt_int_op(ret, OP_EQ, -1);
|
|
|
+
|
|
|
+ * between the store and this call. */
|
|
|
+ hs_cache_clean_as_dir(time(NULL));
|
|
|
+
|
|
|
+ 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);
|
|
|
+ tor_free(desc_out);
|
|
|
+
|
|
|
+ * 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);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ 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);
|
|
|
+
|
|
|
+ hs_cache_clean_as_dir(time(NULL));
|
|
|
+
|
|
|
+ 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);
|
|
|
+ tor_free(desc_out);
|
|
|
+
|
|
|
+ ret = hs_cache_lookup_as_dir(3,
|
|
|
+ helper_get_hsdir_query(desc_zero_lifetime),
|
|
|
+ NULL);
|
|
|
+ tt_int_op(ret, OP_EQ, 0);
|
|
|
+
|
|
|
+ oom_size = hs_cache_handle_oom(time(NULL), 1);
|
|
|
+ tt_int_op(oom_size, >=, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ ret = hs_cache_store_as_dir("blah");
|
|
|
+ tt_int_op(ret, OP_EQ, -1);
|
|
|
+
|
|
|
+ ret = hs_cache_store_as_dir("hs-descriptor 3\nJUNK");
|
|
|
+ tt_int_op(ret, OP_EQ, -1);
|
|
|
+
|
|
|
+ ret = hs_cache_lookup_as_dir(3, "blah", NULL);
|
|
|
+ tt_int_op(ret, OP_EQ, -1);
|
|
|
+
|
|
|
+ ret = hs_cache_lookup_as_dir(3, "dW5pY29ybg==", NULL);
|
|
|
+ tt_int_op(ret, OP_EQ, -1);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ char *new_desc_str;
|
|
|
+
|
|
|
+
|
|
|
+ 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);
|
|
|
+ tor_free(desc_out);
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ 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(desc_out);
|
|
|
+ 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();
|
|
|
+
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+
|
|
|
+ ret = cache_clean_v3_as_dir(now, 0);
|
|
|
+ tt_int_op(ret, ==, 0);
|
|
|
+
|
|
|
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
|
|
|
+ tt_int_op(ret, OP_EQ, 1);
|
|
|
+
|
|
|
+ * since the entry is still recent enough. */
|
|
|
+ ret = cache_clean_v3_as_dir(now, now - 100);
|
|
|
+ tt_int_op(ret, ==, 0);
|
|
|
+
|
|
|
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
|
|
|
+ tt_int_op(ret, OP_EQ, 1);
|
|
|
+
|
|
|
+ * 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);
|
|
|
+
|
|
|
+ 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);
|
|
|
+}
|
|
|
+
|
|
|
+struct testcase_t hs_cache[] = {
|
|
|
+
|
|
|
+ { "directory", test_directory, TT_FORK,
|
|
|
+ NULL, NULL },
|
|
|
+ { "clean_as_dir", test_clean_as_dir, TT_FORK,
|
|
|
+ NULL, NULL },
|
|
|
+
|
|
|
+ END_OF_TESTCASES
|
|
|
+};
|