File 0209-ssl-Enhance-connection_information.patch of Package erlang
From fab01fd44742cc3969f063db5ec2b8ccf5ec852a Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Fri, 23 Jan 2026 13:42:34 +0100
Subject: [PATCH] ssl: Enhance connection_information
Let session_resumption return correct information for TLS-1.2 also.
Although it was introduced for TLS-1.3 testing purposes,
where session resumption is not as observable as for TLS-1.2, it is
visible in the API and it makes more sense to make it work for TL-1.2
then to document that it does not.
closes #10470
---
lib/ssl/src/tls_dtls_client_connection.erl | 17 +-
lib/ssl/src/tls_dtls_server_connection.erl | 3 +-
lib/ssl/test/ssl_session_SUITE.erl | 191 +++++++++++----------
3 files changed, 118 insertions(+), 93 deletions(-)
diff --git a/lib/ssl/src/tls_dtls_client_connection.erl b/lib/ssl/src/tls_dtls_client_connection.erl
index 3601852d42..2e3c36fa89 100644
--- a/lib/ssl/src/tls_dtls_client_connection.erl
+++ b/lib/ssl/src/tls_dtls_client_connection.erl
@@ -461,7 +461,8 @@ handle_session(#server_hello{cipher_suite = CipherSuite},
Version, NewId, ConnectionStates, ProtoExt, Protocol0,
#state{session = Session,
handshake_env = #handshake_env{negotiated_protocol = CurrentProtocol} = HsEnv,
- connection_env = #connection_env{negotiated_version = ReqVersion} = CEnv} = State0) ->
+ connection_env = #connection_env{negotiated_version = ReqVersion} = CEnv}
+ = State0) ->
#{key_exchange := KeyAlgorithm} =
ssl_cipher_format:suite_bin_to_map(CipherSuite),
@@ -473,14 +474,18 @@ handle_session(#server_hello{cipher_suite = CipherSuite},
_ -> {ProtoExt =:= npn, Protocol0}
end,
+ IsNew = ssl_session:is_new(Session, NewId),
+
State = State0#state{connection_states = ConnectionStates,
- handshake_env = HsEnv#handshake_env{kex_algorithm = KeyAlgorithm,
- premaster_secret = PremasterSecret,
- expecting_next_protocol_negotiation = ExpectNPN,
- negotiated_protocol = Protocol},
+ handshake_env =
+ HsEnv#handshake_env{resumption = not IsNew,
+ kex_algorithm = KeyAlgorithm,
+ premaster_secret = PremasterSecret,
+ expecting_next_protocol_negotiation = ExpectNPN,
+ negotiated_protocol = Protocol},
connection_env = CEnv#connection_env{negotiated_version = Version}},
- case ssl_session:is_new(Session, NewId) of
+ case IsNew of
true ->
handle_new_session(NewId, CipherSuite, State);
false ->
diff --git a/lib/ssl/src/tls_dtls_server_connection.erl b/lib/ssl/src/tls_dtls_server_connection.erl
index 5113fc732c..ca3ece1a8f 100644
--- a/lib/ssl/src/tls_dtls_server_connection.erl
+++ b/lib/ssl/src/tls_dtls_server_connection.erl
@@ -364,7 +364,8 @@ do_server_hello(Type, #{next_protocol_negotiation := NextProtocols} =
State = server_hello(ServerHello,
State1#state{handshake_env =
- HsEnv#handshake_env{expecting_next_protocol_negotiation =
+ HsEnv#handshake_env{resumption = (Type == resumed),
+ expecting_next_protocol_negotiation =
NextProtocols =/= undefined}},
Connection),
case Type of
diff --git a/lib/ssl/test/ssl_session_SUITE.erl b/lib/ssl/test/ssl_session_SUITE.erl
index 33919a7fe0..27107deefd 100644
--- a/lib/ssl/test/ssl_session_SUITE.erl
+++ b/lib/ssl/test/ssl_session_SUITE.erl
@@ -59,9 +59,9 @@
no_reuses_session_server_restart_new_cert_file/0,
no_reuses_session_server_restart_new_cert_file/1,
client_max_session_table/0,
- client_max_session_table/1,
+ client_max_session_table/1,
server_max_session_table/0,
- server_max_session_table/1,
+ server_max_session_table/1,
session_table_stable_size_on_tcp_close/0,
session_table_stable_size_on_tcp_close/1
]).
@@ -73,7 +73,7 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-all() ->
+all() ->
[
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
@@ -122,7 +122,7 @@ end_per_suite(_Config) ->
application:stop(crypto).
init_per_group(GroupName, Config) ->
- ssl_test_lib:init_per_group(GroupName, Config).
+ ssl_test_lib:init_per_group(GroupName, Config).
end_per_group(GroupName, Config) ->
ssl_test_lib:end_per_group(GroupName, Config).
@@ -131,7 +131,7 @@ init_per_testcase(TestCase, Config) when TestCase == reuse_session_expired;
TestCase == explicit_session_reuse_expired ->
Versions = ssl_test_lib:protocol_version(Config),
ssl:stop(),
- application:load(ssl),
+ application:load(ssl),
ssl_test_lib:clean_env(),
ssl_test_lib:set_protocol_versions(Versions),
application:set_env(ssl, session_lifetime, ?EXPIRE),
@@ -142,7 +142,7 @@ init_per_testcase(TestCase, Config) when TestCase == reuse_session_expired;
init_per_testcase(client_max_session_table, Config) ->
Versions = ssl_test_lib:protocol_version(Config),
ssl:stop(),
- application:load(ssl),
+ application:load(ssl),
ssl_test_lib:clean_env(),
ssl_test_lib:set_protocol_versions(Versions),
application:set_env(ssl, session_cache_client_max, 2),
@@ -153,7 +153,7 @@ init_per_testcase(client_max_session_table, Config) ->
init_per_testcase(server_max_session_table, Config) ->
Versions = ssl_test_lib:protocol_version(Config),
ssl:stop(),
- application:load(ssl),
+ application:load(ssl),
ssl_test_lib:clean_env(),
ssl_test_lib:set_protocol_versions(Versions),
application:set_env(ssl, session_cache_server_max, 2),
@@ -166,7 +166,7 @@ init_per_testcase(_, Config) ->
Config.
end_per_testcase(reuse_session_expired, Config) ->
- application:unset_env(ssl, session_lifetime),
+ application:unset_env(ssl, session_lifetime),
Config;
end_per_testcase(_, Config) ->
Config.
@@ -176,16 +176,16 @@ end_per_testcase(_, Config) ->
%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
-reuse_session(Config) when is_list(Config) ->
+reuse_session(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
Version = ssl_test_lib:protocol_version(Config),
- ssl_test_lib:reuse_session([{versions,[Version]} | ClientOpts],
+ ssl_test_lib:reuse_session([{versions,[Version]} | ClientOpts],
[{versions,[Version]} | ServerOpts], Config).
%%--------------------------------------------------------------------
reuse_session_expired() ->
[{doc,"Test sessions is not reused when it has expired"}].
-reuse_session_expired(Config) when is_list(Config) ->
+reuse_session_expired(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
TestVersion = ssl_test_lib:protocol_version(Config),
@@ -203,43 +203,46 @@ reuse_session_expired(Config) when is_list(Config) ->
{tcp_options, [{active, false}]},
{options, ServerOpts}]),
Port0 = ssl_test_lib:inet_port(Server0),
-
+
Client0 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, Hostname},
{mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{reuse_sessions, save},
- {ciphers, Ciphers}| ClientOpts]}]),
+ {from, self()},
+ {options, [{reuse_sessions, save},
+ {ciphers, Ciphers}| ClientOpts]}]),
Server0 ! listen,
-
+
Client1 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, Hostname},
- {mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{ciphers, Ciphers} | ClientOpts]}]),
-
+ {mfa, {ssl, connection_information,
+ [[session_id, session_resumption]]}},
+ {from, self()},
+ {options, [{ciphers, Ciphers} | ClientOpts]}]),
+
SID = receive
{Client0, Id0} ->
Id0
end,
-
+
receive
- {Client1, SID} ->
+ {Client1, {ok, [{session_id, SID}, {session_resumption, true}]}} ->
ok
after ?SLEEP ->
ct:fail(session_not_reused)
end,
-
+
Server0 ! listen,
-
+
%% Make sure session is unregistered due to expiration
ct:sleep({seconds, ?EXPIRE*2}),
make_sure_expired(Hostname, Port0, SID),
-
+
Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
+ ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, Hostname},
{mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, ClientOpts}]),
+ {from, self()}, {options, ClientOpts}]),
receive
{Client2, SID} ->
end_per_testcase(?FUNCTION_NAME, Config),
@@ -261,52 +264,52 @@ make_sure_expired(Host, Port, Id) ->
case ssl_client_session_cache_db:lookup(ClientCache, {{Host, Port}, Id}) of
undefined ->
- ok;
+ ok;
#session{is_resumable = false} ->
ok;
_ ->
ct:sleep(?SLEEP),
make_sure_expired(Host, Port, Id)
- end.
+ end.
%%--------------------------------------------------------------------
server_does_not_want_to_reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
-server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
+server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, session_info_result, []}},
{options, [{reuse_session, fun(_,_,_,_) ->
false
- end} |
+ end} |
ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
+ ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
receive
{Server, Info} ->
Info
end,
-
+
Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
+
%% Make sure session is registered
ct:sleep(?SLEEP),
Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
+ ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
+ {from, self()}, {options, ClientOpts}]),
receive
{Client1, SessionInfo} ->
ct:fail(session_reused_when_server_does_not_want_to);
@@ -340,7 +343,8 @@ explicit_session_reuse(Config) when is_list(Config) ->
return_socket
]),
- {ok, [{session_id, ID}, {session_data, SessData}]} = ssl:connection_information(Client0Sock, [session_id, session_data]),
+ {ok, [{session_id, ID}, {session_data, SessData}]} =
+ ssl:connection_information(Client0Sock, [session_id, session_data]),
ssl_test_lib:close(Client0),
@@ -350,7 +354,8 @@ explicit_session_reuse(Config) when is_list(Config) ->
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, [{reuse_session, {ID, SessData}} | ClientOpts]},
+ {from, self()},
+ {options, [{reuse_session, {ID, SessData}} | ClientOpts]},
return_socket]),
{ok, [{session_id, ID}]} = ssl:connection_information(Client1Sock, [session_id]).
@@ -359,7 +364,8 @@ explicit_session_reuse(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
explicit_session_reuse_expired() ->
- [{doc,"Test to reuse a session that has expired and make sure server session table is correctly handled"}].
+ [{doc,"Test to reuse a session that has expired and make sure server "
+ " session table is correctly handled"}].
explicit_session_reuse_expired(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
@@ -375,11 +381,13 @@ explicit_session_reuse_expired(Config) when is_list(Config) ->
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, [{reuse_sessions, false} | ClientOpts]},
+ {from, self()},
+ {options, [{reuse_sessions, false} | ClientOpts]},
return_socket
]),
%% Retrieve session data
- {ok, [{session_id, ID0}, {session_data, SessData}]} = ssl:connection_information(Client0Sock, [session_id, session_data]),
+ {ok, [{session_id, ID0}, {session_data, SessData}]} =
+ ssl:connection_information(Client0Sock, [session_id, session_data]),
ssl_test_lib:close(Client0),
@@ -391,19 +399,23 @@ explicit_session_reuse_expired(Config) when is_list(Config) ->
[{_, SessionCachePid, worker,[ssl_server_session_cache]}] = supervisor:which_children(Sup),
%% Start a new connections so there are three sessions
- {Client1, Client1Sock} = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]},
- return_socket]),
+ {Client1, Client1Sock} =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()},
+ {options, [{reuse_sessions, save} | ClientOpts]},
+ return_socket]),
Server ! listen,
- {Client2, Client2Sock} = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]},
- return_socket]),
+ {Client2, Client2Sock} =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()},
+ {options, [{reuse_sessions, save} | ClientOpts]},
+ return_socket]),
{ok, [{session_id, ID1}]} = ssl:connection_information(Client1Sock, [session_id]),
@@ -426,7 +438,8 @@ explicit_session_reuse_expired(Config) when is_list(Config) ->
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, [{reuse_session, {ID0, SessData}} | ClientOpts]},
+ {from, self()},
+ {options, [{reuse_session, {ID0, SessData}} | ClientOpts]},
return_socket]),
%% Verify that we got a new session
@@ -477,10 +490,11 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
POpts = proplists:get_value(group_opts, Config, []),
#{client_config := NewCOpts,
- server_config := NewSOpts} = ssl_test_lib:make_cert_chains_der(rsa,
- [[{key, ssl_test_lib:hardcode_rsa_key(4)}],
- [{key, ssl_test_lib:hardcode_rsa_key(5)}],
- [{key, ssl_test_lib:hardcode_rsa_key(6)}]]),
+ server_config := NewSOpts} =
+ ssl_test_lib:make_cert_chains_der(rsa,
+ [[{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(5)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(6)}]]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -535,11 +549,12 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
POpts = proplists:get_value(group_opts, Config, []),
#{client_config := NewCOpts,
- server_config := NewSOpts} = ssl_test_lib:make_cert_chains_pem(rsa,
- [[{key, ssl_test_lib:hardcode_rsa_key(4)}],
- [{key, ssl_test_lib:hardcode_rsa_key(5)}],
- [{key, ssl_test_lib:hardcode_rsa_key(6)}]],
- Config, "ssl_session_new_rsa"),
+ server_config := NewSOpts} =
+ ssl_test_lib:make_cert_chains_pem(rsa,
+ [[{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(5)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(6)}]],
+ Config, "ssl_session_new_rsa"),
PrivDir = proplists:get_value(priv_dir, Config),
NewServerOpts0 = ssl_test_lib:new_config(PrivDir, ServerOpts),
@@ -593,20 +608,21 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
client_max_session_table() ->
- [{doc, "Check that max session table limit is not exceeded, set max to 2 in init_per_testcase"}].
+ [{doc, "Check that max session table limit is not exceeded,"
+ " set max to 2 in init_per_testcase"}].
client_max_session_table(Config) when is_list(Config)->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
- test_max_session_limit(ClientOpts,ServerOpts,ClientNode, ServerNode, HostName),
+ test_max_session_limit(ClientOpts,ServerOpts,ClientNode, ServerNode, HostName),
%% Explicit check table size
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
State = ssl_test_lib:state(Prop),
- ClientCache = element(2, State),
+ ClientCache = element(2, State),
2 = ?CLIENT_CB:size(ClientCache).
-
+
server_max_session_table() ->
[{doc, "Check that max session table limit exceeded, set max to 2 in init_per_testcase"}].
@@ -625,7 +641,8 @@ server_max_session_table(Config) when is_list(Config)->
true = N == 2.
session_table_stable_size_on_tcp_close() ->
- [{doc, "Check that new sessions are cleanup when connection is closed abruptly during first handshake"}].
+ [{doc, "Check that new sessions are cleanup when connection is closed "
+ "abruptly during first handshake"}].
session_table_stable_size_on_tcp_close(Config) when is_list(Config)->
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
@@ -804,52 +821,54 @@ test_max_session_limit(ClientOpts, ServerOpts, ClientNode, ServerNode, HostName)
{tcp_options, [{active, false}]},
{options, ServerOpts}]),
Port0 = ssl_test_lib:inet_port(Server0),
-
+
Client0 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, HostName},
{mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
+ {from, self()},
+ {options, [{reuse_sessions, save} | ClientOpts]}]),
SID0 = receive
{Client0, Id0} ->
Id0
end,
-
-
+
Server0 ! listen,
-
+
Client1 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, HostName},
{mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
-
+ {from, self()},
+ {options, [{reuse_sessions, save} | ClientOpts]}]),
+
SID1 = receive
{Client1, Id1} ->
- Id1
+ Id1
end,
-
+
false = SID0 == SID1,
-
-
+
Server0 ! listen,
-
+
Client2 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, HostName},
{mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{reuse_sessions, save}| ClientOpts]}]),
+ {from, self()},
+ {options, [{reuse_sessions, save}| ClientOpts]}]),
+
-
SID2 = receive
{Client2, Id2} ->
- Id2
+ Id2
end,
Server0 ! listen,
-
+
Client3 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, HostName},
{mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{reuse_session, SID2}| ClientOpts]}]),
-
+ {from, self()},
+ {options, [{reuse_session, SID2}| ClientOpts]}]),
+
receive
{Client3, SID2} ->
ok;
--
2.51.0