Skip to content

Commit 4057388

Browse files
committed
fixup! Add client-side session caching
1 parent 8cca50c commit 4057388

4 files changed

Lines changed: 180 additions & 1 deletion

File tree

ssl/ssl_lib.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,6 +2218,8 @@ int SSL_accept(SSL *s)
22182218
int SSL_connect(SSL *s)
22192219
{
22202220
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
2221+
SSL_SESSION *sess;
2222+
int ret;
22212223

22222224
#ifndef OPENSSL_NO_QUIC
22232225
if (IS_QUIC(s))
@@ -2232,6 +2234,24 @@ int SSL_connect(SSL *s)
22322234
SSL_set_connect_state(s);
22332235
}
22342236

2237+
/*
2238+
* If a client session has not been set, and there's a previous session
2239+
* that matches the cache_id, use it.
2240+
* If the cache is not set to client mode, an error will be raised, so
2241+
* pop off as necessary.
2242+
*/
2243+
if (sc->session == NULL && sc->cache_id != NULL) {
2244+
ERR_set_mark();
2245+
sess = SSL_get1_previous_client_session(s);
2246+
ERR_pop_to_mark();
2247+
if (sess != NULL) {
2248+
ret = SSL_set_session(s, sess);
2249+
SSL_SESSION_free(sess);
2250+
if (!ret)
2251+
return ret;
2252+
}
2253+
}
2254+
22352255
return SSL_do_handshake(s);
22362256
}
22372257

test/build.info

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ IF[{- !$disabled{tests} -}]
6969
ca_internals_test bio_tfo_test membio_test bio_dgram_test list_test \
7070
fips_version_test x509_test hpke_test pairwise_fail_test \
7171
nodefltctxtest evp_xof_test x509_load_cert_file_test bio_meth_test \
72-
x509_acert_test x509_req_test strtoultest bio_pw_callback_test
72+
x509_acert_test x509_req_test strtoultest bio_pw_callback_test \
73+
client_cache_test
7374

7475
IF[{- !$disabled{'rpk'} -}]
7576
PROGRAMS{noinst}=rpktest
@@ -583,6 +584,10 @@ IF[{- !$disabled{tests} -}]
583584
INCLUDE[rpktest]=../include ../apps/include ..
584585
DEPEND[rpktest]=../libcrypto ../libssl libtestutil.a
585586

587+
SOURCE[client_cache_test]=client_cache_test.c helpers/ssltestlib.c
588+
INCLUDE[client_cache_test]=../include ../apps/include ..
589+
DEPEND[client_cache_test]=../libcrypto ../libssl libtestutil.a
590+
586591
SOURCE[defltfips_test]=defltfips_test.c
587592
INCLUDE[defltfips_test]=../include ../apps/include
588593
DEPEND[defltfips_test]=../libcrypto libtestutil.a

test/client_cache_test.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. You can obtain a copy
6+
* in the file LICENSE in the source distribution or at
7+
* https://www.openssl.org/source/license.html
8+
*/
9+
#include <openssl/ssl.h>
10+
11+
#include "helpers/ssltestlib.h"
12+
#include "internal/dane.h"
13+
#include "testutil.h"
14+
15+
static char *certsdir = NULL;
16+
static char *cert = NULL;
17+
static char *privkey = NULL;
18+
static OSSL_LIB_CTX *libctx = NULL;
19+
20+
static const unsigned char sid_ctx[] = "sid";
21+
static const unsigned char cache_id[] = "this is a test";
22+
static const unsigned char cache_id2[] = "different";
23+
24+
static int test_client_cache(void)
25+
{
26+
int ret = 0;
27+
SSL_CTX *cctx = NULL, *sctx = NULL;
28+
SSL *cssl = NULL, *sssl = NULL;
29+
SSL_SESSION *sess1 = NULL, *sess2 = NULL, *sess3 = NULL;
30+
31+
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
32+
TLS_client_method(), TLS1_VERSION, TLS1_2_VERSION,
33+
&sctx, &cctx, cert, privkey)))
34+
return 0;
35+
36+
SSL_CTX_set_session_cache_mode(cctx, SSL_SESS_CACHE_CLIENT);
37+
if (!TEST_true(SSL_CTX_set_session_id_context(sctx, sid_ctx, sizeof(sid_ctx)))
38+
|| !TEST_true(SSL_CTX_set_session_id_context(cctx, sid_ctx, sizeof(sid_ctx))))
39+
goto end;
40+
41+
/* Initial connection */
42+
if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL, NULL))
43+
|| !TEST_true(SSL_set1_cache_id(cssl, cache_id, sizeof(cache_id)))
44+
|| !TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE))
45+
|| !TEST_ptr(sess1 = SSL_get1_session(cssl)))
46+
goto end;
47+
48+
shutdown_ssl_connection(sssl, cssl);
49+
sssl = cssl = NULL;
50+
51+
/* Test automatic assignment of session when client has cache_id set */
52+
if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL, NULL))
53+
|| !TEST_true(SSL_set1_cache_id(cssl, cache_id, sizeof(cache_id)))
54+
|| !TEST_ptr(sess2 = SSL_get1_previous_client_session(cssl))
55+
|| !TEST_ptr_eq(sess1, sess2)
56+
|| !TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE))
57+
|| !TEST_true(SSL_session_reused(cssl))
58+
|| !TEST_ptr(sess3 = SSL_get1_session(cssl))
59+
|| !TEST_ptr_eq(sess2, sess3))
60+
goto end;
61+
62+
shutdown_ssl_connection(sssl, cssl);
63+
sssl = cssl = NULL;
64+
65+
/* Ensure client is not resumed when no cache_id is set */
66+
if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL, NULL))
67+
|| !TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE))
68+
|| !TEST_false(SSL_session_reused(cssl)))
69+
goto end;
70+
71+
shutdown_ssl_connection(sssl, cssl);
72+
sssl = cssl = NULL;
73+
74+
/* Ensure client is not resumed when a different cache_id is set */
75+
if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL, NULL))
76+
|| !TEST_true(SSL_set1_cache_id(cssl, cache_id2, sizeof(cache_id2)))
77+
|| !TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE))
78+
|| !TEST_false(SSL_session_reused(cssl)))
79+
goto end;
80+
81+
shutdown_ssl_connection(sssl, cssl);
82+
sssl = cssl = NULL;
83+
84+
ret = 1;
85+
end:
86+
SSL_free(sssl);
87+
SSL_free(cssl);
88+
SSL_SESSION_free(sess1);
89+
SSL_SESSION_free(sess2);
90+
SSL_SESSION_free(sess3);
91+
SSL_CTX_free(sctx);
92+
SSL_CTX_free(cctx);
93+
return ret;
94+
}
95+
OPT_TEST_DECLARE_USAGE("certdir\n")
96+
97+
int setup_tests(void)
98+
{
99+
if (!test_skip_common_options()) {
100+
TEST_error("Error parsing test options\n");
101+
return 0;
102+
}
103+
104+
if (!TEST_ptr(certsdir = test_get_argument(0)))
105+
return 0;
106+
107+
cert = test_mk_file_path(certsdir, "servercert.pem");
108+
if (cert == NULL)
109+
goto err;
110+
111+
privkey = test_mk_file_path(certsdir, "serverkey.pem");
112+
if (privkey == NULL)
113+
goto err;
114+
115+
libctx = OSSL_LIB_CTX_new();
116+
if (libctx == NULL)
117+
goto err;
118+
119+
ADD_TEST(test_client_cache);
120+
return 1;
121+
122+
err:
123+
return 0;
124+
}
125+
126+
void cleanup_tests(void)
127+
{
128+
OPENSSL_free(cert);
129+
OPENSSL_free(privkey);
130+
OSSL_LIB_CTX_free(libctx);
131+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#! /usr/bin/env perl
2+
# Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
3+
#
4+
# Licensed under the Apache License 2.0 (the "License"). You may not use
5+
# this file except in compliance with the License. You can obtain a copy
6+
# in the file LICENSE in the source distribution or at
7+
# https://www.openssl.org/source/license.html
8+
9+
use OpenSSL::Test::Utils;
10+
use OpenSSL::Test qw/:DEFAULT srctop_dir bldtop_dir/;
11+
12+
BEGIN {
13+
setup("test_client_cache");
14+
}
15+
16+
use lib srctop_dir('Configurations');
17+
use lib bldtop_dir('.');
18+
19+
plan skip_all => "TLS is disabled in this OpenSSL build" if disabled("tls1") && disabled("tls1_1") && disabled("tls1_2");
20+
21+
plan tests => 1;
22+
23+
ok(run(test(["client_cache_test", srctop_dir("test", "certs")])), "running client_cache_test");

0 commit comments

Comments
 (0)