From 472c8dbecb85705f39ad87fa07178c2cbb346ec3 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 15 Jul 2022 13:26:33 +0100 Subject: [PATCH 5/5] Add a test for session cache overflow Test sessions behave as we expect even in the case that an overflow occurs when adding a new session into the session cache. Related to CVE-2024-2511 Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24044) (cherry picked from commit ddead0935d77ba9b771d632ace61b145d7153f18) Signed-off-by: Liu-Ermeng --- .../OpensslLib/openssl/test/sslapitest.c | 133 +++++++++++++++++- 1 file changed, 130 insertions(+), 3 deletions(-) diff --git a/CryptoPkg/Library/OpensslLib/openssl/test/sslapitest.c b/CryptoPkg/Library/OpensslLib/openssl/test/sslapitest.c index 86f746c..74bc0af 100644 --- a/CryptoPkg/Library/OpensslLib/openssl/test/sslapitest.c +++ b/CryptoPkg/Library/OpensslLib/openssl/test/sslapitest.c @@ -6317,6 +6317,128 @@ static int test_ca_names(int tst) return testresult; } +/* + * Test that a session cache overflow works as expected + * Test 0: TLSv1.3, timeout on new session later than old session + * Test 1: TLSv1.2, timeout on new session later than old session + * Test 2: TLSv1.3, timeout on new session earlier than old session + * Test 3: TLSv1.2, timeout on new session earlier than old session + */ +#if !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2) +static int test_session_cache_overflow(int idx) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + int testresult = 0; + SSL_SESSION *sess = NULL; + +#ifdef OPENSSL_NO_TLS1_3 + /* If no TLSv1.3 available then do nothing in this case */ + if (idx % 2 == 0) + TEST_info("No TLSv1.3 available"); + return 1; +#endif +#ifdef OPENSSL_NO_TLS1_2 + /* If no TLSv1.2 available then do nothing in this case */ + if (idx % 2 == 1) + TEST_info("No TLSv1.2 available"); + return 1; +#endif + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), + TLS_client_method(), TLS1_VERSION, + (idx % 2 == 0) ? TLS1_3_VERSION + : TLS1_2_VERSION, + &sctx, &cctx, cert, privkey)) + || !TEST_true(SSL_CTX_set_options(sctx, SSL_OP_NO_TICKET))) + goto end; + + SSL_CTX_sess_set_get_cb(sctx, get_session_cb); + get_sess_val = NULL; + + SSL_CTX_sess_set_cache_size(sctx, 1); + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + if (idx > 1) { + sess = SSL_get_session(serverssl); + if (!TEST_ptr(sess)) + goto end; + + /* + * Cause this session to have a longer timeout than the next session to + * be added. + */ + if (!TEST_true(SSL_SESSION_set_timeout(sess, LONG_MAX / 2))) { + sess = NULL; + goto end; + } + sess = NULL; + } + + SSL_shutdown(serverssl); + SSL_shutdown(clientssl); + SSL_free(serverssl); + SSL_free(clientssl); + serverssl = clientssl = NULL; + + /* + * Session cache size is 1 and we already populated the cache with a session + * so the next connection should cause an overflow. + */ + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + /* + * The session we just negotiated may have been already removed from the + * internal cache - but we will return it anyway from our external cache. + */ + get_sess_val = SSL_get_session(serverssl); + if (!TEST_ptr(get_sess_val)) + goto end; + sess = SSL_get1_session(clientssl); + if (!TEST_ptr(sess)) + goto end; + + SSL_shutdown(serverssl); + SSL_shutdown(clientssl); + SSL_free(serverssl); + SSL_free(clientssl); + serverssl = clientssl = NULL; + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + if (!TEST_true(SSL_set_session(clientssl, sess))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + testresult = 1; + + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + SSL_SESSION_free(sess); + + return testresult; +} +#endif /* !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2) */ + /* * Test 0: Client sets servername and server acknowledges it (TLSv1.2) * Test 1: Client sets servername and server does not acknowledge it (TLSv1.2) @@ -6540,14 +6662,16 @@ static int test_multi_resume(int idx) #if defined(OPENSSL_NO_TLS1_2) if (idx == 4) - return TEST_skip("TLSv1.2 is disabled in this build"); + TEST_info("TLSv1.2 is disabled in this build"); + return 1; #else if (idx == 4) max_version = TLS1_2_VERSION; #endif -#if defined(OSSL_NO_USABLE_TLS1_3) +#if defined(OPENSSL_NO_TLS1_3) if (idx != 4) - return TEST_skip("No usable TLSv1.3 in this build"); + TEST_info("No usable TLSv1.3 in this build"); + return 1; #endif if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), @@ -6752,6 +6876,9 @@ int setup_tests(void) 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); +#endif +#if !defined(OPENSSL_NO_TLS1_2) || !defined(OPENSSL_NO_TLS1_3) + ADD_ALL_TESTS(test_session_cache_overflow, 4); #endif ADD_ALL_TESTS(test_info_callback, 6); ADD_ALL_TESTS(test_ssl_pending, 2); -- 2.33.0