diff options
Diffstat (limited to 'lib/ssl/test/ssl_test_lib.erl')
-rw-r--r-- | lib/ssl/test/ssl_test_lib.erl | 443 |
1 files changed, 359 insertions, 84 deletions
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index f1f5b9ae0a..34c52b10b3 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,8 +20,7 @@ %% -module(ssl_test_lib). --include("test_server.hrl"). --include("test_server_line.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). %% Note: This directive should only be used in test suites. @@ -29,12 +28,6 @@ -record(sslsocket, { fd = nil, pid = nil}). -timetrap(Time) -> - Mul = try - test_server:timetrap_scale_factor() - catch _:_ -> 1 end, - test_server:timetrap(1000+Time*Mul). - %% For now always run locally run_where(_) -> ClientNode = node(), @@ -65,8 +58,9 @@ run_server(Opts) -> Port = proplists:get_value(port, Opts), Options = proplists:get_value(options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("ssl:listen(~p, ~p)~n", [Port, Options]), - {ok, ListenSocket} = rpc:call(Node, ssl, listen, [Port, Options]), + Transport = proplists:get_value(transport, Opts, ssl), + ct:log("ssl:listen(~p, ~p)~n", [Port, Options]), + {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), run_server(ListenSocket, Opts). @@ -81,14 +75,15 @@ do_run_server(_, {error, timeout} = Result, Opts) -> do_run_server(ListenSocket, AcceptSocket, Opts) -> Node = proplists:get_value(node, Opts), Pid = proplists:get_value(from, Opts), + Transport = proplists:get_value(transport, Opts, ssl), {Module, Function, Args} = proplists:get_value(mfa, Opts), - test_server:format("Server: apply(~p,~p,~p)~n", + ct:log("Server: apply(~p,~p,~p)~n", [Module, Function, [AcceptSocket | Args]]), case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of no_result_msg -> ok; Msg -> - test_server:format("Server Msg: ~p ~n", [Msg]), + ct:log("Server Msg: ~p ~n", [Msg]), Pid ! {self(), Msg} end, receive @@ -97,15 +92,16 @@ do_run_server(ListenSocket, AcceptSocket, Opts) -> {listen, MFA} -> run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]); close -> - test_server:format("Server closing ~p ~n", [self()]), - Result = rpc:call(Node, ssl, close, [AcceptSocket], 500), - test_server:format("Result ~p ~n", [Result]); + ct:log("Server closing ~p ~n", [self()]), + Result = rpc:call(Node, Transport, close, [AcceptSocket], 500), + Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500), + ct:log("Result ~p : ~p ~n", [Result, Result1]); {ssl_closed, _} -> ok end. %%% To enable to test with s_client -reconnect -connect(ListenSocket, Opts) -> +connect(#sslsocket{} = ListenSocket, Opts) -> Node = proplists:get_value(node, Opts), ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0), Timeout = proplists:get_value(timeout, Opts, infinity), @@ -116,15 +112,21 @@ connect(ListenSocket, Opts) -> _ -> remove_close_msg(ReconnectTimes), AcceptSocket - end. - + end; +connect(ListenSocket, Opts) -> + Node = proplists:get_value(node, Opts), + ct:log("gen_tcp:accept(~p)~n", [ListenSocket]), + {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, + [ListenSocket]), + AcceptSocket. + connect(_, _, 0, AcceptSocket, _) -> AcceptSocket; connect(ListenSocket, Node, N, _, Timeout) -> - test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]), + ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, [ListenSocket]), - test_server:format("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]), + ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]), case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of ok -> @@ -157,45 +159,48 @@ run_client(Opts) -> Host = proplists:get_value(host, Opts), Port = proplists:get_value(port, Opts), Pid = proplists:get_value(from, Opts), + Transport = proplists:get_value(transport, Opts, ssl), Options = proplists:get_value(options, Opts), - test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), - case rpc:call(Node, ssl, connect, [Host, Port, Options]) of + ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), + case rpc:call(Node, Transport, connect, [Host, Port, Options]) of {ok, Socket} -> Pid ! { connected, Socket }, - test_server:format("Client: connected~n", []), + ct:log("Client: connected~n", []), %% In special cases we want to know the client port, it will %% be indicated by sending {port, 0} in options list! send_selected_port(Pid, proplists:get_value(port, Options), Socket), {Module, Function, Args} = proplists:get_value(mfa, Opts), - test_server:format("Client: apply(~p,~p,~p)~n", + ct:log("Client: apply(~p,~p,~p)~n", [Module, Function, [Socket | Args]]), case rpc:call(Node, Module, Function, [Socket | Args]) of no_result_msg -> ok; Msg -> - test_server:format("Client Msg: ~p ~n", [Msg]), + ct:log("Client Msg: ~p ~n", [Msg]), Pid ! {self(), Msg} end, receive close -> - test_server:format("Client closing~n", []), - rpc:call(Node, ssl, close, [Socket]); + ct:log("Client closing~n", []), + rpc:call(Node, Transport, close, [Socket]); {ssl_closed, Socket} -> + ok; + {gen_tcp, closed} -> ok end; {error, Reason} -> - test_server:format("Client: connection failed: ~p ~n", [Reason]), + ct:log("Client: connection failed: ~p ~n", [Reason]), Pid ! {self(), {error, Reason}} end. close(Pid) -> - test_server:format("Close ~p ~n", [Pid]), + ct:log("Close ~p ~n", [Pid]), Monitor = erlang:monitor(process, Pid), Pid ! close, receive {'DOWN', Monitor, process, Pid, Reason} -> erlang:demonitor(Monitor), - test_server:format("Pid: ~p down due to:~p ~n", [Pid, Reason]) + ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason]) end. check_result(Server, ServerMsg, Client, ClientMsg) -> @@ -207,7 +212,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) -> Unexpected -> Reason = {{expected, {Client, ClientMsg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end; {Client, ClientMsg} -> receive @@ -216,7 +221,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) -> Unexpected -> Reason = {{expected, {Server, ClientMsg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end; {Port, {data,Debug}} when is_port(Port) -> io:format("openssl ~s~n",[Debug]), @@ -225,7 +230,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) -> Unexpected -> Reason = {{expected, {Client, ClientMsg}}, {expected, {Server, ServerMsg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end. check_result(Pid, Msg) -> @@ -238,7 +243,7 @@ check_result(Pid, Msg) -> Unexpected -> Reason = {{expected, {Pid, Msg}}, {got, Unexpected}}, - test_server:fail(Reason) + ct:fail(Reason) end. wait_for_result(Server, ServerMsg, Client, ClientMsg) -> @@ -276,6 +281,13 @@ wait_for_result(Pid, Msg) -> %% Unexpected end. +user_lookup(psk, _Identity, UserState) -> + {ok, UserState}; +user_lookup(srp, Username, _UserState) -> + Salt = ssl:random_bytes(16), + UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]), + {ok, {srp_1024, Salt, UserPassHash}}. + cert_options(Config) -> ClientCaCertFile = filename:join([?config(priv_dir, Config), "client", "cacerts.pem"]), @@ -302,6 +314,7 @@ cert_options(Config) -> "badcert.pem"]), BadKeyFile = filename:join([?config(priv_dir, Config), "badkey.pem"]), + PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>, [{client_opts, [{ssl_imp, new},{reuseaddr, true}]}, {client_verification_opts, [{cacertfile, ClientCaCertFile}, {certfile, ClientCertFile}, @@ -314,6 +327,34 @@ cert_options(Config) -> {server_opts, [{ssl_imp, new},{reuseaddr, true}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, {server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]}, + {client_psk, [{ssl_imp, new},{reuseaddr, true}, + {psk_identity, "Test-User"}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}, + {server_psk, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}, + {ciphers, psk_suites()}]}, + {server_psk_hint, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {psk_identity, "HINT"}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}, + {ciphers, psk_suites()}]}, + {server_psk_anon, [{ssl_imp, new},{reuseaddr, true}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}, + {ciphers, psk_anon_suites()}]}, + {server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true}, + {psk_identity, "HINT"}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}, + {ciphers, psk_anon_suites()}]}, + {client_srp, [{ssl_imp, new},{reuseaddr, true}, + {srp_identity, {"Test-User", "secret"}}]}, + {server_srp, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {user_lookup_fun, {fun user_lookup/3, undefined}}, + {ciphers, srp_suites()}]}, + {server_srp_anon, [{ssl_imp, new},{reuseaddr, true}, + {user_lookup_fun, {fun user_lookup/3, undefined}}, + {ciphers, srp_anon_suites()}]}, {server_verification_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ServerCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, @@ -351,9 +392,63 @@ make_dsa_cert(Config) -> {verify, verify_peer}]}, {client_dsa_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ClientCaCertFile}, - {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}, + {server_srp_dsa, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {user_lookup_fun, {fun user_lookup/3, undefined}}, + {ciphers, srp_dss_suites()}]}, + {client_srp_dsa, [{ssl_imp, new},{reuseaddr, true}, + {srp_identity, {"Test-User", "secret"}}, + {cacertfile, ClientCaCertFile}, + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} | Config]. +make_ecdsa_cert(Config) -> + CryptoSupport = crypto:supports(), + case proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)) of + true -> + {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""), + {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""), + [{server_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, + {server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {verify, verify_peer}]}, + {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} + | Config]; + _ -> + Config + end. + +%% RFC 4492, Sect. 2.3. ECDH_RSA +%% +%% This key exchange algorithm is the same as ECDH_ECDSA except that the +%% server's certificate MUST be signed with RSA rather than ECDSA. +make_ecdh_rsa_cert(Config) -> + CryptoSupport = crypto:supports(), + case proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)) of + true -> + {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"), + {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"), + [{server_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, + {server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {verify, verify_peer}]}, + {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} + | Config]; + _ -> + Config + end. make_mix_cert(Config) -> {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa, @@ -405,33 +500,33 @@ run_upgrade_server(Opts) -> SslOptions = proplists:get_value(ssl_options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), + ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - test_server:format("gen_tcp:accept(~p)~n", [ListenSocket]), + ct:log("gen_tcp:accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), try {ok, SslAcceptSocket} = case TimeOut of infinity -> - test_server:format("ssl:ssl_accept(~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, SslOptions]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions]); _ -> - test_server:format("ssl:ssl_accept(~p, ~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p, ~p)~n", [AcceptSocket, SslOptions, TimeOut]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions, TimeOut]) end, {Module, Function, Args} = proplists:get_value(mfa, Opts), Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]), - test_server:format("Upgrade Server Msg: ~p ~n", [Msg]), + ct:log("Upgrade Server Msg: ~p ~n", [Msg]), Pid ! {self(), Msg}, receive close -> - test_server:format("Upgrade Server closing~n", []), + ct:log("Upgrade Server closing~n", []), rpc:call(Node, ssl, close, [SslAcceptSocket]) end catch error:{badmatch, Error} -> @@ -449,24 +544,24 @@ run_upgrade_client(Opts) -> TcpOptions = proplists:get_value(tcp_options, Opts), SslOptions = proplists:get_value(ssl_options, Opts), - test_server:format("gen_tcp:connect(~p, ~p, ~p)~n", + ct:log("gen_tcp:connect(~p, ~p, ~p)~n", [Host, Port, TcpOptions]), {ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]), send_selected_port(Pid, Port, Socket), - test_server:format("ssl:connect(~p, ~p)~n", [Socket, SslOptions]), + ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]), {ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]), {Module, Function, Args} = proplists:get_value(mfa, Opts), - test_server:format("apply(~p, ~p, ~p)~n", + ct:log("apply(~p, ~p, ~p)~n", [Module, Function, [SslSocket | Args]]), Msg = rpc:call(Node, Module, Function, [SslSocket | Args]), - test_server:format("Upgrade Client Msg: ~p ~n", [Msg]), + ct:log("Upgrade Client Msg: ~p ~n", [Msg]), Pid ! {self(), Msg}, receive close -> - test_server:format("Upgrade Client closing~n", []), + ct:log("Upgrade Client closing~n", []), rpc:call(Node, ssl, close, [SslSocket]) end. @@ -485,20 +580,20 @@ run_upgrade_server_error(Opts) -> SslOptions = proplists:get_value(ssl_options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), + ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - test_server:format("gen_tcp:accept(~p)~n", [ListenSocket]), + ct:log("gen_tcp:accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), Error = case TimeOut of infinity -> - test_server:format("ssl:ssl_accept(~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, SslOptions]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions]); _ -> - test_server:format("ssl:ssl_accept(~p, ~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p, ~p)~n", [AcceptSocket, SslOptions, TimeOut]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions, TimeOut]) @@ -517,22 +612,31 @@ run_server_error(Opts) -> Port = proplists:get_value(port, Opts), Options = proplists:get_value(options, Opts), Pid = proplists:get_value(from, Opts), - test_server:format("ssl:listen(~p, ~p)~n", [Port, Options]), - case rpc:call(Node, ssl, listen, [Port, Options]) of - {ok, ListenSocket} -> + Transport = proplists:get_value(transport, Opts, ssl), + ct:log("ssl:listen(~p, ~p)~n", [Port, Options]), + case rpc:call(Node, Transport, listen, [Port, Options]) of + {ok, #sslsocket{} = ListenSocket} -> %% To make sure error_client will %% get {error, closed} and not {error, connection_refused} Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]), - case rpc:call(Node, ssl, transport_accept, [ListenSocket]) of + ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), + case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of {error, _} = Error -> Pid ! {self(), Error}; {ok, AcceptSocket} -> - test_server:format("ssl:ssl_accept(~p)~n", [AcceptSocket]), + ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]), Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]), Pid ! {self(), Error} end; + {ok, ListenSocket} -> + Pid ! {listen, up}, + send_selected_port(Pid, Port, ListenSocket), + ct:log("~p:accept(~p)~n", [Transport, ListenSocket]), + case rpc:call(Node, Transport, accept, [ListenSocket]) of + {error, _} = Error -> + Pid ! {self(), Error} + end; Error -> %% Not really true but as this is an error test %% this is what we want. @@ -548,9 +652,10 @@ run_client_error(Opts) -> Host = proplists:get_value(host, Opts), Port = proplists:get_value(port, Opts), Pid = proplists:get_value(from, Opts), + Transport = proplists:get_value(transport, Opts, ssl), Options = proplists:get_value(options, Opts), - test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), - Error = rpc:call(Node, ssl, connect, [Host, Port, Options]), + ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), + Error = rpc:call(Node, Transport, connect, [Host, Port, Options]), Pid ! {self(), Error}. inet_port(Pid) when is_pid(Pid)-> @@ -577,7 +682,7 @@ trigger_renegotiate(Socket, [ErlData, N]) -> trigger_renegotiate(Socket, ErlData, N, Id). trigger_renegotiate(Socket, _, 0, Id) -> - test_server:sleep(1000), + ct:sleep(1000), case ssl:session_info(Socket) of [{session_id, Id} | _ ] -> fail_session_not_renegotiated; @@ -606,11 +711,16 @@ send_selected_port(Pid, 0, Socket) -> send_selected_port(_,_,_) -> ok. -rsa_suites() -> - lists:filter(fun({dhe_dss, _, _}) -> - false; +rsa_suites(CounterPart) -> + ECC = is_sane_ecc(CounterPart), + lists:filter(fun({rsa, _, _}) -> + true; + ({dhe_rsa, _, _}) -> + true; + ({ecdhe_rsa, _, _}) when ECC == true -> + true; (_) -> - true + false end, ssl:cipher_suites()). @@ -630,17 +740,38 @@ dsa_suites() -> end, ssl:cipher_suites()). +ecdsa_suites() -> + lists:filter(fun({ecdhe_ecdsa, _, _}) -> + true; + (_) -> + false + end, + ssl:cipher_suites()). -openssl_rsa_suites() -> +ecdh_rsa_suites() -> + lists:filter(fun({ecdh_rsa, _, _}) -> + true; + (_) -> + false + end, + ssl:cipher_suites()). + +openssl_rsa_suites(CounterPart) -> Ciphers = ssl:cipher_suites(openssl), + Names = case is_sane_ecc(CounterPart) of + true -> + "DSS | ECDSA"; + false -> + "DSS | ECDHE | ECDH" + end, lists:filter(fun(Str) -> - case re:run(Str,"DSS",[]) of + case re:run(Str, Names,[]) of nomatch -> - true; + false; _ -> - false + true end - end, Ciphers). + end, Ciphers). openssl_dsa_suites() -> Ciphers = ssl:cipher_suites(openssl), @@ -653,12 +784,88 @@ openssl_dsa_suites() -> end end, Ciphers). +openssl_ecdsa_suites() -> + Ciphers = ssl:cipher_suites(openssl), + lists:filter(fun(Str) -> + case re:run(Str,"ECDHE-ECDSA",[]) of + nomatch -> + false; + _ -> + true + end + end, Ciphers). + +openssl_ecdh_rsa_suites() -> + Ciphers = ssl:cipher_suites(openssl), + lists:filter(fun(Str) -> + case re:run(Str,"ECDH-RSA",[]) of + nomatch -> + false; + _ -> + true + end + end, Ciphers). + anonymous_suites() -> - [{dh_anon, rc4_128, md5}, - {dh_anon, des_cbc, sha}, - {dh_anon, '3des_ede_cbc', sha}, - {dh_anon, aes_128_cbc, sha}, - {dh_anon, aes_256_cbc, sha}]. + Suites = + [{dh_anon, rc4_128, md5}, + {dh_anon, des_cbc, sha}, + {dh_anon, '3des_ede_cbc', sha}, + {dh_anon, aes_128_cbc, sha}, + {dh_anon, aes_256_cbc, sha}, + {ecdh_anon,rc4_128,sha}, + {ecdh_anon,'3des_ede_cbc',sha}, + {ecdh_anon,aes_128_cbc,sha}, + {ecdh_anon,aes_256_cbc,sha}], + ssl_cipher:filter_suites(Suites). + +psk_suites() -> + Suites = + [{psk, rc4_128, sha}, + {psk, '3des_ede_cbc', sha}, + {psk, aes_128_cbc, sha}, + {psk, aes_256_cbc, sha}, + {dhe_psk, rc4_128, sha}, + {dhe_psk, '3des_ede_cbc', sha}, + {dhe_psk, aes_128_cbc, sha}, + {dhe_psk, aes_256_cbc, sha}, + {rsa_psk, rc4_128, sha}, + {rsa_psk, '3des_ede_cbc', sha}, + {rsa_psk, aes_128_cbc, sha}, + {rsa_psk, aes_256_cbc, sha}], + ssl_cipher:filter_suites(Suites). + +psk_anon_suites() -> + [{psk, rc4_128, sha}, + {psk, '3des_ede_cbc', sha}, + {psk, aes_128_cbc, sha}, + {psk, aes_256_cbc, sha}, + {dhe_psk, rc4_128, sha}, + {dhe_psk, '3des_ede_cbc', sha}, + {dhe_psk, aes_128_cbc, sha}, + {dhe_psk, aes_256_cbc, sha}]. + +srp_suites() -> + Suites = + [{srp_anon, '3des_ede_cbc', sha}, + {srp_rsa, '3des_ede_cbc', sha}, + {srp_anon, aes_128_cbc, sha}, + {srp_rsa, aes_128_cbc, sha}, + {srp_anon, aes_256_cbc, sha}, + {srp_rsa, aes_256_cbc, sha}], + ssl_cipher:filter_suites(Suites). + +srp_anon_suites() -> + [{srp_anon, '3des_ede_cbc', sha}, + {srp_anon, aes_128_cbc, sha}, + {srp_anon, aes_256_cbc, sha}]. + +srp_dss_suites() -> + Suites = + [{srp_dss, '3des_ede_cbc', sha}, + {srp_dss, aes_128_cbc, sha}, + {srp_dss, aes_256_cbc, sha}], + ssl_cipher:filter_suites(Suites). pem_to_der(File) -> {ok, PemBin} = file:read_file(File), @@ -670,7 +877,7 @@ der_to_pem(File, Entries) -> cipher_result(Socket, Result) -> Result = ssl:connection_info(Socket), - test_server:format("Successfull connect: ~p~n", [Result]), + ct:log("Successfull connect: ~p~n", [Result]), %% Importante to send two packets here %% to properly test "cipher state" handling ssl:send(Socket, "Hello\n"), @@ -740,14 +947,82 @@ init_tls_version(Version) -> ssl:start(). sufficient_crypto_support('tlsv1.2') -> - Data = "Sampl", - Data2 = "e #1", - Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39, - 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>, - try - crypto:sha256_mac(Key, lists:flatten([Data, Data2])), - true - catch _:_ -> false - end; + CryptoSupport = crypto:supports(), + proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)); +sufficient_crypto_support(ciphers_ec) -> + CryptoSupport = crypto:supports(), + proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)); sufficient_crypto_support(_) -> true. + +send_recv_result_active(Socket) -> + ssl:send(Socket, "Hello world"), + receive + {ssl, Socket, "H"} -> + receive + {ssl, Socket, "ello world"} -> + ok + end; + {ssl, Socket, "Hello world"} -> + ok + end. + +send_recv_result(Socket) -> + ssl:send(Socket, "Hello world"), + {ok,"Hello world"} = ssl:recv(Socket, 11), + ok. + +send_recv_result_active_once(Socket) -> + ssl:send(Socket, "Hello world"), + receive + {ssl, Socket, "H"} -> + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, "ello world"} -> + ok + end; + {ssl, Socket, "Hello world"} -> + ok + end. + +is_sane_ecc(openssl) -> + case os:cmd("openssl version") of + "OpenSSL 1.0.0a" ++ _ -> % Known bug in openssl + %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list + false; + "OpenSSL 1.0.0" ++ _ -> % Known bug in openssl + %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list + false; + "OpenSSL 0.9.8" ++ _ -> % Does not support ECC + false; + "OpenSSL 0.9.7" ++ _ -> % Does not support ECC + false; + _ -> + true + end; +is_sane_ecc(crypto) -> + [{_,_, Bin}] = crypto:info_lib(), + case binary_to_list(Bin) of + "OpenSSL 0.9.8" ++ _ -> % Does not support ECC + false; + "OpenSSL 0.9.7" ++ _ -> % Does not support ECC + false; + _ -> + true + end; +is_sane_ecc(_) -> + true. + +cipher_restriction(Config0) -> + case is_sane_ecc(openssl) of + false -> + Opts = proplists:get_value(server_opts, Config0), + Config1 = proplists:delete(server_opts, Config0), + VerOpts = proplists:get_value(server_verification_opts, Config1), + Config = proplists:delete(server_verification_opts, Config1), + Restricted0 = ssl:cipher_suites() -- ecdsa_suites(), + Restricted = Restricted0 -- ecdh_rsa_suites(), + [{server_opts, [{ciphers, Restricted} | Opts]}, {server_verification_opts, [{ciphers, Restricted} | VerOpts] } | Config]; + true -> + Config0 + end. |