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