1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2020-2020. 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: 23%%---------------------------------------------------------------------- 24-module(dtls_gen_connection). 25 26-include_lib("public_key/include/public_key.hrl"). 27-include_lib("kernel/include/logger.hrl"). 28 29-include("dtls_connection.hrl"). 30-include("dtls_handshake.hrl"). 31-include("ssl_alert.hrl"). 32-include("dtls_record.hrl"). 33-include("ssl_cipher.hrl"). 34-include("ssl_api.hrl"). 35-include("ssl_internal.hrl"). 36 37%% Setup 38-export([start_fsm/8, 39 pids/1]). 40 41%% Handshake handling 42-export([send_handshake/2, 43 send_handshake_flight/2, 44 queue_handshake/2, 45 queue_change_cipher/2, 46 reinit/1, 47 reinit_handshake_data/1, 48 select_sni_extension/1, 49 empty_connection_state/2]). 50 51%% State transition handling 52-export([next_event/3, 53 next_event/4, 54 handle_protocol_record/3, 55 new_flight/0, 56 initial_flight_state/1 57 ]). 58 59%% Data handling 60-export([send/3, 61 socket/4, 62 setopts/3, 63 getopts/3, 64 handle_info/3]). 65 66%% Alert and close handling 67-export([send_alert/2, 68 send_alert_in_connection/2, 69 close/5, 70 protocol_name/0]). 71%%==================================================================== 72%% Internal application API 73%%==================================================================== 74%%==================================================================== 75%% Setup 76%%==================================================================== 77start_fsm(Role, Host, Port, Socket, {#{erl_dist := false},_, Tracker} = Opts, 78 User, {CbModule, _, _, _, _} = CbInfo, 79 Timeout) -> 80 try 81 {ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket, 82 Opts, User, CbInfo]), 83 {ok, SslSocket} = ssl_gen_statem:socket_control(?MODULE, Socket, [Pid], CbModule, Tracker), 84 ssl_gen_statem:handshake(SslSocket, Timeout) 85 catch 86 error:{badmatch, {error, _} = Error} -> 87 Error 88 end. 89 90pids(_) -> 91 [self()]. 92 93%%==================================================================== 94%% State transition handling 95%%==================================================================== 96next_record(#state{handshake_env = 97 #handshake_env{unprocessed_handshake_events = N} = HsEnv} 98 = State) when N > 0 -> 99 {no_record, State#state{handshake_env = 100 HsEnv#handshake_env{unprocessed_handshake_events = N-1}}}; 101next_record(#state{protocol_buffers = 102 #protocol_buffers{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} = CT | Rest]} 103 = Buffers, 104 connection_states = #{current_read := #{epoch := Epoch}} = ConnectionStates} = State) -> 105 CurrentRead = dtls_record:get_connection_state_by_epoch(Epoch, ConnectionStates, read), 106 case dtls_record:replay_detect(CT, CurrentRead) of 107 false -> 108 decode_cipher_text(State#state{connection_states = ConnectionStates}) ; 109 true -> 110 %% Ignore replayed record 111 next_record(State#state{protocol_buffers = 112 Buffers#protocol_buffers{dtls_cipher_texts = Rest}, 113 connection_states = ConnectionStates}) 114 end; 115next_record(#state{protocol_buffers = 116 #protocol_buffers{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} | Rest]} 117 = Buffers, 118 connection_states = #{current_read := #{epoch := CurrentEpoch}} = ConnectionStates} = State) 119 when Epoch > CurrentEpoch -> 120 %% TODO Buffer later Epoch message, drop it for now 121 next_record(State#state{protocol_buffers = 122 Buffers#protocol_buffers{dtls_cipher_texts = Rest}, 123 connection_states = ConnectionStates}); 124next_record(#state{protocol_buffers = 125 #protocol_buffers{dtls_cipher_texts = [ _ | Rest]} 126 = Buffers, 127 connection_states = ConnectionStates} = State) -> 128 %% Drop old epoch message 129 next_record(State#state{protocol_buffers = 130 Buffers#protocol_buffers{dtls_cipher_texts = Rest}, 131 connection_states = ConnectionStates}); 132next_record(#state{static_env = #static_env{role = server, 133 socket = {Listener, {Client, _}}}} = State) -> 134 dtls_packet_demux:active_once(Listener, Client, self()), 135 {no_record, State}; 136next_record(#state{protocol_specific = #{active_n_toggle := true, 137 active_n := N} = ProtocolSpec, 138 static_env = #static_env{role = client, 139 socket = {_Server, Socket} = DTLSSocket, 140 close_tag = CloseTag, 141 transport_cb = Transport}} = State) -> 142 case dtls_socket:setopts(Transport, Socket, [{active,N}]) of 143 ok -> 144 {no_record, State#state{protocol_specific = 145 ProtocolSpec#{active_n_toggle => false}}}; 146 _ -> 147 self() ! {CloseTag, DTLSSocket}, 148 {no_record, State} 149 end; 150next_record(State) -> 151 {no_record, State}. 152 153next_event(StateName, Record, State) -> 154 next_event(StateName, Record, State, []). 155 156next_event(StateName, no_record, 157 #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) -> 158 case next_record(State0) of 159 {no_record, State} -> 160 ssl_gen_statem:hibernate_after(StateName, State, Actions); 161 {#ssl_tls{epoch = CurrentEpoch, 162 type = ?HANDSHAKE, 163 version = Version} = Record, State1} -> 164 State = dtls_version(StateName, Version, State1), 165 {next_state, StateName, State, 166 [{next_event, internal, {protocol_record, Record}} | Actions]}; 167 {#ssl_tls{epoch = CurrentEpoch} = Record, State} -> 168 {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]}; 169 {#ssl_tls{epoch = Epoch, 170 type = ?HANDSHAKE, 171 version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 -> 172 {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch), 173 next_event(StateName, no_record, State, Actions ++ MoreActions); 174 %% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake 175 {#ssl_tls{epoch = Epoch, 176 type = ?CHANGE_CIPHER_SPEC, 177 version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 -> 178 {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch), 179 next_event(StateName, no_record, State, Actions ++ MoreActions); 180 {#ssl_tls{epoch = _Epoch, 181 version = _Version}, State} -> 182 %% TODO maybe buffer later epoch 183 next_event(StateName, no_record, State, Actions); 184 {#alert{} = Alert, State} -> 185 Version = State#state.connection_env#connection_env.negotiated_version, 186 handle_own_alert(Alert, Version, StateName, State) 187 end; 188next_event(connection = StateName, Record, 189 #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) -> 190 case Record of 191 #ssl_tls{epoch = CurrentEpoch, 192 type = ?HANDSHAKE, 193 version = Version} = Record -> 194 State = dtls_version(StateName, Version, State0), 195 {next_state, StateName, State, 196 [{next_event, internal, {protocol_record, Record}} | Actions]}; 197 #ssl_tls{epoch = CurrentEpoch} -> 198 {next_state, StateName, State0, [{next_event, internal, {protocol_record, Record}} | Actions]}; 199 #ssl_tls{epoch = Epoch, 200 type = ?HANDSHAKE, 201 version = _Version} when Epoch == CurrentEpoch-1 -> 202 {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch), 203 next_event(StateName, no_record, State, Actions ++ MoreActions); 204 %% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake 205 #ssl_tls{epoch = Epoch, 206 type = ?CHANGE_CIPHER_SPEC, 207 version = _Version} when Epoch == CurrentEpoch-1 -> 208 {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch), 209 next_event(StateName, no_record, State, Actions ++ MoreActions); 210 _ -> 211 next_event(StateName, no_record, State0, Actions) 212 end; 213next_event(StateName, Record, 214 #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) -> 215 case Record of 216 #ssl_tls{epoch = CurrentEpoch, 217 version = Version} = Record -> 218 State = dtls_version(StateName, Version, State0), 219 {next_state, StateName, State, 220 [{next_event, internal, {protocol_record, Record}} | Actions]}; 221 #ssl_tls{epoch = _Epoch, 222 version = _Version} = _Record -> 223 %% TODO maybe buffer later epoch 224 next_event(StateName, no_record, State0, Actions); 225 #alert{} = Alert -> 226 Version = State0#state.connection_env#connection_env.negotiated_version, 227 handle_own_alert(Alert, Version, StateName, State0) 228 end. 229 230initial_flight_state(udp)-> 231 {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}; 232initial_flight_state(_) -> 233 reliable. 234 235new_flight() -> 236 #{next_sequence => 0, 237 handshakes => [], 238 change_cipher_spec => undefined, 239 handshakes_after_change_cipher_spec => []}. 240 241send_handshake_flight(#state{static_env = #static_env{socket = Socket, 242 transport_cb = Transport}, 243 connection_env = #connection_env{negotiated_version = Version}, 244 flight_buffer = #{handshakes := Flight, 245 change_cipher_spec := undefined}, 246 connection_states = ConnectionStates0, 247 ssl_options = #{log_level := LogLevel}} = State0, 248 Epoch) -> 249 PMTUEstimate = 1400, %% TODO make configurable 250 #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0, 251 MaxSize = min(MaxFragmentLength, PMTUEstimate), 252 {Encoded, ConnectionStates} = 253 encode_handshake_flight(lists:reverse(Flight), Version, MaxSize, Epoch, ConnectionStates0), 254 send(Transport, Socket, Encoded), 255 ssl_logger:debug(LogLevel, outbound, 'record', Encoded), 256 {State0#state{connection_states = ConnectionStates}, []}; 257 258send_handshake_flight(#state{static_env = #static_env{socket = Socket, 259 transport_cb = Transport}, 260 connection_env = #connection_env{negotiated_version = Version}, 261 flight_buffer = #{handshakes := [_|_] = Flight0, 262 change_cipher_spec := ChangeCipher, 263 handshakes_after_change_cipher_spec := []}, 264 connection_states = ConnectionStates0, 265 ssl_options = #{log_level := LogLevel}} = State0, 266 Epoch) -> 267 PMTUEstimate = 1400, %% TODO make configurable 268 #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0, 269 MaxSize = min(MaxFragmentLength, PMTUEstimate), 270 {HsBefore, ConnectionStates1} = 271 encode_handshake_flight(lists:reverse(Flight0), Version, MaxSize, Epoch, ConnectionStates0), 272 {EncChangeCipher, ConnectionStates} = encode_change_cipher(ChangeCipher, Version, Epoch, ConnectionStates1), 273 274 send(Transport, Socket, [HsBefore, EncChangeCipher]), 275 ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]), 276 ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]), 277 {State0#state{connection_states = ConnectionStates}, []}; 278 279send_handshake_flight(#state{static_env = #static_env{socket = Socket, 280 transport_cb = Transport}, 281 connection_env = #connection_env{negotiated_version = Version}, 282 flight_buffer = #{handshakes := [_|_] = Flight0, 283 change_cipher_spec := ChangeCipher, 284 handshakes_after_change_cipher_spec := Flight1}, 285 connection_states = ConnectionStates0, 286 ssl_options = #{log_level := LogLevel}} = State0, 287 Epoch) -> 288 PMTUEstimate = 1400, %% TODO make configurable 289 #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0, 290 MaxSize = min(MaxFragmentLength, PMTUEstimate), 291 {HsBefore, ConnectionStates1} = 292 encode_handshake_flight(lists:reverse(Flight0), Version, MaxSize, Epoch-1, ConnectionStates0), 293 {EncChangeCipher, ConnectionStates2} = 294 encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates1), 295 {HsAfter, ConnectionStates} = 296 encode_handshake_flight(lists:reverse(Flight1), Version, MaxSize, Epoch, ConnectionStates2), 297 send(Transport, Socket, [HsBefore, EncChangeCipher, HsAfter]), 298 ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]), 299 ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]), 300 ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]), 301 {State0#state{connection_states = ConnectionStates}, []}; 302 303send_handshake_flight(#state{static_env = #static_env{socket = Socket, 304 transport_cb = Transport}, 305 connection_env = #connection_env{negotiated_version = Version}, 306 flight_buffer = #{handshakes := [], 307 change_cipher_spec := ChangeCipher, 308 handshakes_after_change_cipher_spec := Flight1}, 309 connection_states = ConnectionStates0, 310 ssl_options = #{log_level := LogLevel}} = State0, 311 Epoch) -> 312 PMTUEstimate = 1400, %% TODO make configurable 313 #{current_write := #{max_fragment_length := MaxFragmentLength}} = ConnectionStates0, 314 MaxSize = min(MaxFragmentLength, PMTUEstimate), 315 {EncChangeCipher, ConnectionStates1} = 316 encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates0), 317 {HsAfter, ConnectionStates} = 318 encode_handshake_flight(lists:reverse(Flight1), Version, MaxSize, Epoch, ConnectionStates1), 319 send(Transport, Socket, [EncChangeCipher, HsAfter]), 320 ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]), 321 ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]), 322 {State0#state{connection_states = ConnectionStates}, []}. 323 324%%% DTLS record protocol level application data messages 325 326handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName0, State0) -> 327 case ssl_gen_statem:read_application_data(Data, State0) of 328 {stop, _, _} = Stop-> 329 Stop; 330 {Record, State1} -> 331 {next_state, StateName, State, Actions} = next_event(StateName0, Record, State1), 332 ssl_gen_statem:hibernate_after(StateName, State, Actions) 333 end; 334%%% DTLS record protocol level handshake messages 335handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, 336 fragment = Data}, 337 StateName, 338 #state{protocol_buffers = Buffers0, 339 connection_env = #connection_env{negotiated_version = Version}, 340 ssl_options = Options} = State) -> 341 try 342 case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0, Options) of 343 {[], Buffers} -> 344 next_event(StateName, no_record, State#state{protocol_buffers = Buffers}); 345 {Packets, Buffers} -> 346 HsEnv = State#state.handshake_env, 347 Events = dtls_handshake_events(Packets), 348 {next_state, StateName, 349 State#state{protocol_buffers = Buffers, 350 handshake_env = 351 HsEnv#handshake_env{unprocessed_handshake_events 352 = unprocessed_events(Events)}}, Events} 353 end 354 catch throw:#alert{} = Alert -> 355 handle_own_alert(Alert, Version, StateName, State) 356 end; 357%%% DTLS record protocol level change cipher messages 358handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) -> 359 {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]}; 360%%% DTLS record protocol level Alert messages 361handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName, 362 #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> 363 case decode_alerts(EncAlerts) of 364 Alerts = [_|_] -> 365 handle_alerts(Alerts, {next_state, StateName, State}); 366 #alert{} = Alert -> 367 handle_own_alert(Alert, Version, StateName, State) 368 end; 369%% Ignore unknown TLS record level protocol messages 370handle_protocol_record(#ssl_tls{type = _Unknown}, StateName, State) -> 371 {next_state, StateName, State, []}. 372 373%%==================================================================== 374%% Handshake handling 375%%==================================================================== 376send_handshake(Handshake, #state{connection_states = ConnectionStates} = State) -> 377 #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write), 378 send_handshake_flight(queue_handshake(Handshake, State), Epoch). 379 380queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, 381 connection_env = #connection_env{negotiated_version = Version}, 382 flight_buffer = #{handshakes := HsBuffer0, 383 change_cipher_spec := undefined, 384 next_sequence := Seq} = Flight0, 385 ssl_options = #{log_level := LogLevel}} = State) -> 386 Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq), 387 Hist = update_handshake_history(Handshake0, Handshake, Hist0), 388 ssl_logger:debug(LogLevel, outbound, 'handshake', Handshake0), 389 390 State#state{flight_buffer = Flight0#{handshakes => [Handshake | HsBuffer0], 391 next_sequence => Seq +1}, 392 handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}; 393 394queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, 395 connection_env = #connection_env{negotiated_version = Version}, 396 flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0, 397 next_sequence := Seq} = Flight0, 398 ssl_options = #{log_level := LogLevel}} = State) -> 399 Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq), 400 Hist = update_handshake_history(Handshake0, Handshake, Hist0), 401 ssl_logger:debug(LogLevel, outbound, 'handshake', Handshake0), 402 403 State#state{flight_buffer = Flight0#{handshakes_after_change_cipher_spec => [Handshake | Buffer0], 404 next_sequence => Seq +1}, 405 handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}. 406 407queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight, 408 connection_states = ConnectionStates0} = State) -> 409 ConnectionStates = 410 dtls_record:next_epoch(ConnectionStates0, write), 411 State#state{flight_buffer = Flight#{change_cipher_spec => ChangeCipher}, 412 connection_states = ConnectionStates}. 413 414reinit(State) -> 415 %% To be API compatible with TLS NOOP here 416 reinit_handshake_data(State). 417reinit_handshake_data(#state{static_env = #static_env{data_tag = DataTag}, 418 protocol_buffers = Buffers, 419 protocol_specific = PS, 420 handshake_env = HsEnv} = State) -> 421 State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(), 422 public_key_info = undefined, 423 premaster_secret = undefined}, 424 protocol_specific = PS#{flight_state => initial_flight_state(DataTag)}, 425 flight_buffer = new_flight(), 426 protocol_buffers = 427 Buffers#protocol_buffers{ 428 dtls_handshake_next_seq = 0, 429 dtls_handshake_next_fragments = [], 430 dtls_handshake_later_fragments = [] 431 }}. 432 433select_sni_extension(#client_hello{extensions = #{sni := SNI}}) -> 434 SNI; 435select_sni_extension(_) -> 436 undefined. 437 438empty_connection_state(ConnectionEnd, BeastMitigation) -> 439 Empty = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation), 440 dtls_record:empty_connection_state(Empty). 441%%==================================================================== 442%% Alert and close handling 443%%==================================================================== 444encode_alert(#alert{} = Alert, Version, ConnectionStates) -> 445 dtls_record:encode_alert_record(Alert, Version, ConnectionStates). 446 447send_alert(Alert, #state{static_env = #static_env{socket = Socket, 448 transport_cb = Transport}, 449 450 connection_env = #connection_env{negotiated_version = Version}, 451 connection_states = ConnectionStates0, 452 ssl_options = #{log_level := LogLevel}} = State0) -> 453 {BinMsg, ConnectionStates} = 454 encode_alert(Alert, Version, ConnectionStates0), 455 send(Transport, Socket, BinMsg), 456 ssl_logger:debug(LogLevel, outbound, 'record', BinMsg), 457 State0#state{connection_states = ConnectionStates}. 458 459send_alert_in_connection(Alert, State) -> 460 _ = send_alert(Alert, State), 461 ok. 462 463close(downgrade, _,_,_,_) -> 464 ok; 465%% Other 466close(_, Socket, Transport, _,_) -> 467 dtls_socket:close(Transport,Socket). 468 469protocol_name() -> 470 "DTLS". 471 472%%==================================================================== 473%% Data handling 474%%==================================================================== 475send(Transport, {Listener, Socket}, Data) when is_pid(Listener) -> 476 %% Server socket 477 dtls_socket:send(Transport, Socket, Data); 478send(Transport, Socket, Data) -> % Client socket 479 dtls_socket:send(Transport, Socket, Data). 480 481socket(Pid, Transport, Socket, _Tracker) -> 482 dtls_socket:socket(Pid, Transport, Socket, ?MODULE). 483 484setopts(Transport, Socket, Other) -> 485 dtls_socket:setopts(Transport, Socket, Other). 486 487getopts(Transport, Socket, Tag) -> 488 dtls_socket:getopts(Transport, Socket, Tag). 489 490%% raw data from socket, unpack records 491handle_info({Protocol, _, _, _, Data}, StateName, 492 #state{static_env = #static_env{role = Role, 493 data_tag = Protocol}} = State0) -> 494 case next_dtls_record(Data, StateName, State0) of 495 {Record, State} -> 496 next_event(StateName, Record, State); 497 #alert{} = Alert -> 498 ssl_gen_statem:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State0), 499 {stop, {shutdown, own_alert}, State0} 500 end; 501 502handle_info({PassiveTag, Socket}, StateName, 503 #state{static_env = #static_env{socket = {_, Socket}, 504 passive_tag = PassiveTag}, 505 protocol_specific = PS} = State) -> 506 next_event(StateName, no_record, 507 State#state{protocol_specific = PS#{active_n_toggle => true}}); 508 509handle_info({CloseTag, Socket}, StateName, 510 #state{static_env = #static_env{ 511 role = Role, 512 socket = Socket, 513 close_tag = CloseTag}, 514 connection_env = #connection_env{negotiated_version = Version}, 515 socket_options = #socket_options{active = Active}, 516 protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs}, 517 protocol_specific = PS} = State) -> 518 %% Note that as of DTLS 1.2 (TLS 1.1), 519 %% failure to properly close a connection no longer requires that a 520 %% session not be resumed. This is a change from DTLS 1.0 to conform 521 %% with widespread implementation practice. 522 case (Active == false) andalso (CTs =/= []) of 523 false -> 524 case Version of 525 {254, N} when N =< 253 -> 526 ok; 527 _ -> 528 %% As invalidate_sessions here causes performance issues, 529 %% we will conform to the widespread implementation 530 %% practice and go aginst the spec 531 %%invalidate_session(Role, Host, Port, Session) 532 ok 533 end, 534 Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, transport_closed), 535 ssl_gen_statem:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State), 536 {stop, {shutdown, transport_closed}, State}; 537 true -> 538 %% Fixes non-delivery of final DTLS record in {active, once}. 539 %% Basically allows the application the opportunity to set {active, once} again 540 %% and then receive the final message. 541 next_event(StateName, no_record, State#state{ 542 protocol_specific = PS#{active_n_toggle => true}}) 543 end; 544 545handle_info(new_cookie_secret, StateName, 546 #state{protocol_specific = #{current_cookie_secret := Secret} = CookieInfo} = State) -> 547 erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret), 548 {next_state, StateName, State#state{protocol_specific = 549 CookieInfo#{current_cookie_secret => dtls_v1:cookie_secret(), 550 previous_cookie_secret => Secret}}}; 551handle_info(Msg, StateName, State) -> 552 ssl_gen_statem:handle_info(Msg, StateName, State). 553 554%%==================================================================== 555%% Internal functions 556%%==================================================================== 557 558dtls_handshake_events(Packets) -> 559 lists:map(fun(Packet) -> 560 {next_event, internal, {handshake, Packet}} 561 end, Packets). 562 563unprocessed_events(Events) -> 564 %% The first handshake event will be processed immediately 565 %% as it is entered first in the event queue and 566 %% when it is processed there will be length(Events)-1 567 %% handshake events left to process before we should 568 %% process more TLS-records received on the socket. 569 erlang:length(Events)-1. 570 571encode_handshake_flight(Flight, Version, MaxFragmentSize, Epoch, ConnectionStates) -> 572 Fragments = lists:map(fun(Handshake) -> 573 dtls_handshake:fragment_handshake(Handshake, MaxFragmentSize) 574 end, Flight), 575 dtls_record:encode_handshake(Fragments, Version, Epoch, ConnectionStates). 576 577encode_change_cipher(#change_cipher_spec{}, Version, Epoch, ConnectionStates) -> 578 dtls_record:encode_change_cipher_spec(Version, Epoch, ConnectionStates). 579 580update_handshake_history(#hello_verify_request{}, _, Hist) -> 581 Hist; 582update_handshake_history(_, Handshake, Hist) -> 583 ssl_handshake:update_handshake_history(Hist, iolist_to_binary(Handshake)). 584 585next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{ 586 dtls_record_buffer = Buf0, 587 dtls_cipher_texts = CT0} = Buffers, 588 connection_env = #connection_env{negotiated_version = Version}, 589 static_env = #static_env{data_tag = DataTag}, 590 ssl_options = SslOpts} = State0) -> 591 case dtls_record:get_dtls_records(Data, 592 {DataTag, StateName, Version, 593 [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS]}, 594 Buf0, SslOpts) of 595 {Records, Buf1} -> 596 CT1 = CT0 ++ Records, 597 next_record(State0#state{protocol_buffers = 598 Buffers#protocol_buffers{dtls_record_buffer = Buf1, 599 dtls_cipher_texts = CT1}}); 600 #alert{} = Alert -> 601 Alert 602 end. 603 604 605 606decode_cipher_text(#state{protocol_buffers = #protocol_buffers{dtls_cipher_texts = [ CT | Rest]} = Buffers, 607 connection_states = ConnStates0} = State) -> 608 case dtls_record:decode_cipher_text(CT, ConnStates0) of 609 {Plain, ConnStates} -> 610 {Plain, State#state{protocol_buffers = 611 Buffers#protocol_buffers{dtls_cipher_texts = Rest}, 612 connection_states = ConnStates}}; 613 #alert{} = Alert -> 614 {Alert, State} 615 end. 616 617decode_alerts(Bin) -> 618 ssl_alert:decode(Bin). 619 620handle_alerts([], Result) -> 621 Result; 622handle_alerts(_, {stop, _, _} = Stop) -> 623 Stop; 624handle_alerts([Alert | Alerts], {next_state, StateName, State}) -> 625 handle_alerts(Alerts, ssl_gen_statem:handle_alert(Alert, StateName, State)); 626handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) -> 627 handle_alerts(Alerts, ssl_gen_statem:handle_alert(Alert, StateName, State)). 628 629handle_own_alert(Alert, Version, StateName, 630 #state{static_env = #static_env{data_tag = udp, 631 role = Role}, 632 ssl_options = #{log_level := LogLevel}} = State0) -> 633 case ignore_alert(Alert, State0) of 634 {true, State} -> 635 log_ignore_alert(LogLevel, StateName, Alert, Role), 636 {next_state, StateName, State}; 637 {false, State} -> 638 ssl_gen_statem:handle_own_alert(Alert, Version, StateName, State) 639 end; 640handle_own_alert(Alert, Version, StateName, State) -> 641 ssl_gen_statem:handle_own_alert(Alert, Version, StateName, State). 642ignore_alert(#alert{level = ?FATAL}, #state{protocol_specific = #{ignored_alerts := N, 643 max_ignored_alerts := N}} = State) -> 644 {false, State}; 645ignore_alert(#alert{level = ?FATAL} = Alert, 646 #state{protocol_specific = #{ignored_alerts := N} = PS} = State) -> 647 case is_ignore_alert(Alert) of 648 true -> 649 {true, State#state{protocol_specific = PS#{ignored_alerts => N+1}}}; 650 false -> 651 {false, State} 652 end; 653ignore_alert(_, State) -> 654 {false, State}. 655 656%% RFC 6347 4.1.2.7. Handling Invalid Records 657%% recommends to silently ignore invalid DTLS records when 658%% upd is the transport. Note we do not support compression so no need 659%% include ?DECOMPRESSION_FAILURE 660is_ignore_alert(#alert{description = ?BAD_RECORD_MAC}) -> 661 true; 662is_ignore_alert(#alert{description = ?RECORD_OVERFLOW}) -> 663 true; 664is_ignore_alert(#alert{description = ?DECODE_ERROR}) -> 665 true; 666is_ignore_alert(#alert{description = ?DECRYPT_ERROR}) -> 667 true; 668is_ignore_alert(#alert{description = ?ILLEGAL_PARAMETER}) -> 669 true; 670is_ignore_alert(_) -> 671 false. 672 673log_ignore_alert(Level, StateName, #alert{where = Location} = Alert, Role) -> 674 ssl_logger:log(info, 675 Level, #{alert => Alert, 676 alerter => ignored, 677 statename => StateName, 678 role => Role, 679 protocol => protocol_name()}, Location). 680 681dtls_version(hello, Version, #state{static_env = #static_env{role = server}, 682 connection_env = CEnv} = State) -> 683 State#state{connection_env = CEnv#connection_env{negotiated_version = Version}}; %%Inital version 684dtls_version(_,_, State) -> 685 State. 686