1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21%%----------------------------------------------------------------------
22%% Purpose:
23%%----------------------------------------------------------------------
24-module(dtls_gen_connection).
25
26-include_lib("public_key/include/public_key.hrl").
27-include_lib("kernel/include/logger.hrl").
28
29-include("dtls_connection.hrl").
30-include("dtls_handshake.hrl").
31-include("ssl_alert.hrl").
32-include("dtls_record.hrl").
33-include("ssl_cipher.hrl").
34-include("ssl_api.hrl").
35-include("ssl_internal.hrl").
36
37%% Setup
38-export([start_fsm/8,
39         pids/1]).
40
41%% Handshake handling
42-export([send_handshake/2,
43         send_handshake_flight/2,
44	 queue_handshake/2,
45         queue_change_cipher/2,
46	 reinit/1,
47         reinit_handshake_data/1,
48         select_sni_extension/1,
49         empty_connection_state/2]).
50
51%% State transition handling
52-export([next_event/3,
53         next_event/4,
54         handle_protocol_record/3,
55         new_flight/0,
56         initial_flight_state/1
57        ]).
58
59%% Data handling
60-export([send/3,
61         socket/4,
62         setopts/3,
63         getopts/3,
64         handle_info/3]).
65
66%% Alert and close handling
67-export([send_alert/2,
68         send_alert_in_connection/2,
69         close/5,
70         protocol_name/0]).
71%%====================================================================
72%% Internal application API
73%%====================================================================
74%%====================================================================
75%% Setup
76%%====================================================================
77start_fsm(Role, Host, Port, Socket, {#{erl_dist := false},_, Tracker} = Opts,
78	  User, {CbModule, _, _, _, _} = CbInfo,
79	  Timeout) ->
80    try
81	{ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket,
82						     Opts, User, CbInfo]),
83	{ok, SslSocket} = ssl_gen_statem:socket_control(?MODULE, Socket, [Pid], CbModule, Tracker),
84	ssl_gen_statem:handshake(SslSocket, Timeout)
85    catch
86	error:{badmatch, {error, _} = Error} ->
87	    Error
88    end.
89
90pids(_) ->
91    [self()].
92
93%%====================================================================
94%% State transition handling
95%%====================================================================
96next_record(#state{handshake_env =
97                       #handshake_env{unprocessed_handshake_events = N} = HsEnv}
98            = State) when N > 0 ->
99    {no_record, State#state{handshake_env =
100                                HsEnv#handshake_env{unprocessed_handshake_events = N-1}}};
101next_record(#state{protocol_buffers =
102		       #protocol_buffers{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} = CT | Rest]}
103		   = Buffers,
104		   connection_states = #{current_read := #{epoch := Epoch}} = ConnectionStates} = State) ->
105    CurrentRead = dtls_record:get_connection_state_by_epoch(Epoch, ConnectionStates, read),
106    case dtls_record:replay_detect(CT, CurrentRead) of
107        false ->
108            decode_cipher_text(State#state{connection_states = ConnectionStates}) ;
109        true ->
110            %% Ignore replayed record
111            next_record(State#state{protocol_buffers =
112                                        Buffers#protocol_buffers{dtls_cipher_texts = Rest},
113                                    connection_states = ConnectionStates})
114    end;
115next_record(#state{protocol_buffers =
116		       #protocol_buffers{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} | Rest]}
117		   = Buffers,
118		   connection_states = #{current_read := #{epoch := CurrentEpoch}} = ConnectionStates} = State)
119  when Epoch > CurrentEpoch ->
120    %% TODO Buffer later Epoch message, drop it for now
121    next_record(State#state{protocol_buffers =
122                                Buffers#protocol_buffers{dtls_cipher_texts = Rest},
123                            connection_states = ConnectionStates});
124next_record(#state{protocol_buffers =
125		       #protocol_buffers{dtls_cipher_texts = [ _ | Rest]}
126		   = Buffers,
127		   connection_states = ConnectionStates} = State) ->
128    %% Drop old epoch message
129    next_record(State#state{protocol_buffers =
130                                Buffers#protocol_buffers{dtls_cipher_texts = Rest},
131                            connection_states = ConnectionStates});
132next_record(#state{static_env = #static_env{role = server,
133                                            socket = {Listener, {Client, _}}}} = State) ->
134    dtls_packet_demux:active_once(Listener, Client, self()),
135    {no_record, State};
136next_record(#state{protocol_specific = #{active_n_toggle := true,
137                                         active_n := N} = ProtocolSpec,
138                   static_env = #static_env{role = client,
139                                            socket = {_Server, Socket} = DTLSSocket,
140                                            close_tag = CloseTag,
141                                            transport_cb = Transport}} = State) ->
142    case dtls_socket:setopts(Transport, Socket, [{active,N}]) of
143        ok ->
144            {no_record, State#state{protocol_specific =
145                                        ProtocolSpec#{active_n_toggle => false}}};
146 	_ ->
147            self() ! {CloseTag, DTLSSocket},
148	    {no_record, State}
149    end;
150next_record(State) ->
151    {no_record, State}.
152
153next_event(StateName, Record, State) ->
154    next_event(StateName, Record, State, []).
155
156next_event(StateName, no_record,
157	   #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
158    case next_record(State0) of
159	{no_record, State} ->
160            ssl_gen_statem:hibernate_after(StateName, State, Actions);
161        {#ssl_tls{epoch = CurrentEpoch,
162                  type = ?HANDSHAKE,
163                  version = Version} = Record, State1} ->
164            State = dtls_version(StateName, Version, State1),
165	    {next_state, StateName, State,
166	     [{next_event, internal, {protocol_record, Record}} | Actions]};
167        {#ssl_tls{epoch = CurrentEpoch} = Record, State} ->
168	    {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
169	{#ssl_tls{epoch = Epoch,
170		  type = ?HANDSHAKE,
171		  version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
172	    {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
173            next_event(StateName, no_record, State, Actions ++ MoreActions);
174        %% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake
175        {#ssl_tls{epoch = Epoch,
176		  type = ?CHANGE_CIPHER_SPEC,
177		  version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
178	    {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
179            next_event(StateName, no_record, State, Actions ++ MoreActions);
180	{#ssl_tls{epoch = _Epoch,
181		  version = _Version}, State} ->
182	    %% TODO maybe buffer later epoch
183            next_event(StateName, no_record, State, Actions);
184	{#alert{} = Alert, State} ->
185            Version = State#state.connection_env#connection_env.negotiated_version,
186            handle_own_alert(Alert, Version, StateName, State)
187    end;
188next_event(connection = StateName, Record,
189	   #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
190    case Record of
191        #ssl_tls{epoch = CurrentEpoch,
192                 type = ?HANDSHAKE,
193                 version = Version} = Record ->
194            State = dtls_version(StateName, Version, State0),
195	    {next_state, StateName, State,
196	     [{next_event, internal, {protocol_record, Record}} | Actions]};
197	#ssl_tls{epoch = CurrentEpoch} ->
198	    {next_state, StateName, State0, [{next_event, internal, {protocol_record, Record}} | Actions]};
199	#ssl_tls{epoch = Epoch,
200                 type = ?HANDSHAKE,
201                 version = _Version} when Epoch == CurrentEpoch-1 ->
202	    {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
203            next_event(StateName, no_record, State, Actions ++ MoreActions);
204        %% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake
205        #ssl_tls{epoch = Epoch,
206                 type = ?CHANGE_CIPHER_SPEC,
207                 version = _Version} when Epoch == CurrentEpoch-1 ->
208	    {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
209            next_event(StateName, no_record, State, Actions ++ MoreActions);
210        _ ->
211            next_event(StateName, no_record, State0, Actions)
212    end;
213next_event(StateName, Record,
214	   #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
215    case Record of
216        #ssl_tls{epoch = CurrentEpoch,
217                 version = Version} = Record ->
218            State = dtls_version(StateName, Version, State0),
219            {next_state, StateName, State,
220             [{next_event, internal, {protocol_record, Record}} | Actions]};
221	#ssl_tls{epoch = _Epoch,
222		 version = _Version} = _Record ->
223	    %% TODO maybe buffer later epoch
224            next_event(StateName, no_record, State0, Actions);
225	#alert{} = Alert ->
226	    Version = State0#state.connection_env#connection_env.negotiated_version,
227            handle_own_alert(Alert, Version, StateName, State0)
228    end.
229
230initial_flight_state(udp)->
231    {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT};
232initial_flight_state(_) ->
233    reliable.
234
235new_flight() ->
236    #{next_sequence => 0,
237      handshakes => [],
238      change_cipher_spec => undefined,
239      handshakes_after_change_cipher_spec => []}.
240
241send_handshake_flight(#state{static_env = #static_env{socket = Socket,
242                                                      transport_cb = Transport},
243                             connection_env = #connection_env{negotiated_version = Version},
244                             flight_buffer = #{handshakes := Flight,
245					       change_cipher_spec := undefined},
246			     connection_states = ConnectionStates0,
247                             ssl_options = #{log_level := LogLevel}} = State0,
248                      Epoch) ->
249    PMTUEstimate = 1400, %% TODO make configurable
250    #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
251    MaxSize = min(MaxFragmentLength, PMTUEstimate),
252    {Encoded, ConnectionStates} =
253	encode_handshake_flight(lists:reverse(Flight), Version, MaxSize, Epoch, ConnectionStates0),
254    send(Transport, Socket, Encoded),
255    ssl_logger:debug(LogLevel, outbound, 'record', Encoded),
256   {State0#state{connection_states = ConnectionStates}, []};
257
258send_handshake_flight(#state{static_env = #static_env{socket = Socket,
259                                                      transport_cb = Transport},
260                             connection_env = #connection_env{negotiated_version = Version},
261			     flight_buffer = #{handshakes := [_|_] = Flight0,
262					       change_cipher_spec := ChangeCipher,
263					       handshakes_after_change_cipher_spec := []},
264			     connection_states = ConnectionStates0,
265                             ssl_options = #{log_level := LogLevel}} = State0,
266                      Epoch) ->
267    PMTUEstimate = 1400, %% TODO make configurable
268    #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
269    MaxSize = min(MaxFragmentLength, PMTUEstimate),
270    {HsBefore, ConnectionStates1} =
271	encode_handshake_flight(lists:reverse(Flight0), Version, MaxSize, Epoch, ConnectionStates0),
272    {EncChangeCipher, ConnectionStates} = encode_change_cipher(ChangeCipher, Version, Epoch, ConnectionStates1),
273
274    send(Transport, Socket, [HsBefore, EncChangeCipher]),
275    ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]),
276    ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
277    {State0#state{connection_states = ConnectionStates}, []};
278
279send_handshake_flight(#state{static_env = #static_env{socket = Socket,
280                                                      transport_cb = Transport},
281                             connection_env = #connection_env{negotiated_version = Version},
282			     flight_buffer = #{handshakes := [_|_] = Flight0,
283					       change_cipher_spec := ChangeCipher,
284					       handshakes_after_change_cipher_spec := Flight1},
285			     connection_states = ConnectionStates0,
286                             ssl_options = #{log_level := LogLevel}} = State0,
287                      Epoch) ->
288    PMTUEstimate = 1400, %% TODO make configurable
289    #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
290    MaxSize = min(MaxFragmentLength, PMTUEstimate),
291    {HsBefore, ConnectionStates1} =
292	encode_handshake_flight(lists:reverse(Flight0), Version, MaxSize, Epoch-1, ConnectionStates0),
293    {EncChangeCipher, ConnectionStates2} =
294	encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates1),
295    {HsAfter, ConnectionStates} =
296	encode_handshake_flight(lists:reverse(Flight1), Version, MaxSize, Epoch, ConnectionStates2),
297    send(Transport, Socket, [HsBefore, EncChangeCipher, HsAfter]),
298    ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]),
299    ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
300    ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]),
301    {State0#state{connection_states = ConnectionStates}, []};
302
303send_handshake_flight(#state{static_env = #static_env{socket = Socket,
304                                                      transport_cb = Transport},
305                             connection_env = #connection_env{negotiated_version = Version},
306			     flight_buffer = #{handshakes := [],
307					       change_cipher_spec := ChangeCipher,
308					       handshakes_after_change_cipher_spec := Flight1},
309			     connection_states = ConnectionStates0,
310                             ssl_options = #{log_level := LogLevel}} = State0,
311                      Epoch) ->
312    PMTUEstimate = 1400, %% TODO make configurable
313    #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0,
314    MaxSize = min(MaxFragmentLength, PMTUEstimate),
315    {EncChangeCipher, ConnectionStates1} =
316	encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates0),
317    {HsAfter, ConnectionStates} =
318	encode_handshake_flight(lists:reverse(Flight1), Version, MaxSize, Epoch, ConnectionStates1),
319    send(Transport, Socket, [EncChangeCipher, HsAfter]),
320    ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
321    ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]),
322    {State0#state{connection_states = ConnectionStates}, []}.
323
324%%% DTLS record protocol level application data messages
325
326handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName0, State0) ->
327    case ssl_gen_statem:read_application_data(Data, State0) of
328	{stop, _, _} = Stop->
329            Stop;
330	{Record, State1} ->
331            {next_state, StateName, State, Actions} = next_event(StateName0, Record, State1),
332            ssl_gen_statem:hibernate_after(StateName, State, Actions)
333    end;
334%%% DTLS record protocol level handshake messages
335handle_protocol_record(#ssl_tls{type = ?HANDSHAKE,
336				       fragment = Data},
337		    StateName,
338                       #state{protocol_buffers = Buffers0,
339                              connection_env = #connection_env{negotiated_version = Version},
340                              ssl_options = Options} = State) ->
341    try
342	case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0, Options) of
343	    {[], Buffers} ->
344		next_event(StateName, no_record, State#state{protocol_buffers = Buffers});
345	    {Packets, Buffers} ->
346		HsEnv = State#state.handshake_env,
347		Events = dtls_handshake_events(Packets),
348                {next_state, StateName,
349                 State#state{protocol_buffers = Buffers,
350                             handshake_env =
351                                 HsEnv#handshake_env{unprocessed_handshake_events
352                                                     = unprocessed_events(Events)}}, Events}
353	end
354    catch throw:#alert{} = Alert ->
355	    handle_own_alert(Alert, Version, StateName, State)
356    end;
357%%% DTLS record protocol level change cipher messages
358handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) ->
359    {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]};
360%%% DTLS record protocol level Alert messages
361handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
362                       #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
363    case decode_alerts(EncAlerts) of
364	Alerts = [_|_] ->
365	    handle_alerts(Alerts,  {next_state, StateName, State});
366	#alert{} = Alert ->
367	    handle_own_alert(Alert, Version, StateName, State)
368    end;
369%% Ignore unknown TLS record level protocol messages
370handle_protocol_record(#ssl_tls{type = _Unknown}, StateName, State) ->
371    {next_state, StateName, State, []}.
372
373%%====================================================================
374%% Handshake handling
375%%====================================================================
376send_handshake(Handshake, #state{connection_states = ConnectionStates} = State) ->
377    #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
378    send_handshake_flight(queue_handshake(Handshake, State), Epoch).
379
380queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
381                                   connection_env = #connection_env{negotiated_version = Version},
382				   flight_buffer = #{handshakes := HsBuffer0,
383						     change_cipher_spec := undefined,
384						     next_sequence := Seq} = Flight0,
385                                   ssl_options = #{log_level := LogLevel}} = State) ->
386    Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
387    Hist = update_handshake_history(Handshake0, Handshake, Hist0),
388    ssl_logger:debug(LogLevel, outbound, 'handshake', Handshake0),
389
390    State#state{flight_buffer = Flight0#{handshakes => [Handshake | HsBuffer0],
391					 next_sequence => Seq +1},
392	handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}};
393
394queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
395                                   connection_env = #connection_env{negotiated_version = Version},
396				   flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0,
397						     next_sequence := Seq} = Flight0,
398                                   ssl_options = #{log_level := LogLevel}} = State) ->
399    Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
400    Hist = update_handshake_history(Handshake0, Handshake, Hist0),
401    ssl_logger:debug(LogLevel, outbound, 'handshake', Handshake0),
402
403    State#state{flight_buffer = Flight0#{handshakes_after_change_cipher_spec => [Handshake | Buffer0],
404					 next_sequence => Seq +1},
405                handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}.
406
407queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight,
408					 connection_states = ConnectionStates0} = State) ->
409    ConnectionStates =
410	dtls_record:next_epoch(ConnectionStates0, write),
411    State#state{flight_buffer = Flight#{change_cipher_spec => ChangeCipher},
412		connection_states = ConnectionStates}.
413
414reinit(State) ->
415    %% To be API compatible with TLS NOOP here
416    reinit_handshake_data(State).
417reinit_handshake_data(#state{static_env = #static_env{data_tag = DataTag},
418                             protocol_buffers = Buffers,
419                             protocol_specific = PS,
420                             handshake_env = HsEnv} = State) ->
421    State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(),
422                                                    public_key_info = undefined,
423                                                    premaster_secret = undefined},
424                protocol_specific = PS#{flight_state => initial_flight_state(DataTag)},
425		flight_buffer = new_flight(),
426                protocol_buffers =
427		    Buffers#protocol_buffers{
428                      dtls_handshake_next_seq = 0,
429		      dtls_handshake_next_fragments = [],
430		      dtls_handshake_later_fragments = []
431		     }}.
432
433select_sni_extension(#client_hello{extensions = #{sni := SNI}}) ->
434    SNI;
435select_sni_extension(_) ->
436    undefined.
437
438empty_connection_state(ConnectionEnd, BeastMitigation) ->
439    Empty = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
440    dtls_record:empty_connection_state(Empty).
441%%====================================================================
442%% Alert and close handling
443%%====================================================================
444encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
445    dtls_record:encode_alert_record(Alert, Version, ConnectionStates).
446
447send_alert(Alert, #state{static_env = #static_env{socket = Socket,
448                                                  transport_cb = Transport},
449
450                         connection_env = #connection_env{negotiated_version = Version},
451			 connection_states = ConnectionStates0,
452                         ssl_options = #{log_level := LogLevel}} = State0) ->
453    {BinMsg, ConnectionStates} =
454	encode_alert(Alert, Version, ConnectionStates0),
455    send(Transport, Socket, BinMsg),
456    ssl_logger:debug(LogLevel, outbound, 'record', BinMsg),
457    State0#state{connection_states = ConnectionStates}.
458
459send_alert_in_connection(Alert, State) ->
460    _ = send_alert(Alert, State),
461    ok.
462
463close(downgrade, _,_,_,_) ->
464    ok;
465%% Other
466close(_, Socket, Transport, _,_) ->
467    dtls_socket:close(Transport,Socket).
468
469protocol_name() ->
470    "DTLS".
471
472%%====================================================================
473%% Data handling
474%%====================================================================
475send(Transport, {Listener, Socket}, Data) when is_pid(Listener) ->
476    %% Server socket
477    dtls_socket:send(Transport, Socket, Data);
478send(Transport, Socket, Data) -> % Client socket
479    dtls_socket:send(Transport, Socket, Data).
480
481socket(Pid,  Transport, Socket, _Tracker) ->
482    dtls_socket:socket(Pid, Transport, Socket, ?MODULE).
483
484setopts(Transport, Socket, Other) ->
485    dtls_socket:setopts(Transport, Socket, Other).
486
487getopts(Transport, Socket, Tag) ->
488    dtls_socket:getopts(Transport, Socket, Tag).
489
490%% raw data from socket, unpack records
491handle_info({Protocol, _, _, _, Data}, StateName,
492            #state{static_env = #static_env{role = Role,
493                                            data_tag = Protocol}} = State0) ->
494    case next_dtls_record(Data, StateName, State0) of
495	{Record, State} ->
496	    next_event(StateName, Record, State);
497	#alert{} = Alert ->
498	    ssl_gen_statem:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State0),
499            {stop, {shutdown, own_alert}, State0}
500    end;
501
502handle_info({PassiveTag, Socket}, StateName,
503            #state{static_env = #static_env{socket = {_, Socket},
504                                            passive_tag = PassiveTag},
505                   protocol_specific = PS} = State) ->
506    next_event(StateName, no_record,
507               State#state{protocol_specific = PS#{active_n_toggle => true}});
508
509handle_info({CloseTag, Socket}, StateName,
510	    #state{static_env = #static_env{
511                                   role = Role,
512                                   socket = Socket,
513                                   close_tag = CloseTag},
514                   connection_env = #connection_env{negotiated_version = Version},
515                   socket_options = #socket_options{active = Active},
516                   protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs},
517                   protocol_specific = PS} = State) ->
518    %% Note that as of DTLS 1.2 (TLS 1.1),
519    %% failure to properly close a connection no longer requires that a
520    %% session not be resumed.	This is a change from DTLS 1.0 to conform
521    %% with widespread implementation practice.
522    case (Active == false) andalso (CTs =/= []) of
523        false ->
524            case Version of
525                {254, N} when N =< 253 ->
526                    ok;
527                _ ->
528                    %% As invalidate_sessions here causes performance issues,
529                    %% we will conform to the widespread implementation
530                    %% practice and go aginst the spec
531                    %%invalidate_session(Role, Host, Port, Session)
532                    ok
533            end,
534            Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, transport_closed),
535            ssl_gen_statem:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
536            {stop, {shutdown, transport_closed}, State};
537        true ->
538            %% Fixes non-delivery of final DTLS record in {active, once}.
539            %% Basically allows the application the opportunity to set {active, once} again
540            %% and then receive the final message.
541            next_event(StateName, no_record, State#state{
542                                               protocol_specific = PS#{active_n_toggle => true}})
543    end;
544
545handle_info(new_cookie_secret, StateName,
546            #state{protocol_specific = #{current_cookie_secret := Secret} = CookieInfo} = State) ->
547    erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret),
548    {next_state, StateName, State#state{protocol_specific =
549                                            CookieInfo#{current_cookie_secret => dtls_v1:cookie_secret(),
550                                                        previous_cookie_secret => Secret}}};
551handle_info(Msg, StateName, State) ->
552    ssl_gen_statem:handle_info(Msg, StateName, State).
553
554%%====================================================================
555%% Internal functions
556%%====================================================================
557
558dtls_handshake_events(Packets) ->
559    lists:map(fun(Packet) ->
560		      {next_event, internal, {handshake, Packet}}
561	      end, Packets).
562
563unprocessed_events(Events) ->
564    %% The first handshake event will be processed immediately
565    %% as it is entered first in the event queue and
566    %% when it is processed there will be length(Events)-1
567    %% handshake events left to process before we should
568    %% process more TLS-records received on the socket.
569    erlang:length(Events)-1.
570
571encode_handshake_flight(Flight, Version, MaxFragmentSize, Epoch, ConnectionStates) ->
572    Fragments = lists:map(fun(Handshake) ->
573				  dtls_handshake:fragment_handshake(Handshake, MaxFragmentSize)
574			  end, Flight),
575    dtls_record:encode_handshake(Fragments, Version, Epoch, ConnectionStates).
576
577encode_change_cipher(#change_cipher_spec{}, Version, Epoch, ConnectionStates) ->
578    dtls_record:encode_change_cipher_spec(Version, Epoch, ConnectionStates).
579
580update_handshake_history(#hello_verify_request{}, _, Hist) ->
581    Hist;
582update_handshake_history(_, Handshake, Hist) ->
583    ssl_handshake:update_handshake_history(Hist, iolist_to_binary(Handshake)).
584
585next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
586						   dtls_record_buffer = Buf0,
587						   dtls_cipher_texts = CT0} = Buffers,
588                                         connection_env = #connection_env{negotiated_version = Version},
589                                         static_env = #static_env{data_tag = DataTag},
590                                         ssl_options = SslOpts} = State0) ->
591    case dtls_record:get_dtls_records(Data,
592                                      {DataTag, StateName, Version,
593                                       [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS]},
594                                      Buf0, SslOpts) of
595	{Records, Buf1} ->
596	    CT1 = CT0 ++ Records,
597	    next_record(State0#state{protocol_buffers =
598					 Buffers#protocol_buffers{dtls_record_buffer = Buf1,
599								  dtls_cipher_texts = CT1}});
600	#alert{} = Alert ->
601	    Alert
602    end.
603
604
605
606decode_cipher_text(#state{protocol_buffers = #protocol_buffers{dtls_cipher_texts = [ CT | Rest]} = Buffers,
607                          connection_states = ConnStates0} = State) ->
608    case dtls_record:decode_cipher_text(CT, ConnStates0) of
609	{Plain, ConnStates} ->
610	    {Plain, State#state{protocol_buffers =
611				    Buffers#protocol_buffers{dtls_cipher_texts = Rest},
612				connection_states = ConnStates}};
613	#alert{} = Alert ->
614	    {Alert, State}
615    end.
616
617decode_alerts(Bin) ->
618    ssl_alert:decode(Bin).
619
620handle_alerts([], Result) ->
621    Result;
622handle_alerts(_, {stop, _, _} = Stop) ->
623    Stop;
624handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
625     handle_alerts(Alerts, ssl_gen_statem:handle_alert(Alert, StateName, State));
626handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
627     handle_alerts(Alerts, ssl_gen_statem:handle_alert(Alert, StateName, State)).
628
629handle_own_alert(Alert, Version, StateName,
630                 #state{static_env = #static_env{data_tag = udp,
631                                                 role = Role},
632                        ssl_options = #{log_level := LogLevel}} = State0) ->
633    case ignore_alert(Alert, State0) of
634        {true, State} ->
635            log_ignore_alert(LogLevel, StateName, Alert, Role),
636            {next_state, StateName, State};
637        {false, State} ->
638            ssl_gen_statem:handle_own_alert(Alert, Version, StateName, State)
639    end;
640handle_own_alert(Alert, Version, StateName, State) ->
641    ssl_gen_statem:handle_own_alert(Alert, Version, StateName, State).
642ignore_alert(#alert{level = ?FATAL}, #state{protocol_specific = #{ignored_alerts := N,
643                                                  max_ignored_alerts := N}} = State) ->
644    {false, State};
645ignore_alert(#alert{level = ?FATAL} = Alert,
646             #state{protocol_specific = #{ignored_alerts := N} = PS} = State) ->
647    case is_ignore_alert(Alert) of
648        true ->
649            {true, State#state{protocol_specific = PS#{ignored_alerts => N+1}}};
650        false ->
651            {false, State}
652    end;
653ignore_alert(_, State) ->
654    {false, State}.
655
656%% RFC 6347 4.1.2.7.  Handling Invalid Records
657%% recommends to silently ignore invalid DTLS records when
658%% upd is the transport. Note we do not support compression so no need
659%% include ?DECOMPRESSION_FAILURE
660is_ignore_alert(#alert{description = ?BAD_RECORD_MAC}) ->
661    true;
662is_ignore_alert(#alert{description = ?RECORD_OVERFLOW}) ->
663    true;
664is_ignore_alert(#alert{description = ?DECODE_ERROR}) ->
665    true;
666is_ignore_alert(#alert{description = ?DECRYPT_ERROR}) ->
667    true;
668is_ignore_alert(#alert{description = ?ILLEGAL_PARAMETER}) ->
669     true;
670is_ignore_alert(_) ->
671    false.
672
673log_ignore_alert(Level, StateName, #alert{where = Location} = Alert, Role) ->
674    ssl_logger:log(info,
675                   Level, #{alert => Alert,
676                            alerter => ignored,
677                            statename => StateName,
678                            role => Role,
679                            protocol => protocol_name()}, Location).
680
681dtls_version(hello, Version, #state{static_env = #static_env{role = server},
682                                    connection_env = CEnv} = State) ->
683    State#state{connection_env = CEnv#connection_env{negotiated_version = Version}}; %%Inital version
684dtls_version(_,_, State) ->
685    State.
686