Extend the testing of resetting/clearing an SSL connection

SSL_clear() explicitly clears an SSL object to enable it to be reused.
You can have a similar effect by calling SSL_set_accept_state() or
SSL_set_connect_state(). We extend the testing of SSL_clear() to use these
other methods. We also ensure we test the case where we have unread
bufferred data that needs to be cleared.

Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23256)
This commit is contained in:
Matt Caswell 2024-01-16 13:53:30 +00:00
parent f7f2b665cf
commit 5de8c49d6c

View File

@ -7035,22 +7035,45 @@ static int test_key_update_local_in_read(int tst)
}
#endif /* OSSL_NO_USABLE_TLS1_3 */
/*
* Test clearing a connection via SSL_clear(), or resetting it via
* SSL_set_connect_state()/SSL_set_accept_state()
* Test 0: SSL_set_connect_state, TLSv1.3
* Test 1: SSL_set_connect_state, TLSv1.2
* Test 2: SSL_set_accept_state, TLSv1.3
* Test 3: SSL_set_accept_state, TLSv1.2
* Test 4: SSL_clear (client), TLSv1.3
* Test 5: SSL_clear (client), TLSv1.2
* Test 6: SSL_clear (server), TLSv1.3
* Test 7: SSL_clear (server), TLSv1.2
*/
static int test_ssl_clear(int idx)
{
SSL_CTX *cctx = NULL, *sctx = NULL;
SSL *clientssl = NULL, *serverssl = NULL;
SSL *writer, *reader;
int testresult = 0;
int tls12test, servertest, cleartest;
size_t written, readbytes;
const char *msg = "Hello World";
unsigned char buf[5];
tls12test = idx & 1;
idx >>= 1;
servertest = idx & 1;
idx >>= 1;
cleartest = idx & 1;
#ifdef OPENSSL_NO_TLS1_2
if (idx == 1)
return 1;
if (tls12test == 1)
return TEST_skip("No TLSv1.2 in this build");
#endif
/* Create an initial connection */
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
TLS_client_method(), TLS1_VERSION, 0,
&sctx, &cctx, cert, privkey))
|| (idx == 1
|| (tls12test
&& !TEST_true(SSL_CTX_set_max_proto_version(cctx,
TLS1_2_VERSION)))
|| !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
@ -7059,20 +7082,68 @@ static int test_ssl_clear(int idx)
SSL_ERROR_NONE)))
goto end;
if (servertest) {
writer = clientssl;
reader = serverssl;
} else {
writer = serverssl;
reader = clientssl;
}
/* Write some data */
if (!TEST_true(SSL_write_ex(writer, msg, strlen(msg), &written))
|| written != strlen(msg))
goto end;
/*
* Read a partial record. The remaining buffered data should be cleared by
* the subsequent clear/reset
*/
if (!TEST_true(SSL_read_ex(reader, buf, sizeof(buf), &readbytes))
|| readbytes != sizeof(buf))
goto end;
SSL_shutdown(clientssl);
SSL_shutdown(serverssl);
SSL_free(serverssl);
serverssl = NULL;
/* Clear clientssl - we're going to reuse the object */
if (!TEST_true(SSL_clear(clientssl)))
goto end;
/* Reset/clear one SSL object in order to reuse it. We free the other one */
if (servertest) {
if (cleartest) {
if (!TEST_true(SSL_clear(serverssl)))
goto end;
} else {
SSL_set_accept_state(serverssl);
}
/*
* A peculiarity of SSL_clear() is that it does not clear the session.
* This is intended behaviour so that a client can create a new
* connection and reuse the session. But this doesn't make much sense
* on the server side - and causes incorrect behaviour due to the
* handshake failing (even though the documentation does say SSL_clear()
* is supposed to work on the server side). We clear the session
* explicitly - although note that the documentation for
* SSL_set_session() says that its only useful for clients!
*/
if (!TEST_true(SSL_set_session(serverssl, NULL)))
goto end;
SSL_free(clientssl);
clientssl = NULL;
} else {
if (cleartest) {
if (!TEST_true(SSL_clear(clientssl)))
goto end;
} else {
SSL_set_connect_state(clientssl);
}
SSL_free(serverssl);
serverssl = NULL;
}
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
NULL, NULL))
|| !TEST_true(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_NONE))
|| !TEST_true(SSL_session_reused(clientssl)))
|| !TEST_true(servertest || SSL_session_reused(clientssl)))
goto end;
SSL_shutdown(clientssl);
@ -11637,7 +11708,7 @@ int setup_tests(void)
ADD_ALL_TESTS(test_key_update_local_in_write, 2);
ADD_ALL_TESTS(test_key_update_local_in_read, 2);
#endif
ADD_ALL_TESTS(test_ssl_clear, 2);
ADD_ALL_TESTS(test_ssl_clear, 8);
ADD_ALL_TESTS(test_max_fragment_len_ext, OSSL_NELEM(max_fragment_len_test));
#if !defined(OPENSSL_NO_SRP) && !defined(OPENSSL_NO_TLS1_2)
ADD_ALL_TESTS(test_srp, 6);