1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2013-2019. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19 20%% 21%%---------------------------------------------------------------------- 22%% Purpose: Handle DTLS record protocol. (Parts that are not shared with SSL/TLS) 23%%---------------------------------------------------------------------- 24-module(dtls_record). 25 26-include("dtls_record.hrl"). 27-include("ssl_internal.hrl"). 28-include("ssl_alert.hrl"). 29-include("dtls_handshake.hrl"). 30-include("ssl_cipher.hrl"). 31 32%% Handling of incoming data 33-export([get_dtls_records/4, init_connection_states/2, empty_connection_state/1]). 34 35-export([save_current_connection_state/2, next_epoch/2, get_connection_state_by_epoch/3, replay_detect/2, 36 init_connection_state_seq/2, current_connection_state_epoch/2]). 37 38%% Encoding 39-export([encode_handshake/4, encode_alert_record/3, 40 encode_change_cipher_spec/3, encode_data/3, encode_plain_text/5]). 41 42%% Decoding 43-export([decode_cipher_text/2]). 44 45%% Protocol version handling 46-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2, 47 highest_protocol_version/1, highest_protocol_version/2, 48 is_higher/2, supported_protocol_versions/0, 49 is_acceptable_version/2, hello_version/2]). 50 51%% Debug (whitebox testing) 52-export([init_replay_window/0, is_replay/2, update_replay_window/2]). 53 54 55-export_type([dtls_atom_version/0]). 56 57-type dtls_atom_version() :: dtlsv1 | 'dtlsv1.2'. 58 59-define(REPLAY_WINDOW_SIZE, 58). %% No bignums 60 61-compile(inline). 62 63%%==================================================================== 64%% Handling of incoming data 65%%==================================================================== 66%%-------------------------------------------------------------------- 67-spec init_connection_states(client | server, one_n_minus_one | zero_n | disabled) -> 68 ssl_record:connection_states(). 69%% % 70 % 71%% Description: Creates a connection_states record with appropriate 72%% values for the initial SSL connection setup. 73%%-------------------------------------------------------------------- 74init_connection_states(Role, BeastMitigation) -> 75 ConnectionEnd = ssl_record:record_protocol_role(Role), 76 Initial = initial_connection_state(ConnectionEnd, BeastMitigation), 77 Current = Initial#{epoch := 0}, 78 InitialPending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation), 79 Pending = empty_connection_state(InitialPending), 80 #{saved_read => Current, 81 current_read => Current, 82 pending_read => Pending, 83 saved_write => Current, 84 current_write => Current, 85 pending_write => Pending}. 86 87empty_connection_state(Empty) -> 88 Empty#{epoch => undefined, replay_window => init_replay_window()}. 89 90%%-------------------------------------------------------------------- 91-spec save_current_connection_state(ssl_record:connection_states(), read | write) -> 92 ssl_record:connection_states(). 93%% 94%% Description: Returns the instance of the connection_state map 95%% where the current read|write state has been copied to the save state. 96%%-------------------------------------------------------------------- 97save_current_connection_state(#{current_read := Current} = States, read) -> 98 States#{saved_read := Current}; 99 100save_current_connection_state(#{current_write := Current} = States, write) -> 101 States#{saved_write := Current}. 102 103next_epoch(#{pending_read := Pending, 104 current_read := #{epoch := Epoch}} = States, read) -> 105 States#{pending_read := Pending#{epoch := Epoch + 1, 106 replay_window := init_replay_window()}}; 107 108next_epoch(#{pending_write := Pending, 109 current_write := #{epoch := Epoch}} = States, write) -> 110 States#{pending_write := Pending#{epoch := Epoch + 1, 111 replay_window := init_replay_window()}}. 112 113get_connection_state_by_epoch(Epoch, #{current_write := #{epoch := Epoch} = Current}, 114 write) -> 115 Current; 116get_connection_state_by_epoch(Epoch, #{saved_write := #{epoch := Epoch} = Saved}, 117 write) -> 118 Saved; 119get_connection_state_by_epoch(Epoch, #{current_read := #{epoch := Epoch} = Current}, 120 read) -> 121 Current; 122get_connection_state_by_epoch(Epoch, #{saved_read := #{epoch := Epoch} = Saved}, 123 read) -> 124 Saved. 125 126set_connection_state_by_epoch(WriteState, Epoch, #{current_write := #{epoch := Epoch}} = States, 127 write) -> 128 States#{current_write := WriteState}; 129set_connection_state_by_epoch(WriteState, Epoch, #{saved_write := #{epoch := Epoch}} = States, 130 write) -> 131 States#{saved_write := WriteState}; 132set_connection_state_by_epoch(ReadState, Epoch, #{current_read := #{epoch := Epoch}} = States, 133 read) -> 134 States#{current_read := ReadState}; 135set_connection_state_by_epoch(ReadState, Epoch, #{saved_read := #{epoch := Epoch}} = States, 136 read) -> 137 States#{saved_read := ReadState}. 138 139%%-------------------------------------------------------------------- 140-spec init_connection_state_seq(ssl_record:ssl_version(), ssl_record:connection_states()) -> 141 ssl_record:connection_state(). 142%% 143%% Description: Copy the read sequence number to the write sequence number 144%% This is only valid for DTLS in the first client_hello 145%%-------------------------------------------------------------------- 146init_connection_state_seq({254, _}, 147 #{current_read := #{epoch := 0, sequence_number := Seq}, 148 current_write := #{epoch := 0} = Write} = ConnnectionStates0) -> 149 ConnnectionStates0#{current_write => Write#{sequence_number => Seq}}; 150init_connection_state_seq(_, ConnnectionStates) -> 151 ConnnectionStates. 152 153%%-------------------------------------------------------- 154-spec current_connection_state_epoch(ssl_record:connection_states(), read | write) -> 155 integer(). 156%% 157%% Description: Returns the epoch the connection_state record 158%% that is currently defined as the current connection state. 159%%-------------------------------------------------------------------- 160current_connection_state_epoch(#{current_read := #{epoch := Epoch}}, 161 read) -> 162 Epoch; 163current_connection_state_epoch(#{current_write := #{epoch := Epoch}}, 164 write) -> 165 Epoch. 166 167%%-------------------------------------------------------------------- 168-spec get_dtls_records(binary(), {atom(), atom(), ssl_record:ssl_version(), [ssl_record:ssl_version()]}, binary(), 169 ssl_options()) -> {[binary()], binary()} | #alert{}. 170%% 171%% Description: Given old buffer and new data from UDP/SCTP, packs up a records 172%% and returns it as a list of tls_compressed binaries also returns leftover 173%% data 174%%-------------------------------------------------------------------- 175get_dtls_records(Data, Vinfo, Buffer, SslOpts) -> 176 BinData = list_to_binary([Buffer, Data]), 177 get_dtls_records_aux(Vinfo, BinData, [], SslOpts). 178 179%%==================================================================== 180%% Encoding DTLS records 181%%==================================================================== 182 183%%-------------------------------------------------------------------- 184-spec encode_handshake(iolist(), ssl_record:ssl_version(), integer(), ssl_record:connection_states()) -> 185 {iolist(), ssl_record:connection_states()}. 186% 187%% Description: Encodes a handshake message to send on the ssl-socket. 188%%-------------------------------------------------------------------- 189encode_handshake(Frag, Version, Epoch, ConnectionStates) -> 190 encode_plain_text(?HANDSHAKE, Version, Epoch, Frag, ConnectionStates). 191 192 193%%-------------------------------------------------------------------- 194-spec encode_alert_record(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) -> 195 {iolist(), ssl_record:connection_states()}. 196%% 197%% Description: Encodes an alert message to send on the ssl-socket. 198%%-------------------------------------------------------------------- 199encode_alert_record(#alert{level = Level, description = Description}, 200 Version, ConnectionStates) -> 201 #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write), 202 encode_plain_text(?ALERT, Version, Epoch, <<?BYTE(Level), ?BYTE(Description)>>, 203 ConnectionStates). 204 205%%-------------------------------------------------------------------- 206-spec encode_change_cipher_spec(ssl_record:ssl_version(), integer(), ssl_record:connection_states()) -> 207 {iolist(), ssl_record:connection_states()}. 208%% 209%% Description: Encodes a change_cipher_spec-message to send on the ssl socket. 210%%-------------------------------------------------------------------- 211encode_change_cipher_spec(Version, Epoch, ConnectionStates) -> 212 encode_plain_text(?CHANGE_CIPHER_SPEC, Version, Epoch, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates). 213 214%%-------------------------------------------------------------------- 215-spec encode_data(binary(), ssl_record:ssl_version(), ssl_record:connection_states()) -> 216 {iolist(),ssl_record:connection_states()}. 217%% 218%% Description: Encodes data to send on the ssl-socket. 219%%-------------------------------------------------------------------- 220encode_data(Data, Version, ConnectionStates) -> 221 #{epoch := Epoch, max_fragment_length := MaxFragmentLength} 222 = ssl_record:current_connection_state(ConnectionStates, write), 223 MaxLength = if is_integer(MaxFragmentLength) -> 224 MaxFragmentLength; 225 true -> 226 ?MAX_PLAIN_TEXT_LENGTH 227 end, 228 case iolist_size(Data) of 229 N when N > MaxLength -> 230 Frags = tls_record:split_iovec(erlang:iolist_to_iovec(Data), MaxLength), 231 {RevCipherText, ConnectionStates1} = 232 lists:foldl(fun(Frag, {Acc, CS0}) -> 233 {CipherText, CS1} = 234 encode_plain_text(?APPLICATION_DATA, Version, Epoch, Frag, CS0), 235 {[CipherText|Acc], CS1} 236 end, {[], ConnectionStates}, Frags), 237 {lists:reverse(RevCipherText), ConnectionStates1}; 238 _ -> 239 encode_plain_text(?APPLICATION_DATA, Version, Epoch, Data, ConnectionStates) 240 end. 241 242encode_plain_text(Type, Version, Epoch, Data, ConnectionStates) -> 243 Write0 = get_connection_state_by_epoch(Epoch, ConnectionStates, write), 244 {CipherFragment, Write1} = encode_plain_text(Type, Version, Data, Write0), 245 {CipherText, Write} = encode_dtls_cipher_text(Type, Version, CipherFragment, Write1), 246 {CipherText, set_connection_state_by_epoch(Write, Epoch, ConnectionStates, write)}. 247 248%%==================================================================== 249%% Decoding 250%%==================================================================== 251 252decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) -> 253 ReadState = get_connection_state_by_epoch(Epoch, ConnnectionStates0, read), 254 decode_cipher_text(CipherText, ReadState, ConnnectionStates0). 255 256 257%%==================================================================== 258%% Protocol version handling 259%%==================================================================== 260 261%%-------------------------------------------------------------------- 262-spec protocol_version(dtls_atom_version() | ssl_record:ssl_version()) -> 263 ssl_record:ssl_version() | dtls_atom_version(). 264%% 265%% Description: Creates a protocol version record from a version atom 266%% or vice versa. 267%%-------------------------------------------------------------------- 268protocol_version('dtlsv1.2') -> 269 {254, 253}; 270protocol_version(dtlsv1) -> 271 {254, 255}; 272protocol_version({254, 253}) -> 273 'dtlsv1.2'; 274protocol_version({254, 255}) -> 275 dtlsv1. 276%%-------------------------------------------------------------------- 277-spec lowest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version(). 278%% 279%% Description: Lowes protocol version of two given versions 280%%-------------------------------------------------------------------- 281lowest_protocol_version(Version = {M, N}, {M, O}) when N > O -> 282 Version; 283lowest_protocol_version({M, _}, Version = {M, _}) -> 284 Version; 285lowest_protocol_version(Version = {M,_}, {N, _}) when M > N -> 286 Version; 287lowest_protocol_version(_,Version) -> 288 Version. 289 290%%-------------------------------------------------------------------- 291-spec lowest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version(). 292%% 293%% Description: Lowest protocol version present in a list 294%%-------------------------------------------------------------------- 295lowest_protocol_version([]) -> 296 lowest_protocol_version(); 297lowest_protocol_version(Versions) -> 298 [Ver | Vers] = Versions, 299 lowest_list_protocol_version(Ver, Vers). 300 301%%-------------------------------------------------------------------- 302-spec highest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version(). 303%% 304%% Description: Highest protocol version present in a list 305%%-------------------------------------------------------------------- 306highest_protocol_version([]) -> 307 highest_protocol_version(); 308highest_protocol_version(Versions) -> 309 [Ver | Vers] = Versions, 310 highest_list_protocol_version(Ver, Vers). 311 312%%-------------------------------------------------------------------- 313-spec highest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version(). 314%% 315%% Description: Highest protocol version of two given versions 316%%-------------------------------------------------------------------- 317highest_protocol_version(Version = {M, N}, {M, O}) when N < O -> 318 Version; 319highest_protocol_version({M, _}, 320 Version = {M, _}) -> 321 Version; 322highest_protocol_version(Version = {M,_}, 323 {N, _}) when M < N -> 324 Version; 325highest_protocol_version(_,Version) -> 326 Version. 327 328%%-------------------------------------------------------------------- 329-spec is_higher(V1 :: ssl_record:ssl_version(), V2::ssl_record:ssl_version()) -> boolean(). 330%% 331%% Description: Is V1 > V2 332%%-------------------------------------------------------------------- 333is_higher({M, N}, {M, O}) when N < O -> 334 true; 335is_higher({M, _}, {N, _}) when M < N -> 336 true; 337is_higher(_, _) -> 338 false. 339 340%%-------------------------------------------------------------------- 341-spec supported_protocol_versions() -> [ssl_record:ssl_version()]. 342%% 343%% Description: Protocol versions supported 344%%-------------------------------------------------------------------- 345supported_protocol_versions() -> 346 Fun = fun(Version) -> 347 protocol_version(Version) 348 end, 349 case application:get_env(ssl, dtls_protocol_version) of 350 undefined -> 351 lists:map(Fun, supported_protocol_versions([])); 352 {ok, []} -> 353 lists:map(Fun, supported_protocol_versions([])); 354 {ok, Vsns} when is_list(Vsns) -> 355 supported_protocol_versions(lists:map(Fun, Vsns)); 356 {ok, Vsn} -> 357 supported_protocol_versions([Fun(Vsn)]) 358 end. 359 360supported_protocol_versions([]) -> 361 Vsns = case sufficient_dtlsv1_2_crypto_support() of 362 true -> 363 ?ALL_DATAGRAM_SUPPORTED_VERSIONS; 364 false -> 365 ?MIN_DATAGRAM_SUPPORTED_VERSIONS 366 end, 367 application:set_env(ssl, dtls_protocol_version, Vsns), 368 Vsns; 369 370supported_protocol_versions([_|_] = Vsns) -> 371 case sufficient_dtlsv1_2_crypto_support() of 372 true -> 373 Vsns; 374 false -> 375 case Vsns -- ['dtlsv1.2'] of 376 [] -> 377 ?MIN_SUPPORTED_VERSIONS; 378 NewVsns -> 379 NewVsns 380 end 381 end. 382 383%%-------------------------------------------------------------------- 384-spec is_acceptable_version(ssl_record:ssl_version(), Supported :: [ssl_record:ssl_version()]) -> boolean(). 385%% 386%% Description: ssl version 2 is not acceptable security risks are too big. 387%% 388%%-------------------------------------------------------------------- 389is_acceptable_version(Version, Versions) -> 390 lists:member(Version, Versions). 391 392-spec hello_version(ssl_record:ssl_version(), [ssl_record:ssl_version()]) -> ssl_record:ssl_version(). 393hello_version(Version, Versions) -> 394 case dtls_v1:corresponding_tls_version(Version) of 395 TLSVersion when TLSVersion >= {3, 3} -> 396 Version; 397 _ -> 398 lowest_protocol_version(Versions) 399 end. 400 401 402%%-------------------------------------------------------------------- 403%%% Internal functions 404%%-------------------------------------------------------------------- 405initial_connection_state(ConnectionEnd, BeastMitigation) -> 406 #{security_parameters => 407 ssl_record:initial_security_params(ConnectionEnd), 408 epoch => undefined, 409 sequence_number => 0, 410 replay_window => init_replay_window(), 411 beast_mitigation => BeastMitigation, 412 compression_state => undefined, 413 cipher_state => undefined, 414 mac_secret => undefined, 415 secure_renegotiation => undefined, 416 client_verify_data => undefined, 417 server_verify_data => undefined, 418 max_fragment_length => undefined 419 }. 420 421get_dtls_records_aux({DataTag, StateName, _, Versions} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), 422 ?UINT16(Epoch), ?UINT48(SequenceNumber), 423 ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord, 424 Acc, #{log_level := LogLevel} = SslOpts) 425 when ((StateName == hello) 426 orelse ((StateName == certify) andalso (DataTag == udp)) 427 orelse ((StateName == abbreviated) andalso (DataTag == udp))) andalso ((Type == ?HANDSHAKE) 428 orelse 429 (Type == ?ALERT)) -> 430 ssl_logger:debug(LogLevel, inbound, 'record', [RawDTLSRecord]), 431 case is_acceptable_version({MajVer, MinVer}, Versions) of 432 true -> 433 get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type, 434 version = {MajVer, MinVer}, 435 epoch = Epoch, sequence_number = SequenceNumber, 436 fragment = Data} | Acc], SslOpts); 437 false -> 438 ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) 439 end; 440get_dtls_records_aux({_, _, Version, _} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), 441 ?UINT16(Epoch), ?UINT48(SequenceNumber), 442 ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord, 443 Acc, #{log_level := LogLevel} = SslOpts) when (Type == ?APPLICATION_DATA) orelse 444 (Type == ?HANDSHAKE) orelse 445 (Type == ?ALERT) orelse 446 (Type == ?CHANGE_CIPHER_SPEC) -> 447 ssl_logger:debug(LogLevel, inbound, 'record', [RawDTLSRecord]), 448 case {MajVer, MinVer} of 449 Version -> 450 get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type, 451 version = {MajVer, MinVer}, 452 epoch = Epoch, sequence_number = SequenceNumber, 453 fragment = Data} | Acc], SslOpts); 454 _ -> 455 ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) 456 end; 457get_dtls_records_aux(_, <<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer), 458 ?UINT16(Length), _/binary>>, 459 _Acc, _) when Length > ?MAX_CIPHER_TEXT_LENGTH -> 460 ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW); 461 462get_dtls_records_aux(_, Data, Acc, _) -> 463 case byte_size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of 464 true -> 465 {lists:reverse(Acc), Data}; 466 false -> 467 ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE) 468 end. 469%%-------------------------------------------------------------------- 470 471init_replay_window() -> 472 init_replay_window(?REPLAY_WINDOW_SIZE). 473 474init_replay_window(Size) -> 475 #{top => Size-1, 476 bottom => 0, 477 mask => 0 478 }. 479 480replay_detect(#ssl_tls{sequence_number = SequenceNumber}, #{replay_window := Window}) -> 481 is_replay(SequenceNumber, Window). 482 483is_replay(SequenceNumber, #{bottom := Bottom}) 484 when SequenceNumber < Bottom -> 485 true; 486is_replay(SequenceNumber, #{top := Top, bottom := Bottom, mask := Mask}) 487 when (Bottom =< SequenceNumber) andalso (SequenceNumber =< Top) -> 488 Index = SequenceNumber - Bottom, 489 ((Mask bsr Index) band 1) =:= 1; 490is_replay(_, _) -> 491 false. 492 493update_replay_window(SequenceNumber, 494 #{replay_window := 495 #{top := Top, 496 bottom := Bottom, 497 mask := Mask0} = Window0} 498 = ConnectionStates) -> 499 NoNewBits = SequenceNumber - Top, 500 Window = 501 case NoNewBits > 0 of 502 true -> 503 NewBottom = Bottom + NoNewBits, 504 Index = SequenceNumber - NewBottom, 505 Mask = (Mask0 bsr NoNewBits) bor (1 bsl Index), 506 Window0#{top => Top + NoNewBits, 507 bottom => NewBottom, 508 mask => Mask}; 509 false -> 510 Index = SequenceNumber - Bottom, 511 Mask = Mask0 bor (1 bsl Index), 512 Window0#{mask => Mask} 513 end, 514 ConnectionStates#{replay_window := Window}. 515 516%%-------------------------------------------------------------------- 517 518encode_dtls_cipher_text(Type, {MajVer, MinVer}, Fragment, 519 #{epoch := Epoch, sequence_number := Seq} = WriteState) -> 520 Length = erlang:iolist_size(Fragment), 521 {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Epoch), 522 ?UINT48(Seq), ?UINT16(Length)>>, Fragment], 523 WriteState#{sequence_number => Seq + 1}}. 524 525encode_plain_text(Type, Version, Data, #{compression_state := CompS0, 526 cipher_state := CipherS0, 527 epoch := Epoch, 528 sequence_number := Seq, 529 security_parameters := 530 #security_parameters{ 531 cipher_type = ?AEAD, 532 bulk_cipher_algorithm = BCAlg, 533 compression_algorithm = CompAlg} 534 } = WriteState0) -> 535 {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0), 536 AAD = start_additional_data(Type, Version, Epoch, Seq), 537 CipherS = ssl_record:nonce_seed(BCAlg, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0), 538 WriteState = WriteState0#{compression_state => CompS1, 539 cipher_state => CipherS}, 540 TLSVersion = dtls_v1:corresponding_tls_version(Version), 541 ssl_record:cipher_aead(TLSVersion, Comp, WriteState, AAD); 542encode_plain_text(Type, Version, Fragment, #{compression_state := CompS0, 543 epoch := Epoch, 544 sequence_number := Seq, 545 cipher_state := CipherS0, 546 security_parameters := 547 #security_parameters{compression_algorithm = CompAlg, 548 bulk_cipher_algorithm = 549 BulkCipherAlgo} 550 }= WriteState0) -> 551 {Comp, CompS1} = ssl_record:compress(CompAlg, Fragment, CompS0), 552 WriteState1 = WriteState0#{compression_state => CompS1}, 553 MAC = calc_mac_hash(Type, Version, WriteState1, Epoch, Seq, Comp), 554 TLSVersion = dtls_v1:corresponding_tls_version(Version), 555 {CipherFragment, CipherS1} = 556 ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MAC, Fragment, TLSVersion), 557 {CipherFragment, WriteState0#{cipher_state => CipherS1}}. 558 559%%-------------------------------------------------------------------- 560decode_cipher_text(#ssl_tls{type = Type, version = Version, 561 epoch = Epoch, 562 sequence_number = Seq, 563 fragment = CipherFragment} = CipherText, 564 #{compression_state := CompressionS0, 565 cipher_state := CipherS0, 566 security_parameters := 567 #security_parameters{ 568 cipher_type = ?AEAD, 569 bulk_cipher_algorithm = 570 BulkCipherAlgo, 571 compression_algorithm = CompAlg}} = ReadState0, 572 ConnnectionStates0) -> 573 AAD = start_additional_data(Type, Version, Epoch, Seq), 574 CipherS = ssl_record:nonce_seed(BulkCipherAlgo, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0), 575 TLSVersion = dtls_v1:corresponding_tls_version(Version), 576 case ssl_record:decipher_aead(BulkCipherAlgo, CipherS, AAD, CipherFragment, TLSVersion) of 577 PlainFragment when is_binary(PlainFragment) -> 578 {Plain, CompressionS} = ssl_record:uncompress(CompAlg, 579 PlainFragment, CompressionS0), 580 ReadState1 = ReadState0#{compression_state := CompressionS, 581 cipher_state := CipherS}, 582 ReadState = update_replay_window(Seq, ReadState1), 583 ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read), 584 {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates}; 585 #alert{} = Alert -> 586 Alert 587 end; 588decode_cipher_text(#ssl_tls{type = Type, version = Version, 589 epoch = Epoch, 590 sequence_number = Seq, 591 fragment = CipherFragment} = CipherText, 592 #{compression_state := CompressionS0, 593 security_parameters := 594 #security_parameters{ 595 compression_algorithm = CompAlg}} = ReadState0, 596 ConnnectionStates0) -> 597 {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version), 598 CipherFragment, ReadState0, true), 599 MacHash = calc_mac_hash(Type, Version, ReadState1, Epoch, Seq, PlainFragment), 600 case ssl_record:is_correct_mac(Mac, MacHash) of 601 true -> 602 {Plain, CompressionS1} = ssl_record:uncompress(CompAlg, 603 PlainFragment, CompressionS0), 604 605 ReadState2 = ReadState1#{compression_state => CompressionS1}, 606 ReadState = update_replay_window(Seq, ReadState2), 607 ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read), 608 {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates}; 609 false -> 610 ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) 611 end. 612%%-------------------------------------------------------------------- 613 614calc_mac_hash(Type, Version, #{mac_secret := MacSecret, 615 security_parameters := #security_parameters{mac_algorithm = MacAlg}}, 616 Epoch, SeqNo, Fragment) -> 617 Length = erlang:iolist_size(Fragment), 618 mac_hash(Version, MacAlg, MacSecret, Epoch, SeqNo, Type, 619 Length, Fragment). 620 621mac_hash({Major, Minor}, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment) -> 622 Value = [<<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type), 623 ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>, 624 Fragment], 625 dtls_v1:hmac_hash(MacAlg, MacSecret, Value). 626 627start_additional_data(Type, {MajVer, MinVer}, Epoch, SeqNo) -> 628 <<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>. 629 630%%-------------------------------------------------------------------- 631 632lowest_list_protocol_version(Ver, []) -> 633 Ver; 634lowest_list_protocol_version(Ver1, [Ver2 | Rest]) -> 635 lowest_list_protocol_version(lowest_protocol_version(Ver1, Ver2), Rest). 636 637highest_list_protocol_version(Ver, []) -> 638 Ver; 639highest_list_protocol_version(Ver1, [Ver2 | Rest]) -> 640 highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest). 641 642highest_protocol_version() -> 643 highest_protocol_version(supported_protocol_versions()). 644 645lowest_protocol_version() -> 646 lowest_protocol_version(supported_protocol_versions()). 647 648sufficient_dtlsv1_2_crypto_support() -> 649 CryptoSupport = crypto:supports(), 650 proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)). 651 652