test_extorport.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /* Copyright (c) 2013, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. #define CONNECTION_PRIVATE
  4. #define EXT_ORPORT_PRIVATE
  5. #define MAIN_PRIVATE
  6. #include "or.h"
  7. #include "buffers.h"
  8. #include "connection.h"
  9. #include "control.h"
  10. #include "ext_orport.h"
  11. #include "main.h"
  12. #include "test.h"
  13. /* Test connection_or_remove_from_ext_or_id_map and
  14. * connection_or_set_ext_or_identifier */
  15. static void
  16. test_ext_or_id_map(void *arg)
  17. {
  18. or_connection_t *c1 = NULL, *c2 = NULL, *c3 = NULL;
  19. char *idp = NULL, *idp2 = NULL;
  20. (void)arg;
  21. /* pre-initialization */
  22. tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
  23. c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  24. c2 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  25. c3 = or_connection_new(CONN_TYPE_OR, AF_INET);
  26. tt_ptr_op(c1->ext_or_conn_id, !=, NULL);
  27. tt_ptr_op(c2->ext_or_conn_id, !=, NULL);
  28. tt_ptr_op(c3->ext_or_conn_id, ==, NULL);
  29. tt_ptr_op(c1, ==, connection_or_get_by_ext_or_id(c1->ext_or_conn_id));
  30. tt_ptr_op(c2, ==, connection_or_get_by_ext_or_id(c2->ext_or_conn_id));
  31. tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
  32. idp = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
  33. /* Give c2 a new ID. */
  34. connection_or_set_ext_or_identifier(c2);
  35. test_mem_op(idp, !=, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
  36. idp2 = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
  37. tt_assert(!tor_digest_is_zero(idp2));
  38. tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp));
  39. tt_ptr_op(c2, ==, connection_or_get_by_ext_or_id(idp2));
  40. /* Now remove it. */
  41. connection_or_remove_from_ext_or_id_map(c2);
  42. tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp));
  43. tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp2));
  44. done:
  45. if (c1)
  46. connection_free_(TO_CONN(c1));
  47. if (c2)
  48. connection_free_(TO_CONN(c2));
  49. if (c3)
  50. connection_free_(TO_CONN(c3));
  51. tor_free(idp);
  52. tor_free(idp2);
  53. connection_or_clear_ext_or_id_map();
  54. }
  55. /* Simple connection_write_to_buf_impl_ replacement that unconditionally
  56. * writes to outbuf. */
  57. static void
  58. connection_write_to_buf_impl_replacement(const char *string, size_t len,
  59. connection_t *conn, int zlib)
  60. {
  61. (void) zlib;
  62. tor_assert(string);
  63. tor_assert(conn);
  64. write_to_buf(string, len, conn->outbuf);
  65. }
  66. static char *
  67. buf_get_contents(buf_t *buf, size_t *sz_out)
  68. {
  69. char *out;
  70. *sz_out = buf_datalen(buf);
  71. if (*sz_out >= ULONG_MAX)
  72. return NULL; /* C'mon, really? */
  73. out = tor_malloc(*sz_out + 1);
  74. if (fetch_from_buf(out, (unsigned long)*sz_out, buf) != 0) {
  75. tor_free(out);
  76. return NULL;
  77. }
  78. out[*sz_out] = '\0'; /* Hopefully gratuitous. */
  79. return out;
  80. }
  81. static void
  82. test_ext_or_write_command(void *arg)
  83. {
  84. or_connection_t *c1;
  85. char *cp = NULL;
  86. char *buf = NULL;
  87. size_t sz;
  88. (void) arg;
  89. MOCK(connection_write_to_buf_impl_,
  90. connection_write_to_buf_impl_replacement);
  91. c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  92. tt_assert(c1);
  93. /* Length too long */
  94. tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000),
  95. <, 0);
  96. /* Empty command */
  97. tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0),
  98. ==, 0);
  99. cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
  100. tt_int_op(sz, ==, 4);
  101. test_mem_op(cp, ==, "\x00\x99\x00\x00", 4);
  102. tor_free(cp);
  103. /* Medium command. */
  104. tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99,
  105. "Wai\0Hello", 9), ==, 0);
  106. cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
  107. tt_int_op(sz, ==, 13);
  108. test_mem_op(cp, ==, "\x00\x99\x00\x09Wai\x00Hello", 13);
  109. tor_free(cp);
  110. /* Long command */
  111. buf = tor_malloc(65535);
  112. memset(buf, 'x', 65535);
  113. tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d,
  114. buf, 65535), ==, 0);
  115. cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
  116. tt_int_op(sz, ==, 65539);
  117. test_mem_op(cp, ==, "\xf0\x0d\xff\xff", 4);
  118. test_mem_op(cp+4, ==, buf, 65535);
  119. tor_free(cp);
  120. done:
  121. if (c1)
  122. connection_free_(TO_CONN(c1));
  123. tor_free(cp);
  124. tor_free(buf);
  125. UNMOCK(connection_write_to_buf_impl_);
  126. }
  127. static void
  128. test_ext_or_cookie_auth(void *arg)
  129. {
  130. char *reply=NULL, *reply2=NULL, *client_hash=NULL, *client_hash2=NULL;
  131. size_t reply_len=0;
  132. char hmac1[32], hmac2[32];
  133. const char client_nonce[32] =
  134. "Who is the third who walks alway";
  135. char server_hash_input[] =
  136. "ExtORPort authentication server-to-client hash"
  137. "Who is the third who walks alway"
  138. "................................";
  139. char client_hash_input[] =
  140. "ExtORPort authentication client-to-server hash"
  141. "Who is the third who walks alway"
  142. "................................";
  143. (void)arg;
  144. tt_int_op(strlen(client_hash_input), ==, 46+32+32);
  145. tt_int_op(strlen(server_hash_input), ==, 46+32+32);
  146. memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32);
  147. ext_or_auth_cookie_is_set = 1;
  148. /* For this authentication, the client sends 32 random bytes (ClientNonce)
  149. * The server replies with 32 byte ServerHash and 32 byte ServerNonce,
  150. * where ServerHash is:
  151. * HMAC-SHA256(CookieString,
  152. * "ExtORPort authentication server-to-client hash" | ClientNonce |
  153. * ServerNonce)"
  154. * The client must reply with 32-byte ClientHash, which we compute as:
  155. * ClientHash is computed as:
  156. * HMAC-SHA256(CookieString,
  157. * "ExtORPort authentication client-to-server hash" | ClientNonce |
  158. * ServerNonce)
  159. */
  160. /* Wrong length */
  161. tt_int_op(-1, ==,
  162. handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply,
  163. &reply_len));
  164. tt_int_op(-1, ==,
  165. handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply,
  166. &reply_len));
  167. /* Now let's try this for real! */
  168. tt_int_op(0, ==,
  169. handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
  170. &reply_len));
  171. tt_int_op(reply_len, ==, 64);
  172. tt_ptr_op(reply, !=, NULL);
  173. tt_ptr_op(client_hash, !=, NULL);
  174. /* Fill in the server nonce into the hash inputs... */
  175. memcpy(server_hash_input+46+32, reply+32, 32);
  176. memcpy(client_hash_input+46+32, reply+32, 32);
  177. /* Check the HMACs are correct... */
  178. crypto_hmac_sha256(hmac1, ext_or_auth_cookie, 32, server_hash_input,
  179. 46+32+32);
  180. crypto_hmac_sha256(hmac2, ext_or_auth_cookie, 32, client_hash_input,
  181. 46+32+32);
  182. test_memeq(hmac1, reply, 32);
  183. test_memeq(hmac2, client_hash, 32);
  184. /* Now do it again and make sure that the results are *different* */
  185. tt_int_op(0, ==,
  186. handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2,
  187. &reply_len));
  188. test_memneq(reply2, reply, reply_len);
  189. test_memneq(client_hash2, client_hash, 32);
  190. /* But that this one checks out too. */
  191. memcpy(server_hash_input+46+32, reply2+32, 32);
  192. memcpy(client_hash_input+46+32, reply2+32, 32);
  193. /* Check the HMACs are correct... */
  194. crypto_hmac_sha256(hmac1, ext_or_auth_cookie, 32, server_hash_input,
  195. 46+32+32);
  196. crypto_hmac_sha256(hmac2, ext_or_auth_cookie, 32, client_hash_input,
  197. 46+32+32);
  198. test_memeq(hmac1, reply2, 32);
  199. test_memeq(hmac2, client_hash2, 32);
  200. done:
  201. tor_free(reply);
  202. tor_free(client_hash);
  203. tor_free(reply2);
  204. tor_free(client_hash2);
  205. }
  206. static int
  207. crypto_rand_return_tse_str(char *to, size_t n)
  208. {
  209. if (n != 32) {
  210. TT_FAIL(("Asked for %d bytes, not 32", (int)n));
  211. return -1;
  212. }
  213. memcpy(to, "te road There is always another ", 32);
  214. return 0;
  215. }
  216. static void
  217. test_ext_or_cookie_auth_testvec(void *arg)
  218. {
  219. char *reply=NULL, *client_hash=NULL;
  220. size_t reply_len;
  221. char *mem_op_hex_tmp=NULL;
  222. const char client_nonce[] = "But when I look ahead up the whi";
  223. (void)arg;
  224. memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
  225. ext_or_auth_cookie_is_set = 1;
  226. MOCK(crypto_rand, crypto_rand_return_tse_str);
  227. tt_int_op(0, ==,
  228. handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
  229. &reply_len));
  230. tt_ptr_op(reply, !=, NULL );
  231. tt_ptr_op(reply_len, ==, 64);
  232. test_memeq(reply+32, "te road There is always another ", 32);
  233. /* HMACSHA256("Gliding wrapt in a brown mantle,"
  234. * "ExtORPort authentication server-to-client hash"
  235. * "But when I look ahead up the write road There is always another ");
  236. */
  237. test_memeq_hex(reply,
  238. "ec80ed6e546d3b36fdfc22fe1315416b"
  239. "029f1ade7610d910878b62eeb7403821");
  240. /* HMACSHA256("Gliding wrapt in a brown mantle,"
  241. * "ExtORPort authentication client-to-server hash"
  242. * "But when I look ahead up the write road There is always another ");
  243. * (Both values computed using Python CLI.)
  244. */
  245. test_memeq_hex(client_hash,
  246. "ab391732dd2ed968cd40c087d1b1f25b"
  247. "33b3cd77ff79bd80c2074bbf438119a2");
  248. done:
  249. UNMOCK(crypto_rand);
  250. tor_free(reply);
  251. tor_free(client_hash);
  252. tor_free(mem_op_hex_tmp);
  253. }
  254. static void
  255. ignore_bootstrap_problem(const char *warn, int reason)
  256. {
  257. (void)warn;
  258. (void)reason;
  259. }
  260. static void
  261. test_ext_or_handshake(void *arg)
  262. {
  263. or_connection_t *conn=NULL;
  264. char b[256];
  265. #define WRITE(s,n) \
  266. do { \
  267. write_to_buf((s), (n), TO_CONN(conn)->inbuf); \
  268. } while (0)
  269. #define CONTAINS(s,n) \
  270. do { \
  271. tt_int_op((n), <=, sizeof(b)); \
  272. tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), ==, (n)); \
  273. if ((n)) { \
  274. fetch_from_buf(b, (n), TO_CONN(conn)->outbuf); \
  275. test_memeq(b, (s), (n)); \
  276. } \
  277. } while (0)
  278. (void) arg;
  279. MOCK(connection_write_to_buf_impl_,
  280. connection_write_to_buf_impl_replacement);
  281. /* Use same authenticators as for test_ext_or_cookie_auth_testvec */
  282. memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
  283. ext_or_auth_cookie_is_set = 1;
  284. init_connection_lists();
  285. conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  286. tt_int_op(0, ==, connection_ext_or_start_auth(conn));
  287. /* The server starts by telling us about the one supported authtype. */
  288. CONTAINS("\x01\x00", 2);
  289. /* Say the client hasn't responded yet. */
  290. tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
  291. /* Let's say the client replies badly. */
  292. WRITE("\x99", 1);
  293. tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
  294. CONTAINS("", 0);
  295. tt_assert(TO_CONN(conn)->marked_for_close);
  296. close_closeable_connections();
  297. conn = NULL;
  298. /* Okay, try again. */
  299. conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  300. tt_int_op(0, ==, connection_ext_or_start_auth(conn));
  301. CONTAINS("\x01\x00", 2);
  302. /* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE
  303. * sounds delicious. Let's have some of that!" */
  304. WRITE("\x01", 1);
  305. /* Let's say that the client also sends part of a nonce. */
  306. WRITE("But when I look ", 16);
  307. tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
  308. CONTAINS("", 0);
  309. tt_int_op(TO_CONN(conn)->state, ==,
  310. EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE);
  311. /* Pump it again. Nothing should happen. */
  312. tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
  313. /* send the rest of the nonce. */
  314. WRITE("ahead up the whi", 16);
  315. MOCK(crypto_rand, crypto_rand_return_tse_str);
  316. tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
  317. UNMOCK(crypto_rand);
  318. /* We should get the right reply from the server. */
  319. CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
  320. "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
  321. "te road There is always another ", 64);
  322. /* Send the wrong response. */
  323. WRITE("not with a bang but a whimper...", 32);
  324. MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
  325. tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
  326. CONTAINS("\x00", 1);
  327. tt_assert(TO_CONN(conn)->marked_for_close);
  328. /* XXXX Hold-open-until-flushed. */
  329. close_closeable_connections();
  330. conn = NULL;
  331. UNMOCK(control_event_bootstrap_problem);
  332. /* Okay, this time let's succeed. */
  333. conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  334. tt_int_op(0, ==, connection_ext_or_start_auth(conn));
  335. CONTAINS("\x01\x00", 2);
  336. WRITE("\x01", 1);
  337. WRITE("But when I look ahead up the whi", 32);
  338. MOCK(crypto_rand, crypto_rand_return_tse_str);
  339. tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
  340. UNMOCK(crypto_rand);
  341. tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
  342. CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
  343. "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
  344. "te road There is always another ", 64);
  345. /* Send the right response this time. */
  346. WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b"
  347. "\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2",
  348. 32);
  349. tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
  350. CONTAINS("\x01", 1);
  351. tt_assert(! TO_CONN(conn)->marked_for_close);
  352. tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_OPEN);
  353. done:
  354. UNMOCK(connection_write_to_buf_impl_);
  355. UNMOCK(crypto_rand);
  356. if (conn)
  357. connection_free_(TO_CONN(conn));
  358. #undef WRITE
  359. }
  360. struct testcase_t extorport_tests[] = {
  361. { "id_map", test_ext_or_id_map, TT_FORK, NULL, NULL },
  362. { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL },
  363. { "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL },
  364. { "cookie_auth_testvec", test_ext_or_cookie_auth_testvec, TT_FORK,
  365. NULL, NULL },
  366. { "handshake", test_ext_or_handshake, TT_FORK, NULL, NULL },
  367. END_OF_TESTCASES
  368. };