diff options
Diffstat (limited to 'lib/ssl/test/ssl_basic_SUITE.erl')
-rw-r--r-- | lib/ssl/test/ssl_basic_SUITE.erl | 1356 |
1 files changed, 962 insertions, 394 deletions
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 7f33efd7e1..8f9554f3ce 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -7,7 +7,7 @@ %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% retrieved online at http://www.erlang.org/.2 %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See @@ -27,19 +27,14 @@ -include("test_server.hrl"). -include("test_server_line.hrl"). -include_lib("public_key/include/public_key.hrl"). +-include("ssl_alert.hrl"). -define('24H_in_sec', 86400). -define(TIMEOUT, 60000). +-define(LONG_TIMEOUT, 600000). -define(EXPIRE, 10). -define(SLEEP, 500). - --behaviour(ssl_session_cache_api). - -%% For the session cache tests --export([init/0, terminate/1, lookup/2, update/3, - delete/2, foldl/3, select_session/2]). - %% Test server callback functions %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config @@ -50,14 +45,21 @@ %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- -init_per_suite(Config) -> +init_per_suite(Config0) -> + Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2), crypto:start(), + application:start(public_key), ssl:start(), + + %% make rsa certs using oppenssl Result = - (catch make_certs:all(?config(data_dir, Config), - ?config(priv_dir, Config))), + (catch make_certs:all(?config(data_dir, Config0), + ?config(priv_dir, Config0))), test_server:format("Make certs ~p~n", [Result]), - ssl_test_lib:cert_options(Config). + + Config1 = ssl_test_lib:make_dsa_cert(Config0), + Config = ssl_test_lib:cert_options(Config1), + [{watchdog, Dog} | Config]. %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ @@ -82,13 +84,6 @@ end_per_suite(_Config) -> %% variable, but should NOT alter/remove any existing entries. %% Description: Initialization before each test case %%-------------------------------------------------------------------- -init_per_testcase(session_cache_process_list, Config) -> - init_customized_session_cache(Config); - -init_per_testcase(session_cache_process_mnesia, Config) -> - mnesia:start(), - init_customized_session_cache(Config); - init_per_testcase(reuse_session_expired, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5), @@ -98,19 +93,42 @@ init_per_testcase(reuse_session_expired, Config0) -> ssl:start(), [{watchdog, Dog} | Config]; -init_per_testcase(_TestCase, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = test_server:timetrap(?TIMEOUT), - [{watchdog, Dog} | Config]. +init_per_testcase(no_authority_key_identifier, Config) -> + %% Clear cach so that root cert will not + %% be found. + ssl:stop(), + ssl:start(), + Config; -init_customized_session_cache(Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = test_server:timetrap(?TIMEOUT), +init_per_testcase(TestCase, Config) when TestCase == ciphers_rsa_signed_certs_ssl3; + TestCase == ciphers_rsa_signed_certs_openssl_names_ssl3; + TestCase == ciphers_dsa_signed_certs_ssl3; + TestCase == ciphers_dsa_signed_certs_openssl_names_ssl3 -> ssl:stop(), application:load(ssl), - application:set_env(ssl, session_cb, ?MODULE), + application:set_env(ssl, protocol_version, sslv3), ssl:start(), - [{watchdog, Dog} | Config]. + Config; + +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(), + Config; + +init_per_testcase(empty_protocol_versions, Config) -> + ssl:stop(), + application:load(ssl), + application:set_env(ssl, protocol_version, []), + ssl:start(), + Config; + +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = test_server:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. %%-------------------------------------------------------------------- %% Function: end_per_testcase(TestCase, Config) -> _ @@ -120,16 +138,17 @@ init_customized_session_cache(Config0) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- -end_per_testcase(session_cache_process_list, Config) -> - application:unset_env(ssl, session_cb), - end_per_testcase(default_action, Config); -end_per_testcase(session_cache_process_mnesia, Config) -> - application:unset_env(ssl, session_cb), - mnesia:stop(), - end_per_testcase(default_action, Config); end_per_testcase(reuse_session_expired, Config) -> application:unset_env(ssl, session_lifetime), end_per_testcase(default_action, Config); +end_per_testcase(TestCase, Config) when TestCase == ciphers_rsa_signed_certs_ssl3; + TestCase == ciphers_rsa_signed_certs_openssl_names_ssl3; + TestCase == ciphers_dsa_signed_certs_ssl3; + TestCase == ciphers_dsa_signed_certs_openssl_names_ssl3; + TestCase == protocol_versions; + TestCase == empty_protocol_versions-> + application:unset_env(ssl, protocol_version), + end_per_testcase(default_action, Config); end_per_testcase(_TestCase, Config) -> Dog = ?config(watchdog, Config), case Dog of @@ -151,28 +170,42 @@ all(doc) -> ["Test the basic ssl functionality"]; all(suite) -> - [app, connection_info, controlling_process, controller_dies, - peercert, connect_dist, - peername, sockname, socket_options, misc_ssl_options, versions, cipher_suites, - upgrade, upgrade_with_timeout, tcp_connect, - ipv6, ekeyfile, ecertfile, ecacertfile, eoptions, shutdown, - shutdown_write, shutdown_both, shutdown_error, ciphers, - send_close, close_transport_accept, dh_params, - server_verify_peer_passive, + [app, alerts, connection_info, protocol_versions, + empty_protocol_versions, controlling_process, controller_dies, + client_closes_socket, peercert, connect_dist, peername, sockname, + socket_options, misc_ssl_options, versions, cipher_suites, + upgrade, upgrade_with_timeout, tcp_connect, ipv6, ekeyfile, + ecertfile, ecacertfile, eoptions, shutdown, shutdown_write, + shutdown_both, shutdown_error, + ciphers_rsa_signed_certs, ciphers_rsa_signed_certs_ssl3, + ciphers_rsa_signed_certs_openssl_names, + ciphers_rsa_signed_certs_openssl_names_ssl3, + ciphers_dsa_signed_certs, + ciphers_dsa_signed_certs_ssl3, + ciphers_dsa_signed_certs_openssl_names, + ciphers_dsa_signed_certs_openssl_names_ssl3, + anonymous_cipher_suites, + default_reject_anonymous, + send_close, + close_transport_accept, dh_params, server_verify_peer_passive, server_verify_peer_active, server_verify_peer_active_once, - server_verify_none_passive, server_verify_none_active, + server_verify_none_passive, server_verify_none_active, server_verify_none_active_once, server_verify_no_cacerts, server_require_peer_cert_ok, server_require_peer_cert_fail, server_verify_client_once_passive, server_verify_client_once_active, - server_verify_client_once_active_once, - client_verify_none_passive, - client_verify_none_active, client_verify_none_active_once - %%, session_cache_process_list, session_cache_process_mnesia - ,reuse_session, reuse_session_expired, server_does_not_want_to_reuse_session, - client_renegotiate, server_renegotiate, - client_no_wrap_sequence_number, server_no_wrap_sequence_number, - extended_key_usage, validate_extensions_fun + server_verify_client_once_active_once, client_verify_none_passive, + client_verify_none_active, client_verify_none_active_once, + reuse_session, reuse_session_expired, + server_does_not_want_to_reuse_session, client_renegotiate, + server_renegotiate, client_renegotiate_reused_session, + server_renegotiate_reused_session, client_no_wrap_sequence_number, + server_no_wrap_sequence_number, extended_key_usage, + no_authority_key_identifier, + invalid_signature_client, invalid_signature_server, cert_expired, + client_with_cert_cipher_suites_handshake, unknown_server_ca_fail, + der_input, unknown_server_ca_accept_verify_none, unknown_server_ca_accept_verify_peer, + unknown_server_ca_accept_backwardscompatibilty ]. %% Test cases starts here. @@ -183,7 +216,31 @@ app(suite) -> []; app(Config) when is_list(Config) -> ok = test_server:app_test(ssl). - +%%-------------------------------------------------------------------- +alerts(doc) -> + "Test ssl_alert:alert_txt/1"; +alerts(suite) -> + []; +alerts(Config) when is_list(Config) -> + Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC, + ?DECRYPTION_FAILED, ?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], + Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) | + [?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]], + lists:foreach(fun(Alert) -> + case ssl_alert:alert_txt(Alert) of + Txt when is_list(Txt) -> + ok; + Other -> + test_server:fail({unexpected, Other}) + end + end, Alerts). +%%-------------------------------------------------------------------- connection_info(doc) -> ["Test the API function ssl:connection_info/1"]; connection_info(suite) -> @@ -212,7 +269,7 @@ connection_info(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), - ServerMsg = ClientMsg = {ok, {Version, {rsa,rc4_128,sha,no_export}}}, + ServerMsg = ClientMsg = {ok, {Version, {rsa,rc4_128,sha}}}, ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -224,6 +281,49 @@ connection_info_result(Socket) -> %%-------------------------------------------------------------------- +protocol_versions(doc) -> + ["Test to set a list of protocol versions in app environment."]; + +protocol_versions(suite) -> + []; + +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(suite) -> + []; + +empty_protocol_versions(Config) when is_list(Config) -> + basic_test(Config). + + +basic_test(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(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, 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, {?MODULE, 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). + +%%-------------------------------------------------------------------- + controlling_process(doc) -> ["Test API function controlling_process/2"]; @@ -281,7 +381,7 @@ controlling_process_result(Socket, Pid, Msg) -> ssl:send(Socket, Msg), no_result_msg. - +%%-------------------------------------------------------------------- controller_dies(doc) -> ["Test that the socket is closed after controlling process dies"]; controller_dies(suite) -> []; @@ -322,6 +422,10 @@ controller_dies(Config) when is_list(Config) -> Connect = fun(Pid) -> {ok, Socket} = ssl:connect(Hostname, Port, [{reuseaddr,true},{ssl_imp,new}]), + %% Make sure server finishes and verification + %% and is in coonection state before + %% killing client + test_server:sleep(?SLEEP), Pid ! {self(), connected, Socket}, receive die_nice -> normal end end, @@ -393,6 +497,36 @@ get_close(Pid, Where) -> end. %%-------------------------------------------------------------------- +client_closes_socket(doc) -> + ["Test what happens when client closes socket before handshake is compleated"]; +client_closes_socket(suite) -> []; +client_closes_socket(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + TcpOpts = [binary, {reuseaddr, true}], + + Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {tcp_options, TcpOpts}, + {ssl_options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Connect = fun() -> + {ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect, + [Hostname, Port, TcpOpts]), + %% Make sure that ssl_accept is called before + %% client process ends and closes socket. + test_server:sleep(?SLEEP) + end, + + _Client = spawn_link(Connect), + + ssl_test_lib:check_result(Server, {error,closed}), + + ssl_test_lib:close(Server). + +%%-------------------------------------------------------------------- + peercert(doc) -> [""]; @@ -416,8 +550,8 @@ peercert(Config) when is_list(Config) -> {options, ClientOpts}]), CertFile = proplists:get_value(certfile, ServerOpts), - {ok, [{cert, BinCert, _}]} = public_key:pem_to_der(CertFile), - {ok, ErlCert} = public_key:pkix_decode_cert(BinCert, otp), + [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile), + ErlCert = public_key:pkix_decode_cert(BinCert, otp), ServerMsg = {{error, no_peercert}, {error, no_peercert}}, ClientMsg = {{ok, BinCert}, {ok, ErlCert}}, @@ -562,9 +696,12 @@ cipher_suites(suite) -> []; cipher_suites(Config) when is_list(Config) -> - MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha,no_export}, + MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha}, [_|_] = Suites = ssl:cipher_suites(), - true = lists:member(MandatoryCipherSuite, Suites). + true = lists:member(MandatoryCipherSuite, Suites), + Suites = ssl:cipher_suites(erlang), + [_|_] =ssl:cipher_suites(openssl). + %%-------------------------------------------------------------------- socket_options(doc) -> ["Test API function getopts/2 and setopts/2"]; @@ -599,9 +736,16 @@ socket_options(Config) when is_list(Config) -> {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), - + ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + ssl_test_lib:close(Client), + + {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 @@ -610,6 +754,8 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, 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. %%-------------------------------------------------------------------- @@ -630,7 +776,7 @@ misc_ssl_options(Config) when is_list(Config) -> {password, []}, {reuse_session, fun(_,_,_,_) -> true end}, {debug, []}, - {cb_info, {gen_tcp, tcp, tcp_closed}}], + {cb_info, {gen_tcp, tcp, tcp_closed, tcp_error}}], Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -796,11 +942,12 @@ upgrade(Config) when is_list(Config) -> TcpOpts = [binary, {reuseaddr, true}], Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - upgrade_result, []}}, - {tcp_options, TcpOpts}, - {ssl_options, ServerOpts}]), + {from, self()}, + {mfa, {?MODULE, + upgrade_result, []}}, + {tcp_options, + [{active, false} | TcpOpts]}, + {ssl_options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_upgrade_client([{node, ClientNode}, {port, Port}, @@ -819,6 +966,7 @@ upgrade(Config) when is_list(Config) -> ssl_test_lib:close(Client). upgrade_result(Socket) -> + ssl:setopts(Socket, [{active, true}]), ok = ssl:send(Socket, "Hello world"), %% Make sure binary is inherited from tcp socket and that we do %% not get the list default! @@ -845,7 +993,8 @@ upgrade_with_timeout(Config) when is_list(Config) -> {timeout, 5000}, {mfa, {?MODULE, upgrade_result, []}}, - {tcp_options, TcpOpts}, + {tcp_options, + [{active, false} | TcpOpts]}, {ssl_options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_upgrade_client([{node, ClientNode}, @@ -985,13 +1134,13 @@ ecertfile(Config) when is_list(Config) -> Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, - {options, ServerBadOpts}]), + {options, ServerBadOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client_error([{node, ClientNode}, - {port, Port}, {host, Hostname}, + {port, Port}, {host, Hostname}, {from, self()}, {options, ClientOpts}]), @@ -1081,7 +1230,6 @@ eoptions(Config) when is_list(Config) -> {verify_fun, function}, {fail_if_no_peer_cert, 0}, {verify_client_once, 1}, - {validate_extensions_fun, function}, {depth, four}, {certfile, 'cert.pem'}, {keyfile,'key.pem' }, @@ -1233,20 +1381,142 @@ shutdown_error(Config) when is_list(Config) -> ok = ssl:close(Listen), {error, closed} = ssl:shutdown(Listen, read_write). -%%-------------------------------------------------------------------- -ciphers(doc) -> - [""]; +%%------------------------------------------------------------------- +ciphers_rsa_signed_certs(doc) -> + ["Test all rsa ssl cipher suites in highest support ssl/tls version"]; + +ciphers_rsa_signed_certs(suite) -> + []; + +ciphers_rsa_signed_certs(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl_test_lib:rsa_suites(), + test_server:format("tls1 erlang cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, rsa). + +ciphers_rsa_signed_certs_ssl3(doc) -> + ["Test all rsa ssl cipher suites in ssl3"]; + +ciphers_rsa_signed_certs_ssl3(suite) -> + []; + +ciphers_rsa_signed_certs_ssl3(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version({3,0}), + + Ciphers = ssl_test_lib:rsa_suites(), + test_server:format("ssl3 erlang cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, rsa). + +ciphers_rsa_signed_certs_openssl_names(doc) -> + ["Test all rsa ssl cipher suites in highest support ssl/tls version"]; -ciphers(suite) -> +ciphers_rsa_signed_certs_openssl_names(suite) -> []; -ciphers(Config) when is_list(Config) -> +ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:openssl_rsa_suites(), + test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, rsa). + + +ciphers_rsa_signed_certs_openssl_names_ssl3(doc) -> + ["Test all dsa ssl cipher suites in ssl3"]; + +ciphers_rsa_signed_certs_openssl_names_ssl3(suite) -> + []; + +ciphers_rsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) -> + Version = ssl_record:protocol_version({3,0}), + Ciphers = ssl_test_lib:openssl_rsa_suites(), + run_suites(Ciphers, Version, Config, rsa). + + +ciphers_dsa_signed_certs(doc) -> + ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; + +ciphers_dsa_signed_certs(suite) -> + []; + +ciphers_dsa_signed_certs(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl_test_lib:dsa_suites(), + test_server:format("tls1 erlang cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, dsa). + +ciphers_dsa_signed_certs_ssl3(doc) -> + ["Test all dsa ssl cipher suites in ssl3"]; + +ciphers_dsa_signed_certs_ssl3(suite) -> + []; + +ciphers_dsa_signed_certs_ssl3(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version({3,0}), - Ciphers = ssl:cipher_suites(), + Ciphers = ssl_test_lib:dsa_suites(), + test_server:format("ssl3 erlang cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, dsa). + + +ciphers_dsa_signed_certs_openssl_names(doc) -> + ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; + +ciphers_dsa_signed_certs_openssl_names(suite) -> + []; + +ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl_test_lib:openssl_dsa_suites(), + test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, dsa). + + +ciphers_dsa_signed_certs_openssl_names_ssl3(doc) -> + ["Test all dsa ssl cipher suites in ssl3"]; + +ciphers_dsa_signed_certs_openssl_names_ssl3(suite) -> + []; + +ciphers_dsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) -> + Version = ssl_record:protocol_version({3,0}), + Ciphers = ssl_test_lib:openssl_dsa_suites(), + run_suites(Ciphers, Version, Config, dsa). + +anonymous_cipher_suites(doc)-> + ["Test the anonymous ciphersuites"]; +anonymous_cipher_suites(suite) -> + []; +anonymous_cipher_suites(Config) when is_list(Config) -> + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:anonymous_suites(), + run_suites(Ciphers, Version, Config, anonymous). + +run_suites(Ciphers, Version, Config, Type) -> + {ClientOpts, ServerOpts} = + case Type of + rsa -> + {?config(client_opts, Config), + ?config(server_opts, Config)}; + dsa -> + {?config(client_opts, Config), + ?config(server_dsa_opts, Config)}; + anonymous -> + %% No certs in opts! + {?config(client_opts, Config), + ?config(server_anon, Config)} + end, + Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config) end, + cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, Ciphers), case lists:flatten(Result) of [] -> @@ -1255,30 +1525,36 @@ ciphers(Config) when is_list(Config) -> test_server:format("Cipher suite errors: ~p~n", [Error]), test_server:fail(cipher_suite_failed_see_test_case_log) end. - -cipher(CipherSuite, Version, Config) -> + +erlang_cipher_suite(Suite) when is_list(Suite)-> + ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite)); +erlang_cipher_suite(Suite) -> + Suite. + +cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> process_flag(trap_exit, true), test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + ErlangCipherSuite = erlang_cipher_suite(CipherSuite), + + ConnectionInfo = {ok, {Version, ErlangCipherSuite}}, + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, connection_info_result, []}}, + {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, {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, []}}, + {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, {options, [{ciphers,[CipherSuite]} | ClientOpts]}]), - - ServerMsg = ClientMsg = {ok, {Version, CipherSuite}}, - - Result = ssl_test_lib:wait_for_result(Server, ServerMsg, - Client, ClientMsg), + + Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), receive {'EXIT', Server, normal} -> @@ -1294,10 +1570,36 @@ cipher(CipherSuite, Version, Config) -> ok -> []; Error -> - [{CipherSuite, Error}] + [{ErlangCipherSuite, Error}] end. %%-------------------------------------------------------------------- +default_reject_anonymous(doc)-> + ["Test that by default anonymous cipher suites are rejected "]; +default_reject_anonymous(suite) -> + []; +default_reject_anonymous(Config) when is_list(Config) -> + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + [Cipher | _] = ssl_test_lib:anonymous_suites(), + + 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,[Cipher]} | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, "insufficient security"}, + Client, {error, "insufficient security"}). + +%%-------------------------------------------------------------------- reuse_session(doc) -> ["Test reuse of sessions (short handshake)"]; @@ -1884,7 +2186,6 @@ server_require_peer_cert_fail(Config) when is_list(Config) -> Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, no_result, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), @@ -1892,13 +2193,10 @@ server_require_peer_cert_fail(Config) when is_list(Config) -> Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, no_result, []}}, {options, [{active, false} | BadClientOpts]}]), ssl_test_lib:check_result(Server, {error, esslaccept}, - Client, {error, esslconnect}), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + Client, {error, esslconnect}). %%-------------------------------------------------------------------- @@ -1980,14 +2278,7 @@ client_verify_none_active_once(Config) when is_list(Config) -> {mfa, {?MODULE, send_recv_result_active_once, []}}, {options, [{active, once} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - %% TODO: send message to test process to make sure - %% verifyfun has beeen run as it has the same behavior as - %% the default fun - VerifyFun = fun([{bad_cert, unknown_ca}]) -> - true; - (_) -> - false - end, + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, @@ -1995,8 +2286,7 @@ client_verify_none_active_once(Config) when is_list(Config) -> send_recv_result_active_once, []}}, {options, [{active, once}, - {verify, verify_none}, - {verify_fun, VerifyFun} + {verify, verify_none} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -2076,6 +2366,76 @@ server_renegotiate(Config) when is_list(Config) -> ok. %%-------------------------------------------------------------------- +client_renegotiate_reused_session(doc) -> + ["Test ssl:renegotiate/1 on client when the ssl session will be reused."]; + +client_renegotiate_reused_session(suite) -> + []; + +client_renegotiate_reused_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {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, + renegotiate_reuse_session, [Data]}}, + {options, [{reuse_sessions, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. +%%-------------------------------------------------------------------- +server_renegotiate_reused_session(doc) -> + ["Test ssl:renegotiate/1 on server when the ssl session will be reused."]; + +server_renegotiate_reused_session(suite) -> + []; + +server_renegotiate_reused_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_reuse_session, [Data]}}, + {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, erlang_ssl_receive, [Data]}}, + {options, [{reuse_sessions, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + ok. + +%%-------------------------------------------------------------------- client_no_wrap_sequence_number(doc) -> ["Test that erlang client will renegotiate session when", "max sequence number celing is about to be reached. Although" @@ -2162,34 +2522,89 @@ extended_key_usage(suite) -> []; extended_key_usage(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), PrivDir = ?config(priv_dir, Config), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - NewCertFile = filename:join(PrivDir, "cert.pem"), - - {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(CertFile), + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions, + NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions = + [ServerExtKeyUsageExt | + ServerExtensions]}, + NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']}, + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions, + NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions = + [ClientExtKeyUsageExt | + ClientExtensions]}, + NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, [{verify, verify_peer} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, [{verify, verify_peer} | NewClientOpts]}]), - {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), + ssl_test_lib:check_result(Server, ok, Client, ok), - {ok, Key} = public_key:decode_private_key(KeyInfo), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). - {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp), - - ExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, +%%-------------------------------------------------------------------- +no_authority_key_identifier(doc) -> + ["Test cert that does not have authorityKeyIdentifier extension" + " but are present in trusted certs db."]; +no_authority_key_identifier(suite) -> + []; +no_authority_key_identifier(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), + + CertFile = proplists:get_value(certfile, ServerOpts), + NewCertFile = filename:join(PrivDir, "server/new_cert.pem"), + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, - Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, + NewExtensions = delete_authority_key_extension(Extensions, []), + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions}, - NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = [ExtKeyUsageExt |Extensions]}, + test_server:format("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), - NewDerCert = public_key:sign(NewOTPTbsCert, Key), - - public_key:der_to_pem(NewCertFile, [{cert, NewDerCert}]), - + NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2203,51 +2618,453 @@ extended_key_usage(Config) when is_list(Config) -> {host, Hostname}, {from, self()}, {mfa, {?MODULE, send_recv_result_active, []}}, - {options, ClientOpts}]), + {options, [{verify, verify_peer} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). +delete_authority_key_extension([], Acc) -> + lists:reverse(Acc); +delete_authority_key_extension([#'Extension'{extnID = ?'id-ce-authorityKeyIdentifier'} | Rest], + Acc) -> + delete_authority_key_extension(Rest, Acc); +delete_authority_key_extension([Head | Rest], Acc) -> + delete_authority_key_extension(Rest, [Head | Acc]). + %%-------------------------------------------------------------------- -validate_extensions_fun(doc) -> - ["Test that it is possible to specify a validate_extensions_fun"]; -validate_extensions_fun(suite) -> +invalid_signature_server(doc) -> + ["Test server with invalid signature"]; + +invalid_signature_server(suite) -> []; -validate_extensions_fun(Config) when is_list(Config) -> +invalid_signature_server(Config) when is_list(Config) -> ClientOpts = ?config(client_verification_opts, Config), ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "server/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], - Fun = fun(Extensions, State, _, AccError) -> - {Extensions, State, AccError} - end, + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, NewServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, "bad certificate"}, + Client, {error,"bad certificate"}). + +%%-------------------------------------------------------------------- + +invalid_signature_client(doc) -> + ["Test server with invalid signature"]; + +invalid_signature_client(suite) -> + []; + +invalid_signature_client(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "client/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{validate_extensions_fun, Fun}, - {verify, verify_peer} | ServerOpts]}]), + {options, [{verify, verify_peer} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, NewClientOpts}]), + + tcp_delivery_workaround(Server, {error, "bad certificate"}, + Client, {error,"bad certificate"}). + +tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> + receive + {Server, ServerMsg} -> + receive + {Client, ClientMsg} -> + ok; + {Client, {error,closed}} -> + test_server:format("client got close"); + Unexpected -> + test_server:fail(Unexpected) + end; + {Client, ClientMsg} -> + receive + {Server, ServerMsg} -> + ok; + Unexpected -> + test_server:fail(Unexpected) + end; + {Client, {error,closed}} -> + receive + {Server, ServerMsg} -> + ok; + Unexpected -> + test_server:fail(Unexpected) + end; + {Server, {error,closed}} -> + receive + {Client, ClientMsg} -> + ok; + {Client, {error,closed}} -> + test_server:format("client got close"), + ok; + Unexpected -> + test_server:fail(Unexpected) + end; + Unexpected -> + test_server:fail(Unexpected) + end. +%%-------------------------------------------------------------------- +cert_expired(doc) -> + ["Test server with invalid signature"]; + +cert_expired(suite) -> + []; + +cert_expired(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"), + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), + OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, + + {Year, Month, Day} = date(), + {Hours, Min, Sec} = time(), + NotBeforeStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-2, + two_digits_str(Month), + two_digits_str(Day), + two_digits_str(Hours), + two_digits_str(Min), + two_digits_str(Sec)])), + NotAfterStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-1, + two_digits_str(Month), + two_digits_str(Day), + two_digits_str(Hours), + two_digits_str(Min), + two_digits_str(Sec)])), + NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}}, + + test_server:format("Validity: ~p ~n NewValidity: ~p ~n", + [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]), + + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity}, + NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, NewServerOpts}]), Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, "certificate expired"}, + Client, {error, "certificate expired"}). - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, +two_digits_str(N) when N < 10 -> + lists:flatten(io_lib:format("0~p", [N])); +two_digits_str(N) -> + lists:flatten(io_lib:format("~p", [N])). + +%%-------------------------------------------------------------------- + +client_with_cert_cipher_suites_handshake(doc) -> + ["Test that client with a certificate without keyEncipherment usage " + " extension can connect to a server with restricted cipher suites "]; + +client_with_cert_cipher_suites_handshake(suite) -> + []; + +client_with_cert_cipher_suites_handshake(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts_digital_signature_only, Config), + ServerOpts = ?config(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, + send_recv_result_active, []}}, + {options, [{active, true}, + {ciphers, ssl_test_lib:rsa_non_signed_suites()} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options,[{validate_extensions_fun, Fun} | ClientOpts]}]), - + {from, self()}, + {mfa, {?MODULE, + 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). +%%-------------------------------------------------------------------- +unknown_server_ca_fail(doc) -> + ["Test that the client fails if the ca is unknown in verify_peer mode"]; +unknown_server_ca_fail(suite) -> + []; +unknown_server_ca_fail(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(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()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, [test_to_update_user_state | UserState]}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, []}, + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error,"unknown ca"}, + Client, {error, "unknown ca"}), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +unknown_server_ca_accept_verify_none(doc) -> + ["Test that the client succeds if the ca is unknown in verify_none mode"]; +unknown_server_ca_accept_verify_none(suite) -> + []; +unknown_server_ca_accept_verify_none(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(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, + 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, {?MODULE, + send_recv_result_active, []}}, + {options, + [{verify, verify_none}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +unknown_server_ca_accept_verify_peer(doc) -> + ["Test that the client succeds if the ca is unknown in verify_peer mode" + " with a verify_fun that accepts the unknown ca error"]; +unknown_server_ca_accept_verify_peer(suite) -> + []; +unknown_server_ca_accept_verify_peer(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(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, + send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, []}, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +unknown_server_ca_accept_backwardscompatibilty(doc) -> + ["Test that old style verify_funs will work"]; +unknown_server_ca_accept_backwardscompatibilty(suite) -> + []; +unknown_server_ca_accept_backwardscompatibilty(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(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, + send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc; + (Other, Acc) -> [Other | Acc] + end, + VerifyFun = + fun(ErrorList) -> + case lists:foldl(AcceptBadCa, [], ErrorList) of + [] -> true; + [_|_] -> false + end + end, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, VerifyFun}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +der_input(doc) -> + ["Test to input certs and key as der"]; + +der_input(suite) -> + []; + +der_input(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + DHParamFile = filename:join(DataDir, "dHParam.pem"), + + SeverVerifyOpts = ?config(server_verification_opts, Config), + {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | + SeverVerifyOpts]), + ClientVerifyOpts = ?config(client_verification_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, {?MODULE, 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, {?MODULE, 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). +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), + [{_, 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, {rsa, Key}, CaCerts, DHParams}. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +erlang_ssl_receive(Socket, Data) -> + receive + {ssl, Socket, Data} -> + io:format("Received ~p~n",[Data]), + ok; + Other -> + test_server:fail({unexpected_message, Other}) + after ?SLEEP * 3 -> + test_server:fail({did_not_get, Data}) + end. + send_recv_result(Socket) -> ssl:send(Socket, "Hello world"), {ok,"Hello world"} = ssl:recv(Socket, 11), @@ -2270,6 +3087,7 @@ send_recv_result_active_once(Socket) -> result_ok(_Socket) -> ok. + renegotiate(Socket, Data) -> test_server:format("Renegotiating ~n", []), Result = ssl:renegotiate(Socket), @@ -2278,261 +3096,11 @@ renegotiate(Socket, Data) -> case Result of ok -> ok; - %% It is not an error in erlang ssl - %% if peer rejects renegotiation. - %% Connection will stay up - {error, renegotiation_rejected} -> - ok; Other -> Other end. - -session_cache_process_list(doc) -> - ["Test reuse of sessions (short handshake)"]; - -session_cache_process_list(suite) -> - []; -session_cache_process_list(Config) when is_list(Config) -> - session_cache_process(list,Config). -session_cache_process_mnesia(doc) -> - ["Test reuse of sessions (short handshake)"]; - -session_cache_process_mnesia(suite) -> - []; -session_cache_process_mnesia(Config) when is_list(Config) -> - session_cache_process(mnesia,Config). - -session_cache_process(Type,Config) when is_list(Config) -> - process_flag(trap_exit, true), - setup_session_cb(Type), - - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(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, session_info_result, []}}, - {options, - [{session_cache_cb, ?MODULE}| - ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - Server ! listen, - - %% Make sure session is registered +renegotiate_reuse_session(Socket, Data) -> + %% Make sure session is registerd test_server:sleep(?SLEEP), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client1, SessionInfo} -> - ok; - {Client1, Other} -> - test_server:format("Expected: ~p, Unexpected: ~p~n", - [SessionInfo, Other]), - test_server:fail(session_not_reused) - end, - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client0), - ssl_test_lib:close(Client1), - - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, - {options, - [{reuse_sessions, false} | ServerOpts]}]), - Port1 = ssl_test_lib:inet_port(Server1), - - Client3 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port1}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - - SessionInfo1 = - receive - {Server1, Info1} -> - Info1 - end, - - Server1 ! listen, - - %% Make sure session is registered - test_server:sleep(?SLEEP), - - Client4 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port1}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - - receive - {Client4, SessionInfo1} -> - test_server:fail( - session_reused_when_session_reuse_disabled_by_server); - {Client4, _Other} -> - ok - end, - - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client3), - ssl_test_lib:close(Client4), - process_flag(trap_exit, false). - -setup_session_cb(Type) -> - ssl_test = ets:new(ssl_test,[named_table, set,public]), - ets:insert(ssl_test, {type,Type}). - -session_cb() -> - [{type,Type}] = ets:lookup(ssl_test, type), - Type. - -init() -> - io:format("~p~n",[?LINE]), - case session_cb() of - list -> - spawn(fun() -> session_loop([]) end); - mnesia -> - mnesia:start(), - {atomic,ok} = mnesia:create_table(sess_cache, []) - end. - -terminate(Cache) -> - io:format("~p~n",[?LINE]), - case session_cb() of - list -> - Cache ! terminate; - mnesia -> - {atomic,ok} = mnesia:delete_table(sess_cache, []) - end. - -lookup(Cache, Key) -> - io:format("~p~n",[?LINE]), - case session_cb() of - list -> - Cache ! {self(), lookup, Key}, - receive {Cache, Res} -> Res end; - mnesia -> - case mnesia:transaction(fun() -> - mnesia:read(sess_cache, - Key, read) - end) of - {atomic, [Session]} -> Session; - _ -> undefined - end - end. - -update(Cache, Key, Value) -> - io:format("~p~n",[?LINE]), - case session_cb() of - list -> - Cache ! {update, Key, Value}; - mnesia -> - {atomic, ok} = - mnesia:transaction(fun() -> - mnesia:write(sess_cache, - Key, Value) - end) - end. - -delete(Cache, Key) -> - io:format("~p~n",[?LINE]), - case session_cb() of - list -> - Cache ! {delete, Key}; - mnesia -> - {atomic, ok} = - mnesia:transaction(fun() -> - mnesia:delete(sess_cache, Key) - end) - end. - -foldl(Fun, Acc, Cache) -> - io:format("~p~n",[?LINE]), - case session_cb() of - list -> - Cache ! {self(),foldl,Fun,Acc}, - receive {Cache, Res} -> Res end; - mnesia -> - Foldl = fun() -> - mnesia:foldl(Fun, Acc, sess_cache) - end, - {atomic, Res} = mnesia:transaction(Foldl), - Res - end. - -select_session(Cache, PartialKey) -> - io:format("~p~n",[?LINE]), - case session_cb() of - list -> - Cache ! {self(),select_session, PartialKey}, - receive {Cache, Res} -> Res end; - mnesia -> - Sel = fun() -> - mnesia:select(Cache, - [{{{PartialKey,'$1'}, '$2'}, - [],['$$']}]) - end, - {atomic, Res} = mnesia:transaction(Sel), - Res - end. - -session_loop(Sess) -> - receive - terminate -> - ok; - {Pid, lookup, Key} -> - case lists:keysearch(Key,1,Sess) of - {value, {Key,Value}} -> - Pid ! {self(), Value}; - _ -> - Pid ! {self(), undefined} - end, - session_loop(Sess); - {update, Key, Value} -> - session_loop([{Key,Value}|Sess]); - {delete, Key} -> - session_loop(lists:keydelete(Key,1,Sess)); - {Pid,foldl,Fun,Acc} -> - Res = lists:foldl(Fun, Acc,Sess), - Pid ! {self(), Res}, - session_loop(Sess); - {Pid,select_session,PKey} -> - Sel = fun({{Head, _},Session}, Acc) when Head =:= PKey -> - [Session|Acc]; - (_,Acc) -> - Acc - end, - Pid ! {self(), lists:foldl(Sel, [], Sess)}, - session_loop(Sess) - end. - -erlang_ssl_receive(Socket, Data) -> - receive - {ssl, Socket, Data} -> - io:format("Received ~p~n",[Data]), - ok; - Other -> - test_server:fail({unexpected_message, Other}) - after ?SLEEP * 3 -> - test_server:fail({did_not_get, Data}) - end. - + renegotiate(Socket, Data). |