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