Skip to content

Commit 656cf69

Browse files
committed
MDEV-40445 TLS session resumption
in fact it was already on in the server, so this only enables statistics to see it in SHOW STATUS, adds tests, and updates C/C to match. Assisted-By: Claude:claude-5-opus
1 parent a1b3f98 commit 656cf69

11 files changed

Lines changed: 334 additions & 11 deletions

libmariadb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
--error 0,1,127
2+
--exec openssl version > /dev/null 2> /dev/null
3+
if ($sys_errno)
4+
{
5+
--skip Requires openssl executable
6+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Open a TLS connection to the server, save the negotiated session, then
2+
# open a second one offering that session. Echoes RESUMED or FULL, and how
3+
# the server side counters moved.
4+
#
5+
# $tls_opt - extra "openssl s_client" options, e.g. -tls1_3
6+
#
7+
# -ign_eof is needed to get a session at all: a TLS 1.3 server sends its
8+
# tickets after the handshake, and without it s_client is gone before they
9+
# arrive. It then has to be given a reason to stop, hence the packet - one
10+
# byte long, which is not a login packet, so the connection ends there
11+
# instead of s_client waiting for input forever. s_client exits non zero
12+
# for the same reason.
13+
14+
--let $tls_session= $MYSQL_TMP_DIR/tls_session.pem
15+
--let $s_client= openssl s_client -connect 127.0.0.1:$MASTER_MYPORT -starttls mysql -ign_eof $tls_opt
16+
--let $status= SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME=
17+
18+
eval set @hits=($status 'Ssl_session_cache_hits'),
19+
@stored=($status 'Ssl_used_session_cache_entries');
20+
21+
--echo openssl s_client -ign_eof $tls_opt -sess_out tls_session.pem
22+
--error 1
23+
--exec printf '\001\000\000\001\000' | $s_client -sess_out $tls_session >/dev/null 2>&1
24+
25+
--echo openssl s_client -ign_eof $tls_opt -sess_in tls_session.pem
26+
--exec printf '\001\000\000\001\000' | $s_client -sess_in $tls_session 2>/dev/null | grep -q '^Reused' && echo RESUMED || echo FULL
27+
28+
eval select ($status 'Ssl_session_cache_hits') - @hits as 'hits increase',
29+
($status 'Ssl_used_session_cache_entries') - @stored as 'stored on the server';

mysql-test/main/openssl_1.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ variable_name LIKE 'SSL_CALLBACK_CACHE_HITS';
7070
END$$
7171
SELECT variable_name, variable_value FROM thread_status;
7272
variable_name variable_value
73-
SSL_ACCEPTS #
7473
SSL_CALLBACK_CACHE_HITS #
74+
SSL_ACCEPTS #
7575
DROP TABLE thread_status;
7676
SET GLOBAL event_scheduler=0;
7777
CREATE TABLE t1(a int);

mysql-test/main/ssl.result

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Ssl_cipher_list
66
Ssl_default_timeout
77
Ssl_server_not_after
88
Ssl_server_not_before
9+
Ssl_sessions_reused
910
Ssl_verify_depth
1011
Ssl_verify_mode
1112
Ssl_version
@@ -14,6 +15,7 @@ Ssl_cipher_list
1415
Ssl_default_timeout
1516
Ssl_server_not_after
1617
Ssl_server_not_before
18+
Ssl_sessions_reused
1719
Ssl_verify_depth
1820
Ssl_verify_mode
1921
Ssl_version
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#
2+
# TLS session resumption statistics
3+
#
4+
#
5+
# TLS 1.2, session ticket
6+
#
7+
set @hits=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits'),
8+
@stored=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries');
9+
openssl s_client -ign_eof -tls1_2 -sess_out tls_session.pem
10+
openssl s_client -ign_eof -tls1_2 -sess_in tls_session.pem
11+
RESUMED
12+
select (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits') - @hits as 'hits increase',
13+
(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries') - @stored as 'stored on the server';
14+
hits increase stored on the server
15+
1 0
16+
#
17+
# TLS 1.2, session id. Unlike a ticket, this session is also stored in
18+
# the server side cache, so it is the only case that fills it up
19+
#
20+
set @hits=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits'),
21+
@stored=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries');
22+
openssl s_client -ign_eof -tls1_2 -no_ticket -sess_out tls_session.pem
23+
openssl s_client -ign_eof -tls1_2 -no_ticket -sess_in tls_session.pem
24+
RESUMED
25+
select (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits') - @hits as 'hits increase',
26+
(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries') - @stored as 'stored on the server';
27+
hits increase stored on the server
28+
1 1
29+
#
30+
# TLS 1.3, session ticket. No session id resumption exists in TLS 1.3,
31+
# so like a TLS 1.2 ticket it leaves nothing on the server
32+
#
33+
set @hits=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits'),
34+
@stored=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries');
35+
openssl s_client -ign_eof -tls1_3 -sess_out tls_session.pem
36+
openssl s_client -ign_eof -tls1_3 -sess_in tls_session.pem
37+
RESUMED
38+
select (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits') - @hits as 'hits increase',
39+
(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries') - @stored as 'stored on the server';
40+
hits increase stored on the server
41+
1 0
42+
#
43+
# A session cannot be resumed across FLUSH SSL: it replaces the
44+
# acceptor context, and with it the session cache and the ticket keys
45+
#
46+
set @hits=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits'),
47+
@stored=(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries');
48+
openssl s_client -ign_eof -tls1_3 -sess_out tls_session.pem
49+
openssl s_client -ign_eof -tls1_3 -sess_in tls_session.pem
50+
RESUMED
51+
select (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits') - @hits as 'hits increase',
52+
(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries') - @stored as 'stored on the server';
53+
hits increase stored on the server
54+
1 0
55+
FLUSH SSL;
56+
openssl s_client -ign_eof -tls1_3 -sess_in tls_session.pem
57+
FULL
58+
# and it resets the acceptor statistics
59+
select (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_session_cache_hits') as 'Ssl_session_cache_hits',
60+
(SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'Ssl_used_session_cache_entries') as 'Ssl_used_session_cache_entries';
61+
Ssl_session_cache_hits Ssl_used_session_cache_entries
62+
0 0
63+
# End of 13.2 tests
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--echo #
2+
--echo # TLS session resumption statistics
3+
--echo #
4+
5+
--source include/have_ssl_communication.inc
6+
--source include/not_embedded.inc
7+
--source include/not_windows.inc
8+
--source include/have_openssl_binary.inc
9+
10+
if (`SELECT @@version_ssl_library NOT LIKE 'OpenSSL%'`)
11+
{
12+
--skip Requires a server built against OpenSSL
13+
}
14+
15+
# Driven by openssl s_client rather than by a MariaDB client, to verify the
16+
# server against an independent TLS implementation.
17+
18+
--echo #
19+
--echo # TLS 1.2, session ticket
20+
--echo #
21+
--let $tls_opt= -tls1_2
22+
--source include/tls_session_resume.inc
23+
24+
--echo #
25+
--echo # TLS 1.2, session id. Unlike a ticket, this session is also stored in
26+
--echo # the server side cache, so it is the only case that fills it up
27+
--echo #
28+
--let $tls_opt= -tls1_2 -no_ticket
29+
--source include/tls_session_resume.inc
30+
31+
--echo #
32+
--echo # TLS 1.3, session ticket. No session id resumption exists in TLS 1.3,
33+
--echo # so like a TLS 1.2 ticket it leaves nothing on the server
34+
--echo #
35+
--let $tls_opt= -tls1_3
36+
--source include/tls_session_resume.inc
37+
38+
--echo #
39+
--echo # A session cannot be resumed across FLUSH SSL: it replaces the
40+
--echo # acceptor context, and with it the session cache and the ticket keys
41+
--echo #
42+
--let $tls_opt= -tls1_3
43+
--source include/tls_session_resume.inc
44+
FLUSH SSL;
45+
--echo openssl s_client -ign_eof $tls_opt -sess_in tls_session.pem
46+
--exec printf '\001\000\000\001\000' | $s_client -sess_in $tls_session 2>/dev/null | grep -q '^Reused' && echo RESUMED || echo FULL
47+
48+
--echo # and it resets the acceptor statistics
49+
eval select ($status 'Ssl_session_cache_hits') as 'Ssl_session_cache_hits',
50+
($status 'Ssl_used_session_cache_entries') as 'Ssl_used_session_cache_entries';
51+
52+
--remove_file $tls_session
53+
54+
--echo # End of 13.2 tests
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[tls12]
2+
loose-tls-version=TLSv1.2
3+
4+
[tls_any]
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#
2+
# TLS session resumption, client side
3+
#
4+
#
5+
# a second connection of the same configuration resumes
6+
#
7+
connect ssl1,localhost,root,,,,,SSL;
8+
connection ssl1;
9+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
10+
Variable_name Value
11+
Ssl_sessions_reused 0
12+
disconnect ssl1;
13+
connect ssl2,localhost,root,,,,,SSL;
14+
connection ssl2;
15+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
16+
Variable_name Value
17+
Ssl_sessions_reused 1
18+
disconnect ssl2;
19+
#
20+
# a resumed connection has a session again, so it keeps working. With
21+
# TLS 1.3 the server issues a new ticket, before that the session we
22+
# resumed with is put back
23+
#
24+
connect ssl3,localhost,root,,,,,SSL;
25+
connection ssl3;
26+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
27+
Variable_name Value
28+
Ssl_sessions_reused 1
29+
disconnect ssl3;
30+
#
31+
# a resumed handshake verifies no certificate at all, so a session
32+
# must not be offered to a differently configured connection. Both
33+
# the cipher and the transport are part of the cache key.
34+
#
35+
connect ssl4,localhost,root,,,,,SSL SSL-CIPHER=ECDHE-RSA-AES128-GCM-SHA256;
36+
connection ssl4;
37+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
38+
Variable_name Value
39+
Ssl_sessions_reused 0
40+
disconnect ssl4;
41+
connect tcp1,127.0.0.1,root,,,$MASTER_MYPORT,,SSL TCP;
42+
connection tcp1;
43+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
44+
Variable_name Value
45+
Ssl_sessions_reused 0
46+
disconnect tcp1;
47+
#
48+
# and each of those configurations resumes on its own
49+
#
50+
connect tcp2,127.0.0.1,root,,,$MASTER_MYPORT,,SSL TCP;
51+
connection tcp2;
52+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
53+
Variable_name Value
54+
Ssl_sessions_reused 1
55+
disconnect tcp2;
56+
connection default;
57+
# End of 13.2 tests
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--echo #
2+
--echo # TLS session resumption, client side
3+
--echo #
4+
5+
--source include/have_ssl_communication.inc
6+
--source include/not_embedded.inc
7+
8+
# Every test gets its own mysqltest process, so the client side session
9+
# cache starts out empty here.
10+
11+
--echo #
12+
--echo # a second connection of the same configuration resumes
13+
--echo #
14+
connect ssl1,localhost,root,,,,,SSL;
15+
connection ssl1;
16+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
17+
disconnect ssl1;
18+
19+
connect ssl2,localhost,root,,,,,SSL;
20+
connection ssl2;
21+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
22+
disconnect ssl2;
23+
24+
--echo #
25+
--echo # a resumed connection has a session again, so it keeps working. With
26+
--echo # TLS 1.3 the server issues a new ticket, before that the session we
27+
--echo # resumed with is put back
28+
--echo #
29+
connect ssl3,localhost,root,,,,,SSL;
30+
connection ssl3;
31+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
32+
disconnect ssl3;
33+
34+
--echo #
35+
--echo # a resumed handshake verifies no certificate at all, so a session
36+
--echo # must not be offered to a differently configured connection. Both
37+
--echo # the cipher and the transport are part of the cache key.
38+
--echo #
39+
connect ssl4,localhost,root,,,,,SSL SSL-CIPHER=ECDHE-RSA-AES128-GCM-SHA256;
40+
connection ssl4;
41+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
42+
disconnect ssl4;
43+
44+
connect tcp1,127.0.0.1,root,,,$MASTER_MYPORT,,SSL TCP;
45+
connection tcp1;
46+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
47+
disconnect tcp1;
48+
49+
--echo #
50+
--echo # and each of those configurations resumes on its own
51+
--echo #
52+
connect tcp2,127.0.0.1,root,,,$MASTER_MYPORT,,SSL TCP;
53+
connection tcp2;
54+
SHOW SESSION STATUS LIKE 'Ssl_sessions_reused';
55+
disconnect tcp2;
56+
57+
connection default;
58+
59+
--echo # End of 13.2 tests

0 commit comments

Comments
 (0)