summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsing <>2025-02-01 12:21:52 +0000
committerjsing <>2025-02-01 12:21:52 +0000
commit4192f5457954534fbfd22f2b04a5407172f87b04 (patch)
treebeda1132fc8d58dcda1cfeb8baa351700b208238
parentca5eb817689340c9e11f21f75b2eede73622ad2e (diff)
downloadopenbsd-4192f5457954534fbfd22f2b04a5407172f87b04.tar.gz
openbsd-4192f5457954534fbfd22f2b04a5407172f87b04.tar.bz2
openbsd-4192f5457954534fbfd22f2b04a5407172f87b04.zip
Add regress coverage for TLS renegotiation.
-rw-r--r--src/regress/lib/libssl/renegotiation/Makefile18
-rw-r--r--src/regress/lib/libssl/renegotiation/renegotiation_test.c542
2 files changed, 560 insertions, 0 deletions
diff --git a/src/regress/lib/libssl/renegotiation/Makefile b/src/regress/lib/libssl/renegotiation/Makefile
new file mode 100644
index 0000000000..dd1eaa3ab9
--- /dev/null
+++ b/src/regress/lib/libssl/renegotiation/Makefile
@@ -0,0 +1,18 @@
1# $OpenBSD: Makefile,v 1.1 2025/02/01 12:21:52 jsing Exp $
2
3PROG= renegotiation_test
4LDADD= -lssl -lcrypto
5DPADD= ${LIBSSL} ${LIBCRYPTO}
6WARNINGS= Yes
7CFLAGS+= -DLIBRESSL_INTERNAL -Werror
8
9REGRESS_TARGETS= \
10 regress-renegotiation-test
11
12regress-renegotiation-test: ${PROG}
13 ./renegotiation_test \
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/renegotiation/renegotiation_test.c b/src/regress/lib/libssl/renegotiation/renegotiation_test.c
new file mode 100644
index 0000000000..4a80ef61ea
--- /dev/null
+++ b/src/regress/lib/libssl/renegotiation/renegotiation_test.c
@@ -0,0 +1,542 @@
1/* $OpenBSD: renegotiation_test.c,v 1.1 2025/02/01 12:21:52 jsing Exp $ */
2/*
3 * Copyright (c) 2020,2025 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
30int tls_client_alert;
31
32static void
33hexdump(const unsigned char *buf, size_t len)
34{
35 size_t i;
36
37 for (i = 1; i <= len; i++)
38 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
39
40 if (len % 8)
41 fprintf(stderr, "\n");
42}
43
44static SSL *
45tls_client(BIO *rbio, BIO *wbio)
46{
47 SSL_CTX *ssl_ctx = NULL;
48 SSL *ssl = NULL;
49
50 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
51 errx(1, "client context");
52
53 if ((ssl = SSL_new(ssl_ctx)) == NULL)
54 errx(1, "client ssl");
55
56 BIO_up_ref(rbio);
57 BIO_up_ref(wbio);
58
59 SSL_set_bio(ssl, rbio, wbio);
60
61 SSL_CTX_free(ssl_ctx);
62
63 return ssl;
64}
65
66static SSL *
67tls_server(BIO *rbio, BIO *wbio)
68{
69 SSL_CTX *ssl_ctx = NULL;
70 SSL *ssl = NULL;
71
72 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
73 errx(1, "server context");
74
75 SSL_CTX_set_dh_auto(ssl_ctx, 2);
76
77 if (SSL_CTX_use_certificate_file(ssl_ctx, server_cert_file,
78 SSL_FILETYPE_PEM) != 1) {
79 fprintf(stderr, "FAIL: Failed to load server certificate");
80 goto failure;
81 }
82 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, server_key_file,
83 SSL_FILETYPE_PEM) != 1) {
84 fprintf(stderr, "FAIL: Failed to load server private key");
85 goto failure;
86 }
87
88 if ((ssl = SSL_new(ssl_ctx)) == NULL)
89 errx(1, "server ssl");
90
91 BIO_up_ref(rbio);
92 BIO_up_ref(wbio);
93
94 SSL_set_bio(ssl, rbio, wbio);
95
96 failure:
97 SSL_CTX_free(ssl_ctx);
98
99 return ssl;
100}
101
102static int
103ssl_error(SSL *ssl, const char *name, const char *desc, int ssl_ret)
104{
105 int ssl_err;
106
107 ssl_err = SSL_get_error(ssl, ssl_ret);
108
109 if (ssl_err == SSL_ERROR_WANT_READ) {
110 return 1;
111 } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
112 return 1;
113 } else if (ssl_err == SSL_ERROR_SYSCALL && errno == 0) {
114 /* Yup, this is apparently a thing... */
115 } else {
116 if (tls_client_alert != 0 &&
117 ERR_GET_REASON(ERR_peek_error()) >= SSL_AD_REASON_OFFSET)
118 return 0;
119 fprintf(stderr, "FAIL: %s %s failed - ssl err = %d, errno = %d\n",
120 name, desc, ssl_err, errno);
121 ERR_print_errors_fp(stderr);
122 return 0;
123 }
124
125 return 1;
126}
127
128static int
129do_connect(SSL *ssl, const char *name, int *done)
130{
131 int ssl_ret;
132
133 if ((ssl_ret = SSL_connect(ssl)) == 1) {
134 fprintf(stderr, "INFO: %s connect done\n", name);
135 *done = 1;
136 return 1;
137 }
138
139 return ssl_error(ssl, name, "connect", ssl_ret);
140}
141
142static int
143do_accept(SSL *ssl, const char *name, int *done)
144{
145 int ssl_ret;
146
147 if ((ssl_ret = SSL_accept(ssl)) == 1) {
148 fprintf(stderr, "INFO: %s accept done\n", name);
149 *done = 1;
150 return 1;
151 }
152
153 return ssl_error(ssl, name, "accept", ssl_ret);
154}
155
156static int
157do_read(SSL *ssl, const char *name, int *done)
158{
159 uint8_t buf[512];
160 int ssl_ret;
161
162 if ((ssl_ret = SSL_read(ssl, buf, sizeof(buf))) > 0) {
163 fprintf(stderr, "INFO: %s read done\n", name);
164 if (debug > 1)
165 hexdump(buf, ssl_ret);
166 *done = 1;
167 return 1;
168 }
169
170 return ssl_error(ssl, name, "read", ssl_ret);
171}
172
173static int
174do_write(SSL *ssl, const char *name, int *done)
175{
176 const uint8_t buf[] = "Hello, World!\n";
177 int ssl_ret;
178
179 if ((ssl_ret = SSL_write(ssl, buf, sizeof(buf))) > 0) {
180 fprintf(stderr, "INFO: %s write done\n", name);
181 *done = 1;
182 return 1;
183 }
184
185 return ssl_error(ssl, name, "write", ssl_ret);
186}
187
188static int
189do_shutdown(SSL *ssl, const char *name, int *done)
190{
191 int ssl_ret;
192
193 ssl_ret = SSL_shutdown(ssl);
194 if (ssl_ret == 1) {
195 fprintf(stderr, "INFO: %s shutdown done\n", name);
196 *done = 1;
197 return 1;
198 }
199 return ssl_error(ssl, name, "shutdown", ssl_ret);
200}
201
202typedef int (*ssl_func)(SSL *ssl, const char *name, int *done);
203
204static int
205do_client_server_loop(SSL *client, ssl_func client_func, SSL *server,
206 ssl_func server_func)
207{
208 int client_done = 0, server_done = 0;
209 int i = 0;
210
211 do {
212 if (!client_done) {
213 if (debug)
214 fprintf(stderr, "DEBUG: client loop\n");
215 if (!client_func(client, "client", &client_done))
216 return 0;
217 }
218 if (!server_done) {
219 if (debug)
220 fprintf(stderr, "DEBUG: server loop\n");
221 if (!server_func(server, "server", &server_done))
222 return 0;
223 }
224 } while (i++ < 100 && (!client_done || !server_done));
225
226 if (!client_done || !server_done)
227 fprintf(stderr, "FAIL: gave up\n");
228
229 return client_done && server_done;
230}
231
232struct tls_reneg_test {
233 const unsigned char *desc;
234 int ssl_max_proto_version;
235 long ssl_client_options;
236 long ssl_server_options;
237 int renegotiate_client;
238 int renegotiate_server;
239 int want_alert;
240 int want_failure;
241};
242
243static const struct tls_reneg_test tls_reneg_tests[] = {
244 {
245 .desc = "TLSv1.2 - Renegotiation permitted, no renegotiation",
246 .ssl_max_proto_version = TLS1_2_VERSION,
247 },
248 {
249 .desc = "TLSv1.2 - Renegotiation permitted, server initiated "
250 "renegotiation",
251 .ssl_max_proto_version = TLS1_2_VERSION,
252 .renegotiate_server = 1,
253 },
254 {
255 .desc = "TLSv1.2 - Renegotiation permitted, client initiated "
256 "renegotiation",
257 .ssl_max_proto_version = TLS1_2_VERSION,
258 .renegotiate_client = 1,
259 },
260 {
261 .desc = "TLSv1.2 - Renegotiation permitted, server and client "
262 "initiated renegotiation",
263 .ssl_max_proto_version = TLS1_2_VERSION,
264 .renegotiate_client = 1,
265 .renegotiate_server = 1,
266 },
267 {
268 .desc = "TLSv1.2 - Client renegotiation not permitted, server "
269 "initiated renegotiation",
270 .ssl_max_proto_version = TLS1_2_VERSION,
271 .ssl_server_options = SSL_OP_NO_CLIENT_RENEGOTIATION,
272 .renegotiate_server = 1,
273 .want_alert = 1,
274 },
275 {
276 .desc = "TLSv1.2 - Client renegotiation not permitted, client "
277 "initiated renegotiation",
278 .ssl_max_proto_version = TLS1_2_VERSION,
279 .ssl_server_options = SSL_OP_NO_CLIENT_RENEGOTIATION,
280 .renegotiate_client = 1,
281 .want_alert = 1,
282 },
283 {
284 .desc = "TLSv1.3 - No renegotiation supported, no renegotiation",
285 .ssl_max_proto_version = TLS1_3_VERSION,
286 },
287 {
288 .desc = "TLSv1.3 - No renegotiation supported, server "
289 "initiated renegotiation",
290 .ssl_max_proto_version = TLS1_3_VERSION,
291 .renegotiate_server = 1,
292 .want_failure = 1,
293 },
294 {
295 .desc = "TLSv1.3 - No renegotiation supported, client "
296 "initiated renegotiation",
297 .ssl_max_proto_version = TLS1_3_VERSION,
298 .renegotiate_client = 1,
299 .want_failure = 1,
300 },
301};
302
303#define N_TLS_RENEG_TESTS (sizeof(tls_reneg_tests) / sizeof(*tls_reneg_tests))
304
305static void
306tls_client_info_callback(const SSL *ssl, int where, int value)
307{
308 if (where == SSL_CB_READ_ALERT) {
309 fprintf(stderr, "INFO: client read %s alert - %s\n",
310 SSL_alert_type_string_long(value),
311 SSL_alert_desc_string_long(value));
312 tls_client_alert = value;
313 }
314}
315
316static int
317tls_check_reneg(SSL *client, SSL *server, int client_pending,
318 int server_pending, long client_num_reneg, long server_num_reneg)
319{
320 if (debug) {
321 fprintf(stderr, "DEBUG: client - pending = %d, num reneg = %ld\n",
322 SSL_renegotiate_pending(client), SSL_num_renegotiations(client));
323 fprintf(stderr, "DEBUG: server - pending = %d, num reneg = %ld\n",
324 SSL_renegotiate_pending(server), SSL_num_renegotiations(server));
325 }
326
327 if (SSL_renegotiate_pending(client) != client_pending) {
328 fprintf(stderr, "FAIL: client SSL_renegotiate_pending() = %d, want %d\n",
329 SSL_renegotiate_pending(client), client_pending);
330 return 0;
331 }
332 if (SSL_renegotiate_pending(server) != server_pending) {
333 fprintf(stderr, "FAIL: server SSL_renegotiate_pending() = %d, want %d\n",
334 SSL_renegotiate_pending(server), server_pending);
335 return 0;
336 }
337 if (SSL_num_renegotiations(client) != client_num_reneg) {
338 fprintf(stderr, "FAIL: client SSL_num_renegotiations() = %ld, want %ld\n",
339 SSL_num_renegotiations(client), client_num_reneg);
340 return 0;
341 }
342 if (SSL_num_renegotiations(server) != server_num_reneg) {
343 fprintf(stderr, "FAIL: server SSL_num_renegotiations() = %ld, want %ld\n",
344 SSL_num_renegotiations(server), server_num_reneg);
345 return 0;
346 }
347 return 1;
348}
349
350static int
351tls_reneg_test(const struct tls_reneg_test *trt)
352{
353 BIO *client_wbio = NULL, *server_wbio = NULL;
354 SSL *client = NULL, *server = NULL;
355 int failed = 1;
356
357 fprintf(stderr, "\n== Testing %s... ==\n", trt->desc);
358
359 if ((client_wbio = BIO_new(BIO_s_mem())) == NULL)
360 goto failure;
361 if (BIO_set_mem_eof_return(client_wbio, -1) <= 0)
362 goto failure;
363
364 if ((server_wbio = BIO_new(BIO_s_mem())) == NULL)
365 goto failure;
366 if (BIO_set_mem_eof_return(server_wbio, -1) <= 0)
367 goto failure;
368
369 if ((client = tls_client(server_wbio, client_wbio)) == NULL)
370 goto failure;
371
372 SSL_set_options(client, trt->ssl_client_options);
373
374 if ((server = tls_server(client_wbio, server_wbio)) == NULL)
375 goto failure;
376
377 SSL_set_options(server, trt->ssl_server_options);
378 if (!SSL_set_max_proto_version(server, trt->ssl_max_proto_version))
379 goto failure;
380
381 SSL_set_info_callback(client, tls_client_info_callback);
382
383 if (!do_client_server_loop(client, do_connect, server, do_accept)) {
384 fprintf(stderr, "FAIL: client and server handshake failed\n");
385 goto failure;
386 }
387
388 if (!do_client_server_loop(client, do_write, server, do_read)) {
389 fprintf(stderr, "FAIL: client write and server read failed\n");
390 goto failure;
391 }
392
393 if (!do_client_server_loop(client, do_read, server, do_write)) {
394 fprintf(stderr, "FAIL: client read and server write failed\n");
395 goto failure;
396 }
397
398 if (!tls_check_reneg(client, server, 0, 0, 0, 0))
399 goto failure;
400
401 if (trt->renegotiate_server) {
402 /*
403 * Trigger renegotiation from the server - this results in the
404 * server sending a HelloRequest, then waiting for the client to
405 * respond with a ClientHello.
406 */
407 if (!SSL_renegotiate(server)) {
408 if (!trt->want_failure) {
409 fprintf(stderr, "FAIL: server renegotiation failed\n");
410 goto failure;
411 }
412 goto done;
413 }
414 if (trt->want_failure) {
415 fprintf(stderr, "FAIL: server renegotiation should have failed\n");
416 goto failure;
417 }
418
419 if (!tls_check_reneg(client, server, 0, 1, 0, 0))
420 goto failure;
421
422 if (!do_client_server_loop(client, do_read, server, do_write)) {
423 fprintf(stderr, "FAIL: client read and server write failed\n");
424 goto failure;
425 }
426
427 if (!tls_check_reneg(client, server, 1, 1, 1, 1))
428 goto failure;
429
430 if (!do_client_server_loop(client, do_write, server, do_read)) {
431 if (!trt->want_alert) {
432 fprintf(stderr, "FAIL: client write and server read failed\n");
433 goto failure;
434 }
435 if (tls_client_alert != (SSL3_AL_FATAL << 8 |
436 SSL_AD_NO_RENEGOTIATION)) {
437 fprintf(stderr, "FAIL: client alert = %x, want %x\n",
438 tls_client_alert, SSL3_AL_FATAL << 8 |
439 SSL_AD_NO_RENEGOTIATION);
440 }
441 goto done;
442 }
443 if (trt->want_alert) {
444 fprintf(stderr, "FAIL: server renegotiation should have alerted\n");
445 goto failure;
446 }
447
448 if (!tls_check_reneg(client, server, 0, 0, 1, 1))
449 goto failure;
450 }
451
452 SSL_clear_num_renegotiations(client);
453 SSL_clear_num_renegotiations(server);
454
455 if (trt->renegotiate_client) {
456 /*
457 * Trigger renegotiation from the client - this results in the
458 * client sending a ClientHello.
459 */
460 if (!SSL_renegotiate(client)) {
461 if (!trt->want_failure) {
462 fprintf(stderr, "FAIL: client renegotiation failed\n");
463 goto failure;
464 }
465 goto done;
466 }
467 if (trt->want_failure) {
468 fprintf(stderr, "FAIL: client renegotiation should have failed\n");
469 goto failure;
470 }
471
472 if (!do_client_server_loop(client, do_read, server, do_write)) {
473 fprintf(stderr, "FAIL: client read and server write failed\n");
474 goto failure;
475 }
476
477 if (!tls_check_reneg(client, server, 1, 0, 1, 0))
478 goto failure;
479
480 if (!do_client_server_loop(client, do_write, server, do_read)) {
481 if (!trt->want_alert) {
482 fprintf(stderr, "FAIL: client write and server read failed\n");
483 goto failure;
484 }
485 if (tls_client_alert != (SSL3_AL_FATAL << 8 |
486 SSL_AD_NO_RENEGOTIATION)) {
487 fprintf(stderr, "FAIL: client alert = %x, want %x\n",
488 tls_client_alert, SSL3_AL_FATAL << 8 |
489 SSL_AD_NO_RENEGOTIATION);
490 }
491 goto done;
492 }
493 if (trt->want_alert) {
494 fprintf(stderr, "FAIL: server renegotiation should have alerted\n");
495 goto failure;
496 }
497
498 if (!tls_check_reneg(client, server, 0, 0, 1, 0))
499 goto failure;
500 }
501
502 if (!do_client_server_loop(client, do_shutdown, server, do_shutdown)) {
503 fprintf(stderr, "FAIL: client and server shutdown failed\n");
504 goto failure;
505 }
506
507 done:
508 fprintf(stderr, "INFO: Done!\n");
509
510 failed = 0;
511
512 failure:
513 BIO_free(client_wbio);
514 BIO_free(server_wbio);
515
516 SSL_free(client);
517 SSL_free(server);
518
519 return failed;
520}
521
522int
523main(int argc, char **argv)
524{
525 int failed = 0;
526 size_t i;
527
528 if (argc != 4) {
529 fprintf(stderr, "usage: %s keyfile certfile cafile\n",
530 argv[0]);
531 exit(1);
532 }
533
534 server_key_file = argv[1];
535 server_cert_file = argv[2];
536 server_ca_file = argv[3];
537
538 for (i = 0; i < N_TLS_RENEG_TESTS; i++)
539 failed |= tls_reneg_test(&tls_reneg_tests[i]);
540
541 return failed;
542}