tls_test.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * Copyright (C) 2010 Martin Willi
  3. * Copyright (C) 2010 revosec AG
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * for more details.
  14. */
  15. #include <unistd.h>
  16. #include <stdio.h>
  17. #include <sys/types.h>
  18. #include <sys/socket.h>
  19. #include <getopt.h>
  20. #include <errno.h>
  21. #include <string.h>
  22. #include <library.h>
  23. #include <utils/debug.h>
  24. #include <tls_socket.h>
  25. #include <networking/host.h>
  26. #include <credentials/sets/mem_cred.h>
  27. /**
  28. * Print usage information
  29. */
  30. static void usage(FILE *out, char *cmd)
  31. {
  32. fprintf(out, "usage:\n");
  33. fprintf(out, " %s --connect <address> --port <port> [--key <key] [--cert <file>]+ [--times <n>]\n", cmd);
  34. fprintf(out, " %s --listen <address> --port <port> --key <key> [--cert <file>]+ [--times <n>]\n", cmd);
  35. }
  36. /**
  37. * Check, as client, if we have a client certificate with private key
  38. */
  39. static identification_t *find_client_id()
  40. {
  41. identification_t *client = NULL, *keyid;
  42. enumerator_t *enumerator;
  43. certificate_t *cert;
  44. public_key_t *pubkey;
  45. private_key_t *privkey;
  46. chunk_t chunk;
  47. enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
  48. CERT_X509, KEY_ANY, NULL, FALSE);
  49. while (enumerator->enumerate(enumerator, &cert))
  50. {
  51. pubkey = cert->get_public_key(cert);
  52. if (pubkey)
  53. {
  54. if (pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &chunk))
  55. {
  56. keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
  57. privkey = lib->credmgr->get_private(lib->credmgr,
  58. pubkey->get_type(pubkey), keyid, NULL);
  59. keyid->destroy(keyid);
  60. if (privkey)
  61. {
  62. client = cert->get_subject(cert);
  63. client = client->clone(client);
  64. privkey->destroy(privkey);
  65. }
  66. }
  67. pubkey->destroy(pubkey);
  68. }
  69. if (client)
  70. {
  71. break;
  72. }
  73. }
  74. enumerator->destroy(enumerator);
  75. return client;
  76. }
  77. /**
  78. * Client routine
  79. */
  80. static int run_client(host_t *host, identification_t *server,
  81. identification_t *client, int times, tls_cache_t *cache)
  82. {
  83. tls_socket_t *tls;
  84. int fd, res;
  85. while (times == -1 || times-- > 0)
  86. {
  87. fd = socket(AF_INET, SOCK_STREAM, 0);
  88. if (fd == -1)
  89. {
  90. DBG1(DBG_TLS, "opening socket failed: %s", strerror(errno));
  91. return 1;
  92. }
  93. if (connect(fd, host->get_sockaddr(host),
  94. *host->get_sockaddr_len(host)) == -1)
  95. {
  96. DBG1(DBG_TLS, "connecting to %#H failed: %s", host, strerror(errno));
  97. close(fd);
  98. return 1;
  99. }
  100. tls = tls_socket_create(FALSE, server, client, fd, cache, TLS_1_2, TRUE);
  101. if (!tls)
  102. {
  103. close(fd);
  104. return 1;
  105. }
  106. res = tls->splice(tls, 0, 1) ? 0 : 1;
  107. tls->destroy(tls);
  108. close(fd);
  109. if (res)
  110. {
  111. break;
  112. }
  113. }
  114. return res;
  115. }
  116. /**
  117. * Server routine
  118. */
  119. static int serve(host_t *host, identification_t *server,
  120. int times, tls_cache_t *cache)
  121. {
  122. tls_socket_t *tls;
  123. int fd, cfd;
  124. fd = socket(AF_INET, SOCK_STREAM, 0);
  125. if (fd == -1)
  126. {
  127. DBG1(DBG_TLS, "opening socket failed: %s", strerror(errno));
  128. return 1;
  129. }
  130. if (bind(fd, host->get_sockaddr(host),
  131. *host->get_sockaddr_len(host)) == -1)
  132. {
  133. DBG1(DBG_TLS, "binding to %#H failed: %s", host, strerror(errno));
  134. close(fd);
  135. return 1;
  136. }
  137. if (listen(fd, 1) == -1)
  138. {
  139. DBG1(DBG_TLS, "listen to %#H failed: %m", host, strerror(errno));
  140. close(fd);
  141. return 1;
  142. }
  143. while (times == -1 || times-- > 0)
  144. {
  145. cfd = accept(fd, host->get_sockaddr(host), host->get_sockaddr_len(host));
  146. if (cfd == -1)
  147. {
  148. DBG1(DBG_TLS, "accept failed: %s", strerror(errno));
  149. close(fd);
  150. return 1;
  151. }
  152. DBG1(DBG_TLS, "%#H connected", host);
  153. tls = tls_socket_create(TRUE, server, NULL, cfd, cache, TLS_1_2, TRUE);
  154. if (!tls)
  155. {
  156. close(fd);
  157. return 1;
  158. }
  159. tls->splice(tls, 0, 1);
  160. DBG1(DBG_TLS, "%#H disconnected", host);
  161. tls->destroy(tls);
  162. }
  163. close(fd);
  164. return 0;
  165. }
  166. /**
  167. * In-Memory credential set
  168. */
  169. static mem_cred_t *creds;
  170. /**
  171. * Load certificate from file
  172. */
  173. static bool load_certificate(char *filename)
  174. {
  175. certificate_t *cert;
  176. cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
  177. BUILD_FROM_FILE, filename, BUILD_END);
  178. if (!cert)
  179. {
  180. DBG1(DBG_TLS, "loading certificate from '%s' failed", filename);
  181. return FALSE;
  182. }
  183. creds->add_cert(creds, TRUE, cert);
  184. return TRUE;
  185. }
  186. /**
  187. * Load private key from file
  188. */
  189. static bool load_key(char *filename)
  190. {
  191. private_key_t *key;
  192. key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
  193. BUILD_FROM_FILE, filename, BUILD_END);
  194. if (!key)
  195. {
  196. DBG1(DBG_TLS, "loading key from '%s' failed", filename);
  197. return FALSE;
  198. }
  199. creds->add_key(creds, key);
  200. return TRUE;
  201. }
  202. /**
  203. * TLS debug level
  204. */
  205. static level_t tls_level = 1;
  206. static void dbg_tls(debug_t group, level_t level, char *fmt, ...)
  207. {
  208. if ((group == DBG_TLS && level <= tls_level) || level <= 1)
  209. {
  210. va_list args;
  211. va_start(args, fmt);
  212. vfprintf(stderr, fmt, args);
  213. fprintf(stderr, "\n");
  214. va_end(args);
  215. }
  216. }
  217. /**
  218. * Cleanup
  219. */
  220. static void cleanup()
  221. {
  222. lib->credmgr->remove_set(lib->credmgr, &creds->set);
  223. creds->destroy(creds);
  224. library_deinit();
  225. }
  226. /**
  227. * Initialize library
  228. */
  229. static void init()
  230. {
  231. library_init(NULL, "tls_test");
  232. dbg = dbg_tls;
  233. lib->plugins->load(lib->plugins, PLUGINS);
  234. creds = mem_cred_create();
  235. lib->credmgr->add_set(lib->credmgr, &creds->set);
  236. atexit(cleanup);
  237. }
  238. int main(int argc, char *argv[])
  239. {
  240. char *address = NULL;
  241. bool listen = FALSE;
  242. int port = 0, times = -1, res;
  243. identification_t *server, *client;
  244. tls_cache_t *cache;
  245. host_t *host;
  246. init();
  247. while (TRUE)
  248. {
  249. struct option long_opts[] = {
  250. {"help", no_argument, NULL, 'h' },
  251. {"connect", required_argument, NULL, 'c' },
  252. {"listen", required_argument, NULL, 'l' },
  253. {"port", required_argument, NULL, 'p' },
  254. {"cert", required_argument, NULL, 'x' },
  255. {"key", required_argument, NULL, 'k' },
  256. {"times", required_argument, NULL, 't' },
  257. {"debug", required_argument, NULL, 'd' },
  258. {0,0,0,0 }
  259. };
  260. switch (getopt_long(argc, argv, "", long_opts, NULL))
  261. {
  262. case EOF:
  263. break;
  264. case 'h':
  265. usage(stdout, argv[0]);
  266. return 0;
  267. case 'x':
  268. if (!load_certificate(optarg))
  269. {
  270. return 1;
  271. }
  272. continue;
  273. case 'k':
  274. if (!load_key(optarg))
  275. {
  276. return 1;
  277. }
  278. continue;
  279. case 'l':
  280. listen = TRUE;
  281. /* fall */
  282. case 'c':
  283. if (address)
  284. {
  285. usage(stderr, argv[0]);
  286. return 1;
  287. }
  288. address = optarg;
  289. continue;
  290. case 'p':
  291. port = atoi(optarg);
  292. continue;
  293. case 't':
  294. times = atoi(optarg);
  295. continue;
  296. case 'd':
  297. tls_level = atoi(optarg);
  298. continue;
  299. default:
  300. usage(stderr, argv[0]);
  301. return 1;
  302. }
  303. break;
  304. }
  305. if (!port || !address)
  306. {
  307. usage(stderr, argv[0]);
  308. return 1;
  309. }
  310. host = host_create_from_dns(address, 0, port);
  311. if (!host)
  312. {
  313. DBG1(DBG_TLS, "resolving hostname %s failed", address);
  314. return 1;
  315. }
  316. server = identification_create_from_string(address);
  317. cache = tls_cache_create(100, 30);
  318. if (listen)
  319. {
  320. res = serve(host, server, times, cache);
  321. }
  322. else
  323. {
  324. client = find_client_id();
  325. res = run_client(host, server, client, times, cache);
  326. DESTROY_IF(client);
  327. }
  328. cache->destroy(cache);
  329. host->destroy(host);
  330. server->destroy(server);
  331. return res;
  332. }