test_hs_intropoint.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  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 "log_test_helpers.h"
  13. #include "crypto.h"
  14. #include "or.h"
  15. #include "ht.h"
  16. #include "hs/cell_establish_intro.h"
  17. #include "hs_common.h"
  18. #include "hs_service.h"
  19. #include "hs_circuitmap.h"
  20. #include "hs_intropoint.h"
  21. #include "circuitlist.h"
  22. #include "circuituse.h"
  23. #include "rendservice.h"
  24. /* Mock function to avoid networking in unittests */
  25. static int
  26. mock_send_intro_established_cell(or_circuit_t *circ)
  27. {
  28. (void) circ;
  29. return 0;
  30. }
  31. /* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro
  32. * point. Should fail. */
  33. static void
  34. test_establish_intro_wrong_purpose(void *arg)
  35. {
  36. int retval;
  37. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  38. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  39. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  40. ssize_t cell_len = 0;
  41. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  42. (void)arg;
  43. /* Get the auth key of the intro point */
  44. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  45. memcpy(intro_circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN);
  46. /* Set a bad circuit purpose!! :) */
  47. circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT);
  48. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  49. attempt to parse it. */
  50. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  51. sizeof(circuit_key_material));
  52. tt_assert(establish_intro_cell);
  53. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  54. establish_intro_cell);
  55. tt_int_op(cell_len, >, 0);
  56. /* Receive the cell */
  57. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  58. tt_int_op(retval, ==, -1);
  59. done:
  60. hs_cell_establish_intro_free(establish_intro_cell);
  61. circuit_free(TO_CIRCUIT(intro_circ));
  62. }
  63. /* Prepare a circuit for accepting an ESTABLISH_INTRO cell */
  64. static void
  65. helper_prepare_circ_for_intro(or_circuit_t *circ,
  66. uint8_t *circuit_key_material)
  67. {
  68. /* Prepare the circuit for the incoming ESTABLISH_INTRO */
  69. circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
  70. memcpy(circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN);
  71. }
  72. /* Send an empty ESTABLISH_INTRO cell. Should fail. */
  73. static void
  74. test_establish_intro_wrong_keytype(void *arg)
  75. {
  76. int retval;
  77. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  78. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  79. (void)arg;
  80. /* Get the auth key of the intro point */
  81. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  82. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  83. /* Receive the cell. Should fail. */
  84. retval = hs_intro_received_establish_intro(intro_circ, (uint8_t*)"", 0);
  85. tt_int_op(retval, ==, -1);
  86. done:
  87. circuit_free(TO_CIRCUIT(intro_circ));
  88. }
  89. /* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */
  90. static void
  91. test_establish_intro_wrong_keytype2(void *arg)
  92. {
  93. int retval;
  94. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  95. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  96. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  97. ssize_t cell_len = 0;
  98. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  99. (void)arg;
  100. /* Get the auth key of the intro point */
  101. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  102. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  103. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  104. attempt to parse it. */
  105. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  106. sizeof(circuit_key_material));
  107. tt_assert(establish_intro_cell);
  108. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  109. establish_intro_cell);
  110. tt_int_op(cell_len, >, 0);
  111. /* Mutate the auth key type! :) */
  112. cell_body[0] = 42;
  113. /* Receive the cell. Should fail. */
  114. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  115. tt_int_op(retval, ==, -1);
  116. done:
  117. hs_cell_establish_intro_free(establish_intro_cell);
  118. circuit_free(TO_CIRCUIT(intro_circ));
  119. }
  120. /* Send a legit ESTABLISH_INTRO cell but with a wrong MAC. Should fail. */
  121. static void
  122. test_establish_intro_wrong_mac(void *arg)
  123. {
  124. int retval;
  125. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  126. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  127. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  128. ssize_t cell_len = 0;
  129. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  130. (void)arg;
  131. /* Get the auth key of the intro point */
  132. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  133. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  134. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  135. attempt to parse it. */
  136. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  137. sizeof(circuit_key_material));
  138. tt_assert(establish_intro_cell);
  139. /* Mangle one byte of the MAC. */
  140. uint8_t *handshake_ptr =
  141. hs_cell_establish_intro_getarray_handshake_mac(establish_intro_cell);
  142. handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++;
  143. /* We need to resign the payload with that change. */
  144. {
  145. ed25519_signature_t sig;
  146. ed25519_keypair_t key_struct;
  147. /* New keypair for the signature since we don't have access to the private
  148. * key material generated earlier when creating the cell. */
  149. retval = ed25519_keypair_generate(&key_struct, 0);
  150. tt_int_op(retval, OP_EQ, 0);
  151. uint8_t *auth_key_ptr =
  152. hs_cell_establish_intro_getarray_auth_key(establish_intro_cell);
  153. memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN);
  154. /* Encode payload so we can sign it. */
  155. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  156. establish_intro_cell);
  157. tt_int_op(cell_len, >, 0);
  158. retval = ed25519_sign_prefixed(&sig, cell_body,
  159. cell_len -
  160. (ED25519_SIG_LEN +
  161. sizeof(establish_intro_cell->sig_len)),
  162. ESTABLISH_INTRO_SIG_PREFIX, &key_struct);
  163. tt_int_op(retval, OP_EQ, 0);
  164. /* And write the signature to the cell */
  165. uint8_t *sig_ptr =
  166. hs_cell_establish_intro_getarray_sig(establish_intro_cell);
  167. memcpy(sig_ptr, sig.sig, establish_intro_cell->sig_len);
  168. /* Re-encode with the new signature. */
  169. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  170. establish_intro_cell);
  171. }
  172. /* Receive the cell. Should fail because our MAC is wrong. */
  173. setup_full_capture_of_logs(LOG_INFO);
  174. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  175. expect_log_msg_containing("ESTABLISH_INTRO handshake_auth not as expected");
  176. teardown_capture_of_logs();
  177. tt_int_op(retval, ==, -1);
  178. done:
  179. hs_cell_establish_intro_free(establish_intro_cell);
  180. circuit_free(TO_CIRCUIT(intro_circ));
  181. }
  182. /* Send a legit ESTABLISH_INTRO cell but with a wrong auth key length. Should
  183. * fail. */
  184. static void
  185. test_establish_intro_wrong_auth_key_len(void *arg)
  186. {
  187. int retval;
  188. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  189. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  190. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  191. ssize_t cell_len = 0;
  192. size_t bad_auth_key_len = ED25519_PUBKEY_LEN - 1;
  193. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  194. (void)arg;
  195. /* Get the auth key of the intro point */
  196. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  197. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  198. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  199. attempt to parse it. */
  200. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  201. sizeof(circuit_key_material));
  202. tt_assert(establish_intro_cell);
  203. /* Mangle the auth key length. */
  204. hs_cell_establish_intro_set_auth_key_len(establish_intro_cell,
  205. bad_auth_key_len);
  206. hs_cell_establish_intro_setlen_auth_key(establish_intro_cell,
  207. bad_auth_key_len);
  208. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  209. establish_intro_cell);
  210. tt_int_op(cell_len, >, 0);
  211. /* Receive the cell. Should fail. */
  212. setup_full_capture_of_logs(LOG_INFO);
  213. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  214. expect_log_msg_containing("ESTABLISH_INTRO auth key length is invalid");
  215. teardown_capture_of_logs();
  216. tt_int_op(retval, ==, -1);
  217. done:
  218. hs_cell_establish_intro_free(establish_intro_cell);
  219. circuit_free(TO_CIRCUIT(intro_circ));
  220. }
  221. /* Send a legit ESTABLISH_INTRO cell but with a wrong sig length. Should
  222. * fail. */
  223. static void
  224. test_establish_intro_wrong_sig_len(void *arg)
  225. {
  226. int retval;
  227. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  228. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  229. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  230. ssize_t cell_len = 0;
  231. size_t bad_sig_len = ED25519_SIG_LEN - 1;
  232. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  233. (void)arg;
  234. /* Get the auth key of the intro point */
  235. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  236. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  237. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  238. attempt to parse it. */
  239. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  240. sizeof(circuit_key_material));
  241. tt_assert(establish_intro_cell);
  242. /* Mangle the signature length. */
  243. hs_cell_establish_intro_set_sig_len(establish_intro_cell, bad_sig_len);
  244. hs_cell_establish_intro_setlen_sig(establish_intro_cell, bad_sig_len);
  245. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  246. establish_intro_cell);
  247. tt_int_op(cell_len, >, 0);
  248. /* Receive the cell. Should fail. */
  249. setup_full_capture_of_logs(LOG_INFO);
  250. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  251. expect_log_msg_containing("ESTABLISH_INTRO sig len is invalid");
  252. teardown_capture_of_logs();
  253. tt_int_op(retval, ==, -1);
  254. done:
  255. hs_cell_establish_intro_free(establish_intro_cell);
  256. circuit_free(TO_CIRCUIT(intro_circ));
  257. }
  258. /* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should
  259. * fail. */
  260. static void
  261. test_establish_intro_wrong_sig(void *arg)
  262. {
  263. int retval;
  264. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  265. or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
  266. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  267. ssize_t cell_len = 0;
  268. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  269. (void)arg;
  270. /* Get the auth key of the intro point */
  271. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  272. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  273. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  274. attempt to parse it. */
  275. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  276. sizeof(circuit_key_material));
  277. tt_assert(establish_intro_cell);
  278. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  279. establish_intro_cell);
  280. tt_int_op(cell_len, >, 0);
  281. /* Mutate the last byte (signature)! :) */
  282. cell_body[cell_len-1]++;
  283. /* Receive the cell. Should fail. */
  284. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  285. tt_int_op(retval, ==, -1);
  286. done:
  287. hs_cell_establish_intro_free(establish_intro_cell);
  288. circuit_free(TO_CIRCUIT(intro_circ));
  289. }
  290. /* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to
  291. * <b>intro_circ</b>. Return the cell. */
  292. static hs_cell_establish_intro_t *
  293. helper_establish_intro_v3(or_circuit_t *intro_circ)
  294. {
  295. int retval;
  296. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  297. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  298. ssize_t cell_len = 0;
  299. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  300. tt_assert(intro_circ);
  301. /* Prepare the circuit for the incoming ESTABLISH_INTRO */
  302. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  303. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  304. /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
  305. attempt to parse it. */
  306. establish_intro_cell = generate_establish_intro_cell(circuit_key_material,
  307. sizeof(circuit_key_material));
  308. tt_assert(establish_intro_cell);
  309. cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
  310. establish_intro_cell);
  311. tt_int_op(cell_len, >, 0);
  312. /* Receive the cell */
  313. retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
  314. tt_int_op(retval, ==, 0);
  315. done:
  316. return establish_intro_cell;
  317. }
  318. /* Helper function: Send a well-formed v2 ESTABLISH_INTRO cell to
  319. * <b>intro_circ</b>. Return the public key advertised in the cell. */
  320. static crypto_pk_t *
  321. helper_establish_intro_v2(or_circuit_t *intro_circ)
  322. {
  323. crypto_pk_t *key1 = NULL;
  324. int retval;
  325. uint8_t cell_body[RELAY_PAYLOAD_SIZE];
  326. ssize_t cell_len = 0;
  327. uint8_t circuit_key_material[DIGEST_LEN] = {0};
  328. tt_assert(intro_circ);
  329. /* Prepare the circuit for the incoming ESTABLISH_INTRO */
  330. crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
  331. helper_prepare_circ_for_intro(intro_circ, circuit_key_material);
  332. /* Send legacy establish_intro */
  333. key1 = pk_generate(0);
  334. /* Use old circuit_key_material why not */
  335. cell_len = encode_establish_intro_cell_legacy((char*)cell_body,
  336. key1,
  337. (char *) circuit_key_material);
  338. tt_int_op(cell_len, >, 0);
  339. /* Receive legacy establish_intro */
  340. retval = hs_intro_received_establish_intro(intro_circ,
  341. cell_body, cell_len);
  342. tt_int_op(retval, ==, 0);
  343. done:
  344. return key1;
  345. }
  346. /** Successfuly register a v2 intro point and a v3 intro point. Ensure that HS
  347. * circuitmap is maintained properly. */
  348. static void
  349. test_intro_point_registration(void *arg)
  350. {
  351. int retval;
  352. hs_circuitmap_ht *the_hs_circuitmap = NULL;
  353. or_circuit_t *intro_circ = NULL;
  354. hs_cell_establish_intro_t *establish_intro_cell = NULL;
  355. ed25519_public_key_t auth_key;
  356. crypto_pk_t *legacy_auth_key = NULL;
  357. or_circuit_t *legacy_intro_circ = NULL;
  358. or_circuit_t *returned_intro_circ = NULL;
  359. (void) arg;
  360. MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);
  361. hs_circuitmap_init();
  362. /* Check that the circuitmap is currently empty */
  363. {
  364. the_hs_circuitmap = get_hs_circuitmap();
  365. tt_assert(the_hs_circuitmap);
  366. tt_int_op(0, ==, HT_SIZE(the_hs_circuitmap));
  367. /* Do a circuitmap query in any case */
  368. returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key);
  369. tt_ptr_op(returned_intro_circ, ==, NULL);
  370. }
  371. /* Create a v3 intro point */
  372. {
  373. intro_circ = or_circuit_new(0, NULL);
  374. tt_assert(intro_circ);
  375. establish_intro_cell = helper_establish_intro_v3(intro_circ);
  376. /* Check that the intro point was registered on the HS circuitmap */
  377. the_hs_circuitmap = get_hs_circuitmap();
  378. tt_assert(the_hs_circuitmap);
  379. tt_int_op(1, ==, HT_SIZE(the_hs_circuitmap));
  380. get_auth_key_from_establish_intro_cell(&auth_key, establish_intro_cell);
  381. returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key);
  382. tt_ptr_op(intro_circ, ==, returned_intro_circ);
  383. }
  384. /* Create a v2 intro point */
  385. {
  386. char key_digest[DIGEST_LEN];
  387. legacy_intro_circ = or_circuit_new(1, NULL);
  388. tt_assert(legacy_intro_circ);
  389. legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ);
  390. tt_assert(legacy_auth_key);
  391. /* Check that the circuitmap now has two elements */
  392. the_hs_circuitmap = get_hs_circuitmap();
  393. tt_assert(the_hs_circuitmap);
  394. tt_int_op(2, ==, HT_SIZE(the_hs_circuitmap));
  395. /* Check that the new element is our legacy intro circuit. */
  396. retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
  397. tt_int_op(retval, ==, 0);
  398. returned_intro_circ= hs_circuitmap_get_intro_circ_v2((uint8_t*)key_digest);
  399. tt_ptr_op(legacy_intro_circ, ==, returned_intro_circ);
  400. }
  401. /* XXX Continue test and try to register a second v3 intro point with the
  402. * same auth key. Make sure that old intro circuit gets closed. */
  403. done:
  404. crypto_pk_free(legacy_auth_key);
  405. circuit_free(TO_CIRCUIT(intro_circ));
  406. circuit_free(TO_CIRCUIT(legacy_intro_circ));
  407. hs_cell_establish_intro_free(establish_intro_cell);
  408. { /* Test circuitmap free_all function. */
  409. the_hs_circuitmap = get_hs_circuitmap();
  410. tt_assert(the_hs_circuitmap);
  411. hs_circuitmap_free_all();
  412. the_hs_circuitmap = get_hs_circuitmap();
  413. tt_assert(!the_hs_circuitmap);
  414. }
  415. UNMOCK(hs_intro_send_intro_established_cell);
  416. }
  417. struct testcase_t hs_intropoint_tests[] = {
  418. { "intro_point_registration",
  419. test_intro_point_registration, TT_FORK, NULL, NULL },
  420. { "receive_establish_intro_wrong_keytype",
  421. test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL },
  422. { "receive_establish_intro_wrong_keytype2",
  423. test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL },
  424. { "receive_establish_intro_wrong_purpose",
  425. test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL },
  426. { "receive_establish_intro_wrong_sig",
  427. test_establish_intro_wrong_sig, TT_FORK, NULL, NULL },
  428. { "receive_establish_intro_wrong_sig_len",
  429. test_establish_intro_wrong_sig_len, TT_FORK, NULL, NULL },
  430. { "receive_establish_intro_wrong_auth_key_len",
  431. test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, NULL },
  432. { "receive_establish_intro_wrong_mac",
  433. test_establish_intro_wrong_mac, TT_FORK, NULL, NULL },
  434. END_OF_TESTCASES
  435. };