1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2013-2019. 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: Handle DTLS record protocol. (Parts that are not shared with SSL/TLS)
23%%----------------------------------------------------------------------
24-module(dtls_record).
25
26-include("dtls_record.hrl").
27-include("ssl_internal.hrl").
28-include("ssl_alert.hrl").
29-include("dtls_handshake.hrl").
30-include("ssl_cipher.hrl").
31
32%% Handling of incoming data
33-export([get_dtls_records/3,  init_connection_states/2, empty_connection_state/1]).
34
35-export([save_current_connection_state/2, next_epoch/2, get_connection_state_by_epoch/3, replay_detect/2,
36         init_connection_state_seq/2, current_connection_state_epoch/2]).
37
38%% Encoding
39-export([encode_handshake/4, encode_alert_record/3,
40	 encode_change_cipher_spec/3, encode_data/3, encode_plain_text/5]).
41
42%% Decoding
43-export([decode_cipher_text/2]).
44
45%% Protocol version handling
46-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2,
47	 highest_protocol_version/1, highest_protocol_version/2,
48	 is_higher/2, supported_protocol_versions/0,
49	 is_acceptable_version/2, hello_version/2]).
50
51
52-export_type([dtls_atom_version/0]).
53
54-type dtls_atom_version()  :: dtlsv1 | 'dtlsv1.2'.
55
56-define(REPLAY_WINDOW_SIZE, 64).
57
58-compile(inline).
59
60%%====================================================================
61%%  Handling of incoming data
62%%====================================================================
63%%--------------------------------------------------------------------
64-spec init_connection_states(client | server, one_n_minus_one | zero_n | disabled) ->
65 				    ssl_record:connection_states().
66%% %
67						%
68%% Description: Creates a connection_states record with appropriate
69%% values for the initial SSL connection setup.
70%%--------------------------------------------------------------------
71init_connection_states(Role, BeastMitigation) ->
72    ConnectionEnd = ssl_record:record_protocol_role(Role),
73    Initial = initial_connection_state(ConnectionEnd, BeastMitigation),
74    Current = Initial#{epoch := 0},
75    InitialPending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
76    Pending = empty_connection_state(InitialPending),
77    #{saved_read  => Current,
78      current_read  => Current,
79      pending_read  => Pending,
80      saved_write => Current,
81      current_write => Current,
82      pending_write => Pending}.
83
84empty_connection_state(Empty) ->
85    Empty#{epoch => undefined, replay_window => init_replay_window(?REPLAY_WINDOW_SIZE)}.
86
87%%--------------------------------------------------------------------
88-spec save_current_connection_state(ssl_record:connection_states(), read | write) ->
89				      ssl_record:connection_states().
90%%
91%% Description: Returns the instance of the connection_state map
92%% where the current read|write state has been copied to the save state.
93%%--------------------------------------------------------------------
94save_current_connection_state(#{current_read := Current} = States, read) ->
95    States#{saved_read := Current};
96
97save_current_connection_state(#{current_write := Current} = States, write) ->
98    States#{saved_write := Current}.
99
100next_epoch(#{pending_read := Pending,
101	     current_read := #{epoch := Epoch}} = States, read) ->
102    States#{pending_read := Pending#{epoch := Epoch + 1,
103                                     replay_window := init_replay_window(?REPLAY_WINDOW_SIZE)}};
104
105next_epoch(#{pending_write := Pending,
106	     current_write := #{epoch := Epoch}} = States, write) ->
107    States#{pending_write := Pending#{epoch := Epoch + 1,
108                                      replay_window := init_replay_window(?REPLAY_WINDOW_SIZE)}}.
109
110get_connection_state_by_epoch(Epoch, #{current_write := #{epoch := Epoch} = Current},
111			      write) ->
112    Current;
113get_connection_state_by_epoch(Epoch, #{saved_write := #{epoch := Epoch} = Saved},
114			      write) ->
115    Saved;
116get_connection_state_by_epoch(Epoch, #{current_read := #{epoch := Epoch} = Current},
117			      read) ->
118    Current;
119get_connection_state_by_epoch(Epoch, #{saved_read := #{epoch := Epoch} = Saved},
120			      read) ->
121    Saved.
122
123set_connection_state_by_epoch(WriteState, Epoch, #{current_write := #{epoch := Epoch}} = States,
124			      write) ->
125    States#{current_write := WriteState};
126set_connection_state_by_epoch(WriteState, Epoch, #{saved_write := #{epoch := Epoch}} = States,
127			      write) ->
128    States#{saved_write := WriteState};
129set_connection_state_by_epoch(ReadState, Epoch, #{current_read := #{epoch := Epoch}} = States,
130			      read) ->
131    States#{current_read := ReadState};
132set_connection_state_by_epoch(ReadState, Epoch, #{saved_read := #{epoch := Epoch}} = States,
133			      read) ->
134    States#{saved_read := ReadState}.
135
136%%--------------------------------------------------------------------
137-spec init_connection_state_seq(ssl_record:ssl_version(), ssl_record:connection_states()) ->
138				       ssl_record:connection_state().
139%%
140%% Description: Copy the read sequence number to the write sequence number
141%% This is only valid for DTLS in the first client_hello
142%%--------------------------------------------------------------------
143init_connection_state_seq({254, _},
144			  #{current_read := #{epoch := 0, sequence_number := Seq},
145			    current_write := #{epoch := 0} = Write} = ConnnectionStates0) ->
146    ConnnectionStates0#{current_write => Write#{sequence_number => Seq}};
147init_connection_state_seq(_, ConnnectionStates) ->
148    ConnnectionStates.
149
150%%--------------------------------------------------------
151-spec current_connection_state_epoch(ssl_record:connection_states(), read | write) ->
152					    integer().
153%%
154%% Description: Returns the epoch the connection_state record
155%% that is currently defined as the current connection state.
156%%--------------------------------------------------------------------
157current_connection_state_epoch(#{current_read := #{epoch := Epoch}},
158			       read) ->
159    Epoch;
160current_connection_state_epoch(#{current_write := #{epoch := Epoch}},
161			       write) ->
162    Epoch.
163
164%%--------------------------------------------------------------------
165-spec get_dtls_records(binary(), [ssl_record:ssl_version()], binary()) -> {[binary()], binary()} | #alert{}.
166%%
167%% Description: Given old buffer and new data from UDP/SCTP, packs up a records
168%% and returns it as a list of tls_compressed binaries also returns leftover
169%% data
170%%--------------------------------------------------------------------
171get_dtls_records(Data, Versions, Buffer) ->
172    BinData = list_to_binary([Buffer, Data]),
173    case erlang:byte_size(BinData) of
174        N when N >= 3 ->
175            case assert_version(BinData, Versions) of
176                true ->
177                    get_dtls_records_aux(BinData, []);
178                false ->
179                    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
180            end;
181        _ ->
182            get_dtls_records_aux(BinData, [])
183    end.
184
185%%====================================================================
186%% Encoding DTLS records
187%%====================================================================
188
189%%--------------------------------------------------------------------
190-spec encode_handshake(iolist(), ssl_record:ssl_version(), integer(), ssl_record:connection_states()) ->
191			      {iolist(), ssl_record:connection_states()}.
192%
193%% Description: Encodes a handshake message to send on the ssl-socket.
194%%--------------------------------------------------------------------
195encode_handshake(Frag, Version, Epoch, ConnectionStates) ->
196    encode_plain_text(?HANDSHAKE, Version, Epoch, Frag, ConnectionStates).
197
198
199%%--------------------------------------------------------------------
200-spec encode_alert_record(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
201				 {iolist(), ssl_record:connection_states()}.
202%%
203%% Description: Encodes an alert message to send on the ssl-socket.
204%%--------------------------------------------------------------------
205encode_alert_record(#alert{level = Level, description = Description},
206                    Version, ConnectionStates) ->
207    #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
208    encode_plain_text(?ALERT, Version, Epoch, <<?BYTE(Level), ?BYTE(Description)>>,
209		      ConnectionStates).
210
211%%--------------------------------------------------------------------
212-spec encode_change_cipher_spec(ssl_record:ssl_version(), integer(), ssl_record:connection_states()) ->
213				       {iolist(), ssl_record:connection_states()}.
214%%
215%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
216%%--------------------------------------------------------------------
217encode_change_cipher_spec(Version, Epoch, ConnectionStates) ->
218    encode_plain_text(?CHANGE_CIPHER_SPEC, Version, Epoch, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
219
220%%--------------------------------------------------------------------
221-spec encode_data(binary(), ssl_record:ssl_version(), ssl_record:connection_states()) ->
222			 {iolist(),ssl_record:connection_states()}.
223%%
224%% Description: Encodes data to send on the ssl-socket.
225%%--------------------------------------------------------------------
226encode_data(Data, Version, ConnectionStates) ->
227    #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
228    encode_plain_text(?APPLICATION_DATA, Version, Epoch, Data, ConnectionStates).
229
230encode_plain_text(Type, Version, Epoch, Data, ConnectionStates) ->
231    Write0 = get_connection_state_by_epoch(Epoch, ConnectionStates, write),
232    {CipherFragment, Write1} = encode_plain_text(Type, Version, Data, Write0),
233    {CipherText, Write} = encode_dtls_cipher_text(Type, Version, CipherFragment, Write1),
234    {CipherText, set_connection_state_by_epoch(Write, Epoch, ConnectionStates, write)}.
235
236%%====================================================================
237%% Decoding
238%%====================================================================
239
240decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) ->
241    ReadState = get_connection_state_by_epoch(Epoch, ConnnectionStates0, read),
242    decode_cipher_text(CipherText, ReadState, ConnnectionStates0).
243
244
245%%====================================================================
246%% Protocol version handling
247%%====================================================================
248
249%%--------------------------------------------------------------------
250-spec protocol_version(dtls_atom_version() | ssl_record:ssl_version()) ->
251			      ssl_record:ssl_version() | dtls_atom_version().
252%%
253%% Description: Creates a protocol version record from a version atom
254%% or vice versa.
255%%--------------------------------------------------------------------
256protocol_version('dtlsv1.2') ->
257    {254, 253};
258protocol_version(dtlsv1) ->
259    {254, 255};
260protocol_version({254, 253}) ->
261    'dtlsv1.2';
262protocol_version({254, 255}) ->
263    dtlsv1.
264%%--------------------------------------------------------------------
265-spec lowest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version().
266%%
267%% Description: Lowes protocol version of two given versions
268%%--------------------------------------------------------------------
269lowest_protocol_version(Version = {M, N}, {M, O}) when N > O ->
270    Version;
271lowest_protocol_version({M, _}, Version = {M, _}) ->
272    Version;
273lowest_protocol_version(Version = {M,_}, {N, _}) when M > N ->
274    Version;
275lowest_protocol_version(_,Version) ->
276    Version.
277
278%%--------------------------------------------------------------------
279-spec lowest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version().
280%%
281%% Description: Lowest protocol version present in a list
282%%--------------------------------------------------------------------
283lowest_protocol_version([]) ->
284    lowest_protocol_version();
285lowest_protocol_version(Versions) ->
286    [Ver | Vers] = Versions,
287    lowest_list_protocol_version(Ver, Vers).
288
289%%--------------------------------------------------------------------
290-spec highest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version().
291%%
292%% Description: Highest protocol version present in a list
293%%--------------------------------------------------------------------
294highest_protocol_version([]) ->
295    highest_protocol_version();
296highest_protocol_version(Versions) ->
297    [Ver | Vers] = Versions,
298    highest_list_protocol_version(Ver, Vers).
299
300%%--------------------------------------------------------------------
301-spec highest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version().
302%%
303%% Description: Highest protocol version of two given versions
304%%--------------------------------------------------------------------
305highest_protocol_version(Version = {M, N}, {M, O})   when N < O ->
306    Version;
307highest_protocol_version({M, _},
308			Version = {M, _}) ->
309    Version;
310highest_protocol_version(Version = {M,_},
311			{N, _}) when M < N ->
312    Version;
313highest_protocol_version(_,Version) ->
314    Version.
315
316%%--------------------------------------------------------------------
317-spec is_higher(V1 :: ssl_record:ssl_version(), V2::ssl_record:ssl_version()) -> boolean().
318%%
319%% Description: Is V1 > V2
320%%--------------------------------------------------------------------
321is_higher({M, N}, {M, O}) when N < O ->
322    true;
323is_higher({M, _}, {N, _}) when M < N ->
324    true;
325is_higher(_, _) ->
326    false.
327
328%%--------------------------------------------------------------------
329-spec supported_protocol_versions() -> [ssl_record:ssl_version()].
330%%
331%% Description: Protocol versions supported
332%%--------------------------------------------------------------------
333supported_protocol_versions() ->
334    Fun = fun(Version) ->
335		  protocol_version(Version)
336	  end,
337    case application:get_env(ssl, dtls_protocol_version) of
338	undefined ->
339	    lists:map(Fun, supported_protocol_versions([]));
340	{ok, []} ->
341	    lists:map(Fun, supported_protocol_versions([]));
342	{ok, Vsns} when is_list(Vsns) ->
343	    supported_protocol_versions(lists:map(Fun, Vsns));
344	{ok, Vsn} ->
345	    supported_protocol_versions([Fun(Vsn)])
346     end.
347
348supported_protocol_versions([]) ->
349    Vsns = case sufficient_dtlsv1_2_crypto_support() of
350	       true ->
351		   ?ALL_DATAGRAM_SUPPORTED_VERSIONS;
352	       false ->
353		   ?MIN_DATAGRAM_SUPPORTED_VERSIONS
354	   end,
355    application:set_env(ssl, dtls_protocol_version, Vsns),
356    Vsns;
357
358supported_protocol_versions([_|_] = Vsns) ->
359    case sufficient_dtlsv1_2_crypto_support() of
360	true ->
361	    Vsns;
362	false ->
363	    case Vsns -- ['dtlsv1.2'] of
364		[] ->
365		    ?MIN_SUPPORTED_VERSIONS;
366		NewVsns ->
367		    NewVsns
368	    end
369    end.
370
371%%--------------------------------------------------------------------
372-spec is_acceptable_version(ssl_record:ssl_version(), Supported :: [ssl_record:ssl_version()]) -> boolean().
373%%
374%% Description: ssl version 2 is not acceptable security risks are too big.
375%%
376%%--------------------------------------------------------------------
377is_acceptable_version(Version, Versions) ->
378    lists:member(Version, Versions).
379
380-spec hello_version(ssl_record:ssl_version(), [ssl_record:ssl_version()]) -> ssl_record:ssl_version().
381hello_version(Version, Versions) ->
382    case dtls_v1:corresponding_tls_version(Version) of
383        TLSVersion when TLSVersion >= {3, 3} ->
384            Version;
385        _ ->
386            lowest_protocol_version(Versions)
387    end.
388
389
390%%--------------------------------------------------------------------
391%%% Internal functions
392%%--------------------------------------------------------------------
393initial_connection_state(ConnectionEnd, BeastMitigation) ->
394    #{security_parameters =>
395	  ssl_record:initial_security_params(ConnectionEnd),
396      epoch => undefined,
397      sequence_number => 0,
398      replay_window => init_replay_window(?REPLAY_WINDOW_SIZE),
399      beast_mitigation => BeastMitigation,
400      compression_state  => undefined,
401      cipher_state  => undefined,
402      mac_secret  => undefined,
403      secure_renegotiation => undefined,
404      client_verify_data => undefined,
405      server_verify_data => undefined
406     }.
407assert_version(<<?BYTE(_), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>>, Versions) ->
408    is_acceptable_version({MajVer, MinVer}, Versions).
409
410get_dtls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
411		       ?UINT16(Epoch), ?UINT48(SequenceNumber),
412		       ?UINT16(Length), Data:Length/binary, Rest/binary>>,
413		     Acc) ->
414    get_dtls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
415					 version = {MajVer, MinVer},
416					 epoch = Epoch, sequence_number = SequenceNumber,
417					 fragment = Data} | Acc]);
418get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
419		       ?UINT16(Epoch), ?UINT48(SequenceNumber),
420		       ?UINT16(Length),
421		       Data:Length/binary, Rest/binary>>, Acc) when MajVer >= 128 ->
422    get_dtls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
423					 version = {MajVer, MinVer},
424					 epoch = Epoch, sequence_number = SequenceNumber,
425					 fragment = Data} | Acc]);
426get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
427		       ?UINT16(Epoch), ?UINT48(SequenceNumber),
428		       ?UINT16(Length), Data:Length/binary,
429		       Rest/binary>>, Acc) ->
430    get_dtls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
431					 version = {MajVer, MinVer},
432					 epoch = Epoch, sequence_number = SequenceNumber,
433					 fragment = Data} | Acc]);
434get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
435		       ?UINT16(Epoch), ?UINT48(SequenceNumber),
436		       ?UINT16(Length), Data:Length/binary, Rest/binary>>,
437		     Acc) ->
438    get_dtls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
439					 version = {MajVer, MinVer},
440					 epoch = Epoch, sequence_number = SequenceNumber,
441					 fragment = Data} | Acc]);
442get_dtls_records_aux(<<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer),
443		       ?UINT16(Length), _/binary>>,
444		     _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
445    ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
446
447get_dtls_records_aux(Data, Acc) ->
448    case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
449	true ->
450	    {lists:reverse(Acc), Data};
451	false ->
452	    ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
453    end.
454%%--------------------------------------------------------------------
455
456init_replay_window(Size) ->
457    #{size => Size,
458      top => Size,
459      bottom => 0,
460      mask => 0 bsl 64
461     }.
462
463replay_detect(#ssl_tls{sequence_number = SequenceNumber}, #{replay_window := Window}) ->
464    is_replay(SequenceNumber, Window).
465
466
467is_replay(SequenceNumber, #{bottom := Bottom}) when SequenceNumber < Bottom ->
468    true;
469is_replay(SequenceNumber, #{size := Size,
470                            top := Top,
471                            bottom := Bottom,
472                            mask :=  Mask})  when (SequenceNumber >= Bottom) andalso (SequenceNumber =< Top) ->
473    Index = (SequenceNumber rem Size),
474    (Index band Mask) == 1;
475
476is_replay(_, _) ->
477    false.
478
479update_replay_window(SequenceNumber,  #{replay_window := #{size := Size,
480                                                           top := Top,
481                                                           bottom := Bottom,
482                                                           mask :=  Mask0} = Window0} = ConnectionStates) ->
483    NoNewBits = SequenceNumber - Top,
484    Index = SequenceNumber rem Size,
485    Mask = (Mask0 bsl NoNewBits) bor Index,
486    Window =  Window0#{top => SequenceNumber,
487                       bottom => Bottom + NoNewBits,
488                       mask => Mask},
489    ConnectionStates#{replay_window := Window}.
490
491%%--------------------------------------------------------------------
492
493encode_dtls_cipher_text(Type, {MajVer, MinVer}, Fragment,
494		       #{epoch := Epoch, sequence_number := Seq} = WriteState) ->
495    Length = erlang:iolist_size(Fragment),
496    {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Epoch),
497	?UINT48(Seq), ?UINT16(Length)>>, Fragment],
498     WriteState#{sequence_number => Seq + 1}}.
499
500encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
501                                         cipher_state := CipherS0,
502					 epoch := Epoch,
503					 sequence_number := Seq,
504					 security_parameters :=
505					     #security_parameters{
506						cipher_type = ?AEAD,
507                                                bulk_cipher_algorithm = BCAlg,
508						compression_algorithm = CompAlg}
509					} = WriteState0) ->
510    {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
511    AAD = start_additional_data(Type, Version, Epoch, Seq),
512    CipherS = ssl_record:nonce_seed(BCAlg, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
513    WriteState = WriteState0#{compression_state => CompS1,
514                              cipher_state => CipherS},
515    TLSVersion = dtls_v1:corresponding_tls_version(Version),
516    ssl_record:cipher_aead(TLSVersion, Comp, WriteState, AAD);
517encode_plain_text(Type, Version, Fragment, #{compression_state := CompS0,
518					 epoch := Epoch,
519					 sequence_number := Seq,
520                                         cipher_state := CipherS0,
521					 security_parameters :=
522					     #security_parameters{compression_algorithm = CompAlg,
523                                                                  bulk_cipher_algorithm =
524                                                                      BulkCipherAlgo}
525					}= WriteState0) ->
526    {Comp, CompS1} = ssl_record:compress(CompAlg, Fragment, CompS0),
527    WriteState1 = WriteState0#{compression_state => CompS1},
528    MAC = calc_mac_hash(Type, Version, WriteState1, Epoch, Seq, Comp),
529    TLSVersion = dtls_v1:corresponding_tls_version(Version),
530    {CipherFragment, CipherS1} =
531	ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MAC, Fragment, TLSVersion),
532    {CipherFragment,  WriteState0#{cipher_state => CipherS1}}.
533
534%%--------------------------------------------------------------------
535decode_cipher_text(#ssl_tls{type = Type, version = Version,
536			    epoch = Epoch,
537			    sequence_number = Seq,
538			    fragment = CipherFragment} = CipherText,
539		   #{compression_state := CompressionS0,
540                     cipher_state := CipherS0,
541		     security_parameters :=
542			 #security_parameters{
543			    cipher_type = ?AEAD,
544                            bulk_cipher_algorithm =
545                                BulkCipherAlgo,
546			    compression_algorithm = CompAlg}} = ReadState0,
547		   ConnnectionStates0) ->
548    AAD = start_additional_data(Type, Version, Epoch, Seq),
549    CipherS = ssl_record:nonce_seed(BulkCipherAlgo, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
550    TLSVersion = dtls_v1:corresponding_tls_version(Version),
551    case ssl_record:decipher_aead(BulkCipherAlgo, CipherS, AAD, CipherFragment, TLSVersion) of
552	PlainFragment when is_binary(PlainFragment) ->
553	    {Plain, CompressionS} = ssl_record:uncompress(CompAlg,
554							   PlainFragment, CompressionS0),
555	    ReadState1 = ReadState0#{compression_state := CompressionS,
556                                     cipher_state := CipherS},
557            ReadState = update_replay_window(Seq, ReadState1),
558	    ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
559	    {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
560	  #alert{} = Alert ->
561	    Alert
562    end;
563decode_cipher_text(#ssl_tls{type = Type, version = Version,
564			    epoch = Epoch,
565			    sequence_number = Seq,
566			    fragment = CipherFragment} = CipherText,
567		   #{compression_state := CompressionS0,
568		     security_parameters :=
569			 #security_parameters{
570			    compression_algorithm = CompAlg}} = ReadState0,
571		   ConnnectionStates0) ->
572    {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
573							   CipherFragment, ReadState0, true),
574    MacHash = calc_mac_hash(Type, Version, ReadState1, Epoch, Seq, PlainFragment),
575    case ssl_record:is_correct_mac(Mac, MacHash) of
576	true ->
577	    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
578							   PlainFragment, CompressionS0),
579
580	    ReadState2 = ReadState1#{compression_state => CompressionS1},
581            ReadState = update_replay_window(Seq, ReadState2),
582	    ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
583	    {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
584	false ->
585	    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
586    end.
587%%--------------------------------------------------------------------
588
589calc_mac_hash(Type, Version, #{mac_secret := MacSecret,
590			       security_parameters := #security_parameters{mac_algorithm = MacAlg}},
591	      Epoch, SeqNo, Fragment) ->
592    Length = erlang:iolist_size(Fragment),
593    mac_hash(Version, MacAlg, MacSecret, Epoch, SeqNo, Type,
594	     Length, Fragment).
595
596mac_hash({Major, Minor}, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment) ->
597    Value = [<<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type),
598       ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>,
599     Fragment],
600    dtls_v1:hmac_hash(MacAlg, MacSecret, Value).
601
602start_additional_data(Type, {MajVer, MinVer}, Epoch, SeqNo) ->
603    <<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
604
605%%--------------------------------------------------------------------
606
607lowest_list_protocol_version(Ver, []) ->
608    Ver;
609lowest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
610    lowest_list_protocol_version(lowest_protocol_version(Ver1, Ver2), Rest).
611
612highest_list_protocol_version(Ver, []) ->
613    Ver;
614highest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
615    highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
616
617highest_protocol_version() ->
618    highest_protocol_version(supported_protocol_versions()).
619
620lowest_protocol_version() ->
621    lowest_protocol_version(supported_protocol_versions()).
622
623sufficient_dtlsv1_2_crypto_support() ->
624    CryptoSupport = crypto:supports(),
625    proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
626
627