diff options
Diffstat (limited to 'lib/ssl/src/dtls_connection.erl')
-rw-r--r-- | lib/ssl/src/dtls_connection.erl | 112 |
1 files changed, 72 insertions, 40 deletions
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 65076994f9..08229d8bb5 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2022. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -46,7 +46,8 @@ %% ClientKeyExchange \ %% CertificateVerify* Flight 5 %% [ChangeCipherSpec] / -%% Finished --------> / +%% NextProtocol* / +%% Finished --------> / %% %% [ChangeCipherSpec] \ Flight 6 %% <-------- Finished / @@ -64,7 +65,8 @@ %% <-------- Finished / part 2 %% %% [ChangeCipherSpec] \ Abbrev Flight 3 -%% Finished --------> / +%% NextProtocol* / +%% Finished --------> / %% %% %% Message Flights for Abbbriviated Handshake @@ -142,6 +144,7 @@ user_hello/3, wait_ocsp_stapling/3, certify/3, + wait_cert_verify/3, cipher/3, abbreviated/3, connection/3]). @@ -160,16 +163,15 @@ %%==================================================================== init([Role, Host, Port, Socket, Options, User, CbInfo]) -> process_flag(trap_exit, true), - State0 = #state{protocol_specific = Map} = - initial_state(Role, Host, Port, Socket, Options, User, CbInfo), + State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo), try State = ssl_gen_statem:ssl_config(State0#state.ssl_options, Role, State0), gen_statem:enter_loop(?MODULE, [], initial_hello, State) catch throw:Error -> - EState = State0#state{protocol_specific = - Map#{error => Error}}, + #state{protocol_specific = Map} = State0, + EState = State0#state{protocol_specific = Map#{error => Error}}, gen_statem:enter_loop(?MODULE, [], config_error, EState) end. %%==================================================================== @@ -208,13 +210,14 @@ initial_hello({call, From}, {start, Timeout}, session_cache_cb = CacheCb}, protocol_specific = PS, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, - connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv, + connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv, ssl_options = #{versions := Versions} = SslOpts, session = Session0, connection_states = ConnectionStates0 } = State0) -> Packages = maps:get(active_n, PS), dtls_socket:setopts(Transport, Socket, [{active,Packages}]), + CertKeyPairs = ssl_certificate:available_cert_key_pairs(CertKeyAlts), Session = ssl_session:client_select_session({Host, Port, SslOpts}, Cache, CacheCb, Session0, CertKeyPairs), Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Session#session.session_id, Renegotiation), @@ -324,14 +327,12 @@ hello(internal, #hello_verify_request{cookie = Cookie}, }, dtls_gen_connection:next_event(?FUNCTION_NAME, no_record, State, Actions); hello(internal, #client_hello{extensions = Extensions} = Hello, - #state{ssl_options = #{handshake := hello}, - handshake_env = HsEnv, + #state{handshake_env = #handshake_env{continue_status = pause}, start_or_recv_from = From} = State0) -> try tls_dtls_connection:handle_sni_extension(State0, Hello) of #state{} = State -> - {next_state, user_hello, State#state{start_or_recv_from = undefined, - handshake_env = HsEnv#handshake_env{hello = Hello}}, - [{reply, From, {ok, Extensions}}]} + {next_state, user_hello, State#state{start_or_recv_from = undefined}, + [{postpone, true}, {reply, From, {ok, Extensions}}]} catch throw:#alert{} = Alert -> alert_or_reset_connection(Alert, ?FUNCTION_NAME, State0) end; @@ -354,16 +355,11 @@ hello(internal, #client_hello{cookie = Cookie} = Hello, #state{static_env = #sta hello(internal, Hello#client_hello{cookie = <<>>}, State) end end; -hello(internal, #server_hello{extensions = Extensions} = Hello, - #state{ssl_options = #{ - handshake := hello}, - handshake_env = HsEnv, +hello(internal, #server_hello{extensions = Extensions}, + #state{handshake_env = #handshake_env{continue_status = pause}, start_or_recv_from = From} = State) -> - {next_state, user_hello, State#state{start_or_recv_from = undefined, - handshake_env = HsEnv#handshake_env{ - hello = Hello}}, - [{reply, From, {ok, Extensions}}]}; - + {next_state, user_hello, State#state{start_or_recv_from = undefined}, + [{postpone, true},{reply, From, {ok, Extensions}}]}; hello(internal, #server_hello{} = Hello, #state{ static_env = #static_env{role = client}, @@ -469,6 +465,24 @@ certify(state_timeout, Event, State) -> certify(Type, Event, State) -> gen_handshake(?FUNCTION_NAME, Type, Event, State). + +%%-------------------------------------------------------------------- +-spec wait_cert_verify(gen_statem:event_type(), term(), #state{}) -> + gen_statem:state_function_result(). +%%-------------------------------------------------------------------- +wait_cert_verify(enter, _Event, State0) -> + {State, Actions} = handle_flight_timer(State0), + {keep_state, State, Actions}; +wait_cert_verify(info, Event, State) -> + gen_info(Event, ?FUNCTION_NAME, State); +wait_cert_verify(state_timeout, Event, State) -> + handle_state_timeout(Event, ?FUNCTION_NAME, State); +wait_cert_verify(Type, Event, State) -> + try tls_dtls_connection:gen_handshake(?FUNCTION_NAME, Type, Event, State) + catch throw:#alert{} = Alert -> + ssl_gen_statem:handle_own_alert(Alert, ?FUNCTION_NAME, State) + end. + %%-------------------------------------------------------------------- -spec cipher(gen_statem:event_type(), term(), #state{}) -> gen_statem:state_function_result(). @@ -498,13 +512,20 @@ cipher(Type, Event, State) -> #hello_request{} | #client_hello{}| term(), #state{}) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- -connection(enter, _, #state{connection_states = Cs0} = State0) -> - State = case maps:is_key(previous_cs, Cs0) of - false -> - State0; - true -> - Cs = maps:remove(previous_cs, Cs0), - State0#state{connection_states = Cs} +connection(enter, _, #state{connection_states = Cs0, + static_env = Env} = State0) -> + State = case Env of + #static_env{socket = {Listener, {Client, _}}} -> + dtls_packet_demux:connection_setup(Listener, Client), + case maps:is_key(previous_cs, Cs0) of + false -> + State0; + true -> + Cs = maps:remove(previous_cs, Cs0), + State0#state{connection_states = Cs} + end; + _ -> %% client + State0 end, {keep_state, State}; connection(info, Event, State) -> @@ -516,13 +537,14 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho session_cache_cb = CacheCb }, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, - connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv, + connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv, session = Session0, ssl_options = #{versions := Versions} = SslOpts, connection_states = ConnectionStates0, protocol_specific = PS } = State0) -> #{current_cookie_secret := Cookie} = PS, + CertKeyPairs = ssl_certificate:available_cert_key_pairs(CertKeyAlts), Session = ssl_session:client_select_session({Host, Port, SslOpts}, Cache, CacheCb, Session0, CertKeyPairs), Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts, Session#session.session_id, Renegotiation, undefined), @@ -557,14 +579,20 @@ connection(internal, #client_hello{}, #state{static_env = #static_env{role = ser dtls_gen_connection:next_event(?FUNCTION_NAME, Record, State); connection(internal, new_connection, #state{ssl_options=SSLOptions, handshake_env=HsEnv, + static_env = #static_env{socket = {Listener, {Client, _}}}, connection_states = OldCs} = State) -> case maps:get(previous_cs, OldCs, undefined) of undefined -> - BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled), - ConnectionStates0 = dtls_record:init_connection_states(server, BeastMitigation), - ConnectionStates = ConnectionStates0#{previous_cs => OldCs}, - {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {false, first}}, - connection_states = ConnectionStates}}; + case dtls_packet_demux:new_connection(Listener, Client) of + true -> + {keep_state, State}; + false -> + BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled), + ConnectionStates0 = dtls_record:init_connection_states(server, BeastMitigation), + ConnectionStates = ConnectionStates0#{previous_cs => OldCs}, + {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {false, first}}, + connection_states = ConnectionStates}} + end; _ -> %% Someone spamming new_connection, just drop them {keep_state, State} @@ -628,6 +656,7 @@ format_status(Type, Data) -> initial_state(Role, Host, Port, Socket, {#{client_renegotiation := ClientRenegotiation} = SSLOptions, SocketOptions, Trackers}, User, {CbModule, DataTag, CloseTag, ErrorTag, PassiveTag}) -> + put(log_level, maps:get(log_level, SSLOptions)), BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled), ConnectionStates = dtls_record:init_connection_states(Role, BeastMitigation), #{session_cb := SessionCacheCb} = ssl_config:pre_1_3_session_opts(Role), @@ -681,14 +710,14 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State handshake_env = #handshake_env{kex_algorithm = KeyExAlg, renegotiation = {Renegotiation, _}, negotiated_protocol = CurrentProtocol} = HsEnv, - connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv, + connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv, session = Session0, ssl_options = SslOpts} = tls_dtls_connection:handle_sni_extension(State0, Hello), SessionTracker = proplists:get_value(session_id_tracker, Trackers), {Version, {Type, Session}, ConnectionStates, Protocol0, ServerHelloExt, HashSign} = dtls_handshake:hello(Hello, SslOpts, {SessionTracker, Session0, - ConnectionStates0, CertKeyPairs, KeyExAlg}, Renegotiation), + ConnectionStates0, CertKeyAlts, KeyExAlg}, Renegotiation), Protocol = case Protocol0 of undefined -> CurrentProtocol; _ -> Protocol0 @@ -738,20 +767,23 @@ gen_handshake(StateName, Type, Event, State) -> catch throw:#alert{}=Alert -> alert_or_reset_connection(Alert, StateName, State); - error:_ -> + error:Reason:ST -> + ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]), Alert = ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data), alert_or_reset_connection(Alert, StateName, State) end. gen_info(Event, connection = StateName, State) -> try dtls_gen_connection:handle_info(Event, StateName, State) - catch error:_ -> + catch error:Reason:ST -> + ?SSL_LOG(info, internal_error, [{error, Reason}, {stacktrace, ST}]), Alert = ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, malformed_data), alert_or_reset_connection(Alert, StateName, State) end; gen_info(Event, StateName, State) -> try dtls_gen_connection:handle_info(Event, StateName, State) - catch error:_ -> + catch error:Reason:ST -> + ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]), Alert = ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,malformed_handshake_data), alert_or_reset_connection(Alert, StateName, State) end. |