%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(ssl_session_SUITE).
%% Note: This directive should only be used in test suites.
-compile(export_all).
-include("tls_handshake.hrl").
-include_lib("common_test/include/ct.hrl").
-include_lib("public_key/include/public_key.hrl").
-define(SLEEP, 500).
-define(EXPIRE, 10).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
[
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'},
{group, 'dtlsv1.2'},
{group, 'dtlsv1'}
].
groups() ->
[{'dtlsv1.2', [], session_tests()},
{'dtlsv1', [], session_tests()},
{'tlsv1.3', [], session_tests()},
{'tlsv1.2', [], session_tests()},
{'tlsv1.1', [], session_tests()},
{'tlsv1', [], session_tests()},
{'sslv3', [], session_tests()}
].
session_tests() ->
[reuse_session,
reuse_session_expired,
server_does_not_want_to_reuse_session,
no_reuses_session_server_restart_new_cert,
no_reuses_session_server_restart_new_cert_file].
init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
ssl_test_lib:clean_start(),
Config = ssl_test_lib:make_rsa_cert(Config0),
ssl_test_lib:make_dsa_cert(Config)
catch _:_ ->
{skip, "Crypto did not start"}
end.
end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
init_per_group(GroupName, Config) ->
ssl_test_lib:clean_tls_version(Config),
case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
true ->
ssl_test_lib:init_tls_version(GroupName, Config);
_ ->
case ssl_test_lib:sufficient_crypto_support(GroupName) of
true ->
ssl:start(),
Config;
false ->
{skip, "Missing crypto support"}
end
end.
end_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
true ->
ssl_test_lib:clean_tls_version(Config);
false ->
Config
end.
init_per_testcase(reuse_session_expired, Config) ->
ssl:stop(),
application:load(ssl),
ssl_test_lib:clean_env(),
application:set_env(ssl, session_lifetime, ?EXPIRE),
application:set_env(ssl, session_delay_cleanup_time, 500),
ssl:start(),
ct:timetrap({seconds, 30}),
Config;
init_per_testcase(_, Config) ->
ct:timetrap({seconds, 15}),
Config.
end_per_testcase(_TestCase, Config) ->
Config.
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
%%--------------------------------------------------------------------
reuse_session_expired() ->
[{doc,"Test sessions is not reused when it has expired"}].
reuse_session_expired(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server0 =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
{tcp_options, [{active, false}]},
{options, ServerOpts}]),
Port0 = ssl_test_lib:inet_port(Server0),
Client0 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, Hostname},
{mfa, {ssl_test_lib, session_id, []}},
{from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
Server0 ! listen,
Client1 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, Hostname},
{mfa, {ssl_test_lib, session_id, []}},
{from, self()}, {options, ClientOpts}]),
SID = receive
{Client0, Id0} ->
Id0
end,
receive
{Client1, SID} ->
ok
after ?SLEEP ->
ct:fail(session_not_reused)
end,
Server0 ! listen,
%% Make sure session is unregistered due to expiration
ct:sleep((?EXPIRE*2)),
make_sure_expired(Hostname, Port0, SID),
Client2 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port0}, {host, Hostname},
{mfa, {ssl_test_lib, session_id, []}},
{from, self()}, {options, ClientOpts}]),
receive
{Client2, SID} ->
ct:fail(session_reused_when_session_expired);
{Client2, _} ->
ok
end,
process_flag(trap_exit, false),
ssl_test_lib:close(Server0),
ssl_test_lib:close(Client0),
ssl_test_lib:close(Client1),
ssl_test_lib:close(Client2).
make_sure_expired(Host, Port, Id) ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
State = ssl_test_lib:state(Prop),
ClientCache = element(2, State),
case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of
undefined ->
ok;
#session{is_resumable = false} ->
ok;
_ ->
ct:sleep(?SLEEP),
make_sure_expired(Host, Port, Id)
end.
%%--------------------------------------------------------------------
server_does_not_want_to_reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, session_info_result, []}},
{options, [{reuse_session, fun(_,_,_,_) ->
false
end} |
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, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
ct:sleep(?SLEEP),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, session_info_result, []}},
{from, self()}, {options, ClientOpts}]),
receive
{Client1, SessionInfo} ->
ct:fail(session_reused_when_server_does_not_want_to);
{Client1, _Other} ->
ok
end,
ssl_test_lib:close(Client0),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client1).
no_reuses_session_server_restart_new_cert() ->
[{doc,"Check that a session is not reused if the server is restarted with a new cert."}].
no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
DsaClientOpts = ssl_test_lib:ssl_options(client_dsa_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, session_info_result, []}},
{options, 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,
%% Make sure session is registered
ct:sleep(?SLEEP),
Monitor = erlang:monitor(process, Server),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client0),
receive
{'DOWN', Monitor, _, _, _} ->
ok
end,
Server1 =
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
{options, [{reuseaddr, true} | DsaServerOpts]}]),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, session_info_result, []}},
{from, self()}, {options, DsaClientOpts}]),
receive
{Client1, SessionInfo} ->
ct:fail(session_reused_when_server_has_new_cert);
{Client1, _Other} ->
ok
end,
ssl_test_lib:close(Server1),
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
no_reuses_session_server_restart_new_cert_file() ->
[{doc,"Check that a session is not reused if a server is restarted with a new "
"cert contained in a file with the same name as the old cert."}].
no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
NewServerOpts0 = ssl_test_lib:new_config(PrivDir, ServerOpts),
{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, session_info_result, []}},
{options, NewServerOpts0}]),
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,
%% Make sure session is registered and we get
%% new file time stamp when calling new_config!
ct:sleep(?SLEEP* 2),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client0),
ssl:clear_pem_cache(),
NewServerOpts1 = ssl_test_lib:new_config(PrivDir, DsaServerOpts),
Server1 =
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
{options, [{reuseaddr, true} | NewServerOpts1]}]),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, session_info_result, []}},
{from, self()}, {options, ClientOpts}]),
receive
{Client1, SessionInfo} ->
ct:fail(session_reused_when_server_has_new_cert);
{Client1, _Other} ->
ok
end,
ssl_test_lib:close(Server1),
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------