diff options
Diffstat (limited to 'lib/ssl/test')
21 files changed, 9472 insertions, 0 deletions
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile new file mode 100644 index 0000000000..bd86120c98 --- /dev/null +++ b/lib/ssl/test/Makefile @@ -0,0 +1,137 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. 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 +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# + +# SSL test suite Makefile +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(GS_VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + ssl_test_lib \ + ssl_basic_SUITE \ + ssl_packet_SUITE \ + ssl_payload_SUITE \ + ssl_to_openssl_SUITE \ + ssl_test_MACHINE \ + old_ssl_active_SUITE \ + old_ssl_active_once_SUITE \ + old_ssl_passive_SUITE \ + old_ssl_verify_SUITE \ + old_ssl_peer_cert_SUITE \ + old_ssl_misc_SUITE \ + old_ssl_protocol_SUITE \ + old_transport_accept_SUITE \ + old_ssl_dist_SUITE \ + make_certs + + +ERL_FILES = $(MODULES:%=%.erl) + +HRL_FILES = ssl_test_MACHINE.hrl + +HRL_FILES_SRC = \ + ssl_pkix.hrl \ + ssl_alert.hrl \ + ssl_handshake.hrl + +HRL_FILES_INC = \ + OTP-PKIX.hrl + +HRL_FILES_NEEDED_IN_TEST = \ + $(HRL_FILES_SRC:%=../src/%) \ + $(HRL_FILES_INC:%=../include/%) + +TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +INCLUDES = -I. -I$(ERL_TOP)/lib/test_server/include/ + +DATADIRS = ssl_basic_SUITE_data + +EMAKEFILE=Emakefile +MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile) + +COVER_FILE = ssl.cover + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/ssl_test + +# ---------------------------------------------------- +# FLAGS +# The path to the test_server ebin dir is needed when +# running the target "targets". +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += -pa ../../../internal_tools/test_server/ebin \ + $(INCLUDES) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +tests debug opt: $(BUILDTARGET) + +targets: $(TARGET_FILES) + +.PHONY: emakebuild + +emakebuild: $(EMAKEFILE) + +$(EMAKEFILE): + $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' | grep -v Warning > $(EMAKEFILE) + $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) | grep -v Warning >> $(EMAKEFILE) + +clean: + rm -f $(EMAKEFILE) + rm -f $(TARGET_FILES) + rm -f core *~ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + +release_tests_spec: opt + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(HRL_FILES_NEEDED_IN_TEST) $(COVER_FILE) $(RELSYSDIR) + $(INSTALL_DATA) ssl.spec $(RELSYSDIR) + chmod -f -R u+w $(RELSYSDIR) + @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: + +# Dependencies + +$(TARGET_FILES): $(HRL_FILES) diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl new file mode 100644 index 0000000000..0cdf33c3e2 --- /dev/null +++ b/lib/ssl/test/make_certs.erl @@ -0,0 +1,288 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(make_certs). + +-export([all/2]). + +-record(dn, {commonName, + organizationalUnitName = "Erlang OTP", + organizationName = "Ericsson AB", + localityName = "Stockholm", + countryName = "SE", + emailAddress = "[email protected]"}). + +all(DataDir, PrivDir) -> + OpenSSLCmd = "openssl", + create_rnd(DataDir, PrivDir), % For all requests + rootCA(PrivDir, OpenSSLCmd, "erlangCA"), + intermediateCA(PrivDir, OpenSSLCmd, "otpCA", "erlangCA"), + endusers(PrivDir, OpenSSLCmd, "otpCA", ["client", "server"]), + collect_certs(PrivDir, ["erlangCA", "otpCA"], ["client", "server"]), + %% Create keycert files + SDir = filename:join([PrivDir, "server"]), + SC = filename:join([SDir, "cert.pem"]), + SK = filename:join([SDir, "key.pem"]), + SKC = filename:join([SDir, "keycert.pem"]), + append_files([SK, SC], SKC), + CDir = filename:join([PrivDir, "client"]), + CC = filename:join([CDir, "cert.pem"]), + CK = filename:join([CDir, "key.pem"]), + CKC = filename:join([CDir, "keycert.pem"]), + append_files([CK, CC], CKC), + remove_rnd(PrivDir). + +append_files(FileNames, ResultFileName) -> + {ok, ResultFile} = file:open(ResultFileName, [write]), + do_append_files(FileNames, ResultFile). + +do_append_files([], RF) -> + ok = file:close(RF); +do_append_files([F|Fs], RF) -> + {ok, Data} = file:read_file(F), + ok = file:write(RF, Data), + do_append_files(Fs, RF). + +rootCA(Root, OpenSSLCmd, Name) -> + create_ca_dir(Root, Name, ca_cnf(Name)), + DN = #dn{commonName = Name}, + create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)), + ok. + +intermediateCA(Root, OpenSSLCmd, CA, ParentCA) -> + CA = "otpCA", + create_ca_dir(Root, CA, ca_cnf(CA)), + CARoot = filename:join([Root, CA]), + DN = #dn{commonName = CA}, + CnfFile = filename:join([CARoot, "req.cnf"]), + file:write_file(CnfFile, req_cnf(DN)), + KeyFile = filename:join([CARoot, "private", "key.pem"]), + ReqFile = filename:join([CARoot, "req.pem"]), + create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile), + CertFile = filename:join([CARoot, "cert.pem"]), + sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile). + +endusers(Root, OpenSSLCmd, CA, Users) -> + lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users). + +enduser(Root, OpenSSLCmd, CA, User) -> + UsrRoot = filename:join([Root, User]), + file:make_dir(UsrRoot), + CnfFile = filename:join([UsrRoot, "req.cnf"]), + DN = #dn{commonName = User}, + file:write_file(CnfFile, req_cnf(DN)), + KeyFile = filename:join([UsrRoot, "key.pem"]), + ReqFile = filename:join([UsrRoot, "req.pem"]), + create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile), + CertFile = filename:join([UsrRoot, "cert.pem"]), + sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFile). + +collect_certs(Root, CAs, Users) -> + Bins = lists:foldr( + fun(CA, Acc) -> + File = filename:join([Root, CA, "cert.pem"]), + {ok, Bin} = file:read_file(File), + [Bin, "\n" | Acc] + end, [], CAs), + lists:foreach( + fun(User) -> + File = filename:join([Root, User, "cacerts.pem"]), + file:write_file(File, Bins) + end, Users). + +create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) -> + CARoot = filename:join([Root, CAName]), + CnfFile = filename:join([CARoot, "req.cnf"]), + file:write_file(CnfFile, Cnf), + KeyFile = filename:join([CARoot, "private", "key.pem"]), + CertFile = filename:join([CARoot, "cert.pem"]), + Cmd = [OpenSSLCmd, " req" + " -new" + " -x509" + " -config ", CnfFile, + " -keyout ", KeyFile, + " -out ", CertFile], + Env = [{"ROOTDIR", Root}], + cmd(Cmd, Env). + +create_ca_dir(Root, CAName, Cnf) -> + CARoot = filename:join([Root, CAName]), + file:make_dir(CARoot), + create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]), + create_rnd(Root, filename:join([CAName, "private"])), + create_files(CARoot, [{"serial", "01\n"}, + {"index.txt", ""}, + {"ca.cnf", Cnf}]). + +create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) -> + Cmd = [OpenSSLCmd, " req" + " -new" + " -config ", CnfFile, + " -keyout ", KeyFile, + " -out ", ReqFile], + Env = [{"ROOTDIR", Root}], + cmd(Cmd, Env). + +sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) -> + CACnfFile = filename:join([Root, CA, "ca.cnf"]), + Cmd = [OpenSSLCmd, " ca" + " -batch" + " -notext" + " -config ", CACnfFile, + " -extensions ", CertType, + " -in ", ReqFile, + " -out ", CertFile], + Env = [{"ROOTDIR", Root}], + cmd(Cmd, Env). + +%% +%% Misc +%% + +create_dirs(Root, Dirs) -> + lists:foreach(fun(Dir) -> + file:make_dir(filename:join([Root, Dir])) end, + Dirs). + +create_files(Root, NameContents) -> + lists:foreach( + fun({Name, Contents}) -> + file:write_file(filename:join([Root, Name]), Contents) end, + NameContents). + +create_rnd(FromDir, ToDir) -> + From = filename:join([FromDir, "RAND"]), + To = filename:join([ToDir, "RAND"]), + file:copy(From, To). + +remove_rnd(Dir) -> + File = filename:join([Dir, "RAND"]), + file:delete(File). + +cmd(Cmd, Env) -> + FCmd = lists:flatten(Cmd), + Port = open_port({spawn, FCmd}, [stream, eof, exit_status, stderr_to_stdout, + {env, Env}]), + eval_cmd(Port). + +eval_cmd(Port) -> + receive + {Port, {data, _}} -> + eval_cmd(Port); + {Port, eof} -> + ok + end, + receive + {Port, {exit_status, Status}} when Status /= 0 -> + %% io:fwrite("exit status: ~w~n", [Status]), + exit({eval_cmd, Status}) + after 0 -> + ok + end. + +%% +%% Contents of configuration files +%% + +req_cnf(DN) -> + ["# Purpose: Configuration for requests (end users and CAs)." + "\n" + "ROOTDIR = $ENV::ROOTDIR\n" + "\n" + + "[req]\n" + "input_password = secret\n" + "output_password = secret\n" + "default_bits = 1024\n" + "RANDFILE = $ROOTDIR/RAND\n" + "encrypt_key = no\n" + "default_md = sha1\n" + "#string_mask = pkix\n" + "x509_extensions = ca_ext\n" + "prompt = no\n" + "distinguished_name= name\n" + "\n" + + "[name]\n" + "commonName = ", DN#dn.commonName, "\n" + "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n" + "organizationName = ", DN#dn.organizationName, "\n" + "localityName = ", DN#dn.localityName, "\n" + "countryName = ", DN#dn.countryName, "\n" + "emailAddress = ", DN#dn.emailAddress, "\n" + "\n" + + "[ca_ext]\n" + "basicConstraints = critical, CA:true\n" + "keyUsage = cRLSign, keyCertSign\n" + "subjectKeyIdentifier = hash\n" + "subjectAltName = email:copy\n"]. + + +ca_cnf(CA) -> + ["# Purpose: Configuration for CAs.\n" + "\n" + "ROOTDIR = $ENV::ROOTDIR\n" + "default_ca = ca\n" + "\n" + + "[ca]\n" + "dir = $ROOTDIR/", CA, "\n" + "certs = $dir/certs\n" + "crl_dir = $dir/crl\n" + "database = $dir/index.txt\n" + "new_certs_dir = $dir/newcerts\n" + "certificate = $dir/cert.pem\n" + "serial = $dir/serial\n" + "crl = $dir/crl.pem\n" + "private_key = $dir/private/key.pem\n" + "RANDFILE = $dir/private/RAND\n" + "\n" + "x509_extensions = user_cert\n" + "default_days = 3600\n" + "default_md = sha1\n" + "preserve = no\n" + "policy = policy_match\n" + "\n" + + "[policy_match]\n" + "commonName = supplied\n" + "organizationalUnitName = optional\n" + "organizationName = match\n" + "countryName = match\n" + "localityName = match\n" + "emailAddress = supplied\n" + "\n" + + "[user_cert]\n" + "basicConstraints = CA:false\n" + "keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n" + "subjectKeyIdentifier = hash\n" + "authorityKeyIdentifier = keyid,issuer:always\n" + "subjectAltName = email:copy\n" + "issuerAltName = issuer:copy\n" + "\n" + + "[ca_cert]\n" + "basicConstraints = critical,CA:true\n" + "keyUsage = cRLSign, keyCertSign\n" + "subjectKeyIdentifier = hash\n" + "authorityKeyIdentifier = keyid:always,issuer:always\n" + "subjectAltName = email:copy\n" + "issuerAltName = issuer:copy\n"]. diff --git a/lib/ssl/test/old_ssl_active_SUITE.erl b/lib/ssl/test/old_ssl_active_SUITE.erl new file mode 100644 index 0000000000..fc44fa23dd --- /dev/null +++ b/lib/ssl/test/old_ssl_active_SUITE.erl @@ -0,0 +1,387 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_ssl_active_SUITE). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + config/1, + finish/1, + cinit_return_chkclose/1, + sinit_return_chkclose/1, + cinit_big_return_chkclose/1, + sinit_big_return_chkclose/1, + cinit_big_echo_chkclose/1, + cinit_huge_echo_chkclose/1, + sinit_big_echo_chkclose/1, + cinit_few_echo_chkclose/1, + cinit_many_echo_chkclose/1, + cinit_cnocert/1 + ]). + +-import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). + +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + +-define(MANYCONNS, ssl_test_MACHINE:many_conns()). + +init_per_testcase(_Case, Config) -> + WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of ssl.erl interface in active mode."; +all(suite) -> + {conf, + config, + [cinit_return_chkclose, + sinit_return_chkclose, + cinit_big_return_chkclose, + sinit_big_return_chkclose, + cinit_big_echo_chkclose, + cinit_huge_echo_chkclose, + sinit_big_echo_chkclose, + cinit_few_echo_chkclose, + cinit_many_echo_chkclose, + cinit_cnocert], + finish}. + +config(doc) -> + "Want to se what Config contains, and record the number of available " + "file descriptors"; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + case os:type() of + {unix, _} -> + ?line io:format("Max fd value: ~s", [os:cmd("ulimit -n")]); + _ -> + ok + end, + %% XXX Also record: Erlang/SSL version, version of OpenSSL, + %% operating system, version of OTP, Erts, kernel and stdlib. + + %% Check if SSL exists. If this case fails, all other cases are skipped + case ssl:start() of + ok -> ssl:stop(); + {error, {already_started, _}} -> ssl:stop(); + Error -> ?t:fail({failed_starting_ssl,Error}) + end, + Config. + +finish(doc) -> + "This test case has no mission other than closing the conf case"; +finish(suite) -> + []; +finish(Config) -> + Config. + +cinit_return_chkclose(doc) -> + "Client sends 1000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +cinit_return_chkclose(suite) -> + []; +cinit_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_return_chkclose(doc) -> + "Server sends 1000 bytes to client, that receives them, sends them " + "back, and closes. Server waits for close. Both have certs."; +sinit_return_chkclose(suite) -> + []; +sinit_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {recv, DataSize}, {send, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_big_return_chkclose(doc) -> + "Client sends 50000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +cinit_big_return_chkclose(suite) -> + []; +cinit_big_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_big_return_chkclose(doc) -> + "Server sends 50000 bytes to client, that receives them, sends them " + "back, and closes. Server waits for close. Both have certs."; +sinit_big_return_chkclose(suite) -> + []; +sinit_big_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {recv, DataSize}, {send, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_big_echo_chkclose(doc) -> + "Client sends 50000 bytes to server, that echoes them back " + "and closes. Client waits for close. Both have certs."; +cinit_big_echo_chkclose(suite) -> + []; +cinit_big_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_huge_echo_chkclose(doc) -> + "Client sends 500000 bytes to server, that echoes them back " + "and closes. Client waits for close. Both have certs."; +cinit_huge_echo_chkclose(suite) -> + []; +cinit_huge_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 500000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_big_echo_chkclose(doc) -> + "Server sends 50000 bytes to client, that echoes them back " + "and closes. Server waits for close. Both have certs."; +sinit_big_echo_chkclose(suite) -> + []; +sinit_big_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {echo, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + + +%% This case is repeated several times. + +cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7). + +cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS). + +cinit_many_echo_chkclose(doc, _NConns) -> + "N client sends 10000 bytes to server, that echoes them back " + "and closes. Clients wait for close. All have certs."; +cinit_many_echo_chkclose(suite, _NConns) -> + []; +cinit_many_echo_chkclose(Config, NConns) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 10000, LPort = 3456, + Timeout = 80000, + + io:format("~w connections", [NConns]), + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + + +cinit_cnocert(doc) -> + "Client sends 1000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Client has no cert, " + "but server has."; +cinit_cnocert(suite) -> + []; +cinit_cnocert(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3457, + Timeout = 40000, NConns = 1, + + ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + + diff --git a/lib/ssl/test/old_ssl_active_once_SUITE.erl b/lib/ssl/test/old_ssl_active_once_SUITE.erl new file mode 100644 index 0000000000..6224b17aa7 --- /dev/null +++ b/lib/ssl/test/old_ssl_active_once_SUITE.erl @@ -0,0 +1,409 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_ssl_active_once_SUITE). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + config/1, + finish/1, + server_accept_timeout/1, + cinit_return_chkclose/1, + sinit_return_chkclose/1, + cinit_big_return_chkclose/1, + sinit_big_return_chkclose/1, + cinit_big_echo_chkclose/1, + cinit_huge_echo_chkclose/1, + sinit_big_echo_chkclose/1, + cinit_few_echo_chkclose/1, + cinit_many_echo_chkclose/1, + cinit_cnocert/1 + ]). + +-import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + +-define(MANYCONNS, ssl_test_MACHINE:many_conns()). + +init_per_testcase(_Case, Config) -> + WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of ssl.erl interface in passive mode."; +all(suite) -> + {conf, + config, + [server_accept_timeout, + cinit_return_chkclose, + sinit_return_chkclose, + cinit_big_return_chkclose, + sinit_big_return_chkclose, + cinit_big_echo_chkclose, + cinit_huge_echo_chkclose, + sinit_big_echo_chkclose, + cinit_few_echo_chkclose, + cinit_many_echo_chkclose, + cinit_cnocert], + finish}. + +config(doc) -> + "Want to se what Config contains."; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + + %% Check if SSL exists. If this case fails, all other cases are skipped + case ssl:start() of + ok -> ssl:stop(); + {error, {already_started, _}} -> ssl:stop(); + Error -> ?t:fail({failed_starting_ssl,Error}) + end, + Config. + +finish(doc) -> + "This test case has no mission other than closing the conf case"; +finish(suite) -> + []; +finish(Config) -> + Config. + +server_accept_timeout(doc) -> + "Server has one pending accept with timeout. Checks that return " + "value is {error, timeout}."; +server_accept_timeout(suite) -> + []; +server_accept_timeout(Config) when list(Config) -> + process_flag(trap_exit, true), + LPort = 3456, + Timeout = 40000, NConns = 1, + AccTimeout = 3000, + + ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, AccTimeout}, + accept_timeout], + ?line test_server_only(NConns, LCmds, ACmds, Timeout, ?MODULE, + Config). + +cinit_return_chkclose(doc) -> + "Client sends 1000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +cinit_return_chkclose(suite) -> + []; +cinit_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_return_chkclose(doc) -> + "Server sends 1000 bytes to client, that receives them, sends them " + "back, and closes. Server waits for close. Both have certs."; +sinit_return_chkclose(suite) -> + []; +sinit_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {recv, DataSize}, {send, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_big_return_chkclose(doc) -> + "Client sends 50000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +cinit_big_return_chkclose(suite) -> + []; +cinit_big_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + %% Set {active, false} so that accept is passive to begin with. + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {sockopts, [{active, once}]}, % {active, once} here. + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_big_return_chkclose(doc) -> + "Server sends 50000 bytes to client, that receives them, sends them " + "back, and closes. Server waits for close. Both have certs."; +sinit_big_return_chkclose(suite) -> + []; +sinit_big_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {recv, DataSize}, {send, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_big_echo_chkclose(doc) -> + "Client sends 50000 bytes to server, that echoes them back " + "and closes. Client waits for close. Both have certs."; +cinit_big_echo_chkclose(suite) -> + []; +cinit_big_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_huge_echo_chkclose(doc) -> + "Client sends 500000 bytes to server, that echoes them back " + "and closes. Client waits for close. Both have certs."; +cinit_huge_echo_chkclose(suite) -> + []; +cinit_huge_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 500000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_big_echo_chkclose(doc) -> + "Server sends 50000 bytes to client, that echoes them back " + "and closes. Server waits for close. Both have certs."; +sinit_big_echo_chkclose(suite) -> + []; +sinit_big_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {echo, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7). + +cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS). + +cinit_many_echo_chkclose(doc, _NConns) -> + "client send 10000 bytes to server, that echoes them back " + "and closes. Clients wait for close. All have certs."; +cinit_many_echo_chkclose(suite, _NConns) -> + []; +cinit_many_echo_chkclose(Config, NConns) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 10000, LPort = 3456, + Timeout = 80000, + + io:format("~w connections", [NConns]), + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_cnocert(doc) -> + "Client sends 1000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Client has no cert, " + "but server has."; +cinit_cnocert(suite) -> + []; +cinit_cnocert(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3457, + Timeout = 40000, NConns = 1, + + ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, once}]}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + + diff --git a/lib/ssl/test/old_ssl_dist_SUITE.erl b/lib/ssl/test/old_ssl_dist_SUITE.erl new file mode 100644 index 0000000000..56209c3530 --- /dev/null +++ b/lib/ssl/test/old_ssl_dist_SUITE.erl @@ -0,0 +1,595 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + + +%%%------------------------------------------------------------------- +%%% File : ssl_dist_SUITE.erl +%%% Author : Rickard Green +%%% Description : Test that the Erlang distribution works over ssl. +%%% +%%% Created : 15 Nov 2007 by Rickard Green +%%%------------------------------------------------------------------- +-module(old_ssl_dist_SUITE). + +-include("test_server.hrl"). + +-define(DEFAULT_TIMETRAP_SECS, 240). + +-define(AWAIT_SLL_NODE_UP_TIMEOUT, 30000). + +-export([all/1]). +-export([init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + fin_per_testcase/2]). +-export([cnct2tstsrvr/1]). + +-export([basic/1]). + +-record(node_handle, {connection_handler, socket, name, nodename}). + +all(doc) -> + []; +all(suite) -> + [basic]. + +init_per_suite(Config) -> + add_ssl_opts_config(Config). + +end_per_suite(Config) -> + Config. + +init_per_testcase(Case, Config) when list(Config) -> + Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)), + [{watchdog, Dog},{testcase, Case}|Config]. + +fin_per_testcase(_Case, Config) when list(Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Testcases %% +%% %% + +basic(doc) -> + ["Test that two nodes can connect via ssl distribution"]; +basic(suite) -> + []; +basic(Config) when is_list(Config) -> + ?line NH1 = start_ssl_node(Config), + ?line Node1 = NH1#node_handle.nodename, + ?line NH2 = start_ssl_node(Config), + ?line Node2 = NH2#node_handle.nodename, + + ?line pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), + + ?line [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end), + ?line [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end), + + %% The test_server node has the same cookie as the ssl nodes + %% but it should not be able to communicate with the ssl nodes + %% via the erlang distribution. + ?line pang = net_adm:ping(Node1), + ?line pang = net_adm:ping(Node2), + + + %% + %% Check that we are able to communicate over the erlang + %% distribution between the ssl nodes. + %% + ?line Ref = make_ref(), + ?line spawn(fun () -> + apply_on_ssl_node( + NH1, + fun () -> + tstsrvr_format("Hi from ~p!~n", + [node()]), + send_to_tstcntrl({Ref, self()}), + receive + {From, ping} -> + From ! {self(), pong} + end + end) + end), + ?line receive + {Ref, SslPid} -> + ?line ok = apply_on_ssl_node( + NH2, + fun () -> + tstsrvr_format("Hi from ~p!~n", + [node()]), + SslPid ! {self(), ping}, + receive + {SslPid, pong} -> + ok + end + end) + end, + + ?line stop_ssl_node(NH1), + ?line stop_ssl_node(NH2), + ?line success(Config). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Internal functions %% +%% %% + +%% +%% ssl_node side api +%% + +tstsrvr_format(Fmt, ArgList) -> + send_to_tstsrvr({format, Fmt, ArgList}). + +send_to_tstcntrl(Message) -> + send_to_tstsrvr({message, Message}). + + +%% +%% test_server side api +%% + +apply_on_ssl_node(Node, M, F, A) when atom(M), atom(F), list(A) -> + Ref = make_ref(), + send_to_ssl_node(Node, {apply, self(), Ref, M, F, A}), + receive + {Ref, Result} -> + Result + end. + +apply_on_ssl_node(Node, Fun) when is_function(Fun, 0) -> + Ref = make_ref(), + send_to_ssl_node(Node, {apply, self(), Ref, Fun}), + receive + {Ref, Result} -> + Result + end. + +stop_ssl_node(#node_handle{connection_handler = Handler, + socket = Socket, + name = Name}) -> + ?t:format("Trying to stop ssl node ~s.~n", [Name]), + Mon = erlang:monitor(process, Handler), + unlink(Handler), + case gen_tcp:send(Socket, term_to_binary(stop)) of + ok -> + receive + {'DOWN', Mon, process, Handler, Reason} -> + case Reason of + normal -> ok; + _ -> exit(Reason) + end + end; + Error -> + erlang:demonitor(Mon, [flush]), + exit(Error) + end. + +start_ssl_node(Config) -> + start_ssl_node(Config, ""). + +start_ssl_node(Config, XArgs) -> + Name = mk_node_name(Config), + SSL = ?config(ssl_opts, Config), + SSLDistOpts = setup_dist_opts(Name, ?config(priv_dir, Config)), + start_ssl_node_raw(Name, SSL ++ " " ++ SSLDistOpts ++ XArgs). + +start_ssl_node_raw(Name, Args) -> + {ok, LSock} = gen_tcp:listen(0, + [binary, {packet, 4}, {active, false}]), + {ok, ListenPort} = inet:port(LSock), + CmdLine = mk_node_cmdline(ListenPort, Name, Args), + ?t:format("Attempting to start ssl node ~s: ~s~n", [Name, CmdLine]), + case open_port({spawn, CmdLine}, []) of + Port when port(Port) -> + unlink(Port), + erlang:port_close(Port), + case await_ssl_node_up(Name, LSock) of + #node_handle{} = NodeHandle -> + ?t:format("Ssl node ~s started.~n", [Name]), + NodeName = list_to_atom(Name ++ "@" ++ host_name()), + NodeHandle#node_handle{nodename = NodeName}; + Error -> + exit({failed_to_start_node, Name, Error}) + end; + Error -> + exit({failed_to_start_node, Name, Error}) + end. + +%% +%% command line creation +%% + +host_name() -> + [$@ | Host] = lists:dropwhile(fun ($@) -> false; (_) -> true end, + atom_to_list(node())), + Host. + +mk_node_name(Config) -> + {A, B, C} = erlang:now(), + Case = ?config(testcase, Config), + atom_to_list(?MODULE) + ++ "_" + ++ atom_to_list(Case) + ++ "_" + ++ integer_to_list(A) + ++ "-" + ++ integer_to_list(B) + ++ "-" + ++ integer_to_list(C). + +mk_node_cmdline(ListenPort, Name, Args) -> + Static = "-detached -noinput", + Pa = filename:dirname(code:which(?MODULE)), + Prog = case catch init:get_argument(progname) of + {ok,[[P]]} -> P; + _ -> exit(no_progname_argument_found) + end, + NameSw = case net_kernel:longnames() of + false -> "-sname "; + _ -> "-name " + end, + {ok, Pwd} = file:get_cwd(), + Prog ++ " " + ++ Static ++ " " + ++ NameSw ++ " " ++ Name ++ " " + ++ "-pa " ++ Pa ++ " " + ++ "-run " ++ atom_to_list(?MODULE) ++ " cnct2tstsrvr " + ++ host_name() ++ " " + ++ integer_to_list(ListenPort) ++ " " + ++ Args ++ " " + ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ Name ++ " " + ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()). + +%% +%% Connection handler test_server side +%% + +await_ssl_node_up(Name, LSock) -> + case gen_tcp:accept(LSock, ?AWAIT_SLL_NODE_UP_TIMEOUT) of + timeout -> + gen_tcp:close(LSock), + ?t:format("Timeout waiting for ssl node ~s to come up~n", + [Name]), + timeout; + {ok, Socket} -> + gen_tcp:close(LSock), + case gen_tcp:recv(Socket, 0) of + {ok, Bin} -> + check_ssl_node_up(Socket, Name, Bin); + {error, closed} -> + gen_tcp:close(Socket), + exit({lost_connection_with_ssl_node_before_up, Name}) + end; + {error, Error} -> + gen_tcp:close(LSock), + exit({accept_failed, Error}) + end. + +check_ssl_node_up(Socket, Name, Bin) -> + case catch binary_to_term(Bin) of + {'EXIT', _} -> + gen_tcp:close(Socket), + exit({bad_data_received_from_ssl_node, Name, Bin}); + {ssl_node_up, NodeName} -> + case list_to_atom(Name++"@"++host_name()) of + NodeName -> + Parent = self(), + Go = make_ref(), + %% Spawn connection handler on test server side + Pid = spawn_link( + fun () -> + receive Go -> ok end, + tstsrvr_con_loop(Name, Socket, Parent) + end), + ok = gen_tcp:controlling_process(Socket, Pid), + Pid ! Go, + #node_handle{connection_handler = Pid, + socket = Socket, + name = Name}; + _ -> + exit({unexpected_ssl_node_connected, NodeName}) + end; + Msg -> + exit({unexpected_msg_instead_of_ssl_node_up, Name, Msg}) + end. + +send_to_ssl_node(#node_handle{connection_handler = Hndlr}, Term) -> + Hndlr ! {relay_to_ssl_node, term_to_binary(Term)}, + ok. + +tstsrvr_con_loop(Name, Socket, Parent) -> + inet:setopts(Socket,[{active,once}]), + receive + {relay_to_ssl_node, Data} when is_binary(Data) -> + case gen_tcp:send(Socket, Data) of + ok -> + ok; + _Error -> + gen_tcp:close(Socket), + exit({failed_to_relay_data_to_ssl_node, Name, Data}) + end; + {tcp, Socket, Bin} -> + case catch binary_to_term(Bin) of + {'EXIT', _} -> + gen_tcp:close(Socket), + exit({bad_data_received_from_ssl_node, Name, Bin}); + {format, FmtStr, ArgList} -> + ?t:format(FmtStr, ArgList); + {message, Msg} -> + Parent ! Msg; + {apply_res, To, Ref, Res} -> + To ! {Ref, Res}; + bye -> + ?t:format("Ssl node ~s stopped.~n", [Name]), + gen_tcp:close(Socket), + exit(normal); + Unknown -> + exit({unexpected_message_from_ssl_node, Name, Unknown}) + end; + {tcp_closed, Socket} -> + gen_tcp:close(Socket), + exit({lost_connection_with_ssl_node, Name}) + end, + tstsrvr_con_loop(Name, Socket, Parent). + +%% +%% Connection handler ssl_node side +%% + +% cnct2tstsrvr() is called via command line arg -run ... +cnct2tstsrvr([Host, Port]) when list(Host), list(Port) -> + %% Spawn connection handler on ssl node side + ConnHandler + = spawn(fun () -> + case catch gen_tcp:connect(Host, + list_to_integer(Port), + [binary, + {packet, 4}, + {active, false}]) of + {ok, Socket} -> + notify_ssl_node_up(Socket), + ets:new(test_server_info, + [set, + public, + named_table, + {keypos, 1}]), + ets:insert(test_server_info, + {test_server_handler, self()}), + ssl_node_con_loop(Socket); + _Error -> + halt("Failed to connect to test server") + end + end), + spawn(fun () -> + Mon = erlang:monitor(process, ConnHandler), + receive + {'DOWN', Mon, process, ConnHandler, Reason} -> + receive after 1000 -> ok end, + halt("test server connection handler terminated: " + ++ + lists:flatten(io_lib:format("~p", [Reason]))) + end + end). + +notify_ssl_node_up(Socket) -> + case catch gen_tcp:send(Socket, + term_to_binary({ssl_node_up, node()})) of + ok -> ok; + _ -> halt("Failed to notify test server that I'm up") + end. + +send_to_tstsrvr(Term) -> + case catch ets:lookup_element(test_server_info, test_server_handler, 2) of + Hndlr when pid(Hndlr) -> + Hndlr ! {relay_to_test_server, term_to_binary(Term)}, ok; + _ -> + receive after 200 -> ok end, + send_to_tstsrvr(Term) + end. + +ssl_node_con_loop(Socket) -> + inet:setopts(Socket,[{active,once}]), + receive + {relay_to_test_server, Data} when is_binary(Data) -> + case gen_tcp:send(Socket, Data) of + ok -> + ok; + _Error -> + gen_tcp:close(Socket), + halt("Failed to relay data to test server") + end; + {tcp, Socket, Bin} -> + case catch binary_to_term(Bin) of + {'EXIT', _} -> + gen_tcp:close(Socket), + halt("test server sent me bad data"); + {apply, From, Ref, M, F, A} -> + spawn_link( + fun () -> + send_to_tstsrvr({apply_res, + From, + Ref, + (catch apply(M, F, A))}) + end); + {apply, From, Ref, Fun} -> + spawn_link(fun () -> + send_to_tstsrvr({apply_res, + From, + Ref, + (catch Fun())}) + end); + stop -> + gen_tcp:send(Socket, term_to_binary(bye)), + gen_tcp:close(Socket), + init:stop(), + receive after infinity -> ok end; + _Unknown -> + halt("test server sent me an unexpected message") + end; + {tcp_closed, Socket} -> + halt("Lost connection to test server") + end, + ssl_node_con_loop(Socket). + +%% +%% Setup ssl dist info +%% + +rand_bin(N) -> + rand_bin(N, []). + +rand_bin(0, Acc) -> + Acc; +rand_bin(N, Acc) -> + rand_bin(N-1, [random:uniform(256)-1|Acc]). + +make_randfile(Dir) -> + {ok, IoDev} = file:open(filename:join([Dir, "RAND"]), [write]), + {A, B, C} = erlang:now(), + random:seed(A, B, C), + ok = file:write(IoDev, rand_bin(1024)), + file:close(IoDev). + +append_files(FileNames, ResultFileName) -> + {ok, ResultFile} = file:open(ResultFileName, [write]), + do_append_files(FileNames, ResultFile). + +do_append_files([], RF) -> + ok = file:close(RF); +do_append_files([F|Fs], RF) -> + {ok, Data} = file:read_file(F), + ok = file:write(RF, Data), + do_append_files(Fs, RF). + +setup_dist_opts(Name, PrivDir) -> + NodeDir = filename:join([PrivDir, Name]), + RGenDir = filename:join([NodeDir, "rand_gen"]), + ok = file:make_dir(NodeDir), + ok = file:make_dir(RGenDir), + make_randfile(RGenDir), + make_certs:all(RGenDir, NodeDir), + SDir = filename:join([NodeDir, "server"]), + SC = filename:join([SDir, "cert.pem"]), + SK = filename:join([SDir, "key.pem"]), + SKC = filename:join([SDir, "keycert.pem"]), + append_files([SK, SC], SKC), + CDir = filename:join([NodeDir, "client"]), + CC = filename:join([CDir, "cert.pem"]), + CK = filename:join([CDir, "key.pem"]), + CKC = filename:join([CDir, "keycert.pem"]), + append_files([CK, CC], CKC), + "-proto_dist inet_ssl " + ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " " + ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " " +.% ++ "-ssl_dist_opt verify 1 depth 1". + +%% +%% Start scripts etc... +%% + +add_ssl_opts_config(Config) -> + %% + %% Start with boot scripts if on an installed system; otherwise, + %% just point out ssl ebin with -pa. + %% + try + Dir = ?config(priv_dir, Config), + LibDir = code:lib_dir(), + Apps = application:which_applications(), + {value, {stdlib, _, STDL_VSN}} = lists:keysearch(stdlib, 1, Apps), + {value, {kernel, _, KRNL_VSN}} = lists:keysearch(kernel, 1, Apps), + StdlDir = filename:join([LibDir, "stdlib-" ++ STDL_VSN]), + KrnlDir = filename:join([LibDir, "kernel-" ++ KRNL_VSN]), + {ok, _} = file:read_file_info(StdlDir), + {ok, _} = file:read_file_info(KrnlDir), + SSL_VSN = case lists:keysearch(ssl, 1, Apps) of + {value, {ssl, _, VSN}} -> + VSN; + _ -> + application:start(ssl), + try + {value, + {ssl, + _, + VSN}} = lists:keysearch(ssl, + 1, + application:which_applications()), + VSN + after + application:stop(ssl) + end + end, + SslDir = filename:join([LibDir, "ssl-" ++ SSL_VSN]), + {ok, _} = file:read_file_info(SslDir), + %% We are using an installed otp system, create the boot script. + Script = filename:join(Dir, atom_to_list(?MODULE)), + {ok, RelFile} = file:open(Script ++ ".rel", [write]), + io:format(RelFile, + "{release, ~n" + " {\"SSL distribution test release\", \"~s\"},~n" + " {erts, \"~s\"},~n" + " [{kernel, \"~s\"},~n" + " {stdlib, \"~s\"},~n" + " {ssl, \"~s\"}]}.~n", + [case catch erlang:system_info(otp_release) of + {'EXIT', _} -> "R11B"; + Rel -> Rel + end, + erlang:system_info(version), + KRNL_VSN, + STDL_VSN, + SSL_VSN]), + ok = file:close(RelFile), + ok = systools:make_script(Script, []), + [{ssl_opts, "-boot " ++ Script} | Config] + catch + _:_ -> + [{ssl_opts, "-pa " ++ filename:dirname(code:which(ssl))} + | add_comment_config( + "Bootscript wasn't used since the test wasn't run on an " + "installed OTP system.", + Config)] + end. + +%% +%% Add common comments to config +%% + +add_comment_config(Comment, []) -> + [{comment, Comment}]; +add_comment_config(Comment, [{comment, OldComment} | Cs]) -> + [{comment, Comment ++ " " ++ OldComment} | Cs]; +add_comment_config(Comment, [C|Cs]) -> + [C|add_comment_config(Comment, Cs)]. + +%% +%% Call when test case success +%% + +success(Config) -> + case lists:keysearch(comment, 1, Config) of + {value, {comment, _} = Res} -> Res; + _ -> ok + end. diff --git a/lib/ssl/test/old_ssl_misc_SUITE.erl b/lib/ssl/test/old_ssl_misc_SUITE.erl new file mode 100644 index 0000000000..55d1b71025 --- /dev/null +++ b/lib/ssl/test/old_ssl_misc_SUITE.erl @@ -0,0 +1,105 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_ssl_misc_SUITE). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + config/1, + finish/1, + seed/1, + app/1 + ]). + +-import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + +-define(MANYCONNS, 5). + +init_per_testcase(_Case, Config) -> + WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of misc in ssl.erl interface."; +all(suite) -> + {conf, + config, + [seed, app], + finish + }. + +config(doc) -> + "Want to se what Config contains."; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + + %% Check if SSL exists. If this case fails, all other cases are skipped + case ssl:start() of + ok -> ssl:stop(); + {error, {already_started, _}} -> ssl:stop(); + Error -> ?t:fail({failed_starting_ssl,Error}) + end, + Config. + +finish(doc) -> + "This test case has no mission other than closing the conf case"; +finish(suite) -> + []; +finish(Config) -> + Config. + +seed(doc) -> + "Test that ssl:seed/1 works."; +seed(suite) -> + []; +seed(Config) when list(Config) -> + process_flag(trap_exit, true), + LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config), + + LCmds = [{seed, "tjosan"}, + {sockopts, [{backlog, NConns}, {active, once}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ?line test_server_only(NConns, LCmds, [], Timeout, ?MODULE, + Config). + +app(doc) -> + "Test that the ssl app file is ok"; +app(suite) -> + []; +app(Config) when list(Config) -> + ?line ok = test_server:app_test(ssl). + + diff --git a/lib/ssl/test/old_ssl_passive_SUITE.erl b/lib/ssl/test/old_ssl_passive_SUITE.erl new file mode 100644 index 0000000000..4cb8c1f0cd --- /dev/null +++ b/lib/ssl/test/old_ssl_passive_SUITE.erl @@ -0,0 +1,374 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_ssl_passive_SUITE). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + config/1, + finish/1, + server_accept_timeout/1, + cinit_return_chkclose/1, + sinit_return_chkclose/1, + cinit_big_return_chkclose/1, + sinit_big_return_chkclose/1, + cinit_big_echo_chkclose/1, + sinit_big_echo_chkclose/1, + cinit_few_echo_chkclose/1, + cinit_many_echo_chkclose/1, + cinit_cnocert/1 + ]). + +-import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). + +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + +-define(MANYCONNS, ssl_test_MACHINE:many_conns()). + +init_per_testcase(_Case, Config) -> + WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of ssl.erl interface in passive mode."; +all(suite) -> + {conf, + config, + [server_accept_timeout, + cinit_return_chkclose, + sinit_return_chkclose, + cinit_big_return_chkclose, + sinit_big_return_chkclose, + cinit_big_echo_chkclose, + sinit_big_echo_chkclose, + cinit_few_echo_chkclose, + cinit_many_echo_chkclose, + cinit_cnocert], + finish}. + +config(doc) -> + "Want to se what Config contains."; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + + %% Check if SSL exists. If this case fails, all other cases are skipped + case ssl:start() of + ok -> ssl:stop(); + {error, {already_started, _}} -> ssl:stop(); + Error -> ?t:fail({failed_starting_ssl,Error}) + end, + Config. + +finish(doc) -> + "This test case has no mission other than closing the conf case"; +finish(suite) -> + []; +finish(Config) -> + Config. + +server_accept_timeout(doc) -> + "Server has one pending accept with timeout. Checks that return " + "value is {error, timeout}."; +server_accept_timeout(suite) -> + []; +server_accept_timeout(Config) when list(Config) -> + process_flag(trap_exit, true), + LPort = 3456, + Timeout = 40000, NConns = 1, + AccTimeout = 3000, + + ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, AccTimeout}, + accept_timeout], + ?line test_server_only(NConns, LCmds, ACmds, Timeout, ?MODULE, Config). + +cinit_return_chkclose(doc) -> + "Client sends 1000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +cinit_return_chkclose(suite) -> + []; +cinit_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_return_chkclose(doc) -> + "Server sends 1000 bytes to client, that receives them, sends them " + "back, and closes. Server waits for close. Both have certs."; +sinit_return_chkclose(suite) -> + []; +sinit_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {recv, DataSize}, {send, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_big_return_chkclose(doc) -> + "Client sends 50000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +cinit_big_return_chkclose(suite) -> + []; +cinit_big_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_big_return_chkclose(doc) -> + "Server sends 50000 bytes to client, that receives them, sends them " + "back, and closes. Server waits for close. Both have certs."; +sinit_big_return_chkclose(suite) -> + []; +sinit_big_return_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {recv, DataSize}, {send, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_big_echo_chkclose(doc) -> + "Client sends 50000 bytes to server, that echoes them back " + "and closes. Client waits for close. Both have certs."; +cinit_big_echo_chkclose(suite) -> + []; +cinit_big_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +sinit_big_echo_chkclose(doc) -> + "Server sends 50000 bytes to client, that echoes them back " + "and closes. Server waits for close. Both have certs."; +sinit_big_echo_chkclose(suite) -> + []; +sinit_big_echo_chkclose(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 50000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {send, DataSize}, {recv, DataSize}, + await_close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {echo, DataSize}, + close], + + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + + +cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7). + +cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS). + +cinit_many_echo_chkclose(doc, _NConns) -> + "clients send 10000 bytes to server, that echoes them back " + "and closes. Clients wait for close. All have certs."; +cinit_many_echo_chkclose(suite, _NConns) -> + []; +cinit_many_echo_chkclose(Config, NConns) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 10000, LPort = 3456, + Timeout = 80000, + + io:format("~w connections", [NConns]), + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {echo, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + +cinit_cnocert(doc) -> + "Client sends 1000 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Client has no cert, " + "but server has."; +cinit_cnocert(suite) -> + []; +cinit_cnocert(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3457, + Timeout = 40000, NConns = 1, + + ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, {send, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sockopts, [{active, false}]}, + {connect, {Host, LPort}}, + {send, DataSize}, {recv, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, + Config). + diff --git a/lib/ssl/test/old_ssl_peer_cert_SUITE.erl b/lib/ssl/test/old_ssl_peer_cert_SUITE.erl new file mode 100644 index 0000000000..f0b8db2607 --- /dev/null +++ b/lib/ssl/test/old_ssl_peer_cert_SUITE.erl @@ -0,0 +1,180 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_ssl_peer_cert_SUITE). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + config/1, + finish/1, + cinit_plain/1, + cinit_both_verify/1, + cinit_cnocert/1 + ]). + +-import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + + +init_per_testcase(_Case, Config) -> + WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of ssl verification and peer certificate retrieval."; +all(suite) -> + {conf, + config, + [cinit_plain, + cinit_both_verify, + cinit_cnocert], + finish}. + +config(doc) -> + "Want to se what Config contains."; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + + %% Check if SSL exists. If this case fails, all other cases are skipped + case ssl:start() of + ok -> ssl:stop(); + {error, {already_started, _}} -> ssl:stop(); + Error -> ?t:fail({failed_starting_ssl,Error}) + end, + Config. + +finish(doc) -> + "This test case has no mission other than closing the conf case"; +finish(suite) -> + []; +finish(Config) -> + Config. + +cinit_plain(doc) -> + "Server closes after accept, Client waits for close. Both have certs " + "but both use the defaults for verify and depth, but still tries " + "to retreive each others certificates."; +cinit_plain(suite) -> + []; +cinit_plain(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), + + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + nopeercert, + {recv, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + peercert, + {send, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, + ?MODULE, Config). + +cinit_both_verify(doc) -> + "Server closes after accept, Client waits for close. Both have certs " + "and both verify each other."; +cinit_both_verify(suite) -> + []; +cinit_both_verify(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts0, SsslOpts0}} = mk_ssl_cert_opts(Config), + ?line CsslOpts = [{verify, 2}, {depth, 2} | CsslOpts0], + ?line SsslOpts = [{verify, 2}, {depth, 3} | SsslOpts0], + + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + peercert, + {recv, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + peercert, + {send, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, + ?MODULE, Config). + +cinit_cnocert(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close."; +cinit_cnocert(suite) -> + []; +cinit_cnocert(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3457, + Timeout = 40000, NConns = 1, + + ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config), + ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0], + + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {connect, {Host, LPort}}, + peercert, + {send, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, + ?MODULE, Config). + + diff --git a/lib/ssl/test/old_ssl_protocol_SUITE.erl b/lib/ssl/test/old_ssl_protocol_SUITE.erl new file mode 100644 index 0000000000..7bde5d6749 --- /dev/null +++ b/lib/ssl/test/old_ssl_protocol_SUITE.erl @@ -0,0 +1,169 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_ssl_protocol_SUITE). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2, config/1, + finish/1, sslv2/1, sslv3/1, tlsv1/1, sslv2_sslv3/1, + sslv2_tlsv1/1, sslv3_tlsv1/1, sslv2_sslv3_tlsv1/1]). + +-import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + + +init_per_testcase(_Case, Config) -> + WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of configuration protocol_version."; +all(suite) -> + {conf, + config, + [sslv2, sslv3, tlsv1, sslv2_sslv3, sslv2_tlsv1, sslv3_tlsv1, + sslv2_sslv3_tlsv1], + finish}. + +config(doc) -> + "Want to se what Config contains."; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + + %% Check if SSL exists. If this case fails, all other cases are skipped + case ssl:start() of + ok -> ssl:stop(); + {error, {already_started, _}} -> ssl:stop(); + Error -> ?t:fail({failed_starting_ssl,Error}) + end, + Config. + +finish(doc) -> + "This test case has no other purpose than closing the conf case."; +finish(suite) -> + []; +finish(Config) -> + Config. + +%%%%% + +sslv2(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close. " + "Client and server choose SSLv2."; +sslv2(suite) -> + []; +sslv2(Config) when list(Config) -> + do_run_test(Config, [sslv2]). + +sslv3(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close. " + "Client and server choose SSLv3."; +sslv3(suite) -> + []; +sslv3(Config) when list(Config) -> + do_run_test(Config, [sslv3]). + +tlsv1(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close. " + "Client and server choose TLSv1."; +tlsv1(suite) -> + []; +tlsv1(Config) when list(Config) -> + do_run_test(Config, [tlsv1]). + +sslv2_sslv3(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close. " + "Client and server choose between SSLv2 and SSLv3."; +sslv2_sslv3(suite) -> + []; +sslv2_sslv3(Config) when list(Config) -> + do_run_test(Config, [sslv2, sslv3]). + +sslv2_tlsv1(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close. " + "Client and server choose between SSLv2 and TLSv1."; +sslv2_tlsv1(suite) -> + []; +sslv2_tlsv1(Config) when list(Config) -> + do_run_test(Config, [sslv2, tlsv1]). + +sslv3_tlsv1(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close. " + "Client and server choose between SSLv3 and TLSv1."; +sslv3_tlsv1(suite) -> + []; +sslv3_tlsv1(Config) when list(Config) -> + do_run_test(Config, [sslv3, tlsv1]). + +sslv2_sslv3_tlsv1(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close. " + "Client and server choose between SSLv2, SSLv3, and TLSv1."; +sslv2_sslv3_tlsv1(suite) -> + []; +sslv2_sslv3_tlsv1(Config) when list(Config) -> + do_run_test(Config, [sslv2, sslv3, tlsv1]). + +%%%% + +do_run_test(Config0, Protocols) -> + process_flag(trap_exit, true), + LPort = 3456, + Timeout = 40000, NConns = 1, + DataSize = 10, + + ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config0), + ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0], + + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + connection_info, + {recv, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {connect, {Host, LPort}}, + connection_info, + {send, DataSize}, + await_close], + Config1 = [{env, [{protocol_version, Protocols}]} | Config0], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, + ?MODULE, Config1). + + diff --git a/lib/ssl/test/old_ssl_verify_SUITE.erl b/lib/ssl/test/old_ssl_verify_SUITE.erl new file mode 100644 index 0000000000..5db964526f --- /dev/null +++ b/lib/ssl/test/old_ssl_verify_SUITE.erl @@ -0,0 +1,141 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_ssl_verify_SUITE). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + config/1, + finish/1, + cinit_both_verify/1, + cinit_cnocert/1 + ]). + +-import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + + +init_per_testcase(_Case, Config) -> + WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of ssl.erl interface in active mode."; +all(suite) -> + {conf, + config, + [cinit_both_verify, + cinit_cnocert], + finish}. + +config(doc) -> + "Want to se what Config contains."; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + + %% Check if SSL exists. If this case fails, all other cases are skipped + case ssl:start() of + ok -> ssl:stop(); + {error, {already_started, _}} -> ssl:stop(); + Error -> ?t:fail({failed_starting_ssl,Error}) + end, + Config. + +finish(doc) -> + "This test case has no mission other than closing the conf case"; +finish(suite) -> + []; +finish(Config) -> + Config. + +cinit_both_verify(doc) -> + "Server closes after accept, Client waits for close. Both have certs " + "and both verify each other."; +cinit_both_verify(suite) -> + []; +cinit_both_verify(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3456, + Timeout = 40000, NConns = 1, + + ?line {ok, {CsslOpts0, SsslOpts0}} = mk_ssl_cert_opts(Config), + ?line CsslOpts = [{verify, 2}, {depth, 2} | CsslOpts0], + ?line SsslOpts = [{verify, 2}, {depth, 3} | SsslOpts0], + + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {sslopts, CsslOpts}, + {connect, {Host, LPort}}, + {send, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, + ?MODULE, Config). + +cinit_cnocert(doc) -> + "Client has no cert. Nor the client, nor the server is verifying its " + "peer. Server closes, client waits for close."; +cinit_cnocert(suite) -> + []; +cinit_cnocert(Config) when list(Config) -> + process_flag(trap_exit, true), + DataSize = 1000, LPort = 3457, + Timeout = 40000, NConns = 1, + + ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config), + ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0], + + ?line {ok, Host} = inet:gethostname(), + + LCmds = [{sockopts, [{backlog, NConns}]}, + {sslopts, SsslOpts}, + {listen, LPort}, + wait_sync, + lclose], + ACmds = [{timeout, Timeout}, + accept, + {recv, DataSize}, + close], + CCmds = [{timeout, Timeout}, + {connect, {Host, LPort}}, + {send, DataSize}, + await_close], + ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, + ?MODULE, Config). + + diff --git a/lib/ssl/test/old_transport_accept_SUITE.erl b/lib/ssl/test/old_transport_accept_SUITE.erl new file mode 100644 index 0000000000..4bb09cee19 --- /dev/null +++ b/lib/ssl/test/old_transport_accept_SUITE.erl @@ -0,0 +1,238 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(old_transport_accept_SUITE). +-include("test_server.hrl"). +-include("test_server_line.hrl"). + +%% Default timetrap timeout (set in init_per_testcase). +-define(default_timeout, ?t:minutes(1)). +-define(application, ssh). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + config/1, + echo_once/1, + echo_twice/1, + close_before_ssl_accept/1, + server/5, + tolerant_server/5, + client/5 + ]). + +init_per_testcase(_Case, Config) -> + WatchDog = ssl_test_lib:timetrap(?default_timeout), + [{watchdog, WatchDog}, {protomod, gen_tcp}, {serialize_accept, true}| + Config]. + +fin_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test transport_accept and ssl_accept"; +all(suite) -> + [config, echo_once, echo_twice, close_before_ssl_accept]. + +config(doc) -> + "Want to se what Config contains."; +config(suite) -> + []; +config(Config) -> + io:format("Config: ~p~n", [Config]), + ok. + +echo_once(doc) -> + "Client sends 256 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +echo_once(suite) -> + []; +echo_once(Config) when list(Config) -> + process_flag(trap_exit, true), + LPort = 3456, + {ok, Host} = inet:gethostname(), + {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config), + N = 1, + Msg = lists:seq(0, 255), + Self = self(), + Params = "-pa " ++ filename:dirname(code:which(?MODULE)), + Node = start_node(server, Params), + CNode = start_node(client, Params), + Server = spawn_link(Node, ?MODULE, server, [Self, LPort, SOpts, Msg, N]), + Client = spawn_link(Node, ?MODULE, client, [Host, LPort, COpts, Msg, N]), + ok = receive + {Server, listening} -> + Client ! {Server, listening}, + ok; + E -> + io:format("bad receive (1) ~p\n", [E]), + E + end, + receive + {Server, done} -> + ok + end, + test_server:stop_node(Node), + test_server:stop_node(CNode). + +close_before_ssl_accept(doc) -> + "Client sends 256 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +close_before_ssl_accept(suite) -> + []; +close_before_ssl_accept(Config) when list(Config) -> + process_flag(trap_exit, true), + LPort = 3456, + {ok, Host} = inet:gethostname(), + {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config), + Msg = lists:seq(0, 255), + Self = self(), + Params = "-pa " ++ filename:dirname(code:which(?MODULE)), + Node = start_node(server, Params), + CNode = start_node(client, Params), + Server = spawn_link(Node, ?MODULE, tolerant_server, + [Self, LPort, SOpts, Msg, 2]), + Client = spawn_link(Node, ?MODULE, client, + [Host, LPort, COpts, Msg, 1]), + ok = receive + {Server, listening} -> + {ok, S} = gen_tcp:connect(Host, LPort, []), + gen_tcp:close(S), + Client ! {Server, listening}, + ok; + E -> + io:format("bad receive (1) ~p\n", [E]), + E + end, + receive + {Server, done} -> + ok + end, + test_server:stop_node(Node), + test_server:stop_node(CNode). + +client(Host, LPort, COpts, Msg, N) -> + ok = receive + {_Server, listening} -> + ok; + E -> + io:format("bad receive (2) ~p\n", [E]), + E + end, + Opts = COpts ++ [{packet, raw}, {active, false}], + app(), + lists:foreach(fun(_) -> + {ok, S} = ssl:connect(Host, LPort, Opts), + ssl:send(S, Msg), + {ok, Msg} = ssl:recv(S, length(Msg)), + ssl:close(S) + end, lists:seq(1, N)). + +echo_twice(doc) -> + "Two clients sends 256 bytes to server, that receives them, sends them " + "back, and closes. Client waits for close. Both have certs."; +echo_twice(suite) -> + []; +echo_twice(Config) when list(Config) -> + process_flag(trap_exit, true), + LPort = 3456, + {ok, Host} = inet:gethostname(), + {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config), + N = 2, + Msg = lists:seq(0, 255), + Self = self(), + Params = "-pa " ++ filename:dirname(code:which(?MODULE)), + Node = start_node(server, Params), + CNode = start_node(client, Params), + Server = spawn_link(Node, ?MODULE, server, + [Self, LPort, SOpts, Msg, N]), + Client = spawn_link(Node, ?MODULE, client, + [Host, LPort, COpts, Msg, N]), + ok = receive + {Server, listening} -> + Client ! {Server, listening}, + ok; + E -> + io:format("bad receive (3) ~p\n", [E]), + E + end, + receive + {Server, done} -> + ok + end, + test_server:stop_node(Node), + test_server:stop_node(CNode). + +server(Client, Port, SOpts, Msg, N) -> + app(), + process_flag(trap_exit, true), + Opts = SOpts ++ [{packet, raw}, {active, false}], + {ok, LSock} = ssl:listen(Port, Opts), + Client ! {self(), listening}, + server_loop(Client, LSock, Msg, N). + +server_loop(Client, _, _, 0) -> + Client ! {self(), done}; +server_loop(Client, LSock, Msg, N) -> + {ok, S} = ssl:transport_accept(LSock), + ok = ssl:ssl_accept(S), + %% P = ssl:controlling_process(S, Proxy), + {ok, Msg} = ssl:recv(S, length(Msg)), + ok = ssl:send(S, Msg), + ok = ssl:close(S), + server_loop(Client, LSock, Msg, N-1). + +tolerant_server(Client, Port, SOpts, Msg, N) -> + app(), + process_flag(trap_exit, true), + Opts = SOpts ++ [{packet, raw}, {active, false}], + {ok, LSock} = ssl:listen(Port, Opts), + Client ! {self(), listening}, + tolerant_server_loop(Client, LSock, Msg, N). + +tolerant_server_loop(Client, _, _, 0) -> + Client ! {self(), done}; +tolerant_server_loop(Client, LSock, Msg, N) -> + {ok, S} = ssl:transport_accept(LSock), + case ssl:ssl_accept(S) of + ok -> + %% P = ssl:controlling_process(S, Proxy), + {ok, Msg} = ssl:recv(S, length(Msg)), + ok = ssl:send(S, Msg), + ok = ssl:close(S); + E -> + io:format("ssl_accept error: ~p\n", [E]) + end, + tolerant_server_loop(Client, LSock, Msg, N-1). + +app() -> + case application:get_application(ssl) of + undefined -> + application:start(ssl); + _ -> + ok + end. + +start_node(Kind, Params) -> + S = atom_to_list(?MODULE)++"_" ++ atom_to_list(Kind), + {ok, Node} = test_server:start_node(list_to_atom(S), slave, [{args, Params}]), + Node. + diff --git a/lib/ssl/test/ssl.cover b/lib/ssl/test/ssl.cover new file mode 100644 index 0000000000..138bf96b9d --- /dev/null +++ b/lib/ssl/test/ssl.cover @@ -0,0 +1,7 @@ +{exclude, [ssl_pkix_oid, + 'PKIX1Algorithms88', + 'PKIX1Explicit88', + 'PKIX1Implicit88', + 'PKIXAttributeCertificate', + 'SSL-PKIX']}. + diff --git a/lib/ssl/test/ssl.spec b/lib/ssl/test/ssl.spec new file mode 100644 index 0000000000..6ef4fb73db --- /dev/null +++ b/lib/ssl/test/ssl.spec @@ -0,0 +1 @@ +{topcase, {dir, "../ssl_test"}}. diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl new file mode 100644 index 0000000000..2b247532ee --- /dev/null +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -0,0 +1,2075 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssl_basic_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). + +-define('24H_in_sec', 86400). +-define(TIMEOUT, 60000). +-define(EXPIRE, 10). + +-behaviour(ssl_session_cache_api). + +%% For the session cache tests +-export([init/0, terminate/1, lookup/2, update/3, + delete/2, foldl/3, select_session/2]). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + crypto:start(), + ssl:start(), + Result = + (catch make_certs:all(?config(data_dir, Config), + ?config(priv_dir, Config))), + test_server:format("Make certs ~p~n", [Result]), + ssl_test_lib:cert_options(Config). + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ssl:stop(), + crypto:stop(). + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(session_cache_process_list, Config) -> + init_customized_session_cache(Config); + +init_per_testcase(session_cache_process_mnesia, Config) -> + mnesia:start(), + init_customized_session_cache(Config); + +init_per_testcase(reuse_session_expired, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_lifetime, ?EXPIRE), + ssl:start(), + [{watchdog, Dog} | Config]; + +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = test_server:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. + +init_customized_session_cache(Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = test_server:timetrap(?TIMEOUT), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_cb, ?MODULE), + ssl:start(), + [{watchdog, Dog} | Config]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(session_cache_process_list, Config) -> + application:unset_env(ssl, session_cb), + end_per_testcase(default_action, Config); +end_per_testcase(session_cache_process_mnesia, Config) -> + application:unset_env(ssl, session_cb), + mnesia:stop(), + end_per_testcase(default_action, Config); +end_per_testcase(reuse_session_expired, Config) -> + application:unset_env(ssl, session_lifetime), + end_per_testcase(default_action, Config); +end_per_testcase(_TestCase, Config) -> + Dog = ?config(watchdog, Config), + case Dog of + undefined -> + ok; + _ -> + test_server:timetrap_cancel(Dog) + end. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all(doc) -> + ["Test the basic ssl functionality"]; + +all(suite) -> + [app, connection_info, controlling_process, controller_dies, + peercert, connect_dist, + peername, sockname, socket_options, versions, cipher_suites, upgrade, + upgrade_with_timeout, + ipv6, ekeyfile, ecertfile, ecacertfile, eoptions, shutdown, + shutdown_write, shutdown_both, shutdown_error, ciphers, + send_close, + server_verify_peer_passive, + server_verify_peer_active, server_verify_peer_active_once, + server_verify_none_passive, server_verify_none_active, + server_verify_none_active_once, + server_verify_no_cacerts, client_verify_none_passive, + client_verify_none_active, client_verify_none_active_once + %%, session_cache_process_list, session_cache_process_mnesia + ,reuse_session, reuse_session_expired, server_does_not_want_to_reuse_session + ]. + +%% Test cases starts here. +%%-------------------------------------------------------------------- +app(doc) -> + "Test that the ssl app file is ok"; +app(suite) -> + []; +app(Config) when is_list(Config) -> + ok = test_server:app_test(ssl). + +connection_info(doc) -> + ["Test the API function ssl:connection_info/1"]; +connection_info(suite) -> + []; +connection_info(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, connection_info_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, connection_info_result, []}}, + {options, + [{ciphers,[{rsa,rc4_128,sha,no_export}]} | + ClientOpts]}]), + + test_server:format("Testcase ~p, Client ~p Server ~p ~n", + [self(), Client, Server]), + + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + ServerMsg = ClientMsg = {ok, {Version, {rsa,rc4_128,sha,no_export}}}, + + ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +connection_info_result(Socket) -> + ssl:connection_info(Socket). + +%%-------------------------------------------------------------------- + +controlling_process(doc) -> + ["Test API function controlling_process/2"]; + +controlling_process(suite) -> + []; + +controlling_process(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + ClientMsg = "Hello server", + ServerMsg = "Hello client", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + controlling_process_result, [self(), + ServerMsg]}}, + {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, + controlling_process_result, [self(), + ClientMsg]}}, + {options, ClientOpts}]), + + test_server:format("Testcase ~p, Client ~p Server ~p ~n", + [self(), Client, Server]), + + receive + {ssl, _, ServerMsg} -> + receive + {ssl, _, ClientMsg} -> + ok + end; + {ssl, _, ClientMsg} -> + receive + {ssl, _, ServerMsg} -> + ok + end; + Unexpected -> + test_server:fail(Unexpected) + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +controlling_process_result(Socket, Pid, Msg) -> + ok = ssl:controlling_process(Socket, Pid), + %% Make sure other side has evaluated controlling_process + %% before message is sent + test_server:sleep(100), + ssl:send(Socket, Msg), + no_result_msg. + + +controller_dies(doc) -> + ["Test that the socket is closed after controlling process dies"]; +controller_dies(suite) -> []; +controller_dies(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + ClientMsg = "Hello server", + ServerMsg = "Hello client", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + controller_dies_result, [self(), + ServerMsg]}}, + {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, + controller_dies_result, [self(), + ClientMsg]}}, + {options, ClientOpts}]), + + test_server:format("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), + timer:sleep(200), %% so that they are connected + + process_flag(trap_exit, true), + + %% Test that clients die + exit(Client, killed), + get_close(Client, ?LINE), + + %% Test that clients die when process disappear + Server ! listen, timer:sleep(200), + Tester = self(), + Connect = fun(Pid) -> + {ok, Socket} = ssl:connect(Hostname, Port, + [{reuseaddr,true},{ssl_imp,new}]), + Pid ! {self(), connected, Socket}, + receive die_nice -> normal end + end, + Client2 = spawn_link(fun() -> Connect(Tester) end), + receive {Client2, connected, _Socket} -> Client2 ! die_nice end, + + get_close(Client2, ?LINE), + + %% Test that clients die when the controlling process have changed + Server ! listen, timer:sleep(200), + + Client3 = spawn_link(fun() -> Connect(Tester) end), + Controller = spawn_link(fun() -> receive die_nice -> normal end end), + receive + {Client3, connected, Socket} -> + ok = ssl:controlling_process(Socket, Controller), + Client3 ! die_nice + end, + + test_server:format("Wating on exit ~p~n",[Client3]), + receive {'EXIT', Client3, normal} -> ok end, + + receive %% Client3 is dead but that doesn't matter, socket should not be closed. + Unexpected -> + test_server:format("Unexpected ~p~n",[Unexpected]), + test_server:fail({line, ?LINE-1}) + after 1000 -> + ok + end, + Controller ! die_nice, + get_close(Controller, ?LINE), + + %% Test that servers die + Server ! listen, timer:sleep(200), + LastClient = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + controller_dies_result, [self(), + ClientMsg]}}, + {options, [{reuseaddr,true}|ClientOpts]}]), + timer:sleep(200), %% so that they are connected + + exit(Server, killed), + get_close(Server, ?LINE), + process_flag(trap_exit, false), + ssl_test_lib:close(LastClient). + +controller_dies_result(_Socket, _Pid, _Msg) -> + receive Result -> Result end. + +get_close(Pid, Where) -> + receive + {'EXIT', Pid, _Reason} -> + receive + {_, {ssl_closed, Socket}} -> + test_server:format("Socket closed ~p~n",[Socket]); + Unexpected -> + test_server:format("Unexpected ~p~n",[Unexpected]), + test_server:fail({line, ?LINE-1}) + after 5000 -> + test_server:fail({timeout, {line, ?LINE, Where}}) + end; + Unexpected -> + test_server:format("Unexpected ~p~n",[Unexpected]), + test_server:fail({line, ?LINE-1}) + after 5000 -> + test_server:fail({timeout, {line, ?LINE, Where}}) + end. + +%%-------------------------------------------------------------------- +peercert(doc) -> + [""]; + +peercert(suite) -> + []; + +peercert(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, ClientOpts}]), + + CertFile = proplists:get_value(certfile, ServerOpts), + {ok, [{cert, BinCert, _}]} = public_key:pem_to_der(CertFile), + {ok, ErlCert} = public_key:pkix_decode_cert(BinCert, otp), + + ServerMsg = {{error, no_peercert}, {error, no_peercert}}, + ClientMsg = {{ok, BinCert}, {ok, ErlCert}}, + + test_server:format("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). + +peercert_result(Socket) -> + Result1 = ssl:peercert(Socket), + Result2 = ssl:peercert(Socket, [ssl]), + {Result1, Result2}. + +%%-------------------------------------------------------------------- +connect_dist(doc) -> + ["Test a simple connect as is used by distribution"]; + +connect_dist(suite) -> + []; + +connect_dist(Config) when is_list(Config) -> + ClientOpts0 = ?config(client_kc_opts, Config), + ClientOpts = [{ssl_imp, new},{active, false}, {packet,4}|ClientOpts0], + ServerOpts0 = ?config(server_kc_opts, Config), + ServerOpts = [{ssl_imp, new},{active, false}, {packet,4}|ServerOpts0], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, connect_dist_s, []}}, + {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, connect_dist_c, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +connect_dist_s(S) -> + Msg = term_to_binary({erlang,term}), + ok = ssl:send(S, <<(size(Msg)):32, Msg/binary>>). + +connect_dist_c(S) -> + Test = binary_to_list(term_to_binary({erlang,term})), + {ok, Test} = ssl:recv(S, 0, 10000), + ok. + + +%%-------------------------------------------------------------------- +peername(doc) -> + ["Test API function peername/1"]; + +peername(suite) -> + []; + +peername(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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), + ClientIp = ssl_test_lib:node_to_hostip(ClientNode), + ServerMsg = {ok, {ClientIp, ClientPort}}, + ClientMsg = {ok, {ServerIp, Port}}, + + test_server:format("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). + +peername_result(S) -> + ssl:peername(S). + +%%-------------------------------------------------------------------- +sockname(doc) -> + ["Test API function sockname/1"]; + +sockname(suite) -> + []; + +sockname(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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), + ClientIp = ssl_test_lib:node_to_hostip(ClientNode), + ServerMsg = {ok, {ServerIp, Port}}, + ClientMsg = {ok, {ClientIp, ClientPort}}, + + test_server:format("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_result(S) -> + ssl:sockname(S). + +%%-------------------------------------------------------------------- +cipher_suites(doc) -> + ["Test API function cipher_suites/0"]; + +cipher_suites(suite) -> + []; + +cipher_suites(Config) when is_list(Config) -> + MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha,no_export}, + [_|_] = Suites = ssl:cipher_suites(), + true = lists:member(MandatoryCipherSuite, Suites). +%%-------------------------------------------------------------------- +socket_options(doc) -> + ["Test API function getopts/2 and setopts/2"]; + +socket_options(suite) -> + []; + +socket_options(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Values = [{mode, list}, {packet, 0}, {header, 0}, + {active, true}], + %% Shall be the reverse order of Values! + Options = [active, header, packet, mode], + + NewValues = [{mode, binary}, {active, once}], + %% Shall be the reverse order of NewValues! + NewOptions = [active, mode], + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, socket_options_result, + [Options, Values, NewOptions, NewValues]}}, + {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, socket_options_result, + [Options, Values, NewOptions, NewValues]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> + %% Test get/set emulated opts + {ok, DefaultValues} = ssl:getopts(Socket, Options), + ssl:setopts(Socket, NewValues), + {ok, NewValues} = ssl:getopts(Socket, NewOptions), + %% Test get/set inet opts + {ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]), + ok. + +%%-------------------------------------------------------------------- +versions(doc) -> + ["Test API function versions/0"]; + +versions(suite) -> + []; + +versions(Config) when is_list(Config) -> + [_|_] = Versions = ssl:versions(), + test_server:format("~p~n", [Versions]). + +%%-------------------------------------------------------------------- +send_recv(doc) -> + [""]; + +send_recv(suite) -> + []; + +send_recv(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, send_recv_result, []}}, + {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, send_recv_result, []}}, + {options, [{active, false} | ClientOpts]}]), + + test_server:format("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). + +send_close(doc) -> + [""]; + +send_close(suite) -> + []; + +send_close(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + {ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect, + [Hostname,Port,[binary, {active, false}, {reuseaddr, true}]]), + {ok, SslS} = rpc:call(ClientNode, ssl, connect, + [TcpS,[{active, false}|ClientOpts]]), + + test_server:format("Testcase ~p, Client ~p Server ~p ~n", + [self(), self(), Server]), + ok = ssl:send(SslS, "HejHopp"), + {ok,<<"Hejhopp">>} = ssl:recv(SslS, 7), + gen_tcp:close(TcpS), + {error, _} = ssl:send(SslS, "HejHopp"), + ssl_test_lib:close(Server). + +%%-------------------------------------------------------------------- +upgrade(doc) -> + ["Test that you can upgrade an tcp connection to an ssl connection"]; + +upgrade(suite) -> + []; + +upgrade(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, TcpOpts}, + {ssl_options, 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, ClientOpts}]), + + test_server:format("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). + +upgrade_result(Socket) -> + ok = ssl:send(Socket, "Hejhopp"), + %% Make sure binary is inherited from tcp socket and that we do + %% not get the list default! + receive + {ssl, _, <<"Hejhopp">>} -> + ok + end. + +%%-------------------------------------------------------------------- +upgrade_with_timeout(doc) -> + ["Test ssl_accept/3"]; + +upgrade_with_timeout(suite) -> + []; + +upgrade_with_timeout(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, TcpOpts}, + {ssl_options, 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, ClientOpts}]), + + test_server:format("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). +%%-------------------------------------------------------------------- +ipv6(doc) -> + ["Test ipv6."]; +ipv6(suite) -> + []; +ipv6(Config) when is_list(Config) -> + {ok, Hostname0} = inet:gethostname(), + + case lists:member(list_to_atom(Hostname0), ?config(ipv6_hosts, Config)) of + true -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = + ssl_test_lib:run_where(Config, ipv6), + Server = ssl_test_lib:start_server([{node, ServerNode}, + {port, 0}, {from, self()}, + {mfa, {?MODULE, send_recv_result, []}}, + {options, + [inet6, {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, send_recv_result, []}}, + {options, + [inet6, {active, false} | ClientOpts]}]), + + test_server:format("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); + false -> + {skip, "Host does not support IPv6"} + end. + +%%-------------------------------------------------------------------- + +ekeyfile(doc) -> + ["Test what happens with an invalid key file"]; + +ekeyfile(suite) -> + []; + +ekeyfile(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + BadOpts = ?config(server_bad_key, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Port = ssl_test_lib:inet_port(ServerNode), + + Server = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, BadOpts}]), + Client = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, {error, ekeyfile}, Client, + {error, closed}). + +%%-------------------------------------------------------------------- + +ecertfile(doc) -> + ["Test what happens with an invalid cert file"]; + +ecertfile(suite) -> + []; + +ecertfile(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerBadOpts = ?config(server_bad_cert, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Port = ssl_test_lib:inet_port(ServerNode), + + Server0 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, ServerBadOpts}]), + Client0 = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server0, {error, ecertfile}, Client0, + {error, closed}). + + +%%-------------------------------------------------------------------- +ecacertfile(doc) -> + ["Test what happens with an invalid cacert file"]; + +ecacertfile(suite) -> + []; + +ecacertfile(Config) when is_list(Config) -> + ClientOpts = [{reuseaddr, true}|?config(client_opts, Config)], + ServerBadOpts = [{reuseaddr, true}|?config(server_bad_ca, Config)], + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Port = ssl_test_lib:inet_port(ServerNode), + + Server0 = + ssl_test_lib:start_server_error([{node, ServerNode}, + {port, Port}, {from, self()}, + {options, ServerBadOpts}]), + Client0 = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server0, {error, ecacertfile}, + Client0, {error, closed}), + + File0 = proplists:get_value(cacertfile, ServerBadOpts), + File = File0 ++ "do_not_exit.pem", + ServerBadOpts1 = [{cacertfile, File}|proplists:delete(cacertfile, ServerBadOpts)], + + Server1 = + ssl_test_lib:start_server_error([{node, ServerNode}, + {port, Port}, {from, self()}, + {options, ServerBadOpts1}]), + Client1 = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server1, {error, ecacertfile}, + Client1, {error, closed}), + ok. + + + +%%-------------------------------------------------------------------- +eoptions(doc) -> + ["Test what happens when we give invalid options"]; + +eoptions(suite) -> + []; + +eoptions(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Port = ssl_test_lib:inet_port(ServerNode), + + %% Emulated opts + Server0 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{active, trice} | ServerOpts]}]), + Client0 = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, + {options, [{active, trice} | ClientOpts]}]), + ssl_test_lib:check_result(Server0, {error, {eoptions, {active,trice}}}, + Client0, {error, {eoptions, {active,trice}}}), + + test_server:sleep(500), + + Server1 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{header, a} | ServerOpts]}]), + Client1 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{header, a} | ClientOpts]}]), + ssl_test_lib:check_result(Server1, {error, {eoptions, {header, a}}}, + Client1, {error, {eoptions, {header, a}}}), + + test_server:sleep(500), + + + Server2 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{mode, a} | ServerOpts]}]), + + Client2 = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, + {options, [{mode, a} | ClientOpts]}]), + ssl_test_lib:check_result(Server2, {error, {eoptions, {mode, a}}}, + Client2, {error, {eoptions, {mode, a}}}), + + + test_server:sleep(500), + + Server3 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{packet, 8.0} | ServerOpts]}]), + Client3 = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, + {options, [{packet, 8.0} | ClientOpts]}]), + ssl_test_lib:check_result(Server3, {error, {eoptions, {packet, 8.0}}}, + Client3, {error, {eoptions, {packet, 8.0}}}), + + test_server:sleep(500), + + %% ssl + Server4 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{verify, 4} | ServerOpts]}]), + Client4 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{verify, 4} | ClientOpts]}]), + ssl_test_lib:check_result(Server4, {error, {eoptions, {verify, 4}}}, + Client4, {error, {eoptions, {verify, 4}}}), + + test_server:sleep(500), + + Server5 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{depth, four} | ServerOpts]}]), + Client5 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{depth, four} | ClientOpts]}]), + ssl_test_lib:check_result(Server5, {error, {eoptions, {depth, four}}}, + Client5, {error, {eoptions, {depth, four}}}), + + test_server:sleep(500), + + Server6 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{cacertfile, ""} | ServerOpts]}]), + Client6 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{cacertfile, ""} | ClientOpts]}]), + ssl_test_lib:check_result(Server6, {error, {eoptions, {cacertfile, ""}}}, + Client6, {error, {eoptions, {cacertfile, ""}}}), + + + test_server:sleep(500), + + Server7 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{certfile, 'cert.pem'} | ServerOpts]}]), + Client7 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{certfile, 'cert.pem'} | ClientOpts]}]), + ssl_test_lib:check_result(Server7, + {error, {eoptions, {certfile, 'cert.pem'}}}, + Client7, {error, {eoptions, {certfile, 'cert.pem'}}}), + + test_server:sleep(500), + + Server8 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{keyfile,'key.pem' } | ServerOpts]}]), + Client8 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, {options, [{keyfile, 'key.pem'} + | ClientOpts]}]), + ssl_test_lib:check_result(Server8, + {error, {eoptions, {keyfile, 'key.pem'}}}, + Client8, {error, {eoptions, {keyfile, 'key.pem'}}}), + + test_server:sleep(500), + + Server9 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{key, 'key.pem' } | ServerOpts]}]), + Client9 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, {options, [{key, 'key.pem'} + | ClientOpts]}]), + ssl_test_lib:check_result(Server9, {error, {eoptions, {key, 'key.pem'}}}, + Client9, {error, {eoptions, {key, 'key.pem'}}}), + + + test_server:sleep(500), + + Server10 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{password, foo} | ServerOpts]}]), + Client10 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{password, foo} | ClientOpts]}]), + ssl_test_lib:check_result(Server10, {error, {eoptions, {password, foo}}}, + Client10, {error, {eoptions, {password, foo}}}), + + test_server:sleep(500), + + %% Misc + Server11 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{ssl_imp, cool} | ServerOpts]}]), + Client11 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{ssl_imp, cool} | ClientOpts]}]), + ssl_test_lib:check_result(Server11, {error, {eoptions, {ssl_imp, cool}}}, + Client11, {error, {eoptions, {ssl_imp, cool}}}), + + + test_server:sleep(500), + + Server12 = + ssl_test_lib:start_server_error([{node, ServerNode}, {port, Port}, + {from, self()}, + {options, [{debug, cool} | ServerOpts]}]), + Client12 = + ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{debug, cool} | ClientOpts]}]), + ssl_test_lib:check_result(Server12, {error, {eoptions, {debug, cool}}}, + Client12, {error, {eoptions, {debug, cool}}}). + +%%-------------------------------------------------------------------- +shutdown(doc) -> + [""]; + +shutdown(suite) -> + []; + +shutdown(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, 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, 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). + +shutdown_result(Socket, server) -> + ssl:send(Socket, "Hej"), + ssl:shutdown(Socket, write), + {ok, "Hej hopp"} = ssl:recv(Socket, 8), + ok; + +shutdown_result(Socket, client) -> + {ok, "Hej"} = ssl:recv(Socket, 3), + ssl:send(Socket, "Hej hopp"), + ssl:shutdown(Socket, write), + ok. + +%%-------------------------------------------------------------------- +shutdown_write(doc) -> + [""]; + +shutdown_write(suite) -> + []; + +shutdown_write(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, 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, shutdown_write_result, [client]}}, + {options, [{active, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, {error, closed}). + +shutdown_write_result(Socket, server) -> + test_server:sleep(500), + ssl:shutdown(Socket, write); +shutdown_write_result(Socket, client) -> + ssl:recv(Socket, 0). + +%%-------------------------------------------------------------------- +shutdown_both(doc) -> + [""]; + +shutdown_both(suite) -> + []; + +shutdown_both(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, 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, shutdown_both_result, [client]}}, + {options, [{active, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, {error, closed}). + +shutdown_both_result(Socket, server) -> + test_server:sleep(500), + ssl:shutdown(Socket, read_write); +shutdown_both_result(Socket, client) -> + ssl:recv(Socket, 0). + +%%-------------------------------------------------------------------- +shutdown_error(doc) -> + [""]; + +shutdown_error(suite) -> + []; + +shutdown_error(Config) when is_list(Config) -> + ServerOpts = ?config(server_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). + +%%-------------------------------------------------------------------- +ciphers(doc) -> + [""]; + +ciphers(suite) -> + []; + +ciphers(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl:cipher_suites(), + Result = lists:map(fun(Cipher) -> + cipher(Cipher, Version, Config) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + test_server:format("Cipher suite errors: ~p~n", [Error]), + test_server:fail(cipher_suite_failed_see_test_case_log) + end. + +cipher(CipherSuite, Version, Config) -> + process_flag(trap_exit, true), + test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, connection_info_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, connection_info_result, []}}, + {options, + [{ciphers,[CipherSuite]} | + ClientOpts]}]), + + ServerMsg = ClientMsg = {ok, {Version, CipherSuite}}, + + Result = ssl_test_lib:wait_for_result(Server, ServerMsg, + Client, ClientMsg), + ssl_test_lib:close(Server), + receive + {'EXIT', Server, normal} -> + ok + end, + ssl_test_lib:close(Client), + receive + {'EXIT', Client, normal} -> + ok + end, + process_flag(trap_exit, false), + case Result of + ok -> + []; + Error -> + [{CipherSuite, Error}] + end. + +%%-------------------------------------------------------------------- +reuse_session(doc) -> + ["Test reuse of sessions (short handshake)"]; + +reuse_session(suite) -> + []; + +reuse_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, 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, {?MODULE, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + Server ! listen, + + %% Make sure session is registered + test_server:sleep(500), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client1, SessionInfo} -> + ok; + {Client1, Other} -> + test_server:format("Expected: ~p, Unexpected: ~p~n", + [SessionInfo, Other]), + test_server:fail(session_not_reused) + end, + + Server ! listen, + + Client2 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, [{reuse_sessions, false} + | ClientOpts]}]), + receive + {Client2, SessionInfo} -> + test_server:fail( + session_reused_when_session_reuse_disabled_by_client); + {Client2, _} -> + ok + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1), + ssl_test_lib:close(Client2), + + + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, session_info_result, []}}, + {options, [{reuse_sessions, false} | ServerOpts]}]), + + Port1 = ssl_test_lib:inet_port(Server1), + Client3 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port1}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + + SessionInfo1 = + receive + {Server1, Info1} -> + Info1 + end, + + Server1 ! listen, + + %% Make sure session is registered + test_server:sleep(500), + + Client4 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port1}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + + receive + {Client4, SessionInfo1} -> + test_server:fail( + session_reused_when_session_reuse_disabled_by_server); + {Client4, _Other} -> + ok + end, + + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client3), + ssl_test_lib:close(Client4), + process_flag(trap_exit, false). + + +session_info_result(Socket) -> + ssl:session_info(Socket). + +%%-------------------------------------------------------------------- +reuse_session_expired(doc) -> + ["Test sessions is not reused when it has expired"]; + +reuse_session_expired(suite) -> + []; + +reuse_session_expired(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, 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, {?MODULE, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + Server ! listen, + + %% Make sure session is registered + test_server:sleep(500), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client1, SessionInfo} -> + ok; + {Client1, Other} -> + test_server:format("Expected: ~p, Unexpected: ~p~n", + [SessionInfo, Other]), + test_server:fail(session_not_reused) + end, + + Server ! listen, + + %% Make sure session is unregistered due to expiration + test_server:sleep((?EXPIRE+1) * 1000), + + Client2 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client2, SessionInfo} -> + test_server:fail(session_reused_when_session_expired); + {Client2, _} -> + ok + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1), + ssl_test_lib:close(Client2), + process_flag(trap_exit, false). +%%-------------------------------------------------------------------- +server_does_not_want_to_reuse_session(doc) -> + ["Test reuse of sessions (short handshake)"]; + +server_does_not_want_to_reuse_session(suite) -> + []; + +server_does_not_want_to_reuse_session(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, 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, {?MODULE, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + Server ! listen, + + %% Make sure session is registered + test_server:sleep(500), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client1, SessionInfo} -> + test_server:fail(session_reused_when_server_does_not_want_to); + {Client1, _Other} -> + ok + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1), + process_flag(trap_exit, false). + +%%-------------------------------------------------------------------- + +server_verify_peer_passive(doc) -> + ["Test server option verify_peer"]; + +server_verify_peer_passive(suite) -> + []; + +server_verify_peer_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_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, send_recv_result, []}}, + {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, send_recv_result, []}}, + {options, [{active, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +server_verify_peer_active(doc) -> + ["Test server option verify_peer"]; + +server_verify_peer_active(suite) -> + []; + +server_verify_peer_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_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, send_recv_result_active, []}}, + {options, [{active, true}, {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, send_recv_result_active, []}}, + {options, [{active, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +server_verify_peer_active_once(doc) -> + ["Test server option verify_peer"]; + +server_verify_peer_active_once(suite) -> + []; + +server_verify_peer_active_once(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_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, send_recv_result_active_once, []}}, + {options, [{active, once}, {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, send_recv_result_active_once, []}}, + {options, [{active, once} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +server_verify_none_passive(doc) -> + ["Test server option verify_none"]; + +server_verify_none_passive(suite) -> + []; + +server_verify_none_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, send_recv_result, []}}, + {options, [{active, false}, {verify, verify_none} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result, []}}, + {options, [{active, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +server_verify_none_active(doc) -> + ["Test server option verify_none"]; + +server_verify_none_active(suite) -> + []; + +server_verify_none_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, send_recv_result_active, []}}, + {options, [{active, true}, {verify, verify_none} | + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, [{active, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +server_verify_none_active_once(doc) -> + ["Test server option verify_none"]; + +server_verify_none_active_once(suite) -> + []; + +server_verify_none_active_once(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, send_recv_result_active_once, []}}, + {options, [{active, once}, {verify, verify_none} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active_once, []}}, + {options, [{active, once} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- + +server_verify_no_cacerts(doc) -> + ["Test server must have cacerts if it wants to verify client"]; + +server_verify_no_cacerts(suite) -> + []; + +server_verify_no_cacerts(Config) when is_list(Config) -> + ServerOpts = ServerOpts = ?config(server_opts, Config), + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{verify, verify_peer} + | ServerOpts]}]), + + ssl_test_lib:check_result(Server, {error, {eoptions, {cacertfile, ""}}}). + +%%-------------------------------------------------------------------- + +client_verify_none_passive(doc) -> + ["Test client option verify_none"]; + +client_verify_none_passive(suite) -> + []; + +client_verify_none_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, send_recv_result, []}}, + {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, send_recv_result, []}}, + {options, [{active, false}, + {verify, verify_none} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +client_verify_none_active(doc) -> + ["Test client option verify_none"]; + +client_verify_none_active(suite) -> + []; + +client_verify_none_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, + send_recv_result_active, []}}, + {options, [{active, true} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, [{active, true}, + {verify, verify_none} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +client_verify_none_active_once(doc) -> + ["Test client option verify_none"]; + +client_verify_none_active_once(suite) -> + []; + +client_verify_none_active_once(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, send_recv_result_active_once, []}}, + {options, [{active, once} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + %% TODO: send message to test process to make sure + %% verifyfun has beeen run as it has the same behavior as + %% the default fun + VerifyFun = fun([{bad_cert, unknown_ca}]) -> + true; + (_) -> + false + end, + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active_once, + []}}, + {options, [{active, once}, + {verify, verify_none}, + {verify_fun, VerifyFun} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +send_recv_result(Socket) -> + ssl:send(Socket, "Hejhopp"), + test_server:sleep(100), + {ok,"Hejhopp"} = ssl:recv(Socket, 7), + ok. + +send_recv_result_active(Socket) -> + ssl:send(Socket, "Hejhopp"), + test_server:sleep(100), + receive + {ssl, Socket, "Hejhopp"} -> + ok + end. + +send_recv_result_active_once(Socket) -> + ssl:send(Socket, "Hejhopp"), + test_server:sleep(100), + receive + {ssl, Socket, "Hejhopp"} -> + ok + end. + +session_cache_process_list(doc) -> + ["Test reuse of sessions (short handshake)"]; + +session_cache_process_list(suite) -> + []; +session_cache_process_list(Config) when is_list(Config) -> + session_cache_process(list,Config). + +session_cache_process_mnesia(doc) -> + ["Test reuse of sessions (short handshake)"]; + +session_cache_process_mnesia(suite) -> + []; +session_cache_process_mnesia(Config) when is_list(Config) -> + session_cache_process(mnesia,Config). + +session_cache_process(Type,Config) when is_list(Config) -> + process_flag(trap_exit, true), + setup_session_cb(Type), + + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_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, session_info_result, []}}, + {options, + [{session_cache_cb, ?MODULE}| + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client0 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + Server ! listen, + + %% Make sure session is registered + test_server:sleep(500), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client1, SessionInfo} -> + ok; + {Client1, Other} -> + test_server:format("Expected: ~p, Unexpected: ~p~n", + [SessionInfo, Other]), + test_server:fail(session_not_reused) + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1), + + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, session_info_result, []}}, + {options, + [{reuse_sessions, false} | ServerOpts]}]), + Port1 = ssl_test_lib:inet_port(Server1), + + Client3 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port1}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + + SessionInfo1 = + receive + {Server1, Info1} -> + Info1 + end, + + Server1 ! listen, + + %% Make sure session is registered + test_server:sleep(500), + + Client4 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port1}, {host, Hostname}, + {mfa, {?MODULE, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + + receive + {Client4, SessionInfo1} -> + test_server:fail( + session_reused_when_session_reuse_disabled_by_server); + {Client4, _Other} -> + ok + end, + + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client3), + ssl_test_lib:close(Client4), + process_flag(trap_exit, false). + +setup_session_cb(Type) -> + ssl_test = ets:new(ssl_test,[named_table, set,public]), + ets:insert(ssl_test, {type,Type}). + +session_cb() -> + [{type,Type}] = ets:lookup(ssl_test, type), + Type. + +init() -> + io:format("~p~n",[?LINE]), + case session_cb() of + list -> + spawn(fun() -> session_loop([]) end); + mnesia -> + mnesia:start(), + {atomic,ok} = mnesia:create_table(sess_cache, []) + end. + +terminate(Cache) -> + io:format("~p~n",[?LINE]), + case session_cb() of + list -> + Cache ! terminate; + mnesia -> + {atomic,ok} = mnesia:delete_table(sess_cache, []) + end. + +lookup(Cache, Key) -> + io:format("~p~n",[?LINE]), + case session_cb() of + list -> + Cache ! {self(), lookup, Key}, + receive {Cache, Res} -> Res end; + mnesia -> + case mnesia:transaction(fun() -> + mnesia:read(sess_cache, + Key, read) + end) of + {atomic, [Session]} -> Session; + _ -> undefined + end + end. + +update(Cache, Key, Value) -> + io:format("~p~n",[?LINE]), + case session_cb() of + list -> + Cache ! {update, Key, Value}; + mnesia -> + {atomic, ok} = + mnesia:transaction(fun() -> + mnesia:write(sess_cache, + Key, Value) + end) + end. + +delete(Cache, Key) -> + io:format("~p~n",[?LINE]), + case session_cb() of + list -> + Cache ! {delete, Key}; + mnesia -> + {atomic, ok} = + mnesia:transaction(fun() -> + mnesia:delete(sess_cache, Key) + end) + end. + +foldl(Fun, Acc, Cache) -> + io:format("~p~n",[?LINE]), + case session_cb() of + list -> + Cache ! {self(),foldl,Fun,Acc}, + receive {Cache, Res} -> Res end; + mnesia -> + Foldl = fun() -> + mnesia:foldl(Fun, Acc, sess_cache) + end, + {atomic, Res} = mnesia:transaction(Foldl), + Res + end. + +select_session(Cache, PartialKey) -> + io:format("~p~n",[?LINE]), + case session_cb() of + list -> + Cache ! {self(),select_session, PartialKey}, + receive {Cache, Res} -> Res end; + mnesia -> + Sel = fun() -> + mnesia:select(Cache, + [{{{PartialKey,'$1'}, '$2'}, + [],['$$']}]) + end, + {atomic, Res} = mnesia:transaction(Sel), + Res + end. + +session_loop(Sess) -> + receive + terminate -> + ok; + {Pid, lookup, Key} -> + case lists:keysearch(Key,1,Sess) of + {value, {Key,Value}} -> + Pid ! {self(), Value}; + _ -> + Pid ! {self(), undefined} + end, + session_loop(Sess); + {update, Key, Value} -> + session_loop([{Key,Value}|Sess]); + {delete, Key} -> + session_loop(lists:keydelete(Key,1,Sess)); + {Pid,foldl,Fun,Acc} -> + Res = lists:foldl(Fun, Acc,Sess), + Pid ! {self(), Res}, + session_loop(Sess); + {Pid,select_session,PKey} -> + Sel = fun({{Head, _},Session}, Acc) when Head =:= PKey -> + [Session|Acc]; + (_,Acc) -> + Acc + end, + Pid ! {self(), lists:foldl(Sel, [], Sess)}, + session_loop(Sess) + end. + diff --git a/lib/ssl/test/ssl_basic_SUITE_data/RAND b/lib/ssl/test/ssl_basic_SUITE_data/RAND Binary files differnew file mode 100644 index 0000000000..70997bd01f --- /dev/null +++ b/lib/ssl/test/ssl_basic_SUITE_data/RAND diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl new file mode 100644 index 0000000000..c59a5c9256 --- /dev/null +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -0,0 +1,1486 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2010. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_packet_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("test_server.hrl"). + +-define(BYTE(X), X:8/unsigned-big-integer). +-define(UINT16(X), X:16/unsigned-big-integer). +-define(UINT24(X), X:24/unsigned-big-integer). +-define(UINT32(X), X:32/unsigned-big-integer). +-define(UINT64(X), X:64/unsigned-big-integer). +-define(STRING(X), ?UINT32((size(X))), (X)/binary). + +-define(byte(X), << ?BYTE(X) >> ). +-define(uint16(X), << ?UINT16(X) >> ). +-define(uint24(X), << ?UINT24(X) >> ). +-define(uint32(X), << ?UINT32(X) >> ). +-define(uint64(X), << ?UINT64(X) >> ). +-define(TIMEOUT, 120000). + +-define(MANY, 1000). +-define(SOME, 50). + + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + crypto:start(), + ssl:start(), + Result = + (catch make_certs:all(?config(data_dir, Config), + ?config(priv_dir, Config))), + test_server:format("Make certs ~p~n", [Result]), + ssl_test_lib:cert_options(Config). + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ssl:stop(), + crypto:stop(). + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ssl_test_lib:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + Dog = ?config(watchdog, Config), + case Dog of + undefined -> + ok; + _ -> + test_server:timetrap_cancel(Dog) + end. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all(doc) -> + ["Test that erlang:decode_packet/3 seems to be handled correctly." + "We only use the most basic packet types in our tests as testing of" + "the packet types are for inet to verify" + ]; + +all(suite) -> + [packet_raw_passive_many_small, + packet_0_passive_many_small, packet_1_passive_many_small, + packet_2_passive_many_small, packet_4_passive_many_small, + packet_raw_passive_some_big, packet_0_passive_some_big, + packet_1_passive_some_big, + packet_2_passive_some_big, packet_4_passive_some_big, + packet_raw_active_once_many_small, + packet_0_active_once_many_small, packet_1_active_once_many_small, + packet_2_active_once_many_small, packet_4_active_once_many_small, + packet_raw_active_once_some_big, + packet_0_active_once_some_big, packet_1_active_once_some_big, + packet_2_active_once_some_big, packet_4_active_once_some_big, + packet_raw_active_many_small, packet_0_active_many_small, + packet_1_active_many_small, + packet_2_active_many_small, packet_4_active_many_small, + packet_raw_active_some_big, packet_0_active_some_big, + packet_1_active_some_big, packet_2_active_some_big, + packet_4_active_some_big, + packet_wait_passive, packet_wait_active, + packet_baddata_passive, packet_baddata_active, + packet_size_passive, packet_size_active + ]. + +%% Test cases starts here. +%%-------------------------------------------------------------------- +packet_raw_passive_many_small(doc) -> + ["Test packet option {packet, raw} in passive mode."]; + +packet_raw_passive_many_small(suite) -> + []; + +packet_raw_passive_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, raw}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_raw, [Data, ?MANY]}}, + {options, + [{active, false}, + {packet, raw} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +packet_raw_passive_some_big(doc) -> + ["Test packet option {packet, raw} in passive mode."]; + +packet_raw_passive_some_big(suite) -> + []; + +packet_raw_passive_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_raw, [Data, ?SOME]}}, + {options, + [{active, false}, + {packet, raw} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_0_passive_many_small(doc) -> + ["Test packet option {packet, 0} in passive mode."]; + +packet_0_passive_many_small(suite) -> + []; + +packet_0_passive_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 0}, equivalent to packet raw.", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_raw, [Data, ?MANY]}}, + {options, [{active, false}, + {packet, 0} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_0_passive_some_big(doc) -> + ["Test packet option {packet, 0} in passive mode."]; + +packet_0_passive_some_big(suite) -> + []; + +packet_0_passive_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_raw, [Data, ?SOME]}}, + {options, [{active, false}, + {packet, 0} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_1_passive_many_small(doc) -> + ["Test packet option {packet, 1} in passive mode."]; + +packet_1_passive_many_small(suite) -> + []; + +packet_1_passive_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 1}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_1 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [Data, ?MANY]}}, + {options, [{active, false}, + {packet, 1} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_1_passive_some_big(doc) -> + ["Test packet option {packet, 1} in passive mode."]; + +packet_1_passive_some_big(suite) -> + []; + +packet_1_passive_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(255, "1")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_1 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [Data, ?SOME]}}, + {options, [{active, false}, + {packet, 1} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_2_passive_many_small(doc) -> + ["Test packet option {packet, 2} in passive mode"]; + +packet_2_passive_many_small(suite) -> + []; + +packet_2_passive_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 2}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_2 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [Data, ?MANY]}}, + {options, [{active, false}, + {packet, 2} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_2_passive_some_big(doc) -> + ["Test packet option {packet, 2} in passive mode"]; + +packet_2_passive_some_big(suite) -> + []; + +packet_2_passive_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_2 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [Data, ?SOME]}}, + {options, [{active, false}, + {packet, 2} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_4_passive_many_small(doc) -> + ["Test packet option {packet, 4} in passive mode"]; + +packet_4_passive_many_small(suite) -> + []; + +packet_4_passive_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 4}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, send_4 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [Data, ?MANY]}}, + {options, [{active, false}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_4_passive_some_big(doc) -> + ["Test packet option {packet, 4} in passive mode"]; + +packet_4_passive_some_big(suite) -> + []; + +packet_4_passive_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_4 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [Data, ?SOME]}}, + {options, [{active, false}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +packet_raw_active_once_many_small(doc) -> + ["Test packet option {packet, raw} in active once mode."]; + +packet_raw_active_once_many_small(suite) -> + []; + +packet_raw_active_once_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, raw}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, active_once_raw, [Data, ?MANY]}}, + {options, [{active, once}, + {packet, raw} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_raw_active_once_some_big(doc) -> + ["Test packet option {packet, raw} in active once mode."]; + +packet_raw_active_once_some_big(suite) -> + []; + +packet_raw_active_once_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, active_once_raw, [Data, ?SOME]}}, + {options, [{active, once}, + {packet, raw} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_0_active_once_many_small(doc) -> + ["Test packet option {packet, 0} in active once mode."]; + +packet_0_active_once_many_small(suite) -> + []; + +packet_0_active_once_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 0}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, active_once_raw, + [Data, ?MANY]}}, + {options, [{active, once}, + {packet, 0} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +packet_0_active_once_some_big(doc) -> + ["Test packet option {packet, 0} in active once mode."]; + +packet_0_active_once_some_big(suite) -> + []; + +packet_0_active_once_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw , + [Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, active_once_raw, + [Data, ?SOME]}}, + {options, [{active, once}, + {packet, 0} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_1_active_once_many_small(doc) -> + ["Test packet option {packet, 1} in active once mode."]; + +packet_1_active_once_many_small(suite) -> + []; + +packet_1_active_once_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 1}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_1 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_once_packet, + [Data, ?MANY]}}, + {options, [{active, once}, + {packet, 1} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_1_active_once_some_big(doc) -> + ["Test packet option {packet, 1} in active once mode."]; + +packet_1_active_once_some_big(suite) -> + []; + +packet_1_active_once_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(255, "1")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_1 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_once_packet, + [Data, ?SOME]}}, + {options, [{active, once}, + {packet, 1} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_2_active_once_many_small(doc) -> + ["Test packet option {packet, 2} in active once mode"]; + +packet_2_active_once_many_small(suite) -> + []; + +packet_2_active_once_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 2}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_2 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_once_packet, + [Data, ?MANY]}}, + {options, [{active, once}, + {packet, 2} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +packet_2_active_once_some_big(doc) -> + ["Test packet option {packet, 2} in active once mode"]; + +packet_2_active_once_some_big(suite) -> + []; + +packet_2_active_once_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_2 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_once_packet, + [Data, ?SOME]}}, + {options, [{active, once}, + {packet, 2} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_4_active_once_many_small(doc) -> + ["Test packet option {packet, 4} in active once mode"]; + +packet_4_active_once_many_small(suite) -> + []; + +packet_4_active_once_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 4}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_4 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_once_packet, + [Data, ?MANY]}}, + {options, [{active, once}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_4_active_once_some_big(doc) -> + ["Test packet option {packet, 4} in active once mode"]; + +packet_4_active_once_some_big(suite) -> + []; + +packet_4_active_once_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_4 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_once_packet, + [Data, ?SOME]}}, + {options, [{active, once}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_raw_active_many_small(doc) -> + ["Test packet option {packet, raw} in active mode."]; + +packet_raw_active_many_small(suite) -> + []; + +packet_raw_active_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, raw}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, active_raw, + [Data, ?MANY]}}, + {options, [{active, true}, + {packet, raw} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +packet_raw_active_some_big(doc) -> + ["Test packet option {packet, raw} in active mode."]; + +packet_raw_active_some_big(suite) -> + []; + +packet_raw_active_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, active_raw, [Data, ?SOME]}}, + {options, [{active, true}, + {packet, raw} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_0_active_many_small(doc) -> + ["Test packet option {packet, 0} in active mode."]; + +packet_0_active_many_small(suite) -> + []; + +packet_0_active_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 0}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, active_raw, + [Data, ?MANY]}}, + {options, [{active, true}, + {packet, 0} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_0_active_some_big(doc) -> + ["Test packet option {packet, 0} in active mode."]; + +packet_0_active_some_big(suite) -> + []; + +packet_0_active_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_raw ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, active_raw, + [Data, ?SOME]}}, + {options, [{active, true}, + {packet, 0} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +packet_1_active_many_small(doc) -> + ["Test packet option {packet, 1} in active mode."]; + +packet_1_active_many_small(suite) -> + []; + +packet_1_active_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 1}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_1 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_packet, [Data, ?MANY]}}, + {options, [{active, true}, + {packet, 1} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_1_active_some_big(doc) -> + ["Test packet option {packet, 1} in active mode."]; + +packet_1_active_some_big(suite) -> + []; + +packet_1_active_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(255, "1")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_1 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_packet, [Data, ?SOME]}}, + {options, [{active, true}, + {packet, 1} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_2_active_many_small(doc) -> + ["Test packet option {packet, 2} in active mode"]; + +packet_2_active_many_small(suite) -> + []; + +packet_2_active_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 2}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_2 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_packet, [Data, ?MANY]}}, + {options, [{active, true}, + {packet, 2} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_2_active_some_big(doc) -> + ["Test packet option {packet, 2} in active mode"]; + +packet_2_active_some_big(suite) -> + []; + +packet_2_active_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_2 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_packet, [Data, ?SOME]}}, + {options, [{active, true}, + {packet, 2} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_4_active_many_small(doc) -> + ["Test packet option {packet, 4} in active mode"]; + +packet_4_active_many_small(suite) -> + []; + +packet_4_active_many_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "Packet option is {packet, 4}", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_4 ,[Data, ?MANY]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_packet, [Data, ?MANY]}}, + {options, [{active, true}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +packet_4_active_some_big(doc) -> + ["Test packet option {packet, 4} in active mode"]; + +packet_4_active_some_big(suite) -> + []; + +packet_4_active_some_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:append(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_4 ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, + active_packet, [Data, ?SOME]}}, + {options, [{active, true}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + + + +%%-------------------------------------------------------------------- +packet_wait_active(doc) -> + ["Test waiting when complete packages have not arrived"]; + +packet_wait_active(suite) -> + []; + +packet_wait_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = list_to_binary(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_incomplete ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, active_packet, + [binary_to_list(Data), ?SOME]}}, + {options, [{active, true}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +packet_wait_passive(doc) -> + ["Test waiting when complete packages have not arrived"]; + +packet_wait_passive(suite) -> + []; + +packet_wait_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = list_to_binary(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_incomplete ,[Data, ?SOME]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [binary_to_list(Data), ?SOME]}}, + {options, [{active, false}, + {packet, 4} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +packet_baddata_active(doc) -> + ["Test that if a bad packet arrives error msg is sent and socket is closed"]; +packet_baddata_active(suite) -> + []; + +packet_baddata_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = list_to_binary(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_incomplete ,[Data, 1]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, active_packet, [Data, 1]}}, + {options, [{active, true}, + {packet, cdr} | + ClientOpts]}]), + receive + {Client, {other, {ssl_error, _Socket, {invalid_packet, _}},{error,closed},1}} -> ok; + Unexpected -> + test_server:fail({unexpected, Unexpected}) + end, + + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +packet_baddata_passive(doc) -> + ["Test that if a bad packet arrives error msg is sent and socket is closed"]; + +packet_baddata_passive(suite) -> + []; + +packet_baddata_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = list_to_binary(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_incomplete ,[Data, 1]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, + [Data, 1]}}, + {options, [{active, false}, + {packet, cdr} | + ClientOpts]}]), + + receive + {Client, {other, {error, {invalid_packet, _}},{error,closed}, 1}} -> ok; + Unexpected -> + test_server:fail({unexpected, Unexpected}) + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +packet_size_active(doc) -> + ["Test that if a packet of size larger than packet_size arrives error msg is sent and socket is closed"]; +packet_size_active(suite) -> + []; + +packet_size_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = list_to_binary(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_incomplete ,[Data, 1]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, active_packet, [Data, 1]}}, + {options, [{active, true}, + {packet, 4}, {packet_size, 10} | + ClientOpts]}]), + receive + {Client, {other, {ssl_error, _Socket, {invalid_packet, _}},{error,closed},1}} -> ok; + Unexpected -> + test_server:fail({unexpected, Unexpected}) + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +packet_size_passive(doc) -> + ["Test that if a packet of size larger than packet_size arrives error msg is sent and socket is closed"]; +packet_size_passive(suite) -> + []; + +packet_size_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = list_to_binary(lists:duplicate(100, "1234567890")), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_incomplete ,[Data, 1]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, passive_recv_packet, [Data, 1]}}, + {options, [{active, false}, + {packet, 4}, {packet_size, 30} | + ClientOpts]}]), + receive + {Client, {other, {error, {invalid_packet, _}},{error,closed},1}} -> ok; + Unexpected -> + test_server:fail({unexpected, Unexpected}) + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +%% Internal functions + +send_raw(_,_, 0) -> + no_result_msg; +send_raw(Socket, Data, N) -> + ssl:send(Socket, Data), + send_raw(Socket, Data, N-1). + +passive_raw(_, _, 0) -> + ok; +passive_raw(Socket, Data, N) -> + Length = length(Data), + {ok, Data} = ssl:recv(Socket, Length), + passive_raw(Socket, Data, N-1). + +passive_recv_packet(_, _, 0) -> + ok; +passive_recv_packet(Socket, Data, N) -> + case ssl:recv(Socket, 0) of + {ok, Data} -> + passive_recv_packet(Socket, Data, N-1); + Other -> + {other, Other, ssl:session_info(Socket), N} + end. + +send_1(_,_, 0) -> + no_result_msg; +send_1(Socket, Data, N) -> + Length = length(Data), + ssl:send(Socket, [?byte(Length), Data]), + send_1(Socket, Data, N-1). + +send_2(_,_, 0) -> + no_result_msg; +send_2(Socket, Data, N) -> + Length = length(Data), + ssl:send(Socket, [?uint16(Length), Data]), + send_2(Socket, Data, N-1). + +send_4(_,_, 0) -> + no_result_msg; +send_4(Socket, Data, N) -> + Length = length(Data), + ssl:send(Socket, [?uint32(Length), Data]), + send_4(Socket, Data, N-1). + +send_incomplete(Socket, Data, N) -> + send_incomplete(Socket, Data, N, <<>>). +send_incomplete(Socket, _Data, 0, Prev) -> + ssl:send(Socket, Prev), + no_result_msg; +send_incomplete(Socket, Data, N, Prev) -> + Length = size(Data), + <<Part1:42/binary, Rest/binary>> = Data, + ssl:send(Socket, [Prev, ?uint32(Length), Part1]), + send_incomplete(Socket, Data, N-1, Rest). + +active_once_raw(Socket, Data, N) -> + active_once_raw(Socket, Data, N, []). + +active_once_raw(_, _, 0, _) -> + ok; +active_once_raw(Socket, Data, N, Acc) -> + receive + {ssl, Socket, Data} -> + ssl:setopts(Socket, [{active, once}]), + active_once_raw(Socket, Data, N-1, []); + {ssl, Socket, Other} -> + case Acc ++ Other of + Data -> + ssl:setopts(Socket, [{active, once}]), + active_once_raw(Socket, Data, N-1, []); + NewAcc -> + ssl:setopts(Socket, [{active, once}]), + active_once_raw(Socket, Data, N, NewAcc) + end + end. + +active_once_packet(_,_, 0) -> + ok; +active_once_packet(Socket, Data, N) -> + receive + {ssl, Socket, Data} -> + ok + end, + ssl:setopts(Socket, [{active, once}]), + active_once_packet(Socket, Data, N-1). + +active_raw(Socket, Data, N) -> + active_raw(Socket, Data, N, []). + +active_raw(_, _, 0, _) -> + ok; +active_raw(Socket, Data, N, Acc) -> + receive + {ssl, Socket, Data} -> + active_raw(Socket, Data, N-1, []); + {ssl, Socket, Other} -> + case Acc ++ Other of + Data -> + active_raw(Socket, Data, N-1, []); + NewAcc -> + active_raw(Socket, Data, NewAcc) + end + end. + +active_packet(_, _, 0) -> + ok; +active_packet(Socket, Data, N) -> + receive + {ssl, Socket, Data} -> + active_packet(Socket, Data, N -1); + Other -> + {other, Other, ssl:session_info(Socket),N} + end. diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl new file mode 100644 index 0000000000..a0aa92bdf2 --- /dev/null +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -0,0 +1,726 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(ssl_payload_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("test_server.hrl"). + +-define(TIMEOUT, 600000). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + crypto:start(), + ssl:start(), + make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)), + ssl_test_lib:cert_options(Config). + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ssl:stop(), + crypto:stop(). + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ssl_test_lib:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + Dog = ?config(watchdog, Config), + case Dog of + undefined -> + ok; + _ -> + test_server:timetrap_cancel(Dog) + end. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all(doc) -> + ["Test payload over ssl in all socket modes, active, active_once," + "and passive mode."]; + +all(suite) -> + [server_echos_passive_small, server_echos_active_once_small, + server_echos_active_small, + client_echos_passive_small, client_echos_active_once_small, + client_echos_active_small, + server_echos_passive_big, server_echos_active_once_big, + server_echos_active_big, + client_echos_passive_big, client_echos_active_once_big, + client_echos_active_big, + server_echos_passive_huge, server_echos_active_once_huge, + server_echos_active_huge, + client_echos_passive_huge, client_echos_active_once_huge, + client_echos_active_huge + ]. + +%% Test cases starts here. +%%-------------------------------------------------------------------- +server_echos_passive_small(doc) -> + ["Client sends 1000 bytes in passive mode to server, that receives them, " + "sends them back, and closes."]; + +server_echos_passive_small(suite) -> + []; + +server_echos_passive_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_passive(Str, 1000, ClientOpts, ServerOpts, + ClientNode, ServerNode, Hostname). + +%%-------------------------------------------------------------------- + +server_echos_active_once_small(doc) -> + ["Client sends 1000 bytes in active once mode to server, that receives " + " them, sends them back, and closes."]; + +server_echos_active_once_small(suite) -> + []; + +server_echos_active_once_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_active_once(Str, 1000, ClientOpts, ServerOpts, + ClientNode, ServerNode, Hostname). + +%%-------------------------------------------------------------------- + +server_echos_active_small(doc) -> + ["Client sends 1000 bytes in active mode to server, that receives them, " + "sends them back, and closes."]; + +server_echos_active_small(suite) -> + []; + +server_echos_active_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_active(Str, 1000, ClientOpts, ServerOpts, + ClientNode, ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_passive_small(doc) -> + ["Server sends 1000 bytes in passive mode to client, that receives them, " + "sends them back, and closes."]; + +client_echos_passive_small(suite) -> + []; + +client_echos_passive_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + client_echos_passive(Str, 1000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_active_once_small(doc) -> + ["Server sends 1000 bytes in active once mode to client, that receives " + "them, sends them back, and closes."]; + +client_echos_active_once_small(suite) -> + []; + +client_echos_active_once_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + client_echos_active_once(Str, 1000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_active_small(doc) -> + ["Server sends 1000 bytes in active mode to client, that receives them, " + "sends them back, and closes."]; + +client_echos_active_small(suite) -> + []; + +client_echos_active_small(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + client_echos_active(Str, 1000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + + +%%-------------------------------------------------------------------- +server_echos_passive_big(doc) -> + ["Client sends 50000 bytes to server in passive mode, that receives them, " + "sends them back, and closes."]; + +server_echos_passive_big(suite) -> + []; + +server_echos_passive_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_passive(Str, 50000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- + +server_echos_active_once_big(doc) -> + ["Client sends 50000 bytes to server in active once mode, that receives " + "them, sends them back, and closes."]; + +server_echos_active_once_big(suite) -> + []; + +server_echos_active_once_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_active_once(Str, 50000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- + +server_echos_active_big(doc) -> + ["Client sends 50000 bytes to server in active once mode, that receives " + " them, sends them back, and closes."]; + +server_echos_active_big(suite) -> + []; + +server_echos_active_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_active(Str, 50000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_passive_big(doc) -> + ["Server sends 50000 bytes to client in passive mode, that receives them, " + "sends them back, and closes."]; + +client_echos_passive_big(suite) -> + []; + +client_echos_passive_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + client_echos_passive(Str, 50000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_active_once_big(doc) -> + ["Server sends 50000 bytes to client in active once mode, that receives" + " them, sends them back, and closes."]; + +client_echos_active_once_big(suite) -> + []; + +client_echos_active_once_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + client_echos_active_once(Str, 50000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_active_big(doc) -> + ["Server sends 50000 bytes to client in active mode, that receives them, " + "sends them back, and closes."]; + +client_echos_active_big(suite) -> + []; + +client_echos_active_big(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + client_echos_active(Str, 50000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +server_echos_passive_huge(doc) -> + ["Client sends 500000 bytes to server in passive mode, that receives " + " them, sends them back, and closes."]; + +server_echos_passive_huge(suite) -> + []; + +server_echos_passive_huge(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_passive(Str, 500000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +server_echos_active_once_huge(doc) -> + ["Client sends 500000 bytes to server in active once mode, that receives " + "them, sends them back, and closes."]; + +server_echos_active_once_huge(suite) -> + []; + +server_echos_active_once_huge(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_active_once(Str, 500000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +server_echos_active_huge(doc) -> + ["Client sends 500000 bytes to server in active mode, that receives them, " + "sends them back, and closes."]; + +server_echos_active_huge(suite) -> + []; + +server_echos_active_huge(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + + server_echos_active(Str, 500000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_passive_huge(doc) -> + ["Server sends 500000 bytes to client in passive mode, that receives " + "them, sends them back, and closes."]; + +client_echos_passive_huge(suite) -> + []; + +client_echos_passive_huge(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + client_echos_passive(Str, 500000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_active_once_huge(doc) -> + ["Server sends 500000 bytes to client in active once mode, that receives " + "them, sends them back, and closes."]; + +client_echos_active_once_huge(suite) -> + []; + +client_echos_active_once_huge(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + client_echos_active_once(Str, 500000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_echos_active_huge(doc) -> + ["Server sends 500000 bytes to client in active mode, that receives them, " + "sends them back, and closes."]; + +client_echos_active_huge(suite) -> + []; + +client_echos_active_huge(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Str = "1234567890", + client_echos_active(Str, 500000, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname). + +%%-------------------------------------------------------------------- + +server_echos_passive(Data, Length, ClientOpts, ServerOpts, + ClientNode, ServerNode, Hostname) -> + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, echoer, + [Data, Length]}}, + {options, + [{active, false},{mode, binary} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, sender, + [Data, + Length]}}, + {options, + [{active, false}, {mode, binary} | + ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +server_echos_active_once(Data, Length, ClientOpts, ServerOpts, ClientNode, + ServerNode, Hostname) -> + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, echoer_once, + [Data, Length]}}, + {options, [{active, once}, + {mode, binary}| + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, sender_once, + [Data, Length]}}, + {options, [{active, once}, + {mode, binary} | + ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +server_echos_active(Data, Length, ClientOpts, ServerOpts, + ClientNode, ServerNode, Hostname) -> + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, echoer_active, + [Data, Length]}}, + {options, + [{active, true}, + {mode, binary} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, sender_active, + [Data, + Length]}}, + {options, + [{active, true}, {mode, binary} + | ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +client_echos_passive(Data, Length, ClientOpts, ServerOpts, + ClientNode, ServerNode, Hostname) -> + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, sender, + [Data, Length]}}, + {options, + [{active, false}, {mode, binary} | + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, echoer, + [Data, + Length]}}, + {options, + [{active, false}, {mode, binary} + | ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +client_echos_active_once(Data, Length, + ClientOpts, ServerOpts, ClientNode, ServerNode, + Hostname) -> + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, sender_once, + [Data, Length]}}, + {options, [{active, once}, + {mode, binary} | + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, echoer_once, + [Data, + Length]}}, + {options,[{active, once}, + {mode, binary} + | ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +client_echos_active(Data, Length, ClientOpts, ServerOpts, ClientNode, + ServerNode, + Hostname) -> + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, sender_active, + [Data, Length]}}, + {options, [{active, true}, + {mode, binary} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, + {?MODULE, echoer_active, + [Data, + Length]}}, + {options, [{active, true}, + {mode, binary} + | ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +send(_, _, _, 0,_) -> + ok; +send(Socket, Data, Size, Repeate,F) -> + NewData = lists:duplicate(Size div 10, Data), + ssl:send(Socket, NewData), + F(), + send(Socket, Data, Size, Repeate - 1,F). + +sender(Socket, Data, Size) -> + ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end), + test_server:format("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]), + ok. + +sender_once(Socket, Data, Size) -> + send(Socket, Data, Size, 100, + fun() -> do_active_once(Socket, Data, Size, <<>>, false) end), + test_server:format("Sender active once: ~p~n", + [ssl:getopts(Socket, [active])]), + ok. + +sender_active(Socket, Data, Size) -> + F = fun() -> do_active(Socket, Data, Size, <<>>, false) end, + send(Socket, Data, Size, 100, F), + test_server:format("Sender active: ~p~n", [ssl:getopts(Socket, [active])]), + ok. + +echoer(Socket, Data, Size) -> + test_server:format("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]), + echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100). + +echoer_once(Socket, Data, Size) -> + test_server:format("Echoer active once: ~p ~n", + [ssl:getopts(Socket, [active])]), + echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100). + +echoer_active(Socket, Data, Size) -> + test_server:format("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]), + echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100). + +echo(_Fun, 0) -> ok; +echo(Fun, N) -> + Fun(), + echo(Fun, N-1). + + +do_recv(_Socket, _Data, 0, _Acc, true) -> + ok; +do_recv(_Socket, Data, 0, Acc, false) -> + Data = lists:sublist(binary_to_list(Acc), 10); + +do_recv(Socket, Data, Size, Acc, Echo) -> + {ok, NewData} = ssl:recv(Socket, 0), + NewSize = size(NewData), + case Echo of + true -> + ssl:send(Socket, NewData), + NewSize = size(NewData), + do_recv(Socket, Data, Size - NewSize, [], Echo); + false -> + case size(Acc) < 10 of + true -> + do_recv(Socket, Data, Size - NewSize, + <<Acc/binary, NewData/binary>>, Echo); + false -> + do_recv(Socket, Data, Size - NewSize, Acc, Echo) + end + end. + +do_active_once(_Socket, _Data, 0, _Acc, true) -> + ok; +do_active_once(_Socket, Data, 0, Acc, false) -> + Data = lists:sublist(binary_to_list(Acc), 10); + +do_active_once(Socket, Data, Size, Acc, Echo) -> + receive + {ssl, Socket, NewData} -> + NewSize = size(NewData), + case Echo of + true -> + ssl:send(Socket, NewData), + ssl:setopts(Socket, [{active, once}]), + do_active_once(Socket, Data, Size - NewSize, [], Echo); + false -> + case size(Acc) < 10 of + true -> + ssl:setopts(Socket, [{active, once}]), + do_active_once(Socket, Data, Size - NewSize, + <<Acc/binary, NewData/binary>>, + Echo); + false -> + ssl:setopts(Socket, [{active, once}]), + do_active_once(Socket, Data, + Size - NewSize, Acc, Echo) + end + end + end. + +do_active(_Socket, _Data, 0, _Acc, true) -> + ok; +do_active(_Socket, Data, 0, Acc, false) -> + Data = lists:sublist(binary_to_list(Acc), 10); + +do_active(Socket, Data, Size, Acc, Echo) -> + receive + {ssl, Socket, NewData} -> + NewSize = size(NewData), + case Echo of + true -> + ssl:send(Socket, NewData), + do_active(Socket, Data, Size - NewSize, [], Echo); + false -> + case size(Acc) < 10 of + true -> + do_active(Socket, Data, Size - NewSize, + <<Acc/binary, NewData/binary>>, + Echo); + false -> + do_active(Socket, Data, + Size - NewSize, Acc, Echo) + end + end + end. diff --git a/lib/ssl/test/ssl_test_MACHINE.erl b/lib/ssl/test/ssl_test_MACHINE.erl new file mode 100644 index 0000000000..e75f7079ed --- /dev/null +++ b/lib/ssl/test/ssl_test_MACHINE.erl @@ -0,0 +1,935 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_test_MACHINE). + +-export([many_conns/0, mk_ssl_cert_opts/1, test_one_listener/7, + test_server_only/6]). + +-export([process_init/3, do_start/1]). + + +-include("test_server.hrl"). +-include("ssl_test_MACHINE.hrl"). + +-define(WAIT_TIMEOUT, 10000). +-define(CLOSE_WAIT, 1000). + +%% +%% many_conns() -> ManyConnections +%% +%% Choose a suitable number of "many connections" depending on platform +%% and current limit for file descriptors. +%% +many_conns() -> + case os:type() of + {unix,_} -> many_conns_1(); + _ -> 10 + end. + +many_conns_1() -> + N0 = os:cmd("ulimit -n"), + N1 = lists:reverse(N0), + N2 = lists:dropwhile(fun($\r) -> true; + ($\n) -> true; + (_) -> false + end, N1), + N = list_to_integer(lists:reverse(N2)), + lists:min([(N - 10) div 2, 501]). + +%% +%% mk_ssl_cert_opts(Config) -> {ok, {COpts, SOpts}} +%% +%% +mk_ssl_cert_opts(_Config) -> + Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]), + COpts = [{cacertfile, filename:join([Dir, "client", "cacerts.pem"])}, + {certfile, filename:join([Dir, "client", "cert.pem"])}, + {keyfile, filename:join([Dir, "client", "key.pem"])}], + SOpts = [{cacertfile, filename:join([Dir, "server", "cacerts.pem"])}, + {certfile, filename:join([Dir, "server", "cert.pem"])}, + {keyfile, filename:join([Dir, "server", "key.pem"])}], + {ok, {COpts, SOpts}}. + +%% +%% Cmds: +%% {protomod, gen_tcp | ssl} default = ssl +%% {serialize_accept, true | false} default = false +%% {timeout, Timeout} +%% {sockopts, Opts} +%% {sslopts, Opts} +%% {protocols, Protocols} [sslv2|sslv3|tlsv1] +%% {listen, Port} +%% {lsock, LSock} listen socket for acceptor +%% peercert +%% accept +%% {connect, {Host, Port}} +%% {recv, N} +%% {send, N} +%% {echo, N} async echo back +%% close close connection socket +%% {close, Time} wait time and then close socket +%% lclose close listen socket +%% await_close wait for close +%% wait_sync listener's wait for sync from parent +%% connection_info +%% {exit, Reason} exit +%% +%% +%% We cannot have more than `backlog' acceptors at the same time. +%% + + +%% +%% test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, Suite, Config) +%% +%% Creates one client and one server node, and runs one listener on +%% the server node (according to LCmds), and creates NConns acceptors +%% on the server node, and the same number of connectors on the client +%% node. The acceptors and and connectors execute according to ACmds +%% and CCmds, respectively. +%% +%% It is a good idea to have the backlog size in LCmds set to +%% be at least as large as NConns. +%% +test_one_listener(NConns, LCmds0, ACmds0, CCmds0, Timeout, Suite, Config) -> + ProtoMod = get_protomod(Config), + SerializeAccept = get_serialize_accept(Config), + ?line {ok, {CNode, SNode}} = start_client_server_nodes(Suite), + case ProtoMod of + ssl -> + ?line ok = start_ssl([CNode, SNode], Config); + gen_tcp -> + ok + end, + LCmds = [{protomod, ProtoMod}| LCmds0], + ACmds = [{protomod, ProtoMod}, {serialize_accept, SerializeAccept}| + ACmds0], + CCmds = [{protomod, ProtoMod}| CCmds0], + + ?line {ok, Listener} = start_process(SNode, self(), LCmds, listener), + ?line {ok, LSock} = wait_lsock(Listener, ?WAIT_TIMEOUT), + ?line {ok, Accs0} = start_processes(NConns, SNode, self(), + [{lsock, LSock}| ACmds], acceptor), + Accs = case ProtoMod of + gen_tcp -> + [Acc1| Accs1] = Accs0, + Acc1 ! {continue_accept, self()}, + Accs1; + ssl -> + Accs0 + end, + ?line {ok, Conns} = start_processes(NConns, CNode, self(), + CCmds, connector), + ?line case wait_ack(Accs, Accs0 ++ Conns, Timeout) of + ok -> + ?line sync([Listener]), + ?line wait_ack([], [Listener], ?WAIT_TIMEOUT); + {error, Reason} -> + ?line stop_node(SNode), + ?line stop_node(CNode), + exit(Reason) + end, + ?line stop_node(SNode), + ?line stop_node(CNode), + ok. + +%% +%% test_server_only(NConns, LCmds, ACmds, Timeout, Suite, Config) +%% +%% Creates only one server node, and runs one listener on +%% the server node (according to LCmds), and creates NConns acceptors +%% on the server node. The acceptors execute according to ACmds. +%% There are no connectors. +%% +test_server_only(NConns, LCmds0, ACmds0, Timeout, Suite, Config) -> + ProtoMod = get_protomod(Config), + ?line {ok, SNode} = start_server_node(Suite), + case ProtoMod of + ssl -> + ?line ok = start_ssl([SNode], Config); + gen_tcp -> + ok + end, + LCmds = [{protomod, ProtoMod}| LCmds0], + ACmds = [{protomod, ProtoMod}| ACmds0], + ?line {ok, Listener} = start_process(SNode, self(), LCmds, listener), + ?line {ok, LSock} = wait_lsock(Listener, ?WAIT_TIMEOUT), + ?line {ok, Accs0} = start_processes(NConns, SNode, self(), + [{lsock, LSock}| ACmds], acceptor), + Accs = case ProtoMod of + gen_tcp -> + [Acc1| Accs1] = Accs0, + Acc1 ! {continue_accept, self()}, + Accs1; + ssl -> + Accs0 + end, + ?line case wait_ack(Accs, Accs0, Timeout) of + ok -> + ?line sync([Listener]), + ?line wait_ack([], [Listener], ?WAIT_TIMEOUT); + {error, Reason} -> + ?line stop_node(SNode), + exit(Reason) + end, + ?line stop_node(SNode), + ok. + +%% +%% start_client_server_nodes(Suite) -> {ok, {CNode, SNode}} +%% +start_client_server_nodes(Suite) -> + {ok, CNode} = start_client_node(Suite), + {ok, SNode} = start_server_node(Suite), + {ok, {CNode, SNode}}. + +start_client_node(Suite) -> + start_node(lists:concat([Suite, "_client"])). + +start_server_node(Suite) -> + start_node(lists:concat([Suite, "_server"])). + +%% +%% start_ssl(Nodes, Config) +%% +start_ssl(Nodes, Config) -> + Env0 = lists:flatten([Env00 || {env, Env00} <- Config]), + Env1 = case os:getenv("SSL_DEBUG") of + false -> + []; + _ -> + Dir = ?config(priv_dir, Config), + [{debug, true}, {debugdir, Dir}] + end, + Env = Env0 ++ Env1, + lists:foreach( + fun(Node) -> rpc:call(Node, ?MODULE, do_start, [Env]) end, Nodes), + ok. + +do_start(Env) -> + application:load(ssl), + lists:foreach( + fun({Par, Val}) -> application:set_env(ssl, Par, Val) end, Env), + application:start(ssl), + application:start(crypto). + +%% +%% start_node(Name) -> {ok, Node} +%% start_node(Name, ExtraParams) -> {ok, Node} +%% +start_node(Name) -> + start_node(Name, []). +start_node(Name, ExtraParams) -> + Params = "-pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ + ExtraParams, + test_server:start_node(Name, slave, [{args, Params}]). + +stop_node(Node) -> + test_server:stop_node(Node). + +%% +%% start_processes(N, Node, Parent, Cmds, Type) -> {ok, Pids} +%% +start_processes(M, Node, Parent, Cmds, Type) -> + start_processes1(0, M, Node, Parent, Cmds, Type, []). +start_processes1(M, M, _, _, _, _, Pids) -> + {ok, lists:reverse(Pids)}; +start_processes1(N, M, Node, Parent, Cmds, Type, Pids) -> + {ok, Pid} = start_process(Node, Parent, Cmds, {Type, N + 1}), + start_processes1(N + 1, M, Node, Parent, Cmds, Type, [Pid| Pids]). + +%% +%% start_process(Node, Parent, Cmds, Type) -> {ok, Pid} +%% +start_process(Node, Parent, Cmds0, Type) -> + Cmds = case os:type() of + {win32, _} -> + lists:map(fun(close) -> {close, ?CLOSE_WAIT}; + (Term) -> Term end, Cmds0); + _ -> + Cmds0 + end, + Pid = spawn_link(Node, ?MODULE, process_init, [Parent, Cmds, Type]), + {ok, Pid}. + +process_init(Parent, Cmds, Type) -> + ?debug("#### ~w start~n", [{Type, self()}]), + pre_main_loop(Cmds, #st{parent = Parent, type = Type}). + +%% +%% pre_main_loop +%% +pre_main_loop([], St) -> + ?debug("#### ~w end~n", [{St#st.type, self()}]), + main_loop([], St); +pre_main_loop(Cmds, St) -> + ?debug("#### ~w -> ~w~n", + [{St#st.type, self(), St#st.sock, St#st.port, + St#st.peer, St#st.active}, hd(Cmds)]), + main_loop(Cmds, St). + +%% +%% main_loop(Cmds, St) +%% +main_loop([{protomod, ProtoMod}| Cmds], St) -> + pre_main_loop(Cmds, St#st{protomod = ProtoMod}); + +main_loop([{serialize_accept, Bool}| Cmds], St) -> + pre_main_loop(Cmds, St#st{serialize_accept = Bool}); + +main_loop([{sockopts, Opts}| Cmds], St) -> + pre_main_loop(Cmds, St#st{sockopts = Opts}); + +main_loop([{sslopts, Opts}| Cmds], St) -> + pre_main_loop(Cmds, St#st{sslopts = Opts}); + +main_loop([{protocols, Protocols}| Cmds], St) -> + pre_main_loop(Cmds, St#st{protocols = Protocols}); + +main_loop([{timeout, T}| Cmds], St) -> + pre_main_loop(Cmds, St#st{timeout = T}); + +main_loop([{lsock, LSock}| Cmds], St) -> + pre_main_loop(Cmds, St#st{lsock = LSock}); + +main_loop([{seed, Data}| Cmds], St) -> + case ssl:seed("tjosan") of + ok -> + pre_main_loop(Cmds, St); + {error, Reason} -> + ?error("#### ~w(~w) in seed: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([{listen, Port}| Cmds], St) -> + case listen(St, Port) of + {ok, LSock} -> + ack_lsock(St#st.parent, LSock), + NSt = get_active(St#st{port = Port, sock = LSock, lsock = LSock}), + pre_main_loop(Cmds, St); + {error, Reason} -> + ?error("#### ~w(~w) in listen: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([accept| Cmds], St) -> + case St#st.serialize_accept of + true -> + Parent = St#st.parent, + receive + {continue_accept, Parent} -> + ok + end; + false -> + ok + end, + case accept(St) of + {ok, Sock, Port, Peer} -> + case St#st.serialize_accept of + true -> + St#st.parent ! {one_accept_done, self()}; + false -> + ok + end, + NSt = get_active(St#st{sock = Sock, port = Port, peer = Peer}), + pre_main_loop(Cmds, NSt); + {error, Reason} -> + ?error("#### ~w(~w) in accept: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([accept_timeout| Cmds], St) -> + case accept(St) of + {error, timeout} -> + pre_main_loop(Cmds, St); + {error, Reason} -> + ?error("#### ~w(~w) in accept_timeout: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + + +main_loop([{connect, {Host, Port}}| Cmds], St) -> + case connect(St, Host, Port) of + {ok, Sock, LPort, Peer} -> + NSt = get_active(St#st{sock = Sock, port = LPort, peer = Peer}), + pre_main_loop(Cmds, NSt); + {error, Reason} -> + ?error("#### ~w(~w) in connect: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([connection_info| Cmds], St) -> + case connection_info(St) of + {ok, ProtoInfo} -> + io:fwrite("Got connection_info:~n~p~n", [ProtoInfo]), + pre_main_loop(Cmds, St); + {error, Reason} -> + ?error("#### ~w(~w) in connection_info: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([peercert| Cmds], St) -> + case peercert(St) of + {ok, Cert} -> + io:fwrite("Got cert:~n~p~n", [Cert]), + pre_main_loop(Cmds, St); + {error, Reason} -> + ?error("#### ~w(~w) in peercert: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([nopeercert| Cmds], St) -> + case peercert(St) of + {error, Reason} -> + io:fwrite("Got no cert as expected. reason:~n~p~n", [Reason]), + pre_main_loop(Cmds, St); + {ok, Cert} -> + ?error("#### ~w(~w) in peercert: error: got cert: ~p~n", + [St#st.type, self(), Cert]), + exit(peercert) + end; + +main_loop([{recv, N}| Cmds], St) -> + recv_loop([{recv, N}| Cmds], fun recv/1, St); % Returns to main_loop/2. + +main_loop([{send, N}| Cmds], St) -> + Msg = mk_msg(N), + case send(St, Msg) of + ok -> + pre_main_loop(Cmds, St); + {error, Reason} -> + ?error("#### ~w(~w) in send: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([{echo, N}| Cmds], St) -> + recv_loop([{echo, N}| Cmds], fun echo/1, St); % Returns to main_loop/2. + +main_loop([{close, WaitTime}| Cmds], St) -> + wait(WaitTime), + pre_main_loop([close| Cmds], St); + +main_loop([close| Cmds], St) -> + case close(St) of + ok -> + pre_main_loop(Cmds, St#st{sock = nil}); + {error, Reason} -> + ?error("#### ~w(~w) in close: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([lclose| Cmds], St) -> + case lclose(St) of + ok -> + pre_main_loop(Cmds, St#st{lsock = nil}); + {error, Reason} -> + ?error("#### ~w(~w) in lclose: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([await_close| Cmds], St) -> + case await_close(St) of + ok -> + pre_main_loop(Cmds, St#st{sock = nil}); + {error, Reason} -> + ?error("#### ~w(~w) in await_close: error: ~w~n", + [St#st.type, self(), Reason]), + exit(Reason) + end; + +main_loop([wait_sync| Cmds], St) -> + wait_sync(St), + pre_main_loop(Cmds, St); + +main_loop({exit, Reason}, _St) -> + exit(Reason); + +main_loop([], _St) -> + ok. + +%% +%% recv_loop(Cmds, F, St) +%% +%% F = recv/1 | echo/1 +%% +recv_loop([{_Tag, 0}| Cmds], _, St) -> + pre_main_loop(Cmds, St); +recv_loop([{_Tag, N}| _Cmds], _, St) when N < 0 -> + ?error("#### ~w(~w) in recv_loop: error: too much: ~w~n", + [St#st.type, self(), N]), + exit(toomuch); % XXX or {error, Reason}? +recv_loop([{Tag, N}| Cmds], F, St) -> + case F(St) of + {ok, Len} -> + NSt = St#st{active = new_active(St#st.active)}, + if + Len == N -> + pre_main_loop(Cmds, NSt); + true -> + ?debug("#### ~w -> ~w~n", + [{NSt#st.type, self(), NSt#st.sock, NSt#st.port, + NSt#st.peer, NSt#st.active}, {Tag, N - Len}]), + recv_loop([{Tag, N - Len}| Cmds], F, NSt) + end; + {error, Reason} -> + ?error("#### ~w(~w) in recv_loop: error: ~w, ~w bytes remain~n", + [St#st.type, self(), Reason, N]), + exit(Reason) + end. + +new_active(once) -> + false; +new_active(A) -> + A. + +get_active(St) -> + A = case proplists:get_value(active, St#st.sockopts, undefined) of + undefined -> + Mod = case St#st.protomod of + ssl -> + ssl; + gen_tcp -> + inet + end, + {ok, [{active, Ax}]} = Mod:getopts(St#st.sock, [active]), + Ax; + Ay -> + Ay + end, + ?debug("#### ~w(~w) get_active: ~p\n", [St#st.type, self(), A]), + St#st{active = A}. + + +%% +%% SOCKET FUNCTIONS +%% + +%% +%% ssl +%% + +%% +%% listen(St, LPort) -> {ok, LSock} | {error, Reason} +%% +listen(St, LPort) -> + case St#st.protomod of + ssl -> + ssl:listen(LPort, St#st.sockopts ++ St#st.sslopts); + gen_tcp -> + gen_tcp:listen(LPort, St#st.sockopts) + end. + +%% +%% accept(St) -> {ok, Sock} | {error, Reason} +%% +accept(St) -> + case St#st.protomod of + ssl -> + case ssl:transport_accept(St#st.lsock, St#st.timeout) of + {ok, Sock} -> + case ssl:ssl_accept(Sock, St#st.timeout) of + ok -> + {ok, Port} = ssl:sockname(Sock), + {ok, Peer} = ssl:peername(Sock), + {ok, Sock, Port, Peer}; + Other -> + Other + end; + Other -> + Other + end; + gen_tcp -> + case gen_tcp:accept(St#st.lsock, St#st.timeout) of + {ok, Sock} -> + {ok, Port} = inet:port(Sock), + {ok, Peer} = inet:peername(Sock), + {ok, Sock, Port, Peer}; + Other -> + Other + end + end. + +%% +%% connect(St, Host, Port) -> {ok, Sock} | {error, Reason} +%% +connect(St, Host, Port) -> + + case St#st.protomod of + ssl -> + case ssl:connect(Host, Port, St#st.sockopts ++ St#st.sslopts, + St#st.timeout) of + {ok, Sock} -> + {ok, LPort} = ssl:sockname(Sock), + {ok, Peer} = ssl:peername(Sock), + {ok, Sock, LPort, Peer}; + Other -> + Other + end; + gen_tcp -> + case gen_tcp:connect(Host, Port, St#st.sockopts, St#st.timeout) of + {ok, Sock} -> + {ok, LPort} = inet:port(Sock), + {ok, Peer} = inet:peername(Sock), + {ok, Sock, LPort, Peer}; + Other -> + Other + end + end. + +%% +%% peercert(St) -> {ok, Cert} | {error, Reason} +%% +peercert(St) -> + case St#st.protomod of + ssl -> + ssl:peercert(St#st.sock, [ssl]); + gen_tcp -> + {ok, <<>>} + end. + +%% +%% connection_info(St) -> {ok, ProtoInfo} | {error, Reason} +%% +connection_info(St) -> + case St#st.protomod of + ssl -> + case ssl:connection_info(St#st.sock) of + Res = {ok, {Proto, _}} -> + case St#st.protocols of + [] -> + Res; + Protocols -> + case lists:member(Proto, Protocols) of + true -> + Res; + false -> + {error, Proto} + end + end; + Error -> + Error + end; + gen_tcp -> + {ok, <<>>} + end. + +%% +%% close(St) -> ok | {error, Reason} +%% + +close(St) -> + Mod = St#st.protomod, + case St#st.sock of + nil -> + ok; + _ -> + Mod:close(St#st.sock) + end. + +%% +%% lclose(St) -> ok | {error, Reason} +%% +lclose(St) -> + Mod = St#st.protomod, + case St#st.lsock of + nil -> + ok; + _ -> + Mod:close(St#st.lsock) + end. + +%% +%% recv(St) = {ok, Len} | {error, Reason} +%% +recv(St) -> + case do_recv(St) of + {ok, Msg} -> + {ok, length(Msg)}; + {error, Reason} -> + {error, Reason} + end. + +do_recv(St) when St#st.active == false -> + %% First check that we do *not* have any ssl/gen_tcp messages in the + %% message queue, then call the receive function. + Sock = St#st.sock, + case St#st.protomod of + ssl -> + receive + M = {ssl, Sock, _Msg} -> + {error, {unexpected_messagex, M}}; + M = {ssl_closed, Sock} -> + {error, {unexpected_message, M}}; + M = {ssl_error, Sock, _Reason} -> + {error, {unexpected_message, M}} + after 0 -> + ssl:recv(St#st.sock, 0, St#st.timeout) + end; + gen_tcp -> + receive + M = {tcp, Sock, _Msg} -> + {error, {unexpected_message, M}}; + M = {tcp_closed, Sock} -> + {error, {unexpected_message, M}}; + M = {tcp_error, Sock, _Reason} -> + {error, {unexpected_message, M}} + after 0 -> + gen_tcp:recv(St#st.sock, 0, St#st.timeout) + end + end; +do_recv(St) -> + Sock = St#st.sock, + Timeout = St#st.timeout, + case St#st.protomod of + ssl -> + receive + {ssl, Sock, Msg} -> + {ok, Msg}; + {ssl_closed, Sock} -> + {error, closed}; + {ssl_error, Sock, Reason} -> + {error, Reason} + after Timeout -> + {error, timeout} + end; + gen_tcp -> + receive + {tcp, Sock, Msg} -> + {ok, Msg}; + {tcp_closed, Sock} -> + {error, closed}; + {tcp_error, Sock, Reason} -> + {error, Reason} + after Timeout -> + {error, timeout} + end + end. + +%% +%% echo(St) = {ok, Len} | {error, Reason} +%% +echo(St) -> + Sock = St#st.sock, + case do_recv(St) of + {ok, Msg} -> + Mod = St#st.protomod, + case Mod:send(Sock, Msg) of + ok -> + {ok, length(Msg)}; + {error, Reason} -> + {error, Reason} + end; + {error, Reason} -> + {error, Reason} + end. + +%% +%% send(St, Msg) -> ok | {error, Reason} +%% +send(St, Msg) -> + Mod = St#st.protomod, + Mod:send(St#st.sock, Msg). + +%% +%% await_close(St) -> ok | {error, Reason} +%% +await_close(St) when St#st.active == false -> + %% First check that we do *not* have any ssl/gen_tcp messages in the + %% message queue, then call the receive function. + Sock = St#st.sock, + Res = case St#st.protomod of + ssl -> + receive + M = {ssl, Sock, _Msg0} -> + {error, {unexpected_message, M}}; + M = {ssl_closed, Sock} -> + {error, {unexpected_message, M}}; + M = {ssl_error, Sock, _Reason} -> + {error, {unexpected_message, M}} + after 0 -> + ok + end; + gen_tcp -> + receive + M = {tcp, Sock, _Msg0} -> + {error, {unexpected_message, M}}; + M = {tcp_closed, Sock} -> + {error, {unexpected_message, M}}; + M = {tcp_error, Sock, _Reason} -> + {error, {unexpected_message, M}} + after 0 -> + ok + end + end, + case Res of + ok -> + Mod = St#st.protomod, + case Mod:recv(St#st.sock, 0, St#st.timeout) of + {ok, _Msg} -> + {error, toomuch}; + {error, _} -> + ok + end; + _ -> + Res + end; +await_close(St) -> + Sock = St#st.sock, + Timeout = St#st.timeout, + case St#st.protomod of + ssl -> + receive + {ssl, Sock, _Msg} -> + {error, toomuch}; + {ssl_closed, Sock} -> + ok; + {ssl_error, Sock, Reason} -> + {error, Reason} + after Timeout -> + {error, timeout} + end; + gen_tcp -> + receive + {tcp, Sock, _Msg} -> + {error, toomuch}; + {tcp_closed, Sock} -> + ok; + {tcp_error, Sock, Reason} -> + {error, Reason} + after Timeout -> + {error, timeout} + end + end. + + +%% +%% HELP FUNCTIONS +%% + +wait_ack(_, [], _) -> + ok; +wait_ack(AccPids0, Pids, Timeout) -> + ?debug("#### CONTROLLER: waiting for ~w~n", [Pids]), + receive + {one_accept_done, Pid} -> + case lists:delete(Pid, AccPids0) of + [] -> + wait_ack([], Pids, Timeout); + [AccPid| AccPids1] -> + AccPid ! {continue_accept, self()}, + wait_ack(AccPids1, Pids, Timeout) + end; + {'EXIT', Pid, normal} -> + wait_ack(AccPids0, lists:delete(Pid, Pids), Timeout); + {'EXIT', Pid, Reason} -> + ?error("#### CONTROLLER got abnormal exit: ~w, ~w~n", + [Pid, Reason]), + {error, Reason} + after Timeout -> + ?error("#### CONTROLLER exiting because of timeout = ~w~n", + [Timeout]), + {error, Timeout} + end. + + +%% +%% ack_lsock(Pid, LSock) +%% +ack_lsock(Pid, LSock) -> + Pid ! {lsock, self(), LSock}. + +wait_lsock(Pid, Timeout) -> + receive + {lsock, Pid, LSock} -> + {ok, LSock} + after Timeout -> + exit(timeout) + end. + +%% +%% sync(Pids) +%% +sync(Pids) -> + lists:foreach(fun (Pid) -> Pid ! {self(), sync} end, Pids). + +%% +%% wait_sync(St) +%% +wait_sync(St) -> + Pid = St#st.parent, + receive + {Pid, sync} -> + ok + end. + +%% +%% wait(Time) +%% +wait(Time) -> + receive + after Time -> + ok + end. + +%% +%% mk_msg(Size) +%% +mk_msg(Size) -> + mk_msg(0, Size, []). + +mk_msg(_, 0, Acc) -> + Acc; +mk_msg(Pos, Size, Acc) -> + C = (((Pos + Size) rem 256) - 1) band 255, + mk_msg(Pos, Size - 1, [C| Acc]). + +%% +%% get_protomod(Config) +%% +get_protomod(Config) -> + case lists:keysearch(protomod, 1, Config) of + {value, {_, ProtoMod}} -> + ProtoMod; + false -> + ssl + end. + +%% +%% get_serialize_accept(Config) +%% +get_serialize_accept(Config) -> + case lists:keysearch(serialize_accept, 1, Config) of + {value, {_, Val}} -> + Val; + false -> + false + end. + diff --git a/lib/ssl/test/ssl_test_MACHINE.hrl b/lib/ssl/test/ssl_test_MACHINE.hrl new file mode 100644 index 0000000000..e78b33f505 --- /dev/null +++ b/lib/ssl/test/ssl_test_MACHINE.hrl @@ -0,0 +1,39 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2010. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-record(st, {protomod = ssl, + serialize_accept = false, + parent = nil, + type = nil, + active = nil, + port = 0, + peer = nil, + lsock = nil, + sock = nil, + timeout = infinity, + sockopts = [], + sslopts = [], + protocols = []}). + +%%-define(debug(X, Y), io:format(X, Y)). +-define(debug(X, Y), ok). +-define(error(X, Y), io:format(X, Y)). + +-define(DEFAULT_TIMEOUT, 240000). + diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl new file mode 100644 index 0000000000..7ed19b3a05 --- /dev/null +++ b/lib/ssl/test/ssl_test_lib.erl @@ -0,0 +1,408 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_test_lib). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + + +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(), + ServerNode = node(), + {ok, Host} = rpc:call(ServerNode, inet, gethostname, []), + {ClientNode, ServerNode, Host}. + +run_where(_, ipv6) -> + ClientNode = node(), + ServerNode = node(), + {ok, Host} = rpc:call(ServerNode, inet, gethostname, []), + {ClientNode, ServerNode, Host}. + +node_to_hostip(Node) -> + [_ , Host] = string:tokens(atom_to_list(Node), "@"), + {ok, Address} = inet:getaddr(Host, inet), + Address. + +start_server(Args) -> + spawn_link(?MODULE, run_server, [Args]). + +run_server(Opts) -> + Node = proplists:get_value(node, 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]), + case Port of + 0 -> + {ok, {_, NewPort}} = ssl:sockname(ListenSocket), + Pid ! {self(), {port, NewPort}}; + _ -> + ok + end, + run_server(ListenSocket, Opts). + +run_server(ListenSocket, Opts) -> + Node = proplists:get_value(node, Opts), + Pid = proplists:get_value(from, Opts), + test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]), + {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, + [ListenSocket]), + test_server:format("ssl:ssl_accept(~p)~n", [AcceptSocket]), + ok = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]), + {Module, Function, Args} = proplists:get_value(mfa, Opts), + test_server:format("Server: apply(~p,~p,~p)~n", + [Module, Function, [AcceptSocket | Args]]), + case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of + no_result_msg -> + ok; + Msg -> + Pid ! {self(), Msg} + end, + receive + listen -> + run_server(ListenSocket, Opts); + close -> + ok = rpc:call(Node, ssl, close, [AcceptSocket]) + end. + +start_client(Args) -> + spawn_link(?MODULE, run_client, [Args]). + +run_client(Opts) -> + Node = proplists:get_value(node, Opts), + Host = proplists:get_value(host, Opts), + Port = proplists:get_value(port, Opts), + Pid = proplists:get_value(from, Opts), + 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 + {ok, Socket} -> + test_server:format("Client: connected~n", []), + case proplists:get_value(port, Options) of + 0 -> + {ok, {_, NewPort}} = ssl:sockname(Socket), + Pid ! {self(), {port, NewPort}}; + _ -> + ok + end, + {Module, Function, Args} = proplists:get_value(mfa, Opts), + test_server:format("Client: apply(~p,~p,~p)~n", + [Module, Function, [Socket | Args]]), + case rpc:call(Node, Module, Function, [Socket | Args]) of + no_result_msg -> + ok; + Msg -> + Pid ! {self(), Msg} + end, + receive + close -> + ok = rpc:call(Node, ssl, close, [Socket]) + end; + {error, Reason} -> + test_server:format("Client: connection failed: ~p ~n", [Reason]), + Pid ! {self(), {error, Reason}} + end. + +close(Pid) -> + Pid ! close. + +check_result(Server, ServerMsg, Client, ClientMsg) -> + receive + {Server, ServerMsg} -> + receive + {Client, ClientMsg} -> + ok; + Unexpected -> + Reason = {{expected, {Client, ClientMsg}}, + {got, Unexpected}}, + test_server:fail(Reason) + end; + {Client, ClientMsg} -> + receive + {Server, ServerMsg} -> + ok; + Unexpected -> + Reason = {{expected, {Server, ClientMsg}}, + {got, Unexpected}}, + test_server:fail(Reason) + end; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Server, ServerMsg, Client, ClientMsg); + + Unexpected -> + Reason = {{expected, {Client, ClientMsg}}, + {expected, {Server, ServerMsg}}, {got, Unexpected}}, + test_server:fail(Reason) + end. + +check_result(Pid, Msg) -> + receive + {Pid, Msg} -> + ok; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Pid,Msg); + Unexpected -> + Reason = {{expected, {Pid, Msg}}, + {got, Unexpected}}, + test_server:fail(Reason) + end. + +wait_for_result(Server, ServerMsg, Client, ClientMsg) -> + receive + {Server, ServerMsg} -> + receive + {Client, ClientMsg} -> + ok; + Unexpected -> + Unexpected + end; + {Client, ClientMsg} -> + receive + {Server, ServerMsg} -> + ok; + Unexpected -> + Unexpected + end; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + wait_for_result(Server, ServerMsg, Client, ClientMsg); + Unexpected -> + Unexpected + end. + + +wait_for_result(Pid, Msg) -> + receive + {Pid, Msg} -> + ok; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + wait_for_result(Pid,Msg); + Unexpected -> + Unexpected + end. + +cert_options(Config) -> + ClientCaCertFile = filename:join([?config(priv_dir, Config), + "client", "cacerts.pem"]), + ClientCertFile = filename:join([?config(priv_dir, Config), + "client", "cert.pem"]), + ServerCaCertFile = filename:join([?config(priv_dir, Config), + "server", "cacerts.pem"]), + ServerCertFile = filename:join([?config(priv_dir, Config), + "server", "cert.pem"]), + ServerKeyFile = filename:join([?config(priv_dir, Config), + "server", "key.pem"]), + ClientKeyFile = filename:join([?config(priv_dir, Config), + "client", "key.pem"]), + ServerKeyCertFile = filename:join([?config(priv_dir, Config), + "server", "keycert.pem"]), + ClientKeyCertFile = filename:join([?config(priv_dir, Config), + "client", "keycert.pem"]), + + BadCaCertFile = filename:join([?config(priv_dir, Config), + "badcacert.pem"]), + BadCertFile = filename:join([?config(priv_dir, Config), + "badcert.pem"]), + BadKeyFile = filename:join([?config(priv_dir, Config), + "badkey.pem"]), + [{client_opts, [{ssl_imp, new}]}, + {client_verification_opts, [{cacertfile, ClientCaCertFile}, + {certfile, ClientCertFile}, + {keyfile, ClientKeyFile}, + {ssl_imp, new}]}, + {server_opts, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, + {server_verification_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, + {client_kc_opts, [{certfile, ClientKeyCertFile}, {ssl_imp, new}]}, + {server_kc_opts, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerKeyCertFile}]}, + {client_bad_ca, [{cacertfile, BadCaCertFile}, + {certfile, ClientCertFile}, + {keyfile, ClientKeyFile}, + {ssl_imp, new}]}, + {client_bad_cert, [{cacertfile, ClientCaCertFile}, + {certfile, BadCertFile}, + {keyfile, ClientKeyFile}, + {ssl_imp, new}]}, + {server_bad_ca, [{ssl_imp, new},{cacertfile, BadCaCertFile}, + {certfile, ServerCertFile}, + {keyfile, ServerKeyFile}]}, + {server_bad_cert, [{ssl_imp, new},{cacertfile, ServerCaCertFile}, + {certfile, BadCertFile}, {keyfile, ServerKeyFile}]}, + {server_bad_key, [{ssl_imp, new},{cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, BadKeyFile}]} + | Config]. + + +start_upgrade_server(Args) -> + spawn_link(?MODULE, run_upgrade_server, [Args]). + +run_upgrade_server(Opts) -> + Node = proplists:get_value(node, Opts), + Port = proplists:get_value(port, Opts), + TimeOut = proplists:get_value(timeout, Opts, infinity), + TcpOptions = proplists:get_value(tcp_options, 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]), + {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]), + + case Port of + 0 -> + {ok, {_, NewPort}} = inet:sockname(ListenSocket), + Pid ! {self(), {port, NewPort}}; + _ -> + ok + end, + + test_server:format("gen_tcp:accept(~p)~n", [ListenSocket]), + {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), + + {ok, SslAcceptSocket} = case TimeOut of + infinity -> + test_server:format("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", + [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]), + Pid ! {self(), Msg}, + receive + close -> + ok = rpc:call(Node, ssl, close, [SslAcceptSocket]) + end. + +start_upgrade_client(Args) -> + spawn_link(?MODULE, run_upgrade_client, [Args]). + +run_upgrade_client(Opts) -> + Node = proplists:get_value(node, Opts), + Host = proplists:get_value(host, Opts), + Port = proplists:get_value(port, Opts), + Pid = proplists:get_value(from, 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", + [Host, Port, TcpOptions]), + {ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]), + + case proplists:get_value(port, Opts) of + 0 -> + {ok, {_, NewPort}} = inet:sockname(Socket), + Pid ! {self(), {port, NewPort}}; + _ -> + ok + end, + + test_server:format("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", + [Module, Function, [SslSocket | Args]]), + Msg = rpc:call(Node, Module, Function, [SslSocket | Args]), + Pid ! {self(), Msg}, + receive + close -> + ok = rpc:call(Node, ssl, close, [SslSocket]) + end. + +start_server_error(Args) -> + spawn_link(?MODULE, run_server_error, [Args]). + +run_server_error(Opts) -> + Node = proplists:get_value(node, 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} -> + test_server:sleep(2000), %% To make sure error_client will + %% get {error, closed} and not {error, connection_refused} + test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]), + case rpc:call(Node, ssl, transport_accept, [ListenSocket]) of + {error, _} = Error -> + Pid ! {self(), Error}; + {ok, AcceptSocket} -> + test_server:format("ssl:ssl_accept(~p)~n", [AcceptSocket]), + Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]), + Pid ! {self(), Error} + end; + Error -> + Pid ! {self(), Error} + end. + +start_client_error(Args) -> + spawn_link(?MODULE, run_client_error, [Args]). + +run_client_error(Opts) -> + Node = proplists:get_value(node, Opts), + Host = proplists:get_value(host, Opts), + Port = proplists:get_value(port, Opts), + Pid = proplists:get_value(from, Opts), + 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]), + Pid ! {self(), Error}. + +inet_port(Pid) when is_pid(Pid)-> + receive + {Pid, {port, Port}} -> + Port + end; + +inet_port(Node) -> + {Port, Socket} = do_inet_port(Node), + rpc:call(Node, gen_tcp, close, [Socket]), + Port. + +do_inet_port(Node) -> + {ok, Socket} = rpc:call(Node, gen_tcp, listen, [0, [{reuseaddr, true}]]), + {ok, Port} = rpc:call(Node, inet, port, [Socket]), + {Port, Socket}. + +no_result(_) -> + no_result_msg. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl new file mode 100644 index 0000000000..c079e12b83 --- /dev/null +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -0,0 +1,772 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssl_to_openssl_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). +-include("ssl_pkix.hrl"). + +-define(TIMEOUT, 120000). +-define(SLEEP, 1000). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + crypto:start(), + ssl:start(), + Result = + (catch make_certs:all(?config(data_dir, Config), + ?config(priv_dir, Config))), + test_server:format("Make certs ~p~n", [Result]), + ssl_test_lib:cert_options(Config) + end. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ssl:stop(), + crypto:stop(). + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ssl_test_lib:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + Dog = ?config(watchdog, Config), + case Dog of + undefined -> + ok; + _ -> + test_server:timetrap_cancel(Dog) + end. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all(doc) -> + ["Test erlangs ssl against openssl"]; + +all(suite) -> + [erlang_client_openssl_server, + erlang_server_openssl_client, + ssl3_erlang_client_openssl_server, + ssl3_erlang_server_openssl_client, + ssl3_erlang_client_openssl_server_client_cert, + ssl3_erlang_server_openssl_client_client_cert, + ssl3_erlang_server_erlang_client_client_cert, + tls1_erlang_client_openssl_server, + tls1_erlang_server_openssl_client, + tls1_erlang_client_openssl_server_client_cert, + tls1_erlang_server_openssl_client_client_cert, + tls1_erlang_server_erlang_client_client_cert, + ciphers + ]. + +%% Test cases starts here. +%%-------------------------------------------------------------------- + +erlang_client_openssl_server(doc) -> + ["Test erlang client with openssl server"]; +erlang_client_openssl_server(suite) -> + []; +erlang_client_openssl_server(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + " -cert " ++ CertFile ++ " -key " ++ KeyFile, + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, ClientOpts}]), + port_command(OpensslPort, Data), + + ssl_test_lib:check_result(Client, ok), + + %% Clean close down! Server needs to be closed first !! + close_port(OpensslPort), + + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. + + +%%-------------------------------------------------------------------- +erlang_server_openssl_client(doc) -> + ["Test erlang server with openssl client"]; +erlang_server_openssl_client(suite) -> + []; +erlang_server_openssl_client(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + test_server:sleep(?SLEEP), + + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + " -host localhost", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, ok), + + ssl_test_lib:close(Server), + + close_port(OpenSslPort), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- +ssl3_erlang_client_openssl_server(doc) -> + ["Test erlang client with openssl server"]; +ssl3_erlang_client_openssl_server(suite) -> + []; +ssl3_erlang_client_openssl_server(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -ssl3", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + connection_info, [sslv3]}}, + {options, + [{versions, [sslv3]} | ClientOpts]}]), + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Client), + %% Clean close down! + close_port(OpensslPort), + test_server:sleep(?SLEEP), + ok. + +%%-------------------------------------------------------------------- + +ssl3_erlang_server_openssl_client(doc) -> + ["Test erlang server with openssl client"]; +ssl3_erlang_server_openssl_client(suite) -> + []; +ssl3_erlang_server_openssl_client(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, connection_info, [sslv3]}}, + {options, + [{versions, [sslv3]} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + test_server:sleep(?SLEEP), + + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + " -host localhost -ssl3", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + ssl_test_lib:check_result(Server, ok), + + close_port(OpenSslPort), %% openssl server first + ssl_test_lib:close(Server), + test_server:sleep(?SLEEP), + ok. + +%%-------------------------------------------------------------------- +ssl3_erlang_client_openssl_server_client_cert(doc) -> + ["Test erlang client with openssl server when client sends cert"]; +ssl3_erlang_client_openssl_server_client_cert(suite) -> + []; +ssl3_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_verification_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile + ++ " -key " ++ KeyFile ++ " -Verify 2 -ssl3", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, ClientOpts}]), + port_command(OpensslPort, Data), + + ssl_test_lib:check_result(Client, ok), + + %% Clean close down! + close_port(OpensslPort), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- + +ssl3_erlang_server_openssl_client_client_cert(doc) -> + ["Test erlang server with openssl client when client sends cert"]; +ssl3_erlang_server_openssl_client_client_cert(suite) -> + []; +ssl3_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_verification_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, + [{verify , verify_peer} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + test_server:sleep(?SLEEP), + + CaCertFile = proplists:get_value(cacertfile, ClientOpts), + CertFile = proplists:get_value(certfile, ClientOpts), + KeyFile = proplists:get_value(keyfile, ClientOpts), + + Cmd = "openssl s_client -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile + ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ + " -host localhost -ssl3", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, ok), + + close_port(OpenSslPort), %% openssl server first + ssl_test_lib:close(Server), + %% Clean close down! + process_flag(trap_exit, false), + ok. + + +%%-------------------------------------------------------------------- + +ssl3_erlang_server_erlang_client_client_cert(doc) -> + ["Test erlang server with erlang client when client sends cert"]; +ssl3_erlang_server_erlang_client_client_cert(suite) -> + []; +ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_verification_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, + [{verify , verify_peer} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl, send, [Data]}}, + {options, + [{versions, [sslv3]} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- + +tls1_erlang_client_openssl_server(doc) -> + ["Test erlang client with openssl server"]; +tls1_erlang_client_openssl_server(suite) -> + []; +tls1_erlang_client_openssl_server(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + + test_server:format("Server Opts", [ServerOpts]), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + " -cert " ++ CertFile + ++ " -key " ++ KeyFile ++ " -tls1", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + connection_info, [tlsv1]}}, + {options, + [{versions, [tlsv1]} | ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Client), + %% Clean close down! + close_port(OpensslPort), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- + +tls1_erlang_server_openssl_client(doc) -> + ["Test erlang server with openssl client"]; +tls1_erlang_server_openssl_client(suite) -> + []; +tls1_erlang_server_openssl_client(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, + {?MODULE, connection_info, [tlsv1]}}, + {options, + [{versions, [tlsv1]} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + test_server:sleep(?SLEEP), + + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + " -host localhost -tls1", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + ssl_test_lib:check_result(Server, ok), + + %% Clean close down! + close_port(OpenSslPort), + ssl_test_lib:close(Server), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- + +tls1_erlang_client_openssl_server_client_cert(doc) -> + ["Test erlang client with openssl server when client sends cert"]; +tls1_erlang_client_openssl_server_client_cert(suite) -> + []; +tls1_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_verification_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile + ++ " -key " ++ KeyFile ++ " -Verify 2 -tls1", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, ClientOpts}]), + port_command(OpensslPort, Data), + + ssl_test_lib:check_result(Client, ok), + + %% Clean close down! + close_port(OpensslPort), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- + +tls1_erlang_server_openssl_client_client_cert(doc) -> + ["Test erlang server with openssl client when client sends cert"]; +tls1_erlang_server_openssl_client_client_cert(suite) -> + []; +tls1_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_verification_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, + [{verify , verify_peer} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + test_server:sleep(?SLEEP), + + CaCertFile = proplists:get_value(cacertfile, ClientOpts), + CertFile = proplists:get_value(certfile, ClientOpts), + KeyFile = proplists:get_value(keyfile, ClientOpts), + + Cmd = "openssl s_client -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile + ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ + " -host localhost -tls1", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, ok), + + %% Clean close down! + close_port(OpenSslPort), + ssl_test_lib:close(Server), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- +tls1_erlang_server_erlang_client_client_cert(doc) -> + ["Test erlang server with erlang client when client sends cert"]; +tls1_erlang_server_erlang_client_client_cert(suite) -> + []; +tls1_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_verification_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + erlang_ssl_receive, [Data]}}, + {options, + [{verify , verify_peer} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl, send, [Data]}}, + {options, + [{versions, [tlsv1]} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + %% Clean close down! + process_flag(trap_exit, false), + ok. +%%-------------------------------------------------------------------- + +ciphers(doc) -> + [""]; + +ciphers(suite) -> + []; + +ciphers(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl:cipher_suites(), + Result = lists:map(fun(Cipher) -> + cipher(Cipher, Version, Config) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + test_server:format("Cipher suite errors: ~p~n", [Error]), + test_server:fail(cipher_suite_failed_see_test_case_log) + end. + +cipher(CipherSuite, Version, Config) -> + process_flag(trap_exit, true), + test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + " -cert " ++ CertFile + ++ " -key " ++ KeyFile ++ "", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + test_server:sleep(?SLEEP), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, connection_info_result, []}}, + {options, + [{ciphers,[CipherSuite]} | + ClientOpts]}]), + + ClientMsg = {ok, {Version, CipherSuite}}, + + Result = ssl_test_lib:wait_for_result(Client, ClientMsg), + + close_port(OpenSslPort), + %% Clean close down! + ssl_test_lib:close(Client), + receive + {'EXIT', Client, normal} -> + ok + end, + + Return = case Result of + ok -> + []; + Error -> + [{CipherSuite, Error}] + end, + process_flag(trap_exit, false), + Return. + +%%-------------------------------------------------------------------- + +erlang_ssl_receive(Socket, Data) -> + test_server:format("Connection info: ~p~n", + [ssl:connection_info(Socket)]), + receive + {ssl, Socket, Data} -> + io:format("Received ~p~n",[Data]), + %% open_ssl server sometimes hangs waiting in blocking read + ssl:send(Socket, "Got it"), + ok; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + erlang_ssl_receive(Socket,Data); + Other -> + test_server:fail({unexpected_message, Other}) + after 4000 -> + test_server:fail({did_not_get, Data}) + end. + +connection_info(Socket, Version) -> + case ssl:connection_info(Socket) of + {ok, {Version, _} = Info} -> + test_server:format("Connection info: ~p~n", [Info]), + ok; + {ok, {OtherVersion, _}} -> + {wrong_version, OtherVersion} + end. + +connection_info_result(Socket) -> + ssl:connection_info(Socket). + +close_port(Port) -> + port_command(Port, "Q\n"), + %%catch port_command(Port, "quit\n"), + close_loop(Port, 500, false). + +close_loop(Port, Time, SentClose) -> + receive + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + close_loop(Port, Time, SentClose); + {ssl,_,Msg} -> + io:format("ssl Msg ~s~n",[Msg]), + close_loop(Port, Time, SentClose); + {Port, closed} -> + io:format("Port Closed~n",[]), + ok; + {'EXIT', Port, Reason} -> + io:format("Port Closed ~p~n",[Reason]), + ok; + Msg -> + io:format("Port Msg ~p~n",[Msg]), + close_loop(Port, Time, SentClose) + after Time -> + case SentClose of + false -> + io:format("Closing port ~n",[]), + catch erlang:port_close(Port), + close_loop(Port, Time, true); + true -> + io:format("Timeout~n",[]) + end + end. |