diff options
author | jsing <> | 2024-01-30 14:46:46 +0000 |
---|---|---|
committer | jsing <> | 2024-01-30 14:46:46 +0000 |
commit | 3339ea5d77ded48e0e41a12720882846912c2306 (patch) | |
tree | 5a80f006dd1186e196c14e6a59f87e3b8f50ccbc | |
parent | 30d39d87f7d79b965a5739bbd0f60511c67b140f (diff) | |
download | openbsd-3339ea5d77ded48e0e41a12720882846912c2306.tar.gz openbsd-3339ea5d77ded48e0e41a12720882846912c2306.tar.bz2 openbsd-3339ea5d77ded48e0e41a12720882846912c2306.zip |
Add a shutdown sequence regress test.
Some software relies on SSL_shutdown() returning 0 (indicating close-notify
sent) before returning 1 on a subsequent call (indicating close-notify sent
and received). It is worth noting that there is no guarantee that this will
occur in normal operation, as the peer could send a close-notify prior to
SSL_shutdown() being called.
This is currently failing for TLSv1.3.
-rw-r--r-- | src/regress/lib/libssl/shutdown/shutdowntest.c | 136 |
1 files changed, 133 insertions, 3 deletions
diff --git a/src/regress/lib/libssl/shutdown/shutdowntest.c b/src/regress/lib/libssl/shutdown/shutdowntest.c index 749ccaa435..5b83add359 100644 --- a/src/regress/lib/libssl/shutdown/shutdowntest.c +++ b/src/regress/lib/libssl/shutdown/shutdowntest.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: shutdowntest.c,v 1.2 2024/01/27 14:35:13 jsing Exp $ */ | 1 | /* $OpenBSD: shutdowntest.c,v 1.3 2024/01/30 14:46:46 jsing Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020, 2021, 2024 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2020, 2021, 2024 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -360,7 +360,7 @@ static const struct shutdown_test shutdown_tests[] = { | |||
360 | #define N_TLS_TESTS (sizeof(shutdown_tests) / sizeof(*shutdown_tests)) | 360 | #define N_TLS_TESTS (sizeof(shutdown_tests) / sizeof(*shutdown_tests)) |
361 | 361 | ||
362 | static int | 362 | static int |
363 | shutdowntest(uint16_t ssl_version, const char *ssl_version_name, | 363 | shutdown_test(uint16_t ssl_version, const char *ssl_version_name, |
364 | const struct shutdown_test *st) | 364 | const struct shutdown_test *st) |
365 | { | 365 | { |
366 | BIO *client_wbio = NULL, *server_wbio = NULL; | 366 | BIO *client_wbio = NULL, *server_wbio = NULL; |
@@ -479,6 +479,135 @@ shutdowntest(uint16_t ssl_version, const char *ssl_version_name, | |||
479 | return failed; | 479 | return failed; |
480 | } | 480 | } |
481 | 481 | ||
482 | static int | ||
483 | shutdown_sequence_test(uint16_t ssl_version, const char *ssl_version_name) | ||
484 | { | ||
485 | BIO *client_wbio = NULL, *server_wbio = NULL; | ||
486 | SSL *client = NULL, *server = NULL; | ||
487 | int shutdown, ret; | ||
488 | int failed = 1; | ||
489 | |||
490 | fprintf(stderr, "\n== Testing %s, shutdown sequence... ==\n", | ||
491 | ssl_version_name); | ||
492 | |||
493 | if ((client_wbio = BIO_new(BIO_s_mem())) == NULL) | ||
494 | goto failure; | ||
495 | if (BIO_set_mem_eof_return(client_wbio, -1) <= 0) | ||
496 | goto failure; | ||
497 | |||
498 | if ((server_wbio = BIO_new(BIO_s_mem())) == NULL) | ||
499 | goto failure; | ||
500 | if (BIO_set_mem_eof_return(server_wbio, -1) <= 0) | ||
501 | goto failure; | ||
502 | |||
503 | if ((client = tls_client(server_wbio, client_wbio)) == NULL) | ||
504 | goto failure; | ||
505 | if (!SSL_set_min_proto_version(client, ssl_version)) | ||
506 | goto failure; | ||
507 | if (!SSL_set_max_proto_version(client, ssl_version)) | ||
508 | goto failure; | ||
509 | |||
510 | if ((server = tls_server(client_wbio, server_wbio)) == NULL) | ||
511 | goto failure; | ||
512 | if (!SSL_set_min_proto_version(server, ssl_version)) | ||
513 | goto failure; | ||
514 | if (!SSL_set_max_proto_version(server, ssl_version)) | ||
515 | goto failure; | ||
516 | |||
517 | if (!do_client_server_loop(client, do_connect, server, do_accept)) { | ||
518 | fprintf(stderr, "FAIL: client and server handshake failed\n"); | ||
519 | goto failure; | ||
520 | } | ||
521 | |||
522 | if (!do_client_server_loop(client, do_write, server, do_read)) { | ||
523 | fprintf(stderr, "FAIL: client write and server read I/O failed\n"); | ||
524 | goto failure; | ||
525 | } | ||
526 | |||
527 | if (!do_client_server_loop(client, do_read, server, do_write)) { | ||
528 | fprintf(stderr, "FAIL: client read and server write I/O failed\n"); | ||
529 | goto failure; | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * Shutdown in lock step and check return value and shutdown flags. | ||
534 | * | ||
535 | * It is not documented, however some software relies on SSL_shutdown() | ||
536 | * to only send a close-notify on the first call, then indicate that a | ||
537 | * close-notify was received on a second (or later) call. | ||
538 | */ | ||
539 | |||
540 | if ((shutdown = SSL_get_shutdown(client)) != 0) { | ||
541 | fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n", | ||
542 | shutdown, 0); | ||
543 | goto failure; | ||
544 | } | ||
545 | if ((shutdown = SSL_get_shutdown(server)) != 0) { | ||
546 | fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n", | ||
547 | shutdown, 0); | ||
548 | goto failure; | ||
549 | } | ||
550 | |||
551 | if ((ret = SSL_shutdown(client)) != 0) { | ||
552 | fprintf(stderr, "FAIL: client SSL_shutdown() = %d, want %d\n", | ||
553 | ret, 0); | ||
554 | goto failure; | ||
555 | } | ||
556 | if ((shutdown = SSL_get_shutdown(client)) != SSL_SENT_SHUTDOWN) { | ||
557 | fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n", | ||
558 | shutdown, SSL_SENT_SHUTDOWN); | ||
559 | goto failure; | ||
560 | } | ||
561 | |||
562 | if ((ret = SSL_shutdown(server)) != 0) { | ||
563 | fprintf(stderr, "FAIL: server SSL_shutdown() = %d, want %d\n", | ||
564 | ret, 0); | ||
565 | goto failure; | ||
566 | } | ||
567 | if ((shutdown = SSL_get_shutdown(server)) != SSL_SENT_SHUTDOWN) { | ||
568 | fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n", | ||
569 | shutdown, SSL_SENT_SHUTDOWN); | ||
570 | goto failure; | ||
571 | } | ||
572 | |||
573 | if ((ret = SSL_shutdown(client)) != 1) { | ||
574 | fprintf(stderr, "FAIL: client SSL_shutdown() = %d, want %d\n", | ||
575 | ret, 0); | ||
576 | goto failure; | ||
577 | } | ||
578 | if ((shutdown = SSL_get_shutdown(client)) != | ||
579 | (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) { | ||
580 | fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n", | ||
581 | shutdown, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); | ||
582 | goto failure; | ||
583 | } | ||
584 | |||
585 | if ((ret = SSL_shutdown(server)) != 1) { | ||
586 | fprintf(stderr, "FAIL: server SSL_shutdown() = %d, want %d\n", | ||
587 | ret, 0); | ||
588 | goto failure; | ||
589 | } | ||
590 | if ((shutdown = SSL_get_shutdown(server)) != | ||
591 | (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) { | ||
592 | fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n", | ||
593 | shutdown, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); | ||
594 | goto failure; | ||
595 | } | ||
596 | |||
597 | fprintf(stderr, "INFO: Done!\n"); | ||
598 | |||
599 | failed = 0; | ||
600 | |||
601 | failure: | ||
602 | BIO_free(client_wbio); | ||
603 | BIO_free(server_wbio); | ||
604 | |||
605 | SSL_free(client); | ||
606 | SSL_free(server); | ||
607 | |||
608 | return failed; | ||
609 | } | ||
610 | |||
482 | struct ssl_version { | 611 | struct ssl_version { |
483 | uint16_t version; | 612 | uint16_t version; |
484 | const char *name; | 613 | const char *name; |
@@ -517,9 +646,10 @@ main(int argc, char **argv) | |||
517 | for (i = 0; i < N_SSL_VERSIONS; i++) { | 646 | for (i = 0; i < N_SSL_VERSIONS; i++) { |
518 | sv = &ssl_versions[i]; | 647 | sv = &ssl_versions[i]; |
519 | for (j = 0; j < N_TLS_TESTS; j++) { | 648 | for (j = 0; j < N_TLS_TESTS; j++) { |
520 | failed |= shutdowntest(sv->version, sv->name, | 649 | failed |= shutdown_test(sv->version, sv->name, |
521 | &shutdown_tests[j]); | 650 | &shutdown_tests[j]); |
522 | } | 651 | } |
652 | failed |= shutdown_sequence_test(sv->version, sv->name); | ||
523 | } | 653 | } |
524 | 654 | ||
525 | return failed; | 655 | return failed; |