summaryrefslogtreecommitdiff
path: root/lib/ssl/src/dtls_connection.erl
diff options
context:
space:
mode:
authorIngela Anderton Andin <ingela@erlang.org>2020-12-02 17:41:53 +0100
committerIngela Anderton Andin <ingela@erlang.org>2020-12-07 13:16:10 +0100
commitf61c4302a8a5e6185e05d0f97d1c7bbc0d2621fc (patch)
tree96e1edf142f0c5457193484d7317df58bca4d734 /lib/ssl/src/dtls_connection.erl
parent35b7bd5e4175b1d49b1c7058090029abdf6505cb (diff)
downloaderlang-f61c4302a8a5e6185e05d0f97d1c7bbc0d2621fc.tar.gz
ssl: Continue refactor
Split tls_connection to tls_connection (TLS-1.0 - TLS-1.2) and tls_gen_connection (TLS protocol version generic) used as protocol_cb. Split dtls_connection to dtls_connection (DTLS-1 - DTLS-1.2) and dtls_gen_connection (DTLS protocol version generic) used as protocol_cb. Rename ssl_connection -> tls_dtls_connection common code for pre TLS/DTLS-1.3
Diffstat (limited to 'lib/ssl/src/dtls_connection.erl')
-rw-r--r--lib/ssl/src/dtls_connection.erl797
1 files changed, 90 insertions, 707 deletions
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index b030300a89..fb389dcb4d 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -128,35 +128,9 @@
%% Internal application API
%% Setup
--export([start_fsm/8,
- start_link/7,
- init/1,
- pids/1]).
+-export([init/1]).
-%% State transition handling
--export([next_event/3,
- next_event/4,
- handle_protocol_record/3]).
-
-%% Handshake handling
--export([renegotiate/2,
- send_handshake/2,
- queue_handshake/2,
- queue_change_cipher/2,
- reinit/1,
- reinit_handshake_data/1,
- select_sni_extension/1,
- empty_connection_state/2]).
-
-%% Alert and close handling
--export([encode_alert/3,
- send_alert/2,
- send_alert_in_connection/2,
- close/5,
- protocol_name/0]).
-
-%% Data handling
--export([socket/4, setopts/3, getopts/3]).
+-export([renegotiate/2]).
%% gen_statem state functions
-export([initial_hello/3,
@@ -182,361 +156,35 @@
%%====================================================================
%% Setup
%%====================================================================
-start_fsm(Role, Host, Port, Socket, {#{erl_dist := false},_, Tracker} = Opts,
- User, {CbModule, _, _, _, _} = CbInfo,
- Timeout) ->
- try
- {ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket,
- Opts, User, CbInfo]),
- {ok, SslSocket} = ssl_gen_statem:socket_control(?MODULE, Socket, [Pid], CbModule, Tracker),
- ssl_gen_statem:handshake(SslSocket, Timeout)
- catch
- error:{badmatch, {error, _} = Error} ->
- Error
- end.
-
-%%--------------------------------------------------------------------
--spec start_link(atom(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) ->
- {ok, pid()} | ignore | {error, reason()}.
-%%
-%% Description: Creates a gen_statem process which calls Module:init/1 to
-%% initialize.
-%%--------------------------------------------------------------------
-start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
- {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}.
-
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 = #state{protocol_specific = Map} =
+ initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
try
- State = ssl_gen_statem:ssl_config(State0#state.ssl_options, Role, State0),
+ 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}},
+ EState = State0#state{protocol_specific =
+ Map#{error => Error}},
gen_statem:enter_loop(?MODULE, [], config_error, EState)
end.
-
-pids(_) ->
- [self()].
-
%%====================================================================
-%% State transition handling
+%% Handshake
%%====================================================================
-next_record(#state{handshake_env =
- #handshake_env{unprocessed_handshake_events = N} = HsEnv}
- = State) when N > 0 ->
- {no_record, State#state{handshake_env =
- HsEnv#handshake_env{unprocessed_handshake_events = N-1}}};
-next_record(#state{protocol_buffers =
- #protocol_buffers{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} = CT | Rest]}
- = Buffers,
- connection_states = #{current_read := #{epoch := Epoch}} = ConnectionStates} = State) ->
- CurrentRead = dtls_record:get_connection_state_by_epoch(Epoch, ConnectionStates, read),
- case dtls_record:replay_detect(CT, CurrentRead) of
- false ->
- decode_cipher_text(State#state{connection_states = ConnectionStates}) ;
- true ->
- %% Ignore replayed record
- next_record(State#state{protocol_buffers =
- Buffers#protocol_buffers{dtls_cipher_texts = Rest},
- connection_states = ConnectionStates})
- end;
-next_record(#state{protocol_buffers =
- #protocol_buffers{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} | Rest]}
- = Buffers,
- connection_states = #{current_read := #{epoch := CurrentEpoch}} = ConnectionStates} = State)
- when Epoch > CurrentEpoch ->
- %% TODO Buffer later Epoch message, drop it for now
- next_record(State#state{protocol_buffers =
- Buffers#protocol_buffers{dtls_cipher_texts = Rest},
- connection_states = ConnectionStates});
-next_record(#state{protocol_buffers =
- #protocol_buffers{dtls_cipher_texts = [ _ | Rest]}
- = Buffers,
- connection_states = ConnectionStates} = State) ->
- %% Drop old epoch message
- next_record(State#state{protocol_buffers =
- Buffers#protocol_buffers{dtls_cipher_texts = Rest},
- connection_states = ConnectionStates});
-next_record(#state{static_env = #static_env{role = server,
- socket = {Listener, {Client, _}}}} = State) ->
- dtls_packet_demux:active_once(Listener, Client, self()),
- {no_record, State};
-next_record(#state{protocol_specific = #{active_n_toggle := true,
- active_n := N} = ProtocolSpec,
- static_env = #static_env{role = client,
- socket = {_Server, Socket} = DTLSSocket,
- close_tag = CloseTag,
- transport_cb = Transport}} = State) ->
- case dtls_socket:setopts(Transport, Socket, [{active,N}]) of
- ok ->
- {no_record, State#state{protocol_specific =
- ProtocolSpec#{active_n_toggle => false}}};
- _ ->
- self() ! {CloseTag, DTLSSocket},
- {no_record, State}
- end;
-next_record(State) ->
- {no_record, State}.
-
-next_event(StateName, Record, State) ->
- next_event(StateName, Record, State, []).
-
-next_event(StateName, no_record,
- #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
- case next_record(State0) of
- {no_record, State} ->
- ssl_gen_statem:hibernate_after(StateName, State, Actions);
- {#ssl_tls{epoch = CurrentEpoch,
- type = ?HANDSHAKE,
- version = Version} = Record, State1} ->
- State = dtls_version(StateName, Version, State1),
- {next_state, StateName, State,
- [{next_event, internal, {protocol_record, Record}} | Actions]};
- {#ssl_tls{epoch = CurrentEpoch} = Record, State} ->
- {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
- {#ssl_tls{epoch = Epoch,
- type = ?HANDSHAKE,
- version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
- {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
- next_event(StateName, no_record, State, Actions ++ MoreActions);
- %% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake
- {#ssl_tls{epoch = Epoch,
- type = ?CHANGE_CIPHER_SPEC,
- version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
- {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
- next_event(StateName, no_record, State, Actions ++ MoreActions);
- {#ssl_tls{epoch = _Epoch,
- version = _Version}, State} ->
- %% TODO maybe buffer later epoch
- next_event(StateName, no_record, State, Actions);
- {#alert{} = Alert, State} ->
- Version = State#state.connection_env#connection_env.negotiated_version,
- handle_own_alert(Alert, Version, StateName, State)
- end;
-next_event(connection = StateName, Record,
- #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
- case Record of
- #ssl_tls{epoch = CurrentEpoch,
- type = ?HANDSHAKE,
- version = Version} = Record ->
- State = dtls_version(StateName, Version, State0),
- {next_state, StateName, State,
- [{next_event, internal, {protocol_record, Record}} | Actions]};
- #ssl_tls{epoch = CurrentEpoch} ->
- {next_state, StateName, State0, [{next_event, internal, {protocol_record, Record}} | Actions]};
- #ssl_tls{epoch = Epoch,
- type = ?HANDSHAKE,
- version = _Version} when Epoch == CurrentEpoch-1 ->
- {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
- next_event(StateName, no_record, State, Actions ++ MoreActions);
- %% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake
- #ssl_tls{epoch = Epoch,
- type = ?CHANGE_CIPHER_SPEC,
- version = _Version} when Epoch == CurrentEpoch-1 ->
- {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
- next_event(StateName, no_record, State, Actions ++ MoreActions);
- _ ->
- next_event(StateName, no_record, State0, Actions)
- end;
-next_event(StateName, Record,
- #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
- case Record of
- #ssl_tls{epoch = CurrentEpoch,
- version = Version} = Record ->
- State = dtls_version(StateName, Version, State0),
- {next_state, StateName, State,
- [{next_event, internal, {protocol_record, Record}} | Actions]};
- #ssl_tls{epoch = _Epoch,
- version = _Version} = _Record ->
- %% TODO maybe buffer later epoch
- next_event(StateName, no_record, State0, Actions);
- #alert{} = Alert ->
- Version = State0#state.connection_env#connection_env.negotiated_version,
- handle_own_alert(Alert, Version, StateName, State0)
- end.
-
-%%% DTLS record protocol level application data messages
-
-handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName0, State0) ->
- case ssl_gen_statem:read_application_data(Data, State0) of
- {stop, _, _} = Stop->
- Stop;
- {Record, State1} ->
- {next_state, StateName, State, Actions} = next_event(StateName0, Record, State1),
- ssl_gen_statem:hibernate_after(StateName, State, Actions)
- end;
-%%% DTLS record protocol level handshake messages
-handle_protocol_record(#ssl_tls{type = ?HANDSHAKE,
- fragment = Data},
- StateName,
- #state{protocol_buffers = Buffers0,
- connection_env = #connection_env{negotiated_version = Version},
- ssl_options = Options} = State) ->
- try
- case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0, Options) of
- {[], Buffers} ->
- next_event(StateName, no_record, State#state{protocol_buffers = Buffers});
- {Packets, Buffers} ->
- HsEnv = State#state.handshake_env,
- Events = dtls_handshake_events(Packets),
- {next_state, StateName,
- State#state{protocol_buffers = Buffers,
- handshake_env =
- HsEnv#handshake_env{unprocessed_handshake_events
- = unprocessed_events(Events)}}, Events}
- end
- catch throw:#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State)
- end;
-%%% DTLS record protocol level change cipher messages
-handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) ->
- {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]};
-%%% DTLS record protocol level Alert messages
-handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
- #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
- case decode_alerts(EncAlerts) of
- Alerts = [_|_] ->
- handle_alerts(Alerts, {next_state, StateName, State});
- #alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State)
- end;
-%% Ignore unknown TLS record level protocol messages
-handle_protocol_record(#ssl_tls{type = _Unknown}, StateName, State) ->
- {next_state, StateName, State, []}.
-
-%%====================================================================
-%% Handshake handling
-%%====================================================================
-
renegotiate(#state{static_env = #static_env{role = client}} = State0, Actions) ->
%% Handle same way as if server requested
%% the renegotiation
- State = reinit_handshake_data(State0),
+ State = dtls_gen_connection:reinit_handshake_data(State0),
{next_state, connection, State,
[{next_event, internal, #hello_request{}} | Actions]};
renegotiate(#state{static_env = #static_env{role = server}} = State0, Actions) ->
HelloRequest = ssl_handshake:hello_request(),
State1 = prepare_flight(State0),
- {State, MoreActions} = send_handshake(HelloRequest, State1),
- next_event(hello, no_record, State, Actions ++ MoreActions).
-
-send_handshake(Handshake, #state{connection_states = ConnectionStates} = State) ->
- #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
- send_handshake_flight(queue_handshake(Handshake, State), Epoch).
-
-queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
- connection_env = #connection_env{negotiated_version = Version},
- flight_buffer = #{handshakes := HsBuffer0,
- change_cipher_spec := undefined,
- next_sequence := Seq} = Flight0,
- ssl_options = #{log_level := LogLevel}} = State) ->
- Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
- Hist = update_handshake_history(Handshake0, Handshake, Hist0),
- ssl_logger:debug(LogLevel, outbound, 'handshake', Handshake0),
-
- State#state{flight_buffer = Flight0#{handshakes => [Handshake | HsBuffer0],
- next_sequence => Seq +1},
- handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}};
-
-queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
- connection_env = #connection_env{negotiated_version = Version},
- flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0,
- next_sequence := Seq} = Flight0,
- ssl_options = #{log_level := LogLevel}} = State) ->
- Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
- Hist = update_handshake_history(Handshake0, Handshake, Hist0),
- ssl_logger:debug(LogLevel, outbound, 'handshake', Handshake0),
-
- State#state{flight_buffer = Flight0#{handshakes_after_change_cipher_spec => [Handshake | Buffer0],
- next_sequence => Seq +1},
- handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}.
-
-queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight,
- connection_states = ConnectionStates0} = State) ->
- ConnectionStates =
- dtls_record:next_epoch(ConnectionStates0, write),
- State#state{flight_buffer = Flight#{change_cipher_spec => ChangeCipher},
- connection_states = ConnectionStates}.
-
-reinit(State) ->
- %% To be API compatible with TLS NOOP here
- reinit_handshake_data(State).
-reinit_handshake_data(#state{static_env = #static_env{data_tag = DataTag},
- protocol_buffers = Buffers,
- protocol_specific = PS,
- handshake_env = HsEnv} = State) ->
- State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(),
- public_key_info = undefined,
- premaster_secret = undefined},
- protocol_specific = PS#{flight_state => initial_flight_state(DataTag)},
- flight_buffer = new_flight(),
- protocol_buffers =
- Buffers#protocol_buffers{
- dtls_handshake_next_seq = 0,
- dtls_handshake_next_fragments = [],
- dtls_handshake_later_fragments = []
- }}.
-
-select_sni_extension(#client_hello{extensions = #{sni := SNI}}) ->
- SNI;
-select_sni_extension(_) ->
- undefined.
-
-empty_connection_state(ConnectionEnd, BeastMitigation) ->
- Empty = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
- dtls_record:empty_connection_state(Empty).
-
-%%====================================================================
-%% Alert and close handling
-%%====================================================================
-encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
- dtls_record:encode_alert_record(Alert, Version, ConnectionStates).
-
-send_alert(Alert, #state{static_env = #static_env{socket = Socket,
- transport_cb = Transport},
-
- connection_env = #connection_env{negotiated_version = Version},
- connection_states = ConnectionStates0,
- ssl_options = #{log_level := LogLevel}} = State0) ->
- {BinMsg, ConnectionStates} =
- encode_alert(Alert, Version, ConnectionStates0),
- send(Transport, Socket, BinMsg),
- ssl_logger:debug(LogLevel, outbound, 'record', BinMsg),
- State0#state{connection_states = ConnectionStates}.
-
-send_alert_in_connection(Alert, State) ->
- _ = send_alert(Alert, State),
- ok.
-
-close(downgrade, _,_,_,_) ->
- ok;
-%% Other
-close(_, Socket, Transport, _,_) ->
- dtls_socket:close(Transport,Socket).
-
-protocol_name() ->
- "DTLS".
-
-%%====================================================================
-%% Data handling
-%%====================================================================
-
-send(Transport, {Listener, Socket}, Data) when is_pid(Listener) -> % Server socket
- dtls_socket:send(Transport, Socket, Data);
-send(Transport, Socket, Data) -> % Client socket
- dtls_socket:send(Transport, Socket, Data).
-
-socket(Pid, Transport, Socket, _Tracker) ->
- dtls_socket:socket(Pid, Transport, Socket, ?MODULE).
-
-setopts(Transport, Socket, Other) ->
- dtls_socket:setopts(Transport, Socket, Other).
-
-getopts(Transport, Socket, Tag) ->
- dtls_socket:getopts(Transport, Socket, Tag).
+ {State, MoreActions} = dtls_gen_connection:send_handshake(HelloRequest, State1),
+ dtls_gen_connection:next_event(hello, no_record, State, Actions ++ MoreActions).
%%--------------------------------------------------------------------
%% State functions
@@ -570,19 +218,22 @@ initial_hello({call, From}, {start, Timeout},
HelloVersion = dtls_record:hello_version(Version, Versions),
State1 = prepare_flight(State0#state{connection_env = CEnv#connection_env{negotiated_version = Version},
connection_states = ConnectionStates1}),
- {State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}),
+ {State2, Actions} =
+ dtls_gen_connection:send_handshake(Hello,
+ State1#state{connection_env =
+ CEnv#connection_env{negotiated_version = HelloVersion}}),
State = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% RequestedVersion
session = Session,
start_or_recv_from = From},
- next_event(hello, no_record, State, [{{timeout, handshake}, Timeout, close} | Actions]);
+ dtls_gen_connection:next_event(hello, no_record, State, [{{timeout, handshake}, Timeout, close} | Actions]);
initial_hello({call, _} = Type, Event, #state{static_env = #static_env{role = server},
- protocol_specific = PS} = State) ->
+ protocol_specific = PS} = State) ->
Result = ssl_gen_statem:?FUNCTION_NAME(Type, Event,
- State#state{protocol_specific =
- PS#{current_cookie_secret => dtls_v1:cookie_secret(),
- previous_cookie_secret => <<>>,
- ignored_alerts => 0,
- max_ignored_alerts => 10}}),
+ State#state{protocol_specific =
+ PS#{current_cookie_secret => dtls_v1:cookie_secret(),
+ previous_cookie_secret => <<>>,
+ ignored_alerts => 0,
+ max_ignored_alerts => 10}}),
erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret),
Result;
initial_hello(Type, Event, State) ->
@@ -617,7 +268,7 @@ hello(internal, #client_hello{cookie = <<>>,
handshake_env = HsEnv,
connection_env = CEnv,
protocol_specific = #{current_cookie_secret := Secret}} = State0) ->
- case ssl_connection:handle_sni_extension(State0, Hello) of
+ case tls_dtls_connection:handle_sni_extension(State0, Hello) of
#state{} = State1 ->
{ok, {IP, Port}} = dtls_socket:peername(Transport, Socket),
Cookie = dtls_handshake:cookie(Secret, IP, Port, Hello),
@@ -629,27 +280,28 @@ hello(internal, #client_hello{cookie = <<>>,
%% negotiated.
VerifyRequest = dtls_handshake:hello_verify_request(Cookie, ?HELLO_VERIFY_REQUEST_VERSION),
State2 = prepare_flight(State1#state{connection_env = CEnv#connection_env{negotiated_version = Version}}),
- {State, Actions} = send_handshake(VerifyRequest, State2),
- next_event(?FUNCTION_NAME, no_record,
- State#state{handshake_env = HsEnv#handshake_env{
- tls_handshake_history =
- ssl_handshake:init_handshake_history()}},
+ {State, Actions} = dtls_gen_connection:send_handshake(VerifyRequest, State2),
+ dtls_gen_connection:next_event(?FUNCTION_NAME, no_record,
+ State#state{handshake_env = HsEnv#handshake_env{
+ tls_handshake_history =
+ ssl_handshake:init_handshake_history()}},
Actions);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,?FUNCTION_NAME, State0)
+ ssl_gen_statem:handle_own_alert(Alert, Version,?FUNCTION_NAME, State0)
end;
-hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #static_env{role = client,
- host = Host,
- port = Port},
- handshake_env = #handshake_env{renegotiation = {Renegotiation, _},
- ocsp_stapling_state = OcspState0} = HsEnv,
- connection_env = CEnv,
- ssl_options = #{ocsp_stapling := OcspStaplingOpt,
- ocsp_nonce := OcspNonceOpt} = SslOpts,
- session = #session{own_certificates = OwnCerts,
- session_id = Id},
- connection_states = ConnectionStates0
- } = State0) ->
+hello(internal, #hello_verify_request{cookie = Cookie},
+ #state{static_env = #static_env{role = client,
+ host = Host,
+ port = Port},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _},
+ ocsp_stapling_state = OcspState0} = HsEnv,
+ connection_env = CEnv,
+ ssl_options = #{ocsp_stapling := OcspStaplingOpt,
+ ocsp_nonce := OcspNonceOpt} = SslOpts,
+ session = #session{own_certificates = OwnCerts,
+ session_id = Id},
+ connection_states = ConnectionStates0
+ } = State0) ->
OcspNonce = tls_handshake:ocsp_nonce(OcspNonceOpt, OcspStaplingOpt),
Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0,
SslOpts, Id, Renegotiation, OwnCerts, OcspNonce),
@@ -657,24 +309,25 @@ hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #sta
State1 = prepare_flight(State0#state{handshake_env =
HsEnv#handshake_env{tls_handshake_history
= ssl_handshake:init_handshake_history(),
- ocsp_stapling_state = OcspState0#{ocsp_nonce => OcspNonce}}}),
+ ocsp_stapling_state =
+ OcspState0#{ocsp_nonce => OcspNonce}}}),
- {State2, Actions} = send_handshake(Hello, State1),
+ {State2, Actions} = dtls_gen_connection:send_handshake(Hello, State1),
State = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version} % RequestedVersion
},
- next_event(?FUNCTION_NAME, no_record, State, Actions);
+ dtls_gen_connection:next_event(?FUNCTION_NAME, no_record, State, Actions);
hello(internal, #client_hello{extensions = Extensions, client_version = ClientVersion} = Hello,
#state{ssl_options = #{handshake := hello},
handshake_env = HsEnv,
start_or_recv_from = From} = State0) ->
- case ssl_connection:handle_sni_extension(State0, Hello) of
+ case 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}}]};
#alert{} = Alert ->
- handle_own_alert(Alert, ClientVersion, ?FUNCTION_NAME, State0)
+ ssl_gen_statem:handle_own_alert(Alert, ClientVersion, ?FUNCTION_NAME, State0)
end;
hello(internal, #server_hello{extensions = Extensions} = Hello,
#state{ssl_options = #{
@@ -716,12 +369,13 @@ hello(internal, #server_hello{} = Hello,
ssl_options = SslOptions} = State) ->
case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation, OldId) of
#alert{} = Alert ->
- handle_own_alert(Alert, ReqVersion, ?FUNCTION_NAME, State);
+ ssl_gen_statem:handle_own_alert(Alert, ReqVersion, ?FUNCTION_NAME, State);
{Version, NewId, ConnectionStates, ProtoExt, Protocol, OcspState} ->
- ssl_connection:handle_session(Hello,
+ tls_dtls_connection:handle_session(Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol,
- State#state{handshake_env = HsEnv#handshake_env{
- ocsp_stapling_state = maps:merge(OcspState0,OcspState)}})
+ State#state{handshake_env =
+ HsEnv#handshake_env{
+ ocsp_stapling_state = maps:merge(OcspState0,OcspState)}})
end;
hello(internal, {handshake, {#client_hello{cookie = <<>>} = Handshake, _}}, State) ->
%% Initial hello should not be in handshake history
@@ -730,8 +384,9 @@ hello(internal, {handshake, {#hello_verify_request{} = Handshake, _}}, State) ->
%% hello_verify should not be in handshake history
{next_state, ?FUNCTION_NAME, State, [{next_event, internal, Handshake}]};
hello(internal, #change_cipher_spec{type = <<1>>}, State0) ->
- {State1, Actions0} = send_handshake_flight(State0, retransmit_epoch(?FUNCTION_NAME, State0)),
- {next_state, ?FUNCTION_NAME, State, Actions} = next_event(?FUNCTION_NAME, no_record, State1, Actions0),
+ {State1, Actions0} = dtls_gen_connection:send_handshake_flight(State0, retransmit_epoch(?FUNCTION_NAME, State0)),
+ {next_state, ?FUNCTION_NAME, State, Actions} =
+ dtls_gen_connection:next_event(?FUNCTION_NAME, no_record, State1, Actions0),
%% This will reset the retransmission timer by repeating the enter state event
{repeat_state, State, Actions};
hello(info, Event, State) ->
@@ -797,8 +452,9 @@ certify(info, Event, State) ->
certify(internal = Type, #server_hello_done{} = Event, State) ->
gen_handshake(?FUNCTION_NAME, Type, Event, prepare_flight(State));
certify(internal, #change_cipher_spec{type = <<1>>}, State0) ->
- {State1, Actions0} = send_handshake_flight(State0, retransmit_epoch(?FUNCTION_NAME, State0)),
- {next_state, ?FUNCTION_NAME, State, Actions} = next_event(?FUNCTION_NAME, no_record, State1, Actions0),
+ {State1, Actions0} = dtls_gen_connection:send_handshake_flight(State0, retransmit_epoch(?FUNCTION_NAME, State0)),
+ {next_state, ?FUNCTION_NAME, State, Actions} =
+ dtls_gen_connection:next_event(?FUNCTION_NAME, no_record, State1, Actions0),
%% This will reset the retransmission timer by repeating the enter state event
{repeat_state, State, Actions};
certify(state_timeout, Event, State) ->
@@ -859,12 +515,16 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho
Version = Hello#client_hello.client_version,
HelloVersion = dtls_record:hello_version(Version, Versions),
State1 = prepare_flight(State0),
- {State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}),
- State = State2#state{protocol_specific = PS#{flight_state => initial_flight_state(DataTag)},
+ {State2, Actions} =
+ dtls_gen_connection:send_handshake(Hello,
+ State1#state{connection_env =
+ CEnv#connection_env{negotiated_version = HelloVersion}}),
+ State = State2#state{protocol_specific = PS#{flight_state => dtls_gen_connection:initial_flight_state(DataTag)},
session = Session},
- next_event(hello, no_record, State, Actions);
-connection(internal, #client_hello{} = Hello, #state{static_env = #static_env{role = server},
- handshake_env = #handshake_env{allow_renegotiate = true} = HsEnv} = State) ->
+ dtls_gen_connection:next_event(hello, no_record, State, Actions);
+connection(internal, #client_hello{} = Hello,
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{allow_renegotiate = true} = HsEnv} = State) ->
%% Mitigate Computational DoS attack
%% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
%% http://www.thc.org/thc-ssl-dos/ Rather than disabling client
@@ -874,12 +534,13 @@ connection(internal, #client_hello{} = Hello, #state{static_env = #static_env{ro
{next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, peer},
allow_renegotiate = false}},
[{next_event, internal, Hello}]};
-connection(internal, #client_hello{}, #state{static_env = #static_env{role = server},
+connection(internal, #client_hello{}, #state{static_env = #static_env{role = server,
+ protocol_cb = Connection},
handshake_env = #handshake_env{allow_renegotiate = false}} = State0) ->
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
- State1 = send_alert(Alert, State0),
- {Record, State} = ssl_gen_statem:prepare_connection(State1, ?MODULE),
- next_event(?FUNCTION_NAME, Record, State);
+ State1 = dtls_gen_connection:send_alert(Alert, State0),
+ {Record, State} = ssl_gen_statem:prepare_connection(State1, Connection),
+ dtls_gen_connection:next_event(?FUNCTION_NAME, Record, State);
connection({call, From}, {application_data, Data}, State) ->
try
send_application_data(Data, From, ?FUNCTION_NAME, State)
@@ -887,7 +548,7 @@ connection({call, From}, {application_data, Data}, State) ->
ssl_gen_statem:hibernate_after(?FUNCTION_NAME, State, [{reply, From, Error}])
end;
connection(Type, Event, State) ->
- ssl_connection:?FUNCTION_NAME(Type, Event, State).
+ tls_dtls_connection:?FUNCTION_NAME(Type, Event, State).
%%TODO does this make sense for DTLS ?
%%--------------------------------------------------------------------
@@ -897,7 +558,7 @@ connection(Type, Event, State) ->
downgrade(enter, _, State) ->
{keep_state, State};
downgrade(Type, Event, State) ->
- ssl_connection:?FUNCTION_NAME(Type, Event, State).
+ tls_dtls_connection:?FUNCTION_NAME(Type, Event, State).
%%--------------------------------------------------------------------
%% gen_statem callbacks
@@ -939,7 +600,7 @@ initial_state(Role, Host, Port, Socket,
InitStatEnv = #static_env{
role = Role,
transport_cb = CbModule,
- protocol_cb = ?MODULE,
+ protocol_cb = dtls_gen_connection,
data_tag = DataTag,
close_tag = CloseTag,
error_tag = ErrorTag,
@@ -967,61 +628,15 @@ initial_state(Role, Host, Port, Socket,
protocol_buffers = #protocol_buffers{},
user_data_buffer = {[],0,[]},
start_or_recv_from = undefined,
- flight_buffer = new_flight(),
+ flight_buffer = dtls_gen_connection:new_flight(),
protocol_specific = #{active_n => InternalActiveN,
active_n_toggle => true,
- flight_state => initial_flight_state(DataTag)}
+ flight_state => dtls_gen_connection:initial_flight_state(DataTag)}
}.
-initial_flight_state(udp)->
- {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT};
-initial_flight_state(_) ->
- reliable.
-
-next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
- dtls_record_buffer = Buf0,
- dtls_cipher_texts = CT0} = Buffers,
- connection_env = #connection_env{negotiated_version = Version},
- static_env = #static_env{data_tag = DataTag},
- ssl_options = SslOpts} = State0) ->
- case dtls_record:get_dtls_records(Data,
- {DataTag, StateName, Version,
- [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS]},
- Buf0, SslOpts) of
- {Records, Buf1} ->
- CT1 = CT0 ++ Records,
- next_record(State0#state{protocol_buffers =
- Buffers#protocol_buffers{dtls_record_buffer = Buf1,
- dtls_cipher_texts = CT1}});
- #alert{} = Alert ->
- Alert
- end.
-
-
-dtls_handshake_events(Packets) ->
- lists:map(fun(Packet) ->
- {next_event, internal, {handshake, Packet}}
- end, Packets).
-
-decode_cipher_text(#state{protocol_buffers = #protocol_buffers{dtls_cipher_texts = [ CT | Rest]} = Buffers,
- connection_states = ConnStates0} = State) ->
- case dtls_record:decode_cipher_text(CT, ConnStates0) of
- {Plain, ConnStates} ->
- {Plain, State#state{protocol_buffers =
- Buffers#protocol_buffers{dtls_cipher_texts = Rest},
- connection_states = ConnStates}};
- #alert{} = Alert ->
- {Alert, State}
- end.
-
-dtls_version(hello, Version, #state{static_env = #static_env{role = server},
- connection_env = CEnv} = State) ->
- State#state{connection_env = CEnv#connection_env{negotiated_version = Version}}; %%Inital version
-dtls_version(_,_, State) ->
- State.
handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State0) ->
- case ssl_connection:handle_sni_extension(State0, Hello) of
+ case tls_dtls_connection:handle_sni_extension(State0, Hello) of
#state{connection_states = ConnectionStates0,
static_env = #static_env{trackers = Trackers},
handshake_env = #handshake_env{kex_algorithm = KeyExAlg,
@@ -1034,7 +649,7 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State
case dtls_handshake:hello(Hello, SslOpts, {SessionTracker, Session0,
ConnectionStates0, OwnCerts, KeyExAlg}, Renegotiation) of
#alert{} = Alert ->
- handle_own_alert(Alert, ClientVersion, hello, State1);
+ ssl_gen_statem:handle_own_alert(Alert, ClientVersion, hello, State1);
{Version, {Type, Session},
ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
Protocol = case Protocol0 of
@@ -1052,119 +667,25 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State
{next_state, hello, State, [{next_event, internal, {common_client_hello, Type, ServerHelloExt}}]}
end;
#alert{} = Alert ->
- handle_own_alert(Alert, ClientVersion, hello, State0)
+ ssl_gen_statem:handle_own_alert(Alert, ClientVersion, hello, State0)
end.
-%% raw data from socket, unpack records
-handle_info({Protocol, _, _, _, Data}, StateName,
- #state{static_env = #static_env{role = Role,
- data_tag = Protocol}} = State0) ->
- case next_dtls_record(Data, StateName, State0) of
- {Record, State} ->
- next_event(StateName, Record, State);
- #alert{} = Alert ->
- ssl_gen_statem:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State0),
- {stop, {shutdown, own_alert}, State0}
- end;
-handle_info({PassiveTag, Socket}, StateName,
- #state{static_env = #static_env{socket = {_, Socket},
- passive_tag = PassiveTag},
- protocol_specific = PS} = State) ->
- next_event(StateName, no_record,
- State#state{protocol_specific = PS#{active_n_toggle => true}});
-
-handle_info({CloseTag, Socket}, StateName,
- #state{static_env = #static_env{
- role = Role,
- socket = Socket,
- close_tag = CloseTag},
- connection_env = #connection_env{negotiated_version = Version},
- socket_options = #socket_options{active = Active},
- protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs},
- protocol_specific = PS} = State) ->
- %% Note that as of DTLS 1.2 (TLS 1.1),
- %% failure to properly close a connection no longer requires that a
- %% session not be resumed. This is a change from DTLS 1.0 to conform
- %% with widespread implementation practice.
- case (Active == false) andalso (CTs =/= []) of
- false ->
- case Version of
- {254, N} when N =< 253 ->
- ok;
- _ ->
- %% As invalidate_sessions here causes performance issues,
- %% we will conform to the widespread implementation
- %% practice and go aginst the spec
- %%invalidate_session(Role, Host, Port, Session)
- ok
- end,
- Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, transport_closed),
- ssl_gen_statem:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
- {stop, {shutdown, transport_closed}, State};
- true ->
- %% Fixes non-delivery of final DTLS record in {active, once}.
- %% Basically allows the application the opportunity to set {active, once} again
- %% and then receive the final message.
- next_event(StateName, no_record, State#state{
- protocol_specific = PS#{active_n_toggle => true}})
- end;
-
-handle_info(new_cookie_secret, StateName,
- #state{protocol_specific = #{current_cookie_secret := Secret} = CookieInfo} = State) ->
- erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret),
- {next_state, StateName, State#state{protocol_specific =
- CookieInfo#{current_cookie_secret => dtls_v1:cookie_secret(),
- previous_cookie_secret => Secret}}};
-handle_info(Msg, StateName, State) ->
- ssl_gen_statem:handle_info(Msg, StateName, State).
handle_state_timeout(flight_retransmission_timeout, StateName,
#state{protocol_specific =
#{flight_state := {retransmit, _NextTimeout}}} = State0) ->
- {State1, Actions0} = send_handshake_flight(State0,
- retransmit_epoch(StateName, State0)),
- {next_state, StateName, State, Actions} = next_event(StateName, no_record, State1, Actions0),
+ {State1, Actions0} = dtls_gen_connection:send_handshake_flight(State0,
+ retransmit_epoch(StateName, State0)),
+ {next_state, StateName, State, Actions} =
+ dtls_gen_connection:next_event(StateName, no_record, State1, Actions0),
%% This will reset the retransmission timer by repeating the enter state event
{repeat_state, State, Actions}.
-handle_alerts([], Result) ->
- Result;
-handle_alerts(_, {stop, _, _} = Stop) ->
- Stop;
-handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
- handle_alerts(Alerts, ssl_gen_statem:handle_alert(Alert, StateName, State));
-handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
- handle_alerts(Alerts, ssl_gen_statem:handle_alert(Alert, StateName, State)).
-
-handle_own_alert(Alert, Version, StateName,
- #state{static_env = #static_env{data_tag = udp,
- role = Role},
- ssl_options = #{log_level := LogLevel}} = State0) ->
- case ignore_alert(Alert, State0) of
- {true, State} ->
- log_ignore_alert(LogLevel, StateName, Alert, Role),
- {next_state, StateName, State};
- {false, State} ->
- ssl_gen_statem:handle_own_alert(Alert, Version, StateName, State)
- end;
-handle_own_alert(Alert, Version, StateName, State) ->
- ssl_gen_statem:handle_own_alert(Alert, Version, StateName, State).
-encode_handshake_flight(Flight, Version, MaxFragmentSize, Epoch, ConnectionStates) ->
- Fragments = lists:map(fun(Handshake) ->
- dtls_handshake:fragment_handshake(Handshake, MaxFragmentSize)
- end, Flight),
- dtls_record:encode_handshake(Fragments, Version, Epoch, ConnectionStates).
-
-encode_change_cipher(#change_cipher_spec{}, Version, Epoch, ConnectionStates) ->
- dtls_record:encode_change_cipher_spec(Version, Epoch, ConnectionStates).
-
-decode_alerts(Bin) ->
- ssl_alert:decode(Bin).
gen_handshake(StateName, Type, Event,
#state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
- try ssl_connection:StateName(Type, Event, State) of
+ try tls_dtls_connection:StateName(Type, Event, State) of
Result ->
Result
catch
@@ -1175,7 +696,7 @@ gen_handshake(StateName, Type, Event,
end.
gen_info(Event, connection = StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
- try handle_info(Event, StateName, State) of
+ try dtls_gen_connection:handle_info(Event, StateName, State) of
Result ->
Result
catch
@@ -1186,7 +707,7 @@ gen_info(Event, connection = StateName, #state{connection_env = #connection_env
end;
gen_info(Event, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
- try handle_info(Event, StateName, State) of
+ try dtls_gen_connection:handle_info(Event, StateName, State) of
Result ->
Result
catch
@@ -1195,18 +716,7 @@ gen_info(Event, StateName, #state{connection_env = #connection_env{negotiated_ve
malformed_handshake_data),
Version, StateName, State)
end.
-unprocessed_events(Events) ->
- %% The first handshake event will be processed immediately
- %% as it is entered first in the event queue and
- %% when it is processed there will be length(Events)-1
- %% handshake events left to process before we should
- %% process more TLS-records received on the socket.
- erlang:length(Events)-1.
-update_handshake_history(#hello_verify_request{}, _, Hist) ->
- Hist;
-update_handshake_history(_, Handshake, Hist) ->
- ssl_handshake:update_handshake_history(Hist, iolist_to_binary(Handshake)).
prepare_flight(#state{flight_buffer = Flight,
connection_states = ConnectionStates0,
protocol_buffers =
@@ -1217,11 +727,6 @@ prepare_flight(#state{flight_buffer = Flight,
protocol_buffers = Buffers#protocol_buffers{
dtls_handshake_next_fragments = [],
dtls_handshake_later_fragments = []}}.
-new_flight() ->
- #{next_sequence => 0,
- handshakes => [],
- change_cipher_spec => undefined,
- handshakes_after_change_cipher_spec => []}.
next_flight(Flight) ->
Flight#{handshakes => [],
@@ -1247,133 +752,11 @@ new_timeout(N) when N =< 30000 ->
new_timeout(_) ->
60000.
-send_handshake_flight(#state{static_env = #static_env{socket = Socket,
- transport_cb = Transport},
- connection_env = #connection_env{negotiated_version = Version},
- flight_buffer = #{handshakes := Flight,
- change_cipher_spec := undefined},
- connection_states = ConnectionStates0,
- ssl_options = #{log_level := LogLevel}} = State0,
- Epoch) ->
- PMTUEstimate = 1400, %% TODO make configurable
- #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
- MaxSize = min(MaxFragmentLength, PMTUEstimate),
- {Encoded, ConnectionStates} =
- encode_handshake_flight(lists:reverse(Flight), Version, MaxSize, Epoch, ConnectionStates0),
- send(Transport, Socket, Encoded),
- ssl_logger:debug(LogLevel, outbound, 'record', Encoded),
- {State0#state{connection_states = ConnectionStates}, []};
-
-send_handshake_flight(#state{static_env = #static_env{socket = Socket,
- transport_cb = Transport},
- connection_env = #connection_env{negotiated_version = Version},
- flight_buffer = #{handshakes := [_|_] = Flight0,
- change_cipher_spec := ChangeCipher,
- handshakes_after_change_cipher_spec := []},
- connection_states = ConnectionStates0,
- ssl_options = #{log_level := LogLevel}} = State0,
- Epoch) ->
- PMTUEstimate = 1400, %% TODO make configurable
- #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
- MaxSize = min(MaxFragmentLength, PMTUEstimate),
- {HsBefore, ConnectionStates1} =
- encode_handshake_flight(lists:reverse(Flight0), Version, MaxSize, Epoch, ConnectionStates0),
- {EncChangeCipher, ConnectionStates} = encode_change_cipher(ChangeCipher, Version, Epoch, ConnectionStates1),
-
- send(Transport, Socket, [HsBefore, EncChangeCipher]),
- ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]),
- ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
- {State0#state{connection_states = ConnectionStates}, []};
-
-send_handshake_flight(#state{static_env = #static_env{socket = Socket,
- transport_cb = Transport},
- connection_env = #connection_env{negotiated_version = Version},
- flight_buffer = #{handshakes := [_|_] = Flight0,
- change_cipher_spec := ChangeCipher,
- handshakes_after_change_cipher_spec := Flight1},
- connection_states = ConnectionStates0,
- ssl_options = #{log_level := LogLevel}} = State0,
- Epoch) ->
- PMTUEstimate = 1400, %% TODO make configurable
- #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
- MaxSize = min(MaxFragmentLength, PMTUEstimate),
- {HsBefore, ConnectionStates1} =
- encode_handshake_flight(lists:reverse(Flight0), Version, MaxSize, Epoch-1, ConnectionStates0),
- {EncChangeCipher, ConnectionStates2} =
- encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates1),
- {HsAfter, ConnectionStates} =
- encode_handshake_flight(lists:reverse(Flight1), Version, MaxSize, Epoch, ConnectionStates2),
- send(Transport, Socket, [HsBefore, EncChangeCipher, HsAfter]),
- ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]),
- ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
- ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]),
- {State0#state{connection_states = ConnectionStates}, []};
-
-send_handshake_flight(#state{static_env = #static_env{socket = Socket,
- transport_cb = Transport},
- connection_env = #connection_env{negotiated_version = Version},
- flight_buffer = #{handshakes := [],
- change_cipher_spec := ChangeCipher,
- handshakes_after_change_cipher_spec := Flight1},
- connection_states = ConnectionStates0,
- ssl_options = #{log_level := LogLevel}} = State0,
- Epoch) ->
- PMTUEstimate = 1400, %% TODO make configurable
- #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
- MaxSize = min(MaxFragmentLength, PMTUEstimate),
- {EncChangeCipher, ConnectionStates1} =
- encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates0),
- {HsAfter, ConnectionStates} =
- encode_handshake_flight(lists:reverse(Flight1), Version, MaxSize, Epoch, ConnectionStates1),
- send(Transport, Socket, [EncChangeCipher, HsAfter]),
- ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
- ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]),
- {State0#state{connection_states = ConnectionStates}, []}.
-
retransmit_epoch(_StateName, #state{connection_states = ConnectionStates}) ->
#{epoch := Epoch} =
ssl_record:current_connection_state(ConnectionStates, write),
Epoch.
-ignore_alert(#alert{level = ?FATAL}, #state{protocol_specific = #{ignored_alerts := N,
- max_ignored_alerts := N}} = State) ->
- {false, State};
-ignore_alert(#alert{level = ?FATAL} = Alert,
- #state{protocol_specific = #{ignored_alerts := N} = PS} = State) ->
- case is_ignore_alert(Alert) of
- true ->
- {true, State#state{protocol_specific = PS#{ignored_alerts => N+1}}};
- false ->
- {false, State}
- end;
-ignore_alert(_, State) ->
- {false, State}.
-
-%% RFC 6347 4.1.2.7. Handling Invalid Records
-%% recommends to silently ignore invalid DTLS records when
-%% upd is the transport. Note we do not support compression so no need
-%% include ?DECOMPRESSION_FAILURE
-is_ignore_alert(#alert{description = ?BAD_RECORD_MAC}) ->
- true;
-is_ignore_alert(#alert{description = ?RECORD_OVERFLOW}) ->
- true;
-is_ignore_alert(#alert{description = ?DECODE_ERROR}) ->
- true;
-is_ignore_alert(#alert{description = ?DECRYPT_ERROR}) ->
- true;
-is_ignore_alert(#alert{description = ?ILLEGAL_PARAMETER}) ->
- true;
-is_ignore_alert(_) ->
- false.
-
-log_ignore_alert(Level, StateName, #alert{where = Location} = Alert, Role) ->
- ssl_logger:log(info,
- Level, #{alert => Alert,
- alerter => ignored,
- statename => StateName,
- role => Role,
- protocol => protocol_name()}, Location).
-
send_application_data(Data, From, _StateName,
#state{static_env = #static_env{socket = Socket,
transport_cb = Transport},
@@ -1391,7 +774,7 @@ send_application_data(Data, From, _StateName,
{Msgs, ConnectionStates} =
dtls_record:encode_data(Data, Version, ConnectionStates0),
State = State0#state{connection_states = ConnectionStates},
- case send(Transport, Socket, Msgs) of
+ case dtls_gen_connection:send(Transport, Socket, Msgs) of
ok ->
ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
ssl_gen_statem:hibernate_after(connection, State, [{reply, From, ok}]);