test_hs_intropoint.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* Copyright (c) 2016, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_hs_service.c
  5. * \brief Test hidden service functionality.
  6. */
  7. #define HS_SERVICE_PRIVATE
  8. #define HS_INTROPOINT_PRIVATE
  9. #define RENDSERVICE_PRIVATE
  10. #define CIRCUITLIST_PRIVATE
  11. #include "test.h"
  12. #include "crypto.h"
  13. #include "or.h"
  14. #include "ht.h"
  15. #include "hs/cell_establish_intro.h"
  16. #include "hs_service.h"
  17. #include "hs_circuitmap.h"
  18. #include "hs_intropoint.h"
  19. #include "circuitlist.h"
  20. #include "circuituse.h"
  21. #include "rendservice.h"
  22. /* Mock function to avoid networking in unittests */
  23. static int
  24. mock_send_intro_established_cell(or_circuit_t *circ)
  25. {
  26. (void) circ;
  27. return 0;
  28. }
  29. /* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro
  30. * point. Should fail. */
  31. static void
  32. test_establish_intro_wrong_purpose(void *arg)
  33. {
  34. int retval;
  35. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  36. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  37. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  38. ssize_t cell_len = 0;
  39. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  40. (void)arg;
  41. /* Get the auth key of the intro point */
  42. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  43. memcpy(intro_circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN);
  44. /* Set a bad circuit purpose!! :) */
  45. circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT);
  46. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  47. attempt to parse it. */
  48. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  49. sizeof(circuit_key_material));
  50. tt_assert(establish_intro_cell);
  51. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  52. establish_intro_cell);
  53. tt_int_op(cell_len, >, 0);
  54. /* Receive the cell */
  55. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  56. tt_int_op(retval, ==, -1);
  57. done:
  58. hs_cell_establish_intro_free(establish_intro_cell);
  59. circuit_free(TO_CIRCUIT(intro_circ));
  60. }
  61. /* Prepare a circuit for accepting an ESTABLISH_INTRO cell */
  62. static void
  63. helper_prepare_circ_for_intro(or_circuit_t *circ,
  64. uint8_t *circuit_key_material)
  65. {
  66. /* Prepare the circuit for the incoming ESTABLISH_INTRO */
  67. circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
  68. memcpy(circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN);
  69. }
  70. /* Send an empty ESTABLISH_INTRO cell. Should fail. */
  71. static void
  72. test_establish_intro_wrong_keytype(void *arg)
  73. {
  74. int retval;
  75. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  76. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  77. (void)arg;
  78. /* Get the auth key of the intro point */
  79. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  80. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  81. /* Receive the cell. Should fail. */
  82. retval = hs_intro_received_establish_intro(intro_circ, (uint8_t*)"", 0);
  83. tt_int_op(retval, ==, -1);
  84. done:
  85. circuit_free(TO_CIRCUIT(intro_circ));
  86. }
  87. /* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */
  88. static void
  89. test_establish_intro_wrong_keytype2(void *arg)
  90. {
  91. int retval;
  92. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  93. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  94. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  95. ssize_t cell_len = 0;
  96. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  97. (void)arg;
  98. /* Get the auth key of the intro point */
  99. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  100. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  101. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  102. attempt to parse it. */
  103. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  104. sizeof(circuit_key_material));
  105. tt_assert(establish_intro_cell);
  106. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  107. establish_intro_cell);
  108. tt_int_op(cell_len, >, 0);
  109. /* Mutate the auth key type! :) */
  110. cell_body[0] = 42;
  111. /* Receive the cell. Should fail. */
  112. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  113. tt_int_op(retval, ==, -1);
  114. done:
  115. hs_cell_establish_intro_free(establish_intro_cell);
  116. circuit_free(TO_CIRCUIT(intro_circ));
  117. }
  118. /* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should
  119. * fail. */
  120. static void
  121. test_establish_intro_wrong_sig(void *arg)
  122. {
  123. int retval;
  124. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  125. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  126. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  127. ssize_t cell_len = 0;
  128. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  129. (void)arg;
  130. /* Get the auth key of the intro point */
  131. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  132. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  133. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  134. attempt to parse it. */
  135. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  136. sizeof(circuit_key_material));
  137. tt_assert(establish_intro_cell);
  138. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  139. establish_intro_cell);
  140. tt_int_op(cell_len, >, 0);
  141. /* Mutate the last byte (signature)! :) */
  142. cell_body[cell_len-1]++;
  143. /* Receive the cell. Should fail. */
  144. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  145. tt_int_op(retval, ==, -1);
  146. done:
  147. hs_cell_establish_intro_free(establish_intro_cell);
  148. circuit_free(TO_CIRCUIT(intro_circ));
  149. }
  150. /* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to
  151. * <b>intro_circ</b>. Return the cell. */
  152. static hs_cell_establish_intro_t *
  153. helper_establish_intro_v3(or_circuit_t *intro_circ)
  154. {
  155. int retval;
  156. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  157. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  158. ssize_t cell_len = 0;
  159. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  160. tt_assert(intro_circ);
  161. /* Prepare the circuit for the incoming ESTABLISH_INTRO */
  162. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  163. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  164. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  165. attempt to parse it. */
  166. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  167. sizeof(circuit_key_material));
  168. tt_assert(establish_intro_cell);
  169. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  170. establish_intro_cell);
  171. tt_int_op(cell_len, >, 0);
  172. /* Receive the cell */
  173. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  174. tt_int_op(retval, ==, 0);
  175. done:
  176. return establish_intro_cell;
  177. }
  178. /* Helper function: Send a well-formed v2 ESTABLISH_INTRO cell to
  179. * <b>intro_circ</b>. Return the public key advertised in the cell. */
  180. static crypto_pk_t *
  181. helper_establish_intro_v2(or_circuit_t *intro_circ)
  182. {
  183. crypto_pk_t *key1 = NULL;
  184. int retval;
  185. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  186. ssize_t cell_len = 0;
  187. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  188. tt_assert(intro_circ);
  189. /* Prepare the circuit for the incoming ESTABLISH_INTRO */
  190. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  191. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  192. /* Send legacy establish_intro */
  193. key1 = pk_generate(0);
  194. /* Use old circuit_key_material why not */
  195. cell_len = encode_establish_intro_cell_legacy((char*)cell_body,
  196. key1,
  197. (char *) circuit_key_material);
  198. tt_int_op(cell_len, >, 0);
  199. /* Receive legacy establish_intro */
  200. retval = hs_intro_received_establish_intro(intro_circ,
  201. cell_body, cell_len);
  202. tt_int_op(retval, ==, 0);
  203. done:
  204. return key1;
  205. }
  206. /** Successfuly register a v2 intro point and a v3 intro point. Ensure that HS
  207. * circuitmap is maintained properly. */
  208. static void
  209. test_intro_point_registration(void *arg)
  210. {
  211. int retval;
  212. hs_circuitmap_ht *the_hs_circuitmap = NULL;
  213. or_circuit_t *intro_circ = NULL;
  214. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  215. ed25519_public_key_t auth_key;
  216. crypto_pk_t *legacy_auth_key = NULL;
  217. or_circuit_t *legacy_intro_circ = NULL;
  218. or_circuit_t *returned_intro_circ = NULL;
  219. (void) arg;
  220. MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);
  221. hs_circuitmap_init();
  222. /* Check that the circuitmap is currently empty */
  223. {
  224. the_hs_circuitmap = get_hs_circuitmap();
  225. tt_assert(the_hs_circuitmap);
  226. tt_int_op(0, ==, HT_SIZE(the_hs_circuitmap));
  227. /* Do a circuitmap query in any case */
  228. returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key);
  229. tt_ptr_op(returned_intro_circ, ==, NULL);
  230. }
  231. /* Create a v3 intro point */
  232. {
  233. intro_circ = or_circuit_new(0, NULL);
  234. tt_assert(intro_circ);
  235. establish_intro_cell = helper_establish_intro_v3(intro_circ);
  236. /* Check that the intro point was registered on the HS circuitmap */
  237. the_hs_circuitmap = get_hs_circuitmap();
  238. tt_assert(the_hs_circuitmap);
  239. tt_int_op(1, ==, HT_SIZE(the_hs_circuitmap));
  240. get_auth_key_from_establish_intro_cell(&auth_key, establish_intro_cell);
  241. returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key);
  242. tt_ptr_op(intro_circ, ==, returned_intro_circ);
  243. }
  244. /* Create a v2 intro point */
  245. {
  246. char key_digest[DIGEST_LEN];
  247. legacy_intro_circ = or_circuit_new(1, NULL);
  248. tt_assert(legacy_intro_circ);
  249. legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ);
  250. tt_assert(legacy_auth_key);
  251. /* Check that the circuitmap now has two elements */
  252. the_hs_circuitmap = get_hs_circuitmap();
  253. tt_assert(the_hs_circuitmap);
  254. tt_int_op(2, ==, HT_SIZE(the_hs_circuitmap));
  255. /* Check that the new element is our legacy intro circuit. */
  256. retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
  257. tt_int_op(retval, ==, 0);
  258. returned_intro_circ= hs_circuitmap_get_intro_circ_v2((uint8_t*)key_digest);
  259. tt_ptr_op(legacy_intro_circ, ==, returned_intro_circ);
  260. }
  261. /* XXX Continue test and try to register a second v3 intro point with the
  262. * same auth key. Make sure that old intro circuit gets closed. */
  263. done:
  264. crypto_pk_free(legacy_auth_key);
  265. circuit_free(TO_CIRCUIT(intro_circ));
  266. circuit_free(TO_CIRCUIT(legacy_intro_circ));
  267. hs_cell_establish_intro_free(establish_intro_cell);
  268. { /* Test circuitmap free_all function. */
  269. the_hs_circuitmap = get_hs_circuitmap();
  270. tt_assert(the_hs_circuitmap);
  271. hs_circuitmap_free_all();
  272. the_hs_circuitmap = get_hs_circuitmap();
  273. tt_assert(!the_hs_circuitmap);
  274. }
  275. UNMOCK(hs_intro_send_intro_established_cell);
  276. }
  277. struct testcase_t hs_intropoint_tests[] = {
  278. { "intro_point_registration",
  279. test_intro_point_registration, TT_FORK, NULL, NULL },
  280. { "receive_establish_intro_wrong_keytype",
  281. test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL },
  282. { "receive_establish_intro_wrong_keytype2",
  283. test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL },
  284. { "receive_establish_intro_wrong_purpose",
  285. test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL },
  286. { "receive_establish_intro_wrong_sig",
  287. test_establish_intro_wrong_sig, TT_FORK, NULL, NULL },
  288. END_OF_TESTCASES
  289. };