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(-) 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