diff options
Diffstat (limited to 'lib/ssl/src')
-rw-r--r-- | lib/ssl/src/ssl.erl | 31 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 97 | ||||
-rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 12 | ||||
-rw-r--r-- | lib/ssl/src/tls_connection.erl | 15 | ||||
-rw-r--r-- | lib/ssl/src/tls_handshake.erl | 3 |
5 files changed, 92 insertions, 66 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index dbbb25025c..51732b4a59 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -400,24 +400,23 @@ negotiated_next_protocol(Socket) -> end. %%-------------------------------------------------------------------- +-spec cipher_suites() -> [ssl_cipher:erl_cipher_suite()] | [string()]. +%%-------------------------------------------------------------------- +cipher_suites() -> + cipher_suites(erlang). +%%-------------------------------------------------------------------- -spec cipher_suites(erlang | openssl | all) -> [ssl_cipher:erl_cipher_suite()] | [string()]. %% Description: Returns all supported cipher suites. %%-------------------------------------------------------------------- cipher_suites(erlang) -> - Version = tls_record:highest_protocol_version([]), - ssl_cipher:filter_suites([ssl_cipher:erl_suite_definition(S) - || S <- ssl_cipher:suites(Version)]); + [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(default)]; + cipher_suites(openssl) -> - Version = tls_record:highest_protocol_version([]), - [ssl_cipher:openssl_suite_name(S) - || S <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))]; + [ssl_cipher:openssl_suite_name(Suite) || Suite <- available_suites(default)]; + cipher_suites(all) -> - Version = tls_record:highest_protocol_version([]), - ssl_cipher:filter_suites([ssl_cipher:erl_suite_definition(S) - || S <-ssl_cipher:all_suites(Version)]). -cipher_suites() -> - cipher_suites(erlang). + [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(all)]. %%-------------------------------------------------------------------- -spec getopts(#sslsocket{}, [gen_tcp:option_name()]) -> @@ -584,6 +583,16 @@ format_error(Error) -> %%%-------------------------------------------------------------- %%% Internal functions %%%-------------------------------------------------------------------- + +%% Possible filters out suites not supported by crypto +available_suites(default) -> + Version = tls_record:highest_protocol_version([]), + ssl_cipher:filter_suites(ssl_cipher:suites(Version)); + +available_suites(all) -> + Version = tls_record:highest_protocol_version([]), + ssl_cipher:filter_suites(ssl_cipher:all_suites(Version)). + do_connect(Address, Port, #config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts, emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb}, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 57fa1b904e..089b3615c6 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -875,48 +875,14 @@ handle_call({get_opts, OptTags}, From, _, socket_options = SockOpts}, _) -> OptsReply = get_socket_opts(Transport, Socket, OptTags, SockOpts, []), {keep_state_and_data, [{reply, From, OptsReply}]}; -handle_call({set_opts, Opts0}, From, connection = StateName0, +handle_call({set_opts, Opts0}, From, StateName, #state{socket_options = Opts1, - protocol_cb = Connection, socket = Socket, - transport_cb = Transport, - user_data_buffer = Buffer} = State0, _) -> + transport_cb = Transport} = State0, _) -> {Reply, Opts} = set_socket_opts(Transport, Socket, Opts0, Opts1, []), - State1 = State0#state{socket_options = Opts}, - if - Opts#socket_options.active =:= false -> - hibernate_after(StateName0, State1, [{reply, From, Reply}]); - Buffer =:= <<>>, Opts1#socket_options.active =:= false -> - %% Need data, set active once - {Record, State2} = Connection:next_record_if_active(State1), - %% Note: Renogotiation may cause StateName0 =/= StateName - case Connection:next_event(StateName0, Record, State2) of - {next_state, StateName, State} -> - hibernate_after(StateName, State, [{reply, From, Reply}]); - {next_state, StateName, State, Actions} -> - hibernate_after(StateName, State, [{reply, From, Reply} | Actions]); - {stop, Reason, State} -> - {stop, Reason, State} - end; - Buffer =:= <<>> -> - %% Active once already set - hibernate_after(StateName0, State1, [{reply, From, Reply}]); - true -> - case Connection:read_application_data(<<>>, State1) of - {stop, Reason, State} -> - {stop, Reason, State}; - {Record, State2} -> - %% Note: Renogotiation may cause StateName0 =/= StateName - case Connection:next_event(StateName0, Record, State2) of - {next_state, StateName, State} -> - hibernate_after(StateName, State, [{reply, From, Reply}]); - {next_state, StateName, State, Actions} -> - hibernate_after(StateName, State, [{reply, From, Reply} | Actions]); - {stop, _, _} = Stop -> - Stop - end - end - end; + State = State0#state{socket_options = Opts}, + handle_active_option(Opts#socket_options.active, StateName, From, Reply, State); + handle_call(renegotiate, From, StateName, _, _) when StateName =/= connection -> {keep_state_and_data, [{reply, From, {error, already_renegotiating}}]}; handle_call({prf, Secret, Label, Seed, WantedLength}, From, _, @@ -927,7 +893,8 @@ handle_call({prf, Secret, Label, Seed, WantedLength}, From, _, SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{master_secret = MasterSecret, client_random = ClientRandom, - server_random = ServerRandom} = SecParams, + server_random = ServerRandom, + prf_algorithm = PRFAlgorithm} = SecParams, Reply = try SecretToUse = case Secret of _ when is_binary(Secret) -> Secret; @@ -938,7 +905,7 @@ handle_call({prf, Secret, Label, Seed, WantedLength}, From, _, (client_random, Acc) -> [ClientRandom|Acc]; (server_random, Acc) -> [ServerRandom|Acc] end, [], Seed)), - ssl_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength) + ssl_handshake:prf(Version, PRFAlgorithm, SecretToUse, Label, SeedToUse, WantedLength) catch exit:_ -> {error, badarg}; error:Reason -> {error, Reason} @@ -1875,9 +1842,12 @@ start_or_recv_cancel_timer(infinity, _RecvFrom) -> start_or_recv_cancel_timer(Timeout, RecvFrom) -> erlang:send_after(Timeout, self(), {cancel_start_or_recv, RecvFrom}). -hibernate_after(StateName, #state{ssl_options=#ssl_options{hibernate_after = HibernateAfter}} = State, +hibernate_after(connection = StateName, + #state{ssl_options=#ssl_options{hibernate_after = HibernateAfter}} = State, Actions) -> - {next_state, StateName, State, [{timeout, HibernateAfter, hibernate} | Actions]}. + {next_state, StateName, State, [{timeout, HibernateAfter, hibernate} | Actions]}; +hibernate_after(StateName, State, Actions) -> + {next_state, StateName, State, Actions}. terminate_alert(normal, Version, ConnectionStates) -> ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), @@ -1920,9 +1890,11 @@ prepare_connection(#state{renegotiation = Renegotiate, start_or_recv_from = RecvFrom} = State0, Connection) when Renegotiate =/= {false, first}, RecvFrom =/= undefined -> - {Record, State} = Connection:next_record(State0), + State1 = Connection:reinit_handshake_data(State0), + {Record, State} = Connection:next_record(State1), {Record, ack_connection(State)}; -prepare_connection(State, _) -> +prepare_connection(State0, Connection) -> + State = Connection:reinit_handshake_data(State0), {no_record, ack_connection(State)}. ack_connection(#state{renegotiation = {true, Initiater}} = State) @@ -2029,4 +2001,39 @@ ssl_options_list([ciphers = Key | Keys], [Value | Values], Acc) -> ssl_options_list([Key | Keys], [Value | Values], Acc) -> ssl_options_list(Keys, Values, [{Key, Value} | Acc]). +handle_active_option(false, connection = StateName, To, Reply, State) -> + hibernate_after(StateName, State, [{reply, To, Reply}]); + +handle_active_option(_, connection = StateName0, To, Reply, #state{protocol_cb = Connection, + user_data_buffer = <<>>} = State0) -> + %% Need data, set active once + {Record, State1} = Connection:next_record_if_active(State0), + %% Note: Renogotiation may cause StateName0 =/= StateName + case Connection:next_event(StateName0, Record, State1) of + {next_state, StateName, State} -> + hibernate_after(StateName, State, [{reply, To, Reply}]); + {next_state, StateName, State, Actions} -> + hibernate_after(StateName, State, [{reply, To, Reply} | Actions]); + {stop, Reason, State} -> + {stop, Reason, State} + end; +handle_active_option(_, StateName, To, Reply, #state{user_data_buffer = <<>>} = State) -> + %% Active once already set + {next_state, StateName, State, [{reply, To, Reply}]}; +%% user_data_buffer =/= <<>> +handle_active_option(_, StateName0, To, Reply, #state{protocol_cb = Connection} = State0) -> + case Connection:read_application_data(<<>>, State0) of + {stop, Reason, State} -> + {stop, Reason, State}; + {Record, State1} -> + %% Note: Renogotiation may cause StateName0 =/= StateName + case Connection:next_event(StateName0, Record, State1) of + {next_state, StateName, State} -> + hibernate_after(StateName, State, [{reply, To, Reply}]); + {next_state, StateName, State, Actions} -> + hibernate_after(StateName, State, [{reply, To, Reply} | Actions]); + {stop, _, _} = Stop -> + Stop + end + end. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 2a2a7b7d25..598d4e4112 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -74,7 +74,7 @@ ]). %% MISC --export([select_version/3, prf/5, select_hashsign/5, +-export([select_version/3, prf/6, select_hashsign/5, select_hashsign_algs/3, premaster_secret/2, premaster_secret/3, premaster_secret/4]). @@ -564,17 +564,15 @@ server_key_exchange_hash(md5sha, Value) -> server_key_exchange_hash(Hash, Value) -> crypto:hash(Hash, Value). %%-------------------------------------------------------------------- --spec prf(ssl_record:ssl_version(), binary(), binary(), [binary()], non_neg_integer()) -> +-spec prf(ssl_record:ssl_version(), non_neg_integer(), binary(), binary(), [binary()], non_neg_integer()) -> {ok, binary()} | {error, undefined}. %% %% Description: use the TLS PRF to generate key material %%-------------------------------------------------------------------- -prf({3,0}, _, _, _, _) -> +prf({3,0}, _, _, _, _, _) -> {error, undefined}; -prf({3,1}, Secret, Label, Seed, WantedLength) -> - {ok, tls_v1:prf(?MD5SHA, Secret, Label, Seed, WantedLength)}; -prf({3,_N}, Secret, Label, Seed, WantedLength) -> - {ok, tls_v1:prf(?SHA256, Secret, Label, Seed, WantedLength)}. +prf({3,_N}, PRFAlgo, Secret, Label, Seed, WantedLength) -> + {ok, tls_v1:prf(PRFAlgo, Secret, Label, Seed, WantedLength)}. %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 2193fc18c2..40f3eea527 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -49,7 +49,8 @@ -export([next_record/1, next_event/3]). %% Handshake handling --export([renegotiate/2, send_handshake/2, send_change_cipher/2]). +-export([renegotiate/2, send_handshake/2, send_change_cipher/2, + reinit_handshake_data/1]). %% Alert and close handling -export([send_alert/2, handle_own_alert/4, handle_close_alert/3, @@ -131,6 +132,16 @@ send_change_cipher(Msg, #state{connection_states = ConnectionStates0, Transport:send(Socket, BinChangeCipher), State0#state{connection_states = ConnectionStates}. +reinit_handshake_data(State) -> + %% premaster_secret, public_key_info and tls_handshake_info + %% are only needed during the handshake phase. + %% To reduce memory foot print of a connection reinitialize them. + State#state{ + premaster_secret = undefined, + public_key_info = undefined, + tls_handshake_history = ssl_handshake:init_handshake_history() + }. + %%==================================================================== %% tls_connection_sup API %%==================================================================== @@ -911,7 +922,7 @@ alert_user(Transport, Tracker, Socket,_, _, _, From, Alert, Role) -> alert_user(Transport, Tracker, Socket, From, Alert, Role) -> alert_user(Transport, Tracker, Socket, false, no_pid, From, Alert, Role). -alert_user(_, _, _, false = Active, Pid, From, Alert, Role) -> +alert_user(_, _, _, false = Active, Pid, From, Alert, Role) when From =/= undefined -> %% If there is an outstanding ssl_accept | recv %% From will be defined and send_or_reply will %% send the appropriate error message. diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl index 102dbba198..f34eebb0e4 100644 --- a/lib/ssl/src/tls_handshake.erl +++ b/lib/ssl/src/tls_handshake.erl @@ -283,7 +283,8 @@ available_signature_algs(undefined, SupportedHashSigns, _, {Major, Minor}) when SupportedHashSigns; available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns, _, {Major, Minor}) when (Major >= 3) andalso (Minor >= 3) -> - ordsets:intersection(ClientHashSigns, SupportedHashSigns); + sets:to_list(sets:intersection(sets:from_list(ClientHashSigns), + sets:from_list(SupportedHashSigns))); available_signature_algs(_, _, _, _) -> undefined. |