Annotation of embedaddon/strongswan/scripts/tls_test.c, revision 1.1.1.2
1.1 misho 1: /*
1.1.1.2 ! misho 2: * Copyright (C) 2020 Pascal Knecht
! 3: * Copyright (C) 2020 Tobias Brunner
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
1.1 misho 6: * Copyright (C) 2010 Martin Willi
7: * Copyright (C) 2010 revosec AG
8: *
9: * This program is free software; you can redistribute it and/or modify it
10: * under the terms of the GNU General Public License as published by the
11: * Free Software Foundation; either version 2 of the License, or (at your
12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13: *
14: * This program is distributed in the hope that it will be useful, but
15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17: * for more details.
18: */
19:
20: #include <unistd.h>
21: #include <stdio.h>
22: #include <sys/types.h>
23: #include <sys/socket.h>
24: #include <getopt.h>
25: #include <errno.h>
26: #include <string.h>
27:
28: #include <library.h>
29: #include <utils/debug.h>
30: #include <tls_socket.h>
31: #include <networking/host.h>
32: #include <credentials/sets/mem_cred.h>
33:
34: /**
35: * Print usage information
36: */
37: static void usage(FILE *out, char *cmd)
38: {
39: fprintf(out, "usage:\n");
1.1.1.2 ! misho 40: fprintf(out, " %s --connect <address> --port <port> [--key <key] [--cert <file>] [--cacert <file>]+ [--times <n>]\n", cmd);
! 41: fprintf(out, " %s --listen <address> --port <port> --key <key> --cert <file> [--cacert <file>]+ [--auth-optional] [--times <n>]\n", cmd);
! 42: fprintf(out, "\n");
! 43: fprintf(out, "options:\n");
! 44: fprintf(out, " --help print help and exit\n");
! 45: fprintf(out, " --connect <address> connect to a server on dns name or ip address\n");
! 46: fprintf(out, " --listen <address> listen on dns name or ip address\n");
! 47: fprintf(out, " --port <port> specify the port to use\n");
! 48: fprintf(out, " --cert <file> certificate to authenticate itself\n");
! 49: fprintf(out, " --key <file> private key to authenticate itself\n");
! 50: fprintf(out, " --cacert <file> certificate to verify other peer\n");
! 51: fprintf(out, " --auth-optional don't enforce client authentication\n");
! 52: fprintf(out, " --times <n> specify the amount of repeated connection establishments\n");
! 53: fprintf(out, " --ipv4 use IPv4\n");
! 54: fprintf(out, " --ipv6 use IPv6\n");
! 55: fprintf(out, " --min-version <version> specify the minimum TLS version, supported versions:\n");
! 56: fprintf(out, " 1.0 (default), 1.1, 1.2 and 1.3\n");
! 57: fprintf(out, " --max-version <version> specify the maximum TLS version, supported versions:\n");
! 58: fprintf(out, " 1.0, 1.1, 1.2 and 1.3 (default)\n");
! 59: fprintf(out, " --version <version> set one specific TLS version to use, supported versions:\n");
! 60: fprintf(out, " 1.0, 1.1, 1.2 and 1.3\n");
! 61: fprintf(out, " --debug <debug level> set debug level, default is 1\n");
1.1 misho 62: }
63:
64: /**
65: * Check, as client, if we have a client certificate with private key
66: */
67: static identification_t *find_client_id()
68: {
69: identification_t *client = NULL, *keyid;
70: enumerator_t *enumerator;
71: certificate_t *cert;
72: public_key_t *pubkey;
73: private_key_t *privkey;
74: chunk_t chunk;
75:
76: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
77: CERT_X509, KEY_ANY, NULL, FALSE);
78: while (enumerator->enumerate(enumerator, &cert))
79: {
80: pubkey = cert->get_public_key(cert);
81: if (pubkey)
82: {
83: if (pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &chunk))
84: {
85: keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
86: privkey = lib->credmgr->get_private(lib->credmgr,
87: pubkey->get_type(pubkey), keyid, NULL);
88: keyid->destroy(keyid);
89: if (privkey)
90: {
91: client = cert->get_subject(cert);
92: client = client->clone(client);
93: privkey->destroy(privkey);
94: }
95: }
96: pubkey->destroy(pubkey);
97: }
98: if (client)
99: {
100: break;
101: }
102: }
103: enumerator->destroy(enumerator);
104:
105: return client;
106: }
107:
108: /**
109: * Client routine
110: */
111: static int run_client(host_t *host, identification_t *server,
1.1.1.2 ! misho 112: identification_t *client, int times, tls_cache_t *cache,
! 113: tls_version_t min_version, tls_version_t max_version,
! 114: tls_flag_t flags)
1.1 misho 115: {
116: tls_socket_t *tls;
117: int fd, res;
118:
119: while (times == -1 || times-- > 0)
120: {
1.1.1.2 ! misho 121: DBG2(DBG_TLS, "connecting to %#H", host);
! 122: fd = socket(host->get_family(host), SOCK_STREAM, 0);
1.1 misho 123: if (fd == -1)
124: {
125: DBG1(DBG_TLS, "opening socket failed: %s", strerror(errno));
126: return 1;
127: }
128: if (connect(fd, host->get_sockaddr(host),
129: *host->get_sockaddr_len(host)) == -1)
130: {
131: DBG1(DBG_TLS, "connecting to %#H failed: %s", host, strerror(errno));
132: close(fd);
133: return 1;
134: }
1.1.1.2 ! misho 135: tls = tls_socket_create(FALSE, server, client, fd, cache, min_version,
! 136: max_version, flags);
1.1 misho 137: if (!tls)
138: {
139: close(fd);
140: return 1;
141: }
142: res = tls->splice(tls, 0, 1) ? 0 : 1;
143: tls->destroy(tls);
144: close(fd);
145: if (res)
146: {
147: break;
148: }
149: }
150: return res;
151: }
152:
153: /**
154: * Server routine
155: */
1.1.1.2 ! misho 156: static int serve(host_t *host, identification_t *server, identification_t *client,
! 157: int times, tls_cache_t *cache, tls_version_t min_version,
! 158: tls_version_t max_version, tls_flag_t flags)
1.1 misho 159: {
160: tls_socket_t *tls;
161: int fd, cfd;
162:
163: fd = socket(AF_INET, SOCK_STREAM, 0);
164: if (fd == -1)
165: {
166: DBG1(DBG_TLS, "opening socket failed: %s", strerror(errno));
167: return 1;
168: }
169: if (bind(fd, host->get_sockaddr(host),
170: *host->get_sockaddr_len(host)) == -1)
171: {
172: DBG1(DBG_TLS, "binding to %#H failed: %s", host, strerror(errno));
173: close(fd);
174: return 1;
175: }
176: if (listen(fd, 1) == -1)
177: {
178: DBG1(DBG_TLS, "listen to %#H failed: %m", host, strerror(errno));
179: close(fd);
180: return 1;
181: }
182:
183: while (times == -1 || times-- > 0)
184: {
185: cfd = accept(fd, host->get_sockaddr(host), host->get_sockaddr_len(host));
186: if (cfd == -1)
187: {
188: DBG1(DBG_TLS, "accept failed: %s", strerror(errno));
189: close(fd);
190: return 1;
191: }
192: DBG1(DBG_TLS, "%#H connected", host);
193:
1.1.1.2 ! misho 194: tls = tls_socket_create(TRUE, server, client, cfd, cache, min_version,
! 195: max_version, flags);
1.1 misho 196: if (!tls)
197: {
198: close(fd);
199: return 1;
200: }
201: tls->splice(tls, 0, 1);
202: DBG1(DBG_TLS, "%#H disconnected", host);
203: tls->destroy(tls);
204: }
205: close(fd);
206:
207: return 0;
208: }
209:
210: /**
211: * In-Memory credential set
212: */
213: static mem_cred_t *creds;
214:
215: /**
216: * Load certificate from file
217: */
218: static bool load_certificate(char *filename)
219: {
220: certificate_t *cert;
221:
222: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
223: BUILD_FROM_FILE, filename, BUILD_END);
224: if (!cert)
225: {
226: DBG1(DBG_TLS, "loading certificate from '%s' failed", filename);
227: return FALSE;
228: }
229: creds->add_cert(creds, TRUE, cert);
230: return TRUE;
231: }
232:
233: /**
234: * Load private key from file
235: */
236: static bool load_key(char *filename)
237: {
238: private_key_t *key;
239:
1.1.1.2 ! misho 240: key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
! 241: BUILD_FROM_FILE, filename, BUILD_END);
1.1 misho 242: if (!key)
243: {
244: DBG1(DBG_TLS, "loading key from '%s' failed", filename);
245: return FALSE;
246: }
247: creds->add_key(creds, key);
248: return TRUE;
249: }
250:
251: /**
252: * TLS debug level
253: */
254: static level_t tls_level = 1;
255:
256: static void dbg_tls(debug_t group, level_t level, char *fmt, ...)
257: {
258: if ((group == DBG_TLS && level <= tls_level) || level <= 1)
259: {
260: va_list args;
261:
262: va_start(args, fmt);
263: vfprintf(stderr, fmt, args);
264: fprintf(stderr, "\n");
265: va_end(args);
266: }
267: }
268:
269: /**
270: * Cleanup
271: */
272: static void cleanup()
273: {
274: lib->credmgr->remove_set(lib->credmgr, &creds->set);
275: creds->destroy(creds);
276: library_deinit();
277: }
278:
279: /**
280: * Initialize library
281: */
282: static void init()
283: {
1.1.1.2 ! misho 284: char *plugins;
! 285:
1.1 misho 286: library_init(NULL, "tls_test");
287:
288: dbg = dbg_tls;
289:
1.1.1.2 ! misho 290: plugins = getenv("PLUGINS") ?: PLUGINS;
! 291: lib->plugins->load(lib->plugins, plugins);
1.1 misho 292:
293: creds = mem_cred_create();
294: lib->credmgr->add_set(lib->credmgr, &creds->set);
295:
296: atexit(cleanup);
297: }
298:
299: int main(int argc, char *argv[])
300: {
301: char *address = NULL;
302: bool listen = FALSE;
1.1.1.2 ! misho 303: int port = 0, times = -1, res, family = AF_UNSPEC;
! 304: identification_t *server, *client = NULL;
! 305: tls_version_t min_version = TLS_SUPPORTED_MIN, max_version = TLS_SUPPORTED_MAX;
! 306: tls_flag_t flags = TLS_FLAG_ENCRYPTION_OPTIONAL;
1.1 misho 307: tls_cache_t *cache;
308: host_t *host;
309:
310: init();
311:
312: while (TRUE)
313: {
314: struct option long_opts[] = {
1.1.1.2 ! misho 315: {"help", no_argument, NULL, 'h' },
! 316: {"connect", required_argument, NULL, 'c' },
! 317: {"listen", required_argument, NULL, 'l' },
! 318: {"port", required_argument, NULL, 'p' },
! 319: {"cert", required_argument, NULL, 'x' },
! 320: {"key", required_argument, NULL, 'k' },
! 321: {"cacert", required_argument, NULL, 'f' },
! 322: {"times", required_argument, NULL, 't' },
! 323: {"ipv4", no_argument, NULL, '4' },
! 324: {"ipv6", no_argument, NULL, '6' },
! 325: {"min-version", required_argument, NULL, 'm' },
! 326: {"max-version", required_argument, NULL, 'M' },
! 327: {"version", required_argument, NULL, 'v' },
! 328: {"auth-optional", no_argument, NULL, 'n' },
! 329: {"debug", required_argument, NULL, 'd' },
1.1 misho 330: {0,0,0,0 }
331: };
332: switch (getopt_long(argc, argv, "", long_opts, NULL))
333: {
334: case EOF:
335: break;
336: case 'h':
337: usage(stdout, argv[0]);
338: return 0;
339: case 'x':
340: if (!load_certificate(optarg))
341: {
342: return 1;
343: }
344: continue;
345: case 'k':
346: if (!load_key(optarg))
347: {
348: return 1;
349: }
350: continue;
1.1.1.2 ! misho 351: case 'f':
! 352: if (!load_certificate(optarg))
! 353: {
! 354: return 1;
! 355: }
! 356: client = identification_create_from_encoding(ID_ANY, chunk_empty);
! 357: continue;
1.1 misho 358: case 'l':
359: listen = TRUE;
360: /* fall */
361: case 'c':
362: if (address)
363: {
364: usage(stderr, argv[0]);
365: return 1;
366: }
367: address = optarg;
368: continue;
369: case 'p':
370: port = atoi(optarg);
371: continue;
372: case 't':
373: times = atoi(optarg);
374: continue;
375: case 'd':
376: tls_level = atoi(optarg);
377: continue;
1.1.1.2 ! misho 378: case '4':
! 379: family = AF_INET;
! 380: continue;
! 381: case '6':
! 382: family = AF_INET6;
! 383: continue;
! 384: case 'm':
! 385: if (!enum_from_name(tls_numeric_version_names, optarg,
! 386: &min_version))
! 387: {
! 388: fprintf(stderr, "unknown minimum TLS version: %s\n", optarg);
! 389: return 1;
! 390: }
! 391: continue;
! 392: case 'M':
! 393: if (!enum_from_name(tls_numeric_version_names, optarg,
! 394: &max_version))
! 395: {
! 396: fprintf(stderr, "unknown maximum TLS version: %s\n", optarg);
! 397: return 1;
! 398: }
! 399: continue;
! 400: case 'v':
! 401: if (!enum_from_name(tls_numeric_version_names, optarg,
! 402: &min_version))
! 403: {
! 404: fprintf(stderr, "unknown TLS version: %s\n", optarg);
! 405: return 1;
! 406: }
! 407: max_version = min_version;
! 408: continue;
! 409: case 'n':
! 410: flags |= TLS_FLAG_CLIENT_AUTH_OPTIONAL;
! 411: continue;
1.1 misho 412: default:
413: usage(stderr, argv[0]);
414: return 1;
415: }
416: break;
417: }
418: if (!port || !address)
419: {
420: usage(stderr, argv[0]);
421: return 1;
422: }
1.1.1.2 ! misho 423: host = host_create_from_dns(address, family, port);
1.1 misho 424: if (!host)
425: {
426: DBG1(DBG_TLS, "resolving hostname %s failed", address);
427: return 1;
428: }
429: server = identification_create_from_string(address);
430: cache = tls_cache_create(100, 30);
431: if (listen)
432: {
1.1.1.2 ! misho 433: res = serve(host, server, client, times, cache, min_version,
! 434: max_version, flags);
1.1 misho 435: }
436: else
437: {
1.1.1.2 ! misho 438: DESTROY_IF(client);
1.1 misho 439: client = find_client_id();
1.1.1.2 ! misho 440: res = run_client(host, server, client, times, cache, min_version,
! 441: max_version, flags);
1.1 misho 442: DESTROY_IF(client);
443: }
444: cache->destroy(cache);
445: host->destroy(host);
446: server->destroy(server);
447: return res;
448: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>