test_hs_client.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /* Copyright (c) 2016-2017, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_hs_client.c
  5. * \brief Test prop224 HS client functionality.
  6. */
  7. #define CRYPTO_PRIVATE
  8. #define MAIN_PRIVATE
  9. #define TOR_CHANNEL_INTERNAL_
  10. #define CIRCUITBUILD_PRIVATE
  11. #define CIRCUITLIST_PRIVATE
  12. #define CONNECTION_PRIVATE
  13. #include "test.h"
  14. #include "test_helpers.h"
  15. #include "log_test_helpers.h"
  16. #include "rend_test_helpers.h"
  17. #include "config.h"
  18. #include "crypto.h"
  19. #include "channeltls.h"
  20. #include "hs_circuit.h"
  21. #include "hs_ident.h"
  22. #include "circuitlist.h"
  23. #include "circuitbuild.h"
  24. #include "connection.h"
  25. #include "connection_edge.h"
  26. static int
  27. mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
  28. {
  29. (void) ap_conn;
  30. return 0;
  31. }
  32. /* Test helper function: Setup a circuit and a stream with the same hidden
  33. * service destination, and put them in <b>circ_out</b> and
  34. * <b>conn_out</b>. Make the stream wait for circuits to be established to the
  35. * hidden service. */
  36. static int
  37. helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
  38. connection_t **conn_out,
  39. int is_legacy)
  40. {
  41. int retval;
  42. channel_tls_t *n_chan=NULL;
  43. rend_data_t *conn_rend_data = NULL;
  44. origin_circuit_t *or_circ = NULL;
  45. connection_t *conn = NULL;
  46. ed25519_public_key_t service_pk;
  47. /* Make a dummy connection stream and make it wait for our circuit */
  48. conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT,
  49. CONN_TYPE_AP /* ??? */,
  50. 0);
  51. if (is_legacy) {
  52. /* Legacy: Setup rend_data of stream */
  53. char service_id[REND_SERVICE_ID_LEN_BASE32+1] = {0};
  54. TO_EDGE_CONN(conn)->rend_data = mock_rend_data(service_id);
  55. conn_rend_data = TO_EDGE_CONN(conn)->rend_data;
  56. } else {
  57. /* prop224: Setup hs conn identifier on the stream */
  58. ed25519_secret_key_t sk;
  59. tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
  60. tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
  61. /* Setup hs_conn_identifier of stream */
  62. TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk);
  63. }
  64. /* Make it wait for circuit */
  65. connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn));
  66. /* This is needed to silence a BUG warning from
  67. connection_edge_update_circuit_isolation() */
  68. TO_ENTRY_CONN(conn)->original_dest_address =
  69. tor_strdup(TO_ENTRY_CONN(conn)->socks_request->address);
  70. /****************************************************/
  71. /* Now make dummy circuit */
  72. or_circ = origin_circuit_new();
  73. or_circ->base_.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
  74. or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
  75. or_circ->build_state->is_internal = 1;
  76. if (is_legacy) {
  77. /* Legacy: Setup rend data and final cpath */
  78. or_circ->build_state->pending_final_cpath =
  79. tor_malloc_zero(sizeof(crypt_path_t));
  80. or_circ->build_state->pending_final_cpath->magic = CRYPT_PATH_MAGIC;
  81. or_circ->build_state->pending_final_cpath->rend_dh_handshake_state =
  82. crypto_dh_new(DH_TYPE_REND);
  83. tt_assert(
  84. or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
  85. retval = crypto_dh_generate_public(
  86. or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
  87. tt_int_op(retval, ==, 0);
  88. or_circ->rend_data = rend_data_dup(conn_rend_data);
  89. } else {
  90. /* prop224: Setup hs ident on the circuit */
  91. or_circ->hs_ident = hs_ident_circuit_new(&service_pk,
  92. HS_IDENT_CIRCUIT_RENDEZVOUS);
  93. }
  94. TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
  95. /* fake n_chan */
  96. n_chan = tor_malloc_zero(sizeof(channel_tls_t));
  97. n_chan->base_.global_identifier = 1;
  98. or_circ->base_.n_chan = &(n_chan->base_);
  99. *circ_out = or_circ;
  100. *conn_out = conn;
  101. return 0;
  102. done:
  103. /* something failed */
  104. return -1;
  105. }
  106. /* Test: Ensure that setting up legacy e2e rendezvous circuits works
  107. * correctly. */
  108. static void
  109. test_e2e_rend_circuit_setup_legacy(void *arg)
  110. {
  111. ssize_t retval;
  112. origin_circuit_t *or_circ = NULL;
  113. connection_t *conn = NULL;
  114. (void) arg;
  115. /** In this test we create a v2 legacy HS stream and a circuit with the same
  116. * hidden service destination. We make the stream wait for circuits to be
  117. * established to the hidden service, and then we complete the circuit using
  118. * the hs_circuit_setup_e2e_rend_circ_legacy_client() function. We then
  119. * check that the end-to-end cpath was setup correctly and that the stream
  120. * was attached to the circuit as expected. */
  121. MOCK(connection_ap_handshake_send_begin,
  122. mock_connection_ap_handshake_send_begin);
  123. /* Setup */
  124. retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 1);
  125. tt_int_op(retval, OP_EQ, 0);
  126. tt_assert(or_circ);
  127. tt_assert(conn);
  128. /* Check number of hops */
  129. retval = cpath_get_n_hops(&or_circ->cpath);
  130. tt_int_op(retval, ==, 0);
  131. /* Check that our stream is not attached on any circuits */
  132. tt_assert(!TO_EDGE_CONN(conn)->on_circuit);
  133. /********************************************** */
  134. /* Make a good RENDEZVOUS1 cell body because it needs to pass key exchange
  135. * digest verification... */
  136. uint8_t rend_cell_body[DH_KEY_LEN+DIGEST_LEN] = {2};
  137. {
  138. char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
  139. crypto_dh_t *dh_state =
  140. or_circ->build_state->pending_final_cpath->rend_dh_handshake_state;
  141. /* compute and overwrite digest of cell body with the right value */
  142. retval = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh_state,
  143. (char*)rend_cell_body, DH_KEY_LEN,
  144. keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN);
  145. tt_int_op(retval, OP_GT, 0);
  146. memcpy(rend_cell_body+DH_KEY_LEN, keys, DIGEST_LEN);
  147. }
  148. /* Setup the circuit */
  149. retval = hs_circuit_setup_e2e_rend_circ_legacy_client(or_circ,
  150. rend_cell_body);
  151. tt_int_op(retval, OP_EQ, 0);
  152. /**********************************************/
  153. /* See that a hop was added to the circuit's cpath */
  154. retval = cpath_get_n_hops(&or_circ->cpath);
  155. tt_int_op(retval, OP_EQ, 1);
  156. /* Check the digest algo */
  157. tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
  158. OP_EQ, DIGEST_SHA1);
  159. tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
  160. OP_EQ, DIGEST_SHA1);
  161. tt_assert(or_circ->cpath->f_crypto);
  162. tt_assert(or_circ->cpath->b_crypto);
  163. /* Ensure that circ purpose was changed */
  164. tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
  165. /* Test that stream got attached */
  166. tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ));
  167. done:
  168. connection_free_(conn);
  169. tor_free(TO_CIRCUIT(or_circ)->n_chan);
  170. circuit_free(TO_CIRCUIT(or_circ));
  171. }
  172. /* Test: Ensure that setting up v3 rendezvous circuits works correctly. */
  173. static void
  174. test_e2e_rend_circuit_setup(void *arg)
  175. {
  176. uint8_t ntor_key_seed[DIGEST256_LEN] = {0};
  177. origin_circuit_t *or_circ;
  178. int retval;
  179. connection_t *conn = NULL;
  180. (void) arg;
  181. /** In this test we create a prop224 v3 HS stream and a circuit with the same
  182. * hidden service destination. We make the stream wait for circuits to be
  183. * established to the hidden service, and then we complete the circuit using
  184. * the hs_circuit_setup_e2e_rend_circ() function. We then check that the
  185. * end-to-end cpath was setup correctly and that the stream was attached to
  186. * the circuit as expected. */
  187. MOCK(connection_ap_handshake_send_begin,
  188. mock_connection_ap_handshake_send_begin);
  189. /* Setup */
  190. retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 0);
  191. tt_int_op(retval, OP_EQ, 0);
  192. tt_assert(or_circ);
  193. tt_assert(conn);
  194. /* Check number of hops: There should be no hops yet to this circ */
  195. retval = cpath_get_n_hops(&or_circ->cpath);
  196. tt_int_op(retval, ==, 0);
  197. tt_assert(!or_circ->cpath);
  198. /* Check that our stream is not attached on any circuits */
  199. tt_assert(!TO_EDGE_CONN(conn)->on_circuit);
  200. /**********************************************/
  201. /* Setup the circuit */
  202. retval = hs_circuit_setup_e2e_rend_circ(or_circ,
  203. ntor_key_seed, sizeof(ntor_key_seed),
  204. 0);
  205. tt_int_op(retval, OP_EQ, 0);
  206. /**********************************************/
  207. /* See that a hop was added to the circuit's cpath */
  208. retval = cpath_get_n_hops(&or_circ->cpath);
  209. tt_int_op(retval, OP_EQ, 1);
  210. /* Check that the crypt path has prop224 algorithm parameters */
  211. tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
  212. OP_EQ, DIGEST_SHA3_256);
  213. tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
  214. OP_EQ, DIGEST_SHA3_256);
  215. tt_assert(or_circ->cpath->f_crypto);
  216. tt_assert(or_circ->cpath->b_crypto);
  217. /* Ensure that circ purpose was changed */
  218. tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
  219. /* Test that stream got attached */
  220. tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ));
  221. done:
  222. connection_free_(conn);
  223. tor_free(TO_CIRCUIT(or_circ)->n_chan);
  224. circuit_free(TO_CIRCUIT(or_circ));
  225. }
  226. struct testcase_t hs_client_tests[] = {
  227. { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
  228. TT_FORK, NULL, NULL },
  229. { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup,
  230. TT_FORK, NULL, NULL },
  231. END_OF_TESTCASES
  232. };