summaryrefslogtreecommitdiff
path: root/lib/ssl/src/dtls_connection.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/dtls_connection.erl')
-rw-r--r--lib/ssl/src/dtls_connection.erl112
1 files changed, 72 insertions, 40 deletions
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 65076994f9..08229d8bb5 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2023. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,7 +46,8 @@
%% ClientKeyExchange \
%% CertificateVerify* Flight 5
%% [ChangeCipherSpec] /
-%% Finished --------> /
+%% NextProtocol* /
+%% Finished --------> /
%%
%% [ChangeCipherSpec] \ Flight 6
%% <-------- Finished /
@@ -64,7 +65,8 @@
%% <-------- Finished / part 2
%%
%% [ChangeCipherSpec] \ Abbrev Flight 3
-%% Finished --------> /
+%% NextProtocol* /
+%% Finished --------> /
%%
%%
%% Message Flights for Abbbriviated Handshake
@@ -142,6 +144,7 @@
user_hello/3,
wait_ocsp_stapling/3,
certify/3,
+ wait_cert_verify/3,
cipher/3,
abbreviated/3,
connection/3]).
@@ -160,16 +163,15 @@
%%====================================================================
init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
process_flag(trap_exit, true),
- State0 = #state{protocol_specific = Map} =
- initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_gen_statem:ssl_config(State0#state.ssl_options,
Role, State0),
gen_statem:enter_loop(?MODULE, [], initial_hello, State)
catch
throw:Error ->
- EState = State0#state{protocol_specific =
- Map#{error => Error}},
+ #state{protocol_specific = Map} = State0,
+ EState = State0#state{protocol_specific = Map#{error => Error}},
gen_statem:enter_loop(?MODULE, [], config_error, EState)
end.
%%====================================================================
@@ -208,13 +210,14 @@ initial_hello({call, From}, {start, Timeout},
session_cache_cb = CacheCb},
protocol_specific = PS,
handshake_env = #handshake_env{renegotiation = {Renegotiation, _}},
- connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv,
+ connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv,
ssl_options = #{versions := Versions} = SslOpts,
session = Session0,
connection_states = ConnectionStates0
} = State0) ->
Packages = maps:get(active_n, PS),
dtls_socket:setopts(Transport, Socket, [{active,Packages}]),
+ CertKeyPairs = ssl_certificate:available_cert_key_pairs(CertKeyAlts),
Session = ssl_session:client_select_session({Host, Port, SslOpts}, Cache, CacheCb, Session0, CertKeyPairs),
Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Session#session.session_id, Renegotiation),
@@ -324,14 +327,12 @@ hello(internal, #hello_verify_request{cookie = Cookie},
},
dtls_gen_connection:next_event(?FUNCTION_NAME, no_record, State, Actions);
hello(internal, #client_hello{extensions = Extensions} = Hello,
- #state{ssl_options = #{handshake := hello},
- handshake_env = HsEnv,
+ #state{handshake_env = #handshake_env{continue_status = pause},
start_or_recv_from = From} = State0) ->
try tls_dtls_connection:handle_sni_extension(State0, Hello) of
#state{} = State ->
- {next_state, user_hello, State#state{start_or_recv_from = undefined,
- handshake_env = HsEnv#handshake_env{hello = Hello}},
- [{reply, From, {ok, Extensions}}]}
+ {next_state, user_hello, State#state{start_or_recv_from = undefined},
+ [{postpone, true}, {reply, From, {ok, Extensions}}]}
catch throw:#alert{} = Alert ->
alert_or_reset_connection(Alert, ?FUNCTION_NAME, State0)
end;
@@ -354,16 +355,11 @@ hello(internal, #client_hello{cookie = Cookie} = Hello, #state{static_env = #sta
hello(internal, Hello#client_hello{cookie = <<>>}, State)
end
end;
-hello(internal, #server_hello{extensions = Extensions} = Hello,
- #state{ssl_options = #{
- handshake := hello},
- handshake_env = HsEnv,
+hello(internal, #server_hello{extensions = Extensions},
+ #state{handshake_env = #handshake_env{continue_status = pause},
start_or_recv_from = From} = State) ->
- {next_state, user_hello, State#state{start_or_recv_from = undefined,
- handshake_env = HsEnv#handshake_env{
- hello = Hello}},
- [{reply, From, {ok, Extensions}}]};
-
+ {next_state, user_hello, State#state{start_or_recv_from = undefined},
+ [{postpone, true},{reply, From, {ok, Extensions}}]};
hello(internal, #server_hello{} = Hello,
#state{
static_env = #static_env{role = client},
@@ -469,6 +465,24 @@ certify(state_timeout, Event, State) ->
certify(Type, Event, State) ->
gen_handshake(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_cert_verify(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_cert_verify(enter, _Event, State0) ->
+ {State, Actions} = handle_flight_timer(State0),
+ {keep_state, State, Actions};
+wait_cert_verify(info, Event, State) ->
+ gen_info(Event, ?FUNCTION_NAME, State);
+wait_cert_verify(state_timeout, Event, State) ->
+ handle_state_timeout(Event, ?FUNCTION_NAME, State);
+wait_cert_verify(Type, Event, State) ->
+ try tls_dtls_connection:gen_handshake(?FUNCTION_NAME, Type, Event, State)
+ catch throw:#alert{} = Alert ->
+ ssl_gen_statem:handle_own_alert(Alert, ?FUNCTION_NAME, State)
+ end.
+
%%--------------------------------------------------------------------
-spec cipher(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
@@ -498,13 +512,20 @@ cipher(Type, Event, State) ->
#hello_request{} | #client_hello{}| term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-connection(enter, _, #state{connection_states = Cs0} = State0) ->
- State = case maps:is_key(previous_cs, Cs0) of
- false ->
- State0;
- true ->
- Cs = maps:remove(previous_cs, Cs0),
- State0#state{connection_states = Cs}
+connection(enter, _, #state{connection_states = Cs0,
+ static_env = Env} = State0) ->
+ State = case Env of
+ #static_env{socket = {Listener, {Client, _}}} ->
+ dtls_packet_demux:connection_setup(Listener, Client),
+ case maps:is_key(previous_cs, Cs0) of
+ false ->
+ State0;
+ true ->
+ Cs = maps:remove(previous_cs, Cs0),
+ State0#state{connection_states = Cs}
+ end;
+ _ -> %% client
+ State0
end,
{keep_state, State};
connection(info, Event, State) ->
@@ -516,13 +537,14 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho
session_cache_cb = CacheCb
},
handshake_env = #handshake_env{renegotiation = {Renegotiation, _}},
- connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv,
+ connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv,
session = Session0,
ssl_options = #{versions := Versions} = SslOpts,
connection_states = ConnectionStates0,
protocol_specific = PS
} = State0) ->
#{current_cookie_secret := Cookie} = PS,
+ CertKeyPairs = ssl_certificate:available_cert_key_pairs(CertKeyAlts),
Session = ssl_session:client_select_session({Host, Port, SslOpts}, Cache, CacheCb, Session0, CertKeyPairs),
Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts,
Session#session.session_id, Renegotiation, undefined),
@@ -557,14 +579,20 @@ connection(internal, #client_hello{}, #state{static_env = #static_env{role = ser
dtls_gen_connection:next_event(?FUNCTION_NAME, Record, State);
connection(internal, new_connection, #state{ssl_options=SSLOptions,
handshake_env=HsEnv,
+ static_env = #static_env{socket = {Listener, {Client, _}}},
connection_states = OldCs} = State) ->
case maps:get(previous_cs, OldCs, undefined) of
undefined ->
- BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled),
- ConnectionStates0 = dtls_record:init_connection_states(server, BeastMitigation),
- ConnectionStates = ConnectionStates0#{previous_cs => OldCs},
- {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {false, first}},
- connection_states = ConnectionStates}};
+ case dtls_packet_demux:new_connection(Listener, Client) of
+ true ->
+ {keep_state, State};
+ false ->
+ BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled),
+ ConnectionStates0 = dtls_record:init_connection_states(server, BeastMitigation),
+ ConnectionStates = ConnectionStates0#{previous_cs => OldCs},
+ {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {false, first}},
+ connection_states = ConnectionStates}}
+ end;
_ ->
%% Someone spamming new_connection, just drop them
{keep_state, State}
@@ -628,6 +656,7 @@ format_status(Type, Data) ->
initial_state(Role, Host, Port, Socket,
{#{client_renegotiation := ClientRenegotiation} = SSLOptions, SocketOptions, Trackers}, User,
{CbModule, DataTag, CloseTag, ErrorTag, PassiveTag}) ->
+ put(log_level, maps:get(log_level, SSLOptions)),
BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled),
ConnectionStates = dtls_record:init_connection_states(Role, BeastMitigation),
#{session_cb := SessionCacheCb} = ssl_config:pre_1_3_session_opts(Role),
@@ -681,14 +710,14 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State
handshake_env = #handshake_env{kex_algorithm = KeyExAlg,
renegotiation = {Renegotiation, _},
negotiated_protocol = CurrentProtocol} = HsEnv,
- connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv,
+ connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv,
session = Session0,
ssl_options = SslOpts} =
tls_dtls_connection:handle_sni_extension(State0, Hello),
SessionTracker = proplists:get_value(session_id_tracker, Trackers),
{Version, {Type, Session}, ConnectionStates, Protocol0, ServerHelloExt, HashSign} =
dtls_handshake:hello(Hello, SslOpts, {SessionTracker, Session0,
- ConnectionStates0, CertKeyPairs, KeyExAlg}, Renegotiation),
+ ConnectionStates0, CertKeyAlts, KeyExAlg}, Renegotiation),
Protocol = case Protocol0 of
undefined -> CurrentProtocol;
_ -> Protocol0
@@ -738,20 +767,23 @@ gen_handshake(StateName, Type, Event, State) ->
catch
throw:#alert{}=Alert ->
alert_or_reset_connection(Alert, StateName, State);
- error:_ ->
+ error:Reason:ST ->
+ ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]),
Alert = ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data),
alert_or_reset_connection(Alert, StateName, State)
end.
gen_info(Event, connection = StateName, State) ->
try dtls_gen_connection:handle_info(Event, StateName, State)
- catch error:_ ->
+ catch error:Reason:ST ->
+ ?SSL_LOG(info, internal_error, [{error, Reason}, {stacktrace, ST}]),
Alert = ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, malformed_data),
alert_or_reset_connection(Alert, StateName, State)
end;
gen_info(Event, StateName, State) ->
try dtls_gen_connection:handle_info(Event, StateName, State)
- catch error:_ ->
+ catch error:Reason:ST ->
+ ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]),
Alert = ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,malformed_handshake_data),
alert_or_reset_connection(Alert, StateName, State)
end.