1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2007-2021. 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-include_lib("kernel/include/logger.hrl").
34
35%% Handling of incoming data
36-export([get_tls_records/5,
37         init_connection_states/2,
38         init_connection_states/3]).
39
40%% Encoding TLS records
41-export([encode_handshake/3, encode_alert_record/3,
42	 encode_change_cipher_spec/2, encode_data/3]).
43-export([encode_plain_text/4, split_iovec/2]).
44
45%% Decoding
46-export([decode_cipher_text/4]).
47
48%% Logging helper
49-export([build_tls_record/1]).
50
51%% Protocol version handling
52-export([protocol_version/1,  lowest_protocol_version/1, lowest_protocol_version/2,
53	 highest_protocol_version/1, highest_protocol_version/2,
54	 is_higher/2, supported_protocol_versions/0, sufficient_crypto_support/1,
55	 is_acceptable_version/1, is_acceptable_version/2, hello_version/1]).
56
57-export_type([tls_version/0, tls_atom_version/0]).
58
59-type tls_version()       :: ssl_record:ssl_version().
60-type tls_atom_version()  :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2' | 'tlsv1.3'.
61-type tls_max_frag_len()  :: undefined | 512 | 1024 | 2048 | 4096.
62
63-compile(inline).
64
65%%====================================================================
66%% Handling of incoming data
67%%====================================================================
68%%--------------------------------------------------------------------
69-spec init_connection_states(Role, BeastMitigation) ->
70          ssl_record:connection_states() when
71      Role :: client | server,
72      BeastMitigation :: one_n_minus_one | zero_n | disabled.
73
74%%
75%% Description: Creates a connection_states record with appropriate
76%% values for the initial SSL connection setup.
77%%--------------------------------------------------------------------
78init_connection_states(Role, BeastMitigation) ->
79    MaxEarlyDataSize = ssl_config:get_max_early_data_size(),
80    init_connection_states(Role, BeastMitigation, MaxEarlyDataSize).
81%%
82-spec init_connection_states(Role, BeastMitigation, MaxEarlyDataSize) ->
83          ssl_record:connection_states() when
84      Role :: client | server,
85      BeastMitigation :: one_n_minus_one | zero_n | disabled,
86      MaxEarlyDataSize :: non_neg_integer().
87
88init_connection_states(Role, BeastMitigation, MaxEarlyDataSize) ->
89    ConnectionEnd = ssl_record:record_protocol_role(Role),
90    Current = initial_connection_state(ConnectionEnd, BeastMitigation, MaxEarlyDataSize),
91    Pending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation, MaxEarlyDataSize),
92    #{current_read  => Current,
93      pending_read  => Pending,
94      current_write => Current,
95      pending_write => Pending}.
96
97%%--------------------------------------------------------------------
98-spec get_tls_records(
99        binary(),
100        [tls_version()] | tls_version(),
101        Buffer0 :: binary() | {'undefined' | #ssl_tls{}, {[binary()],non_neg_integer(),[binary()]}},
102        tls_max_frag_len(),
103        ssl_options()) ->
104                             {Records :: [#ssl_tls{}],
105                              Buffer :: {'undefined' | #ssl_tls{}, {[binary()],non_neg_integer(),[binary()]}}} |
106                             #alert{}.
107%%
108%% and returns it as a list of tls_compressed binaries also returns leftover
109%% Description: Given old buffer and new data from TCP, packs up a records
110%% data
111%%--------------------------------------------------------------------
112get_tls_records(Data, Versions, Buffer, MaxFragLen, SslOpts) when is_binary(Buffer) ->
113    parse_tls_records(Versions, {[Data],byte_size(Data),[]}, MaxFragLen, SslOpts, undefined);
114get_tls_records(Data, Versions, {Hdr, {Front,Size,Rear}}, MaxFragLen, SslOpts) ->
115    parse_tls_records(Versions, {Front,Size + byte_size(Data),[Data|Rear]}, MaxFragLen, SslOpts, Hdr).
116
117%%====================================================================
118%% Encoding
119%%====================================================================
120
121%%--------------------------------------------------------------------
122-spec encode_handshake(iolist(), tls_version(), ssl_record:connection_states()) ->
123			      {iolist(), ssl_record:connection_states()}.
124%
125%% Description: Encodes a handshake message to send on the ssl-socket.
126%%--------------------------------------------------------------------
127encode_handshake(Frag, {3, 4}, ConnectionStates) ->
128    tls_record_1_3:encode_handshake(Frag, ConnectionStates);
129encode_handshake(Frag, Version,
130		 #{current_write :=
131		       #{beast_mitigation := BeastMitigation,
132                         max_fragment_length := MaxFragmentLength,
133			  security_parameters :=
134			     #security_parameters{bulk_cipher_algorithm = BCA}}} =
135		     ConnectionStates) ->
136    MaxLength = if is_integer(MaxFragmentLength) ->
137                        MaxFragmentLength;
138                   true ->
139                        ?MAX_PLAIN_TEXT_LENGTH
140                end,
141    case iolist_size(Frag) of
142	N when N > MaxLength ->
143            Data = split_iovec(erlang:iolist_to_iovec(Frag), Version, BCA, BeastMitigation, MaxLength),
144	    encode_fragments(?HANDSHAKE, Version, Data, ConnectionStates);
145	_  ->
146	    encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
147    end.
148
149%%--------------------------------------------------------------------
150-spec encode_alert_record(#alert{}, tls_version(), ssl_record:connection_states()) ->
151				 {iolist(), ssl_record:connection_states()}.
152%%
153%% Description: Encodes an alert message to send on the ssl-socket.
154%%--------------------------------------------------------------------
155encode_alert_record(Alert, {3, 4}, ConnectionStates) ->
156    tls_record_1_3:encode_alert_record(Alert, ConnectionStates);
157encode_alert_record(#alert{level = Level, description = Description},
158                    Version, ConnectionStates) ->
159    encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
160		      ConnectionStates).
161
162%%--------------------------------------------------------------------
163-spec encode_change_cipher_spec(tls_version(), ssl_record:connection_states()) ->
164				       {iolist(), ssl_record:connection_states()}.
165%%
166%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
167%%--------------------------------------------------------------------
168encode_change_cipher_spec(Version, ConnectionStates) ->
169    encode_plain_text(?CHANGE_CIPHER_SPEC, Version, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
170
171%%--------------------------------------------------------------------
172-spec encode_data([binary()], tls_version(), ssl_record:connection_states()) ->
173			 {[[binary()]], ssl_record:connection_states()}.
174%%
175%% Description: Encodes data to send on the ssl-socket.
176%%--------------------------------------------------------------------
177encode_data(Data, {3, 4}, ConnectionStates) ->
178    tls_record_1_3:encode_data(Data, ConnectionStates);
179encode_data(Data, Version,
180	    #{current_write := #{beast_mitigation := BeastMitigation,
181                                 max_fragment_length := MaxFragmentLength,
182				 security_parameters :=
183				     #security_parameters{bulk_cipher_algorithm = BCA}}} =
184		ConnectionStates) ->
185    MaxLength = if is_integer(MaxFragmentLength) ->
186                        MaxFragmentLength;
187                   true ->
188                        ?MAX_PLAIN_TEXT_LENGTH
189                end,
190    Fragments = split_iovec(Data, Version, BCA, BeastMitigation, MaxLength),
191    encode_fragments(?APPLICATION_DATA, Version, Fragments, ConnectionStates).
192
193%%====================================================================
194%% Decoding
195%%====================================================================
196
197%%--------------------------------------------------------------------
198-spec decode_cipher_text(tls_version(), #ssl_tls{}, ssl_record:connection_states(), boolean()) ->
199				{#ssl_tls{} | trial_decryption_failed,
200                                 ssl_record:connection_states()}| #alert{}.
201%%
202%% Description: Decode cipher text
203%%--------------------------------------------------------------------
204decode_cipher_text({3,4}, CipherTextRecord, ConnectionStates, _) ->
205    tls_record_1_3:decode_cipher_text(CipherTextRecord, ConnectionStates);
206decode_cipher_text(_, CipherTextRecord,
207		   #{current_read :=
208			 #{sequence_number := Seq,
209			   security_parameters :=
210                               #security_parameters{cipher_type = ?AEAD,
211                                                    bulk_cipher_algorithm = BulkCipherAlgo},
212                           cipher_state := CipherS0
213                          }
214                    } = ConnectionStates0, _) ->
215    SeqBin = <<?UINT64(Seq)>>,
216    #ssl_tls{type = Type, version = {MajVer,MinVer} = Version, fragment = Fragment} = CipherTextRecord,
217    StartAdditionalData = <<SeqBin/binary, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>,
218    CipherS = ssl_record:nonce_seed(BulkCipherAlgo, SeqBin, CipherS0),
219    case ssl_record:decipher_aead(
220           BulkCipherAlgo, CipherS, StartAdditionalData, Fragment, Version)
221    of
222	PlainFragment when is_binary(PlainFragment) ->
223            #{current_read :=
224                  #{security_parameters := SecParams,
225                    compression_state := CompressionS0} = ReadState0} = ConnectionStates0,
226	    {Plain, CompressionS} = ssl_record:uncompress(SecParams#security_parameters.compression_algorithm,
227                                                          PlainFragment, CompressionS0),
228	    ConnectionStates = ConnectionStates0#{
229				  current_read => ReadState0#{
230                                                    cipher_state => CipherS,
231                                                    sequence_number => Seq + 1,
232                                                    compression_state => CompressionS}},
233	    {CipherTextRecord#ssl_tls{fragment = Plain}, ConnectionStates};
234	#alert{} = Alert ->
235	    Alert
236    end;
237
238decode_cipher_text(_, #ssl_tls{version = Version,
239                               fragment = CipherFragment} = CipherTextRecord,
240		   #{current_read := ReadState0} = ConnnectionStates0, PaddingCheck) ->
241    case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
242	{PlainFragment, Mac, ReadState1} ->
243	    MacHash = ssl_cipher:calc_mac_hash(CipherTextRecord#ssl_tls.type, Version, PlainFragment, ReadState1),
244	    case ssl_record:is_correct_mac(Mac, MacHash) of
245		true ->
246                    #{sequence_number := Seq,
247                      compression_state := CompressionS0,
248                      security_parameters :=
249                          #security_parameters{compression_algorithm = CompAlg}} = ReadState0,
250		    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
251								   PlainFragment, CompressionS0),
252		    ConnnectionStates =
253                        ConnnectionStates0#{current_read =>
254                                                ReadState1#{sequence_number => Seq + 1,
255                                                            compression_state => CompressionS1}},
256		    {CipherTextRecord#ssl_tls{fragment = Plain}, ConnnectionStates};
257		false ->
258                    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
259	    end;
260	    #alert{} = Alert ->
261	    Alert
262    end.
263
264%%====================================================================
265%% Protocol version handling
266%%====================================================================
267
268%%--------------------------------------------------------------------
269-spec protocol_version(tls_atom_version() | tls_version()) ->
270			      tls_version() | tls_atom_version().
271%%
272%% Description: Creates a protocol version record from a version atom
273%% or vice versa.
274%%--------------------------------------------------------------------
275protocol_version('tlsv1.3') ->
276    {3, 4};
277protocol_version('tlsv1.2') ->
278    {3, 3};
279protocol_version('tlsv1.1') ->
280    {3, 2};
281protocol_version(tlsv1) ->
282    {3, 1};
283protocol_version(sslv3) ->
284    {3, 0};
285protocol_version(sslv2) -> %% Backwards compatibility
286    {2, 0};
287protocol_version({3, 4}) ->
288    'tlsv1.3';
289protocol_version({3, 3}) ->
290    'tlsv1.2';
291protocol_version({3, 2}) ->
292    'tlsv1.1';
293protocol_version({3, 1}) ->
294    tlsv1;
295protocol_version({3, 0}) ->
296    sslv3.
297%%--------------------------------------------------------------------
298-spec lowest_protocol_version(tls_version(), tls_version()) -> tls_version().
299%%
300%% Description: Lowes protocol version of two given versions
301%%--------------------------------------------------------------------
302lowest_protocol_version(Version = {M, N}, {M, O})   when N < O ->
303    Version;
304lowest_protocol_version({M, _},
305			Version = {M, _}) ->
306    Version;
307lowest_protocol_version(Version = {M,_},
308			{N, _}) when M < N ->
309    Version;
310lowest_protocol_version(_,Version) ->
311    Version.
312
313%%--------------------------------------------------------------------
314-spec lowest_protocol_version([tls_version()]) -> tls_version().
315%%
316%% Description: Lowest protocol version present in a list
317%%--------------------------------------------------------------------
318lowest_protocol_version([]) ->
319    lowest_protocol_version();
320lowest_protocol_version(Versions) ->
321    [Ver | Vers] = Versions,
322    lowest_list_protocol_version(Ver, Vers).
323
324%%--------------------------------------------------------------------
325-spec highest_protocol_version([tls_version()]) -> tls_version().
326%%
327%% Description: Highest protocol version present in a list
328%%--------------------------------------------------------------------
329highest_protocol_version([]) ->
330    highest_protocol_version();
331highest_protocol_version(Versions) ->
332    [Ver | Vers] = Versions,
333    highest_list_protocol_version(Ver, Vers).
334
335%%--------------------------------------------------------------------
336-spec highest_protocol_version(tls_version(), tls_version()) -> tls_version().
337%%
338%% Description: Highest protocol version of two given versions
339%%--------------------------------------------------------------------
340highest_protocol_version(Version = {M, N}, {M, O})   when N > O ->
341    Version;
342highest_protocol_version({M, _},
343			Version = {M, _}) ->
344    Version;
345highest_protocol_version(Version = {M,_},
346			{N, _}) when M > N ->
347    Version;
348highest_protocol_version(_,Version) ->
349    Version.
350
351%%--------------------------------------------------------------------
352-spec is_higher(V1 :: tls_version(), V2::tls_version()) -> boolean().
353%%
354%% Description: Is V1 > V2
355%%--------------------------------------------------------------------
356is_higher({M, N}, {M, O}) when N > O ->
357    true;
358is_higher({M, _}, {N, _}) when M > N ->
359    true;
360is_higher(_, _) ->
361    false.
362
363%%--------------------------------------------------------------------
364-spec supported_protocol_versions() -> [tls_version()].
365%%
366%% Description: Protocol versions supported
367%%--------------------------------------------------------------------
368supported_protocol_versions() ->
369    Fun = fun(Version) ->
370		  protocol_version(Version)
371	  end,
372    case application:get_env(ssl, protocol_version) of
373	undefined ->
374	    lists:map(Fun, supported_protocol_versions([]));
375	{ok, []} ->
376	    lists:map(Fun, supported_protocol_versions([]));
377	{ok, Vsns} when is_list(Vsns) ->
378	    Versions = lists:filter(fun is_acceptable_version/1, lists:map(Fun, Vsns)),
379	    supported_protocol_versions(Versions);
380	{ok, Vsn} ->
381	    Versions = lists:filter(fun is_acceptable_version/1, [Fun(Vsn)]),
382	    supported_protocol_versions(Versions)
383    end.
384
385supported_protocol_versions([]) ->
386    Vsns = sufficient_support(?ALL_SUPPORTED_VERSIONS),
387    application:set_env(ssl, protocol_version, Vsns),
388    Vsns;
389
390supported_protocol_versions([_|_] = Vsns) ->
391    sufficient_support(Vsns).
392
393sufficient_crypto_support(Version) ->
394    sufficient_crypto_support(crypto:supports(), Version).
395
396sufficient_crypto_support(CryptoSupport, {_,_} = Version) ->
397    sufficient_crypto_support(CryptoSupport, protocol_version(Version));
398sufficient_crypto_support(CryptoSupport, Version) when Version == 'tlsv1';
399                                                       Version == 'tlsv1.1' ->
400    Hashes =  proplists:get_value(hashs, CryptoSupport),
401    PKeys =  proplists:get_value(public_keys, CryptoSupport),
402    proplists:get_bool(sha, Hashes)
403        andalso
404        proplists:get_bool(md5, Hashes)
405        andalso
406        proplists:get_bool(aes_cbc, proplists:get_value(ciphers, CryptoSupport))
407        andalso
408          (proplists:get_bool(ecdsa, PKeys) orelse proplists:get_bool(rsa, PKeys) orelse proplists:get_bool(dss, PKeys))
409        andalso
410          (proplists:get_bool(ecdh, PKeys) orelse proplists:get_bool(dh, PKeys));
411
412sufficient_crypto_support(CryptoSupport, 'tlsv1.2') ->
413    PKeys =  proplists:get_value(public_keys, CryptoSupport),
414    (proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)))
415        andalso
416          (proplists:get_bool(aes_cbc, proplists:get_value(ciphers, CryptoSupport)))
417        andalso
418          (proplists:get_bool(ecdsa, PKeys) orelse proplists:get_bool(rsa, PKeys) orelse proplists:get_bool(dss, PKeys))
419        andalso
420          (proplists:get_bool(ecdh, PKeys) orelse proplists:get_bool(dh, PKeys));
421
422%%  A TLS-compliant application MUST implement the TLS_AES_128_GCM_SHA256
423%%  [GCM] cipher suite and SHOULD implement the TLS_AES_256_GCM_SHA384
424%%  [GCM] and TLS_CHACHA20_POLY1305_SHA256 [RFC8439] cipher suites (see
425%%  Appendix B.4).
426%%
427%%  A TLS-compliant application MUST support digital signatures with
428%%  rsa_pkcs1_sha256 (for certificates), rsa_pss_rsae_sha256 (for
429%%  CertificateVerify and certificates), and ecdsa_secp256r1_sha256.  A
430%%  TLS-compliant application MUST support key exchange with secp256r1
431%%  (NIST P-256) and SHOULD support key exchange with X25519 [RFC7748].
432sufficient_crypto_support(CryptoSupport, 'tlsv1.3') ->
433    Fun = fun({Group, Algorithm}) ->
434                  is_algorithm_supported(CryptoSupport, Group, Algorithm)
435          end,
436    L = [{ciphers, aes_gcm},                %% TLS_AES_*_GCM_*
437         {ciphers, chacha20_poly1305},      %% TLS_CHACHA20_POLY1305_SHA256
438         {hashs, sha256},                   %% TLS_AES_128_GCM_SHA256
439         {hashs, sha384},                   %% TLS_AES_256_GCM_SHA384
440         {rsa_opts, rsa_pkcs1_padding},     %% rsa_pkcs1_sha256
441         {rsa_opts, rsa_pkcs1_pss_padding}, %% rsa_pss_rsae_*
442         {rsa_opts, rsa_pss_saltlen},       %% rsa_pss_rsae_*
443         {public_keys, ecdh},
444         {public_keys, dh},
445         {public_keys, rsa},
446         {public_keys, ecdsa},
447         %% {public_keys, eddsa},  %% TODO
448         {curves, secp256r1},               %% key exchange with secp256r1
449         {curves, x25519}],                 %% key exchange with X25519
450    lists:all(Fun, L).
451
452is_algorithm_supported(CryptoSupport, Group, Algorithm) ->
453    proplists:get_bool(Algorithm, proplists:get_value(Group, CryptoSupport)).
454
455-spec is_acceptable_version(tls_version()) -> boolean().
456is_acceptable_version({N,_})
457  when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
458    true;
459is_acceptable_version(_) ->
460    false.
461
462-spec is_acceptable_version(tls_version(), Supported :: [tls_version()]) -> boolean().
463is_acceptable_version({N,_} = Version, Versions)
464  when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
465    lists:member(Version, Versions);
466is_acceptable_version(_,_) ->
467    false.
468
469-spec hello_version([tls_version()]) -> tls_version().
470hello_version([Highest|_]) when Highest >= {3,3} ->
471    {3,3};
472hello_version(Versions) ->
473    lowest_protocol_version(Versions).
474
475split_iovec([], _) ->
476    [];
477split_iovec(Data, MaximumFragmentLength) ->
478    {Part,Rest} = split_iovec(Data, MaximumFragmentLength, []),
479    [Part|split_iovec(Rest, MaximumFragmentLength)].
480
481%%--------------------------------------------------------------------
482%%% Internal functions
483%%--------------------------------------------------------------------
484initial_connection_state(ConnectionEnd, BeastMitigation, MaxEarlyDataSize) ->
485    #{security_parameters =>
486	  ssl_record:initial_security_params(ConnectionEnd),
487      sequence_number => 0,
488      beast_mitigation => BeastMitigation,
489      compression_state  => undefined,
490      cipher_state  => undefined,
491      mac_secret  => undefined,
492      secure_renegotiation => undefined,
493      client_verify_data => undefined,
494      server_verify_data => undefined,
495      max_early_data_size => MaxEarlyDataSize,
496      max_fragment_length => undefined,
497      trial_decryption => false,
498      early_data_limit => false
499     }.
500
501%% Used by logging to recreate the received bytes
502build_tls_record(#ssl_tls{type = Type, version = {MajVer, MinVer}, fragment = Fragment}) ->
503    Length = byte_size(Fragment),
504    <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),?UINT16(Length), Fragment/binary>>.
505
506
507parse_tls_records(Versions, Q, MaxFragLen, SslOpts, undefined) ->
508    decode_tls_records(Versions, Q, MaxFragLen, SslOpts, [], undefined, undefined, undefined);
509parse_tls_records(Versions, Q, MaxFragLen, SslOpts, #ssl_tls{type = Type, version = Version, fragment = Length}) ->
510    decode_tls_records(Versions, Q, MaxFragLen, SslOpts, [], Type, Version, Length).
511
512%% Generic code path
513decode_tls_records(Versions, {_,Size,_} = Q0, MaxFragLen, SslOpts, Acc, undefined, _Version, _Length) ->
514    if
515        5 =< Size ->
516            {<<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), ?UINT16(Length)>>, Q} = binary_from_front(5, Q0),
517            validate_tls_records_type(Versions, Q, MaxFragLen, SslOpts, Acc, Type, {MajVer,MinVer}, Length);
518        3 =< Size ->
519            {<<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer)>>, Q} = binary_from_front(3, Q0),
520            validate_tls_records_type(Versions, Q, MaxFragLen, SslOpts, Acc, Type, {MajVer,MinVer}, undefined);
521        1 =< Size ->
522            {<<?BYTE(Type)>>, Q} = binary_from_front(1, Q0),
523            validate_tls_records_type(Versions, Q, MaxFragLen, SslOpts, Acc, Type, undefined, undefined);
524        true ->
525            validate_tls_records_type(Versions, Q0, MaxFragLen, SslOpts, Acc, undefined, undefined, undefined)
526    end;
527decode_tls_records(Versions, {_,Size,_} = Q0, MaxFragLen, SslOpts, Acc, Type, undefined, _Length) ->
528    if
529        4 =< Size ->
530            {<<?BYTE(MajVer),?BYTE(MinVer), ?UINT16(Length)>>, Q} = binary_from_front(4, Q0),
531            validate_tls_record_version(Versions, Q, MaxFragLen, SslOpts, Acc, Type, {MajVer,MinVer}, Length);
532        2 =< Size ->
533            {<<?BYTE(MajVer),?BYTE(MinVer)>>, Q} = binary_from_front(2, Q0),
534            validate_tls_record_version(Versions, Q, MaxFragLen, SslOpts, Acc, Type, {MajVer,MinVer}, undefined);
535        true ->
536            validate_tls_record_version(Versions, Q0, MaxFragLen, SslOpts, Acc, Type, undefined, undefined)
537    end;
538decode_tls_records(Versions, {_,Size,_} = Q0, MaxFragLen, SslOpts, Acc, Type, Version, undefined) ->
539    if
540        2 =< Size ->
541            {<<?UINT16(Length)>>, Q} = binary_from_front(2, Q0),
542            validate_tls_record_length(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length);
543        true ->
544            validate_tls_record_length(Versions, Q0, MaxFragLen, SslOpts, Acc, Type, Version, undefined)
545    end;
546decode_tls_records(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length) ->
547    validate_tls_record_length(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length).
548
549validate_tls_records_type(_Versions, Q, _MaxFragLen, _SslOpts, Acc, undefined, _Version, _Length) ->
550    {lists:reverse(Acc),
551     {undefined, Q}};
552validate_tls_records_type(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length) ->
553    if
554        ?KNOWN_RECORD_TYPE(Type) ->
555            validate_tls_record_version(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length);
556        true ->
557            %% Not ?KNOWN_RECORD_TYPE(Type)
558            ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE, {unsupported_record_type, Type})
559    end.
560
561validate_tls_record_version(_Versions, Q, _MaxFragLen, _SslOpts, Acc, Type, undefined, _Length) ->
562    {lists:reverse(Acc),
563     {#ssl_tls{type = Type, version = undefined, fragment = undefined}, Q}};
564validate_tls_record_version(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length) ->
565    case Versions of
566        _ when is_list(Versions) ->
567            case is_acceptable_version(Version, Versions) of
568                true ->
569                    validate_tls_record_length(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length);
570                false ->
571                    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, {unsupported_version, Version})
572            end;
573        {3, 4} when Version =:= {3, 3} ->
574            validate_tls_record_length(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length);
575        Version ->
576            %% Exact version match
577            validate_tls_record_length(Versions, Q, MaxFragLen, SslOpts, Acc, Type, Version, Length);
578        _ ->
579            ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, {unsupported_version, Version})
580    end.
581
582validate_tls_record_length(_Versions, Q, _MaxFragLen, _SslOpts, Acc, Type, Version, undefined) ->
583    {lists:reverse(Acc),
584     {#ssl_tls{type = Type, version = Version, fragment = undefined}, Q}};
585validate_tls_record_length(Versions, {_,Size0,_} = Q0, MaxFragLen,
586                           #{log_level := LogLevel, downgrade := Downgrade} = SslOpts,
587                           Acc, Type, Version, Length) ->
588    Max = if is_integer(MaxFragLen) ->
589                        MaxFragLen + ?MAX_PADDING_LENGTH + ?MAX_MAC_LENGTH;
590                   true ->
591                        max_len(Versions)
592                end,
593    if
594        Length =< Max ->
595            if
596                Length =< Size0 ->
597                    %% Complete record
598                    {Fragment, Q} = binary_from_front(Length, Q0),
599                    Record = #ssl_tls{type = Type, version = Version, fragment = Fragment},
600                    ssl_logger:debug(LogLevel, inbound, 'record', Record),
601                    case Downgrade of
602                        {_Pid, _From} ->
603                            %% parse only single record for downgrade scenario, buffer remaining data
604                            {[Record], {undefined, Q}};
605                        _ ->
606                            decode_tls_records(Versions, Q, MaxFragLen, SslOpts, [Record|Acc], undefined, undefined, undefined)
607                    end;
608                true ->
609                    {lists:reverse(Acc),
610                     {#ssl_tls{type = Type, version = Version, fragment = Length}, Q0}}
611            end;
612        true ->
613            ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW)
614    end.
615
616
617binary_from_front(0, Q) ->
618    {<<>>, Q};
619binary_from_front(SplitSize, {Front,Size,Rear}) when SplitSize =< Size ->
620    binary_from_front(SplitSize, Front, Size, Rear, []).
621%%
622%% SplitSize > 0 and there is at least SplitSize bytes buffered in Front and Rear
623binary_from_front(SplitSize, [], Size, Rear, Acc) ->
624    case Rear of
625        %% Avoid lists:reverse/1 for simple cases.
626        %% Case clause for [] to avoid infinite loop.
627        [_] ->
628            binary_from_front(SplitSize, Rear, Size, [], Acc);
629        [Bin2,Bin1] ->
630            binary_from_front(SplitSize, [Bin1,Bin2], Size, [], Acc);
631        [Bin3,Bin2,Bin1] ->
632            binary_from_front(SplitSize, [Bin1,Bin2,Bin3], Size, [], Acc);
633        [_,_,_|_] ->
634            binary_from_front(SplitSize, lists:reverse(Rear), Size, [], Acc)
635    end;
636binary_from_front(SplitSize, [Bin|Front], Size, Rear, []) ->
637    %% Optimize the frequent case when the accumulator is empty
638    BinSize = byte_size(Bin),
639    if
640        SplitSize < BinSize ->
641            {RetBin, Rest} = erlang:split_binary(Bin, SplitSize),
642            {RetBin, {[Rest|Front],Size - SplitSize,Rear}};
643        BinSize < SplitSize ->
644            binary_from_front(SplitSize - BinSize, Front, Size, Rear, [Bin]);
645        true -> % Perfect fit
646            {Bin, {Front,Size - SplitSize,Rear}}
647    end;
648binary_from_front(SplitSize, [Bin|Front], Size, Rear, Acc) ->
649    BinSize = byte_size(Bin),
650    if
651        SplitSize < BinSize ->
652            {Last, Rest} = erlang:split_binary(Bin, SplitSize),
653            RetBin = iolist_to_binary(lists:reverse(Acc, [Last])),
654            {RetBin, {[Rest|Front],Size - byte_size(RetBin),Rear}};
655        BinSize < SplitSize ->
656            binary_from_front(SplitSize - BinSize, Front, Size, Rear, [Bin|Acc]);
657        true -> % Perfect fit
658            RetBin = iolist_to_binary(lists:reverse(Acc, [Bin])),
659            {RetBin, {Front,Size - byte_size(RetBin),Rear}}
660    end.
661
662%%--------------------------------------------------------------------
663encode_plain_text(Type, Version, Data, ConnectionStates0) ->
664    {[CipherText],ConnectionStates} = encode_fragments(Type, Version, [Data], ConnectionStates0),
665    {CipherText,ConnectionStates}.
666%%--------------------------------------------------------------------
667encode_fragments(Type, Version, Data,
668              #{current_write := #{compression_state := CompS,
669                                   cipher_state := CipherS,
670                                   sequence_number := Seq}} = ConnectionStates) ->
671    encode_fragments(Type, Version, Data, ConnectionStates, CompS, CipherS, Seq, []).
672%%
673encode_fragments(_Type, _Version, [], #{current_write := WriteS} = CS,
674              CompS, CipherS, Seq, CipherFragments) ->
675    {lists:reverse(CipherFragments),
676     CS#{current_write := WriteS#{compression_state := CompS,
677                                  cipher_state := CipherS,
678                                  sequence_number := Seq}}};
679encode_fragments(Type, Version, [Text|Data],
680              #{current_write := #{security_parameters :=
681                                       #security_parameters{cipher_type = ?AEAD,
682                                                            bulk_cipher_algorithm = BCAlg,
683                                                            compression_algorithm = CompAlg} = SecPars}} = CS,
684              CompS0, CipherS0, Seq, CipherFragments) ->
685    {CompText, CompS} = ssl_record:compress(CompAlg, Text, CompS0),
686    SeqBin = <<?UINT64(Seq)>>,
687    CipherS1 = ssl_record:nonce_seed(BCAlg, SeqBin, CipherS0),
688    {MajVer, MinVer} = Version,
689    VersionBin = <<?BYTE(MajVer), ?BYTE(MinVer)>>,
690    StartAdditionalData = <<SeqBin/binary, ?BYTE(Type), VersionBin/binary>>,
691    {CipherFragment,CipherS} = ssl_record:cipher_aead(Version, CompText, CipherS1, StartAdditionalData, SecPars),
692    Length = byte_size(CipherFragment),
693    CipherHeader = <<?BYTE(Type), VersionBin/binary, ?UINT16(Length)>>,
694    encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
695                  [[CipherHeader, CipherFragment] | CipherFragments]);
696encode_fragments(Type, Version, [Text|Data],
697              #{current_write := #{security_parameters :=
698                                       #security_parameters{compression_algorithm = CompAlg,
699                                                            mac_algorithm = MacAlgorithm} = SecPars,
700                                   mac_secret := MacSecret}} = CS,
701              CompS0, CipherS0, Seq, CipherFragments) ->
702    {CompText, CompS} = ssl_record:compress(CompAlg, Text, CompS0),
703    MacHash = ssl_cipher:calc_mac_hash(Type, Version, CompText, MacAlgorithm, MacSecret, Seq),
704    {CipherFragment,CipherS} = ssl_record:cipher(Version, CompText, CipherS0, MacHash, SecPars),
705    Length = byte_size(CipherFragment),
706    {MajVer, MinVer} = Version,
707    CipherHeader = <<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>,
708    encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
709                  [[CipherHeader, CipherFragment] | CipherFragments]);
710encode_fragments(_Type, _Version, _Data, CS, _CompS, _CipherS, _Seq, _CipherFragments) ->
711    exit({cs, CS}).
712%%--------------------------------------------------------------------
713
714%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 ciphers are
715%% not vulnerable to this attack.
716split_iovec(Data, Version, BCA, one_n_minus_one, MaxLength)
717  when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
718                               {3, 0} == Version) ->
719    {Part, RestData} = split_iovec(Data, 1, []),
720    [Part|split_iovec(RestData, MaxLength)];
721%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
722%% splitting.
723split_iovec(Data, Version, BCA, zero_n, MaxLength)
724  when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
725                               {3, 0} == Version) ->
726    {Part, RestData} = split_iovec(Data, 0, []),
727    [Part|split_iovec(RestData, MaxLength)];
728split_iovec(Data, _Version, _BCA, _BeatMitigation, MaxLength) ->
729    split_iovec(Data, MaxLength).
730
731split_iovec([Bin|Data] = Bin_Data, SplitSize, Acc) ->
732    BinSize = byte_size(Bin),
733    if
734        BinSize =< SplitSize ->
735            split_iovec(Data, SplitSize - BinSize, [Bin|Acc]);
736        SplitSize == 0 ->
737            {lists:reverse(Acc), Bin_Data};
738        SplitSize < BinSize ->
739            {Last, Rest} = erlang:split_binary(Bin, SplitSize),
740            {lists:reverse(Acc, [Last]), [Rest|Data]}
741    end;
742split_iovec([], _SplitSize, Acc) ->
743    {lists:reverse(Acc),[]}.
744
745%%--------------------------------------------------------------------
746lowest_list_protocol_version(Ver, []) ->
747    Ver;
748lowest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
749    lowest_list_protocol_version(lowest_protocol_version(Ver1, Ver2), Rest).
750
751highest_list_protocol_version(Ver, []) ->
752    Ver;
753highest_list_protocol_version(Ver1,  [Ver2 | Rest]) ->
754    highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
755
756highest_protocol_version() ->
757    highest_protocol_version(supported_protocol_versions()).
758
759lowest_protocol_version() ->
760    lowest_protocol_version(supported_protocol_versions()).
761
762max_len([{3,4}|_])->
763    ?TLS13_MAX_CIPHER_TEXT_LENGTH;
764max_len(_) ->
765    ?MAX_CIPHER_TEXT_LENGTH.
766
767sufficient_support(Versions) ->
768    CryptoSupport = crypto:supports(),
769    [Ver ||  Ver <- Versions, sufficient_crypto_support(CryptoSupport, Ver)].
770
771