summaryrefslogtreecommitdiff
path: root/lib/ssl/src/ssl_gen_statem.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/ssl_gen_statem.erl')
-rw-r--r--lib/ssl/src/ssl_gen_statem.erl309
1 files changed, 202 insertions, 107 deletions
diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl
index eed0025ad7..12a4721a09 100644
--- a/lib/ssl/src/ssl_gen_statem.erl
+++ b/lib/ssl/src/ssl_gen_statem.erl
@@ -38,7 +38,8 @@
init/1]).
%% TLS connection setup
--export([ssl_config/3,
+-export([init_ssl_config/3,
+ ssl_config/3,
connect/8,
handshake/7,
handshake/2,
@@ -60,7 +61,8 @@
set_opts/2,
peer_certificate/1,
negotiated_protocol/1,
- connection_information/2
+ connection_information/2,
+ ktls_handover/1
]).
%% Erlang Distribution export
@@ -96,6 +98,9 @@
%% Log handling
-export([format_status/2]).
+%% Tracing
+-export([handle_trace/3]).
+
%%--------------------------------------------------------------------
%%% Initial Erlang process setup
%%--------------------------------------------------------------------
@@ -106,7 +111,8 @@
%% Description: Creates a process which calls Module:init/1 to
%% choose appropriat gen_statem and initialize.
%%--------------------------------------------------------------------
-start_link(Role, Sender, Host, Port, Socket, {#{receiver_spawn_opts := ReceiverOpts}, _, _} = Options, User, CbInfo) ->
+start_link(Role, Sender, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) ->
+ ReceiverOpts = maps:get(receiver_spawn_opts, SslOpts, []),
Opts = [link | proplists:delete(link, ReceiverOpts)],
Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]], Opts),
{ok, Pid}.
@@ -118,7 +124,8 @@ start_link(Role, Sender, Host, Port, Socket, {#{receiver_spawn_opts := ReceiverO
%% Description: Creates a gen_statem process which calls Module:init/1 to
%% initialize.
%%--------------------------------------------------------------------
-start_link(Role, Host, Port, Socket, {#{receiver_spawn_opts := ReceiverOpts}, _, _} = Options, User, CbInfo) ->
+start_link(Role, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) ->
+ ReceiverOpts = maps:get(receiver_spawn_opts, SslOpts, []),
Opts = [link | proplists:delete(link, ReceiverOpts)],
Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]], Opts),
{ok, Pid}.
@@ -128,30 +135,51 @@ start_link(Role, Host, Port, Socket, {#{receiver_spawn_opts := ReceiverOpts}, _,
-spec init(list()) -> no_return().
%% Description: Initialization
%%--------------------------------------------------------------------
-init([_Role, _Sender, _Host, _Port, _Socket, {#{erl_dist := ErlDist} = TLSOpts, _, _}, _User, _CbInfo] = InitArgs) ->
+init([Role, _Sender, _Host, _Port, _Socket, {TLSOpts, _, _}, _User, _CbInfo] = InitArgs) ->
process_flag(trap_exit, true),
- case ErlDist of
+ case maps:get(erl_dist, TLSOpts, false) of
true ->
process_flag(priority, max);
_ ->
ok
end,
- ConnectionFsm = tls_connection_fsm(TLSOpts),
- ConnectionFsm:init(InitArgs);
-init([_Role, _Host, _Port, _Socket, {TLSOpts, _, _}, _User, _CbInfo] = InitArgs) ->
+ case {Role, TLSOpts} of
+ {?CLIENT_ROLE, #{versions := [?TLS_1_3]}} ->
+ tls_client_connection_1_3:init(InitArgs);
+ {?SERVER_ROLE, #{versions := [?TLS_1_3]}} ->
+ tls_server_connection_1_3:init(InitArgs);
+ {_,_} ->
+ tls_connection:init(InitArgs)
+ end;
+init([_Role, _Host, _Port, _Socket, _TLSOpts, _User, _CbInfo] = InitArgs) ->
process_flag(trap_exit, true),
- ConnectionFsm = dtls_connection_fsm(TLSOpts),
- ConnectionFsm:init(InitArgs).
+ dtls_connection:init(InitArgs).
%%====================================================================
%% TLS connection setup
%%====================================================================
%%--------------------------------------------------------------------
+-spec init_ssl_config(ssl_options(), client | server, #state{}) -> #state{}.
+%%--------------------------------------------------------------------
+init_ssl_config(Opts, Role, #state{ssl_options = #{handshake := Handshake},
+ handshake_env = HsEnv} = State0) ->
+ ContinueStatus = case Handshake of
+ hello ->
+ %% Will pause handshake after hello message to
+ %% enable user to react to hello extensions
+ pause;
+ full ->
+ Handshake
+ end,
+ ssl_config(Opts, Role,
+ State0#state{handshake_env =
+ HsEnv#handshake_env{continue_status = ContinueStatus}}).
+
+%%--------------------------------------------------------------------
-spec ssl_config(ssl_options(), client | server, #state{}) -> #state{}.
%%--------------------------------------------------------------------
ssl_config(Opts, Role, #state{static_env = InitStatEnv0,
- ssl_options = #{handshake := Handshake},
handshake_env = HsEnv,
connection_env = CEnv} = State0) ->
{ok, #{cert_db_ref := Ref,
@@ -165,15 +193,6 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0,
TimeStamp = erlang:monotonic_time(),
Session = State0#state.session,
- ContinueStatus = case Handshake of
- hello ->
- %% Will pause handshake after hello message to
- %% enable user to react to hello extensions
- pause;
- full ->
- Handshake
- end,
-
State0#state{session = Session#session{time_stamp = TimeStamp},
static_env = InitStatEnv0#static_env{
file_ref_db = FileRefHandle,
@@ -182,8 +201,8 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0,
crl_db = CRLDbHandle,
session_cache = CacheHandle
},
- handshake_env = HsEnv#handshake_env{diffie_hellman_params = DHParams,
- continue_status = ContinueStatus},
+ handshake_env =
+ HsEnv#handshake_env{diffie_hellman_params = DHParams},
connection_env = CEnv#connection_env{cert_key_alts = CertKeyAlts},
ssl_options = Opts}.
@@ -292,21 +311,23 @@ socket_control(Connection, Socket, Pid, Transport) ->
-spec socket_control(tls_gen_connection | dtls_gen_connection, port(), [pid()], atom(), [pid()] | atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%--------------------------------------------------------------------
-socket_control(dtls_gen_connection = Connection, Socket, Pids, Transport, udp_listener) ->
+socket_control(dtls_gen_connection, Socket, Pids, Transport, udp_listener) ->
%% dtls listener process must have the socket control
- {ok, Connection:socket(Pids, Transport, Socket, undefined)};
+ {ok, dtls_gen_connection:socket(Pids, Transport, Socket, undefined)};
-socket_control(tls_gen_connection = Connection, Socket, [Pid|_] = Pids, Transport, Trackers) ->
+socket_control(tls_gen_connection, Socket, [Pid|_] = Pids, Transport, Trackers) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, Connection:socket(Pids, Transport, Socket, Trackers)};
+ {ok, tls_gen_connection:socket(Pids, Transport, Socket, Trackers)};
{error, Reason} ->
{error, Reason}
end;
-socket_control(dtls_gen_connection = Connection, {PeerAddrPort, Socket}, [Pid|_] = Pids, Transport, Trackers) ->
+socket_control(dtls_gen_connection, {PeerAddrPort, Socket},
+ [Pid|_] = Pids, Transport, Trackers) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, Connection:socket(Pids, Transport, {PeerAddrPort, Socket}, Trackers)};
+ {ok, dtls_gen_connection:socket(Pids, Transport, {PeerAddrPort, Socket},
+ Trackers)};
{error, Reason} ->
{error, Reason}
end.
@@ -420,6 +441,14 @@ peer_certificate(ConnectionPid) ->
negotiated_protocol(ConnectionPid) ->
call(ConnectionPid, negotiated_protocol).
+%%--------------------------------------------------------------------
+-spec ktls_handover(pid()) -> {ok, map()} | {error, reason()}.
+%%
+%% Description: Returns the negotiated protocol
+%%--------------------------------------------------------------------
+ktls_handover(ConnectionPid) ->
+ call(ConnectionPid, ktls_handover).
+
dist_handshake_complete(ConnectionPid, DHandle) ->
gen_statem:cast(ConnectionPid, {dist_handshake_complete, DHandle}).
@@ -460,8 +489,6 @@ initial_hello({call, From}, {start, Timeout},
%% Versions is a descending list of supported versions.
versions := [HelloVersion|_] = Versions,
session_tickets := SessionTickets,
- ocsp_stapling := OcspStaplingOpt,
- ocsp_nonce := OcspNonceOpt,
early_data := EarlyData} = SslOpts,
session = Session,
connection_states = ConnectionStates0
@@ -471,9 +498,9 @@ initial_hello({call, From}, {start, Timeout},
%% Update UseTicket in case of automatic session resumption. The automatic ticket handling
%% also takes it into account if the ticket is suitable for sending early data not exceeding
%% the max_early_data_size or if it can only be used for session resumption.
- {UseTicket, State1} = tls_handshake_1_3:maybe_automatic_session_resumption(State0),
+ {UseTicket, State1} = tls_client_connection_1_3:maybe_automatic_session_resumption(State0),
TicketData = tls_handshake_1_3:get_ticket_data(self(), SessionTickets, UseTicket),
- OcspNonce = tls_handshake:ocsp_nonce(OcspNonceOpt, OcspStaplingOpt),
+ OcspNonce = tls_handshake:ocsp_nonce(SslOpts),
Hello0 = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Session#session.session_id,
Renegotiation,
@@ -507,21 +534,24 @@ initial_hello({call, From}, {start, Timeout},
%% ServerHello is processed.
RequestedVersion = tls_record:hello_version(Versions),
- {Ref,Maybe} = tls_handshake_1_3:maybe(),
+ {Ref,Maybe} = tls_gen_connection_1_3:do_maybe(),
try
%% Send Early Data
- State4 = Maybe(tls_handshake_1_3:maybe_send_early_data(State3)),
+ State4 = Maybe(tls_client_connection_1_3:maybe_send_early_data(State3)),
{#state{handshake_env = HsEnv1} = State5, _} =
Connection:send_handshake_flight(State4),
+ OcspStaplingKeyPresent = maps:is_key(ocsp_stapling, SslOpts),
State = State5#state{
connection_env = CEnv#connection_env{
negotiated_version = RequestedVersion},
session = Session,
- handshake_env = HsEnv1#handshake_env{
- ocsp_stapling_state = OcspState0#{ocsp_nonce => OcspNonce,
- ocsp_stapling => OcspStaplingOpt}},
+ handshake_env =
+ HsEnv1#handshake_env{
+ ocsp_stapling_state =
+ OcspState0#{ocsp_nonce => OcspNonce,
+ ocsp_stapling => OcspStaplingKeyPresent}},
start_or_recv_from = From,
key_share = KeyShare},
NextState = next_statem_state(Versions, Role),
@@ -534,17 +564,17 @@ initial_hello({call, From}, {start, Timeout},
initial_hello({call, From}, {start, Timeout}, #state{static_env = #static_env{role = Role,
protocol_cb = Connection},
ssl_options = #{versions := Versions}} = State0) ->
-
- NextState = next_statem_state(Versions, Role),
+
+ NextState = next_statem_state(Versions, Role),
Connection:next_event(NextState, no_record, State0#state{start_or_recv_from = From},
[{{timeout, handshake}, Timeout, close}]);
-
+
initial_hello({call, From}, {start, {Opts, EmOpts}, Timeout},
#state{static_env = #static_env{role = Role},
ssl_options = OrigSSLOptions,
socket_options = SockOpts} = State0) ->
try
- SslOpts = ssl:handle_options(Opts, Role, OrigSSLOptions),
+ SslOpts = ssl:update_options(Opts, Role, OrigSSLOptions),
State = ssl_config(SslOpts, Role, State0),
initial_hello({call, From}, {start, Timeout},
State#state{ssl_options = SslOpts,
@@ -646,6 +676,45 @@ connection({call, From},
{error, timeout} ->
{stop_and_reply, {shutdown, downgrade_fail}, [{reply, From, {error, timeout}}]}
end;
+connection({call, From}, ktls_handover, #state{
+ static_env = #static_env{
+ transport_cb = Transport,
+ socket = Socket
+ },
+ connection_env = #connection_env{
+ user_application = {_Mon, Pid},
+ negotiated_version = TlsVersion
+ },
+ ssl_options = #{ktls := true},
+ socket_options = SocketOpts,
+ connection_states = #{
+ current_write := #{
+ security_parameters := #security_parameters{cipher_suite = CipherSuite},
+ cipher_state := WriteState,
+ sequence_number := WriteSeq
+ },
+ current_read := #{
+ cipher_state := ReadState,
+ sequence_number := ReadSeq
+ }
+ }
+}) ->
+ Reply = case Transport:controlling_process(Socket, Pid) of
+ ok ->
+ {ok, #{
+ socket => Socket,
+ tls_version => TlsVersion,
+ cipher_suite => CipherSuite,
+ socket_options => SocketOpts,
+ write_state => WriteState,
+ write_seq => WriteSeq,
+ read_state => ReadState,
+ read_seq => ReadSeq
+ }};
+ {error, Reason} ->
+ {error, Reason}
+ end,
+ {stop_and_reply, {shutdown, ktls}, [{reply, From, Reply}]};
connection({call, From}, Msg, State) ->
handle_call(Msg, From, ?FUNCTION_NAME, State);
connection(cast, {dist_handshake_complete, DHandle},
@@ -953,8 +1022,9 @@ passive_receive(#state{user_data_buffer = {Front,BufferSize,Rear},
%%====================================================================
hibernate_after(connection = StateName,
- #state{ssl_options= #{hibernate_after := HibernateAfter}} = State,
+ #state{ssl_options= SslOpts} = State,
Actions) ->
+ HibernateAfter = maps:get(hibernate_after, SslOpts, infinity),
{next_state, StateName, State, [{timeout, HibernateAfter, hibernate} | Actions]};
hibernate_after(StateName, State, Actions) ->
{next_state, StateName, State, Actions}.
@@ -1006,26 +1076,8 @@ handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role =
Pids = Connection:pids(State),
alert_user(Pids, Transport, Trackers, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, StateName, Connection).
-handle_alert(#alert{level = ?FATAL} = Alert0, StateName,
- #state{static_env = #static_env{role = Role,
- socket = Socket,
- host = Host,
- port = Port,
- trackers = Trackers,
- transport_cb = Transport,
- protocol_cb = Connection},
- connection_env = #connection_env{user_application = {_Mon, Pid}},
- ssl_options = #{log_level := LogLevel},
- start_or_recv_from = From,
- session = Session,
- socket_options = Opts} = State) ->
- invalidate_session(Role, Host, Port, Session),
- Alert = Alert0#alert{role = opposite_role(Role)},
- log_alert(LogLevel, Role, Connection:protocol_name(),
- StateName, Alert),
- Pids = Connection:pids(State),
- alert_user(Pids, Transport, Trackers, Socket, StateName, Opts, Pid, From, Alert, Role, StateName, Connection),
- {stop, {shutdown, normal}, State};
+handle_alert(#alert{level = ?FATAL} = Alert, StateName, State) ->
+ handle_fatal_alert(Alert, StateName, State);
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
downgrade= StateName, State) ->
{next_state, StateName, State, [{next_event, internal, Alert}]};
@@ -1092,27 +1144,61 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert,
%% Go back to connection!
State = Connection:reinit(State0#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}),
Connection:next_event(connection, no_record, State);
+handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, StateName,
+ #state{static_env = #static_env{role = Role,
+ protocol_cb = Connection},
+ ssl_options = #{log_level := LogLevel}} = State) when StateName =/= connection ->
+ log_alert(LogLevel, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = opposite_role(Role)}),
+ %% Wait for close alert that should follow or handshake timeout
+ Connection:next_event(StateName, no_record, State);
%% Gracefully log and ignore all other warning alerts pre TLS-1.3
handle_alert(#alert{level = ?WARNING} = Alert, StateName,
#state{static_env = #static_env{role = Role,
protocol_cb = Connection},
connection_env = #connection_env{negotiated_version = Version},
- ssl_options = #{log_level := LogLevel}} = State) when Version < {3,4} ->
+ ssl_options = #{log_level := LogLevel}} = State) when ?TLS_LT(Version, ?TLS_1_3) ->
log_alert(LogLevel, Role,
Connection:protocol_name(), StateName,
Alert#alert{role = opposite_role(Role)}),
Connection:next_event(StateName, no_record, State);
-handle_alert(Alert0, StateName, State) ->
+handle_alert(Alert, StateName, State) ->
%% In TLS-1.3 all error alerts are fatal not matter of legacy level
- handle_alert(Alert0#alert{level = ?FATAL}, StateName, State).
+ %% but keep the level for the log so that users looking at what is
+ %% sent and what is logged are not confused! Or if some one sends
+ %% user cancel alert in connection which is inappropriate!
+ handle_fatal_alert(Alert, StateName, State).
+
+handle_fatal_alert(Alert0, StateName,
+ #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ host = Host,
+ port = Port,
+ trackers = Trackers,
+ transport_cb = Transport,
+ protocol_cb = Connection},
+ connection_env = #connection_env{user_application = {_Mon, Pid}},
+ ssl_options = #{log_level := LogLevel},
+ start_or_recv_from = From,
+ session = Session,
+ socket_options = Opts} = State) ->
+ invalidate_session(Role, Host, Port, Session),
+ Alert = Alert0#alert{role = opposite_role(Role)},
+ log_alert(LogLevel, Role, Connection:protocol_name(),
+ StateName, Alert),
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Trackers, Socket, StateName, Opts, Pid, From, Alert, Role, StateName, Connection),
+ {stop, {shutdown, normal}, State}.
-handle_trusted_certs_db(#state{ssl_options =
- #{cacertfile := <<>>, cacerts := []}}) ->
+handle_trusted_certs_db(#state{ssl_options =#{cacerts := []} = Opts})
+ when not is_map_key(cacertfile, Opts) ->
%% No trusted certs specified
ok;
handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref,
cert_db = CertDb},
- ssl_options = #{cacertfile := <<>>}}) when CertDb =/= undefined ->
+ ssl_options = Opts})
+ when CertDb =/= undefined, not is_map_key(cacertfile, Opts) ->
%% Certs provided as DER directly can not be shared
%% with other connections and it is safe to delete them when the connection ends.
ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
@@ -1130,9 +1216,9 @@ handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref,
ok
end.
-maybe_invalidate_session({3, 4},_, _, _, _, _) ->
+maybe_invalidate_session(?TLS_1_3,_, _, _, _, _) ->
ok;
-maybe_invalidate_session({3, N}, Type, Role, Host, Port, Session) when N < 4 ->
+maybe_invalidate_session(Version, Type, Role, Host, Port, Session) when ?TLS_LT(Version, ?TLS_1_3) ->
maybe_invalidate_session(Type, Role, Host, Port, Session).
maybe_invalidate_session({false, first}, server = Role, Host, Port, Session) ->
@@ -1140,6 +1226,9 @@ maybe_invalidate_session({false, first}, server = Role, Host, Port, Session) ->
maybe_invalidate_session(_, _, _, _, _) ->
ok.
+terminate({shutdown, ktls}, connection, State) ->
+ %% Socket shall not be closed as it should be returned to user
+ handle_trusted_certs_db(State);
terminate({shutdown, downgrade}, downgrade, State) ->
%% Socket shall not be closed as it should be returned to user
handle_trusted_certs_db(State);
@@ -1191,10 +1280,9 @@ format_status(normal, [_, StateName, State]) ->
[{data, [{"State", {StateName, State}}]}];
format_status(terminate, [_, StateName, State]) ->
SslOptions = (State#state.ssl_options),
- NewOptions = SslOptions#{password => ?SECRET_PRINTOUT,
- cert => ?SECRET_PRINTOUT,
+ NewOptions = SslOptions#{
+ certs_keys => ?SECRET_PRINTOUT,
cacerts => ?SECRET_PRINTOUT,
- key => ?SECRET_PRINTOUT,
dh => ?SECRET_PRINTOUT,
psk_identity => ?SECRET_PRINTOUT,
srp_identity => ?SECRET_PRINTOUT},
@@ -1210,24 +1298,16 @@ format_status(terminate, [_, StateName, State]) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-tls_connection_fsm(#{versions := [{3,4}]}) ->
- tls_connection_1_3;
-tls_connection_fsm(_) ->
- tls_connection.
-
-dtls_connection_fsm(_) ->
- dtls_connection.
-
next_statem_state([Version], client) ->
case ssl:tls_version(Version) of
- {3,4} ->
+ ?TLS_1_3 ->
wait_sh;
_ ->
hello
end;
next_statem_state([Version], server) ->
case ssl:tls_version(Version) of
- {3,4} ->
+ ?TLS_1_3 ->
start;
_ ->
hello
@@ -1276,11 +1356,8 @@ is_sni_value(Hostname) ->
true
end.
-is_hostname_recognized(#{sni_fun := undefined,
- sni_hosts := SNIHosts}, Hostname) ->
- proplists:is_defined(Hostname, SNIHosts);
-is_hostname_recognized(_, _) ->
- true.
+is_hostname_recognized(#{sni_fun := Fun}, Hostname) ->
+ Fun(Hostname) =:= undefined.
handle_sni_hostname(Hostname,
#state{static_env = #static_env{role = Role} = InitStatEnv0,
@@ -1290,7 +1367,7 @@ handle_sni_hostname(Hostname,
NewOptions = update_ssl_options_from_sni(Opts, Hostname),
case NewOptions of
undefined ->
- case maps:get(server_name_indication, Opts) of
+ case maps:get(server_name_indication, Opts, undefined) of
disable when Role == client->
State0;
_ ->
@@ -1320,23 +1397,14 @@ handle_sni_hostname(Hostname,
}
end.
-update_ssl_options_from_sni(#{sni_fun := SNIFun,
- sni_hosts := SNIHosts} = OrigSSLOptions, SNIHostname) ->
- SSLOptions =
- case SNIFun of
- undefined ->
- proplists:get_value(SNIHostname,
- SNIHosts);
- SNIFun ->
- SNIFun(SNIHostname)
- end,
- case SSLOptions of
+update_ssl_options_from_sni(#{sni_fun := SNIFun} = OrigSSLOptions, SNIHostname) ->
+ case SNIFun(SNIHostname) of
undefined ->
undefined;
- _ ->
+ SSLOptions ->
VersionsOpt = proplists:get_value(versions, SSLOptions, []),
FallBackOptions = filter_for_versions(VersionsOpt, OrigSSLOptions),
- ssl:handle_options(SSLOptions, server, FallBackOptions)
+ ssl:update_options(SSLOptions, server, FallBackOptions)
end.
filter_for_versions([], OrigSSLOptions) ->
@@ -1897,7 +1965,7 @@ connection_info(#state{handshake_env = #handshake_env{sni_hostname = SNIHostname
security_info(#state{connection_states = ConnectionStates,
static_env = #static_env{role = Role},
- ssl_options = #{keep_secrets := KeepSecrets},
+ ssl_options = Opts,
protocol_specific = ProtocolSpecific}) ->
ReadState = ssl_record:current_connection_state(ConnectionStates, read),
#{security_parameters :=
@@ -1908,6 +1976,8 @@ security_info(#state{connection_states = ConnectionStates,
client_early_data_secret = ServerEarlyData
}} = ReadState,
BaseSecurityInfo = [{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}],
+
+ KeepSecrets = maps:get(keep_secrets, Opts, false),
if KeepSecrets =/= true ->
BaseSecurityInfo;
true ->
@@ -2175,12 +2245,37 @@ keylog_secret(SecretBin, sha384) ->
keylog_secret(SecretBin, sha512) ->
io_lib:format("~128.16.0B", [binary:decode_unsigned(SecretBin)]).
-maybe_generate_client_shares(#{versions := [Version|_],
+maybe_generate_client_shares(#{versions := [?TLS_1_3|_],
supported_groups :=
#supported_groups{
- supported_groups = [Group|_]}})
- when Version =:= {3,4} ->
+ supported_groups = [Group|_]}}) ->
%% Generate only key_share entry for the most preferred group
ssl_cipher:generate_client_shares([Group]);
maybe_generate_client_shares(_) ->
undefined.
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+handle_trace(api,
+ {call, {?MODULE, connect, [Connection | _]}}, Stack0) ->
+ {io_lib:format("Connection = ~w", [Connection]), Stack0};
+handle_trace(rle,
+ {call, {?MODULE, init, Args = [[Role | _]]}}, Stack0) ->
+ {io_lib:format("(*~w) Args = ~W", [Role, Args, 3]), [{role, Role} | Stack0]};
+handle_trace(hbn,
+ {call, {?MODULE, hibernate_after,
+ [_StateName = connection, State, Actions]}},
+ Stack) ->
+ #state{ssl_options= #{hibernate_after := HibernateAfter}} = State,
+ {io_lib:format("* * * maybe hibernating in ~w ms * * * Actions = ~W ",
+ [HibernateAfter, Actions, 10]), Stack};
+handle_trace(hbn,
+ {return_from, {?MODULE, hibernate_after, 3},
+ {Cmd, Arg,_State, Actions}},
+ Stack) ->
+ {io_lib:format("Cmd = ~w Arg = ~w Actions = ~W", [Cmd, Arg, Actions, 10]), Stack};
+handle_trace(hbn,
+ {call, {?MODULE, handle_common_event, [timeout, hibernate, connection | _]}}, Stack) ->
+ {io_lib:format("* * * hibernating * * *", []), Stack}.