From e6d9c7eb9e62e220bfb6a5e1b5c1b991c7b9c121 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 20 Jun 2018 11:47:59 +0200 Subject: ssl: Add psk as anonymous key exchange in ssl_handshake:select_hashsign/5 Failing to recognize psk as an anonymous key exchange would fail the connection when trying to decode an undefined certificate. --- lib/ssl/src/ssl_handshake.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/ssl') diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 3028ae9617..76fc7ae3d1 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1055,7 +1055,8 @@ select_curve(undefined, _, _) -> %%-------------------------------------------------------------------- select_hashsign(_, _, KeyExAlgo, _, _Version) when KeyExAlgo == dh_anon; KeyExAlgo == ecdh_anon; - KeyExAlgo == srp_anon -> + KeyExAlgo == srp_anon; + KeyExAlgo == psk -> {null, anon}; %% The signature_algorithms extension was introduced with TLS 1.2. Ignore it if we have %% negotiated a lower version. -- cgit v1.2.3 From 26ed7aa618b4860340d646f8f2b545857cee1289 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 2 Jul 2018 12:25:08 +0200 Subject: ssl: Add connection information on new cipher_suite format --- lib/ssl/doc/src/ssl.xml | 5 +- lib/ssl/src/ssl_connection.erl | 1 + lib/ssl/test/ssl_basic_SUITE.erl | 122 ++++++++++++++++++++------------------- lib/ssl/test/ssl_test_lib.erl | 34 ++++++++--- 4 files changed, 93 insertions(+), 69 deletions(-) (limited to 'lib/ssl') diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index e3deb1c8a4..6e124c3513 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -1066,7 +1066,7 @@ fun(srp, Username :: string(), UserState :: term()) -> SslSocket = sslsocket() - Item = protocol | cipher_suite | sni_hostname | ecc | session_id | atom() + Item = protocol | selected_cipher_suite | sni_hostname | ecc | session_id | atom() Meaningful atoms, not specified above, are the ssl option names. Result = [{Item::atom(), Value::term()}] Reason = term() @@ -1074,6 +1074,9 @@ fun(srp, Username :: string(), UserState :: term()) ->

Returns the most relevant information about the connection, ssl options that are undefined will be filtered out. Note that values that affect the security of the connection will only be returned if explicitly requested by connection_information/2.

+

The legacy Item = cipher_suite is still supported + and returns the cipher suite on its (undocumented) legacy format. + It should be replaced by selected_cipher_suite.

diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 556c204ab1..8ea4740ea4 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1482,6 +1482,7 @@ connection_info(#state{sni_hostname = SNIHostname, [{protocol, RecordCB:protocol_version(Version)}, {session_id, SessionId}, {cipher_suite, ssl_cipher:erl_suite_definition(CipherSuiteDef)}, + {selected_cipher_suite, CipherSuiteDef}, {sni_hostname, SNIHostname} | CurveInfo] ++ ssl_options_list(Opts). security_info(#state{connection_states = ConnectionStates}) -> diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 959de60f57..305b13e5c4 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -147,8 +147,7 @@ options_tests_tls() -> tls_tcp_reuseaddr]. api_tests() -> - [connection_info, - secret_connection_info, + [secret_connection_info, connection_information, peercert, peercert_with_client_cert, @@ -610,7 +609,16 @@ new_options_in_accept(Config) when is_list(Config) -> [_ , _ | ServerSslOpts] = ssl_test_lib:ssl_options(server_opts, Config), %% Remove non ssl opts {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Version = ssl_test_lib:protocol_options(Config, [{tls, sslv3}, {dtls, dtlsv1}]), - Cipher = ssl_test_lib:protocol_options(Config, [{tls, {rsa,rc4_128,sha}}, {dtls, {rsa,aes_128_cbc,sha}}]), + Cipher = ssl_test_lib:protocol_options(Config, [{tls, #{key_exchange =>rsa, + cipher => rc4_128, + mac => sha, + prf => default_prf + }}, + {dtls, #{key_exchange =>rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf + }}]), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {ssl_extra_opts, [{versions, [Version]}, @@ -739,41 +747,6 @@ prf(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -connection_info() -> - [{doc,"Test the API function ssl:connection_information/2"}]. -connection_info(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()}, - {mfa, {?MODULE, connection_info_result, []}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, connection_info_result, []}}, - {options, - [{ciphers,[{dhe_rsa, aes_128_cbc, sha}]} | - ClientOpts]}]), - - ct:log("Testcase ~p, Client ~p Server ~p ~n", - [self(), Client, Server]), - - Version = ssl_test_lib:protocol_version(Config), - - ServerMsg = ClientMsg = {ok, {Version, {dhe_rsa, aes_128_cbc, sha}}}, - - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - secret_connection_info() -> [{doc,"Test the API function ssl:connection_information/2"}]. secret_connection_info(Config) when is_list(Config) -> @@ -3475,16 +3448,50 @@ tls_tcp_reuseaddr(Config) when is_list(Config) -> honor_server_cipher_order() -> [{doc,"Test API honor server cipher order."}]. honor_server_cipher_order(Config) when is_list(Config) -> - ClientCiphers = [{dhe_rsa, aes_128_cbc, sha}, {dhe_rsa, aes_256_cbc, sha}], - ServerCiphers = [{dhe_rsa, aes_256_cbc, sha}, {dhe_rsa, aes_128_cbc, sha}], -honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, {dhe_rsa, aes_256_cbc, sha}). + ClientCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac => sha, + prf => default_prf}], + ServerCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac =>sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}], + honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac => sha, + prf => default_prf}). honor_client_cipher_order() -> [{doc,"Test API honor server cipher order."}]. honor_client_cipher_order(Config) when is_list(Config) -> - ClientCiphers = [{dhe_rsa, aes_128_cbc, sha}, {dhe_rsa, aes_256_cbc, sha}], - ServerCiphers = [{dhe_rsa, aes_256_cbc, sha}, {dhe_rsa, aes_128_cbc, sha}], -honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, {dhe_rsa, aes_128_cbc, sha}). + ClientCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac => sha, + prf => default_prf}], + ServerCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac =>sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}], +honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}). honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), @@ -4221,7 +4228,7 @@ unordered_protocol_versions_server(Config) when is_list(Config) -> {from, self()}, {mfa, {?MODULE, connection_info_result, []}}, {options, ClientOpts}]), - CipherSuite = first_rsa_suite(ssl:cipher_suites()), + CipherSuite = first_rsa_suite(ssl:cipher_suites(default, 'tlsv1.2')), ServerMsg = ClientMsg = {ok, {'tlsv1.2', CipherSuite}}, ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). @@ -4247,7 +4254,7 @@ unordered_protocol_versions_client(Config) when is_list(Config) -> {mfa, {?MODULE, connection_info_result, []}}, {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]), - CipherSuite = first_rsa_suite(ssl:cipher_suites()), + CipherSuite = first_rsa_suite(ssl:cipher_suites(default, 'tlsv1.2')), ServerMsg = ClientMsg = {ok, {'tlsv1.2', CipherSuite}}, ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). @@ -4964,6 +4971,7 @@ run_suites(Ciphers, Config, Type) -> [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]} end, + ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, ssl_test_lib:filter_suites(Ciphers, Version)]), Result = lists:map(fun(Cipher) -> cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, ssl_test_lib:filter_suites(Ciphers, Version)), @@ -4976,7 +4984,7 @@ run_suites(Ciphers, Config, Type) -> end. erlang_cipher_suite(Suite) when is_list(Suite)-> - ssl_cipher:erl_suite_definition(ssl_cipher:openssl_suite(Suite)); + ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite)); erlang_cipher_suite(Suite) -> Suite. @@ -5028,8 +5036,9 @@ connection_information_result(Socket) -> end. connection_info_result(Socket) -> - {ok, Info} = ssl:connection_information(Socket, [protocol, cipher_suite]), - {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}}. + {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]), + {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}. + version_info_result(Socket) -> {ok, [{version, Version}]} = ssl:connection_information(Socket, [version]), {ok, Version}. @@ -5158,17 +5167,10 @@ try_recv_active_once(Socket) -> {error, einval} = ssl:recv(Socket, 11), ok. -first_rsa_suite([{ecdhe_rsa, _, _} = Suite | _]) -> - Suite; -first_rsa_suite([{dhe_rsa, _, _} = Suite| _]) -> - Suite; -first_rsa_suite([{rsa, _, _} = Suite| _]) -> - Suite; -first_rsa_suite([{ecdhe_rsa, _, _, _} = Suite | _]) -> - Suite; -first_rsa_suite([{dhe_rsa, _, _, _} = Suite| _]) -> - Suite; -first_rsa_suite([{rsa, _, _, _} = Suite| _]) -> +first_rsa_suite([#{key_exchange := UseRSACert} = Suite | Rest]) when + UseRSACert == rsa; + UseRSACert == dhe_rsa; + UseRSACert == ecdhe_rsa -> Suite; first_rsa_suite([_ | Rest]) -> first_rsa_suite(Rest). diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 39acc65f6c..5414b30e04 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -1186,13 +1186,13 @@ common_ciphers(crypto) -> common_ciphers(openssl) -> OpenSslSuites = string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"), - [ssl_cipher:erl_suite_definition(S) + [ssl_cipher:suite_definition(S) || S <- ssl_cipher:suites(tls_record:highest_protocol_version([])), lists:member(ssl_cipher:openssl_suite_name(S), OpenSslSuites) ]. available_suites(Version) -> - [ssl_cipher:erl_suite_definition(Suite) || + [ssl_cipher:suite_definition(Suite) || Suite <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))]. @@ -1274,10 +1274,18 @@ ecdh_dh_anonymous_suites(Version) -> (_) -> false end}]). +psk_suites({3,_} = Version) -> + ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []); psk_suites(Version) -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []). + ssl:filter_cipher_suites(psk_suites(dtls_v1:corresponding_tls_version(Version)), + [{cipher, + fun(rc4_128) -> + false; + (_) -> + true + end}]). -psk_anon_suites(Version) -> +psk_anon_suites({3,_} = Version) -> ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)], [{key_exchange, fun(psk) -> @@ -1286,8 +1294,18 @@ psk_anon_suites(Version) -> true; (_) -> false + end}]); + +psk_anon_suites(Version) -> + ssl:filter_cipher_suites(psk_anon_suites(dtls_v1:corresponding_tls_version(Version)), + [{cipher, + fun(rc4_128) -> + false; + (_) -> + true end}]). + srp_suites() -> ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()], [{key_exchange, @@ -1308,7 +1326,7 @@ srp_dss_suites() -> false end}]). chacha_suites(Version) -> - [ssl_cipher:erl_suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))]. + [ssl_cipher:suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))]. rc4_suites(Version) -> @@ -1338,7 +1356,7 @@ der_to_pem(File, Entries) -> cipher_result(Socket, Result) -> {ok, Info} = ssl:connection_information(Socket), - Result = {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}}, + Result = {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}, ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]), %% Importante to send two packets here %% to properly test "cipher state" handling @@ -1709,7 +1727,7 @@ filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_list(Cipher)-> filter_suites([ssl_cipher:openssl_suite(S) || S <- Ciphers], AtomVersion); filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_binary(Cipher)-> - filter_suites([ssl_cipher:erl_suite_definition(S) || S <- Ciphers], + filter_suites([ssl_cipher:suite_definition(S) || S <- Ciphers], AtomVersion); filter_suites(Ciphers0, AtomVersion) -> Version = tls_version(AtomVersion), @@ -1721,7 +1739,7 @@ filter_suites(Ciphers0, AtomVersion) -> ++ ssl_cipher:srp_suites_anon() ++ ssl_cipher:rc4_suites(Version), Supported1 = ssl_cipher:filter_suites(Supported0), - Supported2 = [ssl_cipher:erl_suite_definition(S) || S <- Supported1], + Supported2 = [ssl_cipher:suite_definition(S) || S <- Supported1], [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)]. -define(OPENSSL_QUIT, "Q\n"). -- cgit v1.2.3 From f610e27fe71d0b6a19eb836c3d13cc8de610b9ef Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 3 Jul 2018 07:58:25 +0200 Subject: ssl: Do not use legacy format --- lib/ssl/src/ssl_connection.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/ssl') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 8ea4740ea4..c5f75894cd 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -2523,7 +2523,7 @@ ssl_options_list([ciphers = Key | Keys], [Value | Values], Acc) -> ssl_options_list(Keys, Values, [{Key, lists:map( fun(Suite) -> - ssl_cipher:erl_suite_definition(Suite) + ssl_cipher:suite_definition(Suite) end, Value)} | Acc]); ssl_options_list([Key | Keys], [Value | Values], Acc) -> -- cgit v1.2.3