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