From f69963a389fa1f933fee0664e8bb453389977b14 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 28 Jan 2019 16:23:04 +0100 Subject: ssl: Handle renegotiation and extensions in handshake_env --- lib/ssl/src/dtls_connection.erl | 28 ++++++------ lib/ssl/src/ssl_connection.erl | 94 +++++++++++++++++++++-------------------- lib/ssl/src/ssl_connection.hrl | 17 ++++---- lib/ssl/src/tls_connection.erl | 32 +++++++------- 4 files changed, 90 insertions(+), 81 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 70dae4c677..ac380f2595 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -540,15 +540,17 @@ hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #sta next_event(?FUNCTION_NAME, no_record, State, Actions); hello(internal, #client_hello{extensions = Extensions} = Hello, #state{ssl_options = #ssl_options{handshake = hello}, + handshake_env = HsEnv, start_or_recv_from = From} = State) -> {next_state, user_hello, State#state{start_or_recv_from = undefined, - hello = Hello}, + handshake_env = HsEnv#handshake_env{hello = Hello}}, [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]}; hello(internal, #server_hello{extensions = Extensions} = Hello, #state{ssl_options = #ssl_options{handshake = hello}, + handshake_env = HsEnv, start_or_recv_from = From} = State) -> {next_state, user_hello, State#state{start_or_recv_from = undefined, - hello = Hello}, + handshake_env = HsEnv#handshake_env{hello = Hello}}, [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]}; hello(internal, #client_hello{cookie = Cookie} = Hello, #state{static_env = #static_env{role = server, @@ -709,18 +711,18 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho = Hello#client_hello.session_id}}), next_event(hello, Record, State, Actions); connection(internal, #client_hello{} = Hello, #state{static_env = #static_env{role = server}, - allow_renegotiate = true} = State) -> + handshake_env = #handshake_env{allow_renegotiate = true} = HsEnv} = State) -> %% Mitigate Computational DoS attack %% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html %% http://www.thc.org/thc-ssl-dos/ Rather than disabling client %% initiated renegotiation we will disallow many client initiated %% renegotiations immediately after each other. erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate), - {next_state, hello, State#state{allow_renegotiate = false, - handshake_env = #handshake_env{renegotiation = {true, peer}}}, + {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, peer}, + allow_renegotiate = false}}, [{next_event, internal, Hello}]}; connection(internal, #client_hello{}, #state{static_env = #static_env{role = server}, - allow_renegotiate = false} = State0) -> + handshake_env = #handshake_env{allow_renegotiate = false}} = State0) -> Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION), State1 = send_alert(Alert, State0), {Record, State} = ssl_connection:prepare_connection(State1, ?MODULE), @@ -791,7 +793,8 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User, #state{static_env = InitStatEnv, handshake_env = #handshake_env{ tls_handshake_history = ssl_handshake:init_handshake_history(), - renegotiation = {false, first} + renegotiation = {false, first}, + allow_renegotiate = SSLOptions#ssl_options.client_renegotiation }, socket_options = SocketOptions, %% We do not want to save the password in the state so that @@ -802,7 +805,6 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User, protocol_buffers = #protocol_buffers{}, user_application = {Monitor, User}, user_data_buffer = <<>>, - allow_renegotiate = SSLOptions#ssl_options.client_renegotiation, start_or_recv_from = undefined, flight_buffer = new_flight(), flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT} @@ -854,9 +856,9 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, static_env = #static_env{port = Port, session_cache = Cache, session_cache_cb = CacheCb}, - handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}, + negotiated_protocol = CurrentProtocol} = HsEnv, session = #session{own_certificate = Cert} = Session0, - negotiated_protocol = CurrentProtocol, key_algorithm = KeyExAlg, ssl_options = SslOpts} = State0) -> @@ -874,9 +876,9 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State = prepare_flight(State0#state{connection_states = ConnectionStates, negotiated_version = Version, hashsign_algorithm = HashSign, - handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion}, - session = Session, - negotiated_protocol = Protocol}), + handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion, + negotiated_protocol = Protocol}, + session = Session}), ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt}, State, ?MODULE) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 41a45089d0..9d5b6efced 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -572,7 +572,7 @@ handle_session(#server_hello{cipher_suite = CipherSuite, Version, NewId, ConnectionStates, ProtoExt, Protocol0, #state{session = #session{session_id = OldId}, negotiated_version = ReqVersion, - negotiated_protocol = CurrentProtocol} = State0) -> + handshake_env = #handshake_env{negotiated_protocol = CurrentProtocol} = HsEnv} = State0) -> #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_definition(CipherSuite), @@ -589,8 +589,8 @@ handle_session(#server_hello{cipher_suite = CipherSuite, negotiated_version = Version, connection_states = ConnectionStates, premaster_secret = PremasterSecret, - expecting_next_protocol_negotiation = ExpectNPN, - negotiated_protocol = Protocol}, + handshake_env = HsEnv#handshake_env{expecting_next_protocol_negotiation = ExpectNPN, + negotiated_protocol = Protocol}}, case ssl_session:is_new(OldId, NewId) of true -> @@ -706,8 +706,8 @@ user_hello({call, From}, cancel, #state{negotiated_version = Version} = State, _ handle_own_alert(?ALERT_REC(?FATAL, ?USER_CANCELED, user_canceled), Version, ?FUNCTION_NAME, State); user_hello({call, From}, {handshake_continue, NewOptions, Timeout}, - #state{hello = Hello, - static_env = #static_env{role = Role}, + #state{static_env = #static_env{role = Role}, + handshake_env = #handshake_env{hello = Hello}, start_or_recv_from = RecvFrom, ssl_options = Options0} = State0, _Connection) -> Timer = start_or_recv_cancel_timer(Timeout, RecvFrom), @@ -729,9 +729,9 @@ abbreviated({call, From}, Msg, State, Connection) -> handle_call(Msg, From, ?FUNCTION_NAME, State, Connection); abbreviated(internal, #finished{verify_data = Data} = Finished, #state{static_env = #static_env{role = server}, - handshake_env = #handshake_env{tls_handshake_history = Hist}, + handshake_env = #handshake_env{tls_handshake_history = Hist, + expecting_finished = true} = HsEnv, negotiated_version = Version, - expecting_finished = true, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = State0, Connection) -> @@ -742,7 +742,7 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), {Record, State} = prepare_connection(State0#state{connection_states = ConnectionStates, - expecting_finished = false}, Connection), + handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection), Connection:next_event(connection, Record, State); #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0) @@ -759,10 +759,10 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, verified -> ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0), - {State1, Actions} = + {#state{handshake_env = HsEnv} = State1, Actions} = finalize_handshake(State0#state{connection_states = ConnectionStates1}, ?FUNCTION_NAME, Connection), - {Record, State} = prepare_connection(State1#state{expecting_finished = false}, Connection), + {Record, State} = prepare_connection(State1#state{handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection), Connection:next_event(connection, Record, State, Actions); #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0) @@ -771,19 +771,20 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, %% & before finished message and it is not allowed during renegotiation abbreviated(internal, #next_protocol{selected_protocol = SelectedProtocol}, #state{static_env = #static_env{role = server}, - expecting_next_protocol_negotiation = true} = State, + handshake_env = #handshake_env{expecting_next_protocol_negotiation = true} = HsEnv} = State, Connection) -> Connection:next_event(?FUNCTION_NAME, no_record, - State#state{negotiated_protocol = SelectedProtocol, - expecting_next_protocol_negotiation = false}); + State#state{handshake_env = HsEnv#handshake_env{negotiated_protocol = SelectedProtocol, + expecting_next_protocol_negotiation = false}}); abbreviated(internal, #change_cipher_spec{type = <<1>>}, - #state{connection_states = ConnectionStates0} = State, Connection) -> + #state{connection_states = ConnectionStates0, + handshake_env = HsEnv} = State, Connection) -> ConnectionStates1 = ssl_record:activate_pending_connection_state(ConnectionStates0, read, Connection), Connection:next_event(?FUNCTION_NAME, no_record, State#state{connection_states = ConnectionStates1, - expecting_finished = true}); + handshake_env = HsEnv#handshake_env{expecting_finished = true}}); abbreviated(info, Msg, State, _) -> handle_info(Msg, ?FUNCTION_NAME, State); abbreviated(Type, Msg, State, Connection) -> @@ -1025,21 +1026,22 @@ cipher(internal, #certificate_verify{signature = Signature, %% client must send a next protocol message if we are expecting it cipher(internal, #finished{}, #state{static_env = #static_env{role = server}, - expecting_next_protocol_negotiation = true, - negotiated_protocol = undefined, negotiated_version = Version} = State0, + handshake_env = #handshake_env{expecting_next_protocol_negotiation = true, + negotiated_protocol = undefined}, + negotiated_version = Version} = State0, _Connection) -> handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, ?FUNCTION_NAME, State0); cipher(internal, #finished{verify_data = Data} = Finished, #state{static_env = #static_env{role = Role, host = Host, port = Port}, + handshake_env = #handshake_env{tls_handshake_history = Hist, + expecting_finished = true} = HsEnv, negotiated_version = Version, - expecting_finished = true, session = #session{master_secret = MasterSecret} = Session0, ssl_options = SslOpts, - connection_states = ConnectionStates0, - handshake_env = #handshake_env{tls_handshake_history = Hist}} = State, Connection) -> + connection_states = ConnectionStates0} = State, Connection) -> case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, opposite_role(Role), get_current_prf(ConnectionStates0, read), @@ -1047,7 +1049,7 @@ cipher(internal, #finished{verify_data = Data} = Finished, verified -> Session = handle_session(Role, SslOpts, Host, Port, Session0), cipher_role(Role, Data, Session, - State#state{expecting_finished = false}, Connection); + State#state{handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection); #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State) end; @@ -1055,19 +1057,19 @@ cipher(internal, #finished{verify_data = Data} = Finished, %% & before finished message and it is not allowed during renegotiation cipher(internal, #next_protocol{selected_protocol = SelectedProtocol}, #state{static_env = #static_env{role = server}, - expecting_next_protocol_negotiation = true, - expecting_finished = true} = State0, Connection) -> + handshake_env = #handshake_env{expecting_finished = true, + expecting_next_protocol_negotiation = true} = HsEnv} = State0, Connection) -> {Record, State} = - Connection:next_record(State0#state{negotiated_protocol = SelectedProtocol}), + Connection:next_record(State0), Connection:next_event(?FUNCTION_NAME, Record, - State#state{expecting_next_protocol_negotiation = false}); -cipher(internal, #change_cipher_spec{type = <<1>>}, #state{connection_states = ConnectionStates0} = + State#state{handshake_env = HsEnv#handshake_env{negotiated_protocol = SelectedProtocol, + expecting_next_protocol_negotiation = false}}); +cipher(internal, #change_cipher_spec{type = <<1>>}, #state{handshake_env = HsEnv, connection_states = ConnectionStates0} = State, Connection) -> ConnectionStates = ssl_record:activate_pending_connection_state(ConnectionStates0, read, Connection), - Connection:next_event(?FUNCTION_NAME, no_record, State#state{connection_states = - ConnectionStates, - expecting_finished = true}); + Connection:next_event(?FUNCTION_NAME, no_record, State#state{handshake_env = HsEnv#handshake_env{expecting_finished = true}, + connection_states = ConnectionStates}); cipher(Type, Msg, State, Connection) -> handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). @@ -1099,10 +1101,10 @@ connection({call, From}, {connection_information, false}, State, _) -> Info = connection_info(State), hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Info}}]); connection({call, From}, negotiated_protocol, - #state{negotiated_protocol = undefined} = State, _) -> + #state{handshake_env = #handshake_env{negotiated_protocol = undefined}} = State, _) -> hibernate_after(?FUNCTION_NAME, State, [{reply, From, {error, protocol_not_negotiated}}]); connection({call, From}, negotiated_protocol, - #state{negotiated_protocol = SelectedProtocol} = State, _) -> + #state{handshake_env = #handshake_env{negotiated_protocol = SelectedProtocol}} = State, _) -> hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, SelectedProtocol}}]); connection({call, From}, Msg, State, Connection) -> @@ -1154,14 +1156,14 @@ handle_common_event(internal, {handshake, {#hello_request{}, _}}, StateName, when StateName =/= connection -> keep_state_and_data; handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName, - #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv} = State0, + #state{handshake_env = #handshake_env{tls_handshake_history = Hist0}} = State0, Connection) -> PossibleSNI = Connection:select_sni_extension(Handshake), %% This function handles client SNI hello extension when Handshake is %% a client_hello, which needs to be determined by the connection callback. %% In other cases this is a noop - State = handle_sni_extension(PossibleSNI, State0), + State = #state{handshake_env = HsEnv} = handle_sni_extension(PossibleSNI, State0), Hist = ssl_handshake:update_handshake_history(Hist0, Raw), {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}, @@ -1323,8 +1325,8 @@ handle_info({'EXIT', Socket, normal}, _StateName, #state{static_env = #static_en handle_info({'EXIT', Socket, Reason}, _StateName, #state{static_env = #static_env{socket = Socket}} = State) -> {stop,{shutdown, Reason}, State}; -handle_info(allow_renegotiate, StateName, State) -> - {next_state, StateName, State#state{allow_renegotiate = true}}; +handle_info(allow_renegotiate, StateName, #state{handshake_env = HsEnv} = State) -> + {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{allow_renegotiate = true}}}; handle_info({cancel_start_or_recv, StartFrom}, StateName, #state{handshake_env = #handshake_env{renegotiation = {false, first}}} = State) when StateName =/= connection -> @@ -1433,7 +1435,7 @@ send_alert(Alert, _, #state{static_env = #static_env{protocol_cb = Connection}} Connection:send_alert(Alert, State). connection_info(#state{static_env = #static_env{protocol_cb = Connection}, - sni_hostname = SNIHostname, + handshake_env = #handshake_env{sni_hostname = SNIHostname}, session = #session{session_id = SessionId, cipher_suite = CipherSuite, ecc = ECCCurve}, negotiated_version = {_,_} = Version, @@ -1465,15 +1467,16 @@ security_info(#state{connection_states = ConnectionStates}) -> do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocols} = ServerHelloExt, #state{negotiated_version = Version, + handshake_env = HsEnv, session = #session{session_id = SessId}, connection_states = ConnectionStates0} = State0, Connection) when is_atom(Type) -> - + ServerHello = ssl_handshake:server_hello(SessId, ssl:tls_version(Version), ConnectionStates0, ServerHelloExt), State = server_hello(ServerHello, - State0#state{expecting_next_protocol_negotiation = - NextProtocols =/= undefined}, Connection), + State0#state{handshake_env = HsEnv#handshake_env{expecting_next_protocol_negotiation = + NextProtocols =/= undefined}}, Connection), case Type of new -> new_server_hello(ServerHello, State, Connection); @@ -2030,11 +2033,11 @@ finalize_handshake(State0, StateName, Connection) -> next_protocol(#state{static_env = #static_env{role = server}} = State, _) -> State; -next_protocol(#state{negotiated_protocol = undefined} = State, _) -> +next_protocol(#state{handshake_env = #handshake_env{negotiated_protocol = undefined}} = State, _) -> State; -next_protocol(#state{expecting_next_protocol_negotiation = false} = State, _) -> +next_protocol(#state{handshake_env = #handshake_env{expecting_next_protocol_negotiation = false}} = State, _) -> State; -next_protocol(#state{negotiated_protocol = NextProtocol} = State0, Connection) -> +next_protocol(#state{handshake_env = #handshake_env{negotiated_protocol = NextProtocol}} = State0, Connection) -> NextProtocolMessage = ssl_handshake:next_protocol(NextProtocol), Connection:queue_handshake(NextProtocolMessage, State0). @@ -2728,7 +2731,8 @@ invalidate_session(server, _, Port, Session) -> handle_sni_extension(undefined, State) -> State; -handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{role = Role} = InitStatEnv0} = State0) -> +handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{role = Role} = InitStatEnv0, + handshake_env = HsEnv} = State0) -> NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname), case NewOptions of undefined -> @@ -2755,8 +2759,8 @@ handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{ private_key = Key, diffie_hellman_params = DHParams, ssl_options = NewOptions, - sni_hostname = Hostname - } + handshake_env = HsEnv#handshake_env{sni_hostname = Hostname} + } end. update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) -> diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index a46407b27e..e55ef37b71 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -57,7 +57,15 @@ unprocessed_handshake_events = 0 :: integer(), tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout() | 'undefined', - renegotiation :: undefined | {boolean(), From::term() | internal | peer} + expecting_finished = false ::boolean(), + renegotiation :: undefined | {boolean(), From::term() | internal | peer}, + allow_renegotiate = true ::boolean(), + %% Ext handling + hello, %%:: #client_hello{} | #server_hello{} + sni_hostname = undefined, + expecting_next_protocol_negotiation = false ::boolean(), + next_protocol = undefined :: undefined | binary(), + negotiated_protocol }). -record(state, { @@ -68,7 +76,6 @@ ssl_options :: #ssl_options{}, socket_options :: #socket_options{}, session :: #session{} | secret_printout(), - allow_renegotiate = true ::boolean(), terminated = false ::boolean() | closed, negotiated_version :: ssl_record:ssl_version() | 'undefined', bytes_to_read :: undefined | integer(), %% bytes to read in passive mode @@ -95,12 +102,6 @@ premaster_secret :: binary() | secret_printout() | 'undefined', start_or_recv_from :: term(), timer :: undefined | reference(), % start_or_recive_timer - hello, %%:: #client_hello{} | #server_hello{}, - expecting_next_protocol_negotiation = false ::boolean(), - expecting_finished = false ::boolean(), - next_protocol = undefined :: undefined | binary(), - negotiated_protocol, - sni_hostname = undefined, flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake %% to when possible pack more than one TLS record into the %% underlaying packet format. Introduced by DTLS - RFC 4347. diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index cee69a05a5..fc9c3ba66a 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -513,15 +513,17 @@ error(_, _, _) -> %%-------------------------------------------------------------------- hello(internal, #client_hello{extensions = Extensions} = Hello, #state{ssl_options = #ssl_options{handshake = hello}, + handshake_env = HsEnv, start_or_recv_from = From} = State) -> {next_state, user_hello, State#state{start_or_recv_from = undefined, - hello = Hello}, + handshake_env = HsEnv#handshake_env{hello = Hello}}, [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]}; hello(internal, #server_hello{extensions = Extensions} = Hello, #state{ssl_options = #ssl_options{handshake = hello}, + handshake_env = HsEnv, start_or_recv_from = From} = State) -> {next_state, user_hello, State#state{start_or_recv_from = undefined, - hello = Hello}, + handshake_env = HsEnv#handshake_env{hello = Hello}}, [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]}; hello(internal, #client_hello{client_version = ClientVersion} = Hello, #state{connection_states = ConnectionStates0, @@ -529,9 +531,9 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, port = Port, session_cache = Cache, session_cache_cb = CacheCb}, - handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}, + negotiated_protocol = CurrentProtocol} = HsEnv, session = #session{own_certificate = Cert} = Session0, - negotiated_protocol = CurrentProtocol, key_algorithm = KeyExAlg, ssl_options = SslOpts} = State) -> case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, @@ -550,9 +552,10 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, State#state{connection_states = ConnectionStates, negotiated_version = Version, hashsign_algorithm = HashSign, - handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion}, - session = Session, - negotiated_protocol = Protocol}) + handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion, + negotiated_protocol = Protocol}, + session = Session + }) end; hello(internal, #server_hello{} = Hello, #state{connection_states = ConnectionStates0, @@ -677,8 +680,7 @@ connection(internal, #hello_request{}, = Hello#client_hello.session_id}}, Actions); connection(internal, #client_hello{} = Hello, #state{static_env = #static_env{role = server}, - handshake_env = HsEnv, - allow_renegotiate = true, + handshake_env = #handshake_env{allow_renegotiate = true}= HsEnv, connection_states = CS, protocol_specific = #{sender := Sender} } = State) -> @@ -690,14 +692,14 @@ connection(internal, #client_hello{} = Hello, erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate), {ok, Write} = tls_sender:renegotiate(Sender), next_event(hello, no_record, State#state{connection_states = CS#{current_write => Write}, - allow_renegotiate = false, - handshake_env = HsEnv#handshake_env{renegotiation = {true, peer}} + handshake_env = HsEnv#handshake_env{renegotiation = {true, peer}, + allow_renegotiate = false} }, [{next_event, internal, Hello}]); connection(internal, #client_hello{}, #state{static_env = #static_env{role = server, - protocol_cb = Connection}, - allow_renegotiate = false} = State0) -> + protocol_cb = Connection}, + handshake_env = #handshake_env{allow_renegotiate = false}} = State0) -> Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION), send_alert_in_connection(Alert, State0), State = Connection:reinit_handshake_data(State0), @@ -789,7 +791,8 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac static_env = InitStatEnv, handshake_env = #handshake_env{ tls_handshake_history = ssl_handshake:init_handshake_history(), - renegotiation = {false, first} + renegotiation = {false, first}, + allow_renegotiate = SSLOptions#ssl_options.client_renegotiation }, socket_options = SocketOptions, ssl_options = SSLOptions, @@ -798,7 +801,6 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac protocol_buffers = #protocol_buffers{}, user_application = {UserMonitor, User}, user_data_buffer = <<>>, - allow_renegotiate = SSLOptions#ssl_options.client_renegotiation, start_or_recv_from = undefined, flight_buffer = [], protocol_specific = #{sender => Sender, -- cgit v1.2.3 From 6d6a624193e319e5f3befdc11fd126e778d1a0e9 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 29 Jan 2019 10:02:22 +0100 Subject: ssl: Create connection_env --- lib/ssl/src/dtls_connection.erl | 2 +- lib/ssl/src/ssl_connection.erl | 69 +++++++++++++++++++++-------------------- lib/ssl/src/ssl_connection.hrl | 26 ++++++++++------ lib/ssl/src/tls_connection.erl | 2 +- 4 files changed, 54 insertions(+), 45 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index ac380f2595..178668e808 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -796,6 +796,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User, renegotiation = {false, first}, allow_renegotiate = SSLOptions#ssl_options.client_renegotiation }, + connection_env = #connection_env{user_application = {Monitor, User}}, socket_options = SocketOptions, %% We do not want to save the password in the state so that %% could be written in the clear into error logs. @@ -803,7 +804,6 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User, session = #session{is_resumable = new}, connection_states = ConnectionStates, protocol_buffers = #protocol_buffers{}, - user_application = {Monitor, User}, user_data_buffer = <<>>, start_or_recv_from = undefined, flight_buffer = new_flight(), diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 9d5b6efced..e048dba38d 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -366,8 +366,8 @@ handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = transport_cb = Transport, protocol_cb = Connection, tracker = Tracker}, - socket_options = Opts, - user_application = {_Mon, Pid}, + connection_env = #connection_env{user_application = {_Mon, Pid}}, + socket_options = Opts, start_or_recv_from = RecvFrom} = State) -> Pids = Connection:pids(State), alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection). @@ -380,9 +380,10 @@ handle_alert(#alert{level = ?FATAL} = Alert, StateName, tracker = Tracker, transport_cb = Transport, protocol_cb = Connection}, + connection_env = #connection_env{user_application = {_Mon, Pid}}, ssl_options = SslOpts, start_or_recv_from = From, - session = Session, user_application = {_Mon, Pid}, + session = Session, socket_options = Opts} = State) -> invalidate_session(Role, Host, Port, Session), log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), @@ -508,14 +509,15 @@ read_application_data( %% case get_data(SocketOpts0, BytesToRead, Buffer0) of {ok, ClientData, Buffer} -> % Send data - #state{ - static_env = - #static_env{ - socket = Socket, - protocol_cb = Connection, - transport_cb = Transport, - tracker = Tracker}, - user_application = {_Mon, Pid}} = State, + #state{static_env = + #static_env{ + socket = Socket, + protocol_cb = Connection, + transport_cb = Transport, + tracker = Tracker}, + connection_env = + #connection_env{user_application = {_Mon, Pid}}} + = State, SocketOpts = deliver_app_data( Connection:pids(State), @@ -530,30 +532,31 @@ read_application_data( {no_record, State#state{ user_data_buffer = Buffer, - start_or_recv_from = undefined, + start_or_recv_from = undefined, timer = undefined, bytes_to_read = undefined, socket_options = SocketOpts }}; true -> %% We have more data - read_application_data( - Buffer, State, SocketOpts, - undefined, undefined, undefined) + read_application_data( + Buffer, State, SocketOpts, + undefined, undefined, undefined) end; - {more, Buffer} -> % no reply, we need more data + {more, Buffer} -> % no reply, we need more data {no_record, State#state{user_data_buffer = Buffer}}; - {passive, Buffer} -> - {no_record, State#state{user_data_buffer = Buffer}}; - {error,_Reason} -> %% Invalid packet in packet mode - #state{ - static_env = - #static_env{ - socket = Socket, - protocol_cb = Connection, - transport_cb = Transport, - tracker = Tracker}, - user_application = {_Mon, Pid}} = State, - deliver_packet_error( + {passive, Buffer} -> + {no_record, State#state{user_data_buffer = Buffer}}; + {error,_Reason} -> %% Invalid packet in packet mode + #state{static_env = + #static_env{ + socket = Socket, + protocol_cb = Connection, + transport_cb = Transport, + tracker = Tracker}, + connection_env = + #connection_env{user_application = {_Mon, Pid}}} + = State, + deliver_packet_error( Connection:pids(State), Transport, Socket, SocketOpts0, Buffer0, Pid, RecvFrom, Tracker, Connection), {stop, {shutdown, normal}, State} @@ -1228,10 +1231,10 @@ handle_call({recv, N, Timeout}, RecvFrom, StateName, State, _) -> timer = Timer}, [{next_event, internal, {recv, RecvFrom}}]}; handle_call({new_user, User}, From, StateName, - State =#state{user_application = {OldMon, _}}, _) -> + State = #state{connection_env = #connection_env{user_application = {OldMon, _}} = CEnv}, _) -> NewMon = erlang:monitor(process, User), erlang:demonitor(OldMon, [flush]), - {next_state, StateName, State#state{user_application = {NewMon,User}}, + {next_state, StateName, State#state{connection_env = CEnv#connection_env{user_application = {NewMon, User}}}, [{reply, From, ok}]}; handle_call({get_opts, OptTags}, From, _, #state{static_env = #static_env{socket = Socket, @@ -1305,14 +1308,14 @@ handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_e {stop, {shutdown,normal}, State}; handle_info({'DOWN', MonitorRef, _, _, Reason}, _, - #state{user_application = {MonitorRef, _Pid}, + #state{connection_env = #connection_env{user_application = {MonitorRef, _Pid}}, ssl_options = #ssl_options{erl_dist = true}}) -> {stop, {shutdown, Reason}}; handle_info({'DOWN', MonitorRef, _, _, _}, _, - #state{user_application = {MonitorRef, _Pid}}) -> + #state{connection_env = #connection_env{user_application = {MonitorRef, _Pid}}}) -> {stop, {shutdown, normal}}; handle_info({'EXIT', Pid, _Reason}, StateName, - #state{user_application = {_MonitorRef, Pid}} = State) -> + #state{connection_env = #connection_env{user_application = {_MonitorRef, Pid}}} = State) -> %% It seems the user application has linked to us %% - ignore that and let the monitor handle this {next_state, StateName, State}; diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index e55ef37b71..f182783f54 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -68,26 +68,33 @@ negotiated_protocol }). +-record(connection_env, { + user_application :: {Monitor::reference(), User::pid()}, + + }). + -record(state, { static_env :: #static_env{}, handshake_env :: #handshake_env{} | secret_printout(), + connection_env :: #connection_env{}, + + %% Changed often + connection_states :: ssl_record:connection_states() | secret_printout(), + protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hr + user_data_buffer :: undefined | binary() | secret_printout(), + bytes_to_read :: undefined | integer(), %% bytes to read in passive mode + start_or_recv_from :: term(), + timer :: undefined | reference(), % start_or_recive_timer + %% Change seldome - user_application :: {Monitor::reference(), User::pid()}, ssl_options :: #ssl_options{}, socket_options :: #socket_options{}, session :: #session{} | secret_printout(), terminated = false ::boolean() | closed, negotiated_version :: ssl_record:ssl_version() | 'undefined', - bytes_to_read :: undefined | integer(), %% bytes to read in passive mode downgrade, - - %% Changed often - connection_states :: ssl_record:connection_states() | secret_printout(), - protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hr - user_data_buffer :: undefined | binary() | secret_printout(), %% Used only in HS - client_certificate_requested = false :: boolean(), key_algorithm :: ssl:key_algo(), hashsign_algorithm = {undefined, undefined}, @@ -100,8 +107,7 @@ srp_params :: #srp_user{} | secret_printout() | 'undefined', srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', premaster_secret :: binary() | secret_printout() | 'undefined', - start_or_recv_from :: term(), - timer :: undefined | reference(), % start_or_recive_timer + flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake %% to when possible pack more than one TLS record into the %% underlaying packet format. Introduced by DTLS - RFC 4347. diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index fc9c3ba66a..7c901c882b 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -794,12 +794,12 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac renegotiation = {false, first}, allow_renegotiate = SSLOptions#ssl_options.client_renegotiation }, + connection_env = #connection_env{user_application = {UserMonitor, User}}, socket_options = SocketOptions, ssl_options = SSLOptions, session = #session{is_resumable = new}, connection_states = ConnectionStates, protocol_buffers = #protocol_buffers{}, - user_application = {UserMonitor, User}, user_data_buffer = <<>>, start_or_recv_from = undefined, flight_buffer = [], -- cgit v1.2.3 From 94e43acfeb4d5d5e2f1944ef55ffa302cc901e1f Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 29 Jan 2019 11:49:26 +0100 Subject: ssl: Add downgrade handling to connection_env Remove duplicate handsake history handling form ssl_config function. Later we might refactor to avoid duplication in TLS and DTLS code, but handshake history does not belong in ssl_config function. --- lib/ssl/src/ssl_connection.erl | 58 ++++++++++++++++++------------------------ lib/ssl/src/ssl_connection.hrl | 5 ++-- lib/ssl/src/tls_connection.erl | 27 ++++++++++++-------- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index e048dba38d..f24b4d555a 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -607,11 +607,7 @@ handle_session(#server_hello{cipher_suite = CipherSuite, %%-------------------------------------------------------------------- -spec ssl_config(#ssl_options{}, client | server, #state{}) -> #state{}. %%-------------------------------------------------------------------- -ssl_config(Opts, Role, State) -> - ssl_config(Opts, Role, State, new). - -ssl_config(Opts, Role, #state{static_env = InitStatEnv0, - handshake_env = HsEnv} = State0, Type) -> +ssl_config(Opts, Role, #state{static_env = InitStatEnv0} = State0) -> {ok, #{cert_db_ref := Ref, cert_db_handle := CertDbHandle, fileref_db_handle := FileRefHandle, @@ -623,27 +619,19 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0, ssl_config:init(Opts, Role), TimeStamp = erlang:monotonic_time(), Session = State0#state.session, - - State = State0#state{session = Session#session{own_certificate = OwnCert, - time_stamp = TimeStamp}, - static_env = InitStatEnv0#static_env{ - file_ref_db = FileRefHandle, - cert_db_ref = Ref, - cert_db = CertDbHandle, - crl_db = CRLDbHandle, - session_cache = CacheHandle - }, - private_key = Key, - diffie_hellman_params = DHParams, - ssl_options = Opts}, - case Type of - new -> - Hist = ssl_handshake:init_handshake_history(), - State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}; - continue -> - State - end. - + + State0#state{session = Session#session{own_certificate = OwnCert, + time_stamp = TimeStamp}, + static_env = InitStatEnv0#static_env{ + file_ref_db = FileRefHandle, + cert_db_ref = Ref, + cert_db = CertDbHandle, + crl_db = CRLDbHandle, + session_cache = CacheHandle + }, + private_key = Key, + diffie_hellman_params = DHParams, + ssl_options = Opts}. %%==================================================================== %% gen_statem general state functions with connection cb argument @@ -715,7 +703,7 @@ user_hello({call, From}, {handshake_continue, NewOptions, Timeout}, ssl_options = Options0} = State0, _Connection) -> Timer = start_or_recv_cancel_timer(Timeout, RecvFrom), Options = ssl:handle_options(NewOptions, Options0#ssl_options{handshake = full}), - State = ssl_config(Options, Role, State0, continue), + State = ssl_config(Options, Role, State0), {next_state, hello, State#state{start_or_recv_from = From, timer = Timer}, [{next_event, internal, Hello}]}; @@ -1187,24 +1175,28 @@ handle_common_event(_Type, Msg, StateName, #state{negotiated_version = Version} handle_call({application_data, _Data}, _, _, _, _) -> %% In renegotiation priorities handshake, send data when handshake is finished {keep_state_and_data, [postpone]}; -handle_call({close, _} = Close, From, StateName, State, _Connection) -> +handle_call({close, _} = Close, From, StateName, #state{connection_env = CEnv} = State, _Connection) -> %% Run terminate before returning so that the reuseaddr %% inet-option works properly Result = terminate(Close, StateName, State), {stop_and_reply, {shutdown, normal}, - {reply, From, Result}, State#state{terminated = true}}; + {reply, From, Result}, State#state{connection_env = CEnv#connection_env{terminated = true}}}; handle_call({shutdown, read_write = How}, From, StateName, #state{static_env = #static_env{transport_cb = Transport, - socket = Socket}} = State, _) -> + socket = Socket}, + connection_env = CEnv} = State, _) -> try send_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), StateName, State) of _ -> case Transport:shutdown(Socket, How) of ok -> - {next_state, StateName, State#state{terminated = true}, [{reply, From, ok}]}; + {next_state, StateName, State#state{connection_env = + CEnv#connection_env{terminated = true}}, + [{reply, From, ok}]}; Error -> - {stop_and_reply, {shutdown, normal}, {reply, From, Error}, State#state{terminated = true}} + {stop_and_reply, {shutdown, normal}, {reply, From, Error}, + State#state{connection_env = CEnv#connection_env{terminated = true}}} end catch throw:Return -> @@ -1353,7 +1345,7 @@ handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, err %%==================================================================== %% general gen_statem callbacks %%==================================================================== -terminate(_, _, #state{terminated = true}) -> +terminate(_, _, #state{connection_env = #connection_env{terminated = true}}) -> %% Happens when user closes the connection using ssl:close/1 %% we want to guarantee that Transport:close has been called %% when ssl:close/1 returns unless it is a downgrade where diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index f182783f54..9d535cb1f2 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -70,7 +70,8 @@ -record(connection_env, { user_application :: {Monitor::reference(), User::pid()}, - + downgrade, + terminated = false ::boolean() | closed }). -record(state, { @@ -90,9 +91,7 @@ ssl_options :: #ssl_options{}, socket_options :: #socket_options{}, session :: #session{} | secret_printout(), - terminated = false ::boolean() | closed, negotiated_version :: ssl_record:ssl_version() | 'undefined', - downgrade, %% Used only in HS client_certificate_requested = false :: boolean(), diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 7c901c882b..2e9ae97da0 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -619,13 +619,16 @@ connection({call, From}, {user_renegotiate, WriteState}, [{next_event,{call, From}, renegotiate}]}; connection({call, From}, {close, {Pid, _Timeout}}, - #state{terminated = closed} = State) -> - {next_state, downgrade, State#state{terminated = true, downgrade = {Pid, From}}, + #state{connection_env = #connection_env{terminated = closed} =CEnv} = State) -> + {next_state, downgrade, State#state{connection_env = + CEnv#connection_env{terminated = true, + downgrade = {Pid, From}}}, [{next_event, internal, ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY)}]}; connection({call, From}, {close,{Pid, Timeout}}, #state{connection_states = ConnectionStates, - protocol_specific = #{sender := Sender} + protocol_specific = #{sender := Sender}, + connection_env = CEnv } = State0) -> case tls_sender:downgrade(Sender, Timeout) of {ok, Write} -> @@ -636,8 +639,10 @@ connection({call, From}, State = send_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), State0#state{connection_states = ConnectionStates#{current_write => Write}}), - {next_state, downgrade, State#state{downgrade = {Pid, From}, - terminated = true}, [{timeout, Timeout, downgrade}]}; + {next_state, downgrade, State#state{connection_env = + CEnv#connection_env{downgrade = {Pid, From}, + terminated = true}}, + [{timeout, Timeout, downgrade}]}; {error, timeout} -> {stop_and_reply, {shutdown, downgrade_fail}, [{reply, From, {error, timeout}}]} end; @@ -715,15 +720,16 @@ connection(Type, Event, State) -> downgrade(internal, #alert{description = ?CLOSE_NOTIFY}, #state{static_env = #static_env{transport_cb = Transport, socket = Socket}, - downgrade = {Pid, From}} = State) -> + connection_env = #connection_env{downgrade = {Pid, From}}} = State) -> tls_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]), Transport:controlling_process(Socket, Pid), {stop_and_reply, {shutdown, downgrade},[{reply, From, {ok, Socket}}], State}; -downgrade(timeout, downgrade, #state{downgrade = {_, From}} = State) -> +downgrade(timeout, downgrade, #state{ connection_env = #connection_env{downgrade = {_, From}}} = State) -> {stop_and_reply, {shutdown, normal},[{reply, From, {error, timeout}}], State}; downgrade(info, {CloseTag, Socket}, #state{static_env = #static_env{socket = Socket, - close_tag = CloseTag}, downgrade = {_, From}} = + close_tag = CloseTag}, + connection_env = #connection_env{downgrade = {_, From}}} = State) -> {stop_and_reply, {shutdown, normal},[{reply, From, {error, CloseTag}}], State}; downgrade(info, Info, State) -> @@ -924,12 +930,13 @@ handle_alerts([], Result) -> handle_alerts(_, {stop, _, _} = Stop) -> Stop; handle_alerts([#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} | _Alerts], - {next_state, connection = StateName, #state{user_data_buffer = Buffer, + {next_state, connection = StateName, #state{connection_env = CEnv, socket_options = #socket_options{active = false}, + user_data_buffer = Buffer, protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs}} = State}) when (Buffer =/= <<>>) orelse (CTs =/= []) -> - {next_state, StateName, State#state{terminated = true}}; + {next_state, StateName, State#state{connection_env = CEnv#connection_env{terminated = true}}}; handle_alerts([Alert | Alerts], {next_state, StateName, State}) -> handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)); handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) -> -- cgit v1.2.3 From 2b9412e026ab58bac5b61f239d607db6482974ef Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 29 Jan 2019 13:21:41 +0100 Subject: ssl: Add hashsign_algorithm and cert_hashsign_algorithm to handshake_env --- lib/ssl/src/dtls_connection.erl | 7 ++++--- lib/ssl/src/ssl_connection.erl | 38 ++++++++++++++++++++------------------ lib/ssl/src/ssl_connection.hrl | 9 ++++----- lib/ssl/src/tls_connection.erl | 7 ++++--- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 178668e808..86f79ed7e3 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -875,9 +875,10 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State = prepare_flight(State0#state{connection_states = ConnectionStates, negotiated_version = Version, - hashsign_algorithm = HashSign, - handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion, - negotiated_protocol = Protocol}, + handshake_env = HsEnv#handshake_env{ + hashsign_algorithm = HashSign, + client_hello_version = ClientVersion, + negotiated_protocol = Protocol}, session = Session}), ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt}, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index f24b4d555a..75edf2e42b 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -832,6 +832,7 @@ certify(internal, #certificate{} = Cert, end; certify(internal, #server_key_exchange{exchange_keys = Keys}, #state{static_env = #static_env{role = client}, + handshake_env = HsEnv, negotiated_version = Version, key_algorithm = Alg, public_key_info = PubKeyInfo, @@ -851,15 +852,15 @@ certify(internal, #server_key_exchange{exchange_keys = Keys}, case is_anonymous(Alg) of true -> calculate_secret(Params#server_key_params.params, - State#state{hashsign_algorithm = HashSign}, Connection); + State#state{handshake_env = HsEnv#handshake_env{hashsign_algorithm = HashSign}}, Connection); false -> case ssl_handshake:verify_server_key(Params, HashSign, ConnectionStates, ssl:tls_version(Version), PubKeyInfo) of true -> calculate_secret(Params#server_key_params.params, - State#state{hashsign_algorithm = HashSign, - session = session_handle_params(Params#server_key_params.params, Session)}, - Connection); + State#state{handshake_env = HsEnv#handshake_env{hashsign_algorithm = HashSign}, + session = session_handle_params(Params#server_key_params.params, Session)}, + Connection); false -> handle_own_alert(?ALERT_REC(?FATAL, ?DECRYPT_ERROR), Version, ?FUNCTION_NAME, State) @@ -883,8 +884,9 @@ certify(internal, #certificate_request{}, Connection:next_event(?FUNCTION_NAME, no_record, State#state{client_certificate_requested = true}); certify(internal, #certificate_request{} = CertRequest, #state{static_env = #static_env{role = client}, + handshake_env = HsEnv, session = #session{own_certificate = Cert}, - ssl_options = #ssl_options{signature_algs = SupportedHashSigns}, + ssl_options = #ssl_options{signature_algs = SupportedHashSigns}, negotiated_version = Version} = State, Connection) -> case ssl_handshake:select_hashsign(CertRequest, Cert, SupportedHashSigns, ssl:tls_version(Version)) of #alert {} = Alert -> @@ -892,7 +894,7 @@ certify(internal, #certificate_request{} = CertRequest, NegotiatedHashSign -> Connection:next_event(?FUNCTION_NAME, no_record, State#state{client_certificate_requested = true, - cert_hashsign_algorithm = NegotiatedHashSign}) + handshake_env = HsEnv#handshake_env{cert_hashsign_algorithm = NegotiatedHashSign}}) end; %% PSK and RSA_PSK might bypass the Server-Key-Exchange certify(internal, #server_hello_done{}, @@ -996,7 +998,7 @@ cipher(info, Msg, State, _) -> cipher(internal, #certificate_verify{signature = Signature, hashsign_algorithm = CertHashSign}, #state{static_env = #static_env{role = server}, - handshake_env = #handshake_env{tls_handshake_history = Hist}, + handshake_env = #handshake_env{tls_handshake_history = Hist} = HsEnv, key_algorithm = KexAlg, public_key_info = PublicKeyInfo, negotiated_version = Version, @@ -1010,7 +1012,7 @@ cipher(internal, #certificate_verify{signature = Signature, TLSVersion, HashSign, MasterSecret, Hist) of valid -> Connection:next_event(?FUNCTION_NAME, no_record, - State#state{cert_hashsign_algorithm = HashSign}); + State#state{handshake_env = HsEnv#handshake_env{cert_hashsign_algorithm = HashSign}}); #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State) end; @@ -1566,13 +1568,13 @@ certify_client(#state{client_certificate_requested = false} = State, _) -> State. verify_client_cert(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{tls_handshake_history = Hist}, + handshake_env = #handshake_env{tls_handshake_history = Hist, + cert_hashsign_algorithm = HashSign}, client_certificate_requested = true, negotiated_version = Version, private_key = PrivateKey, session = #session{master_secret = MasterSecret, - own_certificate = OwnCert}, - cert_hashsign_algorithm = HashSign} = State, Connection) -> + own_certificate = OwnCert}} = State, Connection) -> case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret, ssl:tls_version(Version), HashSign, PrivateKey, Hist) of @@ -1701,7 +1703,7 @@ certify_server(#state{static_env = #static_env{cert_db = CertDbHandle, key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa} = State,_) -> State; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, - hashsign_algorithm = HashSignAlgo, + handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, @@ -1729,7 +1731,7 @@ key_exchange(#state{static_env = #static_env{role = server}, State#state{diffie_hellman_keys = Key, session = Session#session{ecc = ECCurve}}; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, - hashsign_algorithm = HashSignAlgo, + handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, private_key = PrivateKey, session = #session{ecc = ECCCurve}, connection_states = ConnectionStates0, @@ -1755,7 +1757,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk State; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - hashsign_algorithm = HashSignAlgo, + handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version @@ -1772,7 +1774,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - hashsign_algorithm = HashSignAlgo, + handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, @@ -1793,7 +1795,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe State#state{diffie_hellman_keys = DHKeys}; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = ecdhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - hashsign_algorithm = HashSignAlgo, + handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, private_key = PrivateKey, session = #session{ecc = ECCCurve}, connection_states = ConnectionStates0, @@ -1817,7 +1819,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa State; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - hashsign_algorithm = HashSignAlgo, + handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version @@ -1834,7 +1836,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, ssl_options = #ssl_options{user_lookup_fun = LookupFun}, - hashsign_algorithm = HashSignAlgo, + handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, session = #session{srp_username = Username}, private_key = PrivateKey, connection_states = ConnectionStates0, diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 9d535cb1f2..e1a53c9982 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -65,7 +65,9 @@ sni_hostname = undefined, expecting_next_protocol_negotiation = false ::boolean(), next_protocol = undefined :: undefined | binary(), - negotiated_protocol + negotiated_protocol, + hashsign_algorithm = {undefined, undefined}, + cert_hashsign_algorithm = {undefined, undefined} }). -record(connection_env, { @@ -96,8 +98,6 @@ %% Used only in HS client_certificate_requested = false :: boolean(), key_algorithm :: ssl:key_algo(), - hashsign_algorithm = {undefined, undefined}, - cert_hashsign_algorithm = {undefined, undefined}, public_key_info :: ssl_handshake:public_key_info() | 'undefined', private_key :: public_key:private_key() | secret_printout() | 'undefined', diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), @@ -105,8 +105,7 @@ psk_identity :: binary() | 'undefined', % server psk identity hint srp_params :: #srp_user{} | secret_printout() | 'undefined', srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', - premaster_secret :: binary() | secret_printout() | 'undefined', - + premaster_secret :: binary() | secret_printout() | 'undefined', flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake %% to when possible pack more than one TLS record into the %% underlaying packet format. Introduced by DTLS - RFC 4347. diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 2e9ae97da0..684910db10 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -551,9 +551,10 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, gen_handshake(?FUNCTION_NAME, internal, {common_client_hello, Type, ServerHelloExt}, State#state{connection_states = ConnectionStates, negotiated_version = Version, - hashsign_algorithm = HashSign, - handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion, - negotiated_protocol = Protocol}, + handshake_env = HsEnv#handshake_env{ + hashsign_algorithm = HashSign, + client_hello_version = ClientVersion, + negotiated_protocol = Protocol}, session = Session }) end; -- cgit v1.2.3 From e8ccff6724b8bd82f4eddb6255a059b10a787722 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 29 Jan 2019 15:12:41 +0100 Subject: ssl: Add key exchange items to handshake_env --- lib/ssl/src/dtls_connection.erl | 4 ++-- lib/ssl/src/ssl_connection.erl | 26 +++++++++++++------------- lib/ssl/src/ssl_connection.hrl | 5 +++-- lib/ssl/src/tls_connection.erl | 4 ++-- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 86f79ed7e3..a11e0a0ac6 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -338,8 +338,8 @@ reinit(State) -> reinit_handshake_data(#state{protocol_buffers = Buffers, handshake_env = HsEnv} = State) -> State#state{premaster_secret = undefined, - public_key_info = undefined, - handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history()}, + handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(), + public_key_info = undefined}, flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, flight_buffer = new_flight(), protocol_buffers = diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 75edf2e42b..ea6c6f3461 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -832,10 +832,9 @@ certify(internal, #certificate{} = Cert, end; certify(internal, #server_key_exchange{exchange_keys = Keys}, #state{static_env = #static_env{role = client}, - handshake_env = HsEnv, + handshake_env = #handshake_env{public_key_info = PubKeyInfo} = HsEnv, negotiated_version = Version, key_algorithm = Alg, - public_key_info = PubKeyInfo, session = Session, connection_states = ConnectionStates} = State, Connection) when Alg == dhe_dss; Alg == dhe_rsa; @@ -998,17 +997,17 @@ cipher(info, Msg, State, _) -> cipher(internal, #certificate_verify{signature = Signature, hashsign_algorithm = CertHashSign}, #state{static_env = #static_env{role = server}, - handshake_env = #handshake_env{tls_handshake_history = Hist} = HsEnv, + handshake_env = #handshake_env{tls_handshake_history = Hist, + public_key_info = PubKeyInfo} = HsEnv, key_algorithm = KexAlg, - public_key_info = PublicKeyInfo, negotiated_version = Version, session = #session{master_secret = MasterSecret} } = State, Connection) -> TLSVersion = ssl:tls_version(Version), %% Use negotiated value if TLS-1.2 otherwhise return default - HashSign = negotiated_hashsign(CertHashSign, KexAlg, PublicKeyInfo, TLSVersion), - case ssl_handshake:certificate_verify(Signature, PublicKeyInfo, + HashSign = negotiated_hashsign(CertHashSign, KexAlg, PubKeyInfo, TLSVersion), + case ssl_handshake:certificate_verify(Signature, PubKeyInfo, TLSVersion, HashSign, MasterSecret, Hist) of valid -> Connection:next_event(?FUNCTION_NAME, no_record, @@ -1526,11 +1525,12 @@ server_hello_done(State, Connection) -> Connection:send_handshake(HelloDone, State). handle_peer_cert(Role, PeerCert, PublicKeyInfo, - #state{session = #session{cipher_suite = CipherSuite} = Session} = State0, + #state{handshake_env = HsEnv, + session = #session{cipher_suite = CipherSuite} = Session} = State0, Connection) -> - State1 = State0#state{session = - Session#session{peer_certificate = PeerCert}, - public_key_info = PublicKeyInfo}, + State1 = State0#state{handshake_env = HsEnv#handshake_env{public_key_info = PublicKeyInfo}, + session = + Session#session{peer_certificate = PeerCert}}, #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_definition(CipherSuite), State = handle_peer_cert_key(Role, PeerCert, PublicKeyInfo, KeyAlgorithm, State1), Connection:next_event(certify, no_record, State). @@ -1865,8 +1865,8 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Alg State#state{srp_params = SrpParams, srp_keys = Keys}; key_exchange(#state{static_env = #static_env{role = client}, - key_algorithm = rsa, - public_key_info = PublicKeyInfo, + handshake_env = #handshake_env{public_key_info = PublicKeyInfo}, + key_algorithm = rsa, negotiated_version = Version, premaster_secret = PremasterSecret} = State0, Connection) -> Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo), @@ -1920,9 +1920,9 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{public_key_info = PublicKeyInfo}, ssl_options = SslOpts, key_algorithm = rsa_psk, - public_key_info = PublicKeyInfo, negotiated_version = Version, premaster_secret = PremasterSecret} = State0, Connection) -> diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index e1a53c9982..6610d79c60 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -67,7 +67,9 @@ next_protocol = undefined :: undefined | binary(), negotiated_protocol, hashsign_algorithm = {undefined, undefined}, - cert_hashsign_algorithm = {undefined, undefined} + cert_hashsign_algorithm = {undefined, undefined}, + %% key exchange + public_key_info :: ssl_handshake:public_key_info() | 'undefined' }). -record(connection_env, { @@ -98,7 +100,6 @@ %% Used only in HS client_certificate_requested = false :: boolean(), key_algorithm :: ssl:key_algo(), - public_key_info :: ssl_handshake:public_key_info() | 'undefined', private_key :: public_key:private_key() | secret_printout() | 'undefined', diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 684910db10..fd60ca0cf8 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -348,8 +348,8 @@ reinit_handshake_data(#state{handshake_env = HsEnv} =State) -> %% To reduce memory foot print of a connection reinitialize them. State#state{ premaster_secret = undefined, - public_key_info = undefined, - handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history()} + handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(), + public_key_info = undefined} }. select_sni_extension(#client_hello{extensions = HelloExtensions}) -> -- cgit v1.2.3 From d689e8a2ea3557a6b7fed2f109a3a4554806a699 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 29 Jan 2019 19:22:26 +0100 Subject: ssl: Add negotiated_version to connection_env --- lib/ssl/src/dtls_connection.erl | 66 ++++++++++--------- lib/ssl/src/ssl_connection.erl | 141 ++++++++++++++++++++-------------------- lib/ssl/src/ssl_connection.hrl | 6 +- lib/ssl/src/tls_connection.erl | 56 ++++++++-------- 4 files changed, 136 insertions(+), 133 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index a11e0a0ac6..88c4d92bab 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -251,7 +251,7 @@ handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data}, StateName, #state{protocol_buffers = Buffers0, - negotiated_version = Version} = State) -> + connection_env = #connection_env{negotiated_version = Version}} = State) -> try case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0) of {[], Buffers} -> @@ -273,7 +273,7 @@ handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, St {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]}; %%% DTLS record protocol level Alert messages handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName, - #state{negotiated_version = Version} = State) -> + #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> case decode_alerts(EncAlerts) of Alerts = [_|_] -> handle_alerts(Alerts, {next_state, StateName, State}); @@ -305,7 +305,7 @@ send_handshake(Handshake, #state{connection_states = ConnectionStates} = State) send_handshake_flight(queue_handshake(Handshake, State), Epoch). queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, flight_buffer = #{handshakes := HsBuffer0, change_cipher_spec := undefined, next_sequence := Seq} = Flight0} = State) -> @@ -316,7 +316,7 @@ queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_ handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}; queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0, next_sequence := Seq} = Flight0} = State) -> Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq), @@ -364,9 +364,9 @@ empty_connection_state(ConnectionEnd, BeastMitigation) -> encode_alert(#alert{} = Alert, Version, ConnectionStates) -> dtls_record:encode_alert_record(Alert, Version, ConnectionStates). -send_alert(Alert, #state{negotiated_version = Version, - static_env = #static_env{socket = Socket, +send_alert(Alert, #state{static_env = #static_env{socket = Socket, transport_cb = Transport}, + connection_env = #connection_env{negotiated_version = Version}, connection_states = ConnectionStates0} = State0) -> {BinMsg, ConnectionStates} = encode_alert(Alert, Version, ConnectionStates0), @@ -424,6 +424,7 @@ init({call, From}, {start, Timeout}, session_cache = Cache, session_cache_cb = CacheCb}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, + connection_env = CEnv, ssl_options = SslOpts, session = #session{own_certificate = Cert} = Session0, connection_states = ConnectionStates0 @@ -434,15 +435,14 @@ init({call, From}, {start, Timeout}, Version = Hello#client_hello.client_version, HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions), - State1 = prepare_flight(State0#state{negotiated_version = Version}), - {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}), - State3 = State2#state{negotiated_version = Version, %% Requested version + State1 = prepare_flight(State0#state{connection_env = CEnv#connection_env{negotiated_version = Version}}), + {State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}), + State3 = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% RequestedVersion session = Session0#session{session_id = Hello#client_hello.session_id}, start_or_recv_from = From, timer = Timer, - flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT} - }, + flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}}, {Record, State} = next_record(State3), next_event(hello, Record, State, Actions); init({call, _} = Type, Event, #state{static_env = #static_env{role = server, @@ -494,6 +494,7 @@ hello(internal, #client_hello{cookie = <<>>, transport_cb = Transport, socket = Socket}, handshake_env = HsEnv, + connection_env = CEnv, protocol_specific = #{current_cookie_secret := Secret}} = State0) -> {ok, {IP, Port}} = dtls_socket:peername(Transport, Socket), Cookie = dtls_handshake:cookie(Secret, IP, Port, Hello), @@ -504,7 +505,7 @@ hello(internal, #client_hello{cookie = <<>>, %% version 1.0 regardless of the version of TLS that is expected to be %% negotiated. VerifyRequest = dtls_handshake:hello_verify_request(Cookie, ?HELLO_VERIFY_REQUEST_VERSION), - State1 = prepare_flight(State0#state{negotiated_version = Version}), + State1 = prepare_flight(State0#state{connection_env = CEnv#connection_env{negotiated_version = Version}}), {State2, Actions} = send_handshake(VerifyRequest, State1), {Record, State} = next_record(State2), next_event(?FUNCTION_NAME, Record, @@ -518,6 +519,7 @@ hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #sta session_cache = Cache, session_cache_cb = CacheCb}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, + connection_env = CEnv, ssl_options = SslOpts, session = #session{own_certificate = OwnCert} = Session0, @@ -533,7 +535,7 @@ hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #sta = ssl_handshake:init_handshake_history()}}), {State2, Actions} = send_handshake(Hello, State1), - State = State2#state{negotiated_version = Version, %% Requested version + State = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% Requested version session = Session0#session{session_id = Hello#client_hello.session_id}}, @@ -576,8 +578,8 @@ hello(internal, #server_hello{} = Hello, #state{ static_env = #static_env{role = client}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, + connection_env = #connection_env{negotiated_version = ReqVersion}, connection_states = ConnectionStates0, - negotiated_version = ReqVersion, ssl_options = SslOptions} = State) -> case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of #alert{} = Alert -> @@ -692,8 +694,8 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho session_cache_cb = CacheCb }, handshake_env = #handshake_env{ renegotiation = {Renegotiation, _}}, + connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, - ssl_options = SslOpts, connection_states = ConnectionStates0 } = State0) -> @@ -703,7 +705,7 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho Version = Hello#client_hello.client_version, HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions), State1 = prepare_flight(State0), - {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}), + {State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}), {Record, State} = next_record( State2#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, @@ -827,7 +829,7 @@ next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{ acceptable_record_versions(hello, _) -> [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_DATAGRAM_SUPPORTED_VERSIONS]; -acceptable_record_versions(_, #state{negotiated_version = Version}) -> +acceptable_record_versions(_, #state{connection_env = #connection_env{negotiated_version = Version}}) -> [Version]. dtls_handshake_events(Packets) -> @@ -846,8 +848,9 @@ decode_cipher_text(#state{protocol_buffers = #protocol_buffers{dtls_cipher_texts {Alert, State} end. -dtls_version(hello, Version, #state{static_env = #static_env{role = server}} = State) -> - State#state{negotiated_version = Version}; %%Inital version +dtls_version(hello, Version, #state{static_env = #static_env{role = server}, + connection_env = CEnv} = State) -> + State#state{connection_env = CEnv#connection_env{negotiated_version = Version}}; %%Inital version dtls_version(_,_, State) -> State. @@ -858,6 +861,7 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, session_cache_cb = CacheCb}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}, negotiated_protocol = CurrentProtocol} = HsEnv, + connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, key_algorithm = KeyExAlg, ssl_options = SslOpts} = State0) -> @@ -874,7 +878,7 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, end, State = prepare_flight(State0#state{connection_states = ConnectionStates, - negotiated_version = Version, + connection_env = CEnv#connection_env{negotiated_version = Version}, handshake_env = HsEnv#handshake_env{ hashsign_algorithm = HashSign, client_hello_version = ClientVersion, @@ -899,9 +903,9 @@ handle_info({Protocol, _, _, _, Data}, StateName, handle_info({CloseTag, Socket}, StateName, #state{static_env = #static_env{socket = Socket, close_tag = CloseTag}, + connection_env = #connection_env{negotiated_version = Version}, socket_options = #socket_options{active = Active}, - protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs}, - negotiated_version = Version} = State) -> + protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs}} = State) -> %% Note that as of DTLS 1.2 (TLS 1.1), %% failure to properly close a connection no longer requires that a %% session not be resumed. This is a change from DTLS 1.0 to conform @@ -979,7 +983,7 @@ decode_alerts(Bin) -> ssl_alert:decode(Bin). gen_handshake(StateName, Type, Event, - #state{negotiated_version = Version} = State) -> + #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> try ssl_connection:StateName(Type, Event, State, ?MODULE) of Result -> Result @@ -990,7 +994,7 @@ gen_handshake(StateName, Type, Event, Version, StateName, State) end. -gen_info(Event, connection = StateName, #state{negotiated_version = Version} = State) -> +gen_info(Event, connection = StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> try handle_info(Event, StateName, State) of Result -> Result @@ -1001,7 +1005,7 @@ gen_info(Event, connection = StateName, #state{negotiated_version = Version} = Version, StateName, State) end; -gen_info(Event, StateName, #state{negotiated_version = Version} = State) -> +gen_info(Event, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> try handle_info(Event, StateName, State) of Result -> Result @@ -1065,9 +1069,9 @@ new_timeout(_) -> send_handshake_flight(#state{static_env = #static_env{socket = Socket, transport_cb = Transport}, - flight_buffer = #{handshakes := Flight, + connection_env = #connection_env{negotiated_version = Version}, + flight_buffer = #{handshakes := Flight, change_cipher_spec := undefined}, - negotiated_version = Version, connection_states = ConnectionStates0} = State0, Epoch) -> %% TODO remove hardcoded Max size {Encoded, ConnectionStates} = @@ -1077,10 +1081,10 @@ send_handshake_flight(#state{static_env = #static_env{socket = Socket, send_handshake_flight(#state{static_env = #static_env{socket = Socket, transport_cb = Transport}, + connection_env = #connection_env{negotiated_version = Version}, flight_buffer = #{handshakes := [_|_] = Flight0, change_cipher_spec := ChangeCipher, handshakes_after_change_cipher_spec := []}, - negotiated_version = Version, connection_states = ConnectionStates0} = State0, Epoch) -> {HsBefore, ConnectionStates1} = encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch, ConnectionStates0), @@ -1091,10 +1095,10 @@ send_handshake_flight(#state{static_env = #static_env{socket = Socket, send_handshake_flight(#state{static_env = #static_env{socket = Socket, transport_cb = Transport}, + connection_env = #connection_env{negotiated_version = Version}, flight_buffer = #{handshakes := [_|_] = Flight0, change_cipher_spec := ChangeCipher, handshakes_after_change_cipher_spec := Flight1}, - negotiated_version = Version, connection_states = ConnectionStates0} = State0, Epoch) -> {HsBefore, ConnectionStates1} = encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch-1, ConnectionStates0), @@ -1107,10 +1111,10 @@ send_handshake_flight(#state{static_env = #static_env{socket = Socket, send_handshake_flight(#state{static_env = #static_env{socket = Socket, transport_cb = Transport}, + connection_env = #connection_env{negotiated_version = Version}, flight_buffer = #{handshakes := [], change_cipher_spec := ChangeCipher, handshakes_after_change_cipher_spec := Flight1}, - negotiated_version = Version, connection_states = ConnectionStates0} = State0, Epoch) -> {EncChangeCipher, ConnectionStates1} = encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates0), @@ -1166,8 +1170,8 @@ send_application_data(Data, From, _StateName, #state{static_env = #static_env{socket = Socket, protocol_cb = Connection, transport_cb = Transport}, + connection_env = #connection_env{negotiated_version = Version}, handshake_env = HsEnv, - negotiated_version = Version, connection_states = ConnectionStates0, ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State0) -> diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index ea6c6f3461..99d429511a 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -574,8 +574,8 @@ handle_session(#server_hello{cipher_suite = CipherSuite, compression_method = Compression}, Version, NewId, ConnectionStates, ProtoExt, Protocol0, #state{session = #session{session_id = OldId}, - negotiated_version = ReqVersion, - handshake_env = #handshake_env{negotiated_protocol = CurrentProtocol} = HsEnv} = State0) -> + handshake_env = #handshake_env{negotiated_protocol = CurrentProtocol} = HsEnv, + connection_env = #connection_env{negotiated_version = ReqVersion} = CEnv} = State0) -> #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_definition(CipherSuite), @@ -589,11 +589,11 @@ handle_session(#server_hello{cipher_suite = CipherSuite, end, State = State0#state{key_algorithm = KeyAlgorithm, - negotiated_version = Version, connection_states = ConnectionStates, premaster_secret = PremasterSecret, handshake_env = HsEnv#handshake_env{expecting_next_protocol_negotiation = ExpectNPN, - negotiated_protocol = Protocol}}, + negotiated_protocol = Protocol}, + connection_env = CEnv#connection_env{negotiated_version = Version}}, case ssl_session:is_new(OldId, NewId) of true -> @@ -692,7 +692,7 @@ hello(info, Msg, State, _) -> hello(Type, Msg, State, Connection) -> handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). -user_hello({call, From}, cancel, #state{negotiated_version = Version} = State, _) -> +user_hello({call, From}, cancel, #state{connection_env = #connection_env{negotiated_version = Version}} = State, _) -> gen_statem:reply(From, ok), handle_own_alert(?ALERT_REC(?FATAL, ?USER_CANCELED, user_canceled), Version, ?FUNCTION_NAME, State); @@ -722,7 +722,7 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, #state{static_env = #static_env{role = server}, handshake_env = #handshake_env{tls_handshake_history = Hist, expecting_finished = true} = HsEnv, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = State0, Connection) -> @@ -741,8 +741,8 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, abbreviated(internal, #finished{verify_data = Data} = Finished, #state{static_env = #static_env{role = client}, handshake_env = #handshake_env{tls_handshake_history = Hist0}, + connection_env = #connection_env{negotiated_version = Version}, session = #session{master_secret = MasterSecret}, - negotiated_version = Version, connection_states = ConnectionStates0} = State0, Connection) -> case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, server, get_pending_prf(ConnectionStates0, write), @@ -794,7 +794,7 @@ certify(info, Msg, State, _) -> handle_info(Msg, ?FUNCTION_NAME, State); certify(internal, #certificate{asn1_certificates = []}, #state{static_env = #static_env{role = server}, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = #ssl_options{verify = verify_peer, fail_if_no_peer_cert = true}} = State, _) -> @@ -808,7 +808,7 @@ certify(internal, #certificate{asn1_certificates = []}, Connection:next_event(?FUNCTION_NAME, no_record, State0#state{client_certificate_requested = false}); certify(internal, #certificate{}, #state{static_env = #static_env{role = server}, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = #ssl_options{verify = verify_none}} = State, _) -> Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, unrequested_certificate), @@ -820,7 +820,7 @@ certify(internal, #certificate{} = Cert, cert_db = CertDbHandle, cert_db_ref = CertDbRef, crl_db = CRLDbInfo}, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = Opts} = State, Connection) -> case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef, Opts, CRLDbInfo, Role, Host) of @@ -833,7 +833,7 @@ certify(internal, #certificate{} = Cert, certify(internal, #server_key_exchange{exchange_keys = Keys}, #state{static_env = #static_env{role = client}, handshake_env = #handshake_env{public_key_info = PubKeyInfo} = HsEnv, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, key_algorithm = Alg, session = Session, connection_states = ConnectionStates} = State, Connection) @@ -867,7 +867,7 @@ certify(internal, #server_key_exchange{exchange_keys = Keys}, end; certify(internal, #certificate_request{}, #state{static_env = #static_env{role = client}, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, key_algorithm = Alg} = State, _) when Alg == dh_anon; Alg == ecdh_anon; Alg == psk; Alg == dhe_psk; Alg == ecdhe_psk; Alg == rsa_psk; @@ -884,9 +884,9 @@ certify(internal, #certificate_request{}, certify(internal, #certificate_request{} = CertRequest, #state{static_env = #static_env{role = client}, handshake_env = HsEnv, + connection_env = #connection_env{negotiated_version = Version}, session = #session{own_certificate = Cert}, - ssl_options = #ssl_options{signature_algs = SupportedHashSigns}, - negotiated_version = Version} = State, Connection) -> + ssl_options = #ssl_options{signature_algs = SupportedHashSigns}} = State, Connection) -> case ssl_handshake:select_hashsign(CertRequest, Cert, SupportedHashSigns, ssl:tls_version(Version)) of #alert {} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State); @@ -899,7 +899,7 @@ certify(internal, #certificate_request{} = CertRequest, certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, session = #session{master_secret = undefined}, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, psk_identity = PSKIdentity, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, premaster_secret = undefined, @@ -915,12 +915,12 @@ certify(internal, #server_hello_done{}, end; certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, + connection_env = #connection_env{negotiated_version = {Major, Minor}} = Version, session = #session{master_secret = undefined}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, - negotiated_version = {Major, Minor} = Version, - psk_identity = PSKIdentity, - premaster_secret = undefined, - key_algorithm = Alg} = State0, Connection) + psk_identity = PSKIdentity, + premaster_secret = undefined, + key_algorithm = Alg} = State0, Connection) when Alg == rsa_psk -> Rand = ssl_cipher:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), RSAPremasterSecret = <>, @@ -936,9 +936,9 @@ certify(internal, #server_hello_done{}, %% Master secret was determined with help of server-key exchange msg certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, - session = #session{master_secret = MasterSecret} = Session, + connection_env = #connection_env{negotiated_version = Version}, + session = #session{master_secret = MasterSecret} = Session, connection_states = ConnectionStates0, - negotiated_version = Version, premaster_secret = undefined} = State0, Connection) -> case ssl_handshake:master_secret(ssl:tls_version(Version), Session, ConnectionStates0, client) of @@ -951,9 +951,9 @@ certify(internal, #server_hello_done{}, %% Master secret is calculated from premaster_secret certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, + connection_env = #connection_env{negotiated_version = Version}, session = Session0, connection_states = ConnectionStates0, - negotiated_version = Version, premaster_secret = PremasterSecret} = State0, Connection) -> case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret, ConnectionStates0, client) of @@ -973,7 +973,8 @@ certify(internal = Type, #client_key_exchange{} = Msg, %% We expect a certificate here handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection); certify(internal, #client_key_exchange{exchange_keys = Keys}, - State = #state{key_algorithm = KeyAlg, negotiated_version = Version}, Connection) -> + State = #state{key_algorithm = KeyAlg, + connection_env = #connection_env{negotiated_version = Version}}, Connection) -> try certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, ssl:tls_version(Version)), State, Connection) @@ -999,8 +1000,8 @@ cipher(internal, #certificate_verify{signature = Signature, #state{static_env = #static_env{role = server}, handshake_env = #handshake_env{tls_handshake_history = Hist, public_key_info = PubKeyInfo} = HsEnv, + connection_env = #connection_env{negotiated_version = Version}, key_algorithm = KexAlg, - negotiated_version = Version, session = #session{master_secret = MasterSecret} } = State, Connection) -> @@ -1020,7 +1021,7 @@ cipher(internal, #finished{}, #state{static_env = #static_env{role = server}, handshake_env = #handshake_env{expecting_next_protocol_negotiation = true, negotiated_protocol = undefined}, - negotiated_version = Version} = State0, + connection_env = #connection_env{negotiated_version = Version}} = State0, _Connection) -> handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, ?FUNCTION_NAME, State0); cipher(internal, #finished{verify_data = Data} = Finished, @@ -1029,7 +1030,7 @@ cipher(internal, #finished{verify_data = Data} = Finished, port = Port}, handshake_env = #handshake_env{tls_handshake_history = Hist, expecting_finished = true} = HsEnv, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, session = #session{master_secret = MasterSecret} = Session0, ssl_options = SslOpts, @@ -1165,10 +1166,10 @@ handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName, Sta handle_common_event(timeout, hibernate, _, _, _) -> {keep_state_and_data, [hibernate]}; handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName, - #state{negotiated_version = Version} = State, _) -> + #state{connection_env = #connection_env{negotiated_version = Version}} = State, _) -> handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version, StateName, State); -handle_common_event(_Type, Msg, StateName, #state{negotiated_version = Version} = State, +handle_common_event(_Type, Msg, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State, _) -> Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, {unexpected_msg, Msg}), handle_own_alert(Alert, Version, StateName, State). @@ -1253,7 +1254,7 @@ handle_call(get_sslsocket, From, _StateName, State, Connection) -> handle_call({prf, Secret, Label, Seed, WantedLength}, From, _, #state{connection_states = ConnectionStates, - negotiated_version = Version}, _) -> + connection_env = #connection_env{negotiated_version = Version}}, _) -> #{security_parameters := SecParams} = ssl_record:current_connection_state(ConnectionStates, read), #security_parameters{master_secret = MasterSecret, @@ -1434,7 +1435,7 @@ connection_info(#state{static_env = #static_env{protocol_cb = Connection}, handshake_env = #handshake_env{sni_hostname = SNIHostname}, session = #session{session_id = SessionId, cipher_suite = CipherSuite, ecc = ECCCurve}, - negotiated_version = {_,_} = Version, + connection_env = #connection_env{negotiated_version = {_,_} = Version}, ssl_options = Opts}) -> RecordCB = record_cb(Connection), CipherSuiteDef = #{key_exchange := KexAlg} = ssl_cipher_format:suite_definition(CipherSuite), @@ -1462,7 +1463,7 @@ security_info(#state{connection_states = ConnectionStates}) -> do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocols} = ServerHelloExt, - #state{negotiated_version = Version, + #state{connection_env = #connection_env{negotiated_version = Version}, handshake_env = HsEnv, session = #session{session_id = SessId}, connection_states = ConnectionStates0} @@ -1483,8 +1484,8 @@ do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocol new_server_hello(#server_hello{cipher_suite = CipherSuite, compression_method = Compression, session_id = SessionId}, - #state{session = Session0, - negotiated_version = Version} = State0, Connection) -> + #state{session = Session0, + connection_env = #connection_env{negotiated_version = Version}} = State0, Connection) -> try server_certify_and_key_exchange(State0, Connection) of #state{} = State1 -> {State, Actions} = server_hello_done(State1, Connection), @@ -1500,7 +1501,7 @@ new_server_hello(#server_hello{cipher_suite = CipherSuite, resumed_server_hello(#state{session = Session, connection_states = ConnectionStates0, - negotiated_version = Version} = State0, Connection) -> + connection_env = #connection_env{negotiated_version = Version}} = State0, Connection) -> case ssl_handshake:master_secret(ssl:tls_version(Version), Session, ConnectionStates0, server) of @@ -1570,8 +1571,8 @@ certify_client(#state{client_certificate_requested = false} = State, _) -> verify_client_cert(#state{static_env = #static_env{role = client}, handshake_env = #handshake_env{tls_handshake_history = Hist, cert_hashsign_algorithm = HashSign}, + connection_env = #connection_env{negotiated_version = Version}, client_certificate_requested = true, - negotiated_version = Version, private_key = PrivateKey, session = #session{master_secret = MasterSecret, own_certificate = OwnCert}} = State, Connection) -> @@ -1588,7 +1589,7 @@ verify_client_cert(#state{static_env = #static_env{role = client}, verify_client_cert(#state{client_certificate_requested = false} = State, _) -> State. -client_certify_and_key_exchange(#state{negotiated_version = Version} = +client_certify_and_key_exchange(#state{connection_env = #connection_env{negotiated_version = Version}} = State0, Connection) -> try do_client_certify_and_key_exchange(State0, Connection) of State1 = #state{} -> @@ -1704,11 +1705,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa State; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + connection_env = #connection_env{negotiated_version = Version}, diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, - connection_states = ConnectionStates0, - negotiated_version = Version - } = State0, Connection) + connection_states = ConnectionStates0} = State0, Connection) when Algo == dhe_dss; Algo == dhe_rsa; Algo == dh_anon -> @@ -1732,11 +1732,10 @@ key_exchange(#state{static_env = #static_env{role = server}, session = Session#session{ecc = ECCurve}}; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + connection_env = #connection_env{negotiated_version = Version}, private_key = PrivateKey, session = #session{ecc = ECCCurve}, - connection_states = ConnectionStates0, - negotiated_version = Version - } = State0, Connection) + connection_states = ConnectionStates0} = State0, Connection) when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa; Algo == ecdh_anon -> @@ -1758,10 +1757,9 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + connection_env = #connection_env{negotiated_version = Version}, private_key = PrivateKey, - connection_states = ConnectionStates0, - negotiated_version = Version - } = State0, Connection) -> + connection_states = ConnectionStates0} = State0, Connection) -> #{security_parameters := SecParams} = ssl_record:pending_connection_state(ConnectionStates0, read), #security_parameters{client_random = ClientRandom, @@ -1775,10 +1773,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + connection_env = #connection_env{negotiated_version = Version}, diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, - connection_states = ConnectionStates0, - negotiated_version = Version + connection_states = ConnectionStates0 } = State0, Connection) -> DHKeys = public_key:generate_key(Params), #{security_parameters := SecParams} = @@ -1796,10 +1794,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = ecdhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + connection_env = #connection_env{negotiated_version = Version}, private_key = PrivateKey, session = #session{ecc = ECCCurve}, - connection_states = ConnectionStates0, - negotiated_version = Version + connection_states = ConnectionStates0 } = State0, Connection) -> ECDHKeys = public_key:generate_key(ECCCurve), #{security_parameters := SecParams} = @@ -1820,9 +1818,9 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + connection_env = #connection_env{negotiated_version = Version}, private_key = PrivateKey, - connection_states = ConnectionStates0, - negotiated_version = Version + connection_states = ConnectionStates0 } = State0, Connection) -> #{security_parameters := SecParams} = ssl_record:pending_connection_state(ConnectionStates0, read), @@ -1837,10 +1835,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, ssl_options = #ssl_options{user_lookup_fun = LookupFun}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + connection_env = #connection_env{negotiated_version = Version}, session = #session{srp_username = Username}, private_key = PrivateKey, - connection_states = ConnectionStates0, - negotiated_version = Version + connection_states = ConnectionStates0 } = State0, Connection) when Algo == srp_dss; Algo == srp_rsa; @@ -1866,14 +1864,14 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Alg srp_keys = Keys}; key_exchange(#state{static_env = #static_env{role = client}, handshake_env = #handshake_env{public_key_info = PublicKeyInfo}, - key_algorithm = rsa, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, + key_algorithm = rsa, premaster_secret = PremasterSecret} = State0, Connection) -> Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - key_algorithm = Algorithm, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, + key_algorithm = Algorithm, diffie_hellman_keys = {DhPubKey, _} } = State0, Connection) when Algorithm == dhe_dss; @@ -1883,8 +1881,8 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + connection_env = #connection_env{negotiated_version = Version}, key_algorithm = Algorithm, - negotiated_version = Version, session = Session, diffie_hellman_keys = #'ECPrivateKey'{parameters = ECCurve} = Key} = State0, Connection) when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa; @@ -1893,16 +1891,16 @@ key_exchange(#state{static_env = #static_env{role = client}, Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Key}), Connection:queue_handshake(Msg, State0#state{session = Session#session{ecc = ECCurve}}); key_exchange(#state{static_env = #static_env{role = client}, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - key_algorithm = psk, - negotiated_version = Version} = State0, Connection) -> + key_algorithm = psk} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {psk, SslOpts#ssl_options.psk_identity}), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, key_algorithm = dhe_psk, - negotiated_version = Version, diffie_hellman_keys = {DhPubKey, _}} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dhe_psk, @@ -1910,9 +1908,9 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, key_algorithm = ecdhe_psk, - negotiated_version = Version, diffie_hellman_keys = ECDHKeys} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdhe_psk, @@ -1921,17 +1919,17 @@ key_exchange(#state{static_env = #static_env{role = client}, key_exchange(#state{static_env = #static_env{role = client}, handshake_env = #handshake_env{public_key_info = PublicKeyInfo}, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, key_algorithm = rsa_psk, - negotiated_version = Version, premaster_secret = PremasterSecret} = State0, Connection) -> Msg = rsa_psk_key_exchange(ssl:tls_version(Version), SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + connection_env = #connection_env{negotiated_version = Version}, key_algorithm = Algorithm, - negotiated_version = Version, srp_keys = {ClientPubKey, _}} = State0, Connection) when Algorithm == srp_dss; @@ -1981,10 +1979,10 @@ request_client_cert(#state{key_algorithm = Alg} = State, _) request_client_cert(#state{static_env = #static_env{cert_db = CertDbHandle, cert_db_ref = CertDbRef}, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = #ssl_options{verify = verify_peer, signature_algs = SupportedHashSigns}, - connection_states = ConnectionStates0, - negotiated_version = Version} = State0, Connection) -> + connection_states = ConnectionStates0} = State0, Connection) -> #{security_parameters := #security_parameters{cipher_suite = CipherSuite}} = ssl_record:pending_connection_state(ConnectionStates0, read), @@ -2001,7 +1999,7 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_none}} = State. calculate_master_secret(PremasterSecret, - #state{negotiated_version = Version, + #state{connection_env = #connection_env{negotiated_version = Version}, connection_states = ConnectionStates0, session = Session0} = State0, Connection, _Current, Next) -> @@ -2043,7 +2041,7 @@ cipher_protocol(State, Connection) -> finished(#state{static_env = #static_env{role = Role}, handshake_env = #handshake_env{tls_handshake_history = Hist}, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, session = Session, connection_states = ConnectionStates0} = State0, StateName, Connection) -> @@ -2123,8 +2121,8 @@ calculate_secret(#server_srp_params{srp_n = Prime, srp_g = Generator} = ServerKe master_secret(#alert{} = Alert, _) -> Alert; master_secret(PremasterSecret, #state{static_env = #static_env{role = Role}, + connection_env = #connection_env{negotiated_version = Version}, session = Session, - negotiated_version = Version, connection_states = ConnectionStates0} = State) -> case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret, ConnectionStates0, Role) of @@ -2465,9 +2463,8 @@ handle_resumed_session(SessId, #state{static_env = #static_env{host = Host, protocol_cb = Connection, session_cache = Cache, session_cache_cb = CacheCb}, - connection_states = ConnectionStates0, - negotiated_version = Version - } = State) -> + connection_env = #connection_env{negotiated_version = Version}, + connection_states = ConnectionStates0} = State) -> Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}), case ssl_handshake:master_secret(ssl:tls_version(Version), Session, ConnectionStates0, client) of diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 6610d79c60..f5fc8dde04 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -75,13 +75,14 @@ -record(connection_env, { user_application :: {Monitor::reference(), User::pid()}, downgrade, - terminated = false ::boolean() | closed + terminated = false ::boolean() | closed, + negotiated_version :: ssl_record:ssl_version() | 'undefined' }). -record(state, { static_env :: #static_env{}, handshake_env :: #handshake_env{} | secret_printout(), - connection_env :: #connection_env{}, + connection_env :: #connection_env{} | secret_printout(), %% Changed often connection_states :: ssl_record:connection_states() | secret_printout(), @@ -95,7 +96,6 @@ ssl_options :: #ssl_options{}, socket_options :: #socket_options{}, session :: #session{} | secret_printout(), - negotiated_version :: ssl_record:ssl_version() | 'undefined', %% Used only in HS client_certificate_requested = false :: boolean(), diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index fd60ca0cf8..c46c371a0e 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -228,7 +228,7 @@ handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, Stat handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data}, StateName, #state{protocol_buffers = #protocol_buffers{tls_handshake_buffer = Buf0} = Buffers, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, ssl_options = Options} = State0) -> try {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0, Options), @@ -261,7 +261,7 @@ handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, St {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]}; %%% TLS record protocol level Alert messages handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName, - #state{negotiated_version = Version} = State) -> + #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> try decode_alerts(EncAlerts) of Alerts = [_|_] -> handle_alerts(Alerts, {next_state, StateName, State}); @@ -296,7 +296,7 @@ renegotiate(#state{static_env = #static_env{role = server, socket = Socket, transport_cb = Transport}, handshake_env = HsEnv, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, connection_states = ConnectionStates0} = State0, Actions) -> HelloRequest = ssl_handshake:hello_request(), Frag = tls_handshake:encode_handshake(HelloRequest, Version), @@ -312,9 +312,9 @@ renegotiate(#state{static_env = #static_env{role = server, send_handshake(Handshake, State) -> send_handshake_flight(queue_handshake(Handshake, State)). -queue_handshake(Handshake, #state{negotiated_version = Version, - handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, - flight_buffer = Flight0, +queue_handshake(Handshake, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, + connection_env = #connection_env{negotiated_version = Version}, + flight_buffer = Flight0, connection_states = ConnectionStates0} = State0) -> {BinHandshake, ConnectionStates, Hist} = encode_handshake(Handshake, Version, ConnectionStates0, Hist0), @@ -328,16 +328,16 @@ send_handshake_flight(#state{static_env = #static_env{socket = Socket, send(Transport, Socket, Flight), {State0#state{flight_buffer = []}, []}. -queue_change_cipher(Msg, #state{negotiated_version = Version, - flight_buffer = Flight0, - connection_states = ConnectionStates0} = State0) -> +queue_change_cipher(Msg, #state{connection_env = #connection_env{negotiated_version = Version}, + flight_buffer = Flight0, + connection_states = ConnectionStates0} = State0) -> {BinChangeCipher, ConnectionStates} = encode_change_cipher(Msg, Version, ConnectionStates0), State0#state{connection_states = ConnectionStates, flight_buffer = Flight0 ++ [BinChangeCipher]}. reinit(#state{protocol_specific = #{sender := Sender}, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, connection_states = #{current_write := Write}} = State) -> tls_sender:update_connection_state(Sender, Write, Version), reinit_handshake_data(State). @@ -372,9 +372,9 @@ empty_connection_state(ConnectionEnd, BeastMitigation) -> encode_alert(#alert{} = Alert, Version, ConnectionStates) -> tls_record:encode_alert_record(Alert, Version, ConnectionStates). -send_alert(Alert, #state{negotiated_version = Version, - static_env = #static_env{socket = Socket, +send_alert(Alert, #state{static_env = #static_env{socket = Socket, transport_cb = Transport}, + connection_env = #connection_env{negotiated_version = Version}, connection_states = ConnectionStates0} = StateData0) -> {BinMsg, ConnectionStates} = encode_alert(Alert, Version, ConnectionStates0), @@ -465,6 +465,7 @@ init({call, From}, {start, Timeout}, session_cache = Cache, session_cache_cb = CacheCb}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, + connection_env = CEnv, ssl_options = SslOpts, session = #session{own_certificate = Cert} = Session0, connection_states = ConnectionStates0 @@ -480,7 +481,7 @@ init({call, From}, {start, Timeout}, encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0), send(Transport, Socket, BinMsg), State = State0#state{connection_states = ConnectionStates, - negotiated_version = Version, %% Requested version + connection_env = CEnv#connection_env{negotiated_version = Version}, %% Requested version session = Session0#session{session_id = Hello#client_hello.session_id}, handshake_env = HsEnv#handshake_env{tls_handshake_history = Handshake}, @@ -533,6 +534,7 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, session_cache_cb = CacheCb}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}, negotiated_protocol = CurrentProtocol} = HsEnv, + connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, key_algorithm = KeyExAlg, ssl_options = SslOpts} = State) -> @@ -540,8 +542,8 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, ClientVersion, hello, - State#state{negotiated_version - = ClientVersion}); + State#state{connection_env = + CEnv#connection_env{negotiated_version = ClientVersion}}); {Version, {Type, Session}, ConnectionStates, Protocol0, ServerHelloExt, HashSign} -> Protocol = case Protocol0 of @@ -550,7 +552,7 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, end, gen_handshake(?FUNCTION_NAME, internal, {common_client_hello, Type, ServerHelloExt}, State#state{connection_states = ConnectionStates, - negotiated_version = Version, + connection_env = CEnv#connection_env{negotiated_version = Version}, handshake_env = HsEnv#handshake_env{ hashsign_algorithm = HashSign, client_hello_version = ClientVersion, @@ -560,14 +562,14 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, end; hello(internal, #server_hello{} = Hello, #state{connection_states = ConnectionStates0, - negotiated_version = ReqVersion, + connection_env = #connection_env{negotiated_version = ReqVersion} = CEnv, static_env = #static_env{role = client}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, ssl_options = SslOptions} = State) -> case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of - #alert{} = Alert -> + #alert{} = Alert -> %%TODO ssl_connection:handle_own_alert(Alert, ReqVersion, hello, - State#state{negotiated_version = ReqVersion}); + State#state{connection_env = CEnv#connection_env{negotiated_version = ReqVersion}}); {Version, NewId, ConnectionStates, ProtoExt, Protocol} -> ssl_connection:handle_session(Hello, Version, NewId, ConnectionStates, ProtoExt, Protocol, State) @@ -823,8 +825,8 @@ initialize_tls_sender(#state{static_env = #static_env{ socket = Socket, tracker = Tracker }, - socket_options = SockOpts, - negotiated_version = Version, + connection_env = #connection_env{negotiated_version = Version}, + socket_options = SockOpts, ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}, connection_states = #{current_write := ConnectionWriteState}, protocol_specific = #{sender := Sender}}) -> @@ -856,7 +858,7 @@ next_tls_record(Data, StateName, #state{protocol_buffers = end. -acceptable_record_versions(StateName, #state{negotiated_version = Version}) when StateName =/= hello-> +acceptable_record_versions(StateName, #state{connection_env = #connection_env{negotiated_version = Version}}) when StateName =/= hello-> Version; acceptable_record_versions(hello, _) -> [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS]. @@ -887,11 +889,11 @@ handle_info({tcp_passive, Socket}, StateName, State#state{protocol_specific = PS#{active_n_toggle => true}}); handle_info({CloseTag, Socket}, StateName, #state{static_env = #static_env{socket = Socket, close_tag = CloseTag}, + connection_env = #connection_env{negotiated_version = Version}, socket_options = #socket_options{active = Active}, protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs}, user_data_buffer = Buffer, - protocol_specific = PS, - negotiated_version = Version} = State) -> + protocol_specific = PS} = State) -> %% Note that as of TLS 1.1, %% failure to properly close a connection no longer requires that a @@ -957,7 +959,7 @@ decode_alerts(Bin) -> ssl_alert:decode(Bin). gen_handshake(StateName, Type, Event, - #state{negotiated_version = Version} = State) -> + #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> try ssl_connection:StateName(Type, Event, State, ?MODULE) of Result -> Result @@ -968,7 +970,7 @@ gen_handshake(StateName, Type, Event, Version, StateName, State) end. -gen_info(Event, connection = StateName, #state{negotiated_version = Version} = State) -> +gen_info(Event, connection = StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> try handle_info(Event, StateName, State) of Result -> Result @@ -979,7 +981,7 @@ gen_info(Event, connection = StateName, #state{negotiated_version = Version} = Version, StateName, State) end; -gen_info(Event, StateName, #state{negotiated_version = Version} = State) -> +gen_info(Event, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) -> try handle_info(Event, StateName, State) of Result -> Result -- cgit v1.2.3 From df20de80e115caf9cb52d77bca6be5f53f7be115 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 31 Jan 2019 07:47:47 +0100 Subject: ssl: Add erl_dist_handle to connection_env --- lib/ssl/src/ssl_connection.erl | 5 +++-- lib/ssl/src/ssl_connection.hrl | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 99d429511a..237cd03c0c 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -464,7 +464,7 @@ read_application_data( Data, #state{ user_data_buffer = Buffer0, - erl_dist_handle = DHandle} = State) -> + connection_env = #connection_env{erl_dist_handle = DHandle}} = State) -> %% Buffer = bincat(Buffer0, Data), case DHandle of @@ -1110,12 +1110,13 @@ connection(cast, {internal_renegotiate, WriteState}, #state{static_env = #static connection_states = ConnectionStates#{current_write => WriteState}}, []); connection(cast, {dist_handshake_complete, DHandle}, #state{ssl_options = #ssl_options{erl_dist = true}, + connection_env = CEnv, socket_options = SockOpts} = State0, Connection) -> process_flag(priority, normal), State1 = State0#state{ socket_options = SockOpts#socket_options{active = true}, - erl_dist_handle = DHandle, + connection_env = CEnv#connection_env{erl_dist_handle = DHandle}, bytes_to_read = undefined}, {Record, State} = read_application_data(<<>>, State1), Connection:next_event(connection, Record, State); diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index f5fc8dde04..21c200271d 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -76,7 +76,8 @@ user_application :: {Monitor::reference(), User::pid()}, downgrade, terminated = false ::boolean() | closed, - negotiated_version :: ssl_record:ssl_version() | 'undefined' + negotiated_version :: ssl_record:ssl_version() | 'undefined', + erl_dist_handle = undefined :: erlang:dist_handle() | undefined }). -record(state, { @@ -113,7 +114,6 @@ %% The mecahnism is also usefull in TLS although we do not %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr flight_state = reliable, %% reliable | {retransmit, integer()}| {waiting, ref(), integer()} - last two is used in DTLS over udp. - erl_dist_handle = undefined :: erlang:dist_handle() | undefined, protocol_specific = #{} :: map() }). -- cgit v1.2.3 From 588987a33e5ba1cb89b4f06a68d0abfcaa9acc99 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 6 Feb 2019 10:17:24 +0100 Subject: ssl: Remove unused record field --- lib/ssl/src/tls_connection.erl | 4 ++-- lib/ssl/src/tls_connection.hrl | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index c46c371a0e..a94782f305 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -149,7 +149,7 @@ next_record(#state{handshake_env = {no_record, State#state{handshake_env = HsEnv#handshake_env{unprocessed_handshake_events = N-1}}}; next_record(#state{protocol_buffers = - #protocol_buffers{tls_packets = [], tls_cipher_texts = [#ssl_tls{type = Type}| _] = CipherTexts0} + #protocol_buffers{tls_cipher_texts = [#ssl_tls{type = Type}| _] = CipherTexts0} = Buffers, connection_states = ConnectionStates0, ssl_options = #ssl_options{padding_check = Check}} = State) -> @@ -161,7 +161,7 @@ next_record(#state{protocol_buffers = {Alert, State#state{protocol_buffers = Buffers#protocol_buffers{tls_cipher_texts = CipherTexts}, connection_states = ConnectionStates}} end; -next_record(#state{protocol_buffers = #protocol_buffers{tls_packets = [], tls_cipher_texts = []}, +next_record(#state{protocol_buffers = #protocol_buffers{tls_cipher_texts = []}, protocol_specific = #{active_n_toggle := true, active_n := N} = ProtocolSpec, static_env = #static_env{socket = Socket, close_tag = CloseTag, diff --git a/lib/ssl/src/tls_connection.hrl b/lib/ssl/src/tls_connection.hrl index 0af2258932..9063b1b736 100644 --- a/lib/ssl/src/tls_connection.hrl +++ b/lib/ssl/src/tls_connection.hrl @@ -30,7 +30,6 @@ -include("tls_record.hrl"). -record(protocol_buffers, { - tls_packets = [], %% :: [#ssl_tls{}], % Not yet handled decode SSL/TLS packets. tls_record_buffer = <<>>, %% :: binary(), % Buffer of incomplete records tls_handshake_buffer = <<>>, %% :: binary(), % Buffer of incomplete handshakes tls_cipher_texts = [] %%:: [binary()] -- cgit v1.2.3 From 4b68540ba24e5606e3a04e4dc4d5f4b07ba153f1 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 6 Feb 2019 10:44:13 +0100 Subject: ssl: Add private_key to connection_env --- lib/ssl/src/ssl_connection.erl | 50 ++++++++++++++++++++++-------------------- lib/ssl/src/ssl_connection.hrl | 4 ++-- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 237cd03c0c..c770ecbdd0 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -607,7 +607,8 @@ handle_session(#server_hello{cipher_suite = CipherSuite, %%-------------------------------------------------------------------- -spec ssl_config(#ssl_options{}, client | server, #state{}) -> #state{}. %%-------------------------------------------------------------------- -ssl_config(Opts, Role, #state{static_env = InitStatEnv0} = State0) -> +ssl_config(Opts, Role, #state{static_env = InitStatEnv0, + connection_env = CEnv} = State0) -> {ok, #{cert_db_ref := Ref, cert_db_handle := CertDbHandle, fileref_db_handle := FileRefHandle, @@ -629,7 +630,7 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0} = State0) -> crl_db = CRLDbHandle, session_cache = CacheHandle }, - private_key = Key, + connection_env = CEnv#connection_env{private_key = Key}, diffie_hellman_params = DHParams, ssl_options = Opts}. @@ -1413,8 +1414,8 @@ format_status(terminate, [_, StateName, State]) -> protocol_buffers = ?SECRET_PRINTOUT, user_data_buffer = ?SECRET_PRINTOUT, handshake_env = ?SECRET_PRINTOUT, + connection_env = ?SECRET_PRINTOUT, session = ?SECRET_PRINTOUT, - private_key = ?SECRET_PRINTOUT, diffie_hellman_params = ?SECRET_PRINTOUT, diffie_hellman_keys = ?SECRET_PRINTOUT, srp_params = ?SECRET_PRINTOUT, @@ -1572,9 +1573,9 @@ certify_client(#state{client_certificate_requested = false} = State, _) -> verify_client_cert(#state{static_env = #static_env{role = client}, handshake_env = #handshake_env{tls_handshake_history = Hist, cert_hashsign_algorithm = HashSign}, - connection_env = #connection_env{negotiated_version = Version}, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, client_certificate_requested = true, - private_key = PrivateKey, session = #session{master_secret = MasterSecret, own_certificate = OwnCert}} = State, Connection) -> @@ -1615,7 +1616,7 @@ server_certify_and_key_exchange(State0, Connection) -> request_client_cert(State2, Connection). certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS}, - #state{private_key = Key, + #state{connection_env = #connection_env{private_key = Key}, handshake_env = #handshake_env{client_hello_version = {Major, Minor} = Version}} = State, Connection) -> FakeSecret = make_premaster_secret(Version, rsa), @@ -1672,7 +1673,7 @@ certify_client_key_exchange(#client_ecdhe_psk_identity{} = ClientKey, ssl_handshake:premaster_secret(ClientKey, ServerEcDhPrivateKey, PSKLookup), calculate_master_secret(PremasterSecret, State, Connection, certify, cipher); certify_client_key_exchange(#client_rsa_psk_identity{} = ClientKey, - #state{private_key = Key, + #state{connection_env = #connection_env{private_key = Key}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State0, Connection) -> @@ -1706,9 +1707,9 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa State; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, - connection_env = #connection_env{negotiated_version = Version}, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, diffie_hellman_params = #'DHParameter'{} = Params, - private_key = PrivateKey, connection_states = ConnectionStates0} = State0, Connection) when Algo == dhe_dss; Algo == dhe_rsa; @@ -1725,7 +1726,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Alg State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = DHKeys}; key_exchange(#state{static_env = #static_env{role = server}, - private_key = #'ECPrivateKey'{parameters = ECCurve} = Key, + connection_env = #connection_env{private_key = #'ECPrivateKey'{parameters = ECCurve} = Key}, key_algorithm = Algo, session = Session} = State, _) when Algo == ecdh_ecdsa; Algo == ecdh_rsa -> @@ -1733,8 +1734,8 @@ key_exchange(#state{static_env = #static_env{role = server}, session = Session#session{ecc = ECCurve}}; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, - connection_env = #connection_env{negotiated_version = Version}, - private_key = PrivateKey, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, session = #session{ecc = ECCCurve}, connection_states = ConnectionStates0} = State0, Connection) when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa; @@ -1758,8 +1759,8 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, - connection_env = #connection_env{negotiated_version = Version}, - private_key = PrivateKey, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, connection_states = ConnectionStates0} = State0, Connection) -> #{security_parameters := SecParams} = ssl_record:pending_connection_state(ConnectionStates0, read), @@ -1774,9 +1775,9 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, - connection_env = #connection_env{negotiated_version = Version}, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, diffie_hellman_params = #'DHParameter'{} = Params, - private_key = PrivateKey, connection_states = ConnectionStates0 } = State0, Connection) -> DHKeys = public_key:generate_key(Params), @@ -1795,8 +1796,8 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = ecdhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, - connection_env = #connection_env{negotiated_version = Version}, - private_key = PrivateKey, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, session = #session{ecc = ECCCurve}, connection_states = ConnectionStates0 } = State0, Connection) -> @@ -1819,8 +1820,8 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, - connection_env = #connection_env{negotiated_version = Version}, - private_key = PrivateKey, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, connection_states = ConnectionStates0 } = State0, Connection) -> #{security_parameters := SecParams} = @@ -1836,9 +1837,9 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, ssl_options = #ssl_options{user_lookup_fun = LookupFun}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, - connection_env = #connection_env{negotiated_version = Version}, + connection_env = #connection_env{negotiated_version = Version, + private_key = PrivateKey}, session = #session{srp_username = Username}, - private_key = PrivateKey, connection_states = ConnectionStates0 } = State0, Connection) when Algo == srp_dss; @@ -2727,7 +2728,8 @@ invalidate_session(server, _, Port, Session) -> handle_sni_extension(undefined, State) -> State; handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{role = Role} = InitStatEnv0, - handshake_env = HsEnv} = State0) -> + handshake_env = HsEnv, + connection_env = CEnv} = State0) -> NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname), case NewOptions of undefined -> @@ -2751,7 +2753,7 @@ handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{ crl_db = CRLDbHandle, session_cache = CacheHandle }, - private_key = Key, + connection_env = CEnv#connection_env{private_key = Key}, diffie_hellman_params = DHParams, ssl_options = NewOptions, handshake_env = HsEnv#handshake_env{sni_hostname = Hostname} diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 21c200271d..fc8e6bdec2 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -77,7 +77,8 @@ downgrade, terminated = false ::boolean() | closed, negotiated_version :: ssl_record:ssl_version() | 'undefined', - erl_dist_handle = undefined :: erlang:dist_handle() | undefined + erl_dist_handle = undefined :: erlang:dist_handle() | undefined, + private_key :: public_key:private_key() | secret_printout() | 'undefined' }). -record(state, { @@ -101,7 +102,6 @@ %% Used only in HS client_certificate_requested = false :: boolean(), key_algorithm :: ssl:key_algo(), - private_key :: public_key:private_key() | secret_printout() | 'undefined', diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), psk_identity :: binary() | 'undefined', % server psk identity hint -- cgit v1.2.3 From d94c54abadd7d12d29edd2f30b29273fd2635c1a Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 6 Feb 2019 15:43:52 +0100 Subject: ssl: Make flight_state DTLS specific flight_state is used to handle retransmission timers for DTLS over udp --- lib/ssl/src/dtls_connection.erl | 70 +++++++++++++++++++++++------------------ lib/ssl/src/ssl_connection.hrl | 5 +-- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 88c4d92bab..0c7446e894 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -335,12 +335,14 @@ queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight, reinit(State) -> %% To be API compatible with TLS NOOP here reinit_handshake_data(State). -reinit_handshake_data(#state{protocol_buffers = Buffers, +reinit_handshake_data(#state{static_env = #static_env{data_tag = DataTag}, + protocol_buffers = Buffers, + protocol_specific = PS, handshake_env = HsEnv} = State) -> State#state{premaster_secret = undefined, handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(), public_key_info = undefined}, - flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, + protocol_specific = PS#{flight_state => initial_flight_state(DataTag)}, flight_buffer = new_flight(), protocol_buffers = Buffers#protocol_buffers{ @@ -441,23 +443,18 @@ init({call, From}, {start, Timeout}, session = Session0#session{session_id = Hello#client_hello.session_id}, start_or_recv_from = From, - timer = Timer, - flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}}, + timer = Timer}, {Record, State} = next_record(State3), next_event(hello, Record, State, Actions); -init({call, _} = Type, Event, #state{static_env = #static_env{role = server, - data_tag = udp}} = State) -> +init({call, _} = Type, Event, #state{static_env = #static_env{role = server}, + protocol_specific = PS} = State) -> Result = gen_handshake(?FUNCTION_NAME, Type, Event, - State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, - protocol_specific = #{current_cookie_secret => dtls_v1:cookie_secret(), - previous_cookie_secret => <<>>, - ignored_alerts => 0, - max_ignored_alerts => 10}}), + State#state{protocol_specific = PS#{current_cookie_secret => dtls_v1:cookie_secret(), + previous_cookie_secret => <<>>, + ignored_alerts => 0, + max_ignored_alerts => 10}}), erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret), Result; -init({call, _} = Type, Event, #state{static_env = #static_env{role = server}} = State) -> - %% I.E. DTLS over sctp - gen_handshake(?FUNCTION_NAME, Type, Event, State#state{flight_state = reliable}); init(Type, Event, State) -> gen_handshake(?FUNCTION_NAME, Type, Event, State). @@ -626,10 +623,11 @@ abbreviated(internal = Type, ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read), ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read), gen_handshake(?FUNCTION_NAME, Type, Event, State#state{connection_states = ConnectionStates}); -abbreviated(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) -> +abbreviated(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates, + protocol_specific = PS} = State) -> gen_handshake(?FUNCTION_NAME, Type, Event, prepare_flight(State#state{connection_states = ConnectionStates, - flight_state = connection})); + protocol_specific = PS#{flight_state => connection}})); abbreviated(state_timeout, Event, State) -> handle_state_timeout(Event, ?FUNCTION_NAME, State); abbreviated(Type, Event, State) -> @@ -669,10 +667,11 @@ cipher(internal = Type, #change_cipher_spec{type = <<1>>} = Event, ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read), ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read), ssl_connection:?FUNCTION_NAME(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE); -cipher(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) -> +cipher(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates, + protocol_specific = PS} = State) -> ssl_connection:?FUNCTION_NAME(Type, Event, prepare_flight(State#state{connection_states = ConnectionStates, - flight_state = connection}), + protocol_specific = PS#{flight_state => connection}}), ?MODULE); cipher(state_timeout, Event, State) -> handle_state_timeout(Event, ?FUNCTION_NAME, State); @@ -690,6 +689,7 @@ connection(info, Event, State) -> gen_info(Event, ?FUNCTION_NAME, State); connection(internal, #hello_request{}, #state{static_env = #static_env{host = Host, port = Port, + data_tag = DataTag, session_cache = Cache, session_cache_cb = CacheCb }, @@ -697,7 +697,8 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, ssl_options = SslOpts, - connection_states = ConnectionStates0 + connection_states = ConnectionStates0, + protocol_specific = PS } = State0) -> Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, @@ -708,9 +709,9 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho {State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}), {Record, State} = next_record( - State2#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, + State2#state{protocol_specific = PS#{flight_state => initial_flight_state(DataTag)}, session = Session0#session{session_id - = Hello#client_hello.session_id}}), + = Hello#client_hello.session_id}}), next_event(hello, Record, State, Actions); connection(internal, #client_hello{} = Hello, #state{static_env = #static_env{role = server}, handshake_env = #handshake_env{allow_renegotiate = true} = HsEnv} = State) -> @@ -809,9 +810,14 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User, user_data_buffer = <<>>, start_or_recv_from = undefined, flight_buffer = new_flight(), - flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT} + protocol_specific = #{flight_state => initial_flight_state(DataTag)} }. +initial_flight_state(udp)-> + {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}; +initial_flight_state(_) -> + reliable. + next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{ dtls_record_buffer = Buf0, dtls_cipher_texts = CT0} = Buffers} = State0) -> @@ -941,9 +947,10 @@ handle_info(Msg, StateName, State) -> ssl_connection:StateName(info, Msg, State, ?MODULE). handle_state_timeout(flight_retransmission_timeout, StateName, - #state{flight_state = {retransmit, NextTimeout}} = State0) -> - {State1, Actions0} = send_handshake_flight(State0#state{flight_state = {retransmit, NextTimeout}}, - retransmit_epoch(StateName, State0)), + #state{protocol_specific = + #{flight_state := {retransmit, _NextTimeout}}} = State0) -> + {State1, Actions0} = send_handshake_flight(State0, + retransmit_epoch(StateName, State0)), {next_state, StateName, State, Actions} = next_event(StateName, no_record, State1, Actions0), %% This will reset the retransmission timer by repeating the enter state event {repeat_state, State, Actions}. @@ -1049,17 +1056,17 @@ next_flight(Flight) -> handshakes_after_change_cipher_spec => []}. handle_flight_timer(#state{static_env = #static_env{data_tag = udp}, - flight_state = {retransmit, Timeout}} = State) -> + protocol_specific = #{flight_state := {retransmit, Timeout}}} = State) -> start_retransmision_timer(Timeout, State); handle_flight_timer(#state{static_env = #static_env{data_tag = udp}, - flight_state = connection} = State) -> + protocol_specific = #{flight_state := connection}} = State) -> {State, []}; -handle_flight_timer(State) -> +handle_flight_timer(#state{protocol_specific = #{flight_state := reliable}} = State) -> %% No retransmision needed i.e DTLS over SCTP - {State#state{flight_state = reliable}, []}. + {State, []}. -start_retransmision_timer(Timeout, State) -> - {State#state{flight_state = {retransmit, new_timeout(Timeout)}}, +start_retransmision_timer(Timeout, #state{protocol_specific = PS} = State) -> + {State#state{protocol_specific = PS#{flight_state => {retransmit, new_timeout(Timeout)}}}, [{state_timeout, Timeout, flight_retransmission_timeout}]}. new_timeout(N) when N =< 30 -> @@ -1205,3 +1212,4 @@ is_time_to_renegotiate(N, M) when N < M-> false; is_time_to_renegotiate(_,_) -> true. + diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index fc8e6bdec2..4c9f95c110 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -86,10 +86,12 @@ handshake_env :: #handshake_env{} | secret_printout(), connection_env :: #connection_env{} | secret_printout(), - %% Changed often + %% Data shuffling connection_states :: ssl_record:connection_states() | secret_printout(), protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hr user_data_buffer :: undefined | binary() | secret_printout(), + + %% recv and start handling bytes_to_read :: undefined | integer(), %% bytes to read in passive mode start_or_recv_from :: term(), timer :: undefined | reference(), % start_or_recive_timer @@ -113,7 +115,6 @@ %% underlaying packet format. Introduced by DTLS - RFC 4347. %% The mecahnism is also usefull in TLS although we do not %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr - flight_state = reliable, %% reliable | {retransmit, integer()}| {waiting, ref(), integer()} - last two is used in DTLS over udp. protocol_specific = #{} :: map() }). -- cgit v1.2.3 From ff2c0fb176c78dc38cd154313402e1fc53e671fd Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 7 Feb 2019 10:34:13 +0100 Subject: ssl: Move premaster_secret to handshake_env --- lib/ssl/src/dtls_connection.erl | 6 +++--- lib/ssl/src/ssl_connection.erl | 37 +++++++++++++++++++------------------ lib/ssl/src/ssl_connection.hrl | 11 ++++++----- lib/ssl/src/tls_connection.erl | 4 ++-- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 0c7446e894..493f3bf581 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -339,9 +339,9 @@ reinit_handshake_data(#state{static_env = #static_env{data_tag = DataTag}, protocol_buffers = Buffers, protocol_specific = PS, handshake_env = HsEnv} = State) -> - State#state{premaster_secret = undefined, - handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(), - public_key_info = undefined}, + State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(), + public_key_info = undefined, + premaster_secret = undefined}, protocol_specific = PS#{flight_state => initial_flight_state(DataTag)}, flight_buffer = new_flight(), protocol_buffers = diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index c770ecbdd0..e2c9423560 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -590,8 +590,8 @@ handle_session(#server_hello{cipher_suite = CipherSuite, State = State0#state{key_algorithm = KeyAlgorithm, connection_states = ConnectionStates, - premaster_secret = PremasterSecret, - handshake_env = HsEnv#handshake_env{expecting_next_protocol_negotiation = ExpectNPN, + handshake_env = HsEnv#handshake_env{premaster_secret = PremasterSecret, + expecting_next_protocol_negotiation = ExpectNPN, negotiated_protocol = Protocol}, connection_env = CEnv#connection_env{negotiated_version = Version}}, @@ -901,9 +901,9 @@ certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, session = #session{master_secret = undefined}, connection_env = #connection_env{negotiated_version = Version}, + handshake_env = #handshake_env{premaster_secret = undefined} = HsEnv, psk_identity = PSKIdentity, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, - premaster_secret = undefined, key_algorithm = Alg} = State0, Connection) when Alg == psk -> case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup) of @@ -911,16 +911,17 @@ certify(internal, #server_hello_done{}, handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0); PremasterSecret -> State = master_secret(PremasterSecret, - State0#state{premaster_secret = PremasterSecret}), - client_certify_and_key_exchange(State, Connection) + State0#state{handshake_env = + HsEnv#handshake_env{premaster_secret = PremasterSecret}}), + client_certify_and_key_exchange(State, Connection) end; certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = {Major, Minor}} = Version, + handshake_env = #handshake_env{premaster_secret = undefined} = HsEnv, session = #session{master_secret = undefined}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, psk_identity = PSKIdentity, - premaster_secret = undefined, key_algorithm = Alg} = State0, Connection) when Alg == rsa_psk -> Rand = ssl_cipher:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), @@ -931,16 +932,17 @@ certify(internal, #server_hello_done{}, handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0); PremasterSecret -> State = master_secret(PremasterSecret, - State0#state{premaster_secret = RSAPremasterSecret}), + State0#state{handshake_env = + HsEnv#handshake_env{premaster_secret = RSAPremasterSecret}}), client_certify_and_key_exchange(State, Connection) end; %% Master secret was determined with help of server-key exchange msg certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, + handshake_env = #handshake_env{premaster_secret = undefined}, session = #session{master_secret = MasterSecret} = Session, - connection_states = ConnectionStates0, - premaster_secret = undefined} = State0, Connection) -> + connection_states = ConnectionStates0} = State0, Connection) -> case ssl_handshake:master_secret(ssl:tls_version(Version), Session, ConnectionStates0, client) of {MasterSecret, ConnectionStates} -> @@ -953,9 +955,9 @@ certify(internal, #server_hello_done{}, certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, + handshake_env = #handshake_env{premaster_secret = PremasterSecret}, session = Session0, - connection_states = ConnectionStates0, - premaster_secret = PremasterSecret} = State0, Connection) -> + connection_states = ConnectionStates0} = State0, Connection) -> case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret, ConnectionStates0, client) of {MasterSecret, ConnectionStates} -> @@ -1420,7 +1422,6 @@ format_status(terminate, [_, StateName, State]) -> diffie_hellman_keys = ?SECRET_PRINTOUT, srp_params = ?SECRET_PRINTOUT, srp_keys = ?SECRET_PRINTOUT, - premaster_secret = ?SECRET_PRINTOUT, ssl_options = NewOptions, flight_buffer = ?SECRET_PRINTOUT} }}]}]. @@ -1865,10 +1866,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Alg State#state{srp_params = SrpParams, srp_keys = Keys}; key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{public_key_info = PublicKeyInfo}, + handshake_env = #handshake_env{public_key_info = PublicKeyInfo, + premaster_secret = PremasterSecret}, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = rsa, - premaster_secret = PremasterSecret} = State0, Connection) -> + key_algorithm = rsa} = State0, Connection) -> Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, @@ -1920,11 +1921,11 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{public_key_info = PublicKeyInfo}, + handshake_env = #handshake_env{public_key_info = PublicKeyInfo, + premaster_secret = PremasterSecret}, connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - key_algorithm = rsa_psk, - premaster_secret = PremasterSecret} + key_algorithm = rsa_psk} = State0, Connection) -> Msg = rsa_psk_key_exchange(ssl:tls_version(Version), SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo), diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 4c9f95c110..d598e513fa 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -69,7 +69,8 @@ hashsign_algorithm = {undefined, undefined}, cert_hashsign_algorithm = {undefined, undefined}, %% key exchange - public_key_info :: ssl_handshake:public_key_info() | 'undefined' + public_key_info :: ssl_handshake:public_key_info() | 'undefined', + premaster_secret :: binary() | secret_printout() | 'undefined' }). -record(connection_env, { @@ -95,7 +96,9 @@ bytes_to_read :: undefined | integer(), %% bytes to read in passive mode start_or_recv_from :: term(), timer :: undefined | reference(), % start_or_recive_timer - + + protocol_specific = #{} :: map(), + %% Change seldome ssl_options :: #ssl_options{}, socket_options :: #socket_options{}, @@ -109,13 +112,11 @@ psk_identity :: binary() | 'undefined', % server psk identity hint srp_params :: #srp_user{} | secret_printout() | 'undefined', srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', - premaster_secret :: binary() | secret_printout() | 'undefined', - flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake + flight_buffer = [] :: list() | map() %% Buffer of TLS/DTLS records, used during the TLS handshake %% to when possible pack more than one TLS record into the %% underlaying packet format. Introduced by DTLS - RFC 4347. %% The mecahnism is also usefull in TLS although we do not %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr - protocol_specific = #{} :: map() }). diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index a94782f305..e1080b2fc9 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -347,9 +347,9 @@ reinit_handshake_data(#state{handshake_env = HsEnv} =State) -> %% are only needed during the handshake phase. %% To reduce memory foot print of a connection reinitialize them. State#state{ - premaster_secret = undefined, handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(), - public_key_info = undefined} + public_key_info = undefined, + premaster_secret = undefined} }. select_sni_extension(#client_hello{extensions = HelloExtensions}) -> -- cgit v1.2.3 From fd17b2ec302f8324b26a2cb87cd9cc3705a9e61f Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 7 Feb 2019 16:52:43 +0100 Subject: ssl: Move and rename psk_identity state record field --- lib/ssl/src/ssl_connection.erl | 14 ++++++++------ lib/ssl/src/ssl_connection.hrl | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index e2c9423560..5510235b04 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -901,8 +901,8 @@ certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, session = #session{master_secret = undefined}, connection_env = #connection_env{negotiated_version = Version}, - handshake_env = #handshake_env{premaster_secret = undefined} = HsEnv, - psk_identity = PSKIdentity, + handshake_env = #handshake_env{premaster_secret = undefined, + server_psk_identity = PSKIdentity} = HsEnv, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, key_algorithm = Alg} = State0, Connection) when Alg == psk -> @@ -918,10 +918,10 @@ certify(internal, #server_hello_done{}, certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = {Major, Minor}} = Version, - handshake_env = #handshake_env{premaster_secret = undefined} = HsEnv, + handshake_env = #handshake_env{premaster_secret = undefined, + server_psk_identity = PSKIdentity} = HsEnv, session = #session{master_secret = undefined}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, - psk_identity = PSKIdentity, key_algorithm = Alg} = State0, Connection) when Alg == rsa_psk -> Rand = ssl_cipher:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), @@ -2087,9 +2087,11 @@ calculate_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey}, calculate_secret(#server_psk_params{ hint = IdentityHint}, - State, Connection) -> + #state{handshake_env = HsEnv} = State, Connection) -> %% store for later use - Connection:next_event(certify, no_record, State#state{psk_identity = IdentityHint}); + Connection:next_event(certify, no_record, + State#state{handshake_env = + HsEnv#handshake_env{server_psk_identity = IdentityHint}}); calculate_secret(#server_dhe_psk_params{ dh_params = #server_dh_params{dh_p = Prime, dh_g = Base}} = ServerKey, diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index d598e513fa..27d414d351 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -70,7 +70,8 @@ cert_hashsign_algorithm = {undefined, undefined}, %% key exchange public_key_info :: ssl_handshake:public_key_info() | 'undefined', - premaster_secret :: binary() | secret_printout() | 'undefined' + premaster_secret :: binary() | secret_printout() | 'undefined', + server_psk_identity :: binary() | 'undefined' % server psk identity hint }). -record(connection_env, { @@ -109,7 +110,6 @@ key_algorithm :: ssl:key_algo(), diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), - psk_identity :: binary() | 'undefined', % server psk identity hint srp_params :: #srp_user{} | secret_printout() | 'undefined', srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', flight_buffer = [] :: list() | map() %% Buffer of TLS/DTLS records, used during the TLS handshake -- cgit v1.2.3 From d56923ffbef7801e93a4a298ce9a7bd990410d42 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 7 Feb 2019 21:15:41 +0100 Subject: ssl: Move diffie_hellman_params to handshake_env --- lib/ssl/src/ssl_connection.erl | 24 ++++++++++++------------ lib/ssl/src/ssl_connection.hrl | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 5510235b04..e4715ba329 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -608,6 +608,7 @@ handle_session(#server_hello{cipher_suite = CipherSuite, -spec ssl_config(#ssl_options{}, client | server, #state{}) -> #state{}. %%-------------------------------------------------------------------- ssl_config(Opts, Role, #state{static_env = InitStatEnv0, + handshake_env = HsEnv, connection_env = CEnv} = State0) -> {ok, #{cert_db_ref := Ref, cert_db_handle := CertDbHandle, @@ -630,8 +631,8 @@ 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{private_key = Key}, - diffie_hellman_params = DHParams, ssl_options = Opts}. %%==================================================================== @@ -1418,7 +1419,6 @@ format_status(terminate, [_, StateName, State]) -> handshake_env = ?SECRET_PRINTOUT, connection_env = ?SECRET_PRINTOUT, session = ?SECRET_PRINTOUT, - diffie_hellman_params = ?SECRET_PRINTOUT, diffie_hellman_keys = ?SECRET_PRINTOUT, srp_params = ?SECRET_PRINTOUT, srp_keys = ?SECRET_PRINTOUT, @@ -1640,7 +1640,7 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS end, calculate_master_secret(PremasterSecret, State, Connection, certify, cipher); certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey}, - #state{diffie_hellman_params = #'DHParameter'{} = Params, + #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params}, diffie_hellman_keys = {_, ServerDhPrivateKey}} = State, Connection) -> PremasterSecret = ssl_handshake:premaster_secret(ClientPublicDhKey, ServerDhPrivateKey, Params), @@ -1657,7 +1657,7 @@ certify_client_key_exchange(#client_psk_identity{} = ClientKey, PremasterSecret = ssl_handshake:premaster_secret(ClientKey, PSKLookup), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher); certify_client_key_exchange(#client_dhe_psk_identity{} = ClientKey, - #state{diffie_hellman_params = #'DHParameter'{} = Params, + #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params}, diffie_hellman_keys = {_, ServerDhPrivateKey}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State0, @@ -1707,10 +1707,10 @@ certify_server(#state{static_env = #static_env{cert_db = CertDbHandle, key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa} = State,_) -> State; key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, - handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, + hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, - diffie_hellman_params = #'DHParameter'{} = Params, connection_states = ConnectionStates0} = State0, Connection) when Algo == dhe_dss; Algo == dhe_rsa; @@ -1775,10 +1775,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, + hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, - diffie_hellman_params = #'DHParameter'{} = Params, connection_states = ConnectionStates0 } = State0, Connection) -> DHKeys = public_key:generate_key(Params), @@ -2755,12 +2755,12 @@ handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{ cert_db = CertDbHandle, crl_db = CRLDbHandle, session_cache = CacheHandle - }, + }, connection_env = CEnv#connection_env{private_key = Key}, - diffie_hellman_params = DHParams, ssl_options = NewOptions, - handshake_env = HsEnv#handshake_env{sni_hostname = Hostname} - } + handshake_env = HsEnv#handshake_env{sni_hostname = Hostname, + diffie_hellman_params = DHParams} + } end. update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) -> diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 27d414d351..97faa36c77 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -69,6 +69,7 @@ hashsign_algorithm = {undefined, undefined}, cert_hashsign_algorithm = {undefined, undefined}, %% key exchange + diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), public_key_info :: ssl_handshake:public_key_info() | 'undefined', premaster_secret :: binary() | secret_printout() | 'undefined', server_psk_identity :: binary() | 'undefined' % server psk identity hint @@ -108,7 +109,6 @@ %% Used only in HS client_certificate_requested = false :: boolean(), key_algorithm :: ssl:key_algo(), - diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), srp_params :: #srp_user{} | secret_printout() | 'undefined', srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', -- cgit v1.2.3 From 098852f7ee518fc1bd5a936ecc8baa5dfc118149 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 8 Feb 2019 10:58:58 +0100 Subject: ssl: Rename --- lib/ssl/src/dtls_connection.erl | 2 +- lib/ssl/src/ssl_connection.erl | 180 +++++++++++++++++++++++----------------- lib/ssl/src/ssl_connection.hrl | 49 ++++++----- lib/ssl/src/tls_connection.erl | 2 +- 4 files changed, 128 insertions(+), 105 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 493f3bf581..fd617bce2a 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -869,7 +869,7 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, negotiated_protocol = CurrentProtocol} = HsEnv, connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, - key_algorithm = KeyExAlg, + kex_algorithm = KeyExAlg, ssl_options = SslOpts} = State0) -> case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index e4715ba329..179ad67940 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -588,7 +588,7 @@ handle_session(#server_hello{cipher_suite = CipherSuite, {ProtoExt =:= npn, Protocol0} end, - State = State0#state{key_algorithm = KeyAlgorithm, + State = State0#state{kex_algorithm = KeyAlgorithm, connection_states = ConnectionStates, handshake_env = HsEnv#handshake_env{premaster_secret = PremasterSecret, expecting_next_protocol_negotiation = ExpectNPN, @@ -836,21 +836,29 @@ certify(internal, #server_key_exchange{exchange_keys = Keys}, #state{static_env = #static_env{role = client}, handshake_env = #handshake_env{public_key_info = PubKeyInfo} = HsEnv, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = Alg, + kex_algorithm = KexAlg, session = Session, connection_states = ConnectionStates} = State, Connection) - when Alg == dhe_dss; Alg == dhe_rsa; - Alg == ecdhe_rsa; Alg == ecdhe_ecdsa; - Alg == dh_anon; Alg == ecdh_anon; - Alg == psk; Alg == dhe_psk; Alg == ecdhe_psk; Alg == rsa_psk; - Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon -> - - Params = ssl_handshake:decode_server_key(Keys, Alg, ssl:tls_version(Version)), + when KexAlg == dhe_dss; + KexAlg == dhe_rsa; + KexAlg == ecdhe_rsa; + KexAlg == ecdhe_ecdsa; + KexAlg == dh_anon; + KexAlg == ecdh_anon; + KexAlg == psk; + KexAlg == dhe_psk; + KexAlg == ecdhe_psk; + KexAlg == rsa_psk; + KexAlg == srp_dss; + KexAlg == srp_rsa; + KexAlg == srp_anon -> + + Params = ssl_handshake:decode_server_key(Keys, KexAlg, ssl:tls_version(Version)), %% Use negotiated value if TLS-1.2 otherwhise return default - HashSign = negotiated_hashsign(Params#server_key_params.hashsign, Alg, PubKeyInfo, ssl:tls_version(Version)), + HashSign = negotiated_hashsign(Params#server_key_params.hashsign, KexAlg, PubKeyInfo, ssl:tls_version(Version)), - case is_anonymous(Alg) of + case is_anonymous(KexAlg) of true -> calculate_secret(Params#server_key_params.params, State#state{handshake_env = HsEnv#handshake_env{hashsign_algorithm = HashSign}}, Connection); @@ -870,10 +878,16 @@ certify(internal, #server_key_exchange{exchange_keys = Keys}, certify(internal, #certificate_request{}, #state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = Alg} = State, _) - when Alg == dh_anon; Alg == ecdh_anon; - Alg == psk; Alg == dhe_psk; Alg == ecdhe_psk; Alg == rsa_psk; - Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon -> + kex_algorithm = KexAlg} = State, _) + when KexAlg == dh_anon; + KexAlg == ecdh_anon; + KexAlg == psk; + KexAlg == dhe_psk; + KexAlg == ecdhe_psk; + KexAlg == rsa_psk; + KexAlg == srp_dss; + KexAlg == srp_rsa; + KexAlg == srp_anon -> handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version, ?FUNCTION_NAME, State); certify(internal, #certificate_request{}, @@ -905,9 +919,9 @@ certify(internal, #server_hello_done{}, handshake_env = #handshake_env{premaster_secret = undefined, server_psk_identity = PSKIdentity} = HsEnv, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, - key_algorithm = Alg} = State0, Connection) - when Alg == psk -> - case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup) of + kex_algorithm = KexAlg} = State0, Connection) + when KexAlg == psk -> + case ssl_handshake:premaster_secret({KexAlg, PSKIdentity}, PSKLookup) of #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0); PremasterSecret -> @@ -923,11 +937,11 @@ certify(internal, #server_hello_done{}, server_psk_identity = PSKIdentity} = HsEnv, session = #session{master_secret = undefined}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, - key_algorithm = Alg} = State0, Connection) - when Alg == rsa_psk -> + kex_algorithm = KexAlg} = State0, Connection) + when KexAlg == rsa_psk -> Rand = ssl_cipher:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), RSAPremasterSecret = <>, - case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup, + case ssl_handshake:premaster_secret({KexAlg, PSKIdentity}, PSKLookup, RSAPremasterSecret) of #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0); @@ -977,7 +991,7 @@ certify(internal = Type, #client_key_exchange{} = Msg, %% We expect a certificate here handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection); certify(internal, #client_key_exchange{exchange_keys = Keys}, - State = #state{key_algorithm = KeyAlg, + State = #state{kex_algorithm = KeyAlg, connection_env = #connection_env{negotiated_version = Version}}, Connection) -> try certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, ssl:tls_version(Version)), @@ -1005,7 +1019,7 @@ cipher(internal, #certificate_verify{signature = Signature, handshake_env = #handshake_env{tls_handshake_history = Hist, public_key_info = PubKeyInfo} = HsEnv, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = KexAlg, + kex_algorithm = KexAlg, session = #session{master_secret = MasterSecret} } = State, Connection) -> @@ -1522,7 +1536,7 @@ server_hello(ServerHello, State0, Connection) -> CipherSuite = ServerHello#server_hello.cipher_suite, #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_definition(CipherSuite), State = Connection:queue_handshake(ServerHello, State0), - State#state{key_algorithm = KeyAlgorithm}. + State#state{kex_algorithm = KeyAlgorithm}. server_hello_done(State, Connection) -> HelloDone = ssl_handshake:server_hello_done(), @@ -1687,12 +1701,12 @@ certify_client_key_exchange(#client_srp_public{} = ClientKey, PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, Params), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher). -certify_server(#state{key_algorithm = Algo} = State, _) when Algo == dh_anon; - Algo == ecdh_anon; - Algo == psk; - Algo == dhe_psk; - Algo == ecdhe_psk; - Algo == srp_anon -> +certify_server(#state{kex_algorithm = KexAlg} = State, _) when KexAlg == dh_anon; + KexAlg == ecdh_anon; + KexAlg == psk; + KexAlg == dhe_psk; + KexAlg == ecdhe_psk; + KexAlg == srp_anon -> State; certify_server(#state{static_env = #static_env{cert_db = CertDbHandle, cert_db_ref = CertDbRef}, @@ -1704,17 +1718,17 @@ certify_server(#state{static_env = #static_env{cert_db = CertDbHandle, throw(Alert) end. -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa} = State,_) -> +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = rsa} = State,_) -> State; -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = KexAlg, handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, connection_states = ConnectionStates0} = State0, Connection) - when Algo == dhe_dss; - Algo == dhe_rsa; - Algo == dh_anon -> + when KexAlg == dhe_dss; + KexAlg == dhe_rsa; + KexAlg == dh_anon -> DHKeys = public_key:generate_key(Params), #{security_parameters := SecParams} = ssl_record:pending_connection_state(ConnectionStates0, read), @@ -1728,19 +1742,21 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Alg State#state{diffie_hellman_keys = DHKeys}; key_exchange(#state{static_env = #static_env{role = server}, connection_env = #connection_env{private_key = #'ECPrivateKey'{parameters = ECCurve} = Key}, - key_algorithm = Algo, + kex_algorithm = KexAlg, session = Session} = State, _) - when Algo == ecdh_ecdsa; Algo == ecdh_rsa -> + when KexAlg == ecdh_ecdsa; + KexAlg == ecdh_rsa -> State#state{diffie_hellman_keys = Key, session = Session#session{ecc = ECCurve}}; -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = KexAlg, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, session = #session{ecc = ECCCurve}, connection_states = ConnectionStates0} = State0, Connection) - when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa; - Algo == ecdh_anon -> + when KexAlg == ecdhe_ecdsa; + KexAlg == ecdhe_rsa; + KexAlg == ecdh_anon -> ECDHKeys = public_key:generate_key(ECCCurve), #{security_parameters := SecParams} = @@ -1754,10 +1770,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Alg PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = ECDHKeys}; -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = psk, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> State; -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, @@ -1773,7 +1789,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk ServerRandom, PrivateKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe_psk, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = dhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, hashsign_algorithm = HashSignAlgo}, @@ -1794,7 +1810,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = DHKeys}; -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = ecdhe_psk, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = ecdhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, @@ -1815,10 +1831,10 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = ecd PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = ECDHKeys}; -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa_psk, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = rsa_psk, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> State; -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa_psk, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = rsa_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, @@ -1835,7 +1851,7 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa ServerRandom, PrivateKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, +key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = KexAlg, ssl_options = #ssl_options{user_lookup_fun = LookupFun}, handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, @@ -1843,9 +1859,9 @@ key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Alg session = #session{srp_username = Username}, connection_states = ConnectionStates0 } = State0, Connection) - when Algo == srp_dss; - Algo == srp_rsa; - Algo == srp_anon -> + when KexAlg == srp_dss; + KexAlg == srp_rsa; + KexAlg == srp_anon -> SrpParams = handle_srp_identity(Username, LookupFun), Keys = case generate_srp_server_keys(SrpParams, 0) of Alert = #alert{} -> @@ -1869,41 +1885,43 @@ key_exchange(#state{static_env = #static_env{role = client}, handshake_env = #handshake_env{public_key_info = PublicKeyInfo, premaster_secret = PremasterSecret}, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = rsa} = State0, Connection) -> + kex_algorithm = rsa} = State0, Connection) -> Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = Algorithm, + kex_algorithm = KexAlg, diffie_hellman_keys = {DhPubKey, _} } = State0, Connection) - when Algorithm == dhe_dss; - Algorithm == dhe_rsa; - Algorithm == dh_anon -> + when KexAlg == dhe_dss; + KexAlg == dhe_rsa; + KexAlg == dh_anon -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dh, DhPubKey}), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = Algorithm, + kex_algorithm = KexAlg, session = Session, diffie_hellman_keys = #'ECPrivateKey'{parameters = ECCurve} = Key} = State0, Connection) - when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa; - Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa; - Algorithm == ecdh_anon -> + when KexAlg == ecdhe_ecdsa; + KexAlg == ecdhe_rsa; + KexAlg == ecdh_ecdsa; + KexAlg == ecdh_rsa; + KexAlg == ecdh_anon -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Key}), Connection:queue_handshake(Msg, State0#state{session = Session#session{ecc = ECCurve}}); key_exchange(#state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - key_algorithm = psk} = State0, Connection) -> + kex_algorithm = psk} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {psk, SslOpts#ssl_options.psk_identity}), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - key_algorithm = dhe_psk, + kex_algorithm = dhe_psk, diffie_hellman_keys = {DhPubKey, _}} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dhe_psk, @@ -1913,7 +1931,7 @@ key_exchange(#state{static_env = #static_env{role = client}, key_exchange(#state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - key_algorithm = ecdhe_psk, + kex_algorithm = ecdhe_psk, diffie_hellman_keys = ECDHKeys} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdhe_psk, @@ -1925,19 +1943,19 @@ key_exchange(#state{static_env = #static_env{role = client}, premaster_secret = PremasterSecret}, connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - key_algorithm = rsa_psk} + kex_algorithm = rsa_psk} = State0, Connection) -> Msg = rsa_psk_key_exchange(ssl:tls_version(Version), SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = Version}, - key_algorithm = Algorithm, + kex_algorithm = KexAlg, srp_keys = {ClientPubKey, _}} = State0, Connection) - when Algorithm == srp_dss; - Algorithm == srp_rsa; - Algorithm == srp_anon -> + when KexAlg == srp_dss; + KexAlg == srp_rsa; + KexAlg == srp_anon -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {srp, ClientPubKey}), Connection:queue_handshake(Msg, State0). @@ -1974,10 +1992,16 @@ rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, rsa_psk_key_exchange(_, _, _, _) -> throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE, pub_key_is_not_rsa)). -request_client_cert(#state{key_algorithm = Alg} = State, _) - when Alg == dh_anon; Alg == ecdh_anon; - Alg == psk; Alg == dhe_psk; Alg == ecdhe_psk; Alg == rsa_psk; - Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon -> +request_client_cert(#state{kex_algorithm = Alg} = State, _) + when Alg == dh_anon; + Alg == ecdh_anon; + Alg == psk; + Alg == dhe_psk; + Alg == ecdhe_psk; + Alg == rsa_psk; + Alg == srp_dss; + Alg == srp_rsa; + Alg == srp_anon -> State; request_client_cert(#state{static_env = #static_env{cert_db = CertDbHandle, @@ -2198,13 +2222,13 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0 {Record, State} = prepare_connection(State1, Connection), Connection:next_event(connection, Record, State, Actions). -is_anonymous(Algo) when Algo == dh_anon; - Algo == ecdh_anon; - Algo == psk; - Algo == dhe_psk; - Algo == ecdhe_psk; - Algo == rsa_psk; - Algo == srp_anon -> +is_anonymous(KexAlg) when KexAlg == dh_anon; + KexAlg == ecdh_anon; + KexAlg == psk; + KexAlg == dhe_psk; + KexAlg == ecdhe_psk; + KexAlg == rsa_psk; + KexAlg == srp_anon -> true; is_anonymous(_) -> false. diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 97faa36c77..15aec8dbf0 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -86,37 +86,36 @@ -record(state, { static_env :: #static_env{}, - handshake_env :: #handshake_env{} | secret_printout(), - connection_env :: #connection_env{} | secret_printout(), - - %% Data shuffling - connection_states :: ssl_record:connection_states() | secret_printout(), - protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hr - user_data_buffer :: undefined | binary() | secret_printout(), - - %% recv and start handling - bytes_to_read :: undefined | integer(), %% bytes to read in passive mode - start_or_recv_from :: term(), - timer :: undefined | reference(), % start_or_recive_timer - - protocol_specific = #{} :: map(), - - %% Change seldome + connection_env :: #connection_env{} | secret_printout(), ssl_options :: #ssl_options{}, socket_options :: #socket_options{}, - session :: #session{} | secret_printout(), - - %% Used only in HS + + %% Hanshake %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + handshake_env :: #handshake_env{} | secret_printout(), + %% Buffer of TLS/DTLS records, used during the TLS + %% handshake to when possible pack more than one TLS + %% record into the underlaying packet + %% format. Introduced by DTLS - RFC 4347. The + %% mecahnism is also usefull in TLS although we do not + %% need to worry about packet loss in TLS. In DTLS we + %% need to track DTLS handshake seqnr + flight_buffer = [] :: list() | map(), + kex_algorithm :: ssl:key_algo(), client_certificate_requested = false :: boolean(), - key_algorithm :: ssl:key_algo(), diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), srp_params :: #srp_user{} | secret_printout() | 'undefined', srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', - flight_buffer = [] :: list() | map() %% Buffer of TLS/DTLS records, used during the TLS handshake - %% to when possible pack more than one TLS record into the - %% underlaying packet format. Introduced by DTLS - RFC 4347. - %% The mecahnism is also usefull in TLS although we do not - %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr + protocol_specific = #{} :: map(), + session :: #session{} | secret_printout(), + %% Data shuffling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + connection_states :: ssl_record:connection_states() | secret_printout(), + protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hr + user_data_buffer :: undefined | binary() | secret_printout(), + bytes_to_read :: undefined | integer(), %% bytes to read in passive mode + + %% recv and start handling + start_or_recv_from :: term(), + timer :: undefined | reference() % start_or_recive_timer }). diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index e1080b2fc9..7d523a7409 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -536,7 +536,7 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, negotiated_protocol = CurrentProtocol} = HsEnv, connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, - key_algorithm = KeyExAlg, + kex_algorithm = KeyExAlg, ssl_options = SslOpts} = State) -> case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of -- cgit v1.2.3 From dcce921e494f4a54341da54c1c8f98ae5941ba00 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 8 Feb 2019 16:47:16 +0100 Subject: ssl: srp --- lib/ssl/src/ssl_connection.erl | 7 +++---- lib/ssl/src/ssl_connection.hrl | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 179ad67940..293f6d70bd 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1434,7 +1434,6 @@ format_status(terminate, [_, StateName, State]) -> connection_env = ?SECRET_PRINTOUT, session = ?SECRET_PRINTOUT, diffie_hellman_keys = ?SECRET_PRINTOUT, - srp_params = ?SECRET_PRINTOUT, srp_keys = ?SECRET_PRINTOUT, ssl_options = NewOptions, flight_buffer = ?SECRET_PRINTOUT} @@ -1695,7 +1694,7 @@ certify_client_key_exchange(#client_rsa_psk_identity{} = ClientKey, PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, PSKLookup), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher); certify_client_key_exchange(#client_srp_public{} = ClientKey, - #state{srp_params = Params, + #state{handshake_env = #handshake_env{srp_params = Params}, srp_keys = Key } = State0, Connection) -> PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, Params), @@ -1878,8 +1877,8 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = Kex HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), - State = Connection:queue_handshake(Msg, State0), - State#state{srp_params = SrpParams, + #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0), + State#state{handshake_env = HsEnv#handshake_env{srp_params = SrpParams}, srp_keys = Keys}; key_exchange(#state{static_env = #static_env{role = client}, handshake_env = #handshake_env{public_key_info = PublicKeyInfo, diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 15aec8dbf0..1e4907661a 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -70,6 +70,7 @@ cert_hashsign_algorithm = {undefined, undefined}, %% key exchange diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), + srp_params :: #srp_user{} | secret_printout() | 'undefined', public_key_info :: ssl_handshake:public_key_info() | 'undefined', premaster_secret :: binary() | secret_printout() | 'undefined', server_psk_identity :: binary() | 'undefined' % server psk identity hint @@ -102,8 +103,7 @@ flight_buffer = [] :: list() | map(), kex_algorithm :: ssl:key_algo(), client_certificate_requested = false :: boolean(), - diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), - srp_params :: #srp_user{} | secret_printout() | 'undefined', + diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', protocol_specific = #{} :: map(), session :: #session{} | secret_printout(), -- cgit v1.2.3 From 10872a78891ca04916ca041148ba2119d3b61bdc Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 8 Feb 2019 20:19:30 +0100 Subject: ssl: Move key_algorithm to handshake_env --- lib/ssl/src/dtls_connection.erl | 4 +- lib/ssl/src/ssl_connection.erl | 126 ++++++++++++++++++++++------------------ lib/ssl/src/ssl_connection.hrl | 2 +- lib/ssl/src/tls_connection.erl | 4 +- 4 files changed, 74 insertions(+), 62 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index fd617bce2a..19c6008374 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -865,11 +865,11 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, static_env = #static_env{port = Port, session_cache = Cache, session_cache_cb = CacheCb}, - handshake_env = #handshake_env{renegotiation = {Renegotiation, _}, + handshake_env = #handshake_env{kex_algorithm = KeyExAlg, + renegotiation = {Renegotiation, _}, negotiated_protocol = CurrentProtocol} = HsEnv, connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, - kex_algorithm = KeyExAlg, ssl_options = SslOpts} = State0) -> case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 293f6d70bd..d378f96a20 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -588,9 +588,9 @@ handle_session(#server_hello{cipher_suite = CipherSuite, {ProtoExt =:= npn, Protocol0} end, - State = State0#state{kex_algorithm = KeyAlgorithm, - connection_states = ConnectionStates, - handshake_env = HsEnv#handshake_env{premaster_secret = PremasterSecret, + State = State0#state{connection_states = ConnectionStates, + handshake_env = HsEnv#handshake_env{kex_algorithm = KeyAlgorithm, + premaster_secret = PremasterSecret, expecting_next_protocol_negotiation = ExpectNPN, negotiated_protocol = Protocol}, connection_env = CEnv#connection_env{negotiated_version = Version}}, @@ -834,9 +834,9 @@ certify(internal, #certificate{} = Cert, end; certify(internal, #server_key_exchange{exchange_keys = Keys}, #state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{public_key_info = PubKeyInfo} = HsEnv, + handshake_env = #handshake_env{kex_algorithm = KexAlg, + public_key_info = PubKeyInfo} = HsEnv, connection_env = #connection_env{negotiated_version = Version}, - kex_algorithm = KexAlg, session = Session, connection_states = ConnectionStates} = State, Connection) when KexAlg == dhe_dss; @@ -877,8 +877,8 @@ certify(internal, #server_key_exchange{exchange_keys = Keys}, end; certify(internal, #certificate_request{}, #state{static_env = #static_env{role = client}, - connection_env = #connection_env{negotiated_version = Version}, - kex_algorithm = KexAlg} = State, _) + handshake_env = #handshake_env{kex_algorithm = KexAlg}, + connection_env = #connection_env{negotiated_version = Version}} = State, _) when KexAlg == dh_anon; KexAlg == ecdh_anon; KexAlg == psk; @@ -916,10 +916,10 @@ certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, session = #session{master_secret = undefined}, connection_env = #connection_env{negotiated_version = Version}, - handshake_env = #handshake_env{premaster_secret = undefined, + handshake_env = #handshake_env{kex_algorithm = KexAlg, + premaster_secret = undefined, server_psk_identity = PSKIdentity} = HsEnv, - ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, - kex_algorithm = KexAlg} = State0, Connection) + ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State0, Connection) when KexAlg == psk -> case ssl_handshake:premaster_secret({KexAlg, PSKIdentity}, PSKLookup) of #alert{} = Alert -> @@ -933,11 +933,11 @@ certify(internal, #server_hello_done{}, certify(internal, #server_hello_done{}, #state{static_env = #static_env{role = client}, connection_env = #connection_env{negotiated_version = {Major, Minor}} = Version, - handshake_env = #handshake_env{premaster_secret = undefined, + handshake_env = #handshake_env{kex_algorithm = KexAlg, + premaster_secret = undefined, server_psk_identity = PSKIdentity} = HsEnv, session = #session{master_secret = undefined}, - ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, - kex_algorithm = KexAlg} = State0, Connection) + ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State0, Connection) when KexAlg == rsa_psk -> Rand = ssl_cipher:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), RSAPremasterSecret = <>, @@ -991,7 +991,7 @@ certify(internal = Type, #client_key_exchange{} = Msg, %% We expect a certificate here handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection); certify(internal, #client_key_exchange{exchange_keys = Keys}, - State = #state{kex_algorithm = KeyAlg, + State = #state{handshake_env = #handshake_env{kex_algorithm = KeyAlg}, connection_env = #connection_env{negotiated_version = Version}}, Connection) -> try certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, ssl:tls_version(Version)), @@ -1017,9 +1017,9 @@ cipher(internal, #certificate_verify{signature = Signature, hashsign_algorithm = CertHashSign}, #state{static_env = #static_env{role = server}, handshake_env = #handshake_env{tls_handshake_history = Hist, + kex_algorithm = KexAlg, public_key_info = PubKeyInfo} = HsEnv, connection_env = #connection_env{negotiated_version = Version}, - kex_algorithm = KexAlg, session = #session{master_secret = MasterSecret} } = State, Connection) -> @@ -1534,8 +1534,8 @@ resumed_server_hello(#state{session = Session, server_hello(ServerHello, State0, Connection) -> CipherSuite = ServerHello#server_hello.cipher_suite, #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_definition(CipherSuite), - State = Connection:queue_handshake(ServerHello, State0), - State#state{kex_algorithm = KeyAlgorithm}. + #state{handshake_env = HsEnv} = State = Connection:queue_handshake(ServerHello, State0), + State#state{handshake_env = HsEnv#handshake_env{kex_algorithm = KeyAlgorithm}}. server_hello_done(State, Connection) -> HelloDone = ssl_handshake:server_hello_done(), @@ -1700,12 +1700,13 @@ certify_client_key_exchange(#client_srp_public{} = ClientKey, PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, Params), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher). -certify_server(#state{kex_algorithm = KexAlg} = State, _) when KexAlg == dh_anon; - KexAlg == ecdh_anon; - KexAlg == psk; - KexAlg == dhe_psk; - KexAlg == ecdhe_psk; - KexAlg == srp_anon -> +certify_server(#state{handshake_env = #handshake_env{kex_algorithm = KexAlg}} = + State, _) when KexAlg == dh_anon; + KexAlg == ecdh_anon; + KexAlg == psk; + KexAlg == dhe_psk; + KexAlg == ecdhe_psk; + KexAlg == srp_anon -> State; certify_server(#state{static_env = #static_env{cert_db = CertDbHandle, cert_db_ref = CertDbRef}, @@ -1717,10 +1718,12 @@ certify_server(#state{static_env = #static_env{cert_db = CertDbHandle, throw(Alert) end. -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = rsa} = State,_) -> +key_exchange(#state{static_env = #static_env{role = server}, + handshake_env = #handshake_env{kex_algorithm = rsa}} = State,_) -> State; -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = KexAlg, - handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, +key_exchange(#state{static_env = #static_env{role = server}, + handshake_env = #handshake_env{kex_algorithm = KexAlg, + diffie_hellman_params = #'DHParameter'{} = Params, hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, @@ -1740,15 +1743,16 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = Kex State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = DHKeys}; key_exchange(#state{static_env = #static_env{role = server}, + handshake_env =#handshake_env{kex_algorithm = KexAlg}, connection_env = #connection_env{private_key = #'ECPrivateKey'{parameters = ECCurve} = Key}, - kex_algorithm = KexAlg, session = Session} = State, _) when KexAlg == ecdh_ecdsa; KexAlg == ecdh_rsa -> State#state{diffie_hellman_keys = Key, session = Session#session{ecc = ECCurve}}; -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = KexAlg, - handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, +key_exchange(#state{static_env = #static_env{role = server}, + handshake_env = #handshake_env{kex_algorithm = KexAlg, + hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, session = #session{ecc = ECCCurve}, @@ -1769,15 +1773,17 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = Kex PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = ECDHKeys}; -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = psk, +key_exchange(#state{static_env = #static_env{role = server}, + handshake_env = #handshake_env{kex_algorithm = psk}, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> State; -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = psk, +key_exchange(#state{static_env = #static_env{role = server}, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + handshake_env = #handshake_env{kex_algorithm = psk, + hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, - connection_states = ConnectionStates0} = State0, Connection) -> + connection_states = ConnectionStates0} = State0, Connection) -> #{security_parameters := SecParams} = ssl_record:pending_connection_state(ConnectionStates0, read), #security_parameters{client_random = ClientRandom, @@ -1788,9 +1794,10 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = psk ServerRandom, PrivateKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = dhe_psk, +key_exchange(#state{static_env = #static_env{role = server}, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, + handshake_env = #handshake_env{kex_algorithm = dhe_psk, + diffie_hellman_params = #'DHParameter'{} = Params, hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, @@ -1809,9 +1816,10 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = dhe PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = DHKeys}; -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = ecdhe_psk, +key_exchange(#state{static_env = #static_env{role = server}, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + handshake_env = #handshake_env{kex_algorithm = ecdhe_psk, + hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, session = #session{ecc = ECCCurve}, @@ -1830,12 +1838,14 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = ecd PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = ECDHKeys}; -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = rsa_psk, +key_exchange(#state{static_env = #static_env{role = server}, + handshake_env = #handshake_env{kex_algorithm = rsa_psk}, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> State; -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = rsa_psk, +key_exchange(#state{static_env = #static_env{role = server}, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, - handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + handshake_env = #handshake_env{kex_algorithm = rsa_psk, + hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, connection_states = ConnectionStates0 @@ -1850,9 +1860,10 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = rsa ServerRandom, PrivateKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = KexAlg, +key_exchange(#state{static_env = #static_env{role = server}, ssl_options = #ssl_options{user_lookup_fun = LookupFun}, - handshake_env = #handshake_env{hashsign_algorithm = HashSignAlgo}, + handshake_env = #handshake_env{kex_algorithm = KexAlg, + hashsign_algorithm = HashSignAlgo}, connection_env = #connection_env{negotiated_version = Version, private_key = PrivateKey}, session = #session{srp_username = Username}, @@ -1881,15 +1892,16 @@ key_exchange(#state{static_env = #static_env{role = server}, kex_algorithm = Kex State#state{handshake_env = HsEnv#handshake_env{srp_params = SrpParams}, srp_keys = Keys}; key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{public_key_info = PublicKeyInfo, + handshake_env = #handshake_env{kex_algorithm = rsa, + public_key_info = PublicKeyInfo, premaster_secret = PremasterSecret}, - connection_env = #connection_env{negotiated_version = Version}, - kex_algorithm = rsa} = State0, Connection) -> + connection_env = #connection_env{negotiated_version = Version} + } = State0, Connection) -> Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{kex_algorithm = KexAlg}, connection_env = #connection_env{negotiated_version = Version}, - kex_algorithm = KexAlg, diffie_hellman_keys = {DhPubKey, _} } = State0, Connection) when KexAlg == dhe_dss; @@ -1899,8 +1911,8 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{kex_algorithm = KexAlg}, connection_env = #connection_env{negotiated_version = Version}, - kex_algorithm = KexAlg, session = Session, diffie_hellman_keys = #'ECPrivateKey'{parameters = ECCurve} = Key} = State0, Connection) when KexAlg == ecdhe_ecdsa; @@ -1911,16 +1923,16 @@ key_exchange(#state{static_env = #static_env{role = client}, Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Key}), Connection:queue_handshake(Msg, State0#state{session = Session#session{ecc = ECCurve}}); key_exchange(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{kex_algorithm = psk}, connection_env = #connection_env{negotiated_version = Version}, - ssl_options = SslOpts, - kex_algorithm = psk} = State0, Connection) -> + ssl_options = SslOpts} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {psk, SslOpts#ssl_options.psk_identity}), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{kex_algorithm = dhe_psk}, connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - kex_algorithm = dhe_psk, diffie_hellman_keys = {DhPubKey, _}} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dhe_psk, @@ -1928,9 +1940,9 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{kex_algorithm = ecdhe_psk}, connection_env = #connection_env{negotiated_version = Version}, ssl_options = SslOpts, - kex_algorithm = ecdhe_psk, diffie_hellman_keys = ECDHKeys} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdhe_psk, @@ -1938,18 +1950,18 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{public_key_info = PublicKeyInfo, - premaster_secret = PremasterSecret}, + handshake_env = #handshake_env{kex_algorithm = rsa_psk, + public_key_info = PublicKeyInfo, + premaster_secret = PremasterSecret}, connection_env = #connection_env{negotiated_version = Version}, - ssl_options = SslOpts, - kex_algorithm = rsa_psk} + ssl_options = SslOpts} = State0, Connection) -> Msg = rsa_psk_key_exchange(ssl:tls_version(Version), SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{kex_algorithm = KexAlg}, connection_env = #connection_env{negotiated_version = Version}, - kex_algorithm = KexAlg, srp_keys = {ClientPubKey, _}} = State0, Connection) when KexAlg == srp_dss; @@ -1991,7 +2003,7 @@ rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, rsa_psk_key_exchange(_, _, _, _) -> throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE, pub_key_is_not_rsa)). -request_client_cert(#state{kex_algorithm = Alg} = State, _) +request_client_cert(#state{handshake_env = #handshake_env{kex_algorithm = Alg}} = State, _) when Alg == dh_anon; Alg == ecdh_anon; Alg == psk; diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 1e4907661a..72fc2b2c40 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -69,6 +69,7 @@ hashsign_algorithm = {undefined, undefined}, cert_hashsign_algorithm = {undefined, undefined}, %% key exchange + kex_algorithm :: ssl:key_algo(), diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), srp_params :: #srp_user{} | secret_printout() | 'undefined', public_key_info :: ssl_handshake:public_key_info() | 'undefined', @@ -101,7 +102,6 @@ %% need to worry about packet loss in TLS. In DTLS we %% need to track DTLS handshake seqnr flight_buffer = [] :: list() | map(), - kex_algorithm :: ssl:key_algo(), client_certificate_requested = false :: boolean(), diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 7d523a7409..4163adb20b 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -532,11 +532,11 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, port = Port, session_cache = Cache, session_cache_cb = CacheCb}, - handshake_env = #handshake_env{renegotiation = {Renegotiation, _}, + handshake_env = #handshake_env{kex_algorithm = KeyExAlg, + renegotiation = {Renegotiation, _}, negotiated_protocol = CurrentProtocol} = HsEnv, connection_env = CEnv, session = #session{own_certificate = Cert} = Session0, - kex_algorithm = KeyExAlg, ssl_options = SslOpts} = State) -> case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of -- cgit v1.2.3 From effb38acb2abddf3312262e8e8fa003613073b47 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 8 Feb 2019 23:25:50 +0100 Subject: ssl: Move and rename diffie_hellman_keys and srp_keys to kex_keys --- lib/ssl/src/ssl_connection.erl | 116 ++++++++++++++++++++--------------------- lib/ssl/src/ssl_connection.hrl | 5 +- 2 files changed, 58 insertions(+), 63 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index d378f96a20..b90893484a 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1433,8 +1433,6 @@ format_status(terminate, [_, StateName, State]) -> handshake_env = ?SECRET_PRINTOUT, connection_env = ?SECRET_PRINTOUT, session = ?SECRET_PRINTOUT, - diffie_hellman_keys = ?SECRET_PRINTOUT, - srp_keys = ?SECRET_PRINTOUT, ssl_options = NewOptions, flight_buffer = ?SECRET_PRINTOUT} }}]}]. @@ -1555,21 +1553,13 @@ handle_peer_cert(Role, PeerCert, PublicKeyInfo, handle_peer_cert_key(client, _, {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams}, - KeyAlg, #state{session = Session} = State) when KeyAlg == ecdh_rsa; + KeyAlg, #state{handshake_env = HsEnv, + session = Session} = State) when KeyAlg == ecdh_rsa; KeyAlg == ecdh_ecdsa -> ECDHKey = public_key:generate_key(PublicKeyParams), PremasterSecret = ssl_handshake:premaster_secret(PublicKey, ECDHKey), - master_secret(PremasterSecret, State#state{diffie_hellman_keys = ECDHKey, + master_secret(PremasterSecret, State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKey}, session = Session#session{ecc = PublicKeyParams}}); -%% We do currently not support cipher suites that use fixed DH. -%% If we want to implement that the following clause can be used -%% to extract DH parameters form cert. -%% handle_peer_cert_key(client, _PeerCert, {?dhpublicnumber, PublicKey, PublicKeyParams}, -%% {_,SignAlg}, -%% #state{diffie_hellman_keys = {_, MyPrivatKey}} = State) when -%% SignAlg == dh_rsa; -%% SignAlg == dh_dss -> -%% dh_master_secret(PublicKeyParams, PublicKey, MyPrivatKey, State); handle_peer_cert_key(_, _, _, _, State) -> State. @@ -1653,14 +1643,15 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS end, calculate_master_secret(PremasterSecret, State, Connection, certify, cipher); certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey}, - #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params}, - diffie_hellman_keys = {_, ServerDhPrivateKey}} = State, + #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, + kex_keys = {_, ServerDhPrivateKey}} + } = State, Connection) -> PremasterSecret = ssl_handshake:premaster_secret(ClientPublicDhKey, ServerDhPrivateKey, Params), calculate_master_secret(PremasterSecret, State, Connection, certify, cipher); certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint}, - #state{diffie_hellman_keys = ECDHKey} = State, Connection) -> + #state{handshake_env = #handshake_env{kex_keys = ECDHKey}} = State, Connection) -> PremasterSecret = ssl_handshake:premaster_secret(#'ECPoint'{point = ClientPublicEcDhPoint}, ECDHKey), calculate_master_secret(PremasterSecret, State, Connection, certify, cipher); certify_client_key_exchange(#client_psk_identity{} = ClientKey, @@ -1670,8 +1661,8 @@ certify_client_key_exchange(#client_psk_identity{} = ClientKey, PremasterSecret = ssl_handshake:premaster_secret(ClientKey, PSKLookup), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher); certify_client_key_exchange(#client_dhe_psk_identity{} = ClientKey, - #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params}, - diffie_hellman_keys = {_, ServerDhPrivateKey}, + #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params, + kex_keys = {_, ServerDhPrivateKey}}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State0, Connection) -> @@ -1679,7 +1670,7 @@ certify_client_key_exchange(#client_dhe_psk_identity{} = ClientKey, ssl_handshake:premaster_secret(ClientKey, ServerDhPrivateKey, Params, PSKLookup), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher); certify_client_key_exchange(#client_ecdhe_psk_identity{} = ClientKey, - #state{diffie_hellman_keys = ServerEcDhPrivateKey, + #state{handshake_env = #handshake_env{kex_keys = ServerEcDhPrivateKey}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State, Connection) -> @@ -1694,8 +1685,8 @@ certify_client_key_exchange(#client_rsa_psk_identity{} = ClientKey, PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, PSKLookup), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher); certify_client_key_exchange(#client_srp_public{} = ClientKey, - #state{handshake_env = #handshake_env{srp_params = Params}, - srp_keys = Key + #state{handshake_env = #handshake_env{srp_params = Params, + kex_keys = Key} } = State0, Connection) -> PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, Params), calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher). @@ -1740,15 +1731,15 @@ key_exchange(#state{static_env = #static_env{role = server}, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), - State = Connection:queue_handshake(Msg, State0), - State#state{diffie_hellman_keys = DHKeys}; + #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0), + State#state{handshake_env = HsEnv#handshake_env{kex_keys = DHKeys}}; key_exchange(#state{static_env = #static_env{role = server}, - handshake_env =#handshake_env{kex_algorithm = KexAlg}, + handshake_env = #handshake_env{kex_algorithm = KexAlg} = HsEnv, connection_env = #connection_env{private_key = #'ECPrivateKey'{parameters = ECCurve} = Key}, session = Session} = State, _) when KexAlg == ecdh_ecdsa; KexAlg == ecdh_rsa -> - State#state{diffie_hellman_keys = Key, + State#state{handshake_env = HsEnv#handshake_env{kex_keys = Key}, session = Session#session{ecc = ECCurve}}; key_exchange(#state{static_env = #static_env{role = server}, handshake_env = #handshake_env{kex_algorithm = KexAlg, @@ -1771,8 +1762,8 @@ key_exchange(#state{static_env = #static_env{role = server}, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), - State = Connection:queue_handshake(Msg, State0), - State#state{diffie_hellman_keys = ECDHKeys}; + #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0), + State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys}}; key_exchange(#state{static_env = #static_env{role = server}, handshake_env = #handshake_env{kex_algorithm = psk}, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> @@ -1792,7 +1783,7 @@ key_exchange(#state{static_env = #static_env{role = server}, {psk, PskIdentityHint, HashSignAlgo, ClientRandom, ServerRandom, - PrivateKey}), + PrivateKey}), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = server}, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, @@ -1814,8 +1805,8 @@ key_exchange(#state{static_env = #static_env{role = server}, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), - State = Connection:queue_handshake(Msg, State0), - State#state{diffie_hellman_keys = DHKeys}; + #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0), + State#state{handshake_env = HsEnv#handshake_env{kex_keys = DHKeys}}; key_exchange(#state{static_env = #static_env{role = server}, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, handshake_env = #handshake_env{kex_algorithm = ecdhe_psk, @@ -1836,8 +1827,8 @@ key_exchange(#state{static_env = #static_env{role = server}, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), - State = Connection:queue_handshake(Msg, State0), - State#state{diffie_hellman_keys = ECDHKeys}; + #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0), + State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys}}; key_exchange(#state{static_env = #static_env{role = server}, handshake_env = #handshake_env{kex_algorithm = rsa_psk}, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> @@ -1889,8 +1880,8 @@ key_exchange(#state{static_env = #static_env{role = server}, ServerRandom, PrivateKey}), #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0), - State#state{handshake_env = HsEnv#handshake_env{srp_params = SrpParams}, - srp_keys = Keys}; + State#state{handshake_env = HsEnv#handshake_env{srp_params = SrpParams, + kex_keys = Keys}}; key_exchange(#state{static_env = #static_env{role = client}, handshake_env = #handshake_env{kex_algorithm = rsa, public_key_info = PublicKeyInfo, @@ -1900,10 +1891,10 @@ key_exchange(#state{static_env = #static_env{role = client}, Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{kex_algorithm = KexAlg}, - connection_env = #connection_env{negotiated_version = Version}, - diffie_hellman_keys = {DhPubKey, _} - } = State0, Connection) + handshake_env = #handshake_env{kex_algorithm = KexAlg, + kex_keys = {DhPubKey, _}}, + connection_env = #connection_env{negotiated_version = Version} + } = State0, Connection) when KexAlg == dhe_dss; KexAlg == dhe_rsa; KexAlg == dh_anon -> @@ -1911,10 +1902,11 @@ key_exchange(#state{static_env = #static_env{role = client}, Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{kex_algorithm = KexAlg}, + handshake_env = #handshake_env{kex_algorithm = KexAlg, + kex_keys = #'ECPrivateKey'{parameters = ECCurve} = Key}, connection_env = #connection_env{negotiated_version = Version}, - session = Session, - diffie_hellman_keys = #'ECPrivateKey'{parameters = ECCurve} = Key} = State0, Connection) + session = Session + } = State0, Connection) when KexAlg == ecdhe_ecdsa; KexAlg == ecdhe_rsa; KexAlg == ecdh_ecdsa; @@ -1930,20 +1922,20 @@ key_exchange(#state{static_env = #static_env{role = client}, {psk, SslOpts#ssl_options.psk_identity}), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{kex_algorithm = dhe_psk}, + handshake_env = #handshake_env{kex_algorithm = dhe_psk, + kex_keys = {DhPubKey, _}}, connection_env = #connection_env{negotiated_version = Version}, - ssl_options = SslOpts, - diffie_hellman_keys = {DhPubKey, _}} = State0, Connection) -> + ssl_options = SslOpts} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{kex_algorithm = ecdhe_psk}, + handshake_env = #handshake_env{kex_algorithm = ecdhe_psk, + kex_keys = ECDHKeys}, connection_env = #connection_env{negotiated_version = Version}, - ssl_options = SslOpts, - diffie_hellman_keys = ECDHKeys} = State0, Connection) -> + ssl_options = SslOpts} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdhe_psk, SslOpts#ssl_options.psk_identity, ECDHKeys}), @@ -1960,9 +1952,9 @@ key_exchange(#state{static_env = #static_env{role = client}, PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); key_exchange(#state{static_env = #static_env{role = client}, - handshake_env = #handshake_env{kex_algorithm = KexAlg}, - connection_env = #connection_env{negotiated_version = Version}, - srp_keys = {ClientPubKey, _}} + handshake_env = #handshake_env{kex_algorithm = KexAlg, + kex_keys = {ClientPubKey, _}}, + connection_env = #connection_env{negotiated_version = Version}} = State0, Connection) when KexAlg == srp_dss; KexAlg == srp_rsa; @@ -2102,21 +2094,22 @@ save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbrev calculate_secret(#server_dh_params{dh_p = Prime, dh_g = Base, dh_y = ServerPublicDhKey} = Params, - State, Connection) -> + #state{handshake_env = HsEnv} = State, Connection) -> Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]), PremasterSecret = ssl_handshake:premaster_secret(ServerPublicDhKey, PrivateDhKey, Params), calculate_master_secret(PremasterSecret, - State#state{diffie_hellman_keys = Keys}, + State#state{handshake_env = HsEnv#handshake_env{kex_keys = Keys}}, Connection, certify, certify); calculate_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey}, - State=#state{session=Session}, Connection) -> + #state{handshake_env = HsEnv, + session = Session} = State, Connection) -> ECDHKeys = public_key:generate_key(ECCurve), PremasterSecret = ssl_handshake:premaster_secret(#'ECPoint'{point = ECServerPubKey}, ECDHKeys), calculate_master_secret(PremasterSecret, - State#state{diffie_hellman_keys = ECDHKeys, + State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys}, session = Session#session{ecc = ECCurve}}, Connection, certify, certify); @@ -2130,32 +2123,35 @@ calculate_secret(#server_psk_params{ calculate_secret(#server_dhe_psk_params{ dh_params = #server_dh_params{dh_p = Prime, dh_g = Base}} = ServerKey, - #state{ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = + #state{handshake_env = HsEnv, + ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State, Connection) -> Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]), PremasterSecret = ssl_handshake:premaster_secret(ServerKey, PrivateDhKey, PSKLookup), - calculate_master_secret(PremasterSecret, State#state{diffie_hellman_keys = Keys}, + calculate_master_secret(PremasterSecret, State#state{handshake_env = HsEnv#handshake_env{kex_keys = Keys}}, Connection, certify, certify); calculate_secret(#server_ecdhe_psk_params{ dh_params = #server_ecdh_params{curve = ECCurve}} = ServerKey, #state{ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = - State=#state{session=Session}, Connection) -> + #state{handshake_env = HsEnv, + session = Session} = State, Connection) -> ECDHKeys = public_key:generate_key(ECCurve), PremasterSecret = ssl_handshake:premaster_secret(ServerKey, ECDHKeys, PSKLookup), calculate_master_secret(PremasterSecret, - State#state{diffie_hellman_keys = ECDHKeys, + State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys}, session = Session#session{ecc = ECCurve}}, Connection, certify, certify); calculate_secret(#server_srp_params{srp_n = Prime, srp_g = Generator} = ServerKey, - #state{ssl_options = #ssl_options{srp_identity = SRPId}} = State, + #state{handshake_env = HsEnv, + ssl_options = #ssl_options{srp_identity = SRPId}} = State, Connection) -> Keys = generate_srp_client_keys(Generator, Prime, 0), PremasterSecret = ssl_handshake:premaster_secret(ServerKey, Keys, SRPId), - calculate_master_secret(PremasterSecret, State#state{srp_keys = Keys}, Connection, + calculate_master_secret(PremasterSecret, State#state{handshake_env = HsEnv#handshake_env{kex_keys = Keys}}, Connection, certify, certify). master_secret(#alert{} = Alert, _) -> diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 72fc2b2c40..eac803bee7 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -69,7 +69,8 @@ hashsign_algorithm = {undefined, undefined}, cert_hashsign_algorithm = {undefined, undefined}, %% key exchange - kex_algorithm :: ssl:key_algo(), + kex_algorithm :: ssl:key_algo(), + kex_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), srp_params :: #srp_user{} | secret_printout() | 'undefined', public_key_info :: ssl_handshake:public_key_info() | 'undefined', @@ -103,8 +104,6 @@ %% need to track DTLS handshake seqnr flight_buffer = [] :: list() | map(), client_certificate_requested = false :: boolean(), - diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), - srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', protocol_specific = #{} :: map(), session :: #session{} | secret_printout(), %% Data shuffling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From 8e83ba4791073274d58891c5ea0da53df1bd1cdb Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 11 Feb 2019 18:23:04 +0100 Subject: ssl: Use gen_statem named timers to handle connection and recv timeouts --- lib/ssl/src/dtls_connection.erl | 6 +-- lib/ssl/src/ssl_connection.erl | 105 ++++++++++++++++------------------------ lib/ssl/src/ssl_connection.hrl | 3 +- lib/ssl/src/tls_connection.erl | 6 +-- 4 files changed, 47 insertions(+), 73 deletions(-) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 19c6008374..7a91578fe2 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -431,7 +431,6 @@ init({call, From}, {start, Timeout}, session = #session{own_certificate = Cert} = Session0, connection_states = ConnectionStates0 } = State0) -> - Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From), Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Cache, CacheCb, Renegotiation, Cert), @@ -442,10 +441,9 @@ init({call, From}, {start, Timeout}, State3 = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% RequestedVersion session = Session0#session{session_id = Hello#client_hello.session_id}, - start_or_recv_from = From, - timer = Timer}, + start_or_recv_from = From}, {Record, State} = next_record(State3), - next_event(hello, Record, State, Actions); + next_event(hello, Record, State, [{{timeout, handshake}, Timeout, close} | Actions]); init({call, _} = Type, Event, #state{static_env = #static_env{role = server}, protocol_specific = PS} = State) -> Result = gen_handshake(?FUNCTION_NAME, Type, Event, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index b90893484a..6206d15c13 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -40,7 +40,7 @@ -export([connect/8, handshake/7, handshake/2, handshake/3, handshake_continue/3, handshake_cancel/1, - socket_control/4, socket_control/5, start_or_recv_cancel_timer/2]). + socket_control/4, socket_control/5]). %% User Events -export([send/2, recv/3, close/2, shutdown/2, @@ -199,10 +199,6 @@ socket_control(dtls_connection = Connection, {_, Socket}, [Pid|_] = Pids, Transp {error, Reason} end. -start_or_recv_cancel_timer(infinity, _RecvFrom) -> - undefined; -start_or_recv_cancel_timer(Timeout, RecvFrom) -> - erlang:send_after(Timeout, self(), {cancel_start_or_recv, RecvFrom}). %%==================================================================== %% User events @@ -446,17 +442,24 @@ handle_alert(#alert{level = ?WARNING} = Alert, StateName, %%==================================================================== %% Data handling %%==================================================================== -passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName, Connection) -> +passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName, Connection, StartTimerAction) -> case Buffer of <<>> -> {Record, State} = Connection:next_record(State0), - Connection:next_event(StateName, Record, State); + Connection:next_event(StateName, Record, State, StartTimerAction); _ -> case read_application_data(<<>>, State0) of {stop, _, _} = ShutdownError -> ShutdownError; {Record, State} -> - Connection:next_event(StateName, Record, State) + case State#state.start_or_recv_from of + undefined -> + %% Cancel recv timeout as data has been delivered + Connection:next_event(StateName, Record, State, + [{{timeout, recv}, infinity, timeout}]); + _ -> + Connection:next_event(StateName, Record, State, StartTimerAction) + end end end. @@ -472,10 +475,9 @@ read_application_data( #state{ socket_options = SocketOpts, bytes_to_read = BytesToRead, - start_or_recv_from = RecvFrom, - timer = Timer} = State, + start_or_recv_from = RecvFrom} = State, read_application_data( - Buffer, State, SocketOpts, RecvFrom, Timer, BytesToRead); + Buffer, State, SocketOpts, RecvFrom, BytesToRead); _ -> try read_application_dist_data(Buffer, State, DHandle) catch error:_ -> @@ -505,7 +507,7 @@ read_application_dist_data(Buffer, State, DHandle) -> end. read_application_data( - Buffer0, State, SocketOpts0, RecvFrom, Timer, BytesToRead) -> + Buffer0, State, SocketOpts0, RecvFrom, BytesToRead) -> %% case get_data(SocketOpts0, BytesToRead, Buffer0) of {ok, ClientData, Buffer} -> % Send data @@ -523,24 +525,21 @@ read_application_data( Connection:pids(State), Transport, Socket, SocketOpts0, ClientData, Pid, RecvFrom, Tracker, Connection), - cancel_timer(Timer), if - SocketOpts#socket_options.active =:= false; - Buffer =:= <<>> -> + SocketOpts#socket_options.active =:= false -> %% Passive mode, wait for active once or recv %% Active and empty, get more data {no_record, State#state{ user_data_buffer = Buffer, - start_or_recv_from = undefined, - timer = undefined, + start_or_recv_from = undefined, bytes_to_read = undefined, socket_options = SocketOpts }}; true -> %% We have more data read_application_data( Buffer, State, SocketOpts, - undefined, undefined, undefined) + undefined, undefined) end; {more, Buffer} -> % no reply, we need more data {no_record, State#state{user_data_buffer = Buffer}}; @@ -646,8 +645,8 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0, %%-------------------------------------------------------------------- init({call, From}, {start, Timeout}, State0, Connection) -> - Timer = start_or_recv_cancel_timer(Timeout, From), - Connection:next_event(hello, no_record, State0#state{start_or_recv_from = From, timer = Timer}); + Connection:next_event(hello, no_record, State0#state{start_or_recv_from = From}, + [{{timeout, handshake}, Timeout, close}]); init({call, From}, {start, {Opts, EmOpts}, Timeout}, #state{static_env = #static_env{role = Role}, ssl_options = OrigSSLOptions, @@ -701,14 +700,11 @@ user_hello({call, From}, cancel, #state{connection_env = #connection_env{negotia user_hello({call, From}, {handshake_continue, NewOptions, Timeout}, #state{static_env = #static_env{role = Role}, handshake_env = #handshake_env{hello = Hello}, - start_or_recv_from = RecvFrom, ssl_options = Options0} = State0, _Connection) -> - Timer = start_or_recv_cancel_timer(Timeout, RecvFrom), Options = ssl:handle_options(NewOptions, Options0#ssl_options{handshake = full}), State = ssl_config(Options, Role, State0), - {next_state, hello, State#state{start_or_recv_from = From, - timer = Timer}, - [{next_event, internal, Hello}]}; + {next_state, hello, State#state{start_or_recv_from = From}, + [{next_event, internal, Hello}, {{timeout, handshake}, Timeout, close}]}; user_hello(_, _, _, _) -> {keep_state_and_data, [postpone]}. @@ -736,7 +732,7 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), {Record, State} = prepare_connection(State0#state{connection_states = ConnectionStates, handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection), - Connection:next_event(connection, Record, State); + Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close}]); #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0) end; @@ -756,7 +752,7 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, finalize_handshake(State0#state{connection_states = ConnectionStates1}, ?FUNCTION_NAME, Connection), {Record, State} = prepare_connection(State1#state{handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection), - Connection:next_event(connection, Record, State, Actions); + Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close} | Actions]); #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0) end; @@ -1093,10 +1089,9 @@ connection({call, RecvFrom}, {recv, N, Timeout}, #state{static_env = #static_env{protocol_cb = Connection}, socket_options = #socket_options{active = false}} = State0, Connection) -> - Timer = start_or_recv_cancel_timer(Timeout, RecvFrom), passive_receive(State0#state{bytes_to_read = N, - start_or_recv_from = RecvFrom, - timer = Timer}, ?FUNCTION_NAME, Connection); + start_or_recv_from = RecvFrom}, ?FUNCTION_NAME, Connection, + [{{timeout, recv}, Timeout, timeout}]); connection({call, From}, renegotiate, #state{static_env = #static_env{protocol_cb = Connection}, handshake_env = HsEnv} = State, @@ -1140,8 +1135,8 @@ connection(cast, {dist_handshake_complete, DHandle}, Connection:next_event(connection, Record, State); connection(info, Msg, State, _) -> handle_info(Msg, ?FUNCTION_NAME, State); -connection(internal, {recv, _}, State, Connection) -> - passive_receive(State, ?FUNCTION_NAME, Connection); +connection(internal, {recv, Timeout}, State, Connection) -> + passive_receive(State, ?FUNCTION_NAME, Connection, [{{timeout, recv}, Timeout, timeout}]); connection(Type, Msg, State, Connection) -> handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). @@ -1188,7 +1183,15 @@ handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State, _) -> handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version, StateName, State); -handle_common_event(_Type, Msg, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State, +handle_common_event({timeout, handshake}, close, _StateName, #state{start_or_recv_from = StartFrom} = State, _) -> + {stop_and_reply, + {shutdown, user_timeout}, + {reply, StartFrom, {error, timeout}}, State#state{start_or_recv_from = undefined}}; +handle_common_event({timeout, recv}, timeout, StateName, #state{start_or_recv_from = RecvFrom} = State, _) -> + {next_state, StateName, State#state{start_or_recv_from = undefined, + bytes_to_read = undefined}, [{reply, RecvFrom, {error, timeout}}]}; +handle_common_event(_Type, Msg, StateName, #state{connection_env = + #connection_env{negotiated_version = Version}} = State, _) -> Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, {unexpected_msg, Msg}), handle_own_alert(Alert, Version, StateName, State). @@ -1239,10 +1242,8 @@ handle_call({recv, _N, _Timeout}, From, _, handle_call({recv, N, Timeout}, RecvFrom, StateName, State, _) -> %% Doing renegotiate wait with handling request until renegotiate is %% finished. - Timer = start_or_recv_cancel_timer(Timeout, RecvFrom), - {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom, - timer = Timer}, - [{next_event, internal, {recv, RecvFrom}}]}; + {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom}, + [{next_event, internal, {recv, RecvFrom}} , {{timeout, recv}, Timeout, timeout}]}; handle_call({new_user, User}, From, StateName, State = #state{connection_env = #connection_env{user_application = {OldMon, _}} = CEnv}, _) -> NewMon = erlang:monitor(process, User), @@ -1344,20 +1345,6 @@ handle_info({'EXIT', Socket, Reason}, _StateName, #state{static_env = #static_en handle_info(allow_renegotiate, StateName, #state{handshake_env = HsEnv} = State) -> {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{allow_renegotiate = true}}}; -handle_info({cancel_start_or_recv, StartFrom}, StateName, - #state{handshake_env = #handshake_env{renegotiation = {false, first}}} = State) when StateName =/= connection -> - {stop_and_reply, - {shutdown, user_timeout}, - {reply, StartFrom, {error, timeout}}, - State#state{timer = undefined}}; -handle_info({cancel_start_or_recv, RecvFrom}, StateName, - #state{start_or_recv_from = RecvFrom} = State) when RecvFrom =/= undefined -> - {next_state, StateName, State#state{start_or_recv_from = undefined, - bytes_to_read = undefined, - timer = undefined}, [{reply, RecvFrom, {error, timeout}}]}; -handle_info({cancel_start_or_recv, _RecvFrom}, StateName, State) -> - {next_state, StateName, State#state{timer = undefined}}; - handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, error_tag = Tag}} = State) -> Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [{Msg, Tag, Socket}]), error_logger:info_report(Report), @@ -2218,7 +2205,7 @@ cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} {Record, State} = prepare_connection(State0#state{session = Session, connection_states = ConnectionStates}, Connection), - Connection:next_event(connection, Record, State); + Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close}]); cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State0, Connection) -> ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, @@ -2227,7 +2214,7 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0 finalize_handshake(State0#state{connection_states = ConnectionStates1, session = Session}, cipher, Connection), {Record, State} = prepare_connection(State1, Connection), - Connection:next_event(connection, Record, State, Actions). + Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close} | Actions]). is_anonymous(KexAlg) when KexAlg == dh_anon; KexAlg == ecdh_anon; @@ -2429,21 +2416,13 @@ ack_connection(#state{handshake_env = #handshake_env{renegotiation = {true, From gen_statem:reply(From, ok), State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}; ack_connection(#state{handshake_env = #handshake_env{renegotiation = {false, first}} = HsEnv, - start_or_recv_from = StartFrom, - timer = Timer} = State) when StartFrom =/= undefined -> + start_or_recv_from = StartFrom} = State) when StartFrom =/= undefined -> gen_statem:reply(StartFrom, connected), - cancel_timer(Timer), State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}, - start_or_recv_from = undefined, timer = undefined}; + start_or_recv_from = undefined}; ack_connection(State) -> State. -cancel_timer(undefined) -> - ok; -cancel_timer(Timer) -> - erlang:cancel_timer(Timer), - ok. - session_handle_params(#server_ecdh_params{curve = ECCurve}, Session) -> Session#session{ecc = ECCurve}; session_handle_params(_, Session) -> diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index eac803bee7..83013e7fba 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -113,8 +113,7 @@ bytes_to_read :: undefined | integer(), %% bytes to read in passive mode %% recv and start handling - start_or_recv_from :: term(), - timer :: undefined | reference() % start_or_recive_timer + start_or_recv_from :: term() }). diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 4163adb20b..dfae13f6d7 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -470,7 +470,6 @@ init({call, From}, {start, Timeout}, session = #session{own_certificate = Cert} = Session0, connection_states = ConnectionStates0 } = State0) -> - Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From), Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Cache, CacheCb, Renegotiation, Cert), @@ -485,9 +484,8 @@ init({call, From}, {start, Timeout}, session = Session0#session{session_id = Hello#client_hello.session_id}, handshake_env = HsEnv#handshake_env{tls_handshake_history = Handshake}, - start_or_recv_from = From, - timer = Timer}, - next_event(hello, no_record, State); + start_or_recv_from = From}, + next_event(hello, no_record, State, [{{timeout, handshake}, Timeout, close}]); init(Type, Event, State) -> gen_handshake(?FUNCTION_NAME, Type, Event, State). -- cgit v1.2.3 From 93acd2052bacf7377900aaef54a5e8366c978929 Mon Sep 17 00:00:00 2001 From: dimadio Date: Thu, 14 Feb 2019 11:45:21 +0100 Subject: ssl: Add test case for continued handshake with a timeout --- lib/ssl/test/ssl_basic_SUITE.erl | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 72606db628..55d77b441f 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -166,6 +166,7 @@ api_tests() -> socket_options, cipher_suites, handshake_continue, + handshake_continue_timeout, hello_client_cancel, hello_server_cancel ]. @@ -681,6 +682,34 @@ handshake_continue(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +%%------------------------------------------------------------------ +handshake_continue_timeout() -> + [{doc, "Test API function ssl:handshake_continue/3 with short timeout"}]. +handshake_continue_timeout(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {timeout, 1}, + {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}], + Config)}, + {continue_options, proplists:delete(reuseaddr, ServerOpts)} + ]), + + Port = ssl_test_lib:inet_port(Server), + + + {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, {error,timeout}), + ssl_test_lib:close(Server). + + %%-------------------------------------------------------------------- hello_client_cancel() -> [{doc, "Test API function ssl:handshake_cancel/1 on the client side"}]. -- cgit v1.2.3 From 730a71a030c30bf233b25cf4aaae47574ea066b8 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 14 Feb 2019 13:29:57 +0100 Subject: ssl: Remove duplicate record_cb handling --- lib/ssl/src/ssl.erl | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index a7d6f28c7a..c39a6f1603 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -1202,7 +1202,6 @@ handle_options(Opts0, Role, Host) -> handle_verify_options(Opts, CaCerts), CertFile = handle_option(certfile, Opts, <<>>), - RecordCb = record_cb(Opts), Versions = case handle_option(versions, Opts, []) of [] -> -- cgit v1.2.3