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