From 7a301f08bc102179248173426ea15e00fa9211d1 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 2 Aug 2017 12:19:15 +0100 Subject: [PATCH] Test server side session caching In particular this covers the scenario mentioned in #4014 Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/4072) --- test/sslapitest.c | 181 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 153 insertions(+), 28 deletions(-) diff --git a/test/sslapitest.c b/test/sslapitest.c index afb119dd35..e44e9c1f4d 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -775,7 +775,18 @@ static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess) remove_called++; } -static int execute_test_session(int use_int_cache, int use_ext_cache) +static SSL_SESSION *get_sess_val = NULL; + +static SSL_SESSION *get_session_cb(SSL *ssl, const unsigned char *id, int len, + int *copy) +{ + *copy = 1; + return get_sess_val; +} + + +static int execute_test_session(int maxprot, int use_int_cache, + int use_ext_cache) { SSL_CTX *sctx = NULL, *cctx = NULL; SSL *serverssl1 = NULL, *clientssl1 = NULL; @@ -793,10 +804,12 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) &cctx, cert, privkey))) return 0; -#ifndef OPENSSL_NO_TLS1_2 - /* Only allow TLS1.2 so we can force a connection failure later */ - SSL_CTX_set_min_proto_version(cctx, TLS1_2_VERSION); -#endif + /* + * Only allow the max protocol version so we can force a connection failure + * later + */ + SSL_CTX_set_min_proto_version(cctx, maxprot); + SSL_CTX_set_max_proto_version(cctx, maxprot); /* Set up session cache */ if (use_ext_cache) { @@ -822,11 +835,10 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) /* Should fail because it should already be in the cache */ if (use_int_cache && !TEST_false(SSL_CTX_add_session(cctx, sess1))) goto end; - if (use_ext_cache && !TEST_int_eq(new_called, 1) - && !TEST_int_eq(remove_called, 0)) + if (use_ext_cache + && (!TEST_int_eq(new_called, 1) || !TEST_int_eq(remove_called, 0))) goto end; -#if !defined(OPENSSL_NO_TLS1_3) new_called = remove_called = 0; if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl2, &clientssl2, NULL, NULL)) @@ -836,20 +848,31 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) || !TEST_true(SSL_session_reused(clientssl2))) goto end; - /* - * In TLSv1.3 we should have created a new session even though we have - * resumed. The original session should also have been removed. - */ - if (use_ext_cache && !TEST_int_eq(new_called, 1) - && !TEST_int_eq(remove_called, 1)) - goto end; + if (maxprot == TLS1_3_VERSION) { + /* + * In TLSv1.3 we should have created a new session even though we have + * resumed. The original session should also have been removed. + */ + if (use_ext_cache + && (!TEST_int_eq(new_called, 1) + || !TEST_int_eq(remove_called, 1))) + goto end; + } else { + /* + * In TLSv1.2 we expect to have resumed so no sessions added or + * removed. + */ + if (use_ext_cache + && (!TEST_int_eq(new_called, 0) + || !TEST_int_eq(remove_called, 0))) + goto end; + } SSL_SESSION_free(sess1); if (!TEST_ptr(sess1 = SSL_get1_session(clientssl2))) goto end; shutdown_ssl_connection(serverssl2, clientssl2); serverssl2 = clientssl2 = NULL; -#endif new_called = remove_called = 0; if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl2, @@ -861,8 +884,8 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) if (!TEST_ptr(sess2 = SSL_get1_session(clientssl2))) goto end; - if (use_ext_cache && !TEST_int_eq(new_called, 1) - && !TEST_int_eq(remove_called, 0)) + if (use_ext_cache + && (!TEST_int_eq(new_called, 1) || !TEST_int_eq(remove_called, 0))) goto end; new_called = remove_called = 0; @@ -872,8 +895,8 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) */ if (!TEST_true(SSL_set_session(clientssl2, sess1))) goto end; - if (use_ext_cache && !TEST_int_eq(new_called, 0) - && !TEST_int_eq(remove_called, 1)) + if (use_ext_cache + && (!TEST_int_eq(new_called, 0) || !TEST_int_eq(remove_called, 1))) goto end; if (!TEST_ptr_eq(SSL_get_session(clientssl2), sess1)) goto end; @@ -890,11 +913,11 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) if (!TEST_false(SSL_CTX_remove_session(cctx, sess2))) goto end; - if (use_ext_cache && !TEST_int_eq(new_called, 0) - && !TEST_int_eq(remove_called, 1)) + if (use_ext_cache + && (!TEST_int_eq(new_called, 0) || !TEST_int_eq(remove_called, 1))) goto end; -#if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_2) +#if !defined(OPENSSL_NO_TLS1_1) new_called = remove_called = 0; /* Force a connection failure */ SSL_CTX_set_max_proto_version(sctx, TLS1_1_VERSION); @@ -907,8 +930,8 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) goto end; /* We should have automatically removed the session from the cache */ - if (use_ext_cache && !TEST_int_eq(new_called, 0) - && !TEST_int_eq(remove_called, 1)) + if (use_ext_cache + && (!TEST_int_eq(new_called, 0) || !TEST_int_eq(remove_called, 1))) goto end; /* Should succeed because it should not already be in the cache */ @@ -916,6 +939,81 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) goto end; #endif + /* Now do some tests for server side caching */ + if (use_ext_cache) { + SSL_CTX_sess_set_new_cb(cctx, NULL); + SSL_CTX_sess_set_remove_cb(cctx, NULL); + SSL_CTX_sess_set_new_cb(sctx, new_session_cb); + SSL_CTX_sess_set_remove_cb(sctx, remove_session_cb); + SSL_CTX_sess_set_get_cb(sctx, get_session_cb); + get_sess_val = NULL; + } + + SSL_CTX_set_session_cache_mode(cctx, 0); + /* Internal caching is the default on the server side */ + if (!use_int_cache) + SSL_CTX_set_session_cache_mode(sctx, + SSL_SESS_CACHE_SERVER + | SSL_SESS_CACHE_NO_INTERNAL_STORE); + + SSL_free(serverssl1); + SSL_free(clientssl1); + serverssl1 = clientssl1 = NULL; + SSL_free(serverssl2); + SSL_free(clientssl2); + serverssl2 = clientssl2 = NULL; + SSL_SESSION_free(sess1); + sess1 = NULL; + SSL_SESSION_free(sess2); + sess2 = NULL; + + SSL_CTX_set_max_proto_version(sctx, maxprot); + SSL_CTX_set_options(sctx, SSL_OP_NO_TICKET); + new_called = remove_called = 0; + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, + NULL, NULL)) + || !TEST_true(create_ssl_connection(serverssl1, clientssl1, + SSL_ERROR_NONE)) + || !TEST_ptr(sess1 = SSL_get1_session(clientssl1)) + || !TEST_ptr(sess2 = SSL_get1_session(serverssl1))) + goto end; + + /* Should fail because it should already be in the cache */ + if (use_int_cache && !TEST_false(SSL_CTX_add_session(sctx, sess2))) + goto end; + + if (use_ext_cache) { + SSL_SESSION *tmp = sess2; + + if (!TEST_int_eq(new_called, 1) || !TEST_int_eq(remove_called, 0)) + goto end; + /* + * Delete the session from the internal cache to force a lookup from + * the external cache. We take a copy first because + * SSL_CTX_remove_session() also marks the session as non-resumable. + */ + if (use_int_cache + && (!TEST_ptr(tmp = SSL_SESSION_dup(sess2)) + || !TEST_true(SSL_CTX_remove_session(sctx, sess2)))) + goto end; + sess2 = tmp; + } + + new_called = remove_called = 0; + get_sess_val = sess2; + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl2, + &clientssl2, NULL, NULL)) + || !TEST_true(SSL_set_session(clientssl2, sess1)) + || !TEST_true(create_ssl_connection(serverssl2, clientssl2, + SSL_ERROR_NONE)) + || !TEST_true(SSL_session_reused(clientssl2))) + goto end; + + if (use_ext_cache + && (!TEST_int_eq(new_called, 0) + || !TEST_int_eq(remove_called, 0))) + goto end; + testresult = 1; end: @@ -937,17 +1035,44 @@ static int execute_test_session(int use_int_cache, int use_ext_cache) static int test_session_with_only_int_cache(void) { - return execute_test_session(1, 0); +#ifndef OPENSSL_NO_TLS1_3 + if (!execute_test_session(TLS1_3_VERSION, 1, 0)) + return 0; +#endif + +#ifndef OPENSSL_NO_TLS1_2 + return execute_test_session(TLS1_2_VERSION, 1, 0); +#else + return 1; +#endif } static int test_session_with_only_ext_cache(void) { - return execute_test_session(0, 1); +#ifndef OPENSSL_NO_TLS1_3 + if (!execute_test_session(TLS1_3_VERSION, 0, 1)) + return 0; +#endif + +#ifndef OPENSSL_NO_TLS1_2 + return execute_test_session(TLS1_2_VERSION, 0, 1); +#else + return 1; +#endif } static int test_session_with_both_cache(void) { - return execute_test_session(1, 1); +#ifndef OPENSSL_NO_TLS1_3 + if (!execute_test_session(TLS1_3_VERSION, 1, 1)) + return 0; +#endif + +#ifndef OPENSSL_NO_TLS1_2 + return execute_test_session(TLS1_2_VERSION, 1, 1); +#else + return 1; +#endif } #define USE_NULL 0 -- GitLab