pt-tls-client.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*
  2. * Copyright (C) 2013-2015 Andreas Steffen
  3. * HSR Hochschule fuer Technik Rapperswil
  4. *
  5. * Copyright (C) 2010-2013 Martin Willi
  6. * Copyright (C) 2010-2013 revosec AG
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  15. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  16. * for more details.
  17. */
  18. #include <unistd.h>
  19. #include <stdio.h>
  20. #include <sys/types.h>
  21. #include <getopt.h>
  22. #include <errno.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #ifdef HAVE_SYSLOG
  26. #include <syslog.h>
  27. #endif
  28. #include <pt_tls.h>
  29. #include <pt_tls_client.h>
  30. #include <tnc/tnc.h>
  31. #include <tls.h>
  32. #include <library.h>
  33. #include <utils/debug.h>
  34. #include <credentials/sets/mem_cred.h>
  35. #include <utils/optionsfrom.h>
  36. /**
  37. * Print usage information
  38. */
  39. static void usage(FILE *out)
  40. {
  41. fprintf(out,
  42. "Usage: pt-tls --connect <hostname|address> [--port <port>]\n"
  43. " [--certid <hex>|--cert <file>]+ [--keyid <hex>|--key <file>]\n"
  44. " [--key-type rsa|ecdsa] [--client <client-id>]\n"
  45. " [--secret <password>] [--mutual] [--quiet]\n"
  46. " [--debug <level>] [--options <filename>]\n");
  47. }
  48. /**
  49. * Client routine
  50. */
  51. static int client(char *address, uint16_t port, char *identity)
  52. {
  53. pt_tls_client_t *assessment;
  54. tls_t *tnccs;
  55. identification_t *server_id, *client_id;
  56. host_t *server_ip, *client_ip;
  57. status_t status;
  58. server_ip = host_create_from_dns(address, AF_UNSPEC, port);
  59. if (!server_ip)
  60. {
  61. return 1;
  62. }
  63. client_ip = host_create_any(server_ip->get_family(server_ip));
  64. if (!client_ip)
  65. {
  66. server_ip->destroy(server_ip);
  67. return 1;
  68. }
  69. server_id = identification_create_from_string(address);
  70. client_id = identification_create_from_string(identity);
  71. tnccs = (tls_t*)tnc->tnccs->create_instance(tnc->tnccs, TNCCS_2_0, FALSE,
  72. server_id, client_id, server_ip, client_ip,
  73. TNC_IFT_TLS_2_0, NULL);
  74. client_ip->destroy(client_ip);
  75. if (!tnccs)
  76. {
  77. fprintf(stderr, "loading TNCCS failed: %s\n", PLUGINS);
  78. server_ip->destroy(server_ip);
  79. server_id->destroy(server_id);
  80. client_id->destroy(client_id);
  81. return 1;
  82. }
  83. assessment = pt_tls_client_create(server_ip, server_id, client_id);
  84. status = assessment->run_assessment(assessment, (tnccs_t*)tnccs);
  85. assessment->destroy(assessment);
  86. tnccs->destroy(tnccs);
  87. return (status != SUCCESS);
  88. }
  89. /**
  90. * In-Memory credential set
  91. */
  92. static mem_cred_t *creds;
  93. /**
  94. * Load certificate from file
  95. */
  96. static bool load_certificate(char *certid, char *filename)
  97. {
  98. certificate_t *cert;
  99. chunk_t chunk;
  100. if (certid)
  101. {
  102. chunk = chunk_from_hex(chunk_create(certid, strlen(certid)), NULL);
  103. cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
  104. BUILD_PKCS11_KEYID, chunk, BUILD_END);
  105. }
  106. else
  107. {
  108. cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
  109. BUILD_FROM_FILE, filename, BUILD_END);
  110. }
  111. if (!cert)
  112. {
  113. DBG1(DBG_TLS, "loading certificate from '%s' failed",
  114. certid ? certid : filename);
  115. return FALSE;
  116. }
  117. creds->add_cert(creds, TRUE, cert);
  118. return TRUE;
  119. }
  120. /**
  121. * Load private key from file
  122. */
  123. static bool load_key(char *keyid, char *filename, key_type_t type)
  124. {
  125. private_key_t *key;
  126. chunk_t chunk;
  127. if (keyid)
  128. {
  129. chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
  130. key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
  131. BUILD_PKCS11_KEYID, chunk, BUILD_END);
  132. chunk_free(&chunk);
  133. }
  134. else
  135. {
  136. key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
  137. BUILD_FROM_FILE, filename, BUILD_END);
  138. }
  139. if (!key)
  140. {
  141. DBG1(DBG_TLS, "loading key from '%s' failed", keyid ? keyid : filename);
  142. return FALSE;
  143. }
  144. creds->add_key(creds, key);
  145. return TRUE;
  146. }
  147. /**
  148. * Logging and debug level
  149. */
  150. static bool log_to_stderr = TRUE;
  151. #ifdef HAVE_SYSLOG
  152. static bool log_to_syslog = TRUE;
  153. #endif /* HAVE_SYSLOG */
  154. static level_t default_loglevel = 1;
  155. static void dbg_pt_tls(debug_t group, level_t level, char *fmt, ...)
  156. {
  157. va_list args;
  158. if (level <= default_loglevel)
  159. {
  160. if (log_to_stderr)
  161. {
  162. va_start(args, fmt);
  163. vfprintf(stderr, fmt, args);
  164. va_end(args);
  165. fprintf(stderr, "\n");
  166. }
  167. #ifdef HAVE_SYSLOG
  168. if (log_to_syslog)
  169. {
  170. char buffer[8192];
  171. char *current = buffer, *next;
  172. /* write in memory buffer first */
  173. va_start(args, fmt);
  174. vsnprintf(buffer, sizeof(buffer), fmt, args);
  175. va_end(args);
  176. /* do a syslog with every line */
  177. while (current)
  178. {
  179. next = strchr(current, '\n');
  180. if (next)
  181. {
  182. *(next++) = '\0';
  183. }
  184. syslog(LOG_INFO, "%s\n", current);
  185. current = next;
  186. }
  187. }
  188. #endif /* HAVE_SYSLOG */
  189. }
  190. }
  191. /**
  192. * Initialize logging to stderr/syslog
  193. */
  194. static void init_log(const char *program)
  195. {
  196. dbg = dbg_pt_tls;
  197. if (log_to_stderr)
  198. {
  199. setbuf(stderr, NULL);
  200. }
  201. #ifdef HAVE_SYSLOG
  202. if (log_to_syslog)
  203. {
  204. openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
  205. }
  206. #endif /* HAVE_SYSLOG */
  207. }
  208. /**
  209. * Handles --optionsfrom arguments
  210. */
  211. options_t *options;
  212. /**
  213. * Cleanup
  214. */
  215. static void cleanup()
  216. {
  217. lib->processor->cancel(lib->processor);
  218. lib->credmgr->remove_set(lib->credmgr, &creds->set);
  219. creds->destroy(creds);
  220. options->destroy(options);
  221. libtnccs_deinit();
  222. library_deinit();
  223. }
  224. /**
  225. * Initialize library
  226. */
  227. static void init()
  228. {
  229. plugin_feature_t features[] = {
  230. PLUGIN_NOOP,
  231. PLUGIN_PROVIDE(CUSTOM, "pt-tls-client"),
  232. PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"),
  233. };
  234. library_init(NULL, "pt-tls-client");
  235. libtnccs_init();
  236. init_log("pt-tls-client");
  237. options = options_create();
  238. lib->plugins->add_static_features(lib->plugins, "pt-tls-client", features,
  239. countof(features), TRUE, NULL, NULL);
  240. if (!lib->plugins->load(lib->plugins,
  241. lib->settings->get_str(lib->settings, "pt-tls-client.load", PLUGINS)))
  242. {
  243. exit(SS_RC_INITIALIZATION_FAILED);
  244. }
  245. lib->plugins->status(lib->plugins, LEVEL_CTRL);
  246. creds = mem_cred_create();
  247. lib->credmgr->add_set(lib->credmgr, &creds->set);
  248. atexit(cleanup);
  249. }
  250. int main(int argc, char *argv[])
  251. {
  252. char *address = NULL, *identity = "%any", *secret = NULL;
  253. char *keyid = NULL, *key_file = NULL;
  254. key_type_t key_type = KEY_RSA;
  255. int port = PT_TLS_PORT;
  256. init();
  257. while (TRUE)
  258. {
  259. struct option long_opts[] = {
  260. {"help", no_argument, NULL, 'h' },
  261. {"connect", required_argument, NULL, 'c' },
  262. {"client", required_argument, NULL, 'i' },
  263. {"secret", required_argument, NULL, 's' },
  264. {"port", required_argument, NULL, 'p' },
  265. {"certid", required_argument, NULL, 'X' },
  266. {"cert", required_argument, NULL, 'x' },
  267. {"keyid", required_argument, NULL, 'K' },
  268. {"key", required_argument, NULL, 'k' },
  269. {"key-type", required_argument, NULL, 't' },
  270. {"mutual", no_argument, NULL, 'm' },
  271. {"quiet", no_argument, NULL, 'q' },
  272. {"debug", required_argument, NULL, 'd' },
  273. {"options", required_argument, NULL, '+' },
  274. {"optionsfrom", required_argument, NULL, '+' },
  275. {0,0,0,0 }
  276. };
  277. switch (getopt_long(argc, argv, "hc:i:s:p:x:K:k:t:mqd:+:", long_opts,
  278. NULL))
  279. {
  280. case EOF:
  281. break;
  282. case 'h': /* --help */
  283. usage(stdout);
  284. return 0;
  285. case 'X': /* --certid <hex> */
  286. if (!load_certificate(optarg, NULL))
  287. {
  288. return 1;
  289. }
  290. continue;
  291. case 'x': /* --cert <file> */
  292. if (!load_certificate(NULL, optarg))
  293. {
  294. return 1;
  295. }
  296. continue;
  297. case 'K': /* --keyid <hex> */
  298. keyid = optarg;
  299. continue;
  300. case 'k': /* --key <file> */
  301. key_file = optarg;
  302. continue;
  303. case 't': /* --key-type <type> */
  304. if (strcaseeq(optarg, "ecdsa"))
  305. {
  306. key_type = KEY_ECDSA;
  307. }
  308. else if (strcaseeq(optarg, "rsa"))
  309. {
  310. key_type = KEY_RSA;
  311. }
  312. else
  313. {
  314. key_type = KEY_ANY;
  315. }
  316. continue;
  317. case 'c': /* --connect <hostname|address> */
  318. if (address)
  319. {
  320. usage(stderr);
  321. return 1;
  322. }
  323. address = optarg;
  324. continue;
  325. case 'i': /* --client <client-id> */
  326. identity = optarg;
  327. continue;
  328. case 's': /* --secret <password> */
  329. secret = optarg;
  330. continue;
  331. case 'p': /* --port <port> */
  332. port = atoi(optarg);
  333. continue;
  334. case 'm': /* --mutual */
  335. lib->settings->set_bool(lib->settings,
  336. "%s.plugins.tnccs-20.mutual", TRUE, lib->ns);
  337. continue;
  338. case 'q': /* --quiet */
  339. log_to_stderr = FALSE;
  340. continue;
  341. case 'd': /* --debug <level> */
  342. default_loglevel = atoi(optarg);
  343. continue;
  344. case '+': /* --optionsfrom <filename> */
  345. if (!options->from(options, optarg, &argc, &argv, optind))
  346. {
  347. return 1;
  348. }
  349. continue;
  350. default:
  351. usage(stderr);
  352. return 1;
  353. }
  354. break;
  355. }
  356. if (!address)
  357. {
  358. usage(stderr);
  359. return 1;
  360. }
  361. if ((keyid || key_file) && !load_key(keyid, key_file, key_type))
  362. {
  363. return 1;
  364. }
  365. if (secret)
  366. {
  367. creds->add_shared(creds, shared_key_create(SHARED_EAP,
  368. chunk_clone(chunk_from_str(secret))),
  369. identification_create_from_string(identity), NULL);
  370. }
  371. return client(address, port, identity);
  372. }