%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2007-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% -module(ssl_basic_SUITE). %% Note: This directive should only be used in test suites. -compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). -include("ssl_api.hrl"). -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). -include("ssl_alert.hrl"). -include("ssl_internal.hrl"). -include("tls_record.hrl"). -include("tls_handshake.hrl"). -define(TIMEOUT, 20000). -define(EXPIRE, 10). -define(SLEEP, 500). -define(RENEGOTIATION_DISABLE_TIME, 12000). -define(CLEAN_SESSION_DB, 60000). -define(SEC_RENEGOTIATION_TIMEOUT, 30). %%-------------------------------------------------------------------- %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- all() -> [ {group, basic}, {group, basic_tls}, {group, options}, {group, options_tls}, {group, 'dtlsv1.2'}, {group, 'dtlsv1'}, %%{group, 'tlsv1.3'}, {group, 'tlsv1.2'}, {group, 'tlsv1.1'}, {group, 'tlsv1'}, {group, 'sslv3'} ]. groups() -> [{basic, [], basic_tests()}, {basic_tls, [], basic_tests_tls()}, {options, [], options_tests()}, {options_tls, [], options_tests_tls()}, {'dtlsv1.2', [], all_versions_groups()}, {'dtlsv1', [], all_versions_groups()}, {'tlsv1.2', [], all_versions_groups() ++ tls_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]}, {'tlsv1.1', [], all_versions_groups() ++ tls_versions_groups()}, {'tlsv1', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests()}, {'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() -- [tls_ciphersuite_vs_version]}, {api,[], api_tests()}, {api_tls,[], api_tests_tls()}, {ciphers, [], cipher_tests()}, {error_handling_tests, [], error_handling_tests()}, {error_handling_tests_tls, [], error_handling_tests_tls()} ]. tls_versions_groups ()-> [ {group, api_tls}, {group, error_handling_tests_tls}]. all_versions_groups ()-> [{group, api}, {group, ciphers}, {group, error_handling_tests}]. basic_tests() -> [app, appup, alerts, alert_details, alert_details_not_too_big, version_option, connect_twice, connect_dist, clear_pem_cache, defaults, fallback, cipher_format ]. basic_tests_tls() -> [tls_send_close ]. options_tests() -> [ %%der_input, Move/remove as redundent ssl_options_not_proplist, raw_ssl_option, invalid_inet_get_option, invalid_inet_get_option_not_list, invalid_inet_get_option_improper_list, invalid_inet_set_option, invalid_inet_set_option_not_list, invalid_inet_set_option_improper_list, invalid_options, protocol_versions, empty_protocol_versions, ipv6, reuseaddr, unordered_protocol_versions_server, unordered_protocol_versions_client, max_handshake_size ]. options_tests_tls() -> [tls_misc_ssl_options, tls_tcp_reuseaddr]. api_tests() -> [eccs, getstat, accept_pool, socket_options, internal_active_1, cipher_suites ]. api_tests_tls() -> [tls_versions_option, tls_socket_options, new_options_in_accept ]. cipher_tests() -> [old_cipher_suites, cipher_suites_mix, default_reject_anonymous]. error_handling_tests()-> [ ]. error_handling_tests_tls()-> [ ]. rizzo_tests() -> [rizzo, no_rizzo_rc4, rizzo_one_n_minus_one, rizzo_zero_n, rizzo_disabled]. %%-------------------------------------------------------------------- init_per_suite(Config0) -> catch crypto:stop(), try crypto:start() of ok -> ssl_test_lib:clean_start(), %% make rsa certs using oppenssl {ok, _} = make_certs:all(proplists:get_value(data_dir, Config0), proplists:get_value(priv_dir, Config0)), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config2 = ssl_test_lib:make_ecdsa_cert(Config1), Config3 = ssl_test_lib:make_rsa_cert(Config2), Config = ssl_test_lib:make_ecdh_rsa_cert(Config3), ssl_test_lib:cert_options(Config) catch _:_ -> {skip, "Crypto did not start"} end. end_per_suite(_Config) -> ssl:stop(), application:stop(crypto). %%-------------------------------------------------------------------- init_per_group(GroupName, Config) when GroupName == basic_tls; GroupName == options_tls; GroupName == options; GroupName == basic; GroupName == session; GroupName == error_handling_tests_tls -> ssl_test_lib:clean_tls_version(Config); %% Do not automatically configure TLS version for the 'tlsv1.3' group init_per_group('tlsv1.3' = GroupName, Config) -> case ssl_test_lib:sufficient_crypto_support(GroupName) of true -> ssl:start(), Config; false -> {skip, "Missing crypto support"} end; init_per_group(GroupName, Config) -> ssl_test_lib:clean_tls_version(Config), case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of true -> ssl_test_lib:init_tls_version(GroupName, Config); _ -> case ssl_test_lib:sufficient_crypto_support(GroupName) of true -> ssl:start(), Config; false -> {skip, "Missing crypto support"} end end. end_per_group(GroupName, Config) -> case ssl_test_lib:is_tls_version(GroupName) of true -> ssl_test_lib:clean_tls_version(Config); false -> Config end. %%-------------------------------------------------------------------- init_per_testcase(Case, Config) when Case == unordered_protocol_versions_client; Case == unordered_protocol_versions_server-> case proplists:get_value(supported, ssl:versions()) of ['tlsv1.2' | _] -> ct:timetrap({seconds, 5}), Config; _ -> {skip, "TLS 1.2 need but not supported on this platform"} end; init_per_testcase(protocol_versions, Config) -> ssl:stop(), application:load(ssl), %% For backwards compatibility sslv2 should be filtered out. application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]), ssl:start(), ct:timetrap({seconds, 5}), Config; init_per_testcase(empty_protocol_versions, Config) -> ssl:stop(), application:load(ssl), ssl_test_lib:clean_env(), application:set_env(ssl, protocol_version, []), ssl:start(), ct:timetrap({seconds, 5}), Config; init_per_testcase(fallback, Config) -> case tls_record:highest_protocol_version([]) of {3, N} when N > 1 -> ct:timetrap({seconds, 5}), Config; _ -> {skip, "Not relevant if highest supported version is less than 3.2"} end; init_per_testcase(TestCase, Config) when TestCase == versions_option; TestCase == tls_tcp_connect_big -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:timetrap({seconds, 60}), Config; init_per_testcase(version_option, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:timetrap({seconds, 10}), Config; init_per_testcase(reuse_session, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:timetrap({seconds, 10}), Config; init_per_testcase(rizzo, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:timetrap({seconds, 60}), Config; init_per_testcase(no_rizzo_rc4, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:timetrap({seconds, 60}), Config; init_per_testcase(rizzo_one_n_minus_one, Config) -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:timetrap({seconds, 60}), rizzo_add_mitigation_option(one_n_minus_one, Config); init_per_testcase(rizzo_zero_n, Config) -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:timetrap({seconds, 60}), rizzo_add_mitigation_option(zero_n, Config); init_per_testcase(rizzo_disabled, Config) -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:timetrap({seconds, 60}), rizzo_add_mitigation_option(disabled, Config); init_per_testcase(TestCase, Config) when TestCase == clear_pem_cache; TestCase == der_input; TestCase == defaults -> ssl_test_lib:ct_log_supported_protocol_versions(Config), %% White box test need clean start ssl:stop(), ssl:start(), ct:timetrap({seconds, 20}), Config; init_per_testcase(raw_ssl_option, Config) -> ct:timetrap({seconds, 5}), case os:type() of {unix,linux} -> Config; _ -> {skip, "Raw options are platform-specific"} end; init_per_testcase(accept_pool, Config) -> ct:timetrap({seconds, 5}), case proplists:get_value(protocol, Config) of dtls -> {skip, "Not yet supported on DTLS sockets"}; _ -> ssl_test_lib:ct_log_supported_protocol_versions(Config), Config end; init_per_testcase(internal_active_1, Config) -> ssl:stop(), application:load(ssl), application:set_env(ssl, internal_active_n, 1), ssl:start(), ct:timetrap({seconds, 5}), Config; init_per_testcase(eccs, Config) -> case ssl:eccs() of [] -> {skip, "named curves not supported"}; [_|_] -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:timetrap({seconds, 5}), Config end; init_per_testcase(_TestCase, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:timetrap({seconds, 5}), Config. end_per_testcase(reuse_session_expired, Config) -> application:unset_env(ssl, session_lifetime), application:unset_env(ssl, session_delay_cleanup_time), end_per_testcase(default_action, Config); end_per_testcase(internal_active_n, Config) -> application:unset_env(ssl, internal_active_n), end_per_testcase(default_action, Config); end_per_testcase(Case, Config) when Case == protocol_versions; Case == empty_protocol_versions-> application:unset_env(ssl, protocol_versions), end_per_testcase(default_action, Config); end_per_testcase(_TestCase, Config) -> Config. %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- app() -> [{doc, "Test that the ssl app file is ok"}]. app(Config) when is_list(Config) -> ok = ?t:app_test(ssl). %%-------------------------------------------------------------------- appup() -> [{doc, "Test that the ssl appup file is ok"}]. appup(Config) when is_list(Config) -> ok = ?t:appup_test(ssl). %%-------------------------------------------------------------------- alerts() -> [{doc, "Test ssl_alert:alert_txt/1"}]. alerts(Config) when is_list(Config) -> Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC, ?DECRYPTION_FAILED_RESERVED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE, ?HANDSHAKE_FAILURE, ?BAD_CERTIFICATE, ?UNSUPPORTED_CERTIFICATE, ?CERTIFICATE_REVOKED,?CERTIFICATE_EXPIRED, ?CERTIFICATE_UNKNOWN, ?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR, ?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION, ?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED, ?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE, ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE, ?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY, 255 %% Unsupported/unknow alert will result in a description too ], Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) | [?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]], lists:foreach(fun(Alert) -> try ssl_alert:alert_txt(Alert) catch C:E:T -> ct:fail({unexpected, {C, E, T}}) end end, Alerts). %%-------------------------------------------------------------------- alert_details() -> [{doc, "Test that ssl_alert:alert_txt/1 result contains extendend error description"}]. alert_details(Config) when is_list(Config) -> Unique = make_ref(), UniqueStr = lists:flatten(io_lib:format("~w", [Unique])), Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Unique), case string:str(ssl_alert:alert_txt(Alert), UniqueStr) of 0 -> ct:fail(error_details_missing); _ -> ok end. %%-------------------------------------------------------------------- alert_details_not_too_big() -> [{doc, "Test that ssl_alert:alert_txt/1 limits printed depth of extended error description"}]. alert_details_not_too_big(Config) when is_list(Config) -> Reason = lists:duplicate(10, lists:duplicate(10, lists:duplicate(10, {some, data}))), Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Reason), case length(ssl_alert:alert_txt(Alert)) < 1000 of true -> ok; false -> ct:fail(ssl_alert_text_too_big) end. %%-------------------------------------------------------------------- new_options_in_accept() -> [{doc,"Test that you can set ssl options in ssl_accept/3 and not only in tcp upgrade"}]. new_options_in_accept(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts0 = ssl_test_lib:ssl_options(server_dsa_opts, 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, #{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]}, {ciphers,[Cipher]} | ServerSslOpts]}, %% To be set in ssl_accept/3 {mfa, {?MODULE, connection_info_result, []}}, {options, proplists:delete(cacertfile, ServerOpts0)}]), 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, [{versions, [Version]}, {ciphers,[Cipher]} | ClientOpts]}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ServerMsg = ClientMsg = {ok, {Version, Cipher}}, ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- protocol_versions() -> [{doc,"Test to set a list of protocol versions in app environment."}]. protocol_versions(Config) when is_list(Config) -> basic_test(Config). %%-------------------------------------------------------------------- empty_protocol_versions() -> [{doc,"Test to set an empty list of protocol versions in app environment."}]. empty_protocol_versions(Config) when is_list(Config) -> basic_test(Config). %%-------------------------------------------------------------------- getstat() -> [{doc,"Test API function getstat/2"}]. getstat(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port1 = ssl_test_lib:inet_port(Server1), Server2 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port2 = ssl_test_lib:inet_port(Server2), {ok, ActiveC} = rpc:call(ClientNode, ssl, connect, [Hostname,Port1,[{active, once}|ClientOpts]]), {ok, PassiveC} = rpc:call(ClientNode, ssl, connect, [Hostname,Port2,[{active, false}|ClientOpts]]), ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n", [self(), self(), Server1, Server2]), %% We only check that the values are non-zero initially %% (due to the handshake), and that sending more changes the values. %% Passive socket. {ok, InitialStats} = ssl:getstat(PassiveC), ct:pal("InitialStats ~p~n", [InitialStats]), [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats) || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]), ok = ssl:send(PassiveC, "Hello world"), wait_for_send(PassiveC), {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]), ct:pal("SStats ~p~n", [SStats]), [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats) || Name <- [send_cnt, send_oct]]), %% Active socket. {ok, InitialAStats} = ssl:getstat(ActiveC), ct:pal("InitialAStats ~p~n", [InitialAStats]), [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats) || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]), _ = receive {ssl, ActiveC, _} -> ok after ?SLEEP -> exit(timeout) end, ok = ssl:send(ActiveC, "Hello world"), wait_for_send(ActiveC), {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]), ct:pal("ASStats ~p~n", [ASStats]), [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats) || Name <- [send_cnt, send_oct]]), ok. %%-------------------------------------------------------------------- connect_dist() -> [{doc,"Test a simple connect as is used by distribution"}]. connect_dist(Config) when is_list(Config) -> ClientOpts0 = ssl_test_lib:ssl_options(client_kc_opts, Config), ClientOpts = [{ssl_imp, new},{active, false}, {packet,4}|ClientOpts0], ServerOpts0 = ssl_test_lib:ssl_options(server_kc_opts, Config), ServerOpts = [{ssl_imp, new},{active, false}, {packet,4}|ServerOpts0], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, connect_dist_s, []}}, {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, connect_dist_c, []}}, {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- clear_pem_cache() -> [{doc,"Test that internal reference tabel is cleaned properly even when " " the PEM cache is cleared" }]. clear_pem_cache(Config) when is_list(Config) -> {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, State = ssl_test_lib:state(Prop), [_,{FilRefDb, _} |_] = element(6, State), {Server, Client} = basic_verify_test_no_close(Config), CountReferencedFiles = fun({_, -1}, Acc) -> Acc; ({_, N}, Acc) -> N + Acc end, 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb), ssl:clear_pem_cache(), _ = sys:get_status(whereis(ssl_manager)), {Server1, Client1} = basic_verify_test_no_close(Config), 4 = ets:foldl(CountReferencedFiles, 0, FilRefDb), ssl_test_lib:close(Server), ssl_test_lib:close(Client), ct:sleep(2000), _ = sys:get_status(whereis(ssl_manager)), 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb), ssl_test_lib:close(Server1), ssl_test_lib:close(Client1), ct:sleep(2000), _ = sys:get_status(whereis(ssl_manager)), 0 = ets:foldl(CountReferencedFiles, 0, FilRefDb). %%-------------------------------------------------------------------- fallback() -> [{doc, "Test TLS_FALLBACK_SCSV downgrade prevention"}]. fallback(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {options, [{fallback, true}, {versions, ['tlsv1']} | ClientOpts]}]), ssl_test_lib:check_server_alert(Server, Client, inappropriate_fallback). %%-------------------------------------------------------------------- cipher_format() -> [{doc, "Test that cipher conversion from maps | tuples | stings to binarys works"}]. cipher_format(Config) when is_list(Config) -> {ok, Socket0} = ssl:listen(0, [{ciphers, ssl:cipher_suites(default, 'tlsv1.2')}]), ssl:close(Socket0), %% Legacy {ok, Socket1} = ssl:listen(0, [{ciphers, ssl:cipher_suites()}]), ssl:close(Socket1), {ok, Socket2} = ssl:listen(0, [{ciphers, ssl:cipher_suites(openssl)}]), ssl:close(Socket2). %%-------------------------------------------------------------------- cipher_suites() -> [{doc,"Test API function cipher_suites/2, filter_cipher_suites/2" " and prepend|append_cipher_suites/2"}]. cipher_suites(Config) when is_list(Config) -> MandatoryCipherSuiteTLS1_0TLS1_1 = #{key_exchange => rsa, cipher => '3des_ede_cbc', mac => sha, prf => default_prf}, MandatoryCipherSuiteTLS1_0TLS1_2 = #{key_exchange =>rsa, cipher => 'aes_128_cbc', mac => sha, prf => default_prf}, Version = ssl_test_lib:protocol_version(Config), All = [_|_] = ssl:cipher_suites(all, Version), Default = [_|_] = ssl:cipher_suites(default, Version), Anonymous = [_|_] = ssl:cipher_suites(anonymous, Version), true = length(Default) < length(All), Filters = [{key_exchange, fun(dhe_rsa) -> true; (_) -> false end }, {cipher, fun(aes_256_cbc) -> true; (_) -> false end }, {mac, fun(sha) -> true; (_) -> false end } ], Cipher = #{cipher => aes_256_cbc, key_exchange => dhe_rsa, mac => sha, prf => default_prf}, [Cipher] = ssl:filter_cipher_suites(All, Filters), [Cipher | Rest0] = ssl:prepend_cipher_suites([Cipher], Default), [Cipher | Rest0] = ssl:prepend_cipher_suites(Filters, Default), true = lists:member(Cipher, Default), false = lists:member(Cipher, Rest0), [Cipher | Rest1] = lists:reverse(ssl:append_cipher_suites([Cipher], Default)), [Cipher | Rest1] = lists:reverse(ssl:append_cipher_suites(Filters, Default)), true = lists:member(Cipher, Default), false = lists:member(Cipher, Rest1), [] = lists:dropwhile(fun(X) -> not lists:member(X, Default) end, Anonymous), [] = lists:dropwhile(fun(X) -> not lists:member(X, All) end, Anonymous), true = lists:member(MandatoryCipherSuiteTLS1_0TLS1_1, All), true = lists:member(MandatoryCipherSuiteTLS1_0TLS1_2, All). %%-------------------------------------------------------------------- old_cipher_suites() -> [{doc,"Test API function cipher_suites/0"}]. old_cipher_suites(Config) when is_list(Config) -> MandatoryCipherSuite = {rsa, '3des_ede_cbc', sha}, [_|_] = Suites = ssl:cipher_suites(), Suites = ssl:cipher_suites(erlang), [_|_] = ssl:cipher_suites(openssl), true = lists:member(MandatoryCipherSuite, ssl:cipher_suites(all)). %%-------------------------------------------------------------------- cipher_suites_mix() -> [{doc,"Test to have old and new cipher suites at the same time"}]. cipher_suites_mix(Config) when is_list(Config) -> CipherSuites = [{dhe_rsa,aes_128_cbc,sha256,sha256}, {dhe_rsa,aes_128_cbc,sha}], ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{ciphers, CipherSuites} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- tls_socket_options() -> [{doc,"Test API function getopts/2 and setopts/2"}]. tls_socket_options(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Values = [{mode, list}, {packet, 0}, {header, 0}, {active, true}], %% Shall be the reverse order of Values! Options = [active, header, packet, mode], NewValues = [{mode, binary}, {active, once}], %% Shall be the reverse order of NewValues! NewOptions = [active, mode], Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, tls_socket_options_result, [Options, Values, NewOptions, NewValues]}}, {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, tls_socket_options_result, [Options, Values, NewOptions, NewValues]}}, {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), {ok, Listen} = ssl:listen(0, ServerOpts), {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]), ok = ssl:setopts(Listen, [{mode, binary}]), {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]), {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]), ssl:close(Listen). tls_socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> %% Test get/set emulated opts {ok, DefaultValues} = ssl:getopts(Socket, Options), ssl:setopts(Socket, NewValues), {ok, NewValues} = ssl:getopts(Socket, NewOptions), %% Test get/set inet opts {ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]), ssl:setopts(Socket, [{nodelay, true}]), {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]), {ok, All} = ssl:getopts(Socket, []), ct:log("All opts ~p~n", [All]), ok. %%-------------------------------------------------------------------- socket_options() -> [{doc,"Test API function getopts/2 and setopts/2"}]. socket_options(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Values = [{mode, list}, {active, true}], %% Shall be the reverse order of Values! Options = [active, mode], NewValues = [{mode, binary}, {active, once}], %% Shall be the reverse order of NewValues! NewOptions = [active, mode], Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, socket_options_result, [Options, Values, NewOptions, NewValues]}}, {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, socket_options_result, [Options, Values, NewOptions, NewValues]}}, {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), {ok, Listen} = ssl:listen(0, ServerOpts), {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]), ok = ssl:setopts(Listen, [{mode, binary}]), {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]), {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]), ssl:close(Listen). socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> %% Test get/set emulated opts {ok, DefaultValues} = ssl:getopts(Socket, Options), ssl:setopts(Socket, NewValues), {ok, NewValues} = ssl:getopts(Socket, NewOptions), %% Test get/set inet opts {ok,[{reuseaddr, _}]} = ssl:getopts(Socket, [reuseaddr]), {ok, All} = ssl:getopts(Socket, []), ct:log("All opts ~p~n", [All]), ok. %%-------------------------------------------------------------------- invalid_inet_get_option() -> [{doc,"Test handling of invalid inet options in getopts"}]. invalid_inet_get_option(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, get_invalid_inet_option, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- invalid_inet_get_option_not_list() -> [{doc,"Test handling of invalid type in getopts"}]. invalid_inet_get_option_not_list(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, get_invalid_inet_option_not_list, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). get_invalid_inet_option_not_list(Socket) -> {error, {options, {socket_options, some_invalid_atom_here}}} = ssl:getopts(Socket, some_invalid_atom_here), ok. %%-------------------------------------------------------------------- invalid_inet_get_option_improper_list() -> [{doc,"Test handling of invalid type in getopts"}]. invalid_inet_get_option_improper_list(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, get_invalid_inet_option_improper_list, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). get_invalid_inet_option_improper_list(Socket) -> {error, {options, {socket_options, foo,_}}} = ssl:getopts(Socket, [packet | foo]), ok. %%-------------------------------------------------------------------- invalid_inet_set_option() -> [{doc,"Test handling of invalid inet options in setopts"}]. invalid_inet_set_option(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, set_invalid_inet_option, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). set_invalid_inet_option(Socket) -> {error, {options, {socket_options, {packet, foo}}}} = ssl:setopts(Socket, [{packet, foo}]), {error, {options, {socket_options, {header, foo}}}} = ssl:setopts(Socket, [{header, foo}]), {error, {options, {socket_options, {active, foo}}}} = ssl:setopts(Socket, [{active, foo}]), {error, {options, {socket_options, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]), ok. %%-------------------------------------------------------------------- invalid_inet_set_option_not_list() -> [{doc,"Test handling of invalid type in setopts"}]. invalid_inet_set_option_not_list(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, set_invalid_inet_option_not_list, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). set_invalid_inet_option_not_list(Socket) -> {error, {options, {not_a_proplist, some_invalid_atom_here}}} = ssl:setopts(Socket, some_invalid_atom_here), ok. %%-------------------------------------------------------------------- invalid_inet_set_option_improper_list() -> [{doc,"Test handling of invalid tye in setopts"}]. invalid_inet_set_option_improper_list(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, set_invalid_inet_option_improper_list, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). set_invalid_inet_option_improper_list(Socket) -> {error, {options, {not_a_proplist, [{packet, 0} | {foo, 2}]}}} = ssl:setopts(Socket, [{packet, 0} | {foo, 2}]), ok. %%-------------------------------------------------------------------- tls_misc_ssl_options() -> [{doc,"Test what happens when we give valid options"}]. tls_misc_ssl_options(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), %% Check that ssl options not tested elsewhere are filtered away e.i. not passed to inet. TestOpts = [{depth, 1}, {key, undefined}, {password, []}, {reuse_session, fun(_,_,_,_) -> true end}, {cb_info, {gen_tcp, tcp, tcp_closed, tcp_error}}], Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, TestOpts ++ ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, TestOpts ++ ClientOpts}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- ssl_options_not_proplist() -> [{doc,"Test what happens if an option is not a key value tuple"}]. ssl_options_not_proplist(Config) when is_list(Config) -> BadOption = {client_preferred_next_protocols, client, [<<"spdy/3">>,<<"http/1.1">>], <<"http/1.1">>}, {option_not_a_key_value_tuple, BadOption} = ssl:connect("twitter.com", 443, [binary, {active, false}, BadOption]). %%-------------------------------------------------------------------- raw_ssl_option() -> [{doc,"Ensure that a single 'raw' option is passed to ssl:listen correctly."}]. raw_ssl_option(Config) when is_list(Config) -> % 'raw' option values are platform-specific; these are the Linux values: IpProtoTcp = 6, % Use TCP_KEEPIDLE, because (e.g.) TCP_MAXSEG can't be read back reliably. TcpKeepIdle = 4, KeepAliveTimeSecs = 55, LOptions = [{raw, IpProtoTcp, TcpKeepIdle, <>}], {ok, LSocket} = ssl:listen(0, LOptions), % Per http://www.erlang.org/doc/man/inet.html#getopts-2, we have to specify % exactly which raw option we want, and the size of the buffer. {ok, [{raw, IpProtoTcp, TcpKeepIdle, <>}]} = ssl:getopts(LSocket, [{raw, IpProtoTcp, TcpKeepIdle, 4}]). %%-------------------------------------------------------------------- eccs() -> [{doc, "Test API functions eccs/0 and eccs/1"}]. eccs(Config) when is_list(Config) -> [_|_] = All = ssl:eccs(), [] = ssl:eccs(sslv3), [_|_] = Tls = ssl:eccs(tlsv1), [_|_] = Tls1 = ssl:eccs('tlsv1.1'), [_|_] = Tls2 = ssl:eccs('tlsv1.2'), [_|_] = Tls1 = ssl:eccs('dtlsv1'), [_|_] = Tls2 = ssl:eccs('dtlsv1.2'), %% ordering is currently not verified by the test true = lists:sort(All) =:= lists:usort(Tls ++ Tls1 ++ Tls2), ok. %%-------------------------------------------------------------------- send_recv() -> [{doc,""}]. send_recv(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ClientOpts]}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- tls_send_close() -> [{doc,""}]. tls_send_close(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), {ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect, [Hostname,Port,[binary, {active, false}]]), {ok, SslS} = rpc:call(ClientNode, ssl, connect, [TcpS,[{active, false}|ClientOpts]]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), self(), Server]), ok = ssl:send(SslS, "Hello world"), {ok,<<"Hello world">>} = ssl:recv(SslS, 11), gen_tcp:close(TcpS), {error, _} = ssl:send(SslS, "Hello world"). %%-------------------------------------------------------------------- version_option() -> [{doc, "Use version option and do no specify ciphers list. Bug specified incorrect ciphers"}]. version_option(Config) when is_list(Config) -> Versions = proplists:get_value(supported, ssl:versions()), [version_option_test(Config, Version) || Version <- Versions]. internal_active_1() -> [{doc,"Test internal active 1 (behave as internal active once)"}]. internal_active_1(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{active, true} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{active, true} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- ipv6() -> [{require, ipv6_hosts}, {doc,"Test ipv6."}]. ipv6(Config) when is_list(Config) -> {ok, Hostname0} = inet:gethostname(), case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of true -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config, ipv6), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [inet6, {active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [inet6, {active, false} | ClientOpts]}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client); false -> {skip, "Host does not support IPv6"} end. %%-------------------------------------------------------------------- invalid_options() -> [{doc,"Test what happens when we give invalid options"}]. invalid_options(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Check = fun(Client, Server, {versions, [sslv2, sslv3]} = Option) -> ssl_test_lib:check_result(Server, {error, {options, {sslv2, Option}}}, Client, {error, {options, {sslv2, Option}}}); (Client, Server, Option) -> ssl_test_lib:check_result(Server, {error, {options, Option}}, Client, {error, {options, Option}}) end, TestOpts = [{versions, [sslv2, sslv3]}, {verify, 4}, {verify_fun, function}, {fail_if_no_peer_cert, 0}, {verify_client_once, 1}, {depth, four}, {certfile, 'cert.pem'}, {keyfile,'key.pem' }, {password, foo}, {cacertfile, ""}, {dhfile,'dh.pem' }, {ciphers, [{foo, bar, sha, ignore}]}, {reuse_session, foo}, {reuse_sessions, 0}, {renegotiate_at, "10"}, {mode, depech}, {packet, 8.0}, {packet_size, "2"}, {header, a}, {active, trice}, {key, 'key.pem' }], [begin Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, {options, [TestOpt | ServerOpts]}]), %% Will never reach a point where port is used. Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0}, {host, Hostname}, {from, self()}, {options, [TestOpt | ClientOpts]}]), Check(Client, Server, TestOpt), ok end || TestOpt <- TestOpts], ok. %%-------------------------------------------------------------------- default_reject_anonymous()-> [{doc,"Test that by default anonymous cipher suites are rejected "}]. default_reject_anonymous(Config) when is_list(Config) -> {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), Version = ssl_test_lib:protocol_version(Config), TLSVersion = ssl_test_lib:tls_version(Version), [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion), Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {options, [{ciphers,[CipherSuite]} | ClientOpts]}]), ssl_test_lib:check_server_alert(Server, Client, insufficient_security). %%-------------------------------------------------------------------- der_input() -> [{doc,"Test to input certs and key as der"}]. der_input(Config) when is_list(Config) -> DataDir = proplists:get_value(data_dir, Config), DHParamFile = filename:join(DataDir, "dHParam.pem"), {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, State = ssl_test_lib:state(Prop), [CADb | _] = element(6, State), Size = ets:info(CADb, size), SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | SeverVerifyOpts]), ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | ClientVerifyOpts]), ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, {dh, DHParams}, {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}], ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, {dh, DHParams}, {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client), Size = ets:info(CADb, size). %%-------------------------------------------------------------------- der_input_opts(Opts) -> Certfile = proplists:get_value(certfile, Opts), CaCertsfile = proplists:get_value(cacertfile, Opts), Keyfile = proplists:get_value(keyfile, Opts), Dhfile = proplists:get_value(dhfile, Opts), [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile), [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile), [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile), CaCerts = lists:map(fun(Entry) -> {_, CaCert, _} = Entry, CaCert end, ssl_test_lib:pem_to_der(CaCertsfile)), {Cert, {Asn1Type, Key}, CaCerts, DHParams}. %%-------------------------------------------------------------------- defaults(Config) when is_list(Config)-> Versions = ssl:versions(), true = lists:member(sslv3, proplists:get_value(available, Versions)), false = lists:member(sslv3, proplists:get_value(supported, Versions)), true = lists:member('tlsv1', proplists:get_value(available, Versions)), false = lists:member('tlsv1', proplists:get_value(supported, Versions)), true = lists:member('tlsv1.1', proplists:get_value(available, Versions)), false = lists:member('tlsv1.1', proplists:get_value(supported, Versions)), true = lists:member('tlsv1.2', proplists:get_value(available, Versions)), true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)), false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()), true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)), false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()), true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)), false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()), true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)), true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)), true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)), true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)), false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)). %%-------------------------------------------------------------------- reuseaddr() -> [{doc,"Test reuseaddr option"}]. reuseaddr(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, [{active, false} | ClientOpts]}]), ssl_test_lib:close(Server), ssl_test_lib:close(Client), Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ServerOpts]}]), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ClientOpts]}]), ssl_test_lib:check_result(Server1, ok, Client1, ok), ssl_test_lib:close(Server1), ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- tls_tcp_reuseaddr() -> [{doc, "Reference test case."}]. tls_tcp_reuseaddr(Config) when is_list(Config) -> {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {transport, gen_tcp}, {mfa, {ssl_test_lib, no_result, []}}, {options, [{active, false}, {reuseaddr, true}]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {transport, gen_tcp}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, [{active, false}]}]), ssl_test_lib:close(Server), ssl_test_lib:close(Client), Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, {transport, gen_tcp}, {mfa, {?MODULE, tcp_send_recv_result, []}}, {options, [{active, false}, {reuseaddr, true}]}]), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {transport, gen_tcp}, {mfa, {?MODULE, tcp_send_recv_result, []}}, {options, [{active, false}]}]), ssl_test_lib:check_result(Server1, ok, Client1, ok), ssl_test_lib:close(Server1), ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- tls_ciphersuite_vs_version() -> [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}]. tls_ciphersuite_vs_version(Config) when is_list(Config) -> {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]), ok = gen_tcp:send(Socket, <<22, 3,0, 49:16, % handshake, SSL 3.0, length 1, 45:24, % client_hello, length 3,0, % SSL 3.0 16#deadbeef:256, % 32 'random' bytes = 256 bits 0, % no session ID %% three cipher suites -- null, one with sha256 hash and one with sha hash 6:16, 0,255, 0,61, 0,57, 1, 0 % no compression >>), {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000), {ok, <>} = gen_tcp:recv(Socket, HelloLen, 5000), ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin), case ServerHello of #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} -> ok; _ -> ct:fail({unexpected_server_hello, ServerHello}) end. %%-------------------------------------------------------------------- conf_signature_algs() -> [{doc,"Test to set the signature_algs option on both client and server"}]. conf_signature_algs(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ClientOpts]}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- no_common_signature_algs() -> [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}]. no_common_signature_algs(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, {options, [{signature_algs, [{sha256, rsa}]} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {options, [{signature_algs, [{sha384, rsa}]} | ClientOpts]}]), ssl_test_lib:check_server_alert(Server, Client, insufficient_security). %%-------------------------------------------------------------------- connect_twice() -> [{doc,""}]. connect_twice(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{keepalive, true},{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{keepalive, true},{active, false} | ClientOpts]}]), Server ! listen, {Client1, #sslsocket{}} = ssl_test_lib:start_client([return_socket, {node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{keepalive, true},{active, false} | ClientOpts]}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:check_result(Server, ok, Client1, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client), ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- rizzo() -> [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is vunrable to Rizzo/Dungon attack"}]. rizzo(Config) when is_list(Config) -> Prop = proplists:get_value(tc_group_properties, Config), Version = proplists:get_value(name, Prop), NVersion = ssl_test_lib:protocol_version(Config, tuple), Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion), [{key_exchange, fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> true; (_) -> false end}, {cipher, fun(rc4_128) -> false; (chacha20_poly1305) -> false; (_) -> true end}]), run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_rizzo, []}). %%-------------------------------------------------------------------- no_rizzo_rc4() -> [{doc,"Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"}]. no_rizzo_rc4(Config) when is_list(Config) -> Prop = proplists:get_value(tc_group_properties, Config), Version = proplists:get_value(name, Prop), NVersion = ssl_test_lib:protocol_version(Config, tuple), %% Test uses RSA certs Ciphers = ssl:filter_cipher_suites(ssl_test_lib:rc4_suites(NVersion), [{key_exchange, fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> true; (_) -> false end}]), run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_no_rizzo, []}). rizzo_one_n_minus_one() -> [{doc,"Test that the 1/n-1-split mitigation of Rizzo/Dungon attack can be explicitly selected"}]. rizzo_one_n_minus_one(Config) when is_list(Config) -> Prop = proplists:get_value(tc_group_properties, Config), Version = proplists:get_value(name, Prop), NVersion = ssl_test_lib:protocol_version(Config, tuple), Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion), [{key_exchange, fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> true; (_) -> false end}, {cipher, fun(rc4_128) -> false; %% TODO: remove this clause when chacha is fixed! (chacha20_poly1305) -> false; (_) -> true end}]), run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_rizzo, []}). rizzo_zero_n() -> [{doc,"Test that the 0/n-split mitigation of Rizzo/Dungon attack can be explicitly selected"}]. rizzo_zero_n(Config) when is_list(Config) -> Prop = proplists:get_value(tc_group_properties, Config), Version = proplists:get_value(name, Prop), NVersion = ssl_test_lib:protocol_version(Config, tuple), Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion), [{cipher, fun(rc4_128) -> false; (_) -> true end}]), run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_no_rizzo, []}). rizzo_disabled() -> [{doc,"Test that the mitigation of Rizzo/Dungon attack can be explicitly disabled"}]. rizzo_disabled(Config) when is_list(Config) -> Prop = proplists:get_value(tc_group_properties, Config), Version = proplists:get_value(name, Prop), NVersion = ssl_test_lib:protocol_version(Config, tuple), Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion), [{cipher, fun(rc4_128) -> false; (_) -> true end}]), run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_no_rizzo, []}). %%-------------------------------------------------------------------- new_server_wants_peer_cert() -> [{doc, "Test that server configured to do client certification does" " not reuse session without a client certificate."}]. new_server_wants_peer_cert(Config) when is_list(Config) -> ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), VServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} | ssl_test_lib:ssl_options(server_verification_opts, Config)], ClientOpts = ssl_test_lib:ssl_options(client_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, peercert_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, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), Monitor = erlang:monitor(process, Server), ssl_test_lib:close(Server), ssl_test_lib:close(Client), receive {'DOWN', Monitor, _, _, _} -> ok end, Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, {mfa, {?MODULE, peercert_result, []}}, {options, VServerOpts}]), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, [ClientOpts]}]), CertFile = proplists:get_value(certfile, ClientOpts), [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile), ServerMsg = {error, no_peercert}, Sever1Msg = {ok, BinCert}, ssl_test_lib:check_result(Server, ServerMsg, Server1, Sever1Msg), ssl_test_lib:close(Server1), ssl_test_lib:close(Client), ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- tls_versions_option() -> [{doc,"Test API versions option to connect/listen."}]. tls_versions_option(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), Supported = proplists:get_value(supported, ssl:versions()), Available = proplists:get_value(available, ssl:versions()), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{versions, Supported} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), Server ! listen, ErrClient = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {options, [{versions , Available -- Supported} | ClientOpts]}]), receive {Server, _} -> ok end, ssl_test_lib:check_client_alert(ErrClient, protocol_version). %%-------------------------------------------------------------------- unordered_protocol_versions_server() -> [{doc,"Test that the highest protocol is selected even" " when it is not first in the versions list."}]. unordered_protocol_versions_server(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, protocol_info_result, []}}, {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {?MODULE, protocol_info_result, []}}, {options, ClientOpts}]), ServerMsg = ClientMsg = {ok,'tlsv1.2'}, ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). %%-------------------------------------------------------------------- unordered_protocol_versions_client() -> [{doc,"Test that the highest protocol is selected even" " when it is not first in the versions list."}]. unordered_protocol_versions_client(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_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, protocol_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, protocol_info_result, []}}, {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]), ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). %%-------------------------------------------------------------------- max_handshake_size() -> [{doc,"Test that we can set max_handshake_size to max value."}]. max_handshake_size(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{max_handshake_size, 8388607} |ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, [{max_handshake_size, 8388607} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok). %%-------------------------------------------------------------------- accept_pool() -> [{doc,"Test having an accept pool."}]. accept_pool(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {accepters, 3}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server0), [Server1, Server2] = ssl_test_lib:accepters(2), Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts} ]), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts} ]), Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts} ]), ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]), ssl_test_lib:close(Server0), ssl_test_lib:close(Server1), ssl_test_lib:close(Server2), ssl_test_lib:close(Client0), ssl_test_lib:close(Client1), ssl_test_lib:close(Client2). %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- send_recv_result(Socket) -> ssl:send(Socket, "Hello world"), {ok,"Hello world"} = ssl:recv(Socket, 11), ok. tcp_send_recv_result(Socket) -> gen_tcp:send(Socket, "Hello world"), {ok,"Hello world"} = gen_tcp:recv(Socket, 11), ok. basic_verify_test_no_close(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), {Server, Client}. basic_test(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). send_recv_result_active_rizzo(Socket) -> ssl:send(Socket, "Hello world"), "Hello world" = ssl_test_lib:active_recv(Socket, 11), ok. send_recv_result_active_no_rizzo(Socket) -> ssl:send(Socket, "Hello world"), "Hello world" = ssl_test_lib:active_recv(Socket, 11), ok. result_ok(_Socket) -> ok. rizzo_add_mitigation_option(Value, Config) -> lists:foldl(fun(Opt, Acc) -> case proplists:get_value(Opt, Acc) of undefined -> Acc; C -> N = lists:keystore(beast_mitigation, 1, C, {beast_mitigation, Value}), lists:keystore(Opt, 1, Acc, {Opt, N}) end end, Config, [client_opts, client_dsa_opts, server_opts, server_dsa_opts, server_ecdsa_opts, server_ecdh_rsa_opts]). erlang_ssl_receive(Socket, Data) -> case ssl_test_lib:active_recv(Socket, length(Data)) of Data -> ok; Other -> ct:fail({{expected, Data}, {got, Other}}) end. run_send_recv_rizzo(Ciphers, Config, Version, Mfa) -> Result = lists:map(fun(Cipher) -> rizzo_test(Cipher, Config, Version, Mfa) end, Ciphers), case lists:flatten(Result) of [] -> ok; Error -> ct:log("Cipher suite errors: ~p~n", [Error]), ct:fail(cipher_suite_failed_see_test_case_log) end. rizzo_test(Cipher, Config, Version, Mfa) -> {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, Mfa}, {options, [{active, true}, {ciphers, [Cipher]}, {versions, [Version]} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, Mfa}, {options, [{active, true}, {ciphers, [Cipher]}| ClientOpts]}]), Result = ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client), case Result of ok -> []; Error -> [{Cipher, Error}] end. client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa orelse KeyAlgo == ecdhe_rsa orelse KeyAlgo == rsa_psk orelse KeyAlgo == srp_rsa -> {ssl_test_lib:ssl_options(client_opts, Config), ssl_test_lib:ssl_options(server_opts, Config)}; client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss -> {ssl_test_lib:ssl_options(client_dsa_opts, Config), ssl_test_lib:ssl_options(server_dsa_opts, Config)}; client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa -> {ssl_test_lib:ssl_options(client_opts, Config), ssl_test_lib:ssl_options(server_ecdsa_opts, Config)}; client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_rsa -> {ssl_test_lib:ssl_options(client_opts, Config), ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)}. protocol_info_result(Socket) -> {ok, [{protocol, PVersion}]} = ssl:connection_information(Socket, [protocol]), {ok, PVersion}. version_info_result(Socket) -> {ok, [{version, Version}]} = ssl:connection_information(Socket, [version]), {ok, Version}. connect_dist_s(S) -> Msg = term_to_binary({erlang,term}), ok = ssl:send(S, Msg). connect_dist_c(S) -> Test = binary_to_list(term_to_binary({erlang,term})), {ok, Test} = ssl:recv(S, 0, 10000), ok. get_invalid_inet_option(Socket) -> {error, {options, {socket_options, foo, _}}} = ssl:getopts(Socket, [foo]), ok. dummy(_Socket) -> %% Should not happen as the ssl connection will not be established %% due to fatal handshake failiure exit(kill). version_option_test(Config, Version) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false}, {versions, [Version]}| ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false}, {versions, [Version]}| ClientOpts]}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). wait_for_send(Socket) -> %% Make sure TLS process processed send message event _ = ssl:connection_information(Socket). connection_info_result(Socket) -> {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]), {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}.