test_hs_cache.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /* Copyright (c) 2016, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_hs_cache.c
  5. * \brief Test hidden service caches.
  6. */
  7. #define HS_CACHE_PRIVATE
  8. #include "ed25519_cert.h"
  9. #include "hs_cache.h"
  10. #include "rendcache.h"
  11. #include "test.h"
  12. /* Build an intro point using a blinded key and an address. */
  13. static hs_desc_intro_point_t *
  14. helper_build_intro_point(const ed25519_keypair_t *blinded_kp,
  15. const char *addr)
  16. {
  17. int ret;
  18. ed25519_keypair_t auth_kp;
  19. hs_desc_intro_point_t *intro_point = NULL;
  20. hs_desc_intro_point_t *ip = tor_malloc_zero(sizeof(*ip));
  21. ip->link_specifiers = smartlist_new();
  22. {
  23. hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls));
  24. ls->u.ap.port = 9001;
  25. int family = tor_addr_parse(&ls->u.ap.addr, addr);
  26. switch (family) {
  27. case AF_INET:
  28. ls->type = LS_IPV4;
  29. break;
  30. case AF_INET6:
  31. ls->type = LS_IPV6;
  32. break;
  33. default:
  34. /* Stop the test, not suppose to have an error. */
  35. tt_int_op(family, OP_EQ, AF_INET);
  36. }
  37. smartlist_add(ip->link_specifiers, ls);
  38. }
  39. ret = ed25519_keypair_generate(&auth_kp, 0);
  40. tt_int_op(ret, ==, 0);
  41. ip->auth_key_cert = tor_cert_create(blinded_kp, CERT_TYPE_HS_IP_AUTH,
  42. &auth_kp.pubkey, time(NULL),
  43. HS_DESC_CERT_LIFETIME,
  44. CERT_FLAG_INCLUDE_SIGNING_KEY);
  45. tt_assert(ip->auth_key_cert);
  46. ret = curve25519_keypair_generate(&ip->enc_key.curve25519, 0);
  47. tt_int_op(ret, ==, 0);
  48. ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519;
  49. intro_point = ip;
  50. done:
  51. return intro_point;
  52. }
  53. /* Return a valid hs_descriptor_t object. */
  54. static hs_descriptor_t *
  55. helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime,
  56. ed25519_keypair_t *blinded_kp)
  57. {
  58. int ret;
  59. hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));
  60. desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;
  61. ret = ed25519_keypair_generate(&desc->plaintext_data.signing_kp, 0);
  62. tt_int_op(ret, ==, 0);
  63. if (blinded_kp) {
  64. memcpy(&desc->plaintext_data.blinded_kp, blinded_kp,
  65. sizeof(ed25519_keypair_t));
  66. } else {
  67. ret = ed25519_keypair_generate(&desc->plaintext_data.blinded_kp, 0);
  68. tt_int_op(ret, ==, 0);
  69. }
  70. desc->plaintext_data.signing_key_cert =
  71. tor_cert_create(&desc->plaintext_data.blinded_kp,
  72. CERT_TYPE_HS_DESC_SIGN,
  73. &desc->plaintext_data.signing_kp.pubkey, time(NULL),
  74. 3600, CERT_FLAG_INCLUDE_SIGNING_KEY);
  75. tt_assert(desc->plaintext_data.signing_key_cert);
  76. desc->plaintext_data.revision_counter = revision_counter;
  77. desc->plaintext_data.lifetime_sec = lifetime;
  78. /* Setup encrypted data section. */
  79. desc->encrypted_data.create2_ntor = 1;
  80. desc->encrypted_data.auth_types = smartlist_new();
  81. smartlist_add(desc->encrypted_data.auth_types, strdup("ed25519"));
  82. desc->encrypted_data.intro_points = smartlist_new();
  83. /* Add an intro point. */
  84. smartlist_add(desc->encrypted_data.intro_points,
  85. helper_build_intro_point(&desc->plaintext_data.blinded_kp,
  86. "1.2.3.4"));
  87. descp = desc;
  88. done:
  89. return descp;
  90. }
  91. /* Static variable used to encoded the HSDir query. */
  92. static char query_b64[256];
  93. /* Build an HSDir query using a ed25519 keypair. */
  94. static const char *
  95. helper_get_hsdir_query(const hs_descriptor_t *desc)
  96. {
  97. ed25519_public_to_base64(query_b64,
  98. &desc->plaintext_data.blinded_kp.pubkey);
  99. return query_b64;
  100. }
  101. static void
  102. init_test(void)
  103. {
  104. /* Always needed. Initialize the subsystem. */
  105. hs_cache_init();
  106. /* We need the v2 cache since our OOM and cache cleanup does poke at it. */
  107. rend_cache_init();
  108. }
  109. static void
  110. test_directory(void *arg)
  111. {
  112. int ret;
  113. size_t oom_size;
  114. char *desc_out, *desc1_str;
  115. hs_descriptor_t *desc1;
  116. (void) arg;
  117. init_test();
  118. /* Generate a valid descriptor with normal values. */
  119. desc1 = helper_build_hs_desc(42, 3 * 60 * 60, NULL);
  120. tt_assert(desc1);
  121. ret = hs_desc_encode_descriptor(desc1, &desc1_str);
  122. tt_int_op(ret, OP_EQ, 0);
  123. /* Very first basic test, should be able to be stored, survive a
  124. * clean, found with a lookup and then cleaned by our OOM. */
  125. {
  126. ret = hs_cache_store_as_dir(desc1_str);
  127. tt_int_op(ret, OP_EQ, 0);
  128. /* Re-add, it should fail since we already have it. */
  129. ret = hs_cache_store_as_dir(desc1_str);
  130. tt_int_op(ret, OP_EQ, -1);
  131. /* Try to clean now which should be fine, there is at worst few seconds
  132. * between the store and this call. */
  133. hs_cache_clean_as_dir(time(NULL));
  134. /* We should find it in our cache. */
  135. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
  136. tt_int_op(ret, OP_EQ, 1);
  137. tt_str_op(desc_out, OP_EQ, desc1_str);
  138. tor_free(desc_out);
  139. /* Tell our OOM to run and to at least remove a byte which will result in
  140. * removing the descriptor from our cache. */
  141. oom_size = hs_cache_handle_oom(time(NULL), 1);
  142. tt_int_op(oom_size, >=, 1);
  143. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
  144. tt_int_op(ret, OP_EQ, 0);
  145. }
  146. /* Store two descriptors and remove the expiring one only. */
  147. {
  148. hs_descriptor_t *desc_zero_lifetime = helper_build_hs_desc(1, 0, NULL);
  149. tt_assert(desc_zero_lifetime);
  150. char *desc_zero_lifetime_str;
  151. ret = hs_desc_encode_descriptor(desc_zero_lifetime,
  152. &desc_zero_lifetime_str);
  153. tt_int_op(ret, OP_EQ, 0);
  154. ret = hs_cache_store_as_dir(desc1_str);
  155. tt_int_op(ret, OP_EQ, 0);
  156. ret = hs_cache_store_as_dir(desc_zero_lifetime_str);
  157. tt_int_op(ret, OP_EQ, 0);
  158. /* This one should clear out our zero lifetime desc. */
  159. hs_cache_clean_as_dir(time(NULL));
  160. /* We should find desc1 in our cache. */
  161. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
  162. tt_int_op(ret, OP_EQ, 1);
  163. tt_str_op(desc_out, OP_EQ, desc1_str);
  164. tor_free(desc_out);
  165. /* We should NOT find our zero lifetime desc in our cache. */
  166. ret = hs_cache_lookup_as_dir(3,
  167. helper_get_hsdir_query(desc_zero_lifetime),
  168. NULL);
  169. tt_int_op(ret, OP_EQ, 0);
  170. /* Cleanup our entire cache. */
  171. oom_size = hs_cache_handle_oom(time(NULL), 1);
  172. tt_int_op(oom_size, >=, 1);
  173. }
  174. /* Throw junk at it. */
  175. {
  176. ret = hs_cache_store_as_dir("blah");
  177. tt_int_op(ret, OP_EQ, -1);
  178. /* Poor attempt at tricking the decoding. */
  179. ret = hs_cache_store_as_dir("hs-descriptor 3\nJUNK");
  180. tt_int_op(ret, OP_EQ, -1);
  181. /* Undecodable base64 query. */
  182. ret = hs_cache_lookup_as_dir(3, "blah", NULL);
  183. tt_int_op(ret, OP_EQ, -1);
  184. /* Decodable base64 query but wrong ed25519 size. */
  185. ret = hs_cache_lookup_as_dir(3, "dW5pY29ybg==", NULL);
  186. tt_int_op(ret, OP_EQ, -1);
  187. }
  188. /* Test descriptor replacement with revision counter. */
  189. {
  190. char *new_desc_str;
  191. /* Add a descriptor. */
  192. ret = hs_cache_store_as_dir(desc1_str);
  193. tt_int_op(ret, OP_EQ, 0);
  194. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
  195. tt_int_op(ret, OP_EQ, 1);
  196. tor_free(desc_out);
  197. /* Bump revision counter. */
  198. desc1->plaintext_data.revision_counter++;
  199. ret = hs_desc_encode_descriptor(desc1, &new_desc_str);
  200. tt_int_op(ret, OP_EQ, 0);
  201. ret = hs_cache_store_as_dir(new_desc_str);
  202. tt_int_op(ret, OP_EQ, 0);
  203. /* Look it up, it should have been replaced. */
  204. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
  205. tt_int_op(ret, OP_EQ, 1);
  206. tt_str_op(desc_out, OP_EQ, new_desc_str);
  207. tor_free(desc_out);
  208. tor_free(new_desc_str);
  209. }
  210. done:
  211. ;
  212. }
  213. static void
  214. test_clean_as_dir(void *arg)
  215. {
  216. size_t ret;
  217. char *desc1_str = NULL;
  218. time_t now = time(NULL);
  219. hs_descriptor_t *desc1 = NULL;
  220. (void) arg;
  221. init_test();
  222. /* Generate a valid descriptor with values. */
  223. desc1 = helper_build_hs_desc(42, 3 * 60 * 60, NULL);
  224. tt_assert(desc1);
  225. ret = hs_desc_encode_descriptor(desc1, &desc1_str);
  226. tt_int_op(ret, OP_EQ, 0);
  227. ret = hs_cache_store_as_dir(desc1_str);
  228. tt_int_op(ret, OP_EQ, 0);
  229. /* With the lifetime being 3 hours, a cleanup shouldn't remove it. */
  230. ret = cache_clean_v3_as_dir(now, 0);
  231. tt_int_op(ret, ==, 0);
  232. /* Should be present after clean up. */
  233. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
  234. tt_int_op(ret, OP_EQ, 1);
  235. /* Set a cutoff 100 seconds in the past. It should not remove the entry
  236. * since the entry is still recent enough. */
  237. ret = cache_clean_v3_as_dir(now, now - 100);
  238. tt_int_op(ret, ==, 0);
  239. /* Should be present after clean up. */
  240. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
  241. tt_int_op(ret, OP_EQ, 1);
  242. /* Set a cutoff of 100 seconds in the future. It should remove the entry
  243. * that we've just added since it's not too old for the cutoff. */
  244. ret = cache_clean_v3_as_dir(now, now + 100);
  245. tt_int_op(ret, >, 0);
  246. /* Shouldn't be present after clean up. */
  247. ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
  248. tt_int_op(ret, OP_EQ, 0);
  249. done:
  250. hs_descriptor_free(desc1);
  251. tor_free(desc1_str);
  252. }
  253. struct testcase_t hs_cache[] = {
  254. /* Encoding tests. */
  255. { "directory", test_directory, TT_FORK,
  256. NULL, NULL },
  257. { "clean_as_dir", test_clean_as_dir, TT_FORK,
  258. NULL, NULL },
  259. END_OF_TESTCASES
  260. };