From: Matt Caswell Date: Wed, 23 May 2018 11:11:15 +0000 (+0100) Subject: Add a bi-directional shutdown test X-Git-Tag: OpenSSL_1_1_1-pre9~221 X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=c748834ff7af7949519d2820a79ec35e809b5a71 Add a bi-directional shutdown test Reviewed-by: Bernd Edlinger Reviewed-by: Kurt Roeckx (Merged from https://github.com/openssl/openssl/pull/6340) --- diff --git a/test/sslapitest.c b/test/sslapitest.c index 61619a327c..d998e104d4 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -4972,6 +4972,128 @@ static int test_ticket_callbacks(int tst) return testresult; } +/* + * Test bi-directional shutdown. + * Test 0: TLSv1.2 + * Test 1: TLSv1.2, server continues to read/write after client shutdown + * Test 2: TLSv1.3, no pending NewSessionTicket messages + * Test 3: TLSv1.3, pending NewSessionTicket messages + * Test 4: TLSv1.3, server continues to read/write after client shutdown, client + * reads it + * Test 5: TLSv1.3, server continues to read/write after client shutdown, client + * doesn't read it + */ +static int test_shutdown(int tst) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + char msg[] = "A test message"; + char buf[80]; + size_t written, readbytes; + +#ifdef OPENSSL_NO_TLS1_2 + if (tst == 0) + return 1; +#endif +#ifdef OPENSSL_NO_TLS1_3 + if (tst != 0) + return 1; +#endif + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), + TLS_client_method(), + TLS1_VERSION, + (tst <= 1) ? TLS1_2_VERSION + : TLS1_3_VERSION, + &sctx, &cctx, cert, privkey)) + || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + if (tst == 3) { + if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + } else if (!TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) { + goto end; + } + + if (!TEST_int_eq(SSL_shutdown(clientssl), 0)) + goto end; + + if (tst >= 4) { + /* + * Reading on the server after the client has sent close_notify should + * fail and provide SSL_ERROR_ZERO_RETURN + */ + if (!TEST_false(SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)) + || !TEST_int_eq(SSL_get_error(serverssl, 0), + SSL_ERROR_ZERO_RETURN) + || !TEST_int_eq(SSL_get_shutdown(serverssl), + SSL_RECEIVED_SHUTDOWN) + /* + * Even though we're shutdown on receive we should still be + * able to write. + */ + || !TEST_true(SSL_write(serverssl, msg, sizeof(msg))) + || !TEST_int_eq(SSL_shutdown(serverssl), 1)) + goto end; + if (tst == 4) { + /* Should still be able to read data from server */ + if (!TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), + &readbytes)) + || !TEST_size_t_eq(readbytes, sizeof(msg)) + || !TEST_int_eq(memcmp(msg, buf, readbytes), 0)) + goto end; + } + } + + /* Writing on the client after sending close_notify shouldn't be possible */ + if (!TEST_false(SSL_write_ex(clientssl, msg, sizeof(msg), &written)) + /* + * Writing on the server after sending close_notify shouldn't be + * possible. + */ + || !TEST_false(SSL_write_ex(clientssl, msg, sizeof(msg), &written))) + goto end; + + if (tst < 4) { + /* + * For these tests the client has sent close_notify but it has not yet + * been received by the server. The server has not sent close_notify + * yet. + */ + if (!TEST_int_eq(SSL_shutdown(serverssl), 0) + || !TEST_int_eq(SSL_shutdown(clientssl), 1) + || !TEST_int_eq(SSL_shutdown(serverssl), 1)) + goto end; + } else { + /* + * In this test the client has sent close_notify and it has been + * received by the server which has responded with a close_notify. The + * client needs to read the close_notify sent by the server. When + * tst == 5, there is application data to be read first but this is + * discarded with a -1 return value. + */ + if (tst == 5 && !TEST_int_eq(SSL_shutdown(clientssl), -1)) + goto end; + if (!TEST_int_eq(SSL_shutdown(clientssl), 1)) + goto end; + } + + testresult = 1; + + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} + int setup_tests(void) { if (!TEST_ptr(cert = test_get_argument(0)) @@ -5069,6 +5191,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_ssl_pending, 2); ADD_ALL_TESTS(test_ssl_get_shared_ciphers, OSSL_NELEM(shared_ciphers_data)); ADD_ALL_TESTS(test_ticket_callbacks, 12); + ADD_ALL_TESTS(test_shutdown, 6); return 1; } diff --git a/test/ssltestlib.c b/test/ssltestlib.c index 2ef4b5d432..a055d3b5d2 100644 --- a/test/ssltestlib.c +++ b/test/ssltestlib.c @@ -680,12 +680,14 @@ int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, return 0; } -int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) +/* + * Create an SSL connection, but does not ready any post-handshake + * NewSessionTicket messages. + */ +int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want) { - int retc = -1, rets = -1, err, abortctr = 0, i; + int retc = -1, rets = -1, err, abortctr = 0; int clienterr = 0, servererr = 0; - unsigned char buf; - size_t readbytes; int isdtls = SSL_is_dtls(serverssl); do { @@ -738,6 +740,22 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) } } while (retc <=0 || rets <= 0); + return 1; +} + +/* + * Create an SSL connection including any post handshake NewSessionTicket + * messages. + */ +int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) +{ + int i; + unsigned char buf; + size_t readbytes; + + if (!create_bare_ssl_connection(serverssl, clientssl, want)) + return 0; + /* * We attempt to read some data on the client side which we expect to fail. * This will ensure we have received the NewSessionTicket in TLSv1.3 where diff --git a/test/ssltestlib.h b/test/ssltestlib.h index c96dff5216..31e3037446 100644 --- a/test/ssltestlib.h +++ b/test/ssltestlib.h @@ -18,6 +18,7 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm, char *privkeyfile); int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio); +int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want); int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want); void shutdown_ssl_connection(SSL *serverssl, SSL *clientssl);