1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2007-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%%----------------------------------------------------------------------
23%% Purpose: Handle TLS/SSL record protocol. (Parts that are not shared with DTLS)
24%%----------------------------------------------------------------------
25
26-module(tls_record).
27
28-include("tls_record.hrl").
29-include("ssl_internal.hrl").
30-include("ssl_alert.hrl").
31-include("tls_handshake.hrl").
32-include("ssl_cipher.hrl").
33
34%% Handling of incoming data
35-export([get_tls_records/3, init_connection_states/2]).
36
37%% Encoding TLS records
38-export([encode_handshake/3, encode_alert_record/3,
39	 encode_change_cipher_spec/2, encode_data/3]).
40-export([encode_plain_text/4]).
41
42%% Decoding
43-export([decode_cipher_text/3]).
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/1, is_acceptable_version/2, hello_version/2]).
50
51-export_type([tls_version/0, tls_atom_version/0]).
52
53-type tls_version()       :: ssl_record:ssl_version().
54-type tls_atom_version()  :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
55
56-compile(inline).
57
58%%====================================================================
59%% Handling of incoming data
60%%====================================================================
61%%--------------------------------------------------------------------
62-spec init_connection_states(client | server, one_n_minus_one | zero_n | disabled) ->
63 				    ssl_record:connection_states().
64%%
65%% Description: Creates a connection_states record with appropriate
66%% values for the initial SSL connection setup.
67%%--------------------------------------------------------------------
68init_connection_states(Role, BeastMitigation) ->
69    ConnectionEnd = ssl_record:record_protocol_role(Role),
70    Current = initial_connection_state(ConnectionEnd, BeastMitigation),
71    Pending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
72    #{current_read  => Current,
73      pending_read  => Pending,
74      current_write => Current,
75      pending_write => Pending}.
76
77%%--------------------------------------------------------------------
78-spec get_tls_records(
79        binary(), [tls_version()] | tls_version(),
80        Buffer0 :: binary() | {'undefined' | #ssl_tls{}, {[binary()],non_neg_integer(),[binary()]}}) ->
81                             {Records :: [#ssl_tls{}],
82                              Buffer :: {'undefined' | #ssl_tls{}, {[binary()],non_neg_integer(),[binary()]}}} |
83                             #alert{}.
84%%
85%% and returns it as a list of tls_compressed binaries also returns leftover
86%% Description: Given old buffer and new data from TCP, packs up a records
87%% data
88%%--------------------------------------------------------------------
89
90get_tls_records(Data, Versions, Buffer) when is_binary(Buffer) ->
91    parse_tls_records(Versions, {[Data],byte_size(Data),[]}, undefined);
92get_tls_records(Data, Versions, {Hdr, {Front,Size,Rear}}) ->
93    parse_tls_records(Versions, {Front,Size + byte_size(Data),[Data|Rear]}, Hdr).
94
95%%====================================================================
96%% Encoding
97%%====================================================================
98
99%%--------------------------------------------------------------------
100-spec encode_handshake(iolist(), tls_version(), ssl_record:connection_states()) ->
101			      {iolist(), ssl_record:connection_states()}.
102%
103%% Description: Encodes a handshake message to send on the ssl-socket.
104%%--------------------------------------------------------------------
105encode_handshake(Frag, Version,
106		 #{current_write :=
107		       #{beast_mitigation := BeastMitigation,
108			  security_parameters :=
109			     #security_parameters{bulk_cipher_algorithm = BCA}}} =
110		     ConnectionStates) ->
111    case iolist_size(Frag) of
112	N  when N > ?MAX_PLAIN_TEXT_LENGTH ->
113	    Data = split_iovec(erlang:iolist_to_iovec(Frag), Version, BCA, BeastMitigation),
114	    encode_fragments(?HANDSHAKE, Version, Data, ConnectionStates);
115	_  ->
116	    encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
117    end.
118
119%%--------------------------------------------------------------------
120-spec encode_alert_record(#alert{}, tls_version(), ssl_record:connection_states()) ->
121				 {iolist(), ssl_record:connection_states()}.
122%%
123%% Description: Encodes an alert message to send on the ssl-socket.
124%%--------------------------------------------------------------------
125encode_alert_record(#alert{level = Level, description = Description},
126                    Version, ConnectionStates) ->
127    encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
128		      ConnectionStates).
129
130%%--------------------------------------------------------------------
131-spec encode_change_cipher_spec(tls_version(), ssl_record:connection_states()) ->
132				       {iolist(), ssl_record:connection_states()}.
133%%
134%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
135%%--------------------------------------------------------------------
136encode_change_cipher_spec(Version, ConnectionStates) ->
137    encode_plain_text(?CHANGE_CIPHER_SPEC, Version, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
138
139%%--------------------------------------------------------------------
140-spec encode_data([binary()], tls_version(), ssl_record:connection_states()) ->
141			 {[[binary()]], ssl_record:connection_states()}.
142%%
143%% Description: Encodes data to send on the ssl-socket.
144%%--------------------------------------------------------------------
145encode_data(Data, Version,
146	    #{current_write := #{beast_mitigation := BeastMitigation,
147				 security_parameters :=
148				     #security_parameters{bulk_cipher_algorithm = BCA}}} =
149		ConnectionStates) ->
150    Fragments = split_iovec(Data, Version, BCA, BeastMitigation),
151    encode_fragments(?APPLICATION_DATA, Version, Fragments, ConnectionStates).
152
153%%====================================================================
154%% Decoding
155%%====================================================================
156
157%%--------------------------------------------------------------------
158-spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states(), boolean()) ->
159				{#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
160%%
161%% Description: Decode cipher text
162%%--------------------------------------------------------------------
163decode_cipher_text(CipherText,
164		   #{current_read :=
165			 #{sequence_number := Seq,
166			   security_parameters :=
167                               #security_parameters{cipher_type = ?AEAD,
168                                                    bulk_cipher_algorithm = BulkCipherAlgo},
169                           cipher_state := CipherS0
170                          }
171                    } = ConnectionStates0, _) ->
172    SeqBin = <<?UINT64(Seq)>>,
173    #ssl_tls{type = Type, version = {MajVer,MinVer} = Version, fragment = Fragment} = CipherText,
174    StartAdditionalData = <<SeqBin/binary, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>,
175    CipherS = ssl_record:nonce_seed(BulkCipherAlgo, SeqBin, CipherS0),
176    case ssl_record:decipher_aead(
177           BulkCipherAlgo, CipherS, StartAdditionalData, Fragment, Version)
178    of
179	PlainFragment when is_binary(PlainFragment) ->
180            #{current_read :=
181                  #{security_parameters := SecParams,
182                    compression_state := CompressionS0} = ReadState0} = ConnectionStates0,
183	    {Plain, CompressionS} = ssl_record:uncompress(SecParams#security_parameters.compression_algorithm,
184                                                          PlainFragment, CompressionS0),
185	    ConnectionStates = ConnectionStates0#{
186				  current_read => ReadState0#{
187                                                    cipher_state => CipherS,
188                                                    sequence_number => Seq + 1,
189                                                    compression_state => CompressionS}},
190	    {CipherText#ssl_tls{fragment = Plain}, ConnectionStates};
191	#alert{} = Alert ->
192	    Alert
193    end;
194
195decode_cipher_text(#ssl_tls{version = Version,
196			    fragment = CipherFragment} = CipherText,
197		   #{current_read := ReadState0} = ConnnectionStates0, PaddingCheck) ->
198    case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
199	{PlainFragment, Mac, ReadState1} ->
200	    MacHash = ssl_cipher:calc_mac_hash(CipherText#ssl_tls.type, Version, PlainFragment, ReadState1),
201	    case ssl_record:is_correct_mac(Mac, MacHash) of
202		true ->
203                    #{sequence_number := Seq,
204                      compression_state := CompressionS0,
205                      security_parameters :=
206                          #security_parameters{compression_algorithm = CompAlg}} = ReadState0,
207		    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
208								   PlainFragment, CompressionS0),
209		    ConnnectionStates =
210                        ConnnectionStates0#{current_read =>
211                                                ReadState1#{sequence_number => Seq + 1,
212                                                            compression_state => CompressionS1}},
213		    {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
214		false ->
215                    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
216	    end;
217	    #alert{} = Alert ->
218	    Alert
219    end.
220
221%%====================================================================
222%% Protocol version handling
223%%====================================================================
224
225%%--------------------------------------------------------------------
226-spec protocol_version(tls_atom_version() | tls_version()) ->
227			      tls_version() | tls_atom_version().
228%%
229%% Description: Creates a protocol version record from a version atom
230%% or vice versa.
231%%--------------------------------------------------------------------
232protocol_version('tlsv1.2') ->
233    {3, 3};
234protocol_version('tlsv1.1') ->
235    {3, 2};
236protocol_version(tlsv1) ->
237    {3, 1};
238protocol_version(sslv3) ->
239    {3, 0};
240protocol_version(sslv2) -> %% Backwards compatibility
241    {2, 0};
242protocol_version({3, 3}) ->
243    'tlsv1.2';
244protocol_version({3, 2}) ->
245    'tlsv1.1';
246protocol_version({3, 1}) ->
247    tlsv1;
248protocol_version({3, 0}) ->
249    sslv3.
250%%--------------------------------------------------------------------
251-spec lowest_protocol_version(tls_version(), tls_version()) -> tls_version().
252%%
253%% Description: Lowes protocol version of two given versions
254%%--------------------------------------------------------------------
255lowest_protocol_version(Version = {M, N}, {M, O})   when N < O ->
256    Version;
257lowest_protocol_version({M, _},
258			Version = {M, _}) ->
259    Version;
260lowest_protocol_version(Version = {M,_},
261			{N, _}) when M < N ->
262    Version;
263lowest_protocol_version(_,Version) ->
264    Version.
265
266%%--------------------------------------------------------------------
267-spec lowest_protocol_version([tls_version()]) -> tls_version().
268%%
269%% Description: Lowest protocol version present in a list
270%%--------------------------------------------------------------------
271lowest_protocol_version([]) ->
272    lowest_protocol_version();
273lowest_protocol_version(Versions) ->
274    [Ver | Vers] = Versions,
275    lowest_list_protocol_version(Ver, Vers).
276
277%%--------------------------------------------------------------------
278-spec highest_protocol_version([tls_version()]) -> tls_version().
279%%
280%% Description: Highest protocol version present in a list
281%%--------------------------------------------------------------------
282highest_protocol_version([]) ->
283    highest_protocol_version();
284highest_protocol_version(Versions) ->
285    [Ver | Vers] = Versions,
286    highest_list_protocol_version(Ver, Vers).
287
288%%--------------------------------------------------------------------
289-spec highest_protocol_version(tls_version(), tls_version()) -> tls_version().
290%%
291%% Description: Highest protocol version of two given versions
292%%--------------------------------------------------------------------
293highest_protocol_version(Version = {M, N}, {M, O})   when N > O ->
294    Version;
295highest_protocol_version({M, _},
296			Version = {M, _}) ->
297    Version;
298highest_protocol_version(Version = {M,_},
299			{N, _}) when M > N ->
300    Version;
301highest_protocol_version(_,Version) ->
302    Version.
303
304%%--------------------------------------------------------------------
305-spec is_higher(V1 :: tls_version(), V2::tls_version()) -> boolean().
306%%
307%% Description: Is V1 > V2
308%%--------------------------------------------------------------------
309is_higher({M, N}, {M, O}) when N > O ->
310    true;
311is_higher({M, _}, {N, _}) when M > N ->
312    true;
313is_higher(_, _) ->
314    false.
315
316%%--------------------------------------------------------------------
317-spec supported_protocol_versions() -> [tls_version()].
318%%
319%% Description: Protocol versions supported
320%%--------------------------------------------------------------------
321supported_protocol_versions() ->
322    Fun = fun(Version) ->
323		  protocol_version(Version)
324	  end,
325    case application:get_env(ssl, protocol_version) of
326	undefined ->
327	    lists:map(Fun, supported_protocol_versions([]));
328	{ok, []} ->
329	    lists:map(Fun, supported_protocol_versions([]));
330	{ok, Vsns} when is_list(Vsns) ->
331	    Versions = lists:filter(fun is_acceptable_version/1, lists:map(Fun, Vsns)),
332	    supported_protocol_versions(Versions);
333	{ok, Vsn} ->
334	    Versions = lists:filter(fun is_acceptable_version/1, [Fun(Vsn)]),
335	    supported_protocol_versions(Versions)
336    end.
337
338supported_protocol_versions([]) ->
339    Vsns = case sufficient_tlsv1_2_crypto_support() of
340	       true ->
341		   ?ALL_SUPPORTED_VERSIONS;
342	       false ->
343		   ?MIN_SUPPORTED_VERSIONS
344	   end,
345    application:set_env(ssl, protocol_version, Vsns),
346    Vsns;
347
348supported_protocol_versions([_|_] = Vsns) ->
349    case sufficient_tlsv1_2_crypto_support() of
350	true ->
351	    Vsns;
352	false ->
353	    case Vsns -- ['tlsv1.2'] of
354		[] ->
355		    ?MIN_SUPPORTED_VERSIONS;
356		NewVsns ->
357		    NewVsns
358	    end
359    end.
360
361-spec is_acceptable_version(tls_version()) -> boolean().
362is_acceptable_version({N,_})
363  when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
364    true;
365is_acceptable_version(_) ->
366    false.
367
368-spec is_acceptable_version(tls_version(), Supported :: [tls_version()]) -> boolean().
369is_acceptable_version({N,_} = Version, Versions)
370  when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
371    lists:member(Version, Versions);
372is_acceptable_version(_,_) ->
373    false.
374
375-spec hello_version(tls_version(), [tls_version()]) -> tls_version().
376hello_version(Version, _) when Version >= {3, 3} ->
377    Version;
378hello_version(_, Versions) ->
379    lowest_protocol_version(Versions).
380
381%%--------------------------------------------------------------------
382%%% Internal functions
383%%--------------------------------------------------------------------
384initial_connection_state(ConnectionEnd, BeastMitigation) ->
385    #{security_parameters =>
386	  ssl_record:initial_security_params(ConnectionEnd),
387      sequence_number => 0,
388      beast_mitigation => BeastMitigation,
389      compression_state  => undefined,
390      cipher_state  => undefined,
391      mac_secret  => undefined,
392      secure_renegotiation => undefined,
393      client_verify_data => undefined,
394      server_verify_data => undefined
395     }.
396
397
398parse_tls_records(Versions, Q, undefined) ->
399    decode_tls_records(Versions, Q, [], undefined, undefined, undefined);
400parse_tls_records(Versions, Q, #ssl_tls{type = Type, version = Version, fragment = Length}) ->
401    decode_tls_records(Versions, Q, [], Type, Version, Length).
402
403%% Generic code path
404decode_tls_records(Versions, {_,Size,_} = Q0, Acc, undefined, _Version, _Length) ->
405    if
406        5 =< Size ->
407            {<<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), ?UINT16(Length)>>, Q} = binary_from_front(5, Q0),
408            validate_tls_records_type(Versions, Q, Acc, Type, {MajVer,MinVer}, Length);
409        3 =< Size ->
410            {<<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer)>>, Q} = binary_from_front(3, Q0),
411            validate_tls_records_type(Versions, Q, Acc, Type, {MajVer,MinVer}, undefined);
412        1 =< Size ->
413            {<<?BYTE(Type)>>, Q} = binary_from_front(1, Q0),
414            validate_tls_records_type(Versions, Q, Acc, Type, undefined, undefined);
415        true ->
416            validate_tls_records_type(Versions, Q0, Acc, undefined, undefined, undefined)
417    end;
418decode_tls_records(Versions, {_,Size,_} = Q0, Acc, Type, undefined, _Length) ->
419    if
420        4 =< Size ->
421            {<<?BYTE(MajVer),?BYTE(MinVer), ?UINT16(Length)>>, Q} = binary_from_front(4, Q0),
422            validate_tls_record_version(Versions, Q, Acc, Type, {MajVer,MinVer}, Length);
423        2 =< Size ->
424            {<<?BYTE(MajVer),?BYTE(MinVer)>>, Q} = binary_from_front(2, Q0),
425            validate_tls_record_version(Versions, Q, Acc, Type, {MajVer,MinVer}, undefined);
426        true ->
427            validate_tls_record_version(Versions, Q0, Acc, Type, undefined, undefined)
428    end;
429decode_tls_records(Versions, {_,Size,_} = Q0, Acc, Type, Version, undefined) ->
430    if
431        2 =< Size ->
432            {<<?UINT16(Length)>>, Q} = binary_from_front(2, Q0),
433            validate_tls_record_length(Versions, Q, Acc, Type, Version, Length);
434        true ->
435            validate_tls_record_length(Versions, Q0, Acc, Type, Version, undefined)
436    end;
437decode_tls_records(Versions, Q, Acc, Type, Version, Length) ->
438    validate_tls_record_length(Versions, Q, Acc, Type, Version, Length).
439
440validate_tls_records_type(_Versions, Q, Acc, undefined, _Version, _Length) ->
441    {lists:reverse(Acc),
442     {undefined, Q}};
443validate_tls_records_type(Versions, Q, Acc, Type, Version, Length) ->
444    if
445        ?KNOWN_RECORD_TYPE(Type) ->
446            validate_tls_record_version(Versions, Q, Acc, Type, Version, Length);
447        true ->
448            %% Not ?KNOWN_RECORD_TYPE(Type)
449            ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
450    end.
451
452validate_tls_record_version(_Versions, Q, Acc, Type, undefined, _Length) ->
453    {lists:reverse(Acc),
454     {#ssl_tls{type = Type, version = undefined, fragment = undefined}, Q}};
455validate_tls_record_version(Versions, Q, Acc, Type, Version, Length) ->
456    if
457        is_list(Versions) ->
458            case is_acceptable_version(Version, Versions) of
459                true ->
460                    validate_tls_record_length(Versions, Q, Acc, Type, Version, Length);
461                false ->
462                    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
463            end;
464        Version =:= Versions ->
465            %% Exact version match
466            validate_tls_record_length(Versions, Q, Acc, Type, Version, Length);
467        true ->
468            ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
469    end.
470
471validate_tls_record_length(_Versions, Q, Acc, Type, Version, undefined) ->
472    {lists:reverse(Acc),
473     {#ssl_tls{type = Type, version = Version, fragment = undefined}, Q}};
474validate_tls_record_length(Versions, {_,Size0,_} = Q0, Acc, Type, Version, Length) ->
475    if
476        Length =< ?MAX_CIPHER_TEXT_LENGTH ->
477            if
478                Length =< Size0 ->
479                    %% Complete record
480                    {Fragment, Q} = binary_from_front(Length, Q0),
481                    Record = #ssl_tls{type = Type, version = Version, fragment = Fragment},
482                    decode_tls_records(Versions, Q, [Record|Acc], undefined, undefined, undefined);
483                true ->
484                    {lists:reverse(Acc),
485                     {#ssl_tls{type = Type, version = Version, fragment = Length}, Q0}}
486            end;
487        true ->
488            ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW)
489    end.
490
491
492binary_from_front(0, Q) ->
493    {<<>>, Q};
494binary_from_front(SplitSize, {Front,Size,Rear}) when SplitSize =< Size ->
495    binary_from_front(SplitSize, Front, Size, Rear, []).
496%%
497%% SplitSize > 0 and there is at least SplitSize bytes buffered in Front and Rear
498binary_from_front(SplitSize, [], Size, Rear, Acc) ->
499    case Rear of
500        %% Avoid lists:reverse/1 for simple cases.
501        %% Case clause for [] to avoid infinite loop.
502        [_] ->
503            binary_from_front(SplitSize, Rear, Size, [], Acc);
504        [Bin2,Bin1] ->
505            binary_from_front(SplitSize, [Bin1,Bin2], Size, [], Acc);
506        [Bin3,Bin2,Bin1] ->
507            binary_from_front(SplitSize, [Bin1,Bin2,Bin3], Size, [], Acc);
508        [_,_,_|_] ->
509            binary_from_front(SplitSize, lists:reverse(Rear), Size, [], Acc)
510    end;
511binary_from_front(SplitSize, [Bin|Front], Size, Rear, []) ->
512    %% Optimize the frequent case when the accumulator is empty
513    BinSize = byte_size(Bin),
514    if
515        SplitSize < BinSize ->
516            {RetBin, Rest} = erlang:split_binary(Bin, SplitSize),
517            {RetBin, {[Rest|Front],Size - SplitSize,Rear}};
518        BinSize < SplitSize ->
519            binary_from_front(SplitSize - BinSize, Front, Size, Rear, [Bin]);
520        true -> % Perfect fit
521            {Bin, {Front,Size - SplitSize,Rear}}
522    end;
523binary_from_front(SplitSize, [Bin|Front], Size, Rear, Acc) ->
524    BinSize = byte_size(Bin),
525    if
526        SplitSize < BinSize ->
527            {Last, Rest} = erlang:split_binary(Bin, SplitSize),
528            RetBin = iolist_to_binary(lists:reverse(Acc, [Last])),
529            {RetBin, {[Rest|Front],Size - byte_size(RetBin),Rear}};
530        BinSize < SplitSize ->
531            binary_from_front(SplitSize - BinSize, Front, Size, Rear, [Bin|Acc]);
532        true -> % Perfect fit
533            RetBin = iolist_to_binary(lists:reverse(Acc, [Bin])),
534            {RetBin, {Front,Size - byte_size(RetBin),Rear}}
535    end.
536
537%%--------------------------------------------------------------------
538encode_plain_text(Type, Version, Data, ConnectionStates0) ->
539    {[CipherText],ConnectionStates} = encode_fragments(Type, Version, [Data], ConnectionStates0),
540    {CipherText,ConnectionStates}.
541%%--------------------------------------------------------------------
542encode_fragments(Type, Version, Data,
543              #{current_write := #{compression_state := CompS,
544                                   cipher_state := CipherS,
545                                   sequence_number := Seq}} = ConnectionStates) ->
546    encode_fragments(Type, Version, Data, ConnectionStates, CompS, CipherS, Seq, []).
547%%
548encode_fragments(_Type, _Version, [], #{current_write := WriteS} = CS,
549              CompS, CipherS, Seq, CipherFragments) ->
550    {lists:reverse(CipherFragments),
551     CS#{current_write := WriteS#{compression_state := CompS,
552                                  cipher_state := CipherS,
553                                  sequence_number := Seq}}};
554encode_fragments(Type, Version, [Text|Data],
555              #{current_write := #{security_parameters :=
556                                       #security_parameters{cipher_type = ?AEAD,
557                                                            bulk_cipher_algorithm = BCAlg,
558                                                            compression_algorithm = CompAlg} = SecPars}} = CS,
559              CompS0, CipherS0, Seq, CipherFragments) ->
560    {CompText, CompS} = ssl_record:compress(CompAlg, Text, CompS0),
561    SeqBin = <<?UINT64(Seq)>>,
562    CipherS1 = ssl_record:nonce_seed(BCAlg, SeqBin, CipherS0),
563    {MajVer, MinVer} = Version,
564    VersionBin = <<?BYTE(MajVer), ?BYTE(MinVer)>>,
565    StartAdditionalData = <<SeqBin/binary, ?BYTE(Type), VersionBin/binary>>,
566    {CipherFragment,CipherS} = ssl_record:cipher_aead(Version, CompText, CipherS1, StartAdditionalData, SecPars),
567    Length = byte_size(CipherFragment),
568    CipherHeader = <<?BYTE(Type), VersionBin/binary, ?UINT16(Length)>>,
569    encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
570                  [[CipherHeader, CipherFragment] | CipherFragments]);
571encode_fragments(Type, Version, [Text|Data],
572              #{current_write := #{security_parameters :=
573                                       #security_parameters{compression_algorithm = CompAlg,
574                                                            mac_algorithm = MacAlgorithm} = SecPars,
575                                   mac_secret := MacSecret}} = CS,
576              CompS0, CipherS0, Seq, CipherFragments) ->
577    {CompText, CompS} = ssl_record:compress(CompAlg, Text, CompS0),
578    MacHash = ssl_cipher:calc_mac_hash(Type, Version, CompText, MacAlgorithm, MacSecret, Seq),
579    {CipherFragment,CipherS} = ssl_record:cipher(Version, CompText, CipherS0, MacHash, SecPars),
580    Length = byte_size(CipherFragment),
581    {MajVer, MinVer} = Version,
582    CipherHeader = <<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>,
583    encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
584                  [[CipherHeader, CipherFragment] | CipherFragments]);
585encode_fragments(_Type, _Version, _Data, CS, _CompS, _CipherS, _Seq, _CipherFragments) ->
586    exit({cs, CS}).
587%%--------------------------------------------------------------------
588
589%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are
590%% not vulnerable to this attack.
591split_iovec(Data, Version, BCA, one_n_minus_one)
592  when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
593                               {3, 0} == Version) ->
594    {Part, RestData} = split_iovec(Data, 1, []),
595    [Part|split_iovec(RestData)];
596%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
597%% splitting.
598split_iovec(Data, Version, BCA, zero_n)
599  when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
600                               {3, 0} == Version) ->
601    {Part, RestData} = split_iovec(Data, 0, []),
602    [Part|split_iovec(RestData)];
603split_iovec(Data, _Version, _BCA, _BeatMitigation) ->
604    split_iovec(Data).
605
606split_iovec([]) ->
607    [];
608split_iovec(Data) ->
609    {Part,Rest} = split_iovec(Data, ?MAX_PLAIN_TEXT_LENGTH, []),
610    [Part|split_iovec(Rest)].
611%%
612split_iovec([Bin|Data] = Bin_Data, SplitSize, Acc) ->
613    BinSize = byte_size(Bin),
614    if
615        BinSize =< SplitSize ->
616            split_iovec(Data, SplitSize - BinSize, [Bin|Acc]);
617        SplitSize == 0 ->
618            {lists:reverse(Acc), Bin_Data};
619        SplitSize < BinSize ->
620            {Last, Rest} = erlang:split_binary(Bin, SplitSize),
621            {lists:reverse(Acc, [Last]), [Rest|Data]}
622    end;
623split_iovec([], _SplitSize, Acc) ->
624    {lists:reverse(Acc),[]}.
625
626%%--------------------------------------------------------------------
627lowest_list_protocol_version(Ver, []) ->
628    Ver;
629lowest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
630    lowest_list_protocol_version(lowest_protocol_version(Ver1, Ver2), Rest).
631
632highest_list_protocol_version(Ver, []) ->
633    Ver;
634highest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
635    highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
636
637highest_protocol_version() ->
638    highest_protocol_version(supported_protocol_versions()).
639
640lowest_protocol_version() ->
641    lowest_protocol_version(supported_protocol_versions()).
642
643sufficient_tlsv1_2_crypto_support() ->
644    CryptoSupport = crypto:supports(),
645    proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
646
647
648