Skip to content

Commit 2f0e284

Browse files
committed
ssl: TLS-1.2 session reuse and client certs
Make session_reuse disabled by default when client certificates are requierd, until extend master secret can be implemented. But best option is to run TLS-1.3.
1 parent e850639 commit 2f0e284

3 files changed

Lines changed: 47 additions & 7 deletions

File tree

lib/ssl/doc/guides/ssl_hardening.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,35 @@ avoid possible [DoS-attacks](https://en.wikipedia.org/wiki/Denial-of-service_att
174174
By default, the server mitigates renegotiation abuse by enforcing a
175175
12-second delay between client initiated renegotiations.
176176

177+
### TLS 1.2 Session Resumption and Client Certificates
178+
179+
> #### Warning {: .warning }
180+
> TLS 1.2 session resumption (session ID and RFC 5077 tickets) does
181+
> not bind the master secret to the handshake transcript. When client
182+
> certificate authentication is required, this leaves the connection
183+
> vulnerable to the Triple Handshake attack (see RFC 7627). This
184+
> concern does not apply to TLS 1.3, which binds all session keys to
185+
> the full transcript.
186+
187+
If your TLS 1.2 server uses {verify, verify_peer} to require client
188+
certificates make sure session resumption is disabled:
189+
190+
```erlang
191+
{reuse_sessions, false}
192+
```
193+
This eliminates the Triple Handshake attack surface at the cost of a
194+
full handshake for every connection. For deployments that need both
195+
mutual authentication and session resumption over TLS 1.2, upgrading
196+
to TLS 1.3 is the recommended solution — TLS 1.3 session tickets are
197+
inherently safe.
198+
199+
Note that this concern only applies to the server role. A client
200+
setting `verify_peer` to verify the server is not affected.
201+
202+
The default value for `reuse_sessions` in above described configuration
203+
is false since OTP @OTP-20289@
204+
205+
177206
### Key Exchange Groups
178207
TLS-1.3 decouples key exchange algorithms from cipher suites. The key
179208
exchange algorithms are configured using the

lib/ssl/src/ssl_config.erl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1388,7 +1388,16 @@ opt_reuse_sessions(UserOpts, #{versions := Versions} = Opts, #{role := client})
13881388
assert_version_dep(Where2 =:= new, reuse_session, Versions, ['tlsv1','tlsv1.1','tlsv1.2']),
13891389
Opts#{reuse_sessions => RUSS, reuse_session => RS};
13901390
opt_reuse_sessions(UserOpts, #{versions := Versions} = Opts, #{role := server}) ->
1391-
{Where1, RUSS} = get_opt_bool(reuse_sessions, true, UserOpts, Opts),
1391+
%% Disable reuse_sessions when client cert verify_peer
1392+
%% verification is required, until Extended Master Secret is implemented.
1393+
ReuseDefault = case maps:get(verify, Opts) of
1394+
verify_peer ->
1395+
false;
1396+
verify_none ->
1397+
true
1398+
end,
1399+
1400+
{Where1, RUSS} = get_opt_bool(reuse_sessions, ReuseDefault, UserOpts, Opts),
13921401

13931402
DefRS = fun(_, _, _, _) -> true end,
13941403
{Where2, RS} = get_opt_fun(reuse_session, 4, DefRS, UserOpts, Opts),

lib/ssl/test/ssl_session_SUITE.erl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ reuse_session(Config) when is_list(Config) ->
186186
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
187187
Version = ssl_test_lib:protocol_version(Config),
188188
ssl_test_lib:reuse_session([{versions,[Version]} | ClientOpts],
189-
[{versions,[Version]} | ServerOpts], Config).
189+
[{reuse_sessions, true},{versions,[Version]} | ServerOpts], Config).
190190
%%--------------------------------------------------------------------
191191
reuse_session_expired() ->
192192
[{doc,"Test sessions is not reused when it has expired"}].
@@ -206,7 +206,7 @@ reuse_session_expired(Config) when is_list(Config) ->
206206
{from, self()},
207207
{mfa, {ssl_test_lib, no_result, []}},
208208
{tcp_options, [{active, false}]},
209-
{options, ServerOpts}]),
209+
{options, [{reuse_sessions, true}| ServerOpts]}]),
210210
Port0 = ssl_test_lib:inet_port(Server0),
211211

212212
Client0 = ssl_test_lib:start_client([{node, ClientNode},
@@ -338,7 +338,7 @@ explicit_session_reuse(Config) when is_list(Config) ->
338338
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
339339
{from, self()},
340340
{mfa, {ssl_test_lib, no_result, []}},
341-
{options, ServerOpts}]),
341+
{options, [{reuse_sessions, true} | ServerOpts]}]),
342342
Port = ssl_test_lib:inet_port(Server),
343343
{Client0, Client0Sock} =
344344
ssl_test_lib:start_client([{node, ClientNode},
@@ -491,7 +491,7 @@ no_reuses_session_server_restart_new_cert() ->
491491
[{doc,"Check that a session is not reused if the server is restarted with a new cert."}].
492492
no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
493493
ClientOpts = ssl_test_lib:ssl_options(client_rsa_der_opts, Config),
494-
ServerOpts = ssl_test_lib:ssl_options(server_rsa_der_verify_opts, Config),
494+
ServerOpts = [[{reuse_sessions, true} | ssl_test_lib:ssl_options(server_rsa_der_verify_opts, Config)],
495495
POpts = proplists:get_value(group_opts, Config, []),
496496

497497
#{client_config := NewCOpts,
@@ -620,7 +620,8 @@ client_max_session_table(Config) when is_list(Config)->
620620
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
621621
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
622622
{ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
623-
test_max_session_limit(ClientOpts,ServerOpts,ClientNode, ServerNode, HostName),
623+
test_max_session_limit(ClientOpts,[{reuse_sessions, true} | ServerOpts],
624+
ClientNode, ServerNode, HostName),
624625
%% Explicit check table size
625626
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
626627
[_, _,_, _, Prop] = StatusInfo,
@@ -635,7 +636,8 @@ server_max_session_table(Config) when is_list(Config)->
635636
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
636637
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
637638
{ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
638-
test_max_session_limit(ClientOpts,ServerOpts,ClientNode, ServerNode, HostName),
639+
test_max_session_limit(ClientOpts,[{reuse_sessions, true} | ServerOpts],
640+
ClientNode, ServerNode, HostName),
639641
%% Explicit check table size
640642
SupName = sup_name(ServerOpts),
641643
Sup = whereis(SupName),

0 commit comments

Comments
 (0)