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/4,  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(), {atom(), atom(), ssl_record:ssl_version(), [ssl_record:ssl_version()]}, binary(),
166                       ssl_options()) -> {[binary()], binary()} | #alert{}.
167%%
168%% Description: Given old buffer and new data from UDP/SCTP, packs up a records
169%% and returns it as a list of tls_compressed binaries also returns leftover
170%% data
171%%--------------------------------------------------------------------
172get_dtls_records(Data, Vinfo, Buffer, SslOpts) ->
173    BinData = list_to_binary([Buffer, Data]),
174    get_dtls_records_aux(Vinfo, BinData, [], SslOpts).
175
176%%====================================================================
177%% Encoding DTLS records
178%%====================================================================
179
180%%--------------------------------------------------------------------
181-spec encode_handshake(iolist(), ssl_record:ssl_version(), integer(), ssl_record:connection_states()) ->
182			      {iolist(), ssl_record:connection_states()}.
183%
184%% Description: Encodes a handshake message to send on the ssl-socket.
185%%--------------------------------------------------------------------
186encode_handshake(Frag, Version, Epoch, ConnectionStates) ->
187    encode_plain_text(?HANDSHAKE, Version, Epoch, Frag, ConnectionStates).
188
189
190%%--------------------------------------------------------------------
191-spec encode_alert_record(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
192				 {iolist(), ssl_record:connection_states()}.
193%%
194%% Description: Encodes an alert message to send on the ssl-socket.
195%%--------------------------------------------------------------------
196encode_alert_record(#alert{level = Level, description = Description},
197                    Version, ConnectionStates) ->
198    #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
199    encode_plain_text(?ALERT, Version, Epoch, <<?BYTE(Level), ?BYTE(Description)>>,
200		      ConnectionStates).
201
202%%--------------------------------------------------------------------
203-spec encode_change_cipher_spec(ssl_record:ssl_version(), integer(), ssl_record:connection_states()) ->
204				       {iolist(), ssl_record:connection_states()}.
205%%
206%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
207%%--------------------------------------------------------------------
208encode_change_cipher_spec(Version, Epoch, ConnectionStates) ->
209    encode_plain_text(?CHANGE_CIPHER_SPEC, Version, Epoch, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
210
211%%--------------------------------------------------------------------
212-spec encode_data(binary(), ssl_record:ssl_version(), ssl_record:connection_states()) ->
213			 {iolist(),ssl_record:connection_states()}.
214%%
215%% Description: Encodes data to send on the ssl-socket.
216%%--------------------------------------------------------------------
217encode_data(Data, Version, ConnectionStates) ->
218    #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
219    encode_plain_text(?APPLICATION_DATA, Version, Epoch, Data, ConnectionStates).
220
221encode_plain_text(Type, Version, Epoch, Data, ConnectionStates) ->
222    Write0 = get_connection_state_by_epoch(Epoch, ConnectionStates, write),
223    {CipherFragment, Write1} = encode_plain_text(Type, Version, Data, Write0),
224    {CipherText, Write} = encode_dtls_cipher_text(Type, Version, CipherFragment, Write1),
225    {CipherText, set_connection_state_by_epoch(Write, Epoch, ConnectionStates, write)}.
226
227%%====================================================================
228%% Decoding
229%%====================================================================
230
231decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) ->
232    ReadState = get_connection_state_by_epoch(Epoch, ConnnectionStates0, read),
233    decode_cipher_text(CipherText, ReadState, ConnnectionStates0).
234
235
236%%====================================================================
237%% Protocol version handling
238%%====================================================================
239
240%%--------------------------------------------------------------------
241-spec protocol_version(dtls_atom_version() | ssl_record:ssl_version()) ->
242			      ssl_record:ssl_version() | dtls_atom_version().
243%%
244%% Description: Creates a protocol version record from a version atom
245%% or vice versa.
246%%--------------------------------------------------------------------
247protocol_version('dtlsv1.2') ->
248    {254, 253};
249protocol_version(dtlsv1) ->
250    {254, 255};
251protocol_version({254, 253}) ->
252    'dtlsv1.2';
253protocol_version({254, 255}) ->
254    dtlsv1.
255%%--------------------------------------------------------------------
256-spec lowest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version().
257%%
258%% Description: Lowes protocol version of two given versions
259%%--------------------------------------------------------------------
260lowest_protocol_version(Version = {M, N}, {M, O}) when N > O ->
261    Version;
262lowest_protocol_version({M, _}, Version = {M, _}) ->
263    Version;
264lowest_protocol_version(Version = {M,_}, {N, _}) when M > N ->
265    Version;
266lowest_protocol_version(_,Version) ->
267    Version.
268
269%%--------------------------------------------------------------------
270-spec lowest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version().
271%%
272%% Description: Lowest protocol version present in a list
273%%--------------------------------------------------------------------
274lowest_protocol_version([]) ->
275    lowest_protocol_version();
276lowest_protocol_version(Versions) ->
277    [Ver | Vers] = Versions,
278    lowest_list_protocol_version(Ver, Vers).
279
280%%--------------------------------------------------------------------
281-spec highest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version().
282%%
283%% Description: Highest protocol version present in a list
284%%--------------------------------------------------------------------
285highest_protocol_version([]) ->
286    highest_protocol_version();
287highest_protocol_version(Versions) ->
288    [Ver | Vers] = Versions,
289    highest_list_protocol_version(Ver, Vers).
290
291%%--------------------------------------------------------------------
292-spec highest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version().
293%%
294%% Description: Highest protocol version of two given versions
295%%--------------------------------------------------------------------
296highest_protocol_version(Version = {M, N}, {M, O})   when N < O ->
297    Version;
298highest_protocol_version({M, _},
299			Version = {M, _}) ->
300    Version;
301highest_protocol_version(Version = {M,_},
302			{N, _}) when M < N ->
303    Version;
304highest_protocol_version(_,Version) ->
305    Version.
306
307%%--------------------------------------------------------------------
308-spec is_higher(V1 :: ssl_record:ssl_version(), V2::ssl_record:ssl_version()) -> boolean().
309%%
310%% Description: Is V1 > V2
311%%--------------------------------------------------------------------
312is_higher({M, N}, {M, O}) when N < O ->
313    true;
314is_higher({M, _}, {N, _}) when M < N ->
315    true;
316is_higher(_, _) ->
317    false.
318
319%%--------------------------------------------------------------------
320-spec supported_protocol_versions() -> [ssl_record:ssl_version()].
321%%
322%% Description: Protocol versions supported
323%%--------------------------------------------------------------------
324supported_protocol_versions() ->
325    Fun = fun(Version) ->
326		  protocol_version(Version)
327	  end,
328    case application:get_env(ssl, dtls_protocol_version) of
329	undefined ->
330	    lists:map(Fun, supported_protocol_versions([]));
331	{ok, []} ->
332	    lists:map(Fun, supported_protocol_versions([]));
333	{ok, Vsns} when is_list(Vsns) ->
334	    supported_protocol_versions(lists:map(Fun, Vsns));
335	{ok, Vsn} ->
336	    supported_protocol_versions([Fun(Vsn)])
337     end.
338
339supported_protocol_versions([]) ->
340    Vsns = case sufficient_dtlsv1_2_crypto_support() of
341	       true ->
342		   ?ALL_DATAGRAM_SUPPORTED_VERSIONS;
343	       false ->
344		   ?MIN_DATAGRAM_SUPPORTED_VERSIONS
345	   end,
346    application:set_env(ssl, dtls_protocol_version, Vsns),
347    Vsns;
348
349supported_protocol_versions([_|_] = Vsns) ->
350    case sufficient_dtlsv1_2_crypto_support() of
351	true ->
352	    Vsns;
353	false ->
354	    case Vsns -- ['dtlsv1.2'] of
355		[] ->
356		    ?MIN_SUPPORTED_VERSIONS;
357		NewVsns ->
358		    NewVsns
359	    end
360    end.
361
362%%--------------------------------------------------------------------
363-spec is_acceptable_version(ssl_record:ssl_version(), Supported :: [ssl_record:ssl_version()]) -> boolean().
364%%
365%% Description: ssl version 2 is not acceptable security risks are too big.
366%%
367%%--------------------------------------------------------------------
368is_acceptable_version(Version, Versions) ->
369    lists:member(Version, Versions).
370
371-spec hello_version(ssl_record:ssl_version(), [ssl_record:ssl_version()]) -> ssl_record:ssl_version().
372hello_version(Version, Versions) ->
373    case dtls_v1:corresponding_tls_version(Version) of
374        TLSVersion when TLSVersion >= {3, 3} ->
375            Version;
376        _ ->
377            lowest_protocol_version(Versions)
378    end.
379
380
381%%--------------------------------------------------------------------
382%%% Internal functions
383%%--------------------------------------------------------------------
384initial_connection_state(ConnectionEnd, BeastMitigation) ->
385    #{security_parameters =>
386	  ssl_record:initial_security_params(ConnectionEnd),
387      epoch => undefined,
388      sequence_number => 0,
389      replay_window => init_replay_window(?REPLAY_WINDOW_SIZE),
390      beast_mitigation => BeastMitigation,
391      compression_state  => undefined,
392      cipher_state  => undefined,
393      mac_secret  => undefined,
394      secure_renegotiation => undefined,
395      client_verify_data => undefined,
396      server_verify_data => undefined
397     }.
398
399get_dtls_records_aux({DataTag, StateName, _, Versions} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),
400                                                         ?UINT16(Epoch), ?UINT48(SequenceNumber),
401                                                         ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
402		     Acc, #{log_level := LogLevel} = SslOpts)
403  when ((StateName == hello)
404        orelse ((StateName == certify) andalso (DataTag == udp))
405        orelse ((StateName == abbreviated) andalso (DataTag == udp))) andalso ((Type == ?HANDSHAKE)
406                                                                               orelse
407                                                                                 (Type == ?ALERT)) ->
408    ssl_logger:debug(LogLevel, inbound, 'record', [RawDTLSRecord]),
409    case is_acceptable_version({MajVer, MinVer}, Versions) of
410        true ->
411            get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type,
412                                                 version = {MajVer, MinVer},
413                                                 epoch = Epoch, sequence_number = SequenceNumber,
414                                                 fragment = Data} | Acc], SslOpts);
415        false ->
416              ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
417        end;
418get_dtls_records_aux({_, _, Version, _} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),
419		       ?UINT16(Epoch), ?UINT48(SequenceNumber),
420		       ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
421		     Acc, #{log_level := LogLevel} = SslOpts) when (Type == ?APPLICATION_DATA) orelse
422                                        (Type == ?HANDSHAKE) orelse
423                                        (Type == ?ALERT) orelse
424                                        (Type == ?CHANGE_CIPHER_SPEC) ->
425    ssl_logger:debug(LogLevel, inbound, 'record', [RawDTLSRecord]),
426    case {MajVer, MinVer} of
427        Version ->
428            get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type,
429                                                 version = {MajVer, MinVer},
430                                                 epoch = Epoch, sequence_number = SequenceNumber,
431                                                 fragment = Data} | Acc], SslOpts);
432        _ ->
433            ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
434    end;
435get_dtls_records_aux(_, <<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer),
436		       ?UINT16(Length), _/binary>>,
437		     _Acc, _) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
438    ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
439
440get_dtls_records_aux(_, Data, Acc, _) ->
441    case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
442	true ->
443	    {lists:reverse(Acc), Data};
444	false ->
445	    ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
446    end.
447%%--------------------------------------------------------------------
448
449init_replay_window(Size) ->
450    #{size => Size,
451      top => Size,
452      bottom => 0,
453      mask => 0 bsl 64
454     }.
455
456replay_detect(#ssl_tls{sequence_number = SequenceNumber}, #{replay_window := Window}) ->
457    is_replay(SequenceNumber, Window).
458
459
460is_replay(SequenceNumber, #{bottom := Bottom}) when SequenceNumber < Bottom ->
461    true;
462is_replay(SequenceNumber, #{size := Size,
463                            top := Top,
464                            bottom := Bottom,
465                            mask :=  Mask})  when (SequenceNumber >= Bottom) andalso (SequenceNumber =< Top) ->
466    Index = (SequenceNumber rem Size),
467    (Index band Mask) == 1;
468
469is_replay(_, _) ->
470    false.
471
472update_replay_window(SequenceNumber,  #{replay_window := #{size := Size,
473                                                           top := Top,
474                                                           bottom := Bottom,
475                                                           mask :=  Mask0} = Window0} = ConnectionStates) ->
476    NoNewBits = SequenceNumber - Top,
477    Index = SequenceNumber rem Size,
478    Mask = (Mask0 bsl NoNewBits) bor Index,
479    Window =  Window0#{top => SequenceNumber,
480                       bottom => Bottom + NoNewBits,
481                       mask => Mask},
482    ConnectionStates#{replay_window := Window}.
483
484%%--------------------------------------------------------------------
485
486encode_dtls_cipher_text(Type, {MajVer, MinVer}, Fragment,
487		       #{epoch := Epoch, sequence_number := Seq} = WriteState) ->
488    Length = erlang:iolist_size(Fragment),
489    {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Epoch),
490	?UINT48(Seq), ?UINT16(Length)>>, Fragment],
491     WriteState#{sequence_number => Seq + 1}}.
492
493encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
494                                         cipher_state := CipherS0,
495					 epoch := Epoch,
496					 sequence_number := Seq,
497					 security_parameters :=
498					     #security_parameters{
499						cipher_type = ?AEAD,
500                                                bulk_cipher_algorithm = BCAlg,
501						compression_algorithm = CompAlg}
502					} = WriteState0) ->
503    {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
504    AAD = start_additional_data(Type, Version, Epoch, Seq),
505    CipherS = ssl_record:nonce_seed(BCAlg, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
506    WriteState = WriteState0#{compression_state => CompS1,
507                              cipher_state => CipherS},
508    TLSVersion = dtls_v1:corresponding_tls_version(Version),
509    ssl_record:cipher_aead(TLSVersion, Comp, WriteState, AAD);
510encode_plain_text(Type, Version, Fragment, #{compression_state := CompS0,
511					 epoch := Epoch,
512					 sequence_number := Seq,
513                                         cipher_state := CipherS0,
514					 security_parameters :=
515					     #security_parameters{compression_algorithm = CompAlg,
516                                                                  bulk_cipher_algorithm =
517                                                                      BulkCipherAlgo}
518					}= WriteState0) ->
519    {Comp, CompS1} = ssl_record:compress(CompAlg, Fragment, CompS0),
520    WriteState1 = WriteState0#{compression_state => CompS1},
521    MAC = calc_mac_hash(Type, Version, WriteState1, Epoch, Seq, Comp),
522    TLSVersion = dtls_v1:corresponding_tls_version(Version),
523    {CipherFragment, CipherS1} =
524	ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MAC, Fragment, TLSVersion),
525    {CipherFragment,  WriteState0#{cipher_state => CipherS1}}.
526
527%%--------------------------------------------------------------------
528decode_cipher_text(#ssl_tls{type = Type, version = Version,
529			    epoch = Epoch,
530			    sequence_number = Seq,
531			    fragment = CipherFragment} = CipherText,
532		   #{compression_state := CompressionS0,
533                     cipher_state := CipherS0,
534		     security_parameters :=
535			 #security_parameters{
536			    cipher_type = ?AEAD,
537                            bulk_cipher_algorithm =
538                                BulkCipherAlgo,
539			    compression_algorithm = CompAlg}} = ReadState0,
540		   ConnnectionStates0) ->
541    AAD = start_additional_data(Type, Version, Epoch, Seq),
542    CipherS = ssl_record:nonce_seed(BulkCipherAlgo, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
543    TLSVersion = dtls_v1:corresponding_tls_version(Version),
544    case ssl_record:decipher_aead(BulkCipherAlgo, CipherS, AAD, CipherFragment, TLSVersion) of
545	PlainFragment when is_binary(PlainFragment) ->
546	    {Plain, CompressionS} = ssl_record:uncompress(CompAlg,
547							   PlainFragment, CompressionS0),
548	    ReadState1 = ReadState0#{compression_state := CompressionS,
549                                     cipher_state := CipherS},
550            ReadState = update_replay_window(Seq, ReadState1),
551	    ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
552	    {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
553	  #alert{} = Alert ->
554	    Alert
555    end;
556decode_cipher_text(#ssl_tls{type = Type, version = Version,
557			    epoch = Epoch,
558			    sequence_number = Seq,
559			    fragment = CipherFragment} = CipherText,
560		   #{compression_state := CompressionS0,
561		     security_parameters :=
562			 #security_parameters{
563			    compression_algorithm = CompAlg}} = ReadState0,
564		   ConnnectionStates0) ->
565    {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
566							   CipherFragment, ReadState0, true),
567    MacHash = calc_mac_hash(Type, Version, ReadState1, Epoch, Seq, PlainFragment),
568    case ssl_record:is_correct_mac(Mac, MacHash) of
569	true ->
570	    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
571							   PlainFragment, CompressionS0),
572
573	    ReadState2 = ReadState1#{compression_state => CompressionS1},
574            ReadState = update_replay_window(Seq, ReadState2),
575	    ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
576	    {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
577	false ->
578	    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
579    end.
580%%--------------------------------------------------------------------
581
582calc_mac_hash(Type, Version, #{mac_secret := MacSecret,
583			       security_parameters := #security_parameters{mac_algorithm = MacAlg}},
584	      Epoch, SeqNo, Fragment) ->
585    Length = erlang:iolist_size(Fragment),
586    mac_hash(Version, MacAlg, MacSecret, Epoch, SeqNo, Type,
587	     Length, Fragment).
588
589mac_hash({Major, Minor}, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment) ->
590    Value = [<<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type),
591       ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>,
592     Fragment],
593    dtls_v1:hmac_hash(MacAlg, MacSecret, Value).
594
595start_additional_data(Type, {MajVer, MinVer}, Epoch, SeqNo) ->
596    <<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
597
598%%--------------------------------------------------------------------
599
600lowest_list_protocol_version(Ver, []) ->
601    Ver;
602lowest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
603    lowest_list_protocol_version(lowest_protocol_version(Ver1, Ver2), Rest).
604
605highest_list_protocol_version(Ver, []) ->
606    Ver;
607highest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
608    highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
609
610highest_protocol_version() ->
611    highest_protocol_version(supported_protocol_versions()).
612
613lowest_protocol_version() ->
614    lowest_protocol_version(supported_protocol_versions()).
615
616sufficient_dtlsv1_2_crypto_support() ->
617    CryptoSupport = crypto:supports(),
618    proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
619
620