%% %% %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 ------------------------------------------------ %%--------------------------------------------------------------------