aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/test/tls_api_SUITE.erl
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2019-07-19 14:18:30 +0200
committerIngela Anderton Andin <[email protected]>2019-07-22 11:13:59 +0200
commitec0f8d69a98b08b2effd07121b5f87e327d370ee (patch)
tree5e38a93adefe9acf3b6372e70026106448dd19a9 /lib/ssl/test/tls_api_SUITE.erl
parent13d0151b407e3b8a9d190babb725b9b34a24caf8 (diff)
downloadotp-ec0f8d69a98b08b2effd07121b5f87e327d370ee.tar.gz
otp-ec0f8d69a98b08b2effd07121b5f87e327d370ee.tar.bz2
otp-ec0f8d69a98b08b2effd07121b5f87e327d370ee.zip
ssl: Add API suites
This is also an effort to group test cases better. More such commits will follow.
Diffstat (limited to 'lib/ssl/test/tls_api_SUITE.erl')
-rw-r--r--lib/ssl/test/tls_api_SUITE.erl681
1 files changed, 681 insertions, 0 deletions
diff --git a/lib/ssl/test/tls_api_SUITE.erl b/lib/ssl/test/tls_api_SUITE.erl
new file mode 100644
index 0000000000..18e17679ac
--- /dev/null
+++ b/lib/ssl/test/tls_api_SUITE.erl
@@ -0,0 +1,681 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(tls_api_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/ssl_record.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
+
+-define(SLEEP, 500).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], api_tests() -- [sockname]},
+ {'tlsv1.2', [], api_tests()},
+ {'tlsv1.1', [], api_tests()},
+ {'tlsv1', [], api_tests()},
+ {'sslv3', [], api_tests()}
+ ].
+
+api_tests() ->
+ [
+ tls_upgrade,
+ tls_upgrade_with_timeout,
+ tls_downgrade,
+ tls_shutdown,
+ tls_shutdown_write,
+ tls_shutdown_both,
+ tls_shutdown_error,
+ tls_client_closes_socket,
+ tls_closed_in_active_once,
+ tls_tcp_msg,
+ tls_tcp_msg_big,
+ tls_dont_crash_on_handshake_garbage,
+ tls_tcp_error_propagation_in_active_mode,
+ peername,
+ sockname,
+ tls_server_handshake_timeout
+ ].
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+tls_upgrade() ->
+ [{doc,"Test that you can upgrade an tcp connection to an ssl connection"}].
+
+tls_upgrade(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ upgrade_result, []}},
+ {tcp_options,
+ [{active, false} | TcpOpts]},
+ {ssl_options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+ {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, upgrade_result, []}},
+ {tcp_options, [binary]},
+ {ssl_options, [{verify, verify_peer},
+ {server_name_indication, Hostname} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+tls_upgrade_with_timeout() ->
+ [{doc,"Test ssl_accept/3"}].
+
+tls_upgrade_with_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE,
+ upgrade_result, []}},
+ {tcp_options,
+ [{active, false} | TcpOpts]},
+ {ssl_options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+ {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, upgrade_result, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, [{verify, verify_peer},
+ {server_name_indication, Hostname} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+tls_downgrade() ->
+ [{doc,"Test that you can downgarde an ssl connection to an tcp connection"}].
+tls_downgrade(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, tls_downgrade_result, [self()]}},
+ {options, [{active, false}, {verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_downgrade_result, [self()]}},
+ {options, [{active, false}, {verify, verify_peer} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ready, Client, ready),
+
+ Server ! go,
+ Client ! go,
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+tls_shutdown() ->
+ [{doc,"Test API function ssl:shutdown/2"}].
+tls_shutdown(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, tls_shutdown_result, [server]}},
+ {options, [{exit_on_close, false},
+ {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, tls_shutdown_result, [client]}},
+ {options,
+ [{exit_on_close, false},
+ {active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+tls_shutdown_write() ->
+ [{doc,"Test API function ssl:shutdown/2 with option write."}].
+tls_shutdown_write(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, tls_shutdown_write_result, [server]}},
+ {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, tls_shutdown_write_result, [client]}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
+
+%%--------------------------------------------------------------------
+tls_shutdown_both() ->
+ [{doc,"Test API function ssl:shutdown/2 with option both."}].
+tls_shutdown_both(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, tls_shutdown_both_result, [server]}},
+ {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, tls_shutdown_both_result, [client]}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
+
+%%--------------------------------------------------------------------
+tls_shutdown_error() ->
+ [{doc,"Test ssl:shutdown/2 error handling"}].
+tls_shutdown_error(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Port = ssl_test_lib:inet_port(node()),
+ {ok, Listen} = ssl:listen(Port, ServerOpts),
+ {error, enotconn} = ssl:shutdown(Listen, read_write),
+ ok = ssl:close(Listen),
+ {error, closed} = ssl:shutdown(Listen, read_write).
+%%--------------------------------------------------------------------
+tls_client_closes_socket() ->
+ [{doc,"Test what happens when client closes socket before handshake is compleated"}].
+
+tls_client_closes_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(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, [binary]]),
+ %% Make sure that ssl_accept is called before
+ %% client process ends and closes socket.
+ ct:sleep(?SLEEP)
+ end,
+
+ _Client = spawn_link(Connect),
+
+ ssl_test_lib:check_result(Server, {error,closed}).
+
+%%--------------------------------------------------------------------
+tls_closed_in_active_once() ->
+ [{doc, "Test that ssl_closed is delivered in active once with non-empty buffer, check ERL-420."}].
+
+tls_closed_in_active_once(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+ Port = ssl_test_lib:inet_port(node()),
+ Server = fun() ->
+ {ok, Listen} = gen_tcp:listen(Port, TcpOpts),
+ {ok, TcpServerSocket} = gen_tcp:accept(Listen),
+ {ok, ServerSocket} = ssl:handshake(TcpServerSocket, ServerOpts),
+ lists:foreach(
+ fun(_) ->
+ ssl:send(ServerSocket, "some random message\r\n")
+ end, lists:seq(1, 20)),
+ %% Close TCP instead of SSL socket to trigger the bug:
+ gen_tcp:close(TcpServerSocket),
+ gen_tcp:close(Listen)
+ end,
+ spawn_link(Server),
+ {ok, Socket} = ssl:connect(Hostname, Port, [{active, false} | ClientOpts]),
+ Result = tls_closed_in_active_once_loop(Socket),
+ ssl:close(Socket),
+ case Result of
+ ok -> ok;
+ _ -> ct:fail(Result)
+ end.
+%%--------------------------------------------------------------------
+tls_tcp_msg() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}].
+
+tls_tcp_msg(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}, {active, false}],
+
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE, dummy, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
+
+ receive
+ {tcp_closed, Socket} ->
+ receive
+ {Server, {error, Error}} ->
+ ct:log("Error ~p", [Error])
+ end
+ end.
+%%--------------------------------------------------------------------
+tls_tcp_msg_big() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"}].
+
+tls_tcp_msg_big(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Rand = crypto:strong_rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE, dummy, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+
+ gen_tcp:send(Socket, <<?BYTE(0),
+ ?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>),
+
+ receive
+ {tcp_closed, Socket} ->
+ receive
+ {Server, {error, timeout}} ->
+ ct:fail("hangs");
+ {Server, {error, Error}} ->
+ ct:log("Error ~p", [Error]);
+ {'EXIT', Server, _} ->
+ ok
+ end
+ end.
+
+%%--------------------------------------------------------------------
+tls_dont_crash_on_handshake_garbage() ->
+ [{doc, "Ensure SSL server worker thows an alert on garbage during handshake "
+ "instead of crashing and exposing state to user code"}].
+
+tls_dont_crash_on_handshake_garbage(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ unlink(Server), monitor(process, Server),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
+
+ % Send hello and garbage record
+ ok = gen_tcp:send(Socket,
+ [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello
+ 16#deadbeef:256, % 32 'random' bytes = 256 bits
+ 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values
+
+ <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage
+ ]),
+ % Send unexpected change_cipher_spec
+ ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>),
+
+ % Ensure we receive an alert, not sudden disconnect
+ {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000).
+
+%%--------------------------------------------------------------------
+tls_tcp_error_propagation_in_active_mode() ->
+ [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}].
+tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, receive_msg, []}},
+ {options, ClientOpts}]),
+
+ {status, _, _, StatusInfo} = sys:get_status(Pid),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ StaticEnv = element(2, State),
+ Socket = element(11, StaticEnv),
+ %% Fake tcp error
+ Pid ! {tcp_error, Socket, etimedout},
+
+ ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
+
+%%--------------------------------------------------------------------
+peername() ->
+ [{doc,"Test API function peername/1"}].
+
+peername(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, peername_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peername_result, []}},
+ {options, [{port, 0} | ClientOpts]}]),
+
+ ClientPort = ssl_test_lib:inet_port(Client),
+ ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
+ ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
+ ServerMsg = {ok, {ClientIp, ClientPort}},
+ ClientMsg = {ok, {ServerIp, Port}},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+sockname() ->
+ [{doc,"Test API function sockname/1"}].
+sockname(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, sockname_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, sockname_result, []}},
+ {options, [{port, 0} | ClientOpts]}]),
+
+ ClientPort = ssl_test_lib:inet_port(Client),
+ ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
+ ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
+ ServerMsg = {ok, {ServerIp, Port}},
+ ClientMsg = {ok, {ClientIp, ClientPort}},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+tls_server_handshake_timeout() ->
+ [{doc,"Test server handshake timeout"}].
+
+tls_server_handshake_timeout(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {ssl_test_lib,
+ no_result_msg, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]),
+
+ receive
+ {tcp_closed, CSocket} ->
+ ssl_test_lib:check_result(Server, {error, timeout}),
+ receive
+ {'EXIT', Server, _} ->
+ %% Make sure supervisor had time to react on process exit
+ %% Could we come up with a better solution to this?
+ ct:sleep(500),
+ [] = supervisor:which_children(tls_connection_sup)
+ end
+ end.
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+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!
+ receive
+ {ssl, _, <<"H">>} ->
+ receive
+ {ssl, _, <<"ello world">>} ->
+ ok
+ end;
+ {ssl, _, <<"Hello world">>} ->
+ ok
+ end.
+tls_downgrade_result(Socket, Pid) ->
+ ok = ssl_test_lib:send_recv_result(Socket),
+ Pid ! {self(), ready},
+ receive
+ go ->
+ ok
+ end,
+ case ssl:close(Socket, {self(), 10000}) of
+ {ok, TCPSocket} ->
+ inet:setopts(TCPSocket, [{active, true}]),
+ gen_tcp:send(TCPSocket, "Downgraded"),
+ receive
+ {tcp, TCPSocket, <<"Downgraded">>} ->
+ ok;
+ {tcp_closed, TCPSocket} ->
+ ct:fail("Peer timed out, downgrade aborted"),
+ ok;
+ Other ->
+ {error, Other}
+ end;
+ {error, timeout} ->
+ ct:fail("Timed out, downgrade aborted"),
+ ok;
+ Fail ->
+ {error, Fail}
+ end.
+
+tls_shutdown_result(Socket, server) ->
+ ssl:send(Socket, "Hej"),
+ ok = ssl:shutdown(Socket, write),
+ {ok, "Hej hopp"} = ssl:recv(Socket, 8),
+ ok;
+
+tls_shutdown_result(Socket, client) ->
+ ssl:send(Socket, "Hej hopp"),
+ ok = ssl:shutdown(Socket, write),
+ {ok, "Hej"} = ssl:recv(Socket, 3),
+ ok.
+
+tls_shutdown_write_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, write);
+tls_shutdown_write_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+tls_shutdown_both_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, read_write);
+tls_shutdown_both_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+tls_closed_in_active_once_loop(Socket) ->
+ case ssl:setopts(Socket, [{active, once}]) of
+ ok ->
+ receive
+ {ssl, Socket, _} ->
+ tls_closed_in_active_once_loop(Socket);
+ {ssl_closed, Socket} ->
+ ok
+ after 5000 ->
+ no_ssl_closed_received
+ end;
+ {error, closed} ->
+ ok
+ end.
+
+drop_handshakes(Socket, Timeout) ->
+ {ok, <<RecType:8, _RecMajor:8, _RecMinor:8, RecLen:16>> = Header} = gen_tcp:recv(Socket, 5, Timeout),
+ {ok, <<Frag:RecLen/binary>>} = gen_tcp:recv(Socket, RecLen, Timeout),
+ case RecType of
+ 22 -> drop_handshakes(Socket, Timeout);
+ _ -> {ok, <<Header/binary, Frag/binary>>}
+ end.
+
+receive_msg(_) ->
+ receive
+ Msg ->
+ Msg
+ end.
+
+sockname_result(S) ->
+ ssl:sockname(S).
+
+peername_result(S) ->
+ ssl:peername(S).