diff options
Diffstat (limited to 'lib/ssl/src/ssl_gen_statem.erl')
-rw-r--r-- | lib/ssl/src/ssl_gen_statem.erl | 84 |
1 files changed, 55 insertions, 29 deletions
diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl index caa6c6742d..36768ab6c7 100644 --- a/lib/ssl/src/ssl_gen_statem.erl +++ b/lib/ssl/src/ssl_gen_statem.erl @@ -25,8 +25,6 @@ -module(ssl_gen_statem). --include_lib("kernel/include/logger.hrl"). - -include("ssl_api.hrl"). -include("ssl_internal.hrl"). -include("ssl_connection.hrl"). @@ -102,24 +100,28 @@ %%% Initial Erlang process setup %%-------------------------------------------------------------------- %%-------------------------------------------------------------------- --spec start_link(client| server, pid(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) -> +-spec start_link(client| server, pid(), ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) -> {ok, pid()} | ignore | {error, reason()}. %% %% Description: Creates a process which calls Module:init/1 to %% choose appropriat gen_statem and initialize. %%-------------------------------------------------------------------- -start_link(Role, Sender, Host, Port, Socket, Options, User, CbInfo) -> - {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]])}. +start_link(Role, Sender, Host, Port, Socket, {#{receiver_spawn_opts := ReceiverOpts}, _, _} = Options, User, CbInfo) -> + Opts = [link | proplists:delete(link, ReceiverOpts)], + Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]], Opts), + {ok, Pid}. %%-------------------------------------------------------------------- --spec start_link(atom(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) -> +-spec start_link(atom(), ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) -> {ok, pid()} | ignore | {error, reason()}. %% %% Description: Creates a gen_statem process which calls Module:init/1 to %% initialize. %%-------------------------------------------------------------------- -start_link(Role, Host, Port, Socket, Options, User, CbInfo) -> - {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}. +start_link(Role, Host, Port, Socket, {#{receiver_spawn_opts := ReceiverOpts}, _, _} = Options, User, CbInfo) -> + Opts = [link | proplists:delete(link, ReceiverOpts)], + Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]], Opts), + {ok, Pid}. %%-------------------------------------------------------------------- @@ -149,6 +151,7 @@ init([_Role, _Host, _Port, _Socket, {TLSOpts, _, _}, _User, _CbInfo] = InitArgs -spec ssl_config(ssl_options(), client | server, #state{}) -> #state{}. %%-------------------------------------------------------------------- ssl_config(Opts, Role, #state{static_env = InitStatEnv0, + ssl_options = #{handshake := Handshake}, handshake_env = HsEnv, connection_env = CEnv} = State0) -> {ok, #{cert_db_ref := Ref, @@ -156,12 +159,21 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0, fileref_db_handle := FileRefHandle, session_cache := CacheHandle, crl_db_info := CRLDbHandle, - cert_key_pairs := CertKeyPairs, + cert_key_alts := CertKeyAlts, dh_params := DHParams}} = ssl_config:init(Opts, Role), TimeStamp = erlang:monotonic_time(), Session = State0#state.session, + ContinueStatus = case Handshake of + hello -> + %% Will pause handshake after hello message to + %% enable user to react to hello extensions + pause; + full -> + Handshake + end, + State0#state{session = Session#session{time_stamp = TimeStamp}, static_env = InitStatEnv0#static_env{ file_ref_db = FileRefHandle, @@ -170,8 +182,9 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0, crl_db = CRLDbHandle, session_cache = CacheHandle }, - handshake_env = HsEnv#handshake_env{diffie_hellman_params = DHParams}, - connection_env = CEnv#connection_env{cert_key_pairs = CertKeyPairs}, + handshake_env = HsEnv#handshake_env{diffie_hellman_params = DHParams, + continue_status = ContinueStatus}, + connection_env = CEnv#connection_env{cert_key_alts = CertKeyAlts}, ssl_options = Opts}. %%-------------------------------------------------------------------- @@ -709,8 +722,6 @@ handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName, Connection:handle_protocol_record(TLSorDTLSRecord, StateName, State); handle_common_event(timeout, hibernate, _, _) -> {keep_state_and_data, [hibernate]}; -handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName, State) -> - handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), StateName, State); handle_common_event({timeout, handshake}, close, _StateName, #state{start_or_recv_from = StartFrom} = State) -> {stop_and_reply, {shutdown, user_timeout}, @@ -840,10 +851,9 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName, handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{ role = Role, socket = Socket, - error_tag = ErrorTag}, - ssl_options = #{log_level := Level}} = State) -> - ssl_logger:log(info, Level, #{description => "Socket error", - reason => [{error_tag, ErrorTag}, {description, Reason}]}, ?LOCATION), + error_tag = ErrorTag} + } = State) -> + ?SSL_LOG(info, "Socket error", [{error_tag, ErrorTag}, {description, Reason}]), Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, {transport_error, Reason}), handle_normal_shutdown(Alert#alert{role = Role}, StateName, State), {stop, {shutdown,normal}, State}; @@ -870,11 +880,9 @@ handle_info({'EXIT', Socket, Reason}, _StateName, #state{static_env = #static_en {stop,{shutdown, Reason}, State}; handle_info(allow_renegotiate, StateName, #state{handshake_env = HsEnv} = State) -> %% PRE TLS-1.3 {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{allow_renegotiate = true}}}; -handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, error_tag = ErrorTag}, - ssl_options = #{log_level := Level}} = State) -> - ssl_logger:log(notice, Level, #{description => "Unexpected INFO message", - reason => [{message, Msg}, {socket, Socket}, - {error_tag, ErrorTag}]}, ?LOCATION), +handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, error_tag = ErrorTag}} = State) -> + ?SSL_LOG(notice, "Unexpected INFO message", + [{message, Msg}, {socket, Socket}, {error_tag, ErrorTag}]), {next_state, StateName, State}. %%==================================================================== @@ -896,9 +904,25 @@ read_application_data(Data, try read_application_dist_data(DHandle, Front, BufferSize, Rear) of Buffer -> {no_record, State#state{user_data_buffer = Buffer}} - catch error:_ -> - {stop,disconnect, - State#state{user_data_buffer = {Front,BufferSize,Rear}}} + catch + error:notsup -> + %% Distribution controller has shut down + %% so we are no longer input handler and therefore + %% erlang:dist_ctrl_put_data/2 raises this exception + {stop, {shutdown, dist_closed}, + %% This buffers known data, but we might have delivered + %% some of it to the VM, which makes buffering all + %% incorrect, as would be wasting all. + %% But we are stopping the server so + %% user_data_buffer is not important at all... + State#state{ + user_data_buffer = {Front,BufferSize,Rear}}}; + error:Reason:Stacktrace -> + %% Unforeseen exception in parsing application data + {stop, + {disconnect,{error,Reason,Stacktrace}}, + State#state{ + user_data_buffer = {Front,BufferSize,Rear}}} end end. passive_receive(#state{user_data_buffer = {Front,BufferSize,Rear}, @@ -1151,7 +1175,7 @@ terminate(Reason, connection, #state{static_env = #static_env{ handle_trusted_certs_db(State), Alert = terminate_alert(Reason), %% Send the termination ALERT if possible - catch (ok = Connection:send_alert_in_connection(Alert, State)), + catch Connection:send_alert_in_connection(Alert, State), Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, ConnectionStates); terminate(Reason, _StateName, #state{static_env = #static_env{transport_cb = Transport, protocol_cb = Connection, @@ -1278,7 +1302,7 @@ handle_sni_hostname(Hostname, fileref_db_handle := FileRefHandle, session_cache := CacheHandle, crl_db_info := CRLDbHandle, - cert_key_pairs := CertKeyPairs, + cert_key_alts := CertKeyAlts, dh_params := DHParams}} = ssl_config:init(NewOptions, Role), State0#state{ @@ -1289,7 +1313,7 @@ handle_sni_hostname(Hostname, crl_db = CRLDbHandle, session_cache = CacheHandle }, - connection_env = CEnv#connection_env{cert_key_pairs = CertKeyPairs}, + connection_env = CEnv#connection_env{cert_key_alts = CertKeyAlts}, ssl_options = NewOptions, handshake_env = HsEnv#handshake_env{sni_hostname = Hostname, diffie_hellman_params = DHParams} @@ -1333,7 +1357,9 @@ filter_for_versions(['tlsv1.1'], OrigSSLOptions) -> maps:without(Opts, OrigSSLOptions); filter_for_versions(['tlsv1.1'| Rest], OrigSSLOptions) -> Opts = ?'TLS-1_3_ONLY_OPTIONS' ++ ?'FROM_TLS-1_2_ONLY_OPTIONS', - maybe_exclude_tlsv1(Rest, maps:without(Opts, OrigSSLOptions)). + maybe_exclude_tlsv1(Rest, maps:without(Opts, OrigSSLOptions)); +filter_for_versions(['tlsv1'], OrigSSLOptions) -> + OrigSSLOptions. maybe_exclude_tlsv1(Versions, Options) -> case lists:member('tlsv1', Versions) of |