summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2021-10-23 14:34:10 +0000
committerjsing <>2021-10-23 14:34:10 +0000
commit29938589622ccf645f7dc926feb10e611775c666 (patch)
tree2b26bf7861c6aabf91e4e6042c83c70cdf6d2d2d /src
parent13e9f107004c047e24ff1034b8982d5514250dee (diff)
downloadopenbsd-29938589622ccf645f7dc926feb10e611775c666.tar.gz
openbsd-29938589622ccf645f7dc926feb10e611775c666.tar.bz2
openbsd-29938589622ccf645f7dc926feb10e611775c666.zip
Add a regress test for TLS client/server.
This currently exercises various combinations of TLS versions and their associated key exchange mechanisms. Note that this currently fails for TLSv1.0/TLSv1.1 with RSA KEX (to be fixed shortly). Over time all of the ssl regress should be moved into the dtls and tls regress tests.
Diffstat (limited to 'src')
-rw-r--r--src/regress/lib/libssl/Makefile3
-rw-r--r--src/regress/lib/libssl/tls/Makefile18
-rw-r--r--src/regress/lib/libssl/tls/tlstest.c476
3 files changed, 496 insertions, 1 deletions
diff --git a/src/regress/lib/libssl/Makefile b/src/regress/lib/libssl/Makefile
index 07a35d983d..ff06e0b0ba 100644
--- a/src/regress/lib/libssl/Makefile
+++ b/src/regress/lib/libssl/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.46 2021/08/30 17:34:32 tb Exp $ 1# $OpenBSD: Makefile,v 1.47 2021/10/23 14:34:10 jsing Exp $
2 2
3SUBDIR += asn1 3SUBDIR += asn1
4SUBDIR += buffer 4SUBDIR += buffer
@@ -12,6 +12,7 @@ SUBDIR += record
12SUBDIR += record_layer 12SUBDIR += record_layer
13SUBDIR += server 13SUBDIR += server
14SUBDIR += ssl 14SUBDIR += ssl
15SUBDIR += tls
15SUBDIR += tlsext 16SUBDIR += tlsext
16SUBDIR += tlslegacy 17SUBDIR += tlslegacy
17SUBDIR += key_schedule 18SUBDIR += key_schedule
diff --git a/src/regress/lib/libssl/tls/Makefile b/src/regress/lib/libssl/tls/Makefile
new file mode 100644
index 0000000000..a22cdcdeb2
--- /dev/null
+++ b/src/regress/lib/libssl/tls/Makefile
@@ -0,0 +1,18 @@
1# $OpenBSD: Makefile,v 1.1 2021/10/23 14:34:10 jsing Exp $
2
3PROG= tlstest
4LDADD= -lssl -lcrypto
5DPADD= ${LIBSSL} ${LIBCRYPTO}
6WARNINGS= Yes
7CFLAGS+= -DLIBRESSL_INTERNAL -Werror
8
9REGRESS_TARGETS= \
10 regress-tlstest
11
12regress-tlstest: ${PROG}
13 ./tlstest \
14 ${.CURDIR}/../../libssl/certs/server.pem \
15 ${.CURDIR}/../../libssl/certs/server.pem \
16 ${.CURDIR}/../../libssl/certs/ca.pem
17
18.include <bsd.regress.mk>
diff --git a/src/regress/lib/libssl/tls/tlstest.c b/src/regress/lib/libssl/tls/tlstest.c
new file mode 100644
index 0000000000..5c72717e6e
--- /dev/null
+++ b/src/regress/lib/libssl/tls/tlstest.c
@@ -0,0 +1,476 @@
1/* $OpenBSD: tlstest.c,v 1.1 2021/10/23 14:34:10 jsing Exp $ */
2/*
3 * Copyright (c) 2020, 2021 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <err.h>
19
20#include <openssl/bio.h>
21#include <openssl/err.h>
22#include <openssl/ssl.h>
23
24const char *server_ca_file;
25const char *server_cert_file;
26const char *server_key_file;
27
28int debug = 0;
29
30static void
31hexdump(const unsigned char *buf, size_t len)
32{
33 size_t i;
34
35 for (i = 1; i <= len; i++)
36 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
37
38 if (len % 8)
39 fprintf(stderr, "\n");
40}
41
42static SSL *
43tls_client(BIO *rbio, BIO *wbio)
44{
45 SSL_CTX *ssl_ctx = NULL;
46 SSL *ssl = NULL;
47
48 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
49 errx(1, "client context");
50
51 if ((ssl = SSL_new(ssl_ctx)) == NULL)
52 errx(1, "client ssl");
53
54 BIO_up_ref(rbio);
55 BIO_up_ref(wbio);
56
57 SSL_set_bio(ssl, rbio, wbio);
58
59 SSL_CTX_free(ssl_ctx);
60
61 return ssl;
62}
63
64static SSL *
65tls_server(BIO *rbio, BIO *wbio)
66{
67 SSL_CTX *ssl_ctx = NULL;
68 SSL *ssl = NULL;
69
70 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
71 errx(1, "server context");
72
73 SSL_CTX_set_dh_auto(ssl_ctx, 2);
74
75 if (SSL_CTX_use_certificate_file(ssl_ctx, server_cert_file,
76 SSL_FILETYPE_PEM) != 1) {
77 fprintf(stderr, "FAIL: Failed to load server certificate");
78 goto failure;
79 }
80 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, server_key_file,
81 SSL_FILETYPE_PEM) != 1) {
82 fprintf(stderr, "FAIL: Failed to load server private key");
83 goto failure;
84 }
85
86 if ((ssl = SSL_new(ssl_ctx)) == NULL)
87 errx(1, "server ssl");
88
89 BIO_up_ref(rbio);
90 BIO_up_ref(wbio);
91
92 SSL_set_bio(ssl, rbio, wbio);
93
94 failure:
95 SSL_CTX_free(ssl_ctx);
96
97 return ssl;
98}
99
100static int
101ssl_error(SSL *ssl, const char *name, const char *desc, int ssl_ret)
102{
103 int ssl_err;
104
105 ssl_err = SSL_get_error(ssl, ssl_ret);
106
107 if (ssl_err == SSL_ERROR_WANT_READ) {
108 return 1;
109 } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
110 return 1;
111 } else if (ssl_err == SSL_ERROR_SYSCALL && errno == 0) {
112 /* Yup, this is apparently a thing... */
113 } else {
114 fprintf(stderr, "FAIL: %s %s failed - ssl err = %d, errno = %d\n",
115 name, desc, ssl_err, errno);
116 ERR_print_errors_fp(stderr);
117 return 0;
118 }
119
120 return 1;
121}
122
123static int
124do_connect(SSL *ssl, const char *name, int *done)
125{
126 int ssl_ret;
127
128 if ((ssl_ret = SSL_connect(ssl)) == 1) {
129 fprintf(stderr, "INFO: %s connect done\n", name);
130 *done = 1;
131 return 1;
132 }
133
134 return ssl_error(ssl, name, "connect", ssl_ret);
135}
136
137static int
138do_accept(SSL *ssl, const char *name, int *done)
139{
140 int ssl_ret;
141
142 if ((ssl_ret = SSL_accept(ssl)) == 1) {
143 fprintf(stderr, "INFO: %s accept done\n", name);
144 *done = 1;
145 return 1;
146 }
147
148 return ssl_error(ssl, name, "accept", ssl_ret);
149}
150
151static int
152do_read(SSL *ssl, const char *name, int *done)
153{
154 uint8_t buf[512];
155 int ssl_ret;
156
157 if ((ssl_ret = SSL_read(ssl, buf, sizeof(buf))) > 0) {
158 fprintf(stderr, "INFO: %s read done\n", name);
159 if (debug > 1)
160 hexdump(buf, ssl_ret);
161 *done = 1;
162 return 1;
163 }
164
165 return ssl_error(ssl, name, "read", ssl_ret);
166}
167
168static int
169do_write(SSL *ssl, const char *name, int *done)
170{
171 const uint8_t buf[] = "Hello, World!\n";
172 int ssl_ret;
173
174 if ((ssl_ret = SSL_write(ssl, buf, sizeof(buf))) > 0) {
175 fprintf(stderr, "INFO: %s write done\n", name);
176 *done = 1;
177 return 1;
178 }
179
180 return ssl_error(ssl, name, "write", ssl_ret);
181}
182
183static int
184do_shutdown(SSL *ssl, const char *name, int *done)
185{
186 int ssl_ret;
187
188 ssl_ret = SSL_shutdown(ssl);
189 if (ssl_ret == 1) {
190 fprintf(stderr, "INFO: %s shutdown done\n", name);
191 *done = 1;
192 return 1;
193 }
194 return ssl_error(ssl, name, "shutdown", ssl_ret);
195}
196
197typedef int (*ssl_func)(SSL *ssl, const char *name, int *done);
198
199static int
200do_client_server_loop(SSL *client, ssl_func client_func, SSL *server,
201 ssl_func server_func)
202{
203 int client_done = 0, server_done = 0;
204 int i = 0;
205
206 do {
207 if (!client_done) {
208 if (debug)
209 fprintf(stderr, "DEBUG: client loop\n");
210 if (!client_func(client, "client", &client_done))
211 return 0;
212 }
213 if (!server_done) {
214 if (debug)
215 fprintf(stderr, "DEBUG: server loop\n");
216 if (!server_func(server, "server", &server_done))
217 return 0;
218 }
219 } while (i++ < 100 && (!client_done || !server_done));
220
221 if (!client_done || !server_done)
222 fprintf(stderr, "FAIL: gave up\n");
223
224 return client_done && server_done;
225}
226
227struct tls_test {
228 const unsigned char *desc;
229 const SSL_METHOD *(*client_method)(void);
230 uint16_t client_min_version;
231 uint16_t client_max_version;
232 const char *client_ciphers;
233 const SSL_METHOD *(*server_method)(void);
234 uint16_t server_min_version;
235 uint16_t server_max_version;
236 const char *server_ciphers;
237};
238
239static const struct tls_test tls_tests[] = {
240 {
241 .desc = "Default client and server",
242 },
243 {
244 .desc = "Default client and TLSv1.2 server",
245 .server_max_version = TLS1_2_VERSION,
246 },
247 {
248 .desc = "Default client and TLSv1.1 server",
249 .server_max_version = TLS1_1_VERSION,
250 },
251 {
252 .desc = "Default client and TLSv1.0 server",
253 .server_max_version = TLS1_VERSION,
254 },
255 {
256 .desc = "Default client and default server with ECDHE KEX",
257 .server_ciphers = "ECDHE-RSA-AES128-SHA",
258 },
259 {
260 .desc = "Default client and TLSv1.2 server with ECDHE KEX",
261 .server_max_version = TLS1_2_VERSION,
262 .server_ciphers = "ECDHE-RSA-AES128-SHA",
263 },
264 {
265 .desc = "Default client and TLSv1.1 server with ECDHE KEX",
266 .server_max_version = TLS1_1_VERSION,
267 .server_ciphers = "ECDHE-RSA-AES128-SHA",
268 },
269 {
270 .desc = "Default client and TLSv1.0 server with ECDHE KEX",
271 .server_max_version = TLS1_VERSION,
272 .server_ciphers = "ECDHE-RSA-AES128-SHA",
273 },
274 {
275 .desc = "Default client and default server with DHE KEX",
276 .server_ciphers = "DHE-RSA-AES128-SHA",
277 },
278 {
279 .desc = "Default client and TLSv1.2 server with DHE KEX",
280 .server_max_version = TLS1_2_VERSION,
281 .server_ciphers = "DHE-RSA-AES128-SHA",
282 },
283 {
284 .desc = "Default client and TLSv1.1 server with DHE KEX",
285 .server_max_version = TLS1_1_VERSION,
286 .server_ciphers = "DHE-RSA-AES128-SHA",
287 },
288 {
289 .desc = "Default client and TLSv1.0 server with DHE KEX",
290 .server_max_version = TLS1_VERSION,
291 .server_ciphers = "DHE-RSA-AES128-SHA",
292 },
293 {
294 .desc = "Default client and default server with RSA KEX",
295 .server_ciphers = "AES128-SHA",
296 },
297 {
298 .desc = "Default client and TLSv1.2 server with RSA KEX",
299 .server_max_version = TLS1_2_VERSION,
300 .server_ciphers = "AES128-SHA",
301 },
302 {
303 .desc = "Default client and TLSv1.1 server with RSA KEX",
304 .server_max_version = TLS1_1_VERSION,
305 .server_ciphers = "AES128-SHA",
306 },
307 {
308 .desc = "Default client and TLSv1.0 server with RSA KEX",
309 .server_max_version = TLS1_VERSION,
310 .server_ciphers = "AES128-SHA",
311 },
312 {
313 .desc = "TLSv1.2 client and default server",
314 .client_max_version = TLS1_2_VERSION,
315 },
316 {
317 .desc = "TLSv1.1 client and default server",
318 .client_max_version = TLS1_1_VERSION,
319 },
320 {
321 .desc = "TLSv1.0 client and default server",
322 .client_max_version = TLS1_VERSION,
323 },
324 {
325 .desc = "TLSv1.2 client and default server with ECDHE KEX",
326 .client_max_version = TLS1_2_VERSION,
327 .client_ciphers = "ECDHE-RSA-AES128-SHA",
328 },
329 {
330 .desc = "TLSv1.1 client and default server with ECDHE KEX",
331 .client_max_version = TLS1_1_VERSION,
332 .client_ciphers = "ECDHE-RSA-AES128-SHA",
333 },
334 {
335 .desc = "TLSv1.0 client and default server with ECDHE KEX",
336 .client_max_version = TLS1_VERSION,
337 .client_ciphers = "ECDHE-RSA-AES128-SHA",
338 },
339 {
340 .desc = "TLSv1.2 client and default server with DHE KEX",
341 .server_max_version = TLS1_2_VERSION,
342 .client_ciphers = "DHE-RSA-AES128-SHA",
343 },
344 {
345 .desc = "TLSv1.1 client and default server with DHE KEX",
346 .client_max_version = TLS1_1_VERSION,
347 .client_ciphers = "DHE-RSA-AES128-SHA",
348 },
349 {
350 .desc = "TLSv1.0 client and default server with DHE KEX",
351 .client_max_version = TLS1_VERSION,
352 .client_ciphers = "DHE-RSA-AES128-SHA",
353 },
354 {
355 .desc = "TLSv1.2 client and default server with RSA KEX",
356 .client_max_version = TLS1_2_VERSION,
357 .client_ciphers = "AES128-SHA",
358 },
359 {
360 .desc = "TLSv1.1 client and default server with RSA KEX",
361 .client_max_version = TLS1_1_VERSION,
362 .client_ciphers = "AES128-SHA",
363 },
364 {
365 .desc = "TLSv1.0 client and default server with RSA KEX",
366 .client_max_version = TLS1_VERSION,
367 .client_ciphers = "AES128-SHA",
368 },
369};
370
371#define N_TLS_TESTS (sizeof(tls_tests) / sizeof(*tls_tests))
372
373static int
374tlstest(const struct tls_test *tt)
375{
376 BIO *client_wbio = NULL, *server_wbio = NULL;
377 SSL *client = NULL, *server = NULL;
378 int failed = 1;
379
380 fprintf(stderr, "\n== Testing %s... ==\n", tt->desc);
381
382 if ((client_wbio = BIO_new(BIO_s_mem())) == NULL)
383 goto failure;
384 if (BIO_set_mem_eof_return(client_wbio, -1) <= 0)
385 goto failure;
386
387 if ((server_wbio = BIO_new(BIO_s_mem())) == NULL)
388 goto failure;
389 if (BIO_set_mem_eof_return(server_wbio, -1) <= 0)
390 goto failure;
391
392 if ((client = tls_client(server_wbio, client_wbio)) == NULL)
393 goto failure;
394 if (tt->client_min_version != 0) {
395 if (!SSL_set_min_proto_version(client, tt->client_min_version))
396 goto failure;
397 }
398 if (tt->client_max_version != 0) {
399 if (!SSL_set_max_proto_version(client, tt->client_max_version))
400 goto failure;
401 }
402 if (tt->client_ciphers != NULL) {
403 if (!SSL_set_cipher_list(client, tt->client_ciphers))
404 goto failure;
405 }
406
407 if ((server = tls_server(client_wbio, server_wbio)) == NULL)
408 goto failure;
409 if (tt->server_min_version != 0) {
410 if (!SSL_set_min_proto_version(server, tt->server_min_version))
411 goto failure;
412 }
413 if (tt->server_max_version != 0) {
414 if (!SSL_set_max_proto_version(server, tt->server_max_version))
415 goto failure;
416 }
417 if (tt->server_ciphers != NULL) {
418 if (!SSL_set_cipher_list(server, tt->server_ciphers))
419 goto failure;
420 }
421
422 if (!do_client_server_loop(client, do_connect, server, do_accept)) {
423 fprintf(stderr, "FAIL: client and server handshake failed\n");
424 goto failure;
425 }
426
427 if (!do_client_server_loop(client, do_write, server, do_read)) {
428 fprintf(stderr, "FAIL: client write and server read I/O failed\n");
429 goto failure;
430 }
431
432 if (!do_client_server_loop(client, do_read, server, do_write)) {
433 fprintf(stderr, "FAIL: client read and server write I/O failed\n");
434 goto failure;
435 }
436
437 if (!do_client_server_loop(client, do_shutdown, server, do_shutdown)) {
438 fprintf(stderr, "FAIL: client and server shutdown failed\n");
439 goto failure;
440 }
441
442 fprintf(stderr, "INFO: Done!\n");
443
444 failed = 0;
445
446 failure:
447 BIO_free(client_wbio);
448 BIO_free(server_wbio);
449
450 SSL_free(client);
451 SSL_free(server);
452
453 return failed;
454}
455
456int
457main(int argc, char **argv)
458{
459 int failed = 0;
460 size_t i;
461
462 if (argc != 4) {
463 fprintf(stderr, "usage: %s keyfile certfile cafile\n",
464 argv[0]);
465 exit(1);
466 }
467
468 server_key_file = argv[1];
469 server_cert_file = argv[2];
470 server_ca_file = argv[3];
471
472 for (i = 0; i < N_TLS_TESTS; i++)
473 failed |= tlstest(&tls_tests[i]);
474
475 return failed;
476}