diff options
Diffstat (limited to 'lib/ssl/test/ssl_test_lib.erl')
-rw-r--r-- | lib/ssl/test/ssl_test_lib.erl | 195 |
1 files changed, 178 insertions, 17 deletions
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 23b2f3cab5..8c27571d64 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -79,17 +79,21 @@ run_server(ListenSocket, Opts, N) -> Pid ! {accepter, N, Server}, run_server(ListenSocket, Opts, N-1). -do_run_server(_, {error, timeout} = Result, Opts) -> +do_run_server(_, {error, _} = Result, Opts) -> + ct:log("Server error result ~p~n", [Result]), + Pid = proplists:get_value(from, Opts), + Pid ! {self(), Result}; +do_run_server(_, ok = Result, Opts) -> + ct:log("Server cancel result ~p~n", [Result]), Pid = proplists:get_value(from, Opts), Pid ! {self(), Result}; - 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), ct:log("~p:~p~nServer: apply(~p,~p,~p)~n", - [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]), + [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]), case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of no_result_msg -> ok; @@ -117,7 +121,8 @@ connect(#sslsocket{} = ListenSocket, Opts) -> ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0), Timeout = proplists:get_value(timeout, Opts, infinity), SslOpts = proplists:get_value(ssl_extra_opts, Opts, []), - AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout, SslOpts), + ContOpts = proplists:get_value(continue_options, Opts, []), + AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout, SslOpts, ContOpts), case ReconnectTimes of 0 -> AcceptSocket; @@ -132,10 +137,45 @@ connect(ListenSocket, Opts) -> [ListenSocket]), AcceptSocket. -connect(_, _, 0, AcceptSocket, _, _) -> +connect(_, _, 0, AcceptSocket, _, _, _) -> AcceptSocket; - -connect(ListenSocket, Node, N, _, Timeout, []) -> +connect(ListenSocket, Node, _N, _, Timeout, SslOpts, cancel) -> + ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), + {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, + [ListenSocket]), + ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]), + + case rpc:call(Node, ssl, handshake, [AcceptSocket, SslOpts, Timeout]) of + {ok, Socket0, Ext} -> + ct:log("Ext ~p:~n", [Ext]), + ct:log("~p:~p~nssl:handshake_cancel(~p)~n", [?MODULE,?LINE, Socket0]), + rpc:call(Node, ssl, handshake_cancel, [Socket0]); + Result -> + ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]), + Result + end; +connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) -> + ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), + {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, + [ListenSocket]), + ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]), + + case rpc:call(Node, ssl, handshake, [AcceptSocket, SslOpts, Timeout]) of + {ok, Socket0, Ext} -> + ct:log("Ext ~p:~n", [Ext]), + ct:log("~p:~p~nssl:handshake_continue(~p,~p,~p)~n", [?MODULE,?LINE, Socket0, ContOpts,Timeout]), + case rpc:call(Node, ssl, handshake_continue, [Socket0, ContOpts, Timeout]) of + {ok, Socket} -> + connect(ListenSocket, Node, N-1, Socket, Timeout, SslOpts, ContOpts); + Error -> + ct:log("~p:~p~nssl:handshake_continue@~p ret ~p",[?MODULE,?LINE, Node,Error]), + Error + end; + Result -> + ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]), + Result + end; +connect(ListenSocket, Node, N, _, Timeout, [], ContOpts) -> ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, [ListenSocket]), @@ -143,12 +183,12 @@ connect(ListenSocket, Node, N, _, Timeout, []) -> case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of ok -> - connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, []); + connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, [], ContOpts); Result -> ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]), Result end; -connect(ListenSocket, Node, _, _, Timeout, Opts) -> +connect(ListenSocket, Node, _, _, Timeout, Opts, _) -> ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, [ListenSocket]), @@ -187,8 +227,17 @@ run_client(Opts) -> Pid = proplists:get_value(from, Opts), Transport = proplists:get_value(transport, Opts, ssl), Options = proplists:get_value(options, Opts), + ContOpts = proplists:get_value(continue_options, Opts, []), ct:log("~p:~p~n~p:connect(~p, ~p)@~p~n", [?MODULE,?LINE, Transport, Host, Port, Node]), ct:log("SSLOpts: ~p", [Options]), + case ContOpts of + [] -> + client_loop(Node, Host, Port, Pid, Transport, Options, Opts); + _ -> + client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) + end. + +client_loop(Node, Host, Port, Pid, Transport, Options, Opts) -> case rpc:call(Node, Transport, connect, [Host, Port, Options]) of {ok, Socket} -> Pid ! {connected, Socket}, @@ -245,6 +294,40 @@ run_client(Opts) -> Pid ! {connect_failed, {badrpc,BadRPC}} end. +client_cont_loop(Node, Host, Port, Pid, Transport, Options, cancel, _Opts) -> + case rpc:call(Node, Transport, connect, [Host, Port, Options]) of + {ok, Socket, _} -> + Result = rpc:call(Node, Transport, handshake_cancel, [Socket]), + ct:log("~p:~p~nClient: Cancel: ~p ~n", [?MODULE,?LINE, Result]), + Pid ! {connect_failed, Result}; + {error, Reason} -> + ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]), + Pid ! {connect_failed, Reason} + end; + +client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) -> + case rpc:call(Node, Transport, connect, [Host, Port, Options]) of + {ok, Socket0, _} -> + ct:log("~p:~p~nClient: handshake_continue(~p, ~p, infinity) ~n", [?MODULE, ?LINE, Socket0, ContOpts]), + case rpc:call(Node, Transport, handshake_continue, [Socket0, ContOpts, infinity]) of + {ok, Socket} -> + Pid ! {connected, Socket}, + {Module, Function, Args} = proplists:get_value(mfa, Opts), + ct:log("~p:~p~nClient: apply(~p,~p,~p)~n", + [?MODULE,?LINE, Module, Function, [Socket | Args]]), + case rpc:call(Node, Module, Function, [Socket | Args]) of + no_result_msg -> + ok; + Msg -> + ct:log("~p:~p~nClient Msg: ~p ~n", [?MODULE,?LINE, Msg]), + Pid ! {self(), Msg} + end + end; + {error, Reason} -> + ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]), + Pid ! {connect_failed, Reason} + end. + close(Pid) -> ct:log("~p:~p~nClose ~p ~n", [?MODULE,?LINE, Pid]), Monitor = erlang:monitor(process, Pid), @@ -1351,16 +1434,33 @@ sufficient_crypto_support(_) -> check_key_exchange_send_active(Socket, false) -> send_recv_result_active(Socket); check_key_exchange_send_active(Socket, KeyEx) -> - {ok, [{cipher_suite, Suite}]} = ssl:connection_information(Socket, [cipher_suite]), - true = check_key_exchange(Suite, KeyEx), + {ok, Info} = + ssl:connection_information(Socket, [cipher_suite, protocol]), + Suite = proplists:get_value(cipher_suite, Info), + Version = proplists:get_value(protocol, Info), + true = check_key_exchange(Suite, KeyEx, Version), send_recv_result_active(Socket). -check_key_exchange({KeyEx,_, _}, KeyEx) -> +check_key_exchange({KeyEx,_, _}, KeyEx, _) -> true; -check_key_exchange({KeyEx,_,_,_}, KeyEx) -> +check_key_exchange({KeyEx,_,_,_}, KeyEx, _) -> true; -check_key_exchange(KeyEx1, KeyEx2) -> - ct:pal("Negotiated ~p Expected ~p", [KeyEx1, KeyEx2]), +check_key_exchange(KeyEx1, KeyEx2, Version) -> + case Version of + 'tlsv1.2' -> + v_1_2_check(element(1, KeyEx1), KeyEx2); + 'dtlsv1.2' -> + v_1_2_check(element(1, KeyEx1), KeyEx2); + _ -> + ct:pal("Negotiated ~p Expected ~p", [KeyEx1, KeyEx2]), + false + end. + +v_1_2_check(ecdh_ecdsa, ecdh_rsa) -> + true; +v_1_2_check(ecdh_rsa, ecdh_ecdsa) -> + true; +v_1_2_check(_, _) -> false. send_recv_result_active(Socket) -> @@ -1484,12 +1584,62 @@ openssl_dsa_support() -> true end. +%% Acctual support is tested elsewhere, this is to exclude some LibreSSL and OpenSSL versions +openssl_sane_dtls() -> + case os:cmd("openssl version") of + "OpenSSL 0." ++ _ -> + false; + "OpenSSL 1.0.1s-freebsd" ++ _ -> + false; + "OpenSSL 1.0.2k-freebsd" ++ _ -> + false; + "OpenSSL 1.0.2d" ++ _ -> + false; + "OpenSSL 1.0.2n" ++ _ -> + false; + "OpenSSL 1.0.2m" ++ _ -> + false; + "OpenSSL 1.0.0" ++ _ -> + false; + "OpenSSL" ++ _ -> + true; + "LibreSSL 2.7" ++ _ -> + true; + _ -> + false + end. +openssl_sane_client_cert() -> + case os:cmd("openssl version") of + "LibreSSL 2.5.2" ++ _ -> + true; + "LibreSSL 2.4" ++ _ -> + false; + "LibreSSL 2.3" ++ _ -> + false; + "LibreSSL 2.1" ++ _ -> + false; + "LibreSSL 2.0" ++ _ -> + false; + "LibreSSL 2.0" ++ _ -> + false; + "OpenSSL 1.0.1s-freebsd" -> + false; + "OpenSSL 1.0.0" ++ _ -> + false; + _ -> + true + end. + check_sane_openssl_version(Version) -> case supports_ssl_tls_version(Version) of true -> case {Version, os:cmd("openssl version")} of {'sslv3', "OpenSSL 1.0.2" ++ _} -> false; + {'dtlsv1', _} -> + not is_fips(openssl); + {'dtlsv1.2', _} -> + not is_fips(openssl); {_, "OpenSSL 1.0.2" ++ _} -> true; {_, "OpenSSL 1.0.1" ++ _} -> @@ -1498,7 +1648,7 @@ check_sane_openssl_version(Version) -> false; {'tlsv1.1', "OpenSSL 1.0.0" ++ _} -> false; - {'dtlsv1.2', "OpenSSL 1.0.0" ++ _} -> + {'dtlsv1.2', "OpenSSL 1.0.2" ++ _} -> false; {'dtlsv1', "OpenSSL 1.0.0" ++ _} -> false; @@ -1620,8 +1770,13 @@ supports_ssl_tls_version(sslv2 = Version) -> VersionFlag = version_flag(Version), Exe = "openssl", Args = ["s_client", VersionFlag], + [{trap_exit, Trap}] = process_info(self(), [trap_exit]), + process_flag(trap_exit, true), Port = ssl_test_lib:portable_open_port(Exe, Args), - do_supports_ssl_tls_version(Port, "") + Bool = do_supports_ssl_tls_version(Port, ""), + consume_port_exit(Port), + process_flag(trap_exit, Trap), + Bool end; supports_ssl_tls_version(Version) -> @@ -1739,6 +1894,12 @@ tls_version('dtlsv1.2' = Atom) -> tls_version(Atom) -> tls_record:protocol_version(Atom). +consume_port_exit(OpenSSLPort) -> + receive + {'EXIT', OpenSSLPort, _} -> + ok + end. + hardcode_rsa_key(1) -> #'RSAPrivateKey'{ version = 'two-prime', |