aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/test')
-rw-r--r--lib/ssl/test/Makefile36
-rw-r--r--lib/ssl/test/inet_crypto_dist.erl1541
-rw-r--r--lib/ssl/test/make_certs.erl6
-rw-r--r--lib/ssl/test/openssl_alpn_SUITE.erl421
-rw-r--r--lib/ssl/test/openssl_cipher_suite_SUITE.erl801
-rw-r--r--lib/ssl/test/openssl_client_cert_SUITE.erl350
-rw-r--r--lib/ssl/test/openssl_npn_SUITE.erl311
-rw-r--r--lib/ssl/test/openssl_reject_SUITE.erl209
-rw-r--r--lib/ssl/test/openssl_renegotiate_SUITE.erl341
-rw-r--r--lib/ssl/test/openssl_server_cert_SUITE.erl373
-rw-r--r--lib/ssl/test/openssl_session_SUITE.erl262
-rw-r--r--lib/ssl/test/openssl_sni_SUITE.erl251
-rw-r--r--lib/ssl/test/openssl_tls_1_3_version_SUITE.erl172
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_cipher_format.erl96
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_handshake.erl883
-rw-r--r--lib/ssl/test/ssl.spec16
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl59
-rw-r--r--lib/ssl/test/ssl_ECC_openssl_SUITE.erl99
-rw-r--r--lib/ssl/test/ssl_alert_SUITE.erl100
-rw-r--r--lib/ssl/test/ssl_alpn_SUITE.erl (renamed from lib/ssl/test/ssl_alpn_handshake_SUITE.erl)28
-rw-r--r--lib/ssl/test/ssl_api_SUITE.erl1976
-rw-r--r--lib/ssl/test/ssl_api_SUITE_data/dHParam.pem (renamed from lib/ssl/test/ssl_basic_SUITE_data/dHParam.pem)0
-rw-r--r--lib/ssl/test/ssl_app_env_SUITE.erl171
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl5058
-rw-r--r--lib/ssl/test/ssl_bench.spec1
-rw-r--r--lib/ssl/test/ssl_bench_SUITE.erl72
-rw-r--r--lib/ssl/test/ssl_cert_SUITE.erl563
-rw-r--r--lib/ssl/test/ssl_cert_tests.erl386
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl597
-rw-r--r--lib/ssl/test/ssl_cipher_suite_SUITE.erl777
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_dist_bench_SUITE.erl177
-rw-r--r--lib/ssl/test/ssl_dist_test_lib.erl5
-rw-r--r--lib/ssl/test/ssl_eqc_SUITE.erl70
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl132
-rw-r--r--lib/ssl/test/ssl_npn_SUITE.erl (renamed from lib/ssl/test/ssl_npn_handshake_SUITE.erl)2
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl51
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl157
-rw-r--r--lib/ssl/test/ssl_pem_cache_SUITE.erl55
-rw-r--r--lib/ssl/test/ssl_renegotiate_SUITE.erl499
-rw-r--r--lib/ssl/test/ssl_rfc_5869_SUITE.erl316
-rw-r--r--lib/ssl/test/ssl_session_SUITE.erl377
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl68
-rw-r--r--lib/ssl/test/ssl_socket_SUITE.erl437
-rw-r--r--lib/ssl/test/ssl_test_lib.erl833
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl2116
-rw-r--r--lib/ssl/test/ssl_upgrade_SUITE.erl13
-rw-r--r--lib/ssl/test/tls_1_3_record_SUITE.erl973
-rw-r--r--lib/ssl/test/tls_1_3_version_SUITE.erl153
-rw-r--r--lib/ssl/test/tls_api_SUITE.erl880
-rw-r--r--lib/ssl/test/x509_test.erl2
52 files changed, 15129 insertions, 8149 deletions
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index a10f71a3de..0925c0facc 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -37,12 +37,29 @@ VSN=$(SSL_VSN)
MODULES = \
ssl_test_lib \
+ ssl_app_env_SUITE\
+ ssl_alert_SUITE\
ssl_bench_test_lib \
ssl_dist_test_lib \
- ssl_alpn_handshake_SUITE \
+ ssl_api_SUITE\
+ tls_api_SUITE\
ssl_basic_SUITE \
ssl_bench_SUITE \
ssl_cipher_SUITE \
+ ssl_cipher_suite_SUITE \
+ openssl_cipher_suite_SUITE\
+ ssl_alpn_SUITE \
+ openssl_alpn_SUITE\
+ ssl_npn_SUITE \
+ openssl_npn_SUITE\
+ openssl_sni_SUITE\
+ ssl_renegotiate_SUITE\
+ openssl_renegotiate_SUITE\
+ openssl_reject_SUITE\
+ ssl_cert_tests\
+ ssl_cert_SUITE\
+ openssl_server_cert_SUITE\
+ openssl_client_cert_SUITE\
ssl_certificate_verify_SUITE\
ssl_crl_SUITE\
ssl_dist_SUITE \
@@ -50,19 +67,26 @@ MODULES = \
ssl_engine_SUITE\
ssl_handshake_SUITE \
ssl_npn_hello_SUITE \
- ssl_npn_handshake_SUITE \
ssl_packet_SUITE \
ssl_payload_SUITE \
ssl_pem_cache_SUITE \
+ ssl_session_SUITE \
ssl_session_cache_SUITE \
- ssl_to_openssl_SUITE \
+ openssl_session_SUITE \
ssl_ECC_SUITE \
ssl_ECC_openssl_SUITE \
ssl_ECC\
ssl_upgrade_SUITE\
ssl_sni_SUITE \
- make_certs\
- x509_test
+ ssl_eqc_SUITE \
+ ssl_rfc_5869_SUITE \
+ tls_1_3_record_SUITE\
+ openssl_tls_1_3_version_SUITE\
+ tls_1_3_version_SUITE\
+ ssl_socket_SUITE\
+ make_certs \
+ x509_test \
+ inet_crypto_dist
ERL_FILES = $(MODULES:%=%.erl)
@@ -144,7 +168,7 @@ release_tests_spec: opt
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(HRL_FILES_NEEDED_IN_TEST) $(COVER_FILE) "$(RELSYSDIR)"
$(INSTALL_DATA) ssl.spec ssl_bench.spec ssl.cover "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/ssl/test/inet_crypto_dist.erl b/lib/ssl/test/inet_crypto_dist.erl
new file mode 100644
index 0000000000..63c19d9438
--- /dev/null
+++ b/lib/ssl/test/inet_crypto_dist.erl
@@ -0,0 +1,1541 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% -------------------------------------------------------------------------
+%%
+%% Module for encrypted Erlang protocol - a minimal encrypted
+%% distribution protocol based on only a shared secret
+%% and the crypto application
+%%
+-module(inet_crypto_dist).
+-define(DIST_NAME, inet_crypto).
+-define(DIST_PROTO, crypto).
+-define(DRIVER, inet_tcp).
+-define(FAMILY, inet).
+
+-export([listen/1, accept/1, accept_connection/5,
+ setup/5, close/1, select/1, is_node_name/1]).
+
+%% Generalized dist API, for sibling IPv6 module inet6_crypto_dist
+-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
+ gen_setup/6, gen_close/2, gen_select/2]).
+
+-export([nodelay/0]).
+
+%% Debug
+%%%-compile(export_all).
+-export([dbg/0, test_server/0, test_client/1]).
+
+-include_lib("kernel/include/net_address.hrl").
+-include_lib("kernel/include/dist.hrl").
+-include_lib("kernel/include/dist_util.hrl").
+
+-define(PACKET_SIZE, 65536).
+-define(BUFFER_SIZE, (?PACKET_SIZE bsl 4)).
+
+%% -------------------------------------------------------------------------
+
+-record(params,
+ {socket,
+ dist_handle,
+ hmac_algorithm = sha256,
+ aead_cipher = aes_gcm,
+ rekey_key,
+ iv = 12,
+ key = 16,
+ tag_len = 16,
+ rekey_interval = 262144
+ }).
+
+params(Socket) ->
+ #params{socket = Socket}.
+
+
+-record(key_pair,
+ {type = ecdh,
+ %% The curve choice greatly affects setup time,
+ %% we really want an Edwards curve but that would
+ %% require a very new openssl version.
+ %% Twisted brainpool curves (*t1) are faster than
+ %% non-twisted (*r1), 256 is much faster than 384,
+ %% and so on...
+%%% params = brainpoolP384t1,
+ params = brainpoolP256t1,
+ public,
+ private}).
+
+-define(KEY_PAIR_LIFE_TIME, 3600000). % 1 hour
+-define(KEY_PAIR_LIFE_COUNT, 256). % Number of connection setups
+
+
+%% -------------------------------------------------------------------------
+%% Keep the node's public/private key pair in the process state
+%% of a key pair server linked to the acceptor process.
+%% Create the key pair the first time it is needed
+%% so crypto gets time to start first.
+%%
+
+start_key_pair_server() ->
+ monitor_dist_proc(
+ spawn_link(
+ fun () ->
+ register(?MODULE, self()),
+ key_pair_server()
+ end)).
+
+key_pair_server() ->
+ key_pair_server(undefined, undefined, undefined).
+%%
+key_pair_server(KeyPair) ->
+ key_pair_server(
+ KeyPair,
+ erlang:start_timer(?KEY_PAIR_LIFE_TIME, self(), discard),
+ ?KEY_PAIR_LIFE_COUNT).
+%%
+key_pair_server(_KeyPair, Timer, 0) ->
+ cancel_timer(Timer),
+ key_pair_server();
+key_pair_server(KeyPair, Timer, Count) ->
+ receive
+ {Pid, Tag, get_key_pair} ->
+ case KeyPair of
+ undefined ->
+ KeyPair_1 = generate_key_pair(),
+ Pid ! {Tag, KeyPair_1},
+ key_pair_server(KeyPair_1);
+ #key_pair{} ->
+ Pid ! {Tag, KeyPair},
+ key_pair_server(KeyPair, Timer, Count - 1)
+ end;
+ {Pid, Tag, get_new_key_pair} ->
+ cancel_timer(Timer),
+ KeyPair_1 = generate_key_pair(),
+ Pid ! {Tag, KeyPair_1},
+ key_pair_server(KeyPair_1);
+ {timeout, Timer, discard} when is_reference(Timer) ->
+ key_pair_server()
+ end.
+
+generate_key_pair() ->
+ #key_pair{type = Type, params = Params} = #key_pair{},
+ {Public, Private} =
+ crypto:generate_key(Type, Params),
+ #key_pair{public = Public, private = Private}.
+
+cancel_timer(undefined) ->
+ ok;
+cancel_timer(Timer) ->
+ case erlang:cancel_timer(Timer) of
+ false ->
+ receive
+ {timeout, Timer, _} -> ok
+ end;
+ _RemainingTime ->
+ ok
+ end.
+
+get_key_pair() ->
+ call_key_pair_server(get_key_pair).
+
+get_new_key_pair() ->
+ call_key_pair_server(get_new_key_pair).
+
+call_key_pair_server(Request) ->
+ Pid = whereis(?MODULE),
+ Ref = erlang:monitor(process, Pid),
+ Pid ! {self(), Ref, Request},
+ receive
+ {Ref, Reply} ->
+ erlang:demonitor(Ref, [flush]),
+ Reply;
+ {'DOWN', Ref, process, Pid, Reason} ->
+ error(Reason)
+ end.
+
+compute_shared_secret(
+ #key_pair{
+ type = PublicKeyType,
+ params = PublicKeyParams,
+ private = PrivKey}, PubKey) ->
+ %%
+ crypto:compute_key(PublicKeyType, PubKey, PrivKey, PublicKeyParams).
+
+%% -------------------------------------------------------------------------
+%% Erlang distribution plugin structure explained to myself
+%% -------
+%% These are the processes involved in the distribution:
+%% * net_kernel
+%% * The Acceptor
+%% * The Controller | Handshaker | Ticker
+%% * The DistCtrl process that may be split into:
+%% + The Output controller
+%% + The Input controller
+%% For the regular inet_tcp_dist distribution module, DistCtrl
+%% is not one or two processes, but one port - a gen_tcp socket
+%%
+%% When the VM is started with the argument "-proto_dist inet_crypto"
+%% net_kernel registers the module inet_crypto_dist acli,oams distribution
+%% module. net_kernel calls listen/1 to create a listen socket
+%% and then accept/1 with the listen socket as argument to spawn
+%% the Acceptor process, which is linked to net_kernel. Apparently
+%% the listen socket is owned by net_kernel - I wonder if it could
+%% be owned by the Acceptor process instead...
+%%
+%% The Acceptor process calls blocking accept on the listen socket
+%% and when an incoming socket is returned it spawns the DistCtrl
+%% process a linked to the Acceptor. The ownership of the accepted
+%% socket is transferred to the DistCtrl process.
+%% A message is sent to net_kernel to inform it that an incoming
+%% connection has appeared and the Acceptor awaits a reply from net_kernel.
+%%
+%% net_kernel then calls accept_connection/5 to spawn the Controller |
+%% Handshaker | Ticker process that is linked to net_kernel.
+%% The Controller then awaits a message from the Acceptor process.
+%%
+%% When net_kernel has spawned the Controller it replies with a message
+%% to the Acceptor that then calls DistCtrl to changes its links
+%% so DistCtrl ends up linked to the Controller and not to the Acceptor.
+%% The Acceptor then sends a message to the Controller. The Controller
+%% then changes role into the Handshaker creates a #hs_data{} record
+%% and calls dist_util:handshake_other_started/1. After this
+%% the Acceptor goes back into a blocking accept on the listen socket.
+%%
+%% For the regular distribution inet_tcp_dist DistCtrl is a gen_tcp socket
+%% and when it is a process it also acts as a socket. The #hs_data{}
+%% record used by dist_util presents a set of funs that are used
+%% by dist_util to perform the distribution handshake. These funs
+%% make sure to transfer the handshake messages through the DistCtrl
+%% "socket".
+%%
+%% When the handshake is finished a fun for this purpose in #hs_data{}
+%% is called, which tells DistCtrl that it does not need to be prepared
+%% for any more #hs_data{} handshake calls. The DistCtrl process in this
+%% module then spawns the Input controller process that gets ownership
+%% of the connection's gen_tcp socket and changes into {active, N} mode
+%% so now it gets all incoming traffic and delivers that to the VM.
+%% The original DistCtrl process changes role into the Output controller
+%% process and starts asking the VM for outbound messages and transfers
+%% them on the connection socket.
+%%
+%% The Handshaker now changes into the Ticker role, and uses only two
+%% functions in the #hs_data{} record; one to get socket statistics
+%% and one to send a tick. None of these may block for any reason
+%% in particular not for a congested socket since that would destroy
+%% connection supervision.
+%%
+%%
+%% For an connection net_kernel calls setup/5 which spawns the
+%% Controller process as linked to net_kernel. This Controller process
+%% connects to the other node's listen socket and when that is succesful
+%% spawns the DistCtrl process as linked to the controller and transfers
+%% socket ownership to it.
+%%
+%% Then the Controller creates the #hs_data{} record and calls
+%% dist_util:handshake_we_started/1 which changes the process role
+%% into Handshaker.
+%%
+%% When the distribution handshake is finished the procedure is just
+%% as for an incoming connection above.
+%%
+%%
+%% To sum it up.
+%%
+%% There is an Acceptor process that is linked to net_kernel and
+%% informs it when new connections arrive.
+%%
+%% net_kernel spawns Controllers for incoming and for outgoing connections.
+%% these Controllers use the DistCtrl processes to do distribution
+%% handshake and after that becomes Tickers that supervise the connection.
+%%
+%% The Controller | Handshaker | Ticker is linked to net_kernel, and to
+%% DistCtrl, one or both. If any of these connection processes would die
+%% all others should be killed by the links. Therefore none of them may
+%% terminate with reason 'normal'.
+%% -------------------------------------------------------------------------
+
+-compile({inline, [socket_options/0]}).
+socket_options() ->
+ [binary, {active, false}, {packet, 2}, {nodelay, true},
+ {sndbuf, ?BUFFER_SIZE}, {recbuf, ?BUFFER_SIZE},
+ {buffer, ?BUFFER_SIZE}].
+
+%% -------------------------------------------------------------------------
+%% select/1 is called by net_kernel to ask if this distribution protocol
+%% is willing to handle Node
+%%
+
+select(Node) ->
+ gen_select(Node, ?DRIVER).
+
+gen_select(Node, Driver) ->
+ case dist_util:split_node(Node) of
+ {node, _, Host} ->
+ case Driver:getaddr(Host) of
+ {ok, _} -> true;
+ _ -> false
+ end;
+ _ ->
+ false
+ end.
+
+%% -------------------------------------------------------------------------
+
+is_node_name(Node) ->
+ dist_util:is_node_name(Node).
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to create a listen socket for this
+%% distribution protocol. This listen socket is used by
+%% the Acceptor process.
+%%
+
+listen(Name) ->
+ gen_listen(Name, ?DRIVER).
+
+gen_listen(Name, Driver) ->
+ case inet_tcp_dist:gen_listen(Driver, Name) of
+ {ok, {Socket, Address, Creation}} ->
+ inet:setopts(Socket, socket_options()),
+ {ok,
+ {Socket, Address#net_address{protocol = ?DIST_PROTO}, Creation}};
+ Other ->
+ Other
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to spawn the Acceptor process that awaits
+%% new connection in a blocking accept and informs net_kernel
+%% when a new connection has appeared, and starts the DistCtrl
+%% "socket" process for the connection.
+%%
+
+accept(Listen) ->
+ gen_accept(Listen, ?DRIVER).
+
+gen_accept(Listen, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Acceptor process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ start_key_pair_server(),
+ accept_loop(Listen, Driver, NetKernel)
+ end,
+ [link, {priority, max}])).
+
+accept_loop(Listen, Driver, NetKernel) ->
+ case Driver:accept(trace(Listen)) of
+ {ok, Socket} ->
+ wait_for_code_server(),
+ Timeout = net_kernel:connecttime(),
+ DistCtrl = start_dist_ctrl(trace(Socket), Timeout),
+ %% DistCtrl is a "socket"
+ NetKernel !
+ trace({accept,
+ self(), DistCtrl, Driver:family(), ?DIST_PROTO}),
+ receive
+ {NetKernel, controller, Controller} ->
+ call_dist_ctrl(DistCtrl, {controller, Controller, self()}),
+ Controller ! {self(), controller, Socket};
+ {NetKernel, unsupported_protocol} ->
+ exit(unsupported_protocol)
+ end,
+ accept_loop(Listen, Driver, NetKernel);
+ AcceptError ->
+ exit({accept, AcceptError})
+ end.
+
+wait_for_code_server() ->
+ %% This is an ugly hack. Starting encryption on a connection
+ %% requires the crypto module to be loaded. Loading the crypto
+ %% module triggers its on_load function, which calls
+ %% code:priv_dir/1 to find the directory where its NIF library is.
+ %% However, distribution is started earlier than the code server,
+ %% so the code server is not necessarily started yet, and
+ %% code:priv_dir/1 might fail because of that, if we receive
+ %% an incoming connection on the distribution port early enough.
+ %%
+ %% If the on_load function of a module fails, the module is
+ %% unloaded, and the function call that triggered loading it fails
+ %% with 'undef', which is rather confusing.
+ %%
+ %% So let's avoid that by waiting for the code server to start.
+ %%
+ case whereis(code_server) of
+ undefined ->
+ timer:sleep(10),
+ wait_for_code_server();
+ Pid when is_pid(Pid) ->
+ ok
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel when a new connection has appeared, to spawn
+%% a Controller process that performs the handshake with the new node,
+%% and then becomes the Ticker connection supervisor.
+%% -------------------------------------------------------------------------
+
+accept_connection(Acceptor, DistCtrl, MyNode, Allowed, SetupTime) ->
+ gen_accept_connection(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, ?DRIVER).
+
+gen_accept_connection(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Controller/handshaker/ticker process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ fun() ->
+ do_accept(
+ Acceptor, DistCtrl,
+ trace(MyNode), Allowed, SetupTime, Driver, NetKernel)
+ end,
+ [link, {priority, max}])).
+
+do_accept(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, Driver, NetKernel) ->
+ %%
+ receive
+ {Acceptor, controller, Socket} ->
+ Timer = dist_util:start_timer(SetupTime),
+ HSData =
+ hs_data_common(
+ NetKernel, MyNode, DistCtrl, Timer,
+ Socket, Driver:family()),
+ HSData_1 =
+ HSData#hs_data{
+ this_node = MyNode,
+ this_flags = 0,
+ allowed = Allowed},
+ dist_util:handshake_other_started(trace(HSData_1))
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to spawn a Controller process that sets up
+%% a new connection to another Erlang node, performs the handshake
+%% with the other it, and then becomes the Ticker process
+%% that supervises the connection.
+%% -------------------------------------------------------------------------
+
+setup(Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ gen_setup(Node, Type, MyNode, LongOrShortNames, SetupTime, ?DRIVER).
+
+gen_setup(Node, Type, MyNode, LongOrShortNames, SetupTime, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Controller/handshaker/ticker process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ setup_fun(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel),
+ [link, {priority, max}])).
+
+-spec setup_fun(_,_,_,_,_,_,_) -> fun(() -> no_return()).
+setup_fun(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel) ->
+ %%
+ fun() ->
+ do_setup(
+ trace(Node), Type, MyNode, LongOrShortNames, SetupTime,
+ Driver, NetKernel)
+ end.
+
+-spec do_setup(_,_,_,_,_,_,_) -> no_return().
+do_setup(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel) ->
+ %%
+ {Name, Address} = split_node(Driver, Node, LongOrShortNames),
+ ErlEpmd = net_kernel:epmd_module(),
+ {ARMod, ARFun} = get_address_resolver(ErlEpmd, Driver),
+ Timer = trace(dist_util:start_timer(SetupTime)),
+ case ARMod:ARFun(Name, Address, Driver:family()) of
+ {ok, Ip, TcpPort, Version} ->
+ do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, Version);
+ {ok, Ip} ->
+ case ErlEpmd:port_please(Name, Ip) of
+ {port, TcpPort, Version} ->
+ do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, trace(Version));
+ Other ->
+ _ = trace(
+ {ErlEpmd, port_please, [Name, Ip], Other}),
+ ?shutdown(Node)
+ end;
+ Other ->
+ _ = trace(
+ {ARMod, ARFun, [Name, Address, Driver:family()],
+ Other}),
+ ?shutdown(Node)
+ end.
+
+-spec do_setup_connect(_,_,_,_,_,_,_,_,_) -> no_return().
+
+do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, Version) ->
+ dist_util:reset_timer(Timer),
+ ConnectOpts = trace(connect_options(socket_options())),
+ case Driver:connect(Ip, TcpPort, ConnectOpts) of
+ {ok, Socket} ->
+ DistCtrl =
+ try start_dist_ctrl(Socket, net_kernel:connecttime())
+ catch error : {dist_ctrl, _} = DistCtrlError ->
+ _ = trace(DistCtrlError),
+ ?shutdown(Node)
+ end,
+ %% DistCtrl is a "socket"
+ HSData =
+ hs_data_common(
+ NetKernel, MyNode, DistCtrl, Timer,
+ Socket, Driver:family()),
+ HSData_1 =
+ HSData#hs_data{
+ other_node = Node,
+ this_flags = 0,
+ other_version = Version,
+ request_type = Type},
+ dist_util:handshake_we_started(trace(HSData_1));
+ ConnectError ->
+ _ = trace(
+ {Driver, connect, [Ip, TcpPort, ConnectOpts],
+ ConnectError}),
+ ?shutdown(Node)
+ end.
+
+%% -------------------------------------------------------------------------
+%% close/1 is only called by net_kernel on the socket returned by listen/1.
+
+close(Socket) ->
+ gen_close(Socket, ?DRIVER).
+
+gen_close(Socket, Driver) ->
+ Driver:close(trace(Socket)).
+
+%% -------------------------------------------------------------------------
+
+
+hs_data_common(NetKernel, MyNode, DistCtrl, Timer, Socket, Family) ->
+ %% Field 'socket' below is set to DistCtrl, which makes
+ %% the distribution handshake process (ticker) call
+ %% the funs below with DistCtrl as the S argument.
+ %% So, S =:= DistCtrl below...
+ #hs_data{
+ kernel_pid = NetKernel,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ %%
+ f_send = % -> ok | {error, closed}=>?shutdown()
+ fun (S, Packet) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, {send, Packet})
+ catch error : {dist_ctrl, Reason} ->
+ _ = trace(Reason),
+ {error, closed}
+ end
+ end,
+ f_recv = % -> {ok, List} | Other=>?shutdown()
+ fun (S, 0, infinity) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, recv) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, binary_to_list(Bin)};
+ Error ->
+ Error
+ catch error : {dist_ctrl, Reason} ->
+ {error, trace(Reason)}
+ end
+ end,
+ f_setopts_pre_nodeup =
+ fun (S) when S =:= DistCtrl ->
+ ok
+ end,
+ f_setopts_post_nodeup =
+ fun (S) when S =:= DistCtrl ->
+ ok
+ end,
+ f_getll =
+ fun (S) when S =:= DistCtrl ->
+ {ok, S} %% DistCtrl is the distribution port
+ end,
+ f_address = % -> #net_address{} | ?shutdown()
+ fun (S, Node) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, peername) of
+ {ok, Address} ->
+ case dist_util:split_node(Node) of
+ {node, _, Host} ->
+ #net_address{
+ address = Address,
+ host = Host,
+ protocol = ?DIST_PROTO,
+ family = Family};
+ _ ->
+ ?shutdown(Node)
+ end;
+ Error ->
+ _ = trace(Error),
+ ?shutdown(Node)
+ catch error : {dist_ctrl, Reason} ->
+ _ = trace(Reason),
+ ?shutdown(Node)
+ end
+ end,
+ f_handshake_complete = % -> ok | ?shutdown()
+ fun (S, Node, DistHandle) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, {handshake_complete, DistHandle})
+ catch error : {dist_ctrl, Reason} ->
+ _ = trace(Reason),
+ ?shutdown(Node)
+ end
+ end,
+ %%
+ %% mf_tick/1, mf_getstat/1, mf_setopts/2 and mf_getopts/2
+ %% are called by the ticker any time after f_handshake_complete/3
+ %% so they may not block the caller even for congested socket
+ mf_tick =
+ fun (S) when S =:= DistCtrl ->
+ S ! dist_tick
+ end,
+ mf_getstat = % -> {ok, RecvCnt, SendCnt, SendPend} | Other=>ignore_it
+ fun (S) when S =:= DistCtrl ->
+ case
+ inet:getstat(Socket, [recv_cnt, send_cnt, send_pend])
+ of
+ {ok, Stat} ->
+ split_stat(Stat, 0, 0, 0);
+ Error ->
+ trace(Error)
+ end
+ end,
+ mf_setopts =
+ fun (S, Opts) when S =:= DistCtrl ->
+ inet:setopts(Socket, setopts_filter(Opts))
+ end,
+ mf_getopts =
+ fun (S, Opts) when S =:= DistCtrl ->
+ inet:getopts(Socket, Opts)
+ end}.
+
+setopts_filter(Opts) ->
+ [Opt ||
+ Opt <- Opts,
+ case Opt of
+ {K, _} when K =:= active; K =:= deliver; K =:= packet -> false;
+ K when K =:= list; K =:= binary -> false;
+ K when K =:= inet; K =:= inet6 -> false;
+ _ -> true
+ end].
+
+split_stat([{recv_cnt, R}|Stat], _, W, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_cnt, W}|Stat], R, _, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_pend, P}|Stat], R, W, _) ->
+ split_stat(Stat, R, W, P);
+split_stat([], R, W, P) ->
+ {ok, R, W, P}.
+
+%% ------------------------------------------------------------
+%% Determine if EPMD module supports address resolving. Default
+%% is to use inet_tcp:getaddr/2.
+%% ------------------------------------------------------------
+get_address_resolver(EpmdModule, _Driver) ->
+ case erlang:function_exported(EpmdModule, address_please, 3) of
+ true -> {EpmdModule, address_please};
+ _ -> {erl_epmd, address_please}
+ end.
+
+
+%% If Node is illegal terminate the connection setup!!
+split_node(Driver, Node, LongOrShortNames) ->
+ case dist_util:split_node(Node) of
+ {node, Name, Host} ->
+ check_node(Driver, Node, Name, Host, LongOrShortNames);
+ {host, _} ->
+ error_logger:error_msg(
+ "** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown2(Node, trace({illegal_node_n@me, Node}));
+ _ ->
+ error_logger:error_msg(
+ "** Nodename ~p illegal **~n", [Node]),
+ ?shutdown2(Node, trace({illegal_node_name, Node}))
+ end.
+
+check_node(Driver, Node, Name, Host, LongOrShortNames) ->
+ case string:split(Host, ".", all) of
+ [_] when LongOrShortNames =:= longnames ->
+ case Driver:parse_address(Host) of
+ {ok, _} ->
+ {Name, Host};
+ _ ->
+ error_logger:error_msg(
+ "** System running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_longnames, Host}))
+ end;
+ [_, _|_] when LongOrShortNames =:= shortnames ->
+ error_logger:error_msg(
+ "** System NOT running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_shortnames, Host}));
+ _ ->
+ {Name, Host}
+ end.
+
+%% -------------------------------------------------------------------------
+
+connect_options(Opts) ->
+ case application:get_env(kernel, inet_dist_connect_options) of
+ {ok, ConnectOpts} ->
+ Opts ++ setopts_filter(ConnectOpts);
+ _ ->
+ Opts
+ end.
+
+%% we may not always want the nodelay behaviour
+%% for performance reasons
+nodelay() ->
+ case application:get_env(kernel, dist_nodelay) of
+ undefined ->
+ {nodelay, true};
+ {ok, true} ->
+ {nodelay, true};
+ {ok, false} ->
+ {nodelay, false};
+ _ ->
+ {nodelay, true}
+ end.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% The DistCtrl process(es).
+%%
+%% At net_kernel handshake_complete spawns off the input controller that
+%% takes over the socket ownership, and itself becomes the output controller
+%%
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% XXX Missing to "productified":
+%%% * Cryptoanalysis by experts, this is crypto amateur work.
+%%% * Is it useful over inet_tls_dist; i.e to not have to bother
+%%% with certificates but instead manage a secret cluster cookie?
+%%% * An application to belong to (kernel)
+%%% * Restart and/or code reload policy (not needed in kernel)
+%%% * Fitting into the epmd/Erlang distro protocol version framework
+%%% (something needs to be created for multiple protocols, epmd,
+%%% multiple address families, fallback to previous version, etc)
+
+
+%% Debug client and server
+
+test_server() ->
+ {ok, Listen} = gen_tcp:listen(0, socket_options()),
+ {ok, Port} = inet:port(Listen),
+ io:format(?MODULE_STRING":test_client(~w).~n", [Port]),
+ {ok, Socket} = gen_tcp:accept(Listen),
+ test(Socket).
+
+test_client(Port) ->
+ {ok, Socket} = gen_tcp:connect(localhost, Port, socket_options()),
+ test(Socket).
+
+test(Socket) ->
+ start_dist_ctrl(Socket, 10000).
+
+%% -------------------------------------------------------------------------
+
+start_dist_ctrl(Socket, Timeout) ->
+ Secret = atom_to_binary(auth:get_cookie(), latin1),
+ Controller = self(),
+ Server =
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ receive
+ {?MODULE, From, start} ->
+ {SendParams, RecvParams} =
+ init(Socket, Secret),
+ reply(From, self()),
+ handshake(SendParams, 1, RecvParams, 1, Controller)
+ end
+ end,
+ [link,
+ {priority, max},
+ {message_queue_data, off_heap},
+ {fullsweep_after, 0}])),
+ ok = gen_tcp:controlling_process(Socket, Server),
+ call_dist_ctrl(Server, start, Timeout).
+
+
+call_dist_ctrl(Server, Msg) ->
+ call_dist_ctrl(Server, Msg, infinity).
+%%
+call_dist_ctrl(Server, Msg, Timeout) ->
+ Ref = erlang:monitor(process, Server),
+ Server ! {?MODULE, {Ref, self()}, Msg},
+ receive
+ {Ref, Res} ->
+ erlang:demonitor(Ref, [flush]),
+ Res;
+ {'DOWN', Ref, process, Server, Reason} ->
+ error({dist_ctrl, Reason})
+ after Timeout -> % Timeout < infinity is only used by start_dist_ctrl/2
+ receive
+ {'DOWN', Ref, process, Server, _} ->
+ receive {Ref, _} -> ok after 0 -> ok end,
+ error({dist_ctrl, timeout})
+ %% Server will be killed by link
+ end
+ end.
+
+reply({Ref, Pid}, Msg) ->
+ Pid ! {Ref, Msg},
+ ok.
+
+%% -------------------------------------------------------------------------
+
+-define(TCP_ACTIVE, 16).
+-define(CHUNK_SIZE, (?PACKET_SIZE - 512)).
+
+-define(HANDSHAKE_CHUNK, 1).
+-define(DATA_CHUNK, 2).
+-define(TICK_CHUNK, 3).
+-define(REKEY_CHUNK, 4).
+
+%% -------------------------------------------------------------------------
+%% Crypto strategy
+%% -------
+%% The crypto strategy is as simple as possible to get an encrypted
+%% connection as benchmark reference. It is geared around AEAD
+%% ciphers in particular AES-GCM.
+%%
+%% The init message and the start message must fit in the TCP buffers
+%% since both sides start with sending the init message, waits
+%% for the other end's init message, sends the start message
+%% and waits for the other end's start message. So if the send
+%% blocks we have a deadlock.
+%%
+%% The init + start sequence tries to implement Password Encrypted
+%% Key Exchange using a node public/private key pair and the
+%% shared secret (the Cookie) to create session encryption keys
+%% that can not be re-created if the shared secret is compromized,
+%% which should create forward secrecy. You need both nodes'
+%% key pairs and the shared secret to decrypt the traffic
+%% between the nodes.
+%%
+%% All exchanged messages uses {packet, 2} i.e 16 bit size header.
+%%
+%% The init message contains a random number and encrypted: the public key
+%% and two random numbers. The encryption is done with Key and IV hashed
+%% from the unencrypted random number and the shared secret.
+%%
+%% The other node's public key is used with the own node's private
+%% key to create a shared key that is hashed with one of the encrypted
+%% random numbers from each side to create Key and IV for the session.
+%%
+%% The start message contains the two encrypted random numbers
+%% this time encrypted with the session keys for verification
+%% by the other side, plus the rekey interval. The rekey interval
+%% is just there to get an early check for if the other side's
+%% maximum rekey interal is acceptable, it is just an embryo
+%% of some better check. Any side may rekey earlier but if the
+%% rekey interval is exceeded the connection fails.
+%%
+%% Subsequent encrypted messages has the sequence number and the length
+%% of the message as AAD data, and an incrementing IV. These messages
+%% has got a message type that differentiates data from ticks and rekeys.
+%% Ticks have a random size in an attempt to make them less obvious to spot.
+%%
+%% Rekeying is done by the sender that creates a new key pair and
+%% a new shared secret from the other end's public key and with
+%% this and the current key and iv hashes a new key and iv.
+%% The new public key is sent to the other end that uses it
+%% and its old private key to create the same new shared
+%% secret and from that a new key and iv.
+%% So the receiver keeps its private key, and the sender keeps
+%% the receivers public key for the connection's life time.
+%% While the sender generates a new key pair at every rekey,
+%% which changes the shared secret at every rekey.
+%%
+%% The only reaction to errors is to crash noisily (?) wich will bring
+%% down the connection and hopefully produce something useful
+%% in the local log, but all the other end sees is a closed connection.
+%% -------------------------------------------------------------------------
+
+init(Socket, Secret) ->
+ #key_pair{public = PubKey} = KeyPair = get_key_pair(),
+ Params = params(Socket),
+ {R2, R3, Msg} = init_msg(Params, PubKey, Secret),
+ ok = gen_tcp:send(Socket, Msg),
+ init_recv(Params, Secret, KeyPair, R2, R3).
+
+init_recv(
+ #params{socket = Socket, iv = IVLen} = Params, Secret, KeyPair, R2, R3) ->
+ %%
+ {ok, InitMsg} = gen_tcp:recv(Socket, 0),
+ IVSaltLen = IVLen - 6,
+ try
+ case init_msg(Params, Secret, KeyPair, R2, R3, InitMsg) of
+ {#params{iv = <<IV2ASalt:IVSaltLen/binary, IV2ANo:48>>} =
+ SendParams,
+ RecvParams, SendStartMsg} ->
+ ok = gen_tcp:send(Socket, SendStartMsg),
+ {ok, RecvStartMsg} = gen_tcp:recv(Socket, 0),
+ #params{
+ iv = <<IV2BSalt:IVSaltLen/binary, IV2BNo:48>>} =
+ RecvParams_1 =
+ start_msg(RecvParams, R2, R3, RecvStartMsg),
+ {SendParams#params{iv = {IV2ASalt, IV2ANo}},
+ RecvParams_1#params{iv = {IV2BSalt, IV2BNo}}}
+ end
+ catch
+ error : Reason : Stacktrace->
+ _ = trace({Reason, Stacktrace}),
+ exit(connection_closed)
+ end.
+
+
+
+init_msg(
+ #params{
+ hmac_algorithm = HmacAlgo,
+ aead_cipher = AeadCipher,
+ key = KeyLen,
+ iv = IVLen,
+ tag_len = TagLen}, PubKeyA, Secret) ->
+ %%
+ RLen = KeyLen + IVLen,
+ <<R1A:RLen/binary, R2A:RLen/binary, R3A:RLen/binary>> =
+ crypto:strong_rand_bytes(3 * RLen),
+ {Key1A, IV1A} = hmac_key_iv(HmacAlgo, R1A, Secret, KeyLen, IVLen),
+ Plaintext = [R2A, R3A, PubKeyA],
+ MsgLen = byte_size(R1A) + TagLen + iolist_size(Plaintext),
+ AAD = [<<MsgLen:32>>, R1A],
+ {Ciphertext, Tag} =
+ crypto:block_encrypt(AeadCipher, Key1A, IV1A, {AAD, Plaintext, TagLen}),
+ Msg = [R1A, Tag, Ciphertext],
+ {R2A, R3A, Msg}.
+%%
+init_msg(
+ #params{
+ hmac_algorithm = HmacAlgo,
+ aead_cipher = AeadCipher,
+ key = KeyLen,
+ iv = IVLen,
+ tag_len = TagLen,
+ rekey_interval = RekeyInterval} = Params,
+ Secret, KeyPair, R2A, R3A, Msg) ->
+ %%
+ RLen = KeyLen + IVLen,
+ case Msg of
+ <<R1B:RLen/binary, Tag:TagLen/binary, Ciphertext/binary>> ->
+ {Key1B, IV1B} = hmac_key_iv(HmacAlgo, R1B, Secret, KeyLen, IVLen),
+ MsgLen = byte_size(Msg),
+ AAD = [<<MsgLen:32>>, R1B],
+ case
+ crypto:block_decrypt(
+ AeadCipher, Key1B, IV1B, {AAD, Ciphertext, Tag})
+ of
+ <<R2B:RLen/binary, R3B:RLen/binary, PubKeyB/binary>> ->
+ SharedSecret = compute_shared_secret(KeyPair, PubKeyB),
+ %%
+ {Key2A, IV2A} =
+ hmac_key_iv(
+ HmacAlgo, SharedSecret, [R2A, R3B], KeyLen, IVLen),
+ SendParams =
+ Params#params{
+ rekey_key = PubKeyB,
+ key = Key2A, iv = IV2A},
+ %%
+ StartCleartext = [R2B, R3B, <<RekeyInterval:32>>],
+ StartMsgLen = TagLen + iolist_size(StartCleartext),
+ StartAAD = <<StartMsgLen:32>>,
+ {StartCiphertext, StartTag} =
+ crypto:block_encrypt(
+ AeadCipher, Key2A, IV2A,
+ {StartAAD, StartCleartext, TagLen}),
+ StartMsg = [StartTag, StartCiphertext],
+ %%
+ {Key2B, IV2B} =
+ hmac_key_iv(
+ HmacAlgo, SharedSecret, [R2B, R3A], KeyLen, IVLen),
+ RecvParams =
+ Params#params{
+ rekey_key = KeyPair,
+ key = Key2B, iv = IV2B},
+ %%
+ {SendParams, RecvParams, StartMsg}
+ end
+ end.
+
+start_msg(
+ #params{
+ aead_cipher = AeadCipher,
+ key = Key2B,
+ iv = IV2B,
+ tag_len = TagLen,
+ rekey_interval = RekeyIntervalA} = RecvParams, R2A, R3A, Msg) ->
+ %%
+ case Msg of
+ <<Tag:TagLen/binary, Ciphertext/binary>> ->
+ KeyLen = byte_size(Key2B),
+ IVLen = byte_size(IV2B),
+ RLen = KeyLen + IVLen,
+ MsgLen = byte_size(Msg),
+ AAD = <<MsgLen:32>>,
+ case
+ crypto:block_decrypt(
+ AeadCipher, Key2B, IV2B, {AAD, Ciphertext, Tag})
+ of
+ <<R2A:RLen/binary, R3A:RLen/binary, RekeyIntervalB:32>>
+ when RekeyIntervalA =< (RekeyIntervalB bsl 2),
+ RekeyIntervalB =< (RekeyIntervalA bsl 2) ->
+ RecvParams#params{rekey_interval = RekeyIntervalB}
+ end
+ end.
+
+hmac_key_iv(HmacAlgo, MacKey, Data, KeyLen, IVLen) ->
+ <<Key:KeyLen/binary, IV:IVLen/binary>> =
+ crypto:hmac(HmacAlgo, MacKey, Data, KeyLen + IVLen),
+ {Key, IV}.
+
+%% -------------------------------------------------------------------------
+%% net_kernel distribution handshake in progress
+%%
+
+handshake(
+ SendParams, SendSeq,
+ #params{socket = Socket} = RecvParams, RecvSeq, Controller) ->
+ receive
+ {?MODULE, From, {controller, Controller_1, Parent}} ->
+ Result = link(Controller_1),
+ true = unlink(Parent),
+ reply(From, Result),
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller_1);
+ {?MODULE, From, {handshake_complete, DistHandle}} ->
+ InputHandler =
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ link(Controller),
+ receive
+ DistHandle ->
+ ok =
+ inet:setopts(
+ Socket,
+ [{active, ?TCP_ACTIVE},
+ nodelay()]),
+ input_handler(
+ RecvParams#params{
+ dist_handle = DistHandle},
+ RecvSeq, empty_q(), infinity)
+ end
+ end,
+ [link,
+ {priority, normal},
+ {message_queue_data, off_heap},
+ {fullsweep_after, 0}])),
+ _ = monitor(process, InputHandler), % For the benchmark test
+ ok = gen_tcp:controlling_process(Socket, InputHandler),
+ ok = erlang:dist_ctrl_input_handler(DistHandle, InputHandler),
+ InputHandler ! DistHandle,
+ crypto:rand_seed_alg(crypto_cache),
+ reply(From, ok),
+ process_flag(priority, normal),
+ erlang:dist_ctrl_get_data_notification(DistHandle),
+ output_handler(
+ SendParams#params{dist_handle = DistHandle}, SendSeq);
+ %%
+ {?MODULE, From, {send, Data}} ->
+ case
+ encrypt_and_send_chunk(
+ SendParams, SendSeq, [?HANDSHAKE_CHUNK, Data])
+ of
+ {SendParams_1, SendSeq_1, ok} ->
+ reply(From, ok),
+ handshake(
+ SendParams_1, SendSeq_1, RecvParams, RecvSeq,
+ Controller);
+ {_, _, Error} ->
+ reply(From, {error, closed}),
+ death_row({send, trace(Error)})
+ end;
+ {?MODULE, From, recv} ->
+ case recv_and_decrypt_chunk(RecvParams, RecvSeq) of
+ {RecvParams_1, RecvSeq_1, {ok, _} = Reply} ->
+ reply(From, Reply),
+ handshake(
+ SendParams, SendSeq, RecvParams_1, RecvSeq_1,
+ Controller);
+ {_, _, Error} ->
+ reply(From, Error),
+ death_row({recv, trace(Error)})
+ end;
+ {?MODULE, From, peername} ->
+ reply(From, inet:peername(Socket)),
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller);
+ %%
+ _Alien ->
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller)
+ end.
+
+recv_and_decrypt_chunk(#params{socket = Socket} = RecvParams, RecvSeq) ->
+ case gen_tcp:recv(Socket, 0) of
+ {ok, Chunk} ->
+ case decrypt_chunk(RecvParams, RecvSeq, Chunk) of
+ <<?HANDSHAKE_CHUNK, Cleartext/binary>> ->
+ {RecvParams, RecvSeq + 1, {ok, Cleartext}};
+ OtherChunk when is_binary(OtherChunk) ->
+ {RecvParams, RecvSeq + 1, {error, decrypt_error}};
+ #params{} = RecvParams_1 ->
+ recv_and_decrypt_chunk(RecvParams_1, 0);
+ error ->
+ {RecvParams, RecvSeq, {error, decrypt_error}}
+ end;
+ Error ->
+ {RecvParams, RecvSeq, Error}
+ end.
+
+%% -------------------------------------------------------------------------
+%% Output handler process
+%%
+%% The game here is to flush all dist_data and dist_tick messages,
+%% prioritize dist_data over dist_tick, and to not use selective receive
+
+output_handler(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_tick(Params, Seq);
+ Other ->
+ %% Ignore
+ _ = trace(Other),
+ output_handler(Params, Seq)
+ end
+ end.
+
+output_handler_data(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_data(Params, Seq);
+ Other ->
+ %% Ignore
+ _ = trace(Other),
+ output_handler_data(Params, Seq)
+ end
+ after 0 ->
+ DistHandle = Params#params.dist_handle,
+ Q = get_data(DistHandle, empty_q()),
+ {Params_1, Seq_1} = output_handler_send(Params, Seq, Q),
+ erlang:dist_ctrl_get_data_notification(DistHandle),
+ output_handler(Params_1, Seq_1)
+ end.
+
+output_handler_tick(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_tick(Params, Seq);
+ Other ->
+ %% Ignore
+ _ = trace(Other),
+ output_handler_tick(Params, Seq)
+ end
+ after 0 ->
+ TickSize = 7 + rand:uniform(56),
+ TickData = binary:copy(<<0>>, TickSize),
+ case
+ encrypt_and_send_chunk(Params, Seq, [?TICK_CHUNK, TickData])
+ of
+ {Params_1, Seq_1, ok} ->
+ output_handler(Params_1, Seq_1);
+ {_, _, Error} ->
+ _ = trace(Error),
+ death_row()
+ end
+ end.
+
+output_handler_send(Params, Seq, {_, Size, _} = Q) ->
+ if
+ ?CHUNK_SIZE < Size ->
+ output_handler_send(Params, Seq, Q, ?CHUNK_SIZE);
+ true ->
+ case get_data(Params#params.dist_handle, Q) of
+ {_, 0, _} ->
+ {Params, Seq};
+ {_, Size, _} = Q_1 -> % Got no more
+ output_handler_send(Params, Seq, Q_1, Size);
+ Q_1 ->
+ output_handler_send(Params, Seq, Q_1)
+ end
+ end.
+
+output_handler_send(Params, Seq, Q, Size) ->
+ {Cleartext, Q_1} = deq_iovec(Size, Q),
+ case
+ encrypt_and_send_chunk(Params, Seq, [?DATA_CHUNK, Cleartext])
+ of
+ {Params_1, Seq_1, ok} ->
+ output_handler_send(Params_1, Seq_1, Q_1);
+ {_, _, Error} ->
+ _ = trace(Error),
+ death_row()
+ end.
+
+%% -------------------------------------------------------------------------
+%% Input handler process
+%%
+%% Here is T = 0|infinity to steer if we should try to receive
+%% more data or not; start with infinity, and when we get some
+%% data try with 0 to see if more is waiting
+
+input_handler(#params{socket = Socket} = Params, Seq, Q, T) ->
+ receive
+ Msg ->
+ case Msg of
+ {tcp_passive, Socket} ->
+ ok = inet:setopts(Socket, [{active, ?TCP_ACTIVE}]),
+ Q_1 =
+ case T of
+ 0 ->
+ deliver_data(Params#params.dist_handle, Q);
+ infinity ->
+ Q
+ end,
+ input_handler(Params, Seq, Q_1, infinity);
+ {tcp, Socket, Chunk} ->
+ input_chunk(Params, Seq, Q, T, Chunk);
+ {tcp_closed, Socket} ->
+ exit(connection_closed);
+ Other ->
+ %% Ignore...
+ _ = trace(Other),
+ input_handler(Params, Seq, Q, T)
+ end
+ after T ->
+ Q_1 = deliver_data(Params#params.dist_handle, Q),
+ input_handler(Params, Seq, Q_1, infinity)
+ end.
+
+input_chunk(Params, Seq, Q, T, Chunk) ->
+ case decrypt_chunk(Params, Seq, Chunk) of
+ <<?DATA_CHUNK, Cleartext/binary>> ->
+ input_handler(Params, Seq + 1, enq_binary(Cleartext, Q), 0);
+ <<?TICK_CHUNK, _/binary>> ->
+ input_handler(Params, Seq + 1, Q, T);
+ OtherChunk when is_binary(OtherChunk) ->
+ _ = trace(invalid_chunk),
+ exit(connection_closed);
+ #params{} = Params_1 ->
+ input_handler(Params_1, 0, Q, T);
+ error ->
+ _ = trace(decrypt_error),
+ exit(connection_closed)
+ end.
+
+%% -------------------------------------------------------------------------
+%% erlang:dist_ctrl_* helpers
+
+%% Get data for sending from the VM and place it in a queue
+%%
+get_data(DistHandle, {Front, Size, Rear}) ->
+ get_data(DistHandle, Front, Size, Rear).
+%%
+get_data(DistHandle, Front, Size, Rear) ->
+ case erlang:dist_ctrl_get_data(DistHandle) of
+ none ->
+ {Front, Size, Rear};
+ Bin when is_binary(Bin) ->
+ Len = byte_size(Bin),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ [Bin, <<Len:32>>|Rear]);
+ [Bin1, Bin2] ->
+ Len = byte_size(Bin1) + byte_size(Bin2),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ [Bin2, Bin1, <<Len:32>>|Rear]);
+ Iovec ->
+ Len = iolist_size(Iovec),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ lists:reverse(Iovec, [<<Len:32>>|Rear]))
+ end.
+
+%% De-packet and deliver received data to the VM from a queue
+%%
+deliver_data(DistHandle, Q) ->
+ case Q of
+ {[], Size, []} ->
+ Size = 0, % Assert
+ Q;
+ {[], Size, Rear} ->
+ [Bin|Front] = lists:reverse(Rear),
+ deliver_data(DistHandle, Front, Size, [], Bin);
+ {[Bin|Front], Size, Rear} ->
+ deliver_data(DistHandle, Front, Size, Rear, Bin)
+ end.
+%%
+deliver_data(DistHandle, Front, Size, Rear, Bin) ->
+ case Bin of
+ <<DataSizeA:32, DataA:DataSizeA/binary,
+ DataSizeB:32, DataB:DataSizeB/binary, Rest/binary>> ->
+ erlang:dist_ctrl_put_data(DistHandle, DataA),
+ erlang:dist_ctrl_put_data(DistHandle, DataB),
+ deliver_data(
+ DistHandle,
+ Front, Size - (4 + DataSizeA + 4 + DataSizeB), Rear,
+ Rest);
+ <<DataSize:32, Data:DataSize/binary, Rest/binary>> ->
+ erlang:dist_ctrl_put_data(DistHandle, Data),
+ deliver_data(DistHandle, Front, Size - (4 + DataSize), Rear, Rest);
+ <<DataSize:32, FirstData/binary>> ->
+ TotalSize = 4 + DataSize,
+ if
+ TotalSize =< Size ->
+ BinSize = byte_size(Bin),
+ {MoreData, Q} =
+ deq_iovec(
+ TotalSize - BinSize,
+ Front, Size - BinSize, Rear),
+ erlang:dist_ctrl_put_data(DistHandle, [FirstData|MoreData]),
+ deliver_data(DistHandle, Q);
+ true -> % Incomplete data
+ {[Bin|Front], Size, Rear}
+ end;
+ <<_/binary>> ->
+ BinSize = byte_size(Bin),
+ if
+ 4 =< Size -> % Fragmented header - extract a header bin
+ {RestHeader, {Front_1, _Size_1, Rear_1}} =
+ deq_iovec(4 - BinSize, Front, Size - BinSize, Rear),
+ Header = iolist_to_binary([Bin|RestHeader]),
+ deliver_data(DistHandle, Front_1, Size, Rear_1, Header);
+ true -> % Incomplete header
+ {[Bin|Front], Size, Rear}
+ end
+ end.
+
+%% -------------------------------------------------------------------------
+%% Encryption and decryption helpers
+
+encrypt_and_send_chunk(
+ #params{
+ socket = Socket,
+ rekey_interval = Seq,
+ rekey_key = PubKeyB,
+ key = Key,
+ iv = {IVSalt, IVNo},
+ hmac_algorithm = HmacAlgo} = Params,
+ Seq, Cleartext) ->
+ %%
+ KeyLen = byte_size(Key),
+ IVSaltLen = byte_size(IVSalt),
+ #key_pair{public = PubKeyA} = KeyPair = get_new_key_pair(),
+ case
+ gen_tcp:send(
+ Socket, encrypt_chunk(Params, Seq, [?REKEY_CHUNK, PubKeyA]))
+ of
+ ok ->
+ SharedSecret = compute_shared_secret(KeyPair, PubKeyB),
+ IV = <<(IVNo + Seq):48>>,
+ {Key_1, <<IVSalt_1:IVSaltLen/binary, IVNo_1:48>>} =
+ hmac_key_iv(
+ HmacAlgo, SharedSecret, [Key, IVSalt, IV],
+ KeyLen, IVSaltLen + 6),
+ Params_1 = Params#params{key = Key_1, iv = {IVSalt_1, IVNo_1}},
+ Result =
+ gen_tcp:send(Socket, encrypt_chunk(Params_1, 0, Cleartext)),
+ {Params_1, 1, Result};
+ SendError ->
+ {Params, Seq + 1, SendError}
+ end;
+encrypt_and_send_chunk(#params{socket = Socket} = Params, Seq, Cleartext) ->
+ Result = gen_tcp:send(Socket, encrypt_chunk(Params, Seq, Cleartext)),
+ {Params, Seq + 1, Result}.
+
+encrypt_chunk(
+ #params{
+ aead_cipher = AeadCipher,
+ iv = {IVSalt, IVNo}, key = Key, tag_len = TagLen}, Seq, Cleartext) ->
+ %%
+ ChunkLen = iolist_size(Cleartext) + TagLen,
+ AAD = <<Seq:32, ChunkLen:32>>,
+ IVBin = <<IVSalt/binary, (IVNo + Seq):48>>,
+ {Ciphertext, CipherTag} =
+ crypto:block_encrypt(AeadCipher, Key, IVBin, {AAD, Cleartext, TagLen}),
+ Chunk = [Ciphertext,CipherTag],
+ Chunk.
+
+decrypt_chunk(
+ #params{
+ aead_cipher = AeadCipher,
+ iv = {IVSalt, IVNo}, key = Key, tag_len = TagLen} = Params, Seq, Chunk) ->
+ %%
+ ChunkLen = byte_size(Chunk),
+ if
+ ChunkLen < TagLen ->
+ error;
+ true ->
+ AAD = <<Seq:32, ChunkLen:32>>,
+ IVBin = <<IVSalt/binary, (IVNo + Seq):48>>,
+ CiphertextLen = ChunkLen - TagLen,
+ case Chunk of
+ <<Ciphertext:CiphertextLen/binary,
+ CipherTag:TagLen/binary>> ->
+ block_decrypt(
+ Params, Seq, AeadCipher, Key, IVBin,
+ {AAD, Ciphertext, CipherTag});
+ _ ->
+ error
+ end
+ end.
+
+block_decrypt(
+ #params{
+ rekey_key = #key_pair{public = PubKeyA} = KeyPair,
+ rekey_interval = RekeyInterval} = Params,
+ Seq, AeadCipher, Key, IV, Data) ->
+ %%
+ case crypto:block_decrypt(AeadCipher, Key, IV, Data) of
+ <<?REKEY_CHUNK, Rest/binary>> ->
+ PubKeyLen = byte_size(PubKeyA),
+ case Rest of
+ <<PubKeyB:PubKeyLen/binary>> ->
+ SharedSecret = compute_shared_secret(KeyPair, PubKeyB),
+ KeyLen = byte_size(Key),
+ IVLen = byte_size(IV),
+ IVSaltLen = IVLen - 6,
+ {Key_1, <<IVSalt:IVSaltLen/binary, IVNo:48>>} =
+ hmac_key_iv(
+ Params#params.hmac_algorithm,
+ SharedSecret, [Key, IV], KeyLen, IVLen),
+ Params#params{iv = {IVSalt, IVNo}, key = Key_1};
+ _ ->
+ error
+ end;
+ Chunk when is_binary(Chunk) ->
+ case Seq of
+ RekeyInterval ->
+ %% This was one chunk too many without rekeying
+ error;
+ _ ->
+ Chunk
+ end;
+ error ->
+ error
+ end.
+
+%% -------------------------------------------------------------------------
+%% Queue of binaries i.e an iovec queue
+
+empty_q() ->
+ {[], 0, []}.
+
+enq_binary(Bin, {Front, Size, Rear}) ->
+ {Front, Size + byte_size(Bin), [Bin|Rear]}.
+
+deq_iovec(GetSize, {Front, Size, Rear}) when GetSize =< Size ->
+ deq_iovec(GetSize, Front, Size, Rear, []).
+%%
+deq_iovec(GetSize, Front, Size, Rear) ->
+ deq_iovec(GetSize, Front, Size, Rear, []).
+%%
+deq_iovec(GetSize, [], Size, Rear, Acc) ->
+ deq_iovec(GetSize, lists:reverse(Rear), Size, [], Acc);
+deq_iovec(GetSize, [Bin|Front], Size, Rear, Acc) ->
+ BinSize = byte_size(Bin),
+ if
+ BinSize < GetSize ->
+ deq_iovec(
+ GetSize - BinSize, Front, Size - BinSize, Rear, [Bin|Acc]);
+ GetSize < BinSize ->
+ {Bin1,Bin2} = erlang:split_binary(Bin, GetSize),
+ {lists:reverse(Acc, [Bin1]), {[Bin2|Front], Size - GetSize, Rear}};
+ true ->
+ {lists:reverse(Acc, [Bin]), {Front, Size - BinSize, Rear}}
+ end.
+
+%% -------------------------------------------------------------------------
+
+death_row() -> death_row(connection_closed).
+%%
+death_row(normal) -> death_row(connection_closed);
+death_row(Reason) -> receive after 5000 -> exit(Reason) end.
+
+%% -------------------------------------------------------------------------
+
+%% Trace point
+trace(Term) -> Term.
+
+%% Keep an eye on this Pid (debug)
+-ifndef(undefined).
+monitor_dist_proc(Pid) ->
+ Pid.
+-else.
+monitor_dist_proc(Pid) ->
+ spawn(
+ fun () ->
+ MRef = erlang:monitor(process, Pid),
+ receive
+ {'DOWN', MRef, _, _, normal} ->
+ error_logger:error_report(
+ [dist_proc_died,
+ {reason, normal},
+ {pid, Pid}]);
+ {'DOWN', MRef, _, _, Reason} ->
+ error_logger:info_report(
+ [dist_proc_died,
+ {reason, Reason},
+ {pid, Pid}])
+ end
+ end),
+ Pid.
+-endif.
+
+dbg() ->
+ dbg:stop(),
+ dbg:tracer(),
+ dbg:p(all, c),
+ dbg:tpl(?MODULE, trace, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data_notification, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data, cx),
+ dbg:tpl(erlang, dist_ctrl_put_data, cx),
+ ok.
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 7f3371da9a..76bf0fa895 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -377,7 +377,7 @@ req_cnf(Root, C) ->
"default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -427,7 +427,7 @@ ca_cnf(
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
@@ -511,7 +511,7 @@ ca_cnf(
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
diff --git a/lib/ssl/test/openssl_alpn_SUITE.erl b/lib/ssl/test/openssl_alpn_SUITE.erl
new file mode 100644
index 0000000000..5008dba922
--- /dev/null
+++ b/lib/ssl/test/openssl_alpn_SUITE.erl
@@ -0,0 +1,421 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(openssl_alpn_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(SLEEP, 1000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ %% Note: ALPN not supported in sslv3
+ case ssl_test_lib:openssl_sane_dtls_alpn() of
+ true ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls_alpn() of
+ true ->
+ [
+ {'tlsv1.3', [], alpn_tests()},
+ {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'dtlsv1.2', [], alpn_tests()},
+ {'dtlsv1', [], alpn_tests()}
+ ];
+ false ->
+ [
+ {'tlsv1.3', [], alpn_tests()},
+ {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()}
+ ]
+ end.
+
+alpn_tests() ->
+ [erlang_client_alpn_openssl_server_alpn,
+ erlang_server_alpn_openssl_client_alpn,
+ erlang_client_alpn_openssl_server,
+ erlang_client_openssl_server_alpn,
+ erlang_server_alpn_openssl_client,
+ erlang_server_openssl_client_alpn].
+
+alpn_npn_coexist() ->
+ [
+ erlang_client_alpn_npn_openssl_server_alpn_npn,
+ erlang_server_alpn_npn_openssl_client_alpn_npn
+ ].
+rengotiation_tests() ->
+ case ssl_test_lib:sane_openssl_alpn_npn_renegotiate() of
+ true ->
+ [erlang_client_alpn_openssl_server_alpn_renegotiate,
+ erlang_server_alpn_openssl_client_alpn_renegotiate];
+ false ->
+ []
+ end.
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ case check_openssl_alpn_support(Config0) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate;
+ TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ ssl_test_lib:check_sane_openssl_renegotaite(Config, Version);
+special_init(TestCase, Config)
+ when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn;
+ TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn ->
+ ssl_test_lib:check_openssl_npn_support(Config);
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+erlang_client_alpn_openssl_server_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_server_alpn_openssl_client_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_client_alpn_openssl_server(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config,
+ [{alpn_advertised_protocols, [<<"spdy/2">>]}],
+ [],
+ Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_client_openssl_server_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config,
+ [],
+ ["-alpn", "spdy/2"],
+ Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_server_alpn_openssl_client(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config,
+ [{alpn_preferred_protocols, [<<"spdy/2">>]}],
+ [],
+ Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_server_openssl_client_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config,
+ [],
+ ["-alpn", "spdy/2"],
+ Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_client_alpn_openssl_server_alpn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_server_alpn_openssl_client_alpn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_client_alpn_npn_openssl_server_alpn_npn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_server_alpn_npn_openssl_client_alpn_npn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions -----------------------------------------------
+%%--------------------------------------------------------------------
+check_openssl_alpn_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case string:str(HelpText, "alpn") of
+ 0 ->
+ {skip, "Openssl not compiled with alpn support"};
+ _ ->
+ Config
+ end.
+
+start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0],
+
+ {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),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile],
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ Callback(Client, OpensslPort),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
+start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]} | ServerOpts0],
+
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client", "-alpn", "http/1.0,spdy/2", "-msg", "-port",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-host", "localhost"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
+start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]},
+ {client_preferred_next_protocols, {client, [<<"spdy/3">>, <<"http/1.1">>]}} | ClientOpts0],
+
+ {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),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg",
+ "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ Callback(Client, OpensslPort),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
+start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]},
+ {next_protocols_advertised, [<<"spdy/3">>, <<"http/1.1">>]} | ServerOpts0],
+
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3",
+ "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-host", "localhost"],
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
diff --git a/lib/ssl/test/openssl_cipher_suite_SUITE.erl b/lib/ssl/test/openssl_cipher_suite_SUITE.erl
new file mode 100644
index 0000000000..955eb914c0
--- /dev/null
+++ b/lib/ssl/test/openssl_cipher_suite_SUITE.erl
@@ -0,0 +1,801 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(openssl_cipher_suite_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, openssl_server},
+ {group, openssl_client}
+ ].
+
+all_protocol_groups() ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ %% TODO: Enable SRP, PSK suites (needs OpenSSL s_server conf)
+ %% TODO: Enable all "kex" on DTLS
+ [
+ {openssl_server, all_protocol_groups()},
+ {openssl_client, all_protocol_groups()},
+ {'tlsv1.2', [], kex()},
+ {'tlsv1.1', [], kex()},
+ {'tlsv1', [], kex()},
+ {'sslv3', [], kex()},
+ {'dtlsv1.2', [], dtls_kex()},
+ {'dtlsv1', [], dtls_kex()},
+ {dhe_rsa, [],[dhe_rsa_3des_ede_cbc,
+ dhe_rsa_aes_128_cbc,
+ dhe_rsa_aes_256_cbc,
+ dhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc,
+ ecdhe_rsa_aes_128_cbc,
+ ecdhe_rsa_aes_128_gcm,
+ ecdhe_rsa_aes_256_cbc,
+ ecdhe_rsa_aes_256_gcm,
+ ecdhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128,
+ ecdhe_ecdsa_3des_ede_cbc,
+ ecdhe_ecdsa_aes_128_cbc,
+ ecdhe_ecdsa_aes_128_gcm,
+ ecdhe_ecdsa_aes_256_cbc,
+ ecdhe_ecdsa_aes_256_gcm,
+ ecdhe_ecdsa_chacha20_poly1305
+ ]},
+ {rsa, [], [rsa_3des_ede_cbc,
+ rsa_aes_128_cbc,
+ rsa_aes_256_cbc,
+ rsa_rc4_128
+ ]},
+ {dhe_dss, [], [dhe_dss_3des_ede_cbc,
+ dhe_dss_aes_128_cbc,
+ dhe_dss_aes_256_cbc]},
+ %% {srp_rsa, [], [srp_rsa_3des_ede_cbc,
+ %% srp_rsa_aes_128_cbc,
+ %% srp_rsa_aes_256_cbc]},
+ %% {srp_dss, [], [srp_dss_3des_ede_cbc,
+ %% srp_dss_aes_128_cbc,
+ %% srp_dss_aes_256_cbc]},
+ %% {rsa_psk, [], [rsa_psk_3des_ede_cbc,
+ %% rsa_psk_rc4_128,
+ %% rsa_psk_aes_128_cbc,
+ %% rsa_psk_aes_256_cbc
+ %% ]},
+ {dh_anon, [], [dh_anon_rc4_128,
+ dh_anon_3des_ede_cbc,
+ dh_anon_aes_128_cbc,
+ dh_anon_aes_128_gcm,
+ dh_anon_aes_256_cbc,
+ dh_anon_aes_256_gcm]},
+ {ecdh_anon, [], [ecdh_anon_3des_ede_cbc,
+ ecdh_anon_aes_128_cbc,
+ ecdh_anon_aes_256_cbc
+ ]}
+ %% {srp_anon, [], [srp_anon_3des_ede_cbc,
+ %% srp_anon_aes_128_cbc,
+ %% srp_anon_aes_256_cbc]},
+ %% {psk, [], [psk_3des_ede_cbc,
+ %% psk_rc4_128,
+ %% psk_aes_128_cbc,
+ %% psk_aes_128_ccm,
+ %% psk_aes_128_ccm_8,
+ %% psk_aes_256_cbc,
+ %% psk_aes_256_ccm,
+ %% psk_aes_256_ccm_8
+ %% ]},
+ %% {dhe_psk, [], [dhe_psk_3des_ede_cbc,
+ %% dhe_psk_rc4_128,
+ %% dhe_psk_aes_128_cbc,
+ %% dhe_psk_aes_128_ccm,
+ %% dhe_psk_aes_128_ccm_8,
+ %% dhe_psk_aes_256_cbc,
+ %% dhe_psk_aes_256_ccm,
+ %% dhe_psk_aes_256_ccm_8
+ %% ]},
+ %% {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc,
+ %% ecdhe_psk_rc4_128,
+ %% ecdhe_psk_aes_128_cbc,
+ %% ecdhe_psk_aes_128_ccm,
+ %% ecdhe_psk_aes_128_ccm_8,
+ %% ecdhe_psk_aes_256_cbc
+ %% ]}
+ ].
+
+kex() ->
+ rsa() ++ ecdsa() ++ dss() ++ anonymous().
+
+dtls_kex() -> %% Should be all kex in the future
+ dtls_rsa() ++ dss() ++ anonymous().
+
+ssl3_kex() ->
+ ssl3_rsa() ++ ssl3_dss() ++ ssl3_anonymous().
+
+rsa() ->
+ [{group, dhe_rsa},
+ {group, ecdhe_rsa},
+ {group, rsa} %%, {group, srp_rsa},
+ %%{group, rsa_psk}
+ ].
+
+dtls_rsa() ->
+ [
+ {group, rsa}
+ %%,{group, rsa_psk}
+ ].
+
+ssl3_rsa() ->
+ [{group, dhe_rsa},
+ {group, rsa}
+ ].
+
+ecdsa() ->
+ [{group, ecdhe_ecdsa}].
+
+dss() ->
+ [{group, dhe_dss}
+ %%{group, srp_dss}
+ ].
+
+ssl3_dss() ->
+ [{group, dhe_dss}
+ ].
+
+anonymous() ->
+ [{group, dh_anon},
+ {group, ecdh_anon}
+ %% {group, psk},
+ %%{group, dhe_psk},
+ %%{group, ecdhe_psk}
+ %%{group, srp_anon}
+ ].
+
+ssl3_anonymous() ->
+ [{group, dh_anon}].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+%%--------------------------------------------------------------------
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config),
+ do_init_per_group(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, {openssl_does_not_support, GroupName}}
+ end;
+ false ->
+ do_init_per_group(GroupName, Config)
+ end.
+do_init_per_group(openssl_client, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, openssl}, {server_type, erlang} | Config];
+do_init_per_group(openssl_server, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, erlang}, {server_type, openssl} | Config];
+do_init_per_group(GroupName, Config) when GroupName == ecdh_anon;
+ GroupName == ecdhe_rsa;
+ GroupName == ecdhe_psk ->
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+do_init_per_group(ecdhe_ecdsa = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+do_init_per_group(dhe_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+do_init_per_group(srp_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS_SRP crypto support"}
+ end;
+do_init_per_group(GroupName, Config) when GroupName == srp_anon;
+ GroupName == srp_rsa ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+do_init_per_group(dhe_psk = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+do_init_per_group(GroupName, Config0) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, end_per_group(GroupName, Config0));
+ false ->
+ init_certs(GroupName, Config0)
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc;
+ TestCase == srp_anon_3des_ede_cbc;
+ TestCase == dhe_psk_3des_ede_cbc;
+ TestCase == ecdhe_psk_3des_ede_cbc;
+ TestCase == srp_rsa_3des_ede_cbc;
+ TestCase == srp_dss_3des_ede_cbc;
+ TestCase == rsa_psk_3des_ede_cbc;
+ TestCase == rsa_3des_ede_cbc;
+ TestCase == dhe_rsa_3des_ede_cbc;
+ TestCase == dhe_dss_3des_ede_cbc;
+ TestCase == ecdhe_rsa_3des_ede_cbc;
+ TestCase == srp_anon_dss_3des_ede_cbc;
+ TestCase == dh_anon_3des_ede_cbc;
+ TestCase == ecdh_anon_3des_ede_cbc;
+ TestCase == ecdhe_ecdsa_3des_ede_cbc ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(des_ede3, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing 3DES crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128;
+ TestCase == ecdhe_psk_rc4_128;
+ TestCase == dhe_psk_rc4_128;
+ TestCase == rsa_psk_rc4_128;
+ TestCase == rsa_rc4_128;
+ TestCase == ecdhe_rsa_rc4_128;
+ TestCase == ecdhe_ecdsa_rc4_128;
+ TestCase == dh_anon_rc4_128 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(rc4, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing RC4 crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8;
+ TestCase == rsa_psk_aes_128_ccm_8;
+ TestCase == psk_aes_128_ccm_8;
+ TestCase == dhe_psk_aes_128_ccm_8;
+ TestCase == ecdhe_psk_aes_128_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_128_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8;
+ TestCase == rsa_psk_aes_256_ccm_8;
+ TestCase == psk_aes_256_ccm_8;
+ TestCase == dhe_psk_aes_256_ccm_8;
+ TestCase == ecdhe_psk_aes_256_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_256_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_256_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) ->
+ Cipher = ssl_test_lib:test_cipher(TestCase, Config),
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(Cipher, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, {Cipher, SupCiphers}}
+ end.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Initializtion ------------------------------------------
+%%--------------------------------------------------------------------
+init_certs(srp_rsa, Config) ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_anon, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa_psk, Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[ssl_test_lib:digest()],[ssl_test_lib:digest()],
+ [ssl_test_lib:digest(), {extensions, Ext}]]},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, "_peer_keyEncipherment"),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ServerOpts],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa, Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[ssl_test_lib:digest()],[ssl_test_lib:digest()],
+ [ssl_test_lib:digest(), {extensions, Ext}]]}
+ ],
+ Config, "_peer_keyEncipherment"),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(dhe_dss, Config) ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_dss, Config) ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_rsa;
+ GroupName == ecdhe_rsa ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_ecdsa;
+ GroupName == ecdhe_ecdsa ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_ecc_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == psk;
+ GroupName == dhe_psk;
+ GroupName == ecdhe_psk ->
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(_GroupName, Config) ->
+ %% Anonymous does not need certs
+ [{tls_config, #{server_config => [],
+ client_config => []}} |
+ proplists:delete(tls_config, Config)].
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% SRP --------------------------------------------------------
+%%--------------------------------------------------------------------
+srp_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, '3des_ede_cbc', Config).
+
+srp_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_128_cbc', Config).
+
+srp_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_256_cbc', Config).
+
+srp_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, '3des_ede_cbc', Config).
+
+srp_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_128_cbc', Config).
+
+srp_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_256_cbc', Config).
+
+%%--------------------------------------------------------------------
+%% PSK --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, '3des_ede_cbc', Config).
+
+rsa_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_cbc', Config).
+
+rsa_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm', Config).
+
+rsa_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm_8', Config).
+
+rsa_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_cbc', Config).
+
+rsa_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm', Config).
+
+rsa_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm_8', Config).
+
+rsa_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'rc4_128', Config).
+
+%%--------------------------------------------------------------------
+%% RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'des_cbc', Config).
+
+rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, '3des_ede_cbc', Config).
+
+rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_cbc', Config).
+
+rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_cbc', Config).
+
+rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_gcm', Config).
+
+rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_gcm', Config).
+
+rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'rc4_128', Config).
+%%--------------------------------------------------------------------
+%% DHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, '3des_ede_cbc', Config).
+
+dhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_cbc', Config).
+
+dhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_gcm', Config).
+
+dhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config).
+
+dhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config).
+
+dhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% ECDHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, '3des_ede_cbc', Config).
+
+ecdhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_cbc', Config).
+
+ecdhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_gcm', Config).
+
+ecdhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_cbc', Config).
+
+ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_gcm', Config).
+
+ecdhe_rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'rc4_128', Config).
+
+ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config).
+
+%%--------------------------------------------------------------------
+%% ECDHE_ECDSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_ecdsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'rc4_128', Config).
+
+ecdhe_ecdsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, '3des_ede_cbc', Config).
+
+ecdhe_ecdsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_cbc', Config).
+
+ecdhe_ecdsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_gcm', Config).
+
+ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_cbc', Config).
+
+ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config).
+
+ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% DHE_DSS --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_dss_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'des_cbc', Config).
+
+dhe_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, '3des_ede_cbc', Config).
+
+dhe_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_cbc', Config).
+
+dhe_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_cbc', Config).
+
+dhe_dss_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_gcm', Config).
+
+dhe_dss_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_gcm', Config).
+
+%%--------------------------------------------------------------------
+%% Anonymous --------------------------------------------------------
+%%--------------------------------------------------------------------
+dh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, '3des_ede_cbc', Config).
+
+dh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_cbc', Config).
+
+dh_anon_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_gcm', Config).
+
+dh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_cbc', Config).
+
+dh_anon_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_gcm', Config).
+
+dh_anon_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'rc4_128', Config).
+
+ecdh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, '3des_ede_cbc', Config).
+
+ecdh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_128_cbc', Config).
+
+ecdh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config).
+
+srp_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, '3des_ede_cbc', Config).
+
+srp_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_128_cbc', Config).
+
+srp_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_256_cbc', Config).
+
+dhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'des_cbc', Config).
+
+dhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'rc4_128', Config).
+
+dhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, '3des_ede_cbc', Config).
+
+dhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_cbc', Config).
+
+dhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_cbc', Config).
+
+dhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_gcm', Config).
+
+dhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_gcm', Config).
+
+dhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm', Config).
+
+dhe_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm', Config).
+
+dhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm_8', Config).
+
+dhe_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config).
+
+ecdhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'des_cbc', Config).
+
+ecdhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'rc4_128', Config).
+
+ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config).
+
+ecdhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config).
+
+ecdhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config).
+
+ecdhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config).
+
+ecdhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config).
+
+ecdhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config).
+
+ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config).
+
+psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'des_cbc', Config).
+
+psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'rc4_128', Config).
+
+psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, '3des_ede_cbc', Config).
+
+psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_cbc', Config).
+
+psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_cbc', Config).
+
+psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_gcm', Config).
+
+psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_gcm', Config).
+
+psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm', Config).
+
+psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm', Config).
+
+psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm_8', Config).
+
+psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm_8', Config).
+
+%%--------------------------------------------------------------------
+%% Internal functions ----------------------------------------------
+%%--------------------------------------------------------------------
+run_ciphers_test(Kex, Cipher, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ TestCiphers = test_ciphers(Kex, Cipher, Version),
+
+ case TestCiphers of
+ [_|_] ->
+ lists:foreach(fun(TestCipher) ->
+ cipher_suite_test(TestCipher, Version, Config)
+ end, TestCiphers);
+ [] ->
+ {skip, {not_sup, Kex, Cipher, Version}}
+ end.
+
+cipher_suite_test(CipherSuite, _Version, Config) ->
+ #{server_config := SOpts,
+ client_config := COpts} = proplists:get_value(tls_config, Config),
+ ServerOpts = ssl_test_lib:ssl_options(SOpts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(COpts, Config),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Server Opts ~p~n", [ServerOpts]),
+ ct:log("Client Opts ~p~n", [ClientOpts]),
+ ssl_test_lib:basic_test([{ciphers, [CipherSuite]} | COpts], SOpts, Config).
+
+
+test_ciphers(Kex, Cipher, Version) ->
+ Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, Version) ++ ssl:cipher_suites(anonymous, Version),
+ [{key_exchange,
+ fun(Kex0) when Kex0 == Kex -> true;
+ (_) -> false
+ end},
+ {cipher,
+ fun(Cipher0) when Cipher0 == Cipher -> true;
+ (_) -> false
+ end}]),
+ ct:log("Version ~p Testing ~p~n", [Version, Ciphers]),
+ OpenSSLCiphers = openssl_ciphers(),
+ ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]),
+ lists:filter(fun(C) ->
+ ct:log("Cipher ~p~n", [C]),
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers)
+ end, Ciphers).
+
+
+openssl_ciphers() ->
+ Str = os:cmd("openssl ciphers"),
+ string:split(string:strip(Str, right, $\n), ":", all).
diff --git a/lib/ssl/test/openssl_client_cert_SUITE.erl b/lib/ssl/test/openssl_client_cert_SUITE.erl
new file mode 100644
index 0000000000..b327988744
--- /dev/null
+++ b/lib/ssl/test/openssl_client_cert_SUITE.erl
@@ -0,0 +1,350 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(openssl_client_cert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, openssl_client}
+ ].
+
+groups() ->
+ [
+ {openssl_client, [], protocol_groups()},
+ {'tlsv1.3', [], tls_1_3_protocol_groups()},
+ {'tlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1.1', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1', [], pre_tls_1_3_protocol_groups()},
+ {'sslv3', [], ssl_protocol_groups()},
+ {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'dtlsv1', [], pre_tls_1_3_protocol_groups()},
+ {rsa, [], all_version_tests()},
+ {ecdsa, [], all_version_tests()},
+ {dsa, [], all_version_tests()},
+ {rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_client_auth,
+ unsupported_sign_algo_cert_client_auth]},
+ {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
+ ].
+
+protocol_groups() ->
+ [{group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+ssl_protocol_groups() ->
+ [{group, rsa},
+ {group, dsa}].
+
+pre_tls_1_3_protocol_groups() ->
+ [{group, rsa},
+ {group, ecdsa},
+ {group, dsa}].
+
+tls_1_3_protocol_groups() ->
+ [{group, rsa_1_3},
+ {group, ecdsa_1_3}].
+
+tls_1_3_tests() ->
+ [
+ hello_retry_request,
+ custom_groups,
+ hello_retry_client_auth,
+ hello_retry_client_auth_empty_cert_accepted,
+ hello_retry_client_auth_empty_cert_rejected
+ ].
+
+all_version_tests() ->
+ [
+ no_auth,
+ auth,
+ client_auth_empty_cert_accepted,
+ client_auth_empty_cert_rejected,
+ client_auth_partial_chain,
+ client_auth_allow_partial_chain,
+ client_auth_do_not_allow_partial_chain,
+ client_auth_partial_chain_fun_fail,
+ missing_root_cert_no_auth
+ %%invalid_signature_client
+ ].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(openssl_client, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, openssl}, {server_type, erlang} | Config];
+init_per_group(Group, Config0) when Group == rsa;
+ Group == rsa_1_3 ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dhe_rsa) ->
+ true;
+ (ecdhe_rsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+init_per_group(Group, Config0) when Group == ecdsa;
+ Group == ecdsa_1_3 ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse
+ lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(ecdh_ecdsa) ->
+ true;
+ (ecdhe_ecdsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(Group, Config0) when Group == dsa ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ Config = ssl_test_lib:make_dsa_cert(Config0),
+ COpts = proplists:get_value(client_dsa_opts, Config),
+ SOpts = proplists:get_value(server_dsa_opts, Config),
+ %% Make sure dhe_dss* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dh_dss) ->
+ true;
+ (dhe_dss) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, dsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ [{version, GroupName}
+ | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing openssl support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+init_per_testcase(TestCase, Config) when
+ TestCase == client_auth_empty_cert_accepted;
+ TestCase == client_auth_empty_cert_rejected ->
+ Version = proplists:get_value(version,Config),
+ case Version of
+ sslv3 ->
+ %% Openssl client sends "No Certificate Reserved" warning ALERT
+ %% instead of sending EMPTY cert message in SSL-3.0 so empty cert test are not
+ %% relevant
+ {skip, openssl_behaves_differently};
+ _ ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config
+ end;
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+no_auth() ->
+ ssl_cert_tests:no_auth().
+
+no_auth(Config) ->
+ ssl_cert_tests:no_auth(Config).
+%%--------------------------------------------------------------------
+auth() ->
+ ssl_cert_tests:auth().
+auth(Config) ->
+ ssl_cert_tests:auth(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:client_auth_empty_cert_accepted().
+client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:client_auth_empty_cert_rejected().
+client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_rejected(Config).
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ ssl_cert_tests:client_auth_partial_chain().
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_allow_partial_chain().
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_allow_partial_chain(Config).
+%%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain().
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail().
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail(Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ ssl_cert_tests:missing_root_cert_no_auth().
+missing_root_cert_no_auth(Config) when is_list(Config) ->
+ ssl_cert_tests:missing_root_cert_no_auth(Config).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_client(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_server(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test Cases ------------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ ssl_cert_tests:hello_retry_request().
+hello_retry_request(Config) ->
+ ssl_cert_tests:hello_retry_request(Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ ssl_cert_tests:custom_groups().
+custom_groups(Config) ->
+ ssl_cert_tests:custom_groups(Config).
+unsupported_sign_algo_cert_client_auth() ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth().
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth(Config).
+unsupported_sign_algo_client_auth() ->
+ ssl_cert_tests:unsupported_sign_algo_client_auth().
+unsupported_sign_algo_client_auth(Config) ->
+ ssl_cert_tests:unsupported_sign_algo_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ ssl_cert_tests:hello_retry_client_auth().
+hello_retry_client_auth(Config) ->
+ ssl_cert_tests:hello_retry_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted().
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected().
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(Config).
diff --git a/lib/ssl/test/openssl_npn_SUITE.erl b/lib/ssl/test/openssl_npn_SUITE.erl
new file mode 100644
index 0000000000..0294f4997f
--- /dev/null
+++ b/lib/ssl/test/openssl_npn_SUITE.erl
@@ -0,0 +1,311 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(openssl_npn_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(SLEEP, 1000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ %% NPN is not supported in TLS-1.3 (replaced by ALPN and deprecated in TLS 1.2)
+ %% OpenSSL DTLS support for NPN is either not there or broken.
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}].
+
+groups() ->
+ [{'tlsv1.2', [], npn_tests() ++ npn_renegotiate_tests()},
+ {'tlsv1.1', [], npn_tests() ++ npn_renegotiate_tests()},
+ {'tlsv1', [], npn_tests() ++ npn_renegotiate_tests()}
+ ].
+
+npn_tests() ->
+ [erlang_client_openssl_server_npn,
+ erlang_server_openssl_client_npn,
+ erlang_server_openssl_client_npn_only_client,
+ erlang_server_openssl_client_npn_only_server,
+ erlang_client_openssl_server_npn_only_client,
+ erlang_client_openssl_server_npn_only_server].
+
+npn_renegotiate_tests() ->
+ case ssl_test_lib:sane_openssl_alpn_npn_renegotiate() of
+ true ->
+ [erlang_server_openssl_client_npn_renegotiate,
+ erlang_client_openssl_server_npn_renegotiate];
+ false ->
+ []
+ end.
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ case check_openssl_npn_support(Config0) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_npn_openssl_server_npn_renegotiate;
+ TestCase == erlang_server_npn_openssl_client_npn_renegotiate ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ ssl_test_lib:check_sane_openssl_renegotaite(Config, Version);
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+erlang_client_openssl_server_npn() ->
+ [{doc,"Test erlang client with openssl server doing npn negotiation"}].
+
+erlang_client_openssl_server_npn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data,
+ fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_npn_renegotiate() ->
+ [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}].
+
+erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data,
+ fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort,
+ ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn() ->
+ [{doc,"Test erlang server with openssl client and npn negotiation"}].
+
+erlang_server_openssl_client_npn(Config) when is_list(Config) ->
+
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn_renegotiate() ->
+ [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}].
+
+erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort,
+ ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+%%--------------------------------------------------------------------------
+erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config, [],
+ ["-nextprotoneg", "spdy/2"], Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config,
+ [{client_preferred_next_protocols,
+ {client, [<<"spdy/2">>], <<"http/1.1">>}}], [],
+ Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config,
+ [{next_protocols_advertised, [<<"spdy/2">>]}], [],
+ Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config, [], ["-nextprotoneg", "spdy/2"],
+ Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------
+%% Internal functions -----------------------------------------------
+%%--------------------------------------------------------------------
+
+start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0],
+
+ {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),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile],
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ClientOpts}]),
+
+ Callback(Client, OpensslPort),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
+start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>]} | ServerOpts0],
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client", "-nextprotoneg", "http/1.0,spdy/2", "-msg", "-connect",
+ ssl_test_lib:hostname_format(Hostname) ++ ":"
+ ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
+check_openssl_npn_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case string:str(HelpText, "nextprotoneg") of
+ 0 ->
+ {skip, "Openssl not compiled with nextprotoneg support"};
+ _ ->
+ Config
+ end.
diff --git a/lib/ssl/test/openssl_reject_SUITE.erl b/lib/ssl/test/openssl_reject_SUITE.erl
new file mode 100644
index 0000000000..deefd11823
--- /dev/null
+++ b/lib/ssl/test/openssl_reject_SUITE.erl
@@ -0,0 +1,209 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(openssl_reject_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(SLEEP, 1000).
+-define(OPENSSL_GARBAGE, "P\n").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}].
+
+groups() ->
+ [{'tlsv1.2', [], all_versions_tests()},
+ {'tlsv1.1', [], all_versions_tests()},
+ {'tlsv1', [], all_versions_tests()},
+ {'sslv3', [], all_versions_tests()}
+ ].
+
+all_versions_tests() ->
+ [
+ erlang_client_bad_openssl_server,
+ ssl2_erlang_server_openssl_client
+ ].
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(ssl2_erlang_server_openssl_client, Config) ->
+ case ssl_test_lib:supports_ssl_tls_version(sslv2) of
+ true ->
+ Config;
+ false ->
+ {skip, "sslv2 not supported by openssl"}
+ end;
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+erlang_client_bad_openssl_server() ->
+ [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}].
+erlang_client_bad_openssl_server(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_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),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile],
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, server_sent_garbage, []}},
+ {options,
+ [{versions, [Version]} | ClientOpts]}]),
+
+ %% Send garbage
+ true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
+
+ ct:sleep(?SLEEP),
+
+ Client0 ! server_sent_garbage,
+
+ ssl_test_lib:check_result(Client0, true),
+
+ ssl_test_lib:close(Client0),
+
+ %% Make sure openssl does not hang and leave zombie process
+ Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options,
+ [{versions, [Version]} | ClientOpts]}]),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client1),
+ process_flag(trap_exit, false).
+
+%%--------------------------------------------------------------------
+ssl2_erlang_server_openssl_client() ->
+ [{doc,"Test that ssl v2 clients are rejected"}].
+
+ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Exe = "openssl",
+ Args = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ "-ssl2", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
+ ssl_test_lib:consume_port_exit(OpenSslPort),
+ ssl_test_lib:check_server_alert(Server, unexpected_message),
+ process_flag(trap_exit, false).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+server_sent_garbage(Socket) ->
+ receive
+ server_sent_garbage ->
+ {error, closed} == ssl:send(Socket, "data")
+
+ end.
diff --git a/lib/ssl/test/openssl_renegotiate_SUITE.erl b/lib/ssl/test/openssl_renegotiate_SUITE.erl
new file mode 100644
index 0000000000..91a8175ac6
--- /dev/null
+++ b/lib/ssl/test/openssl_renegotiate_SUITE.erl
@@ -0,0 +1,341 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(openssl_renegotiate_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(SLEEP, 1000).
+-define(OPENSSL_RENEGOTIATE, "R\n").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], all_versions_tests()},
+ {'tlsv1.1', [], all_versions_tests()},
+ {'tlsv1', [], all_versions_tests()},
+ {'sslv3', [], all_versions_tests()},
+ {'dtlsv1.2', [], all_versions_tests()},
+ {'dtlsv1', [], all_versions_tests()}
+ ];
+ false ->
+ [{'tlsv1.2', [], all_versions_tests()},
+ {'tlsv1.1', [], all_versions_tests()},
+ {'tlsv1', [], all_versions_tests()},
+ {'sslv3', [], all_versions_tests()}
+ ]
+ end.
+
+all_versions_tests() ->
+ [
+ erlang_client_openssl_server_renegotiate,
+ erlang_client_openssl_server_renegotiate_after_client_data,
+ erlang_client_openssl_server_nowrap_seqnum,
+ erlang_server_openssl_client_nowrap_seqnum
+ ].
+
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_openssl_server_renegotiate;
+ TestCase == erlang_client_openssl_server_nowrap_seqnum;
+ TestCase == erlang_server_openssl_client_nowrap_seqnum;
+ TestCase == erlang_client_openssl_server_renegotiate_after_client_data
+ ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ ssl_test_lib:check_sane_openssl_renegotaite(Config, Version);
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+erlang_client_openssl_server_renegotiate() ->
+ [{doc,"Test erlang client when openssl server issuses a renegotiate"}].
+erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to openssl",
+ OpenSslData = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ delayed_send, [[ErlData, OpenSslData]]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, OpenSslData),
+
+ ssl_test_lib:check_result(Client, OpenSslData),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false),
+ ok.
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_renegotiate_after_client_data() ->
+ [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}].
+erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to openssl",
+ OpenSslData = "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),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_wait_send, [[ErlData, OpenSslData]]}},
+ {options, [{reuse_sessions, false} |ClientOpts]}]),
+
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, OpenSslData),
+
+ ssl_test_lib:check_result(Client, OpenSslData),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false),
+ ok.
+
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_nowrap_seqnum() ->
+ [{doc, "Test that erlang client will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to openssl\n",
+ N = 10,
+
+ 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),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[ErlData, N+2]]}},
+ {options, [{reuse_sessions, false},
+ {renegotiate_at, N} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+%%--------------------------------------------------------------------
+erlang_server_openssl_client_nowrap_seqnum() ->
+ [{doc, "Test that erlang client will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ N = 10,
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[Data, N+2]]}},
+ {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client","-connect", ssl_test_lib:hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+delayed_send(Socket, [ErlData, OpenSslData]) ->
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, ErlData),
+ ssl_test_lib:active_recv(Socket, length(OpenSslData)).
+
+
+send_wait_send(Socket, [ErlData, OpenSslData]) ->
+ ssl:send(Socket, ErlData),
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, ErlData),
+ ssl_test_lib:active_recv(Socket, length(OpenSslData)).
+
diff --git a/lib/ssl/test/openssl_server_cert_SUITE.erl b/lib/ssl/test/openssl_server_cert_SUITE.erl
new file mode 100644
index 0000000000..c2af864a92
--- /dev/null
+++ b/lib/ssl/test/openssl_server_cert_SUITE.erl
@@ -0,0 +1,373 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(openssl_server_cert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, openssl_server}].
+
+groups() ->
+ [
+ {openssl_server, [], protocol_groups()},
+ {'tlsv1.3', [], tls_1_3_protocol_groups()},
+ {'tlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1.1', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1', [], pre_tls_1_3_protocol_groups()},
+ {'sslv3', [], ssl_protocol_groups()},
+ {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'dtlsv1', [], pre_tls_1_3_protocol_groups()},
+ {rsa, [], all_version_tests()},
+ {ecdsa, [], all_version_tests()},
+ {dsa, [], all_version_tests()},
+ {rsa_1_3, [], all_version_tests() ++ tls_1_3_tests()},
+ %% TODO: Create proper conf of openssl server
+ %%++ [unsupported_sign_algo_client_auth,
+ %% unsupported_sign_algo_cert_client_auth]},
+ {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
+ ].
+
+protocol_groups() ->
+ [{group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+ssl_protocol_groups() ->
+ [{group, rsa},
+ {group, dsa}].
+
+pre_tls_1_3_protocol_groups() ->
+ [{group, rsa},
+ {group, ecdsa},
+ {group, dsa}].
+
+tls_1_3_protocol_groups() ->
+ [{group, rsa_1_3},
+ {group, ecdsa_1_3}].
+
+tls_1_3_tests() ->
+ [
+ hello_retry_request,
+ custom_groups,
+ hello_retry_client_auth,
+ hello_retry_client_auth_empty_cert_accepted,
+ hello_retry_client_auth_empty_cert_rejected
+ ].
+
+all_version_tests() ->
+ [
+ no_auth,
+ auth,
+ missing_root_cert_no_auth
+ %%invalid_signature_client
+ ].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(openssl_server, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, erlang}, {server_type, openssl} | Config];
+init_per_group(rsa = Group, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dhe_rsa) ->
+ true;
+ (ecdhe_rsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+init_per_group(rsa_1_3 = Group, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(undefined, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+init_per_group(ecdsa = Group, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse
+ lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(ecdh_ecdsa) ->
+ true;
+ (ecdhe_ecdsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(ecdsa_1_3 = Group, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse
+ lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(undefined, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(Group, Config0) when Group == dsa ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ Config = ssl_test_lib:make_dsa_cert(Config0),
+ COpts = proplists:get_value(client_dsa_opts, Config),
+ SOpts = proplists:get_value(server_dsa_opts, Config),
+ %% Make sure dhe_dss* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dh_dss) ->
+ true;
+ (dhe_dss) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, dsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ [{version, GroupName}
+ | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing openssl support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+no_auth() ->
+ ssl_cert_tests:no_auth().
+
+no_auth(Config) ->
+ ssl_cert_tests:no_auth(Config).
+%%--------------------------------------------------------------------
+auth() ->
+ ssl_cert_tests:auth().
+auth(Config) ->
+ ssl_cert_tests:auth(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:client_auth_empty_cert_accepted().
+client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:client_auth_empty_cert_rejected().
+client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_rejected(Config).
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ ssl_cert_tests:client_auth_partial_chain().
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_allow_partial_chain().
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_allow_partial_chain(Config).
+%%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain().
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail().
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail(Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ ssl_cert_tests:missing_root_cert_no_auth().
+missing_root_cert_no_auth(Config) when is_list(Config) ->
+ ssl_cert_tests:missing_root_cert_no_auth(Config).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_client(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_server(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test Cases ------------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ ssl_cert_tests:hello_retry_request().
+hello_retry_request(Config) ->
+ ssl_cert_tests:hello_retry_request(Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ ssl_cert_tests:custom_groups().
+custom_groups(Config) ->
+ ssl_cert_tests:custom_groups(Config).
+unsupported_sign_algo_cert_client_auth() ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth().
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth(Config).
+unsupported_sign_algo_client_auth() ->
+ ssl_cert_tests:unsupported_sign_algo_client_auth().
+unsupported_sign_algo_client_auth(Config) ->
+ ssl_cert_tests:unsupported_sign_algo_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ ssl_cert_tests:hello_retry_client_auth().
+hello_retry_client_auth(Config) ->
+ ssl_cert_tests:hello_retry_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted().
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected().
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(Config).
diff --git a/lib/ssl/test/openssl_session_SUITE.erl b/lib/ssl/test/openssl_session_SUITE.erl
new file mode 100644
index 0000000000..24dcaa7817
--- /dev/null
+++ b/lib/ssl/test/openssl_session_SUITE.erl
@@ -0,0 +1,262 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(openssl_session_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(SLEEP, 1000).
+-define(EXPIRE, 10).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], tests()},
+ {'tlsv1.1', [], tests()},
+ {'tlsv1', [], tests()},
+ {'sslv3', [], tests()},
+ {'dtlsv1.2', [], dtls_tests()},
+ {'dtlsv1', [], dtls_tests()}
+ ];
+ false ->
+ [{'tlsv1.2', [], tests()},
+ {'tlsv1.1', [], tests()},
+ {'tlsv1', [], tests()},
+ {'sslv3', [], tests()}
+ ]
+ end.
+
+tests() ->
+ [
+ reuse_session_erlang_server,
+ reuse_session_erlang_client
+ ].
+
+dtls_tests() ->
+ [
+ reuse_session_erlang_server
+ ].
+
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(reuse_session_erlang_client, Config) ->
+ ct:timetrap(?EXPIRE * 1000 * 5),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, session_lifetime, ?EXPIRE),
+ ssl:start(),
+ Config;
+
+init_per_testcase(TestCase, Config) ->
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(reuse_session_erlang_client, Config) ->
+ application:unset_env(ssl, session_lifetime),
+ Config;
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+reuse_session_erlang_server() ->
+ [{doc, "Test erlang server with openssl client that reconnects with the"
+ "same session id, to test reusing of sessions."}].
+reuse_session_erlang_server(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, active_recv, [length(Data)]}},
+ {reconnect_times, 5},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
+ ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-reconnect"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, Data),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort).
+
+%%--------------------------------------------------------------------
+
+reuse_session_erlang_client() ->
+ [{doc, "Test erlang ssl client that wants to reuse sessions"}].
+reuse_session_erlang_client(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CACertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ "-cert", CertFile,"-key", KeyFile, "-CAfile", CACertFile],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, tls),
+
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save}, {verify, verify_peer}| ClientOpts]}]),
+
+ SID = receive
+ {Client0, Id0} ->
+ Id0
+ end,
+
+ ssl_test_lib:close(Client0),
+
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_session, SID} | ClientOpts]}]),
+ receive
+ {Client1, SID} ->
+ ok
+ after ?SLEEP ->
+ ct:fail(session_not_reused)
+ end,
+
+
+ ssl_test_lib:close(Client1),
+ %% Make sure session is unregistered due to expiration
+ ct:sleep(20000),
+
+ Client2 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client2, ID} ->
+ case ID of
+ SID ->
+ ct:fail(expired_session_reused);
+ _ ->
+ ok
+ end
+ end,
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client2).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/openssl_sni_SUITE.erl b/lib/ssl/test/openssl_sni_SUITE.erl
new file mode 100644
index 0000000000..26f08e36c0
--- /dev/null
+++ b/lib/ssl/test/openssl_sni_SUITE.erl
@@ -0,0 +1,251 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(openssl_sni_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(SLEEP, 1000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ %% Note: SNI not supported in sslv3
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}
+ %% Seems broken in openssl
+ %%{group, 'dtlsv1.2'},
+ %%{group, 'dtlsv1'}
+ ];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], sni_tests()},
+ {'tlsv1.1', [], sni_tests()},
+ {'tlsv1', [], sni_tests()}
+ %% Seems broken in openssl
+ %%{'dtlsv1.2', [], sni_tests()},
+ %%{'dtlsv1', [], sni_tests()}
+ ];
+ false ->
+ [{'tlsv1.2', [], sni_tests()},
+ {'tlsv1.1', [], sni_tests()},
+ {'tlsv1', [], sni_tests()}
+ ]
+ end.
+
+sni_tests() ->
+ [erlang_server_openssl_client_sni_match,
+ erlang_server_openssl_client_sni_match_fun,
+ erlang_server_openssl_client_sni_no_match,
+ erlang_server_openssl_client_sni_no_match_fun,
+ erlang_server_openssl_client_sni_no_header,
+ erlang_server_openssl_client_sni_no_header_fun].
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ case check_openssl_sni_support(Config0) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ [{sni_server_opts, [{sni_hosts,
+ [{"a.server", [
+ {certfile, proplists:get_value(certfile, RsaOpts)},
+ {keyfile, proplists:get_value(keyfile, RsaOpts)}
+ ]},
+ {"b.server", [
+ {certfile, proplists:get_value(certfile, RsaOpts)},
+ {keyfile, proplists:get_value(keyfile, RsaOpts)}
+ ]}
+ ]}]} | Config]
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 10}),
+ Config.
+
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+erlang_server_openssl_client_sni_no_header(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test(Config, undefined, undefined, "server Peer cert").
+
+erlang_server_openssl_client_sni_no_header_fun(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test_sni_fun(Config, undefined, undefined, "server Peer cert").
+
+erlang_server_openssl_client_sni_match(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test(Config, "a.server", "a.server", "server Peer cert").
+
+erlang_server_openssl_client_sni_match_fun(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test_sni_fun(Config, "a.server", "a.server", "server Peer cert").
+
+erlang_server_openssl_client_sni_no_match(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test(Config, "c.server", undefined, "server Peer cert").
+
+erlang_server_openssl_client_sni_no_match_fun(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test_sni_fun(Config, "c.server", undefined, "server Peer cert").
+
+
+erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p",
+ [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
+ ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
+ {options, ServerOptions}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Exe = "openssl",
+ ClientArgs = case SNIHostname of
+ undefined ->
+ openssl_client_args(Version, Hostname,Port);
+ _ ->
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
+ end,
+ ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
+
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname),
+ ssl_test_lib:close_port(ClientPort),
+ ssl_test_lib:close(Server),
+ ok.
+
+
+erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p",
+ [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
+ [{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config),
+ SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
+ ServerOptions = proplists:get_value(server_rsa_opts, Config) ++ [{sni_fun, SNIFun}],
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
+ {options, ServerOptions}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Exe = "openssl",
+ ClientArgs = case SNIHostname of
+ undefined ->
+ openssl_client_args(Version, Hostname,Port);
+ _ ->
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
+ end,
+
+ ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
+
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname),
+ ssl_test_lib:close_port(ClientPort),
+ ssl_test_lib:close(Server).
+
+send_and_hostname(SSLSocket) ->
+ ssl:send(SSLSocket, "OK"),
+ case ssl:connection_information(SSLSocket, [sni_hostname]) of
+ {ok, []} ->
+ undefined;
+ {ok, [{sni_hostname, Hostname}]} ->
+ Hostname
+ end.
+
+openssl_client_args(Version, Hostname, Port) ->
+ ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)].
+
+openssl_client_args(Version, Hostname, Port, ServerName) ->
+ ["s_client", "-connect", Hostname ++ ":" ++
+ integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName].
+
+check_openssl_sni_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case ssl_test_lib:is_sane_oppenssl_client() of
+ true ->
+ case string:str(HelpText, "-servername") of
+ 0 ->
+ {skip, "Current openssl doesn't support SNI"};
+ _ ->
+ Config
+ end;
+ false ->
+ {skip, "Current openssl doesn't support SNI or extension handling is flawed"}
+ end.
diff --git a/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl b/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl
new file mode 100644
index 0000000000..8a2692ec1d
--- /dev/null
+++ b/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl
@@ -0,0 +1,172 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(openssl_tls_1_3_version_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ %%{group, openssl_server},
+ {group, openssl_client}
+ ].
+
+groups() ->
+ [
+ %%{openssl_server, [{group, 'tlsv1.3'}]},
+ {openssl_client, [{group, 'tlsv1.3'}]},
+ {'tlsv1.3', [], cert_groups()},
+ {rsa, [], tests()},
+ {ecdsa, [], tests()}
+ ].
+
+cert_groups() ->
+ [{group, rsa},
+ {group, ecdsa}].
+
+tests() ->
+ [tls13_client_tls12_server,
+ %%tls13_client_with_ext_tls12_server,
+ tls12_client_tls13_server].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ case ssl_test_lib:check_sane_openssl_version('tlsv1.3') of
+ true ->
+ ssl_test_lib:clean_start(),
+ Config;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(openssl_client, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, openssl}, {server_type, erlang} | Config];
+init_per_group(openssl_server, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, erlang}, {server_type, openssl} | Config];
+init_per_group(rsa, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+init_per_group(ecdsa, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso
+ (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso
+ ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls13_client_tls12_server() ->
+ [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}].
+
+tls13_client_tls12_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%% tls13_client_with_ext_tls12_server() ->
+%% [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when "
+%% "client has TLS 1.3 specsific extensions"}].
+
+%% tls13_client_with_ext_tls12_server(Config) ->
+%% ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+%% ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+%% {ServerOpts, ClientOpts} =
+%% case proplists:get_value(client_type) of
+%% erlang ->
+%% {[{versions, ['tlsv1.2']}|ServerOpts0],
+%% [{versions, ['tlsv1.2','tlsv1.3']},
+%% {signature_algs_cert, [ecdsa_secp384r1_sha384,
+%% ecdsa_secp256r1_sha256,
+%% rsa_pss_rsae_sha256,
+%% rsa_pkcs1_sha256,
+%% {sha256,rsa},{sha256,dsa}]}|ClientOpts0]};
+%% openssl ->
+
+
+%% ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+tls12_client_tls13_server() ->
+ [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}].
+
+tls12_client_tls13_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
diff --git a/lib/ssl/test/property_test/ssl_eqc_cipher_format.erl b/lib/ssl/test/property_test/ssl_eqc_cipher_format.erl
new file mode 100644
index 0000000000..f225065ba6
--- /dev/null
+++ b/lib/ssl/test/property_test/ssl_eqc_cipher_format.erl
@@ -0,0 +1,96 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. 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_eqc_cipher_format).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+-define('TLS_v1.3', 'tlsv1.3').
+-define('TLS_v1.2', 'tlsv1.2').
+-define('TLS_v1.1', 'tlsv1.1').
+-define('TLS_v1', 'tlsv1').
+-define('SSL_v3', 'sslv3').
+
+%%--------------------------------------------------------------------
+%% Properties --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+prop_tls_cipher_suite_rfc_name() ->
+ ?FORALL({CipherSuite, TLSVersion}, ?LET(Version, tls_version(), {cipher_suite(Version), Version}),
+ case ssl:str_to_suite(ssl:suite_to_str(CipherSuite)) of
+ CipherSuite ->
+ true;
+ _ ->
+ false
+ end
+ ).
+
+prop_tls_cipher_suite_openssl_name() ->
+ ?FORALL({CipherSuite, TLSVersion}, ?LET(Version, tls_version(), {cipher_suite(Version), Version}),
+ case ssl:str_to_suite(ssl:suite_to_openssl_str(CipherSuite)) of
+ CipherSuite ->
+ true;
+ _ ->
+ false
+ end
+ ).
+
+
+%%--------------------------------------------------------------------
+%% Generators -----------------------------------------------
+%%--------------------------------------------------------------------
+tls_version() ->
+ oneof([?'TLS_v1.2', ?'TLS_v1.1', ?'TLS_v1', ?'SSL_v3']).
+
+cipher_suite(Version) ->
+ oneof(cipher_suites(Version)).
+
+cipher_suites(Version) ->
+ ssl:cipher_suites(all, Version).
+
diff --git a/lib/ssl/test/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
new file mode 100644
index 0000000000..2ceb540e15
--- /dev/null
+++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
@@ -0,0 +1,883 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. 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_eqc_handshake).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+-include_lib("kernel/include/inet.hrl").
+-include_lib("ssl/src/tls_handshake_1_3.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+-include_lib("ssl/src/ssl_handshake.hrl").
+-include_lib("ssl/src/ssl_alert.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+
+-define('TLS_v1.3', {3,4}).
+-define('TLS_v1.2', {3,3}).
+-define('TLS_v1.1', {3,2}).
+-define('TLS_v1', {3,1}).
+-define('SSL_v3', {3,0}).
+
+%%--------------------------------------------------------------------
+%% Properties --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+prop_tls_hs_encode_decode() ->
+ ?FORALL({Handshake, TLSVersion}, ?LET(Version, tls_version(), {tls_msg(Version), Version}),
+ try
+ [Type, _Length, Data] = tls_handshake:encode_handshake(Handshake, TLSVersion),
+ case tls_handshake:decode_handshake(TLSVersion, Type, Data) of
+ Handshake ->
+ true;
+ _ ->
+ false
+ end
+ catch
+ throw:#alert{} ->
+ true
+ end
+ ).
+
+%%--------------------------------------------------------------------
+%% Message Generators -----------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_msg(?'TLS_v1.3'= Version) ->
+ oneof([client_hello(Version),
+ server_hello(Version),
+ %%new_session_ticket()
+ #end_of_early_data{},
+ encrypted_extensions(),
+ certificate_1_3(),
+ %%certificate_request_1_3,
+ certificate_verify_1_3(),
+ finished(),
+ key_update()
+ ]);
+tls_msg(Version) ->
+ oneof([
+ #hello_request{},
+ client_hello(Version),
+ server_hello(Version),
+ certificate(),
+ %%server_key_exchange()
+ certificate_request(Version),
+ #server_hello_done{},
+ %%certificate_verify()
+ %%client_key_exchange()
+ finished()
+ ]).
+
+%%
+%% Shared messages
+%%
+client_hello(?'TLS_v1.3' = Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = ?'TLS_v1.2',
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = client_hello_extensions(Version)
+ };
+client_hello(Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = Version,
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = client_hello_extensions(Version)
+ };
+client_hello(?'SSL_v3' = Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = Version,
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = ssl_handshake:empty_extensions(Version, client_hello)
+ }.
+
+server_hello(?'TLS_v1.3' = Version) ->
+ #server_hello{server_version = ?'TLS_v1.2',
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = server_hello_extensions(Version)
+ };
+server_hello(?'SSL_v3' = Version) ->
+ #server_hello{server_version = Version,
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = ssl_handshake:empty_extensions(Version, server_hello)
+ };
+server_hello(Version) ->
+ #server_hello{server_version = Version,
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = server_hello_extensions(Version)
+ }.
+
+certificate() ->
+ #certificate{
+ asn1_certificates = certificate_chain()
+ }.
+
+certificate_1_3() ->
+ ?LET(Certs, certificate_chain(),
+ #certificate_1_3{
+ certificate_request_context = certificate_request_context(),
+ certificate_list = certificate_entries(Certs, [])
+ }).
+
+certificate_verify_1_3() ->
+ ?LET(Certs, certificate_chain(),
+ #certificate_verify_1_3{
+ algorithm = sig_scheme(),
+ signature = signature()
+ }).
+
+finished() ->
+ ?LET(Size, digest_size(),
+ #finished{verify_data = crypto:strong_rand_bytes(Size)}).
+
+%%
+%% TLS 1.0-1.2 messages
+%%
+
+
+
+%%
+%% TLS 1.3 messages
+%%
+
+encrypted_extensions() ->
+ ?LET(Exts, extensions(?'TLS_v1.3', encrypted_extensions),
+ #encrypted_extensions{extensions = Exts}).
+
+
+key_update() ->
+ #key_update{request_update = request_update()}.
+
+
+%%--------------------------------------------------------------------
+%% Messge Data Generators -------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_version() ->
+ oneof([?'TLS_v1.3', ?'TLS_v1.2', ?'TLS_v1.1', ?'TLS_v1', ?'SSL_v3']).
+
+cipher_suite(Version) ->
+ oneof(cipher_suites(Version)).
+
+cipher_suites(Version) ->
+ ssl_cipher:suites(Version).
+
+session_id() ->
+ crypto:strong_rand_bytes(?NUM_OF_SESSION_ID_BYTES).
+
+compression(Version) ->
+ oneof(compressions(Version)).
+
+compressions(_) ->
+ ssl_record:compressions().
+
+client_random(_) ->
+ crypto:strong_rand_bytes(32).
+
+server_random(_) ->
+ crypto:strong_rand_bytes(32).
+
+
+client_hello_extensions(Version) ->
+ ?LET(Exts, extensions(Version, client_hello),
+ maps:merge(ssl_handshake:empty_extensions(Version, client_hello),
+ Exts)).
+
+server_hello_extensions(Version) ->
+ ?LET(Exts, extensions(Version, server_hello),
+ maps:merge(ssl_handshake:empty_extensions(Version, server_hello),
+ Exts)).
+
+key_share_client_hello() ->
+ oneof([undefined]).
+ %%oneof([#key_share_client_hello{}, undefined]).
+
+key_share_server_hello() ->
+ oneof([undefined]).
+ %%oneof([#key_share_server_hello{}, undefined]).
+
+pre_shared_keyextension() ->
+ oneof([undefined]).
+ %%oneof([#pre_shared_keyextension{},undefined]).
+
+%% +--------------------------------------------------+-------------+
+%% | Extension | TLS 1.3 |
+%% +--------------------------------------------------+-------------+
+%% | server_name [RFC6066] | CH, EE |
+%% | | |
+%% | max_fragment_length [RFC6066] | CH, EE |
+%% | | |
+%% | status_request [RFC6066] | CH, CR, CT |
+%% | | |
+%% | supported_groups [RFC7919] | CH, EE |
+%% | | |
+%% | signature_algorithms (RFC 8446) | CH, CR |
+%% | | |
+%% | use_srtp [RFC5764] | CH, EE |
+%% | | |
+%% | heartbeat [RFC6520] | CH, EE |
+%% | | |
+%% | application_layer_protocol_negotiation [RFC7301] | CH, EE |
+%% | | |
+%% | signed_certificate_timestamp [RFC6962] | CH, CR, CT |
+%% | | |
+%% | client_certificate_type [RFC7250] | CH, EE |
+%% | | |
+%% | server_certificate_type [RFC7250] | CH, EE |
+%% | | |
+%% | padding [RFC7685] | CH |
+%% | | |
+%% | key_share (RFC 8446) | CH, SH, HRR |
+%% | | |
+%% | pre_shared_key (RFC 8446) | CH, SH |
+%% | | |
+%% | psk_key_exchange_modes (RFC 8446) | CH |
+%% | | |
+%% | early_data (RFC 8446) | CH, EE, NST |
+%% | | |
+%% | cookie (RFC 8446) | CH, HRR |
+%% | | |
+%% | supported_versions (RFC 8446) | CH, SH, HRR |
+%% | | |
+%% | certificate_authorities (RFC 8446) | CH, CR |
+%% | | |
+%% | oid_filters (RFC 8446) | CR |
+%% | | |
+%% | post_handshake_auth (RFC 8446) | CH |
+%% | | |
+%% | signature_algorithms_cert (RFC 8446) | CH, CR |
+%% +--------------------------------------------------+-------------+
+extensions(?'TLS_v1.3' = Version, MsgType = client_hello) ->
+ ?LET({
+ ServerName,
+ %% MaxFragmentLength,
+ %% StatusRequest,
+ SupportedGroups,
+ SignatureAlgorithms,
+ %% UseSrtp,
+ %% Heartbeat,
+ ALPN,
+ %% SignedCertTimestamp,
+ %% ClientCertiticateType,
+ %% ServerCertificateType,
+ %% Padding,
+ KeyShare,
+ PreSharedKey,
+ PSKKeyExchangeModes,
+ %% EarlyData,
+ %% Cookie,
+ SupportedVersions,
+ %% CertAuthorities,
+ %% PostHandshakeAuth,
+ SignatureAlgorithmsCert
+ },
+ {
+ oneof([server_name(), undefined]),
+ %% oneof([max_fragment_length(), undefined]),
+ %% oneof([status_request(), undefined]),
+ oneof([supported_groups(Version), undefined]),
+ oneof([signature_algs(Version), undefined]),
+ %% oneof([use_srtp(), undefined]),
+ %% oneof([heartbeat(), undefined]),
+ oneof([alpn(), undefined]),
+ %% oneof([signed_cert_timestamp(), undefined]),
+ %% oneof([client_cert_type(), undefined]),
+ %% oneof([server_cert_type(), undefined]),
+ %% oneof([padding(), undefined]),
+ oneof([key_share(MsgType), undefined]),
+ oneof([pre_shared_key(MsgType), undefined]),
+ oneof([psk_key_exchange_modes(), undefined]),
+ %% oneof([early_data(), undefined]),
+ %% oneof([cookie(), undefined]),
+ oneof([client_hello_versions(Version)]),
+ %% oneof([cert_authorities(), undefined]),
+ %% oneof([post_handshake_auth(), undefined]),
+ oneof([signature_algs_cert(), undefined])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ sni => ServerName,
+ %% max_fragment_length => MaxFragmentLength,
+ %% status_request => StatusRequest,
+ elliptic_curves => SupportedGroups,
+ signature_algs => SignatureAlgorithms,
+ %% use_srtp => UseSrtp,
+ %% heartbeat => Heartbeat,
+ alpn => ALPN,
+ %% signed_cert_timestamp => SignedCertTimestamp,
+ %% client_cert_type => ClientCertificateType,
+ %% server_cert_type => ServerCertificateType,
+ %% padding => Padding,
+ key_share => KeyShare,
+ pre_shared_key => PreSharedKey,
+ psk_key_exchange_modes => PSKKeyExchangeModes,
+ %% early_data => EarlyData,
+ %% cookie => Cookie,
+ client_hello_versions => SupportedVersions,
+ %% cert_authorities => CertAuthorities,
+ %% post_handshake_auth => PostHandshakeAuth,
+ signature_algs_cert => SignatureAlgorithmsCert
+ }));
+extensions(?'SSL_v3', client_hello) ->
+ #{};
+extensions(Version, client_hello) ->
+ ?LET({
+ SNI,
+ ECPoitF,
+ ECCurves,
+ ALPN,
+ NextP,
+ SRP
+ %% RenegotiationInfo
+ },
+ {
+ oneof([sni(), undefined]),
+ oneof([ec_point_formats(), undefined]),
+ oneof([elliptic_curves(Version), undefined]),
+ oneof([alpn(), undefined]),
+ oneof([next_protocol_negotiation(), undefined]),
+ oneof([srp(), undefined])
+ %% oneof([renegotiation_info(), undefined])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ sni => SNI,
+ ec_point_formats => ECPoitF,
+ elliptic_curves => ECCurves,
+ alpn => ALPN,
+ next_protocol_negotiation => NextP,
+ srp => SRP
+ %% renegotiation_info => RenegotiationInfo
+ }));
+extensions(?'TLS_v1.3' = Version, MsgType = server_hello) ->
+ ?LET({
+ KeyShare,
+ PreSharedKey,
+ SupportedVersions
+ },
+ {
+ oneof([key_share(MsgType), undefined]),
+ oneof([pre_shared_key(MsgType), undefined]),
+ oneof([server_hello_selected_version()])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ key_share => KeyShare,
+ pre_shared_key => PreSharedKey,
+ server_hello_selected_version => SupportedVersions
+ }));
+extensions(Version, server_hello) ->
+ ?LET({
+ ECPoitF,
+ ALPN,
+ NextP
+ %% RenegotiationInfo,
+ },
+ {
+ oneof([ec_point_formats(), undefined]),
+ oneof([alpn(), undefined]),
+ oneof([next_protocol_negotiation(), undefined])
+ %% oneof([renegotiation_info(), undefined]),
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ ec_point_formats => ECPoitF,
+ alpn => ALPN,
+ next_protocol_negotiation => NextP
+ %% renegotiation_info => RenegotiationInfo
+ }));
+extensions(?'TLS_v1.3' = Version, encrypted_extensions) ->
+ ?LET({
+ ServerName,
+ %% MaxFragmentLength,
+ SupportedGroups,
+ %% UseSrtp,
+ %% Heartbeat,
+ ALPN
+ %% ClientCertiticateType,
+ %% ServerCertificateType,
+ %% EarlyData
+ },
+ {
+ oneof([server_name(), undefined]),
+ %% oneof([max_fragment_length(), undefined]),
+ oneof([supported_groups(Version), undefined]),
+ %% oneof([use_srtp(), undefined]),
+ %% oneof([heartbeat(), undefined]),
+ oneof([alpn(), undefined])
+ %% oneof([client_cert_type(), undefined]),
+ %% oneof([server_cert_type(), undefined]),
+ %% oneof([early_data(), undefined])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ sni => ServerName,
+ %% max_fragment_length => MaxFragmentLength,
+ elliptic_curves => SupportedGroups,
+ %% use_srtp => UseSrtp,
+ %% heartbeat => Heartbeat,
+ alpn => ALPN
+ %% client_cert_type => ClientCertificateType,
+ %% server_cert_type => ServerCertificateType,
+ %% early_data => EarlyData
+ })).
+
+server_name() ->
+ ?LET(ServerName, sni(),
+ ServerName).
+ %% sni().
+
+signature_algs_cert() ->
+ ?LET(List, sig_scheme_list(),
+ #signature_algorithms_cert{signature_scheme_list = List}).
+
+signature_algorithms() ->
+ ?LET(List, sig_scheme_list(),
+ #signature_algorithms{signature_scheme_list = List}).
+
+sig_scheme_list() ->
+ oneof([[rsa_pkcs1_sha256],
+ [rsa_pkcs1_sha256, ecdsa_sha1],
+ [rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1]
+ ]).
+
+sig_scheme() ->
+ oneof([rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1]).
+
+signature() ->
+ <<44,119,215,137,54,84,156,26,121,212,64,173,189,226,
+ 191,46,76,89,204,2,78,79,163,228,90,21,89,179,4,198,
+ 109,14,52,26,230,22,56,8,170,129,86,0,7,132,245,81,
+ 181,131,62,70,79,167,112,85,14,171,175,162,110,29,
+ 212,198,45,188,83,176,251,197,224,104,95,74,89,59,
+ 26,60,63,79,238,196,137,65,23,199,127,145,176,184,
+ 216,3,48,116,172,106,97,83,227,172,246,137,91,79,
+ 173,119,169,60,67,1,177,117,9,93,38,86,232,253,73,
+ 140,17,147,130,110,136,245,73,10,91,70,105,53,225,
+ 158,107,60,190,30,14,26,92,147,221,60,117,104,53,70,
+ 142,204,7,131,11,183,192,120,246,243,68,99,147,183,
+ 49,149,48,188,8,218,17,150,220,121,2,99,194,140,35,
+ 13,249,201,37,216,68,45,87,58,18,10,106,11,132,241,
+ 71,170,225,216,197,212,29,107,36,80,189,184,202,56,
+ 86,213,45,70,34,74,71,48,137,79,212,194,172,151,57,
+ 57,30,126,24,157,198,101,220,84,162,89,105,185,245,
+ 76,105,212,176,25,6,148,49,194,106,253,241,212,200,
+ 37,154,227,53,49,216,72,82,163>>.
+
+client_hello_versions(?'TLS_v1.3') ->
+ ?LET(SupportedVersions,
+ oneof([[{3,4}],
+ %% This list breaks the property but can be used for negative tests
+ %% [{3,3},{3,4}],
+ [{3,4},{3,3}],
+ [{3,4},{3,3},{3,2},{3,1},{3,0}]
+ ]),
+ #client_hello_versions{versions = SupportedVersions});
+client_hello_versions(_) ->
+ ?LET(SupportedVersions,
+ oneof([[{3,3}],
+ [{3,3},{3,2}],
+ [{3,3},{3,2},{3,1},{3,0}]
+ ]),
+ #client_hello_versions{versions = SupportedVersions}).
+
+server_hello_selected_version() ->
+ #server_hello_selected_version{selected_version = {3,4}}.
+
+request_update() ->
+ oneof([?UPDATE_NOT_REQUESTED, ?UPDATE_REQUESTED]).
+
+certificate_chain()->
+ Conf = cert_conf(),
+ ?LET(Chain,
+ choose_certificate_chain(Conf),
+ Chain).
+
+choose_certificate_chain(#{server_config := ServerConf,
+ client_config := ClientConf}) ->
+ oneof([certificate_chain(ServerConf), certificate_chain(ClientConf)]).
+
+certificate_request_context() ->
+ oneof([<<>>,
+ <<1>>,
+ <<"foobar">>
+ ]).
+certificate_entries([], Acc) ->
+ lists:reverse(Acc);
+certificate_entries([Cert | Rest], Acc) ->
+ certificate_entries(Rest, [certificate_entry(Cert) | Acc]).
+
+certificate_entry(Cert) ->
+ #certificate_entry{data = Cert,
+ extensions = certificate_entry_extensions()
+ }.
+certificate_entry_extensions() ->
+ #{}.
+
+certificate_chain(Conf) ->
+ CAs = proplists:get_value(cacerts, Conf),
+ Cert = proplists:get_value(cert, Conf),
+ %% Middle argument are of correct type but will not be used
+ {ok, _, Chain} = ssl_certificate:certificate_chain(Cert, ets:new(foo, []), make_ref(), CAs),
+ Chain.
+
+cert_conf()->
+ Hostname = net_adm:localhost(),
+ {ok, #hostent{h_addr_list = [_IP |_]}} = inet:gethostbyname(net_adm:localhost()),
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
+ peer => [{extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false}]},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}
+ ]},
+ client_chain =>
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}).
+
+certificate_request(Version) ->
+ #certificate_request{certificate_types = certificate_types(Version),
+ hashsign_algorithms = hashsign_algorithms(Version),
+ certificate_authorities = certificate_authorities()}.
+
+certificate_types(?'TLS_v1.3') ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>]);
+certificate_types(?'TLS_v1.2') ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>, <<?BYTE(?DSS_SIGN)>>]);
+certificate_types(_) ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>, <<?BYTE(?DSS_SIGN)>>]).
+
+
+
+signature_algs({3,4}) ->
+ ?LET(Algs, signature_algorithms(),
+ Algs);
+signature_algs({3,3} = Version) ->
+ #hash_sign_algos{hash_sign_algos = hash_alg_list(Version)};
+signature_algs(Version) when Version < {3,3} ->
+ undefined.
+
+
+
+hashsign_algorithms({_, N} = Version) when N >= 3 ->
+ #hash_sign_algos{hash_sign_algos = hash_alg_list(Version)};
+hashsign_algorithms(_) ->
+ undefined.
+
+hash_alg_list(Version) ->
+ ?LET(NumOf, choose(1,15),
+ ?LET(List, [hash_alg(Version) || _ <- lists:seq(1,NumOf)],
+ lists:usort(List)
+ )).
+
+hash_alg(Version) ->
+ ?LET(Alg, sign_algorithm(Version),
+ {hash_algorithm(Version, Alg), Alg}
+ ).
+
+hash_algorithm(?'TLS_v1.3', _) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(?'TLS_v1.2', rsa) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, rsa) ->
+ oneof([md5, sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, ecdsa) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, dsa) ->
+ sha.
+
+sign_algorithm(?'TLS_v1.3') ->
+ oneof([rsa, ecdsa]);
+sign_algorithm(_) ->
+ oneof([rsa, dsa, ecdsa]).
+
+certificate_authorities() ->
+ #{server_config := ServerConf} = cert_conf(),
+ Authorities = proplists:get_value(cacerts, ServerConf),
+ Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
+ OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
+ DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
+ DNEncodedLen = byte_size(DNEncodedBin),
+ <<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
+ end,
+ list_to_binary([Enc(public_key:pkix_decode_cert(DERCert, otp)) || DERCert <- Authorities]).
+
+digest_size()->
+ oneof([160,224,256,384,512]).
+
+key_share_entry() ->
+ undefined.
+ %%#key_share_entry{}.
+
+server_hello_selected_version(Version) ->
+ #server_hello_selected_version{selected_version = Version}.
+
+sni() ->
+ #sni{hostname = net_adm:localhost()}.
+
+ec_point_formats() ->
+ #ec_point_formats{ec_point_format_list = ec_point_format_list()}.
+
+ec_point_format_list() ->
+ [?ECPOINT_UNCOMPRESSED].
+
+elliptic_curves({_, Minor}) when Minor < 4 ->
+ Curves = tls_v1:ecc_curves(Minor),
+ #elliptic_curves{elliptic_curve_list = Curves}.
+
+%% RFC 8446 (TLS 1.3) renamed the "elliptic_curve" extension.
+supported_groups({_, Minor}) when Minor >= 4 ->
+ SupportedGroups = tls_v1:groups(Minor),
+ #supported_groups{supported_groups = SupportedGroups}.
+
+
+alpn() ->
+ ?LET(ExtD, alpn_protocols(), #alpn{extension_data = ExtD}).
+
+alpn_protocols() ->
+ oneof([<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>, <<"http/1.0">>, <<"http/1.1">>]).
+
+next_protocol_negotiation() ->
+ %% Predecessor to APLN
+ ?LET(ExtD, alpn_protocols(), #next_protocol_negotiation{extension_data = ExtD}).
+
+srp() ->
+ ?LET(Name, gen_name(), #srp{username = list_to_binary(Name)}).
+
+renegotiation_info() ->
+ #renegotiation_info{renegotiated_connection = 0}.
+
+gen_name() ->
+ ?LET(Size, choose(1,10), gen_string(Size)).
+
+gen_char() ->
+ choose($a,$z).
+
+gen_string(N) ->
+ gen_string(N, []).
+
+gen_string(0, Acc) ->
+ Acc;
+gen_string(N, Acc) ->
+ ?LET(Char, gen_char(), gen_string(N-1, [Char | Acc])).
+
+key_share(client_hello) ->
+ ?LET(ClientShares, key_share_entry_list(),
+ #key_share_client_hello{
+ client_shares = ClientShares});
+key_share(server_hello) ->
+ ?LET([ServerShare], key_share_entry_list(1),
+ #key_share_server_hello{
+ server_share = ServerShare}).
+
+key_share_entry_list() ->
+ Max = length(ssl:groups()),
+ ?LET(Size, choose(1,Max), key_share_entry_list(Size)).
+%%
+key_share_entry_list(N) ->
+ key_share_entry_list(N, ssl:groups(), []).
+%%
+key_share_entry_list(0, _Pool, Acc) ->
+ Acc;
+key_share_entry_list(N, Pool, Acc) ->
+ R = rand:uniform(length(Pool)),
+ G = lists:nth(R, Pool),
+ P = generate_public_key(G),
+ KeyShareEntry =
+ #key_share_entry{
+ group = G,
+ key_exchange = P},
+ key_share_entry_list(N - 1, Pool -- [G], [KeyShareEntry|Acc]).
+
+%% TODO: fix curve generation
+generate_public_key(Group)
+ when Group =:= secp256r1 orelse
+ Group =:= secp384r1 orelse
+ Group =:= secp521r1 orelse
+ Group =:= x448 orelse
+ Group =:= x25519 ->
+ #'ECPrivateKey'{publicKey = PublicKey} =
+ public_key:generate_key({namedCurve, secp256r1}),
+ PublicKey;
+generate_public_key(Group) ->
+ {PublicKey, _} =
+ public_key:generate_key(ssl_dh_groups:dh_params(Group)),
+ PublicKey.
+
+groups() ->
+ Max = length(ssl:groups()),
+ ?LET(Size, choose(1,Max), group_list(Size)).
+
+group_list(N) ->
+ group_list(N, ssl:groups(), []).
+%%
+group_list(0, _Pool, Acc) ->
+ Acc;
+group_list(N, Pool, Acc) ->
+ R = rand:uniform(length(Pool)),
+ G = lists:nth(R, Pool),
+ group_list(N - 1, Pool -- [G], [G|Acc]).
+
+
+ke_modes() ->
+ oneof([[psk_ke],[psk_dhe_ke],[psk_ke,psk_dhe_ke]]).
+
+psk_key_exchange_modes() ->
+ ?LET(KEModes, ke_modes(),
+ #psk_key_exchange_modes{
+ ke_modes = KEModes}).
+
+pre_shared_key(client_hello) ->
+ ?LET(OfferedPsks, offered_psks(),
+ #pre_shared_key_client_hello{
+ offered_psks = OfferedPsks});
+pre_shared_key(server_hello) ->
+ ?LET(SelectedIdentity, selected_identity(),
+ #pre_shared_key_server_hello{
+ selected_identity = SelectedIdentity}).
+
+selected_identity() ->
+ rand:uniform(32).
+
+offered_psks() ->
+ ?LET(Size, choose(1,5),
+ #offered_psks{
+ identities = psk_identities(Size),
+ binders = psk_binders(Size)}).
+
+psk_identities(Size) ->
+ psk_identities(Size, []).
+%%
+psk_identities(0, Acc) ->
+ Acc;
+psk_identities(N, Acc) ->
+ psk_identities(N - 1, [psk_identity()|Acc]).
+
+psk_identity() ->
+ Len = rand:uniform(32),
+ Identity = crypto:strong_rand_bytes(Len),
+ Age = crypto:strong_rand_bytes(4),
+ #psk_identity{
+ identity = Identity,
+ obfuscated_ticket_age = Age}.
+
+psk_binders(Size) ->
+ psk_binders(Size, []).
+%%
+psk_binders(0, Acc) ->
+ Acc;
+psk_binders(N, Acc) ->
+ psk_binders(N - 1, [psk_binder()|Acc]).
+
+psk_binder() ->
+ Len = rand:uniform(224) + 31,
+ crypto:strong_rand_bytes(Len).
diff --git a/lib/ssl/test/ssl.spec b/lib/ssl/test/ssl.spec
index cb54168d36..15587abecd 100644
--- a/lib/ssl/test/ssl.spec
+++ b/lib/ssl/test/ssl.spec
@@ -1,4 +1,12 @@
-{suites,"../ssl_test",all}.
-{skip_suites, "../ssl_test",
- [ssl_bench_SUITE, ssl_dist_bench_SUITE],
- "Benchmarks run separately"}.
+% {merge_tests,false}.
+{alias,dir,"../ssl_test"}.
+
+{suites,dir,all}.
+{skip_groups,dir,ssl_bench_SUITE,setup,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_bench_SUITE,payload,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_bench_SUITE,pem_cache,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,setup,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,roundtrip,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,throughput,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,sched_utilization,"Benchmarks run separately"}.
+
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index c64358960c..d02888793c 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -51,35 +51,7 @@ groups() ->
].
test_cases()->
- key_cert_combinations()
- ++ misc()
- ++ ecc_negotiation().
-
-key_cert_combinations() ->
- server_ecdh_rsa() ++
- server_ecdhe_rsa() ++
- server_ecdh_ecdsa() ++
- server_ecdhe_ecdsa().
-
-server_ecdh_rsa() ->
- [client_ecdh_rsa_server_ecdh_rsa,
- client_ecdhe_rsa_server_ecdh_rsa,
- client_ecdhe_ecdsa_server_ecdh_rsa].
-
-server_ecdhe_rsa() ->
- [client_ecdh_rsa_server_ecdhe_rsa,
- client_ecdhe_rsa_server_ecdhe_rsa,
- client_ecdhe_ecdsa_server_ecdhe_rsa].
-
-server_ecdh_ecdsa() ->
- [client_ecdh_ecdsa_server_ecdh_ecdsa,
- client_ecdhe_rsa_server_ecdh_ecdsa,
- client_ecdhe_ecdsa_server_ecdh_ecdsa].
-
-server_ecdhe_ecdsa() ->
- [client_ecdh_rsa_server_ecdhe_ecdsa,
- client_ecdh_ecdsa_server_ecdhe_ecdsa,
- client_ecdhe_ecdsa_server_ecdhe_ecdsa].
+ misc() ++ ecc_negotiation().
misc()->
[client_ecdsa_server_ecdsa_with_raw_key].
@@ -160,35 +132,6 @@ end_per_testcase(_TestCase, Config) ->
%% Test diffrent certificate chain types, note that it is the servers
%% chain that affect what cipher suit that will be choosen
-%% ECDH_RSA
-client_ecdh_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_rsa_server_ecdh_rsa(Config).
-client_ecdhe_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_rsa_server_ecdh_rsa(Config).
-client_ecdhe_ecdsa_server_ecdh_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdh_rsa(Config).
-%% ECDHE_RSA
-client_ecdh_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_rsa_server_ecdhe_rsa(Config).
-client_ecdhe_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_rsa_server_ecdhe_rsa(Config).
-client_ecdhe_ecdsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdhe_rsa(Config).
-%% ECDH_ECDSA
-client_ecdh_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_ecdsa_server_ecdh_ecdsa(Config).
-client_ecdhe_rsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_rsa_server_ecdh_ecdsa(Config).
-client_ecdhe_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdh_ecdsa(Config).
-%% ECDHE_ECDSA
-client_ecdh_rsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_rsa_server_ecdhe_ecdsa(Config).
-client_ecdh_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_ecdsa_server_ecdhe_ecdsa(Config).
-client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config).
-
client_ecdsa_server_ecdsa_with_raw_key(Config) when is_list(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
diff --git a/lib/ssl/test/ssl_ECC_openssl_SUITE.erl b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
index 81a7dfd2da..787c08a517 100644
--- a/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
@@ -33,77 +33,23 @@
%%--------------------------------------------------------------------
all() ->
- case test_cases() of
- [_|_] ->
- all_groups();
- [] ->
- [skip]
- end.
-
-all_groups() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
[{group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'dtlsv1.2'},
- {group, 'dtlsv1'}];
+ {group, 'dtlsv1.2'}];
false ->
- [{group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'}]
+ [{group, 'tlsv1.2'}]
end.
groups() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{'tlsv1.2', [], [mix_sign | test_cases()]},
- {'tlsv1.1', [], test_cases()},
- {'tlsv1', [], test_cases()},
- {'dtlsv1.2', [], [mix_sign | test_cases()]},
- {'dtlsv1', [], test_cases()}];
+ [{'tlsv1.2', [], [mix_sign]},
+ {'dtlsv1.2', [], [mix_sign]}];
false ->
- [{'tlsv1.2', [], [mix_sign | test_cases()]},
- {'tlsv1.1', [], test_cases()},
- {'tlsv1', [], test_cases()}]
+ [{'tlsv1.2', [], [mix_sign]}]
end.
-
-test_cases()->
- cert_combinations().
-cert_combinations() ->
- lists:append(lists:map(fun({Name, Suites}) ->
- case ssl_test_lib:openssl_filter(Name) of
- [] ->
- [];
- [_|_] ->
- Suites
- end
- end, [{"ECDH-ECDSA", server_ecdh_ecdsa()},
- {"ECDH-RSA", server_ecdh_rsa()},
- {"ECDHE-RSA", server_ecdhe_rsa()},
- {"ECDHE-ECDSA", server_ecdhe_ecdsa()}
- ])).
-server_ecdh_rsa() ->
- [client_ecdh_rsa_server_ecdh_rsa,
- client_ecdhe_rsa_server_ecdh_rsa,
- client_ecdhe_ecdsa_server_ecdh_rsa].
-
-server_ecdhe_rsa() ->
- [client_ecdh_rsa_server_ecdhe_rsa,
- client_ecdhe_rsa_server_ecdhe_rsa,
- client_ecdhe_ecdsa_server_ecdhe_rsa].
-
-server_ecdh_ecdsa() ->
- [client_ecdh_ecdsa_server_ecdh_ecdsa,
- client_ecdhe_rsa_server_ecdh_ecdsa,
- client_ecdhe_ecdsa_server_ecdh_ecdsa].
-
-server_ecdhe_ecdsa() ->
- [client_ecdh_rsa_server_ecdhe_ecdsa,
- client_ecdh_ecdsa_server_ecdhe_ecdsa,
- client_ecdhe_ecdsa_server_ecdhe_ecdsa].
-
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
end_per_suite(Config0),
@@ -121,7 +67,8 @@ init_per_suite(Config0) ->
end_per_suite(_Config) ->
application:stop(ssl),
- application:stop(crypto).
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
%%--------------------------------------------------------------------
init_per_group(GroupName, Config) ->
@@ -171,38 +118,6 @@ end_per_testcase(_TestCase, Config) ->
skip(Config) when is_list(Config) ->
{skip, openssl_does_not_support_ECC}.
-%% Test diffrent certificate chain types, note that it is the servers
-%% chain that affect what cipher suit that will be choosen
-
-%% ECDH_RSA
-client_ecdh_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_rsa_server_ecdh_rsa(Config).
-client_ecdhe_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_rsa_server_ecdh_rsa(Config).
-client_ecdhe_ecdsa_server_ecdh_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdh_rsa(Config).
-%% ECDHE_RSA
-client_ecdh_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_rsa_server_ecdhe_rsa(Config).
-client_ecdhe_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_rsa_server_ecdhe_rsa(Config).
-client_ecdhe_ecdsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdhe_rsa(Config).
-%% ECDH_ECDSA
-client_ecdh_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_ecdsa_server_ecdh_ecdsa(Config).
-client_ecdhe_rsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_rsa_server_ecdh_ecdsa(Config).
-client_ecdhe_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdh_ecdsa(Config).
-%% ECDHE_ECDSA
-client_ecdh_rsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_rsa_server_ecdhe_ecdsa(Config).
-client_ecdh_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdh_ecdsa_server_ecdhe_ecdsa(Config).
-client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- ssl_ECC:client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config).
-
mix_sign(Config) ->
{COpts0, SOpts0} = ssl_test_lib:make_mix_cert(Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
diff --git a/lib/ssl/test/ssl_alert_SUITE.erl b/lib/ssl/test/ssl_alert_SUITE.erl
new file mode 100644
index 0000000000..cc0b636580
--- /dev/null
+++ b/lib/ssl/test/ssl_alert_SUITE.erl
@@ -0,0 +1,100 @@
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_alert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-include_lib("ssl/src/ssl_alert.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ alerts,
+ alert_details,
+ alert_details_not_too_big
+ ].
+
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+alerts() ->
+ [{doc, "Test ssl_alert:alert_txt/1"}].
+alerts(Config) when is_list(Config) ->
+ Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC,
+ ?DECRYPTION_FAILED_RESERVED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE,
+ ?HANDSHAKE_FAILURE, ?BAD_CERTIFICATE, ?UNSUPPORTED_CERTIFICATE,
+ ?CERTIFICATE_REVOKED,?CERTIFICATE_EXPIRED, ?CERTIFICATE_UNKNOWN,
+ ?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR,
+ ?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION,
+ ?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED,
+ ?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE,
+ ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
+ ?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY,
+ 255 %% Unsupported/unknow alert will result in a description too
+ ],
+ Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) |
+ [?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]],
+ lists:foreach(fun(Alert) ->
+ try ssl_alert:alert_txt(Alert)
+ catch
+ C:E:T ->
+ ct:fail({unexpected, {C, E, T}})
+ end
+ end, Alerts).
+%%--------------------------------------------------------------------
+alert_details() ->
+ [{doc, "Test that ssl_alert:alert_txt/1 result contains extendend error description"}].
+alert_details(Config) when is_list(Config) ->
+ Unique = make_ref(),
+ UniqueStr = lists:flatten(io_lib:format("~w", [Unique])),
+ Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Unique),
+ case string:str(ssl_alert:alert_txt(Alert), UniqueStr) of
+ 0 ->
+ ct:fail(error_details_missing);
+ _ ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
+alert_details_not_too_big() ->
+ [{doc, "Test that ssl_alert:alert_txt/1 limits printed depth of extended error description"}].
+alert_details_not_too_big(Config) when is_list(Config) ->
+ Reason = lists:duplicate(10, lists:duplicate(10, lists:duplicate(10, {some, data}))),
+ Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Reason),
+ case length(ssl_alert:alert_txt(Alert)) < 1000 of
+ true ->
+ ok;
+ false ->
+ ct:fail(ssl_alert_text_too_big)
+ end.
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_SUITE.erl
index dfc780479e..82a49e1469 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_SUITE.erl
@@ -19,7 +19,7 @@
%%
%%
--module(ssl_alpn_handshake_SUITE).
+-module(ssl_alpn_SUITE).
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -32,7 +32,9 @@
%%--------------------------------------------------------------------
all() ->
- [{group, 'tlsv1.2'},
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'},
@@ -42,12 +44,13 @@ all() ->
groups() ->
[
- {'tlsv1.2', [], alpn_tests()},
- {'tlsv1.1', [], alpn_tests()},
- {'tlsv1', [], alpn_tests()},
+ {'tlsv1.3', [], alpn_tests() -- [client_renegotiate, session_reused]},
+ {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()},
+ {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist()},
+ {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist()},
{'sslv3', [], alpn_not_supported()},
- {'dtlsv1.2', [], alpn_tests() -- [client_renegotiate]},
- {'dtlsv1', [], alpn_tests() -- [client_renegotiate]}
+ {'dtlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()},
+ {'dtlsv1', [], alpn_tests() ++ alpn_npn_coexist()}
].
alpn_tests() ->
@@ -61,12 +64,16 @@ alpn_tests() ->
client_alpn_and_server_no_support,
client_no_support_and_server_alpn,
client_alpn_npn_and_server_alpn,
- client_alpn_npn_and_server_alpn_npn,
- client_alpn_and_server_alpn_npn,
client_renegotiate,
session_reused
].
+alpn_npn_coexist() ->
+ [
+ client_alpn_npn_and_server_alpn_npn,
+ client_alpn_and_server_alpn_npn
+ ].
+
alpn_not_supported() ->
[alpn_not_supported_client,
alpn_not_supported_server
@@ -77,8 +84,7 @@ init_per_suite(Config0) ->
try crypto:start() of
ok ->
ssl_test_lib:clean_start(),
- Config = ssl_test_lib:make_rsa_cert(Config0),
- ssl_test_lib:cert_options(Config)
+ ssl_test_lib:make_rsa_cert(Config0)
catch _:_ ->
{skip, "Crypto did not start"}
end.
diff --git a/lib/ssl/test/ssl_api_SUITE.erl b/lib/ssl/test/ssl_api_SUITE.erl
new file mode 100644
index 0000000000..fefecc0b65
--- /dev/null
+++ b/lib/ssl/test/ssl_api_SUITE.erl
@@ -0,0 +1,1976 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_api_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
+
+-define(SLEEP, 500).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], ((gen_api_tests() ++ tls13_group() ++ handshake_paus_tests()) -- [dh_params, honor_server_cipher_order, honor_client_cipher_order,
+ new_options_in_handshake])
+ ++ (since_1_2() -- [conf_signature_algs])},
+ {'tlsv1.2', [], gen_api_tests() ++ since_1_2() ++ handshake_paus_tests() ++ pre_1_3()},
+ {'tlsv1.1', [], gen_api_tests() ++ handshake_paus_tests() ++ pre_1_3()},
+ {'tlsv1', [], gen_api_tests() ++ handshake_paus_tests() ++ pre_1_3() ++ beast_mitigation_test()},
+ {'sslv3', [], (gen_api_tests() -- [new_options_in_handshake]) ++ beast_mitigation_test() ++ pre_1_3()},
+ {'dtlsv1.2', [], (gen_api_tests() -- [invalid_keyfile, invalid_certfile, invalid_cacertfile,
+ invalid_options, new_options_in_handshake]) ++ handshake_paus_tests() ++ pre_1_3()},
+ {'dtlsv1', [], (gen_api_tests() -- [invalid_keyfile, invalid_certfile, invalid_cacertfile,
+ invalid_options, new_options_in_handshake]) ++ handshake_paus_tests() ++ pre_1_3()}
+ ].
+
+since_1_2() ->
+ [
+ conf_signature_algs,
+ no_common_signature_algs
+ ].
+
+pre_1_3() ->
+ [
+ default_reject_anonymous
+ ].
+gen_api_tests() ->
+ [
+ peercert,
+ peercert_with_client_cert,
+ connection_information,
+ secret_connection_info,
+ versions,
+ active_n,
+ dh_params,
+ hibernate,
+ hibernate_right_away,
+ listen_socket,
+ recv_active,
+ recv_active_once,
+ recv_active_n,
+ recv_timeout,
+ recv_close,
+ controlling_process,
+ controller_dies,
+ controlling_process_transport_accept_socket,
+ close_with_timeout,
+ close_in_error_state,
+ call_in_error_state,
+ close_transport_accept,
+ abuse_transport_accept_socket,
+ honor_server_cipher_order,
+ honor_client_cipher_order,
+ ipv6,
+ der_input,
+ new_options_in_handshake,
+ max_handshake_size,
+ invalid_certfile,
+ invalid_cacertfile,
+ invalid_keyfile,
+ options_not_proplist,
+ invalid_options
+ ].
+
+handshake_paus_tests() ->
+ [
+ handshake_continue,
+ handshake_continue_timeout,
+ hello_client_cancel,
+ hello_server_cancel
+ ].
+
+%% Only relevant for SSL 3.0 and TLS 1.1
+beast_mitigation_test() ->
+ [%% Original option
+ rizzo_disabled,
+ %% Same effect as disable
+ rizzo_zero_n,
+ %% Same as default
+ rizzo_one_n_minus_one
+ ].
+
+tls13_group() ->
+ [
+ supported_groups,
+ honor_server_cipher_order_tls13,
+ honor_client_cipher_order_tls13
+ ].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ [{client_type, erlang},
+ {server_type, erlang} | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(prf, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Version = ssl_test_lib:protocol_version(Config),
+ PRFS = [md5, sha, sha256, sha384, sha512],
+ %% All are the result of running tls_v1:prf(PrfAlgo, <<>>, <<>>, <<>>, 16)
+ %% with the specified PRF algorithm
+ ExpectedPrfResults =
+ [{md5, <<96,139,180,171,236,210,13,10,28,32,2,23,88,224,235,199>>},
+ {sha, <<95,3,183,114,33,169,197,187,231,243,19,242,220,228,70,151>>},
+ {sha256, <<166,249,145,171,43,95,158,232,6,60,17,90,183,180,0,155>>},
+ {sha384, <<153,182,217,96,186,130,105,85,65,103,123,247,146,91,47,106>>},
+ {sha512, <<145,8,98,38,243,96,42,94,163,33,53,49,241,4,127,28>>},
+ %% TLS 1.0 and 1.1 PRF:
+ {md5sha, <<63,136,3,217,205,123,200,177,251,211,17,229,132,4,173,80>>}],
+ TestPlan = prf_create_plan([Version], PRFS, ExpectedPrfResults),
+ [{prf_test_plan, TestPlan} | Config];
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(internal_active_n, _Config) ->
+ application:unset_env(ssl, internal_active_n);
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+peercert() ->
+ [{doc,"Test API function peercert/1"}].
+peercert(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, 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),
+ [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
+
+ ServerMsg = {error, no_peercert},
+ ClientMsg = {ok, BinCert},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+peercert_with_client_cert() ->
+ [{doc,"Test API function peercert/1"}].
+peercert_with_client_cert(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, [{verify, verify_peer} | 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}]),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ [{'Certificate', ServerBinCert, _}]= ssl_test_lib:pem_to_der(ServerCertFile),
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ [{'Certificate', ClientBinCert, _}]= ssl_test_lib:pem_to_der(ClientCertFile),
+
+ ServerMsg = {ok, ClientBinCert},
+ ClientMsg = {ok, ServerBinCert},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+connection_information() ->
+ [{doc,"Test the API function ssl:connection_information/1"}].
+connection_information(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, connection_information_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_information_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+
+secret_connection_info() ->
+ [{doc,"Test the API function ssl:connection_information/2"}].
+secret_connection_info(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, secret_connection_info_result, []}},
+ {options, [{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, secret_connection_info_result, []}},
+ {options, [{verify, verify_peer} |ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, true, Client, true),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+prf() ->
+ [{doc,"Test that ssl:prf/5 uses the negotiated PRF."}].
+prf(Config) when is_list(Config) ->
+ TestPlan = proplists:get_value(prf_test_plan, Config),
+ case TestPlan of
+ [] -> ct:fail({error, empty_prf_test_plan});
+ _ -> lists:foreach(fun(Suite) ->
+ lists:foreach(
+ fun(Test) ->
+ V = proplists:get_value(tls_ver, Test),
+ C = proplists:get_value(ciphers, Test),
+ E = proplists:get_value(expected, Test),
+ P = proplists:get_value(prf, Test),
+ prf_run_test(Config, V, C, E, P)
+ end, Suite)
+ end, TestPlan)
+ end.
+
+%%--------------------------------------------------------------------
+dh_params() ->
+ [{doc,"Test to specify DH-params file in server."}].
+
+dh_params(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ DataDir = proplists:get_value(data_dir, Config),
+ DHParamFile = filename:join(DataDir, "dHParam.pem"),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{dhfile, DHParamFile} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{ciphers,[{dhe_rsa,aes_256_cbc,sha}]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+conf_signature_algs() ->
+ [{doc,"Test to set the signature_algs option on both client and server"}].
+conf_signature_algs(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+no_common_signature_algs() ->
+ [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}].
+no_common_signature_algs(Config) when is_list(Config) ->
+
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [{signature_algs, [{sha256, rsa}]}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, [{signature_algs, [{sha384, rsa}]}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
+
+%%--------------------------------------------------------------------
+handshake_continue() ->
+ [{doc, "Test API function ssl:handshake_continue/3"}].
+handshake_continue(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ssl_test_lib:ssl_options([{reuseaddr, true},
+ {verify, verify_peer},
+ {handshake, hello} | ServerOpts
+ ],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}
+ ]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ClientOpts
+ ],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%------------------------------------------------------------------
+handshake_continue_timeout() ->
+ [{doc, "Test API function ssl:handshake_continue/3 with short timeout"}].
+handshake_continue_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 1},
+ {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello},
+ {verify, verify_peer} | ServerOpts],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}
+ ]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, [{verify, verify_peer} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error,timeout}),
+ ssl_test_lib:close(Server).
+
+
+%%--------------------------------------------------------------------
+hello_client_cancel() ->
+ [{doc, "Test API function ssl:handshake_cancel/1 on the client side"}].
+hello_client_cancel(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ServerOpts], Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ %% That is ssl:handshake_cancel returns ok
+ {connect_failed, ok} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ClientOpts], Config)},
+ {continue_options, cancel}]),
+ ssl_test_lib:check_server_alert(Server, user_canceled).
+%%--------------------------------------------------------------------
+hello_server_cancel() ->
+ [{doc, "Test API function ssl:handshake_cancel/1 on the server side"}].
+hello_server_cancel(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ServerOpts
+ ], Config)},
+ {continue_options, cancel}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ClientOpts
+ ], Config)},
+ {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
+
+ ssl_test_lib:check_result(Server, ok).
+
+%%--------------------------------------------------------------------
+versions() ->
+ [{doc,"Test API function versions/0"}].
+
+versions(Config) when is_list(Config) ->
+ [_|_] = Versions = ssl:versions(),
+ ct:log("~p~n", [Versions]).
+
+%%--------------------------------------------------------------------
+%% Test case adapted from gen_tcp_misc_SUITE.
+active_n() ->
+ [{doc,"Test {active,N} option"}].
+
+active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Port = ssl_test_lib:inet_port(node()),
+ N = 3,
+ LS = ok(ssl:listen(Port, [{active,N}|ServerOpts])),
+ [{active,N}] = ok(ssl:getopts(LS, [active])),
+ active_n_common(LS, N),
+ Self = self(),
+ spawn_link(fun() ->
+ S0 = ok(ssl:transport_accept(LS)),
+ {ok, S} = ssl:handshake(S0),
+ ok = ssl:setopts(S, [{active,N}]),
+ [{active,N}] = ok(ssl:getopts(S, [active])),
+ ssl:controlling_process(S, Self),
+ Self ! {server, S}
+ end),
+ C = ok(ssl:connect("localhost", Port, [{active,N}|ClientOpts])),
+ [{active,N}] = ok(ssl:getopts(C, [active])),
+ S = receive
+ {server, S0} -> S0
+ after
+ 1000 ->
+ exit({error, connect})
+ end,
+ active_n_common(C, N),
+ active_n_common(S, N),
+ ok = ssl:setopts(C, [{active,N}]),
+ ok = ssl:setopts(S, [{active,N}]),
+ ReceiveMsg = fun(Socket, Msg) ->
+ receive
+ {ssl,Socket,Msg} ->
+ ok;
+ {ssl,Socket,Begin} ->
+ receive
+ {ssl,Socket,End} ->
+ Msg = Begin ++ End,
+ ok
+ after 1000 ->
+ exit(timeout)
+ end
+ after 1000 ->
+ exit(timeout)
+ end
+ end,
+ repeat(3, fun(I) ->
+ Msg = "message "++integer_to_list(I),
+ ok = ssl:send(C, Msg),
+ ReceiveMsg(S, Msg),
+ ok = ssl:send(S, Msg),
+ ReceiveMsg(C, Msg)
+ end),
+ receive
+ {ssl_passive,S} ->
+ [{active,false}] = ok(ssl:getopts(S, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ receive
+ {ssl_passive,C} ->
+ [{active,false}] = ok(ssl:getopts(C, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ LS2 = ok(ssl:listen(0, [{active,0}])),
+ receive
+ {ssl_passive,LS2} ->
+ [{active,false}] = ok(ssl:getopts(LS2, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ ok = ssl:close(LS2),
+ ok = ssl:close(C),
+ ok = ssl:close(S),
+ ok = ssl:close(LS),
+ ok.
+
+hibernate() ->
+ [{doc,"Check that an SSL connection that is started with option "
+ "{hibernate_after, 1000} indeed hibernates after 1000ms of "
+ "inactivity"}].
+
+hibernate(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{hibernate_after, 1000}|ClientOpts]}]),
+ {current_function, _} =
+ process_info(Pid, current_function),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ct:sleep(1500),
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid, current_function),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+hibernate_right_away() ->
+ [{doc,"Check that an SSL connection that is configured to hibernate "
+ "after 0 or 1 milliseconds hibernates as soon as possible and not "
+ "crashes"}].
+
+hibernate_right_away(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ StartServerOpts = [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}],
+ StartClientOpts = [return_socket,
+ {node, ClientNode},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}}],
+
+ Server1 = ssl_test_lib:start_server(StartServerOpts),
+ Port1 = ssl_test_lib:inet_port(Server1),
+ {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++
+ [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server1, ok, Client1, ok),
+
+ ct:sleep(1000), %% Schedule out
+
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid1, current_function),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1),
+
+ Server2 = ssl_test_lib:start_server(StartServerOpts),
+ Port2 = ssl_test_lib:inet_port(Server2),
+ {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++
+ [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server2, ok, Client2, ok),
+
+ ct:sleep(1000), %% Schedule out
+
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid2, current_function),
+
+ ssl_test_lib:close(Server2),
+ ssl_test_lib:close(Client2).
+
+listen_socket() ->
+ [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}].
+
+listen_socket(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ok, ListenSocket} = ssl:listen(0, ServerOpts),
+
+ %% This can be a valid thing to do as
+ %% options are inherited by the accept socket
+ ok = ssl:controlling_process(ListenSocket, self()),
+
+ {ok, _} = ssl:sockname(ListenSocket),
+
+ {error, enotconn} = ssl:send(ListenSocket, <<"data">>),
+ {error, enotconn} = ssl:recv(ListenSocket, 0),
+ {error, enotconn} = ssl:connection_information(ListenSocket),
+ {error, enotconn} = ssl:peername(ListenSocket),
+ {error, enotconn} = ssl:peercert(ListenSocket),
+ {error, enotconn} = ssl:renegotiate(ListenSocket),
+ {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, [client_random], 256),
+ {error, enotconn} = ssl:shutdown(ListenSocket, read_write),
+
+ ok = ssl:close(ListenSocket).
+
+%%--------------------------------------------------------------------
+recv_active() ->
+ [{doc,"Test recv on active socket"}].
+
+recv_active(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_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, try_recv_active, []}},
+ {options, [{active, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+recv_active_once() ->
+ [{doc,"Test recv on active (once) socket"}].
+
+recv_active_once(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, once} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_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).
+
+%%--------------------------------------------------------------------
+recv_active_n() ->
+ [{doc,"Test recv on active (n) socket"}].
+
+recv_active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+recv_timeout() ->
+ [{doc,"Test ssl:ssl_accept timeout"}].
+
+recv_timeout(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result_timeout_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,
+ send_recv_result_timeout_client, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+recv_close() ->
+ [{doc,"Special case of call error handling"}].
+recv_close(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, do_recv_close, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {_Client, #sslsocket{} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+ ssl:close(SslSocket),
+ ssl_test_lib:check_result(Server, ok).
+
+
+
+%%--------------------------------------------------------------------
+controlling_process() ->
+ [{doc,"Test API function controlling_process/2"}].
+
+controlling_process(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientMsg = "Server hello",
+ ServerMsg = "Client hello",
+
+ 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, CSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ controlling_process_result, [self(),
+ ClientMsg]}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ServerMsg = ssl_test_lib:active_recv(CSocket, length(ServerMsg)),
+ %% We do not have the TLS server socket but all messages form the client
+ %% socket are now read, so ramining are form the server socket
+ ClientMsg = ssl_active_recv(length(ClientMsg)),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+controller_dies() ->
+ [{doc,"Test that the socket is closed after controlling process dies"}].
+controller_dies(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ 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}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
+ ct:sleep(?SLEEP), %% 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,
+ Tester = self(),
+ Connect = fun(Pid) ->
+ {ok, Socket} = ssl:connect(Hostname, Port, ClientOpts),
+ %% Make sure server finishes and verification
+ %% and is in coonection state before
+ %% killing client
+ ct:sleep(?SLEEP),
+ 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,
+
+ 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,
+
+ ct:log("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 ->
+ ct:log("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 1000 ->
+ ok
+ end,
+ Controller ! die_nice,
+ get_close(Controller, ?LINE),
+
+ %% Test that servers die
+ Server ! listen,
+ LastClient = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ controller_dies_result, [self(),
+ ClientMsg]}},
+ {options, ClientOpts}]),
+ ct:sleep(?SLEEP), %% so that they are connected
+
+ exit(Server, killed),
+ get_close(Server, ?LINE),
+ process_flag(trap_exit, false),
+ ssl_test_lib:close(LastClient).
+%%--------------------------------------------------------------------
+controlling_process_transport_accept_socket() ->
+ [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
+controlling_process_transport_accept_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_transport_control([{node, ServerNode},
+ {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ _Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server).
+
+%%--------------------------------------------------------------------
+close_with_timeout() ->
+ [{doc,"Test normal (not downgrade) ssl:close/2"}].
+close_with_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_close, []}},
+ {options,[{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_close, []}},
+ {options, [{active, false} |ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok).
+
+%%--------------------------------------------------------------------
+close_in_error_state() ->
+ [{doc,"Special case of closing socket in error state"}].
+close_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]),
+ receive
+ {_Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ ok ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+%%--------------------------------------------------------------------
+call_in_error_state() ->
+ [{doc,"Special case of call error handling"}].
+call_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]),
+ receive
+ {Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+%%--------------------------------------------------------------------
+close_transport_accept() ->
+ [{doc,"Tests closing ssl socket when waiting on ssl:transport_accept/1"}].
+
+close_transport_accept(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Port = 0,
+ Opts = [{active, false} | ServerOpts],
+ {ok, ListenSocket} = rpc:call(ServerNode, ssl, listen, [Port, Opts]),
+ spawn_link(fun() ->
+ ct:sleep(?SLEEP),
+ rpc:call(ServerNode, ssl, close, [ListenSocket])
+ end),
+ case rpc:call(ServerNode, ssl, transport_accept, [ListenSocket]) of
+ {error, closed} ->
+ ok;
+ Other ->
+ exit({?LINE, Other})
+ end.
+%%--------------------------------------------------------------------
+abuse_transport_accept_socket() ->
+ [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
+abuse_transport_accept_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_transport_abuse_socket([{node, ServerNode},
+ {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+invalid_keyfile() ->
+ [{doc,"Test what happens with an invalid key file"}].
+invalid_keyfile(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ BadKeyFile = filename:join([proplists:get_value(priv_dir, Config),
+ "badkey.pem"]),
+ BadOpts = [{keyfile, BadKeyFile}| proplists:delete(keyfile, ServerOpts)],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, BadOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()}, {options, ClientOpts}]),
+
+ File = proplists:get_value(keyfile,BadOpts),
+ ssl_test_lib:check_result(Server, {error,{options, {keyfile, File, {error,enoent}}}}, Client,
+ {error, closed}).
+
+%%--------------------------------------------------------------------
+honor_server_cipher_order() ->
+ [{doc,"Test API honor server cipher order."}].
+honor_server_cipher_order(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+ honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}).
+
+%%--------------------------------------------------------------------
+honor_client_cipher_order() ->
+ [{doc,"Test API honor server cipher order."}].
+honor_client_cipher_order(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+ honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}).
+
+%%--------------------------------------------------------------------
+ipv6() ->
+ [{require, ipv6_hosts},
+ {doc,"Test ipv6."}].
+ipv6(Config) when is_list(Config) ->
+ {ok, Hostname0} = inet:gethostname(),
+
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
+ true ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} =
+ ssl_test_lib:run_where(Config, ipv6),
+ Server = ssl_test_lib:start_server([{node, ServerNode},
+ {port, 0}, {from, self()},
+ {mfa, {ssl_test_lib, 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, {ssl_test_lib, send_recv_result, []}},
+ {options,
+ [inet6, {active, false} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client);
+ false ->
+ {skip, "Host does not support IPv6"}
+ end.
+
+%%--------------------------------------------------------------------
+der_input() ->
+ [{doc,"Test to input certs and key as der"}].
+
+der_input(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ DHParamFile = filename:join(DataDir, "dHParam.pem"),
+
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ [CADb | _] = element(6, State),
+
+ Size = ets:info(CADb, size),
+
+ SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
+ SeverVerifyOpts]),
+ ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
+ ClientVerifyOpts]),
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
+ {dh, DHParams},
+ {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}],
+ ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
+ {dh, DHParams},
+ {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {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, {ssl_test_lib, 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),
+ Size = ets:info(CADb, size).
+
+%%--------------------------------------------------------------------
+invalid_certfile() ->
+ [{doc,"Test what happens with an invalid cert file"}].
+
+invalid_certfile(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ BadCertFile = filename:join([proplists:get_value(priv_dir, Config),
+ "badcert.pem"]),
+ ServerBadOpts = [{certfile, BadCertFile}| proplists:delete(certfile, ServerOpts)],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerBadOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+ File = proplists:get_value(certfile, ServerBadOpts),
+ ssl_test_lib:check_result(Server, {error,{options, {certfile, File, {error,enoent}}}},
+ Client, {error, closed}).
+
+
+%%--------------------------------------------------------------------
+invalid_cacertfile() ->
+ [{doc,"Test what happens with an invalid cacert file"}].
+
+invalid_cacertfile(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ BadCACertFile = filename:join([proplists:get_value(priv_dir, Config),
+ "badcacert.pem"]),
+ ServerBadOpts = [{cacertfile, BadCACertFile}| proplists:delete(cacertfile, ServerOpts)],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server0 =
+ ssl_test_lib:start_server_error([{node, ServerNode},
+ {port, 0}, {from, self()},
+ {options, ServerBadOpts}]),
+
+ Port0 = ssl_test_lib:inet_port(Server0),
+
+
+ Client0 =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+
+ File0 = proplists:get_value(cacertfile, ServerBadOpts),
+
+ ssl_test_lib:check_result(Server0, {error, {options, {cacertfile, File0,{error,enoent}}}},
+ Client0, {error, closed}),
+
+ File = File0 ++ "do_not_exit.pem",
+ ServerBadOpts1 = [{cacertfile, File}|proplists:delete(cacertfile, ServerBadOpts)],
+
+ Server1 =
+ ssl_test_lib:start_server_error([{node, ServerNode},
+ {port, 0}, {from, self()},
+ {options, ServerBadOpts1}]),
+
+ Port1 = ssl_test_lib:inet_port(Server1),
+
+ Client1 =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port1}, {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+
+
+ ssl_test_lib:check_result(Server1, {error, {options, {cacertfile, File,{error,enoent}}}},
+ Client1, {error, closed}),
+ ok.
+
+%%--------------------------------------------------------------------
+new_options_in_handshake() ->
+ [{doc,"Test that you can set ssl options in handshake/3 and not only in tcp upgrade"}].
+new_options_in_handshake(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Version = ssl_test_lib:protocol_version(Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ [_, Cipher | _] = ssl:filter_cipher_suites(ssl:cipher_suites(all, Version),
+ [{key_exchange,
+ fun(dhe_rsa) ->
+ true;
+ (ecdhe_rsa) ->
+ true;
+ (ecdh_rsa) ->
+ true;
+ (rsa) ->
+ true;
+ (_) ->
+ false
+ end
+ }]),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {ssl_extra_opts, [{versions, [Version]},
+ {ciphers,[Cipher]}]}, %% To be set in ssl_accept/3
+ {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, [Cipher]} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ServerMsg = ClientMsg = {ok, {Version, Cipher}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%-------------------------------------------------------------------
+max_handshake_size() ->
+ [{doc,"Test that we can set max_handshake_size to max value."}].
+
+max_handshake_size(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} |ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok).
+
+
+%%-------------------------------------------------------------------
+options_not_proplist() ->
+ [{doc,"Test what happens if an option is not a key value tuple"}].
+
+options_not_proplist(Config) when is_list(Config) ->
+ BadOption = {client_preferred_next_protocols,
+ client, [<<"spdy/3">>,<<"http/1.1">>], <<"http/1.1">>},
+ {option_not_a_key_value_tuple, BadOption} =
+ ssl:connect("twitter.com", 443, [binary, {active, false},
+ BadOption]).
+
+%%-------------------------------------------------------------------
+invalid_options() ->
+ [{doc,"Test what happens when we give invalid options"}].
+
+invalid_options(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Check = fun(Client, Server, {versions, [sslv2, sslv3]} = Option) ->
+ ssl_test_lib:check_result(Server,
+ {error, {options, {sslv2, Option}}},
+ Client,
+ {error, {options, {sslv2, Option}}});
+ (Client, Server, Option) ->
+ ssl_test_lib:check_result(Server,
+ {error, {options, Option}},
+ Client,
+ {error, {options, Option}})
+ end,
+
+ TestOpts =
+ [{versions, [sslv2, sslv3]},
+ {verify, 4},
+ {verify_fun, function},
+ {fail_if_no_peer_cert, 0},
+ {verify_client_once, 1},
+ {depth, four},
+ {certfile, 'cert.pem'},
+ {keyfile,'key.pem' },
+ {password, foo},
+ {cacertfile, ""},
+ {dhfile,'dh.pem' },
+ {ciphers, [{foo, bar, sha, ignore}]},
+ {reuse_session, foo},
+ {reuse_sessions, 0},
+ {renegotiate_at, "10"},
+ {mode, depech},
+ {packet, 8.0},
+ {packet_size, "2"},
+ {header, a},
+ {active, trice},
+ {key, 'key.pem' }],
+
+ [begin
+ Server =
+ ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [TestOpt | ServerOpts]}]),
+ %% Will never reach a point where port is used.
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0},
+ {host, Hostname}, {from, self()},
+ {options, [TestOpt | ClientOpts]}]),
+ Check(Client, Server, TestOpt),
+ ok
+ end || TestOpt <- TestOpts],
+ ok.
+%%-------------------------------------------------------------------
+
+default_reject_anonymous()->
+ [{doc,"Test that by default anonymous cipher suites are rejected "}].
+default_reject_anonymous(Config) when is_list(Config) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Version = ssl_test_lib:protocol_version(Config),
+ TLSVersion = ssl_test_lib:tls_version(Version),
+
+ [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
+
+%%-------------------------------------------------------------------
+%% Note that these test only test that the options are valid to set. As application data
+%% is a stream you can not test that the send acctually splits it up as when it arrives
+%% again at the user layer it may be concatenated. But COVER can show that the split up
+%% code has been run.
+
+rizzo_disabled() ->
+ [{doc, "Test original beast mitigation disable option for SSL 3.0 and TLS 1.0"}].
+
+rizzo_disabled(Config) ->
+ ClientOpts = [{beast_mitigation, disabled} | ssl_test_lib:ssl_options(client_rsa_opts, Config)],
+ ServerOpts = [{beast_mitigation, disabled} | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%-------------------------------------------------------------------
+rizzo_zero_n() ->
+ [{doc, "Test zero_n beast mitigation option (same affect as original disable option) for SSL 3.0 and TLS 1.0"}].
+
+rizzo_zero_n(Config) ->
+ ClientOpts = [{beast_mitigation, zero_n} | ssl_test_lib:ssl_options(client_rsa_opts, Config)],
+ ServerOpts = [{beast_mitigation, zero_n} | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%-------------------------------------------------------------------
+rizzo_one_n_minus_one () ->
+ [{doc, "Test beast_mitigation option one_n_minus_one (same affect as default) for SSL 3.0 and TLS 1.0"}].
+
+rizzo_one_n_minus_one (Config) ->
+ ClientOpts = [{beast_mitigation, one_n_minus_one } | ssl_test_lib:ssl_options(client_rsa_opts, Config)],
+ ServerOpts = [{beast_mitigation, one_n_minus_one} | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+supported_groups() ->
+ [{doc,"Test the supported_groups option in TLS 1.3."}].
+
+supported_groups(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{supported_groups, [x448, x25519]} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{supported_groups,[x448]} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+honor_client_cipher_order_tls13() ->
+ [{doc,"Test API honor server cipher order in TLS 1.3."}].
+honor_client_cipher_order_tls13(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384},
+ #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}],
+ ServerCiphers = [#{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256},
+ #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384}],
+ honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384}).
+
+%%--------------------------------------------------------------------
+honor_server_cipher_order_tls13() ->
+ [{doc,"Test API honor server cipher order in TLS 1.3."}].
+honor_server_cipher_order_tls13(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384},
+ #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}],
+ ServerCiphers = [#{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256},
+ #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384}],
+ honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+peercert_result(Socket) ->
+ ssl:peercert(Socket).
+
+connection_information_result(Socket) ->
+ {ok, Info = [_ | _]} = ssl:connection_information(Socket),
+ case length(Info) > 3 of
+ true ->
+ %% Atleast one ssl_option() is set
+ ct:log("Info ~p", [Info]),
+ ok;
+ false ->
+ ct:fail(no_ssl_options_returned)
+ end.
+secret_connection_info_result(Socket) ->
+ {ok, [{protocol, Protocol}]} = ssl:connection_information(Socket, [protocol]),
+ {ok, ConnInfo} = ssl:connection_information(Socket, [client_random, server_random, master_secret]),
+ check_connection_info(Protocol, ConnInfo).
+
+
+%% In TLS 1.3 the master_secret field is used to store multiple secrets from the key schedule and it is a tuple.
+%% client_random and server_random are not used in the TLS 1.3 key schedule.
+check_connection_info('tlsv1.3', [{client_random, ClientRand}, {master_secret, {master_secret, MasterSecret}}]) ->
+ is_binary(ClientRand) andalso is_binary(MasterSecret);
+check_connection_info('tlsv1.3', [{server_random, ServerRand}, {master_secret, {master_secret, MasterSecret}}]) ->
+ is_binary(ServerRand) andalso is_binary(MasterSecret);
+check_connection_info(_, [{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}]) ->
+ is_binary(ClientRand) andalso is_binary(ServerRand) andalso is_binary(MasterSecret);
+check_connection_info(_, _) ->
+ false.
+
+
+prf_create_plan(TlsVersions, PRFs, Results) ->
+ lists:foldl(fun(Ver, Acc) ->
+ A = prf_ciphers_and_expected(Ver, PRFs, Results),
+ [A|Acc]
+ end, [], TlsVersions).
+
+prf_ciphers_and_expected(TlsVer, PRFs, Results) ->
+ case TlsVer of
+ TlsVer when TlsVer == sslv3 orelse TlsVer == tlsv1
+ orelse TlsVer == 'tlsv1.1' orelse TlsVer == 'dtlsv1' ->
+ Ciphers = ssl:cipher_suites(),
+ {_, Expected} = lists:keyfind(md5sha, 1, Results),
+ [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, {prf, md5sha}]];
+ TlsVer when TlsVer == 'tlsv1.2' orelse TlsVer == 'dtlsv1.2'->
+ lists:foldl(
+ fun(PRF, Acc) ->
+ Ciphers = prf_get_ciphers(TlsVer, PRF),
+ case Ciphers of
+ [] ->
+ ct:log("No ciphers for PRF algorithm ~p. Skipping.", [PRF]),
+ Acc;
+ Ciphers ->
+ {_, Expected} = lists:keyfind(PRF, 1, Results),
+ [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected},
+ {prf, PRF}] | Acc]
+ end
+ end, [], PRFs)
+ end.
+
+prf_get_ciphers(_, PRF) ->
+ lists:filter(
+ fun(C) when tuple_size(C) == 4 andalso
+ element(4, C) == PRF ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
+prf_run_test(_, TlsVer, [], _, Prf) ->
+ ct:fail({error, cipher_list_empty, TlsVer, Prf});
+prf_run_test(Config, TlsVer, Ciphers, Expected, Prf) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ BaseOpts = [{active, true}, {versions, [TlsVer]}, {ciphers, Ciphers}, {protocol, tls_or_dtls(TlsVer)}],
+ ServerOpts = BaseOpts ++ proplists:get_value(server_opts, Config),
+ ClientOpts = BaseOpts ++ proplists:get_value(client_opts, Config),
+ Server = ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0}, {from, self()},
+ {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}},
+ {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, prf_verify_value, [TlsVer, Expected, Prf]}},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+prf_verify_value(Socket, TlsVer, Expected, Algo) ->
+ Ret = ssl:prf(Socket, <<>>, <<>>, [<<>>], 16),
+ case TlsVer of
+ sslv3 ->
+ case Ret of
+ {error, undefined} -> ok;
+ _ ->
+ {error, {expected, {error, undefined},
+ got, Ret, tls_ver, TlsVer, prf_algorithm, Algo}}
+ end;
+ _ ->
+ case Ret of
+ {ok, Expected} -> ok;
+ {ok, Val} -> {error, {expected, Expected, got, Val, tls_ver, TlsVer,
+ prf_algorithm, Algo}}
+ end
+ end.
+
+tls_or_dtls('dtlsv1') ->
+ dtls;
+tls_or_dtls('dtlsv1.2') ->
+ dtls;
+tls_or_dtls(_) ->
+ tls.
+
+active_n_common(S, N) ->
+ ok = ssl:setopts(S, [{active,-N}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,0}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ ok = ssl:setopts(S, [{active,32767}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,1}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,-32769}]),
+ ok = ssl:setopts(S, [{active,-32768}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,true}]),
+ [{active,true}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,once}]),
+ [{active,once}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ {error,{options,_}} = ssl:setopts(S, [{active,32768}]),
+ ok = ssl:setopts(S, [{active,false}]),
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok.
+
+ok({ok,V}) -> V.
+
+repeat(N, Fun) ->
+ repeat(N, N, Fun).
+
+repeat(N, T, Fun) when is_integer(N), N > 0 ->
+ Fun(T-N),
+ repeat(N-1, T, Fun);
+repeat(_, _, _) ->
+ ok.
+
+try_recv_active(Socket) ->
+ ssl:send(Socket, "Hello world"),
+ {error, einval} = ssl:recv(Socket, 11),
+ ok.
+try_recv_active_once(Socket) ->
+ {error, einval} = ssl:recv(Socket, 11),
+ ok.
+
+controlling_process_result(Socket, Pid, Msg) ->
+ ok = ssl:controlling_process(Socket, Pid),
+ %% Make sure other side has evaluated controlling_process
+ %% before message is sent
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, Msg),
+ no_result_msg.
+
+controller_dies_result(_Socket, _Pid, _Msg) ->
+ receive Result -> Result end.
+get_close(Pid, Where) ->
+ receive
+ {'EXIT', Pid, _Reason} ->
+ receive
+ {_, {ssl_closed, Socket}} ->
+ ct:log("Socket closed ~p~n",[Socket]);
+ Unexpected ->
+ ct:log("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 5000 ->
+ ct:fail({timeout, {line, ?LINE, Where}})
+ end;
+ Unexpected ->
+ ct:log("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 5000 ->
+ ct:fail({timeout, {line, ?LINE, Where}})
+ end.
+
+ssl_active_recv(N) ->
+ ssl_active_recv(N, []).
+
+ssl_active_recv(0, Acc) ->
+ Acc;
+ssl_active_recv(N, Acc) ->
+ receive
+ {ssl, _, Bytes} ->
+ ssl_active_recv(N-length(Bytes), Acc ++ Bytes)
+ end.
+
+send_recv_result_timeout_client(Socket) ->
+ {error, timeout} = ssl:recv(Socket, 11, 500),
+ {error, timeout} = ssl:recv(Socket, 11, 0),
+ ssl:send(Socket, "Hello world"),
+ receive
+ Msg ->
+ io:format("Msg ~p~n",[Msg])
+ after 500 ->
+ ok
+ end,
+ {ok, "Hello world"} = ssl:recv(Socket, 11, 500),
+ ok.
+send_recv_result_timeout_server(Socket) ->
+ ssl:send(Socket, "Hello"),
+ {ok, "Hello world"} = ssl:recv(Socket, 11),
+ ssl:send(Socket, " world"),
+ ok.
+
+do_recv_close(Socket) ->
+ {error, closed} = ssl:recv(Socket, 11),
+ receive
+ {_,{error,closed}} ->
+ error_extra_close_sent_to_user_process
+ after 500 ->
+ ok
+ end.
+
+tls_close(Socket) ->
+ ok = ssl_test_lib:send_recv_result(Socket),
+ case ssl:close(Socket, 5000) of
+ ok ->
+ ok;
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+run_error_server_close([Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:close(Socket).
+
+run_error_server([ Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:controlling_process(Socket, self()).
+
+run_client_error([Port, Opts]) ->
+ ssl:connect("localhost", Port, Opts).
+
+honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{ciphers, ServerCiphers}, {honor_cipher_order, Honor}
+ | 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, ClientCiphers}, {honor_cipher_order, Honor}
+ | ClientOpts]}]),
+
+ Version = ssl_test_lib:protocol_version(Config),
+
+ ServerMsg = ClientMsg = {ok, {Version, Expected}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+connection_info_result(Socket) ->
+ {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]),
+ {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}.
+
+der_input_opts(Opts) ->
+ Certfile = proplists:get_value(certfile, Opts),
+ CaCertsfile = proplists:get_value(cacertfile, Opts),
+ Keyfile = proplists:get_value(keyfile, Opts),
+ Dhfile = proplists:get_value(dhfile, Opts),
+ [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile),
+ [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
+ [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile),
+ CaCerts =
+ lists:map(fun(Entry) ->
+ {_, CaCert, _} = Entry,
+ CaCert
+ end, ssl_test_lib:pem_to_der(CaCertsfile)),
+ {Cert, {Asn1Type, Key}, CaCerts, DHParams}.
diff --git a/lib/ssl/test/ssl_basic_SUITE_data/dHParam.pem b/lib/ssl/test/ssl_api_SUITE_data/dHParam.pem
index feb581da30..feb581da30 100644
--- a/lib/ssl/test/ssl_basic_SUITE_data/dHParam.pem
+++ b/lib/ssl/test/ssl_api_SUITE_data/dHParam.pem
diff --git a/lib/ssl/test/ssl_app_env_SUITE.erl b/lib/ssl/test/ssl_app_env_SUITE.erl
new file mode 100644
index 0000000000..27fbcb8e47
--- /dev/null
+++ b/lib/ssl/test/ssl_app_env_SUITE.erl
@@ -0,0 +1,171 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_app_env_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
+
+-define(SLEEP, 500).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], tests()},
+ {'tlsv1.2', [], tests()},
+ {'tlsv1.1', [], tests()},
+ {'tlsv1', [], tests()},
+ {'sslv3', [], tests()},
+ {'dtlsv1.2', [], tests()},
+ {'dtlsv1', [], tests()}
+ ].
+
+tests() ->
+ [
+ internal_active_1,
+ protocol_versions,
+ empty_protocol_versions
+ ].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ [{client_type, erlang},
+ {server_type, erlang} | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(internal_active_1, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, internal_active_n, 1),
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
+ Config;
+init_per_testcase(protocol_versions, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ case atom_to_list(Version) of
+ "d" ++ _ ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, dtls_protocol_version, [Version]),
+ ssl:start();
+ _ ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, protocol_version, [Version]),
+ ssl:start()
+ end,
+ ct:timetrap({seconds, 5}),
+ Config;
+init_per_testcase(empty_protocol_versions, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ ssl_test_lib:clean_env(),
+ application:set_env(ssl, protocol_version, []),
+ application:set_env(ssl, dtls_protocol_version, []),
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
+ Config;
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_, _Config) ->
+ ssl_test_lib:clean_start().
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+internal_active_1() ->
+ [{doc,"Test internal active 1 (behave as internal active once)"}].
+
+internal_active_1(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+protocol_versions() ->
+ [{doc,"Test to set a list of protocol versions in app environment."}].
+
+protocol_versions(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+empty_protocol_versions() ->
+ [{doc,"Test to set an empty list of protocol versions in app environment."}].
+
+empty_protocol_versions(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 4452adaea7..355cd31070 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -26,14 +26,8 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
--include_lib("public_key/include/public_key.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
--include("ssl_api.hrl").
--include("ssl_internal.hrl").
--include("ssl_alert.hrl").
--include("ssl_internal.hrl").
--include("tls_record.hrl").
--include("tls_handshake.hrl").
-define(TIMEOUT, 20000).
-define(EXPIRE, 10).
@@ -48,228 +42,35 @@
all() ->
[
{group, basic},
- {group, basic_tls},
- {group, options},
- {group, options_tls},
- {group, session},
- {group, 'dtlsv1.2'},
- {group, 'dtlsv1'},
- {group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'sslv3'}
+ {group, options}
].
groups() ->
[{basic, [], basic_tests()},
- {basic_tls, [], basic_tests_tls()},
- {options, [], options_tests()},
- {options_tls, [], options_tests_tls()},
- {'dtlsv1.2', [], all_versions_groups()},
- {'dtlsv1', [], all_versions_groups()},
- {'tlsv1.2', [], all_versions_groups() ++ tls_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]},
- {'tlsv1.1', [], all_versions_groups() ++ tls_versions_groups()},
- {'tlsv1', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests()},
- {'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() ++ [tls_ciphersuite_vs_version]},
- {api,[], api_tests()},
- {api_tls,[], api_tests_tls()},
- {tls_ciphers,[], tls_cipher_tests()},
- {session, [], session_tests()},
- {renegotiate, [], renegotiate_tests()},
- {ciphers, [], cipher_tests()},
- {ciphers_ec, [], cipher_tests_ec()},
- {error_handling_tests, [], error_handling_tests()},
- {error_handling_tests_tls, [], error_handling_tests_tls()}
+ {options, [], options_tests()}
].
-tls_versions_groups ()->
- [
- {group, api_tls},
- {group, tls_ciphers},
- {group, error_handling_tests_tls}].
-
-all_versions_groups ()->
- [{group, api},
- {group, renegotiate},
- {group, ciphers},
- {group, ciphers_ec},
- {group, error_handling_tests}].
-
-
basic_tests() ->
[app,
- appup,
- alerts,
- alert_details,
- alert_details_not_too_big,
+ appup,
version_option,
connect_twice,
connect_dist,
- clear_pem_cache,
defaults,
fallback,
cipher_format,
- suite_to_str
- ].
-
-basic_tests_tls() ->
- [tls_send_close
- ].
-
-options_tests() ->
- [der_input,
- ssl_options_not_proplist,
- raw_ssl_option,
- invalid_inet_get_option,
- invalid_inet_get_option_not_list,
- invalid_inet_get_option_improper_list,
- invalid_inet_set_option,
- invalid_inet_set_option_not_list,
- invalid_inet_set_option_improper_list,
- dh_params,
- invalid_certfile,
- invalid_cacertfile,
- invalid_keyfile,
- invalid_options,
- protocol_versions,
- empty_protocol_versions,
- ipv6,
- reuseaddr,
- honor_server_cipher_order,
- honor_client_cipher_order,
- unordered_protocol_versions_server,
- unordered_protocol_versions_client,
- max_handshake_size
-].
-
-options_tests_tls() ->
- [tls_misc_ssl_options,
- tls_tcp_reuseaddr].
-
-api_tests() ->
- [secret_connection_info,
- connection_information,
- peercert,
- peercert_with_client_cert,
- versions,
+ tls_versions_option,
eccs,
- controlling_process,
- getstat,
- close_with_timeout,
- hibernate,
- hibernate_right_away,
- listen_socket,
- ssl_recv_timeout,
- server_name_indication_option,
- accept_pool,
- prf,
- socket_options,
- active_n,
cipher_suites,
- handshake_continue,
- handshake_continue_timeout,
- hello_client_cancel,
- hello_server_cancel
- ].
-
-api_tests_tls() ->
- [tls_versions_option,
- tls_upgrade,
- tls_upgrade_with_timeout,
- tls_ssl_accept_timeout,
- tls_downgrade,
- tls_shutdown,
- tls_shutdown_write,
- tls_shutdown_both,
- tls_shutdown_error,
- peername,
- sockname,
- tls_socket_options,
- new_options_in_accept
- ].
-
-session_tests() ->
- [reuse_session,
- reuse_session_expired,
- server_does_not_want_to_reuse_session,
- no_reuses_session_server_restart_new_cert,
- no_reuses_session_server_restart_new_cert_file].
-
-renegotiate_tests() ->
- [client_renegotiate,
- server_renegotiate,
- client_secure_renegotiate,
- client_secure_renegotiate_fallback,
- client_renegotiate_reused_session,
- server_renegotiate_reused_session,
- client_no_wrap_sequence_number,
- server_no_wrap_sequence_number,
- renegotiate_dos_mitigate_active,
- renegotiate_dos_mitigate_passive,
- renegotiate_dos_mitigate_absolute].
-
-tls_cipher_tests() ->
- [rc4_rsa_cipher_suites,
- rc4_ecdh_rsa_cipher_suites,
- rc4_ecdsa_cipher_suites].
-
-cipher_tests() ->
- [old_cipher_suites,
- cipher_suites_mix,
- ciphers_rsa_signed_certs,
- ciphers_rsa_signed_certs_openssl_names,
- ciphers_dsa_signed_certs,
- ciphers_dsa_signed_certs_openssl_names,
- chacha_rsa_cipher_suites,
- chacha_ecdsa_cipher_suites,
- anonymous_cipher_suites,
- psk_cipher_suites,
- psk_with_hint_cipher_suites,
- psk_anon_cipher_suites,
- psk_anon_with_hint_cipher_suites,
- srp_cipher_suites,
- srp_anon_cipher_suites,
- srp_dsa_cipher_suites,
- des_rsa_cipher_suites,
- des_ecdh_rsa_cipher_suites,
- default_reject_anonymous].
-
-cipher_tests_ec() ->
- [ciphers_ecdsa_signed_certs,
- ciphers_ecdsa_signed_certs_openssl_names,
- ciphers_ecdh_rsa_signed_certs,
- ciphers_ecdh_rsa_signed_certs_openssl_names].
-
-error_handling_tests()->
- [close_transport_accept,
- recv_active,
- recv_active_once,
- recv_active_n,
- recv_error_handling,
- call_in_error_state,
- close_in_error_state,
- abuse_transport_accept_socket,
- controlling_process_transport_accept_socket
- ].
-
-error_handling_tests_tls()->
- [controller_dies,
- tls_client_closes_socket,
- tls_closed_in_active_once,
- tls_tcp_error_propagation_in_active_mode,
- tls_tcp_connect,
- tls_tcp_connect_big,
- tls_dont_crash_on_handshake_garbage
+ old_cipher_suites,
+ cipher_suites_mix
].
-rizzo_tests() ->
- [rizzo,
- no_rizzo_rc4,
- rizzo_one_n_minus_one,
- rizzo_zero_n,
- rizzo_disabled].
+options_tests() ->
+ [
+ unordered_protocol_versions_server,
+ unordered_protocol_versions_client].
-%%--------------------------------------------------------------------
init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
@@ -292,231 +93,6 @@ end_per_suite(_Config) ->
application:stop(crypto).
%%--------------------------------------------------------------------
-
-init_per_group(GroupName, Config) when GroupName == basic_tls;
- GroupName == options_tls;
- GroupName == options;
- GroupName == basic;
- GroupName == session;
- GroupName == error_handling_tests_tls
- ->
- ssl_test_lib:clean_tls_version(Config);
-init_per_group(GroupName, Config) ->
- ssl_test_lib:clean_tls_version(Config),
- case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl_test_lib:init_tls_version(GroupName, Config);
- _ ->
- case ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl:start(),
- Config;
- false ->
- {skip, "Missing crypto support"}
- end
- end.
-
-end_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
- true ->
- ssl_test_lib:clean_tls_version(Config);
- false ->
- Config
- end.
-
-%%--------------------------------------------------------------------
-init_per_testcase(Case, Config) when Case == unordered_protocol_versions_client;
- Case == unordered_protocol_versions_server->
- case proplists:get_value(supported, ssl:versions()) of
- ['tlsv1.2' | _] ->
- ct:timetrap({seconds, 5}),
- Config;
- _ ->
- {skip, "TLS 1.2 need but not supported on this platform"}
- end;
-
-init_per_testcase(protocol_versions, Config) ->
- ssl:stop(),
- application:load(ssl),
- %% For backwards compatibility sslv2 should be filtered out.
- application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]),
- ssl:start(),
- ct:timetrap({seconds, 5}),
- Config;
-
-init_per_testcase(reuse_session_expired, Config) ->
- ssl:stop(),
- application:load(ssl),
- ssl_test_lib:clean_env(),
- application:set_env(ssl, session_lifetime, ?EXPIRE),
- application:set_env(ssl, session_delay_cleanup_time, 500),
- ssl:start(),
- ct:timetrap({seconds, 30}),
- Config;
-
-init_per_testcase(empty_protocol_versions, Config) ->
- ssl:stop(),
- application:load(ssl),
- ssl_test_lib:clean_env(),
- application:set_env(ssl, protocol_version, []),
- ssl:start(),
- ct:timetrap({seconds, 5}),
- Config;
-
-init_per_testcase(fallback, Config) ->
- case tls_record:highest_protocol_version([]) of
- {3, N} when N > 1 ->
- ct:timetrap({seconds, 5}),
- Config;
- _ ->
- {skip, "Not relevant if highest supported version is less than 3.2"}
- end;
-
-init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;
- TestCase == server_renegotiate;
- TestCase == client_secure_renegotiate;
- TestCase == client_renegotiate_reused_session;
- TestCase == server_renegotiate_reused_session;
- TestCase == client_no_wrap_sequence_number;
- TestCase == server_no_wrap_sequence_number;
- TestCase == renegotiate_dos_mitigate_active;
- TestCase == renegotiate_dos_mitigate_passive;
- TestCase == renegotiate_dos_mitigate_absolute ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, ?SEC_RENEGOTIATION_TIMEOUT + 5}),
- Config;
-
-init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites;
- TestCase == psk_with_hint_cipher_suites;
- TestCase == ciphers_rsa_signed_certs;
- TestCase == ciphers_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == ciphers_ecdsa_signed_certs;
- TestCase == ciphers_ecdsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == psk_anon_cipher_suites;
- TestCase == psk_anon_with_hint_cipher_suites;
- TestCase == srp_cipher_suites;
- TestCase == srp_anon_cipher_suites;
- TestCase == srp_dsa_cipher_suites;
- TestCase == des_rsa_cipher_suites;
- TestCase == des_ecdh_rsa_cipher_suites;
- TestCase == versions_option;
- TestCase == tls_tcp_connect_big ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 60}),
- Config;
-
-init_per_testcase(version_option, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 10}),
- Config;
-
-init_per_testcase(reuse_session, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 10}),
- Config;
-
-init_per_testcase(rizzo, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 60}),
- Config;
-
-init_per_testcase(no_rizzo_rc4, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 60}),
- Config;
-
-init_per_testcase(rizzo_one_n_minus_one, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 60}),
- rizzo_add_mitigation_option(one_n_minus_one, Config);
-
-init_per_testcase(rizzo_zero_n, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 60}),
- rizzo_add_mitigation_option(zero_n, Config);
-
-init_per_testcase(rizzo_disabled, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 60}),
- rizzo_add_mitigation_option(disabled, Config);
-
-init_per_testcase(TestCase, Config) when TestCase == no_reuses_session_server_restart_new_cert_file;
- TestCase == no_reuses_session_server_restart_new_cert ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 15}),
- Config;
-
-init_per_testcase(prf, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 40}),
- case proplists:get_value(tc_group_path, Config) of
- [] -> Prop = [];
- [Prop] -> Prop
- end,
- case proplists:get_value(name, Prop) of
- undefined -> TlsVersions = [sslv3, tlsv1, 'tlsv1.1', 'tlsv1.2'];
- TlsVersion when is_atom(TlsVersion) ->
- TlsVersions = [TlsVersion]
- end,
- PRFS=[md5, sha, sha256, sha384, sha512],
- %All are the result of running tls_v1:prf(PrfAlgo, <<>>, <<>>, <<>>, 16)
- %with the specified PRF algorithm
- ExpectedPrfResults=
- [{md5, <<96,139,180,171,236,210,13,10,28,32,2,23,88,224,235,199>>},
- {sha, <<95,3,183,114,33,169,197,187,231,243,19,242,220,228,70,151>>},
- {sha256, <<166,249,145,171,43,95,158,232,6,60,17,90,183,180,0,155>>},
- {sha384, <<153,182,217,96,186,130,105,85,65,103,123,247,146,91,47,106>>},
- {sha512, <<145,8,98,38,243,96,42,94,163,33,53,49,241,4,127,28>>},
- %TLS 1.0 and 1.1 PRF:
- {md5sha, <<63,136,3,217,205,123,200,177,251,211,17,229,132,4,173,80>>}],
- TestPlan = prf_create_plan(TlsVersions, PRFS, ExpectedPrfResults),
- [{prf_test_plan, TestPlan} | Config];
-
-init_per_testcase(TestCase, Config) when TestCase == tls_ssl_accept_timeout;
- TestCase == tls_client_closes_socket;
- TestCase == tls_closed_in_active_once;
- TestCase == tls_downgrade ->
- ssl:stop(),
- ssl:start(),
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 15}),
- Config;
-init_per_testcase(TestCase, Config) when TestCase == clear_pem_cache;
- TestCase == der_input;
- TestCase == defaults ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- %% White box test need clean start
- ssl:stop(),
- ssl:start(),
- ct:timetrap({seconds, 20}),
- Config;
-init_per_testcase(raw_ssl_option, Config) ->
- ct:timetrap({seconds, 5}),
- case os:type() of
- {unix,linux} ->
- Config;
- _ ->
- {skip, "Raw options are platform-specific"}
- end;
-
-init_per_testcase(accept_pool, Config) ->
- ct:timetrap({seconds, 5}),
- case proplists:get_value(protocol, Config) of
- dtls ->
- {skip, "Not yet supported on DTLS sockets"};
- _ ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- Config
- end;
-init_per_testcase(controller_dies, Config) ->
- ct:timetrap({seconds, 10}),
- Config;
init_per_testcase(eccs, Config) ->
case ssl:eccs() of
[] ->
@@ -531,19 +107,8 @@ init_per_testcase(_TestCase, Config) ->
ct:timetrap({seconds, 5}),
Config.
-end_per_testcase(reuse_session_expired, Config) ->
- application:unset_env(ssl, session_lifetime),
- application:unset_env(ssl, session_delay_cleanup_time),
- end_per_testcase(default_action, Config);
-
-end_per_testcase(Case, Config) when Case == protocol_versions;
- Case == empty_protocol_versions->
- application:unset_env(ssl, protocol_versions),
- end_per_testcase(default_action, Config);
-
end_per_testcase(_TestCase, Config) ->
Config.
-
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -557,632 +122,76 @@ appup() ->
appup(Config) when is_list(Config) ->
ok = ?t:appup_test(ssl).
%%--------------------------------------------------------------------
-alerts() ->
- [{doc, "Test ssl_alert:alert_txt/1"}].
-alerts(Config) when is_list(Config) ->
- Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC,
- ?DECRYPTION_FAILED_RESERVED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE,
- ?HANDSHAKE_FAILURE, ?BAD_CERTIFICATE, ?UNSUPPORTED_CERTIFICATE,
- ?CERTIFICATE_REVOKED,?CERTIFICATE_EXPIRED, ?CERTIFICATE_UNKNOWN,
- ?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR,
- ?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION,
- ?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED,
- ?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE,
- ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
- ?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY,
- 255 %% Unsupported/unknow alert will result in a description too
- ],
- Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) |
- [?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]],
- lists:foreach(fun(Alert) ->
- try ssl_alert:alert_txt(Alert)
- catch
- C:E:T ->
- ct:fail({unexpected, {C, E, T}})
- end
- end, Alerts).
-%%--------------------------------------------------------------------
-alert_details() ->
- [{doc, "Test that ssl_alert:alert_txt/1 result contains extendend error description"}].
-alert_details(Config) when is_list(Config) ->
- Unique = make_ref(),
- UniqueStr = lists:flatten(io_lib:format("~w", [Unique])),
- Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Unique),
- case string:str(ssl_alert:alert_txt(Alert), UniqueStr) of
- 0 ->
- ct:fail(error_details_missing);
- _ ->
- ok
- end.
-
-%%--------------------------------------------------------------------
-alert_details_not_too_big() ->
- [{doc, "Test that ssl_alert:alert_txt/1 limits printed depth of extended error description"}].
-alert_details_not_too_big(Config) when is_list(Config) ->
- Reason = lists:duplicate(10, lists:duplicate(10, lists:duplicate(10, {some, data}))),
- Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Reason),
- case length(ssl_alert:alert_txt(Alert)) < 1000 of
- true ->
- ok;
- false ->
- ct:fail(ssl_alert_text_too_big)
- end.
-
-%%--------------------------------------------------------------------
-new_options_in_accept() ->
- [{doc,"Test that you can set ssl options in ssl_accept/3 and not only in tcp upgrade"}].
-new_options_in_accept(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_dsa_opts, Config),
- [_ , _ | ServerSslOpts] = ssl_test_lib:ssl_options(server_opts, Config), %% Remove non ssl opts
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Version = ssl_test_lib:protocol_options(Config, [{tls, sslv3}, {dtls, dtlsv1}]),
- Cipher = ssl_test_lib:protocol_options(Config, [{tls, #{key_exchange =>rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf
- }},
- {dtls, #{key_exchange =>rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf
- }}]),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {ssl_extra_opts, [{versions, [Version]},
- {ciphers,[Cipher]} | ServerSslOpts]}, %% To be set in ssl_accept/3
- {mfa, {?MODULE, connection_info_result, []}},
- {options, proplists:delete(cacertfile, ServerOpts0)}]),
-
- 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, [{versions, [Version]},
- {ciphers,[Cipher]} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ServerMsg = ClientMsg = {ok, {Version, Cipher}},
+version_option() ->
+ [{doc, "Use version option and do no specify ciphers list. Bug specified incorrect ciphers"}].
+version_option(Config) when is_list(Config) ->
+ Versions = proplists:get_value(supported, ssl:versions()),
+ [version_option_test(Config, Version) || Version <- Versions].
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
%%--------------------------------------------------------------------
-handshake_continue() ->
- [{doc, "Test API function ssl:handshake_continue/3"}].
-handshake_continue(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}],
- Config)},
- {continue_options, proplists:delete(reuseaddr, ServerOpts)}
- ]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ssl_test_lib:ssl_options([{handshake, hello}],
- Config)},
- {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%------------------------------------------------------------------
-handshake_continue_timeout() ->
- [{doc, "Test API function ssl:handshake_continue/3 with short timeout"}].
-handshake_continue_timeout(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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()},
- {timeout, 1},
- {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}],
- Config)},
- {continue_options, proplists:delete(reuseaddr, ServerOpts)}
- ]),
-
- Port = ssl_test_lib:inet_port(Server),
-
-
- {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, {error,timeout}),
- ssl_test_lib:close(Server).
-
-
-%%--------------------------------------------------------------------
-hello_client_cancel() ->
- [{doc, "Test API function ssl:handshake_cancel/1 on the client side"}].
-hello_client_cancel(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, proplists:delete(reuseaddr, ServerOpts)}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- %% That is ssl:handshake_cancel returns ok
- {connect_failed, ok} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, cancel}]),
- ssl_test_lib:check_server_alert(Server, user_canceled).
-%%--------------------------------------------------------------------
-hello_server_cancel() ->
- [{doc, "Test API function ssl:handshake_cancel/1 on the server side"}].
-hello_server_cancel(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, cancel}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
-
- ssl_test_lib:check_result(Server, ok).
-
-%%--------------------------------------------------------------------
-prf() ->
- [{doc,"Test that ssl:prf/5 uses the negotiated PRF."}].
-prf(Config) when is_list(Config) ->
- TestPlan = proplists:get_value(prf_test_plan, Config),
- case TestPlan of
- [] -> ct:fail({error, empty_prf_test_plan});
- _ -> lists:foreach(fun(Suite) ->
- lists:foreach(
- fun(Test) ->
- V = proplists:get_value(tls_ver, Test),
- C = proplists:get_value(ciphers, Test),
- E = proplists:get_value(expected, Test),
- P = proplists:get_value(prf, Test),
- prf_run_test(Config, V, C, E, P)
- end, Suite)
- end, TestPlan)
- end.
-
-%%--------------------------------------------------------------------
-
-secret_connection_info() ->
- [{doc,"Test the API function ssl:connection_information/2"}].
-secret_connection_info(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, secret_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, secret_connection_info_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, true, Client, true),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-
-connection_information() ->
- [{doc,"Test the API function ssl:connection_information/1"}].
-connection_information(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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_information_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_information_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ServerMsg = ClientMsg = ok,
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-protocol_versions() ->
- [{doc,"Test to set a list of protocol versions in app environment."}].
-
-protocol_versions(Config) when is_list(Config) ->
- basic_test(Config).
-
-%%--------------------------------------------------------------------
-empty_protocol_versions() ->
- [{doc,"Test to set an empty list of protocol versions in app environment."}].
-
-empty_protocol_versions(Config) when is_list(Config) ->
- basic_test(Config).
-
-%%--------------------------------------------------------------------
-
-controlling_process() ->
- [{doc,"Test API function controlling_process/2"}].
-
-controlling_process(Config) when is_list(Config) ->
+connect_twice() ->
+ [{doc,""}].
+connect_twice(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ClientMsg = "Server hello",
- ServerMsg = "Client hello",
-
- 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, CSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- controlling_process_result, [self(),
- ClientMsg]}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ServerMsg = ssl_test_lib:active_recv(CSocket, length(ServerMsg)),
- %% We do not have the TLS server socket but all messages form the client
- %% socket are now read, so ramining are form the server socket
- ClientMsg = ssl_active_recv(length(ClientMsg)),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-getstat() ->
- [{doc,"Test API function getstat/2"}].
-
-getstat(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port1 = ssl_test_lib:inet_port(Server1),
- Server2 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port2 = ssl_test_lib:inet_port(Server2),
- {ok, ActiveC} = rpc:call(ClientNode, ssl, connect,
- [Hostname,Port1,[{active, once}|ClientOpts]]),
- {ok, PassiveC} = rpc:call(ClientNode, ssl, connect,
- [Hostname,Port2,[{active, false}|ClientOpts]]),
-
- ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n",
- [self(), self(), Server1, Server2]),
-
- %% We only check that the values are non-zero initially
- %% (due to the handshake), and that sending more changes the values.
-
- %% Passive socket.
-
- {ok, InitialStats} = ssl:getstat(PassiveC),
- ct:pal("InitialStats ~p~n", [InitialStats]),
- [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats)
- || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
-
- ok = ssl:send(PassiveC, "Hello world"),
- wait_for_send(PassiveC),
- {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]),
- ct:pal("SStats ~p~n", [SStats]),
- [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats)
- || Name <- [send_cnt, send_oct]]),
-
- %% Active socket.
-
- {ok, InitialAStats} = ssl:getstat(ActiveC),
- ct:pal("InitialAStats ~p~n", [InitialAStats]),
- [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats)
- || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
-
- _ = receive
- {ssl, ActiveC, _} ->
- ok
- after
- ?SLEEP ->
- exit(timeout)
- end,
-
- ok = ssl:send(ActiveC, "Hello world"),
- wait_for_send(ActiveC),
- {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]),
- ct:pal("ASStats ~p~n", [ASStats]),
- [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats)
- || Name <- [send_cnt, send_oct]]),
-
- ok.
-
-%%--------------------------------------------------------------------
-controller_dies() ->
- [{doc,"Test that the socket is closed after controlling process dies"}].
-controller_dies(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
- ct:sleep(?SLEEP), %% 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,
- Tester = self(),
- Connect = fun(Pid) ->
- {ok, Socket} = ssl:connect(Hostname, Port, ClientOpts),
- %% Make sure server finishes and verification
- %% and is in coonection state before
- %% killing client
- ct:sleep(?SLEEP),
- 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,
-
- 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,
- ct:log("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 ->
- ct:log("Unexpected ~p~n",[Unexpected]),
- ct:fail({line, ?LINE-1})
- after 1000 ->
- ok
- end,
- Controller ! die_nice,
- get_close(Controller, ?LINE),
-
- %% Test that servers die
- Server ! listen,
- LastClient = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- controller_dies_result, [self(),
- ClientMsg]}},
- {options, ClientOpts}]),
- ct:sleep(?SLEEP), %% so that they are connected
-
- exit(Server, killed),
- get_close(Server, ?LINE),
- process_flag(trap_exit, false),
- ssl_test_lib:close(LastClient).
-
-%%--------------------------------------------------------------------
-tls_client_closes_socket() ->
- [{doc,"Test what happens when client closes socket before handshake is compleated"}].
-
-tls_client_closes_socket(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {tcp_options, TcpOpts},
- {ssl_options, ServerOpts}]),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{keepalive, true},{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, {ssl_test_lib, send_recv_result, []}},
+ {options, [{keepalive, true},{active, false}
+ | ClientOpts]}]),
+ Server ! listen,
- Connect = fun() ->
- {ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect,
- [Hostname, Port, [binary]]),
- %% Make sure that ssl_accept is called before
- %% client process ends and closes socket.
- ct:sleep(?SLEEP)
- end,
-
- _Client = spawn_link(Connect),
-
- ssl_test_lib:check_result(Server, {error,closed}).
-
-%%--------------------------------------------------------------------
-tls_closed_in_active_once() ->
- [{doc, "Test that ssl_closed is delivered in active once with non-empty buffer, check ERL-420."}].
-
-tls_closed_in_active_once(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
- Port = ssl_test_lib:inet_port(node()),
- Server = fun() ->
- {ok, Listen} = gen_tcp:listen(Port, TcpOpts),
- {ok, TcpServerSocket} = gen_tcp:accept(Listen),
- {ok, ServerSocket} = ssl:ssl_accept(TcpServerSocket, ServerOpts),
- lists:foreach(
- fun(_) ->
- ssl:send(ServerSocket, "some random message\r\n")
- end, lists:seq(1, 20)),
- %% Close TCP instead of SSL socket to trigger the bug:
- gen_tcp:close(TcpServerSocket),
- gen_tcp:close(Listen)
- end,
- spawn_link(Server),
- {ok, Socket} = ssl:connect(Hostname, Port, [{active, false} | ClientOpts]),
- Result = tls_closed_in_active_once_loop(Socket),
- ssl:close(Socket),
- case Result of
- ok -> ok;
- _ -> ct:fail(Result)
- end.
-
-tls_closed_in_active_once_loop(Socket) ->
- case ssl:setopts(Socket, [{active, once}]) of
- ok ->
- receive
- {ssl, Socket, _} ->
- tls_closed_in_active_once_loop(Socket);
- {ssl_closed, Socket} ->
- ok
- after 5000 ->
- no_ssl_closed_received
- end;
- {error, closed} ->
- ok
- end.
-%%--------------------------------------------------------------------
-connect_dist() ->
- [{doc,"Test a simple connect as is used by distribution"}].
-
-connect_dist(Config) when is_list(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_kc_opts, Config),
- ClientOpts = [{ssl_imp, new},{active, false}, {packet,4}|ClientOpts0],
- ServerOpts0 = ssl_test_lib:ssl_options(server_kc_opts, Config),
- ServerOpts = [{ssl_imp, new},{active, false}, {packet,4}|ServerOpts0],
+ {Client1, #sslsocket{}} =
+ ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{keepalive, true},{active, false}
+ | ClientOpts]}]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
- 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:check_result(Server, ok, Client1, ok),
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-clear_pem_cache() ->
- [{doc,"Test that internal reference tabel is cleaned properly even when "
- " the PEM cache is cleared" }].
-clear_pem_cache(Config) when is_list(Config) ->
- {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- [_,{FilRefDb, _} |_] = element(6, State),
- {Server, Client} = basic_verify_test_no_close(Config),
- CountReferencedFiles = fun({_, -1}, Acc) ->
- Acc;
- ({_, N}, Acc) ->
- N + Acc
- end,
-
- 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
- ssl:clear_pem_cache(),
- _ = sys:get_status(whereis(ssl_manager)),
- {Server1, Client1} = basic_verify_test_no_close(Config),
- 4 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
- ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
- ct:sleep(2000),
- _ = sys:get_status(whereis(ssl_manager)),
- 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1),
- ct:sleep(2000),
- _ = sys:get_status(whereis(ssl_manager)),
- 0 = ets:foldl(CountReferencedFiles, 0, FilRefDb).
+ ssl_test_lib:close(Client1).
+defaults(Config) when is_list(Config)->
+ Versions = ssl:versions(),
+ true = lists:member(sslv3, proplists:get_value(available, Versions)),
+ false = lists:member(sslv3, proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1', proplists:get_value(available, Versions)),
+ false = lists:member('tlsv1', proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1.1', proplists:get_value(available, Versions)),
+ false = lists:member('tlsv1.1', proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1.2', proplists:get_value(available, Versions)),
+ true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)),
+ false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()),
+ true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)),
+ false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()),
+ true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)),
+ false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()),
+ true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)),
+ true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)),
+ true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)),
+ true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)),
+ false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)).
-%%--------------------------------------------------------------------
fallback() ->
[{doc, "Test TLS_FALLBACK_SCSV downgrade prevention"}].
@@ -1208,7 +217,6 @@ fallback(Config) when is_list(Config) ->
| ClientOpts]}]),
ssl_test_lib:check_server_alert(Server, Client, inappropriate_fallback).
-
%%--------------------------------------------------------------------
cipher_format() ->
[{doc, "Test that cipher conversion from maps | tuples | stings to binarys works"}].
@@ -1222,175 +230,6 @@ cipher_format(Config) when is_list(Config) ->
ssl:close(Socket2).
%%--------------------------------------------------------------------
-suite_to_str() ->
- [{doc, "Test that the suite_to_str API works"}].
-suite_to_str(Config) when is_list(Config) ->
- "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" =
- ssl:suite_to_str(#{key_exchange => null,
- cipher => null,
- mac => null,
- prf => null}),
- "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" =
- ssl:suite_to_str(#{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256}),
- "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256" =
- ssl:suite_to_str(#{key_exchange => ecdh_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256}).
-
-%%--------------------------------------------------------------------
-
-peername() ->
- [{doc,"Test API function peername/1"}].
-
-peername(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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}},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-peercert() ->
- [{doc,"Test API function peercert/1"}].
-peercert(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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),
- [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
-
- ServerMsg = {error, no_peercert},
- ClientMsg = {ok, BinCert},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-peercert_result(Socket) ->
- ssl:peercert(Socket).
-%%--------------------------------------------------------------------
-
-peercert_with_client_cert() ->
- [{doc,"Test API function peercert/1"}].
-peercert_with_client_cert(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_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}]),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- [{'Certificate', ServerBinCert, _}]= ssl_test_lib:pem_to_der(ServerCertFile),
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- [{'Certificate', ClientBinCert, _}]= ssl_test_lib:pem_to_der(ClientCertFile),
-
- ServerMsg = {ok, ClientBinCert},
- ClientMsg = {ok, ServerBinCert},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-sockname() ->
- [{doc,"Test API function sockname/1"}].
-sockname(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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 =
- case proplists:get_value(protocol, Config) of
- dtls ->
- %% DTLS sockets are not connected on the server side,
- %% so we can only get a ClientIP, ServerIP will always be 0.0.0.0
- {0,0,0,0};
- _ ->
- ssl_test_lib:node_to_hostip(ServerNode)
- end,
-
- ClientIp = ssl_test_lib:node_to_hostip(ClientNode),
- ServerMsg = {ok, {ServerIp, Port}},
- ClientMsg = {ok, {ClientIp, ClientPort}},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-sockname_result(S) ->
- ssl:sockname(S).
-
-%%--------------------------------------------------------------------
cipher_suites() ->
[{doc,"Test API function cipher_suites/2, filter_cipher_suites/2"
@@ -1487,2884 +326,95 @@ cipher_suites_mix(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-tls_socket_options() ->
- [{doc,"Test API function getopts/2 and setopts/2"}].
+unordered_protocol_versions_server() ->
+ [{doc,"Test that the highest protocol is selected even"
+ " when it is not first in the versions list."}].
-tls_socket_options(Config) when is_list(Config) ->
+unordered_protocol_versions_server(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, tls_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, tls_socket_options_result,
- [Options, Values, NewOptions, NewValues]}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
-
- {ok, Listen} = ssl:listen(0, ServerOpts),
- {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
- ok = ssl:setopts(Listen, [{mode, binary}]),
- {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
- {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
- ssl:close(Listen).
-
-tls_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]),
- ssl:setopts(Socket, [{nodelay, true}]),
- {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
- {ok, All} = ssl:getopts(Socket, []),
- ct:log("All opts ~p~n", [All]),
- ok.
-
-
-%%--------------------------------------------------------------------
-socket_options() ->
- [{doc,"Test API function getopts/2 and setopts/2"}].
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-socket_options(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Values = [{mode, list}, {active, true}],
- %% Shall be the reverse order of Values!
- Options = [active, 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),
-
- {ok, Listen} = ssl:listen(0, ServerOpts),
- {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
- ok = ssl:setopts(Listen, [{mode, binary}]),
- {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
- {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
- ssl:close(Listen).
-
-
-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,[{reuseaddr, _}]} = ssl:getopts(Socket, [reuseaddr]),
- {ok, All} = ssl:getopts(Socket, []),
- ct:log("All opts ~p~n", [All]),
- ok.
-
-
-%%--------------------------------------------------------------------
-invalid_inet_get_option() ->
- [{doc,"Test handling of invalid inet options in getopts"}].
-
-invalid_inet_get_option(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, get_invalid_inet_option, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-invalid_inet_get_option_not_list() ->
- [{doc,"Test handling of invalid type in getopts"}].
-
-invalid_inet_get_option_not_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, get_invalid_inet_option_not_list, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-get_invalid_inet_option_not_list(Socket) ->
- {error, {options, {socket_options, some_invalid_atom_here}}}
- = ssl:getopts(Socket, some_invalid_atom_here),
- ok.
-
-%%--------------------------------------------------------------------
-invalid_inet_get_option_improper_list() ->
- [{doc,"Test handling of invalid type in getopts"}].
-
-invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, get_invalid_inet_option_improper_list, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-get_invalid_inet_option_improper_list(Socket) ->
- {error, {options, {socket_options, foo,_}}} = ssl:getopts(Socket, [packet | foo]),
- ok.
-
-%%--------------------------------------------------------------------
-invalid_inet_set_option() ->
- [{doc,"Test handling of invalid inet options in setopts"}].
-
-invalid_inet_set_option(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, set_invalid_inet_option, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-set_invalid_inet_option(Socket) ->
- {error, {options, {socket_options, {packet, foo}}}} = ssl:setopts(Socket, [{packet, foo}]),
- {error, {options, {socket_options, {header, foo}}}} = ssl:setopts(Socket, [{header, foo}]),
- {error, {options, {socket_options, {active, foo}}}} = ssl:setopts(Socket, [{active, foo}]),
- {error, {options, {socket_options, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]),
- ok.
-%%--------------------------------------------------------------------
-invalid_inet_set_option_not_list() ->
- [{doc,"Test handling of invalid type in setopts"}].
-
-invalid_inet_set_option_not_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, set_invalid_inet_option_not_list, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-set_invalid_inet_option_not_list(Socket) ->
- {error, {options, {not_a_proplist, some_invalid_atom_here}}}
- = ssl:setopts(Socket, some_invalid_atom_here),
- ok.
-
-%%--------------------------------------------------------------------
-invalid_inet_set_option_improper_list() ->
- [{doc,"Test handling of invalid tye in setopts"}].
-
-invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, set_invalid_inet_option_improper_list, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-set_invalid_inet_option_improper_list(Socket) ->
- {error, {options, {not_a_proplist, [{packet, 0} | {foo, 2}]}}} =
- ssl:setopts(Socket, [{packet, 0} | {foo, 2}]),
- ok.
-
-%%--------------------------------------------------------------------
-tls_misc_ssl_options() ->
- [{doc,"Test what happens when we give valid options"}].
-
-tls_misc_ssl_options(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Check that ssl options not tested elsewhere are filtered away e.i. not passed to inet.
- TestOpts = [{depth, 1},
- {key, undefined},
- {password, []},
- {reuse_session, fun(_,_,_,_) -> true end},
- {cb_info, {gen_tcp, tcp, tcp_closed, tcp_error}}],
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, TestOpts ++ ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, TestOpts ++ ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-ssl_options_not_proplist() ->
- [{doc,"Test what happens if an option is not a key value tuple"}].
-
-ssl_options_not_proplist(Config) when is_list(Config) ->
- BadOption = {client_preferred_next_protocols,
- client, [<<"spdy/3">>,<<"http/1.1">>], <<"http/1.1">>},
- {option_not_a_key_value_tuple, BadOption} =
- ssl:connect("twitter.com", 443, [binary, {active, false},
- BadOption]).
-
-%%--------------------------------------------------------------------
-raw_ssl_option() ->
- [{doc,"Ensure that a single 'raw' option is passed to ssl:listen correctly."}].
-
-raw_ssl_option(Config) when is_list(Config) ->
- % 'raw' option values are platform-specific; these are the Linux values:
- IpProtoTcp = 6,
- % Use TCP_KEEPIDLE, because (e.g.) TCP_MAXSEG can't be read back reliably.
- TcpKeepIdle = 4,
- KeepAliveTimeSecs = 55,
- LOptions = [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}],
- {ok, LSocket} = ssl:listen(0, LOptions),
- % Per http://www.erlang.org/doc/man/inet.html#getopts-2, we have to specify
- % exactly which raw option we want, and the size of the buffer.
- {ok, [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}]} = ssl:getopts(LSocket, [{raw, IpProtoTcp, TcpKeepIdle, 4}]).
-
-
-%%--------------------------------------------------------------------
-versions() ->
- [{doc,"Test API function versions/0"}].
-
-versions(Config) when is_list(Config) ->
- [_|_] = Versions = ssl:versions(),
- ct:log("~p~n", [Versions]).
-
-
-%%--------------------------------------------------------------------
-eccs() ->
- [{doc, "Test API functions eccs/0 and eccs/1"}].
-
-eccs(Config) when is_list(Config) ->
- [_|_] = All = ssl:eccs(),
- [] = SSL3 = ssl:eccs(sslv3),
- [_|_] = Tls = ssl:eccs(tlsv1),
- [_|_] = Tls1 = ssl:eccs('tlsv1.1'),
- [_|_] = Tls2 = ssl:eccs('tlsv1.2'),
- [_|_] = Tls1 = ssl:eccs('dtlsv1'),
- [_|_] = Tls2 = ssl:eccs('dtlsv1.2'),
- %% ordering is currently unverified by the test
- true = lists:sort(All) =:= lists:usort(SSL3 ++ Tls ++ Tls1 ++ Tls2),
- ok.
-
-%%--------------------------------------------------------------------
-send_recv() ->
- [{doc,""}].
-send_recv(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, 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, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_send_close() ->
- [{doc,""}].
-tls_send_close(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, 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}]]),
- {ok, SslS} = rpc:call(ClientNode, ssl, connect,
- [TcpS,[{active, false}|ClientOpts]]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), self(), Server]),
- ok = ssl:send(SslS, "Hello world"),
- {ok,<<"Hello world">>} = ssl:recv(SslS, 11),
- gen_tcp:close(TcpS),
- {error, _} = ssl:send(SslS, "Hello world").
-
-%%--------------------------------------------------------------------
-version_option() ->
- [{doc, "Use version option and do no specify ciphers list. Bug specified incorrect ciphers"}].
-version_option(Config) when is_list(Config) ->
- Versions = proplists:get_value(supported, ssl:versions()),
- [version_option_test(Config, Version) || Version <- Versions].
-
-%%--------------------------------------------------------------------
-close_transport_accept() ->
- [{doc,"Tests closing ssl socket when waiting on ssl:transport_accept/1"}].
-
-close_transport_accept(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Port = 0,
- Opts = [{active, false} | ServerOpts],
- {ok, ListenSocket} = rpc:call(ServerNode, ssl, listen, [Port, Opts]),
- spawn_link(fun() ->
- ct:sleep(?SLEEP),
- rpc:call(ServerNode, ssl, close, [ListenSocket])
- end),
- case rpc:call(ServerNode, ssl, transport_accept, [ListenSocket]) of
- {error, closed} ->
- ok;
- Other ->
- exit({?LINE, Other})
- end.
-%%--------------------------------------------------------------------
-recv_active() ->
- [{doc,"Test recv on active socket"}].
-
-recv_active(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, try_recv_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, try_recv_active, []}},
- {options, [{active, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-recv_active_once() ->
- [{doc,"Test recv on active (once) socket"}].
-
-recv_active_once(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, try_recv_active_once, []}},
- {options, [{active, once} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, try_recv_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).
-
-%%--------------------------------------------------------------------
-recv_active_n() ->
- [{doc,"Test recv on active (n) socket"}].
-
-recv_active_n(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, try_recv_active_once, []}},
- {options, [{active, 1} | ServerOpts]}]),
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, try_recv_active_once, []}},
- {options, [{active, 1} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-%% Test case adapted from gen_tcp_misc_SUITE.
-active_n() ->
- [{doc,"Test {active,N} option"}].
-
-active_n(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- Port = ssl_test_lib:inet_port(node()),
- N = 3,
- LS = ok(ssl:listen(Port, [{active,N}|ServerOpts])),
- [{active,N}] = ok(ssl:getopts(LS, [active])),
- active_n_common(LS, N),
- Self = self(),
- spawn_link(fun() ->
- S0 = ok(ssl:transport_accept(LS)),
- {ok, S} = ssl:handshake(S0),
- ok = ssl:setopts(S, [{active,N}]),
- [{active,N}] = ok(ssl:getopts(S, [active])),
- ssl:controlling_process(S, Self),
- Self ! {server, S}
- end),
- C = ok(ssl:connect("localhost", Port, [{active,N}|ClientOpts])),
- [{active,N}] = ok(ssl:getopts(C, [active])),
- S = receive
- {server, S0} -> S0
- after
- 1000 ->
- exit({error, connect})
- end,
- active_n_common(C, N),
- active_n_common(S, N),
- ok = ssl:setopts(C, [{active,N}]),
- ok = ssl:setopts(S, [{active,N}]),
- ReceiveMsg = fun(Socket, Msg) ->
- receive
- {ssl,Socket,Msg} ->
- ok;
- {ssl,Socket,Begin} ->
- receive
- {ssl,Socket,End} ->
- Msg = Begin ++ End,
- ok
- after 1000 ->
- exit(timeout)
- end
- after 1000 ->
- exit(timeout)
- end
- end,
- repeat(3, fun(I) ->
- Msg = "message "++integer_to_list(I),
- ok = ssl:send(C, Msg),
- ReceiveMsg(S, Msg),
- ok = ssl:send(S, Msg),
- ReceiveMsg(C, Msg)
- end),
- receive
- {ssl_passive,S} ->
- [{active,false}] = ok(ssl:getopts(S, [active]))
- after
- 1000 ->
- exit({error,ssl_passive})
- end,
- receive
- {ssl_passive,C} ->
- [{active,false}] = ok(ssl:getopts(C, [active]))
- after
- 1000 ->
- exit({error,ssl_passive})
- end,
- LS2 = ok(ssl:listen(0, [{active,0}])),
- receive
- {ssl_passive,LS2} ->
- [{active,false}] = ok(ssl:getopts(LS2, [active]))
- after
- 1000 ->
- exit({error,ssl_passive})
- end,
- ok = ssl:close(LS2),
- ok = ssl:close(C),
- ok = ssl:close(S),
- ok = ssl:close(LS),
- ok.
-
-active_n_common(S, N) ->
- ok = ssl:setopts(S, [{active,-N}]),
- receive
- {ssl_passive, S} -> ok
- after
- 1000 ->
- error({error,ssl_passive_failure})
- end,
- [{active,false}] = ok(ssl:getopts(S, [active])),
- ok = ssl:setopts(S, [{active,0}]),
- receive
- {ssl_passive, S} -> ok
- after
- 1000 ->
- error({error,ssl_passive_failure})
- end,
- ok = ssl:setopts(S, [{active,32767}]),
- {error,{options,_}} = ssl:setopts(S, [{active,1}]),
- {error,{options,_}} = ssl:setopts(S, [{active,-32769}]),
- ok = ssl:setopts(S, [{active,-32768}]),
- receive
- {ssl_passive, S} -> ok
- after
- 1000 ->
- error({error,ssl_passive_failure})
- end,
- [{active,false}] = ok(ssl:getopts(S, [active])),
- ok = ssl:setopts(S, [{active,N}]),
- ok = ssl:setopts(S, [{active,true}]),
- [{active,true}] = ok(ssl:getopts(S, [active])),
- receive
- _ -> error({error,active_n})
- after
- 0 ->
- ok
- end,
- ok = ssl:setopts(S, [{active,N}]),
- ok = ssl:setopts(S, [{active,once}]),
- [{active,once}] = ok(ssl:getopts(S, [active])),
- receive
- _ -> error({error,active_n})
- after
- 0 ->
- ok
- end,
- {error,{options,_}} = ssl:setopts(S, [{active,32768}]),
- ok = ssl:setopts(S, [{active,false}]),
- [{active,false}] = ok(ssl:getopts(S, [active])),
- ok.
-
-ok({ok,V}) -> V.
-
-repeat(N, Fun) ->
- repeat(N, N, Fun).
-
-repeat(N, T, Fun) when is_integer(N), N > 0 ->
- Fun(T-N),
- repeat(N-1, T, Fun);
-repeat(_, _, _) ->
- ok.
-
-%%--------------------------------------------------------------------
-dh_params() ->
- [{doc,"Test to specify DH-params file in server."}].
-
-dh_params(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- DataDir = proplists:get_value(data_dir, Config),
- DHParamFile = filename:join(DataDir, "dHParam.pem"),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{dhfile, DHParamFile} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{ciphers,[{dhe_rsa,aes_256_cbc,sha}]} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_upgrade() ->
- [{doc,"Test that you can upgrade an tcp connection to an ssl connection"}].
-
-tls_upgrade(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- upgrade_result, []}},
- {tcp_options,
- [{active, false} | 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, [binary]},
- {ssl_options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-upgrade_result(Socket) ->
- ssl:setopts(Socket, [{active, true}]),
- ok = ssl:send(Socket, "Hello world"),
- %% Make sure binary is inherited from tcp socket and that we do
- %% not get the list default!
- receive
- {ssl, _, <<"H">>} ->
- receive
- {ssl, _, <<"ello world">>} ->
- ok
- end;
- {ssl, _, <<"Hello world">>} ->
- ok
- end.
-
-%%--------------------------------------------------------------------
-tls_upgrade_with_timeout() ->
- [{doc,"Test ssl_accept/3"}].
-
-tls_upgrade_with_timeout(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {?MODULE,
- upgrade_result, []}},
- {tcp_options,
- [{active, false} | 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}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_downgrade() ->
- [{doc,"Test that you can downgarde an ssl connection to an tcp connection"}].
-tls_downgrade(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, tls_downgrade_result, [self()]}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_downgrade_result, [self()]}},
- {options, [{active, false} |ClientOpts]}]),
-
-
- ssl_test_lib:check_result(Server, ready, Client, ready),
-
- Server ! go,
- Client ! go,
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-close_with_timeout() ->
- [{doc,"Test normal (not downgrade) ssl:close/2"}].
-close_with_timeout(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, tls_close, []}},
- {options,[{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_close, []}},
- {options, [{active, false} |ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok).
-
-
-%%--------------------------------------------------------------------
-tls_tcp_connect() ->
- [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}].
-
-tls_tcp_connect(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}, {active, false}],
-
- Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {?MODULE, dummy, []}},
- {tcp_options, TcpOpts},
- {ssl_options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
- gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
-
- receive
- {tcp_closed, Socket} ->
- receive
- {Server, {error, Error}} ->
- ct:log("Error ~p", [Error])
- end
- end.
-%%--------------------------------------------------------------------
-tls_tcp_connect_big() ->
- [{doc,"Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"}].
-
-tls_tcp_connect_big(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Rand = crypto:strong_rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
- Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {?MODULE, dummy, []}},
- {tcp_options, TcpOpts},
- {ssl_options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
-
- gen_tcp:send(Socket, <<?BYTE(0),
- ?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>),
-
- receive
- {tcp_closed, Socket} ->
- receive
- {Server, {error, timeout}} ->
- ct:fail("hangs");
- {Server, {error, Error}} ->
- ct:log("Error ~p", [Error]);
- {'EXIT', Server, _} ->
- ok
- end
- end.
-
-%%--------------------------------------------------------------------
-ipv6() ->
- [{require, ipv6_hosts},
- {doc,"Test ipv6."}].
-ipv6(Config) when is_list(Config) ->
- {ok, Hostname0} = inet:gethostname(),
-
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, 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, {ssl_test_lib, send_recv_result, []}},
- {options,
- [inet6, {active, false} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client);
- false ->
- {skip, "Host does not support IPv6"}
- end.
-
-%%--------------------------------------------------------------------
-
-invalid_keyfile() ->
- [{doc,"Test what happens with an invalid key file"}].
-invalid_keyfile(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- BadOpts = ssl_test_lib:ssl_options(server_bad_key, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, BadOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {from, self()}, {options, ClientOpts}]),
+ {from, self()},
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, ClientOpts}]),
- File = proplists:get_value(keyfile,BadOpts),
- ssl_test_lib:check_result(Server, {error,{options, {keyfile, File, {error,enoent}}}}, Client,
- {error, closed}).
+ ServerMsg = ClientMsg = {ok,'tlsv1.2'},
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
+unordered_protocol_versions_client() ->
+ [{doc,"Test that the highest protocol is selected even"
+ " when it is not first in the versions list."}].
-invalid_certfile() ->
- [{doc,"Test what happens with an invalid cert file"}].
-
-invalid_certfile(Config) when is_list(Config) ->
+unordered_protocol_versions_client(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerBadOpts = ssl_test_lib:ssl_options(server_bad_cert, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerBadOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
- File = proplists:get_value(certfile, ServerBadOpts),
- ssl_test_lib:check_result(Server, {error,{options, {certfile, File, {error,enoent}}}},
- Client, {error, closed}).
-
-
-%%--------------------------------------------------------------------
-invalid_cacertfile() ->
- [{doc,"Test what happens with an invalid cacert file"}].
-
-invalid_cacertfile(Config) when is_list(Config) ->
- ClientOpts = [{reuseaddr, true}|ssl_test_lib:ssl_options(client_opts, Config)],
- ServerBadOpts = [{reuseaddr, true}|ssl_test_lib:ssl_options(server_bad_ca, Config)],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server0 =
- ssl_test_lib:start_server_error([{node, ServerNode},
- {port, 0}, {from, self()},
- {options, ServerBadOpts}]),
-
- Port0 = ssl_test_lib:inet_port(Server0),
-
-
- Client0 =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
-
- File0 = proplists:get_value(cacertfile, ServerBadOpts),
-
- ssl_test_lib:check_result(Server0, {error, {options, {cacertfile, File0,{error,enoent}}}},
- Client0, {error, closed}),
-
- File = File0 ++ "do_not_exit.pem",
- ServerBadOpts1 = [{cacertfile, File}|proplists:delete(cacertfile, ServerBadOpts)],
-
- Server1 =
- ssl_test_lib:start_server_error([{node, ServerNode},
- {port, 0}, {from, self()},
- {options, ServerBadOpts1}]),
-
- Port1 = ssl_test_lib:inet_port(Server1),
-
- Client1 =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port1}, {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
-
-
- ssl_test_lib:check_result(Server1, {error, {options, {cacertfile, File,{error,enoent}}}},
- Client1, {error, closed}),
- ok.
-
-
-
-%%--------------------------------------------------------------------
-invalid_options() ->
- [{doc,"Test what happens when we give invalid options"}].
-
-invalid_options(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Check = fun(Client, Server, {versions, [sslv2, sslv3]} = Option) ->
- ssl_test_lib:check_result(Server,
- {error, {options, {sslv2, Option}}},
- Client,
- {error, {options, {sslv2, Option}}});
- (Client, Server, Option) ->
- ssl_test_lib:check_result(Server,
- {error, {options, Option}},
- Client,
- {error, {options, Option}})
- end,
-
- TestOpts =
- [{versions, [sslv2, sslv3]},
- {verify, 4},
- {verify_fun, function},
- {fail_if_no_peer_cert, 0},
- {verify_client_once, 1},
- {depth, four},
- {certfile, 'cert.pem'},
- {keyfile,'key.pem' },
- {password, foo},
- {cacertfile, ""},
- {dhfile,'dh.pem' },
- {ciphers, [{foo, bar, sha, ignore}]},
- {reuse_session, foo},
- {reuse_sessions, 0},
- {renegotiate_at, "10"},
- {mode, depech},
- {packet, 8.0},
- {packet_size, "2"},
- {header, a},
- {active, trice},
- {key, 'key.pem' }],
-
- [begin
- Server =
- ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [TestOpt | ServerOpts]}]),
- %% Will never reach a point where port is used.
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0},
- {host, Hostname}, {from, self()},
- {options, [TestOpt | ClientOpts]}]),
- Check(Client, Server, TestOpt),
- ok
- end || TestOpt <- TestOpts],
- ok.
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-%%--------------------------------------------------------------------
-tls_shutdown() ->
- [{doc,"Test API function ssl:shutdown/2"}].
-tls_shutdown(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, tls_shutdown_result, [server]}},
- {options, [{exit_on_close, false},
- {active, false} | ServerOpts]}]),
+ {mfa, {?MODULE, protocol_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, tls_shutdown_result, [client]}},
- {options,
- [{exit_on_close, false},
- {active, false} | ClientOpts]}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_shutdown_write() ->
- [{doc,"Test API function ssl:shutdown/2 with option write."}].
-tls_shutdown_write(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, tls_shutdown_write_result, [server]}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_shutdown_write_result, [client]}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
-
-%%--------------------------------------------------------------------
-tls_shutdown_both() ->
- [{doc,"Test API function ssl:shutdown/2 with option both."}].
-tls_shutdown_both(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, tls_shutdown_both_result, [server]}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_shutdown_both_result, [client]}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
-
-%%--------------------------------------------------------------------
-tls_shutdown_error() ->
- [{doc,"Test ssl:shutdown/2 error handling"}].
-tls_shutdown_error(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_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_rsa_signed_certs() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:rsa_suites(crypto),
- run_suites(Ciphers, Config, rsa).
-%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs_openssl_names() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_rsa_suites(),
- run_suites(Ciphers, Config, rsa).
-
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:dsa_suites(NVersion),
- run_suites(Ciphers, Config, dsa).
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs_openssl_names() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_dsa_suites(),
- run_suites(Ciphers, Config, dsa).
-
-%%-------------------------------------------------------------------
-chacha_rsa_cipher_suites()->
- [{doc,"Test the cacha with ECDSA signed certs ciphersuites"}].
-chacha_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {KeyEx,_,_} = S <- ssl_test_lib:chacha_suites(NVersion),
- KeyEx == ecdhe_rsa, KeyEx == dhe_rsa],
- run_suites(Ciphers, Config, chacha_ecdsa).
-
-%%-------------------------------------------------------------------
-chacha_ecdsa_cipher_suites()->
- [{doc,"Test the cacha with ECDSA signed certs ciphersuites"}].
-chacha_ecdsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {ecdhe_ecdsa,_,_} = S <- ssl_test_lib:chacha_suites(NVersion)],
- run_suites(Ciphers, Config, chacha_rsa).
-%%-----------------------------------------------------------------
-anonymous_cipher_suites()->
- [{doc,"Test the anonymous ciphersuites"}].
-anonymous_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(NVersion),
- run_suites(Ciphers, Config, anonymous).
-%%-------------------------------------------------------------------
-psk_cipher_suites() ->
- [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk).
-%%-------------------------------------------------------------------
-psk_with_hint_cipher_suites()->
- [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
-psk_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk_with_hint).
-%%-------------------------------------------------------------------
-psk_anon_cipher_suites() ->
- [{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_anon_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon).
-%%-------------------------------------------------------------------
-psk_anon_with_hint_cipher_suites()->
- [{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
-psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon_with_hint).
-%%-------------------------------------------------------------------
-srp_cipher_suites()->
- [{doc, "Test the SRP ciphersuites"}].
-srp_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_suites(),
- run_suites(Ciphers, Config, srp).
-%%-------------------------------------------------------------------
-srp_anon_cipher_suites()->
- [{doc, "Test the anonymous SRP ciphersuites"}].
-srp_anon_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_anon_suites(),
- run_suites(Ciphers, Config, srp_anon).
-%%-------------------------------------------------------------------
-srp_dsa_cipher_suites()->
- [{doc, "Test the SRP DSA ciphersuites"}].
-srp_dsa_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_dss_suites(),
- run_suites(Ciphers, Config, srp_dsa).
-%%-------------------------------------------------------------------
-rc4_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_rsa).
-%-------------------------------------------------------------------
-rc4_ecdh_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {ecdh_rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdh_rsa).
-
-%%-------------------------------------------------------------------
-rc4_ecdsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Ciphers = [S || {ecdhe_ecdsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdsa).
-
-%%-------------------------------------------------------------------
-des_rsa_cipher_suites()->
- [{doc, "Test the des_rsa ciphersuites"}].
-des_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Ciphers = [S || {rsa,_,_} = S <- ssl_test_lib:des_suites(NVersion)],
- run_suites(Ciphers, Config, des_rsa).
-%-------------------------------------------------------------------
-des_ecdh_rsa_cipher_suites()->
- [{doc, "Test ECDH rsa signed ciphersuites"}].
-des_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {dhe_rsa,_,_} = S <- ssl_test_lib:des_suites(NVersion)],
- run_suites(Ciphers, Config, des_dhe_rsa).
-
-%%--------------------------------------------------------------------
-default_reject_anonymous()->
- [{doc,"Test that by default anonymous cipher suites are rejected "}].
-default_reject_anonymous(Config) when is_list(Config) ->
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- Version = ssl_test_lib:protocol_version(Config),
- TLSVersion = ssl_test_lib:tls_version(Version),
-
- [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
-
-%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_rsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdh_rsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
- run_suites(Ciphers, Config, ecdh_rsa).
-%%--------------------------------------------------------------------
-reuse_session() ->
- [{doc,"Test reuse of sessions (short handshake)"}].
-reuse_session(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
-%%--------------------------------------------------------------------
-reuse_session_expired() ->
- [{doc,"Test sessions is not reused when it has expired"}].
-reuse_session_expired(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server0 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {tcp_options, [{active, false}]},
- {options, ServerOpts}]),
- Port0 = ssl_test_lib:inet_port(Server0),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
- Server0 ! listen,
-
- Client1 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, ClientOpts}]),
-
- SID = receive
- {Client0, Id0} ->
- Id0
- end,
-
- receive
- {Client1, SID} ->
- ok
- after ?SLEEP ->
- ct:fail(session_not_reused)
- end,
-
- Server0 ! listen,
-
- %% Make sure session is unregistered due to expiration
- ct:sleep((?EXPIRE*2)),
-
- make_sure_expired(Hostname, Port0, SID),
-
- Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client2, SID} ->
- ct:fail(session_reused_when_session_expired);
- {Client2, _} ->
- ok
- end,
- process_flag(trap_exit, false),
- ssl_test_lib:close(Server0),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1),
- ssl_test_lib:close(Client2).
-
-make_sure_expired(Host, Port, Id) ->
- {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- ClientCache = element(2, State),
-
- case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of
- undefined ->
- ok;
- #session{is_resumable = false} ->
- ok;
- _ ->
- ct:sleep(?SLEEP),
- make_sure_expired(Host, Port, Id)
- end.
-
-%%--------------------------------------------------------------------
-server_does_not_want_to_reuse_session() ->
- [{doc,"Test reuse of sessions (short handshake)"}].
-server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, session_info_result, []}},
- {options, [{reuse_session, fun(_,_,_,_) ->
- false
- end} |
- ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
- ssl_test_lib:close(Client0),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client1, SessionInfo} ->
- ct:fail(session_reused_when_server_does_not_want_to);
- {Client1, _Other} ->
- ok
- end,
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-client_renegotiate() ->
- [{doc,"Test ssl:renegotiate/1 on client."}].
-client_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_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, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate, [Data]}},
- {options, [{reuse_sessions, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_secure_renegotiate() ->
- [{doc,"Test ssl:renegotiate/1 on client."}].
-client_secure_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_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, [{secure_renegotiate, 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,
- renegotiate, [Data]}},
- {options, [{reuse_sessions, false},
- {secure_renegotiate, true}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_secure_renegotiate_fallback() ->
- [{doc,"Test that we can set secure_renegotiate to false that is "
- "fallback option, we however do not have a insecure server to test against!"}].
-client_secure_renegotiate_fallback(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_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, [{secure_renegotiate, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate, [Data]}},
- {options, [{reuse_sessions, false},
- {secure_renegotiate, false}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
+
+connect_dist() ->
+ [{doc,"Test a simple connect as is used by distribution"}].
-%%--------------------------------------------------------------------
-server_renegotiate() ->
- [{doc,"Test ssl:renegotiate/1 on server."}].
-server_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+connect_dist(Config) when is_list(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_kc_opts, Config),
+ ClientOpts = [{ssl_imp, new},{active, false}, {packet,4}|ClientOpts0],
+ ServerOpts0 = ssl_test_lib:ssl_options(server_kc_opts, Config),
+ ServerOpts = [{ssl_imp, new},{active, false}, {packet,4}|ServerOpts0],
{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,
- renegotiate, [Data]}},
+ {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, erlang_ssl_receive, [Data]}},
- {options, [{reuse_sessions, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_renegotiate_reused_session() ->
- [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}].
-client_renegotiate_reused_session(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_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, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate_reuse_session, [Data]}},
- {options, [{reuse_sessions, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-server_renegotiate_reused_session() ->
- [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}].
-server_renegotiate_reused_session(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_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,
- renegotiate_reuse_session, [Data]}},
- {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, erlang_ssl_receive, [Data]}},
- {options, [{reuse_sessions, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-client_no_wrap_sequence_number() ->
- [{doc,"Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-
-client_no_wrap_sequence_number(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to erlang",
- N = 12,
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Version = ssl_test_lib:protocol_version(Config, tuple),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[ErlData, treashold(N, Version)]]}},
- {options, [{reuse_sessions, false},
- {renegotiate_at, N} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-server_no_wrap_sequence_number() ->
- [{doc, "Test that erlang server will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-
-server_no_wrap_sequence_number(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang to erlang",
- N = 12,
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[Data, N+2]]}},
- {options, [{renegotiate_at, N} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{reuse_sessions, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-der_input() ->
- [{doc,"Test to input certs and key as der"}].
-
-der_input(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- DHParamFile = filename:join(DataDir, "dHParam.pem"),
-
- {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- [CADb | _] = element(6, State),
-
- Size = ets:info(CADb, size),
-
- SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
- SeverVerifyOpts]),
- ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
- ClientVerifyOpts]),
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
- {dh, DHParams},
- {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}],
- ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
- {dh, DHParams},
- {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {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, {ssl_test_lib, 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),
- Size = ets:info(CADb, size).
-
-%%--------------------------------------------------------------------
-der_input_opts(Opts) ->
- Certfile = proplists:get_value(certfile, Opts),
- CaCertsfile = proplists:get_value(cacertfile, Opts),
- Keyfile = proplists:get_value(keyfile, Opts),
- Dhfile = proplists:get_value(dhfile, Opts),
- [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile),
- [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
- [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile),
- CaCerts =
- lists:map(fun(Entry) ->
- {_, CaCert, _} = Entry,
- CaCert
- end, ssl_test_lib:pem_to_der(CaCertsfile)),
- {Cert, {Asn1Type, Key}, CaCerts, DHParams}.
-
-%%--------------------------------------------------------------------
-no_reuses_session_server_restart_new_cert() ->
- [{doc,"Check that a session is not reused if the server is restarted with a new cert."}].
-no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
-
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
- Monitor = erlang:monitor(process, Server),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
- receive
- {'DOWN', Monitor, _, _, _} ->
- ok
- end,
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{reuseaddr, true} | DsaServerOpts]}]),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client1, SessionInfo} ->
- ct:fail(session_reused_when_server_has_new_cert);
- {Client1, _Other} ->
- ok
- end,
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-no_reuses_session_server_restart_new_cert_file() ->
- [{doc,"Check that a session is not reused if a server is restarted with a new "
- "cert contained in a file with the same name as the old cert."}].
-
-no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
-
- NewServerOpts0 = new_config(PrivDir, ServerOpts),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, NewServerOpts0}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- %% Make sure session is registered and we get
- %% new file time stamp when calling new_config!
- ct:sleep(?SLEEP* 2),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
-
- ssl:clear_pem_cache(),
-
- NewServerOpts1 = new_config(PrivDir, DsaServerOpts),
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{reuseaddr, true} | NewServerOpts1]}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client1, SessionInfo} ->
- ct:fail(session_reused_when_server_has_new_cert);
- {Client1, _Other} ->
- ok
- end,
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-defaults(Config) when is_list(Config)->
- Versions = ssl:versions(),
- true = lists:member(sslv3, proplists:get_value(available, Versions)),
- false = lists:member(sslv3, proplists:get_value(supported, Versions)),
- true = lists:member('tlsv1', proplists:get_value(available, Versions)),
- true = lists:member('tlsv1', proplists:get_value(supported, Versions)),
- true = lists:member('tlsv1.1', proplists:get_value(available, Versions)),
- true = lists:member('tlsv1.1', proplists:get_value(supported, Versions)),
- true = lists:member('tlsv1.2', proplists:get_value(available, Versions)),
- true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)),
- false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()),
- true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)),
- false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()),
- true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)),
- false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()),
- true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)),
- true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)),
- true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)),
- true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)),
- true = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)).
-
-%%--------------------------------------------------------------------
-reuseaddr() ->
- [{doc,"Test reuseaddr option"}].
-
-reuseaddr(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, no_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, {ssl_test_lib, no_result, []}},
- {options, [{active, false} | ClientOpts]}]),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server1, ok, Client1, ok),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-tls_tcp_reuseaddr() ->
- [{doc, "Reference test case."}].
-tls_tcp_reuseaddr(Config) when is_list(Config) ->
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {transport, gen_tcp},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, false}, {reuseaddr, true}]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {transport, gen_tcp},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, false}]}]),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {transport, gen_tcp},
- {mfa, {?MODULE, tcp_send_recv_result, []}},
- {options, [{active, false}, {reuseaddr, true}]}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {transport, gen_tcp},
- {mfa, {?MODULE, tcp_send_recv_result, []}},
- {options, [{active, false}]}]),
-
- ssl_test_lib:check_result(Server1, ok, Client1, ok),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-
-honor_server_cipher_order() ->
- [{doc,"Test API honor server cipher order."}].
-honor_server_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf}],
- ServerCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac =>sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf}],
- honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf}).
-
-honor_client_cipher_order() ->
- [{doc,"Test API honor server cipher order."}].
-honor_client_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf}],
- ServerCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac =>sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf}],
-honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf}).
-
-honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, [{ciphers, ServerCiphers}, {honor_cipher_order, Honor}
- | 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, ClientCiphers}, {honor_cipher_order, Honor}
- | ClientOpts]}]),
-
- Version = ssl_test_lib:protocol_version(Config),
-
- ServerMsg = ClientMsg = {ok, {Version, Expected}},
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_ciphersuite_vs_version() ->
- [{doc,"Test a SSLv3 client can not negotiate a TLSv* cipher suite."}].
-tls_ciphersuite_vs_version(Config) when is_list(Config) ->
-
- {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
- ok = gen_tcp:send(Socket,
- <<22, 3,0, 49:16, % handshake, SSL 3.0, length
- 1, 45:24, % client_hello, length
- 3,0, % SSL 3.0
- 16#deadbeef:256, % 32 'random' bytes = 256 bits
- 0, % no session ID
- %% three cipher suites -- null, one with sha256 hash and one with sha hash
- 6:16, 0,255, 0,61, 0,57,
- 1, 0 % no compression
- >>),
- {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000),
- {ok, <<HelloBin:HelloLen/binary>>} = gen_tcp:recv(Socket, HelloLen, 5000),
- ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin),
- case ServerHello of
- #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} ->
- ok;
- _ ->
- ct:fail({unexpected_server_hello, ServerHello})
- end.
-
-%%--------------------------------------------------------------------
-conf_signature_algs() ->
- [{doc,"Test to set the signature_algs option on both client and server"}].
-conf_signature_algs(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-no_common_signature_algs() ->
- [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}].
-no_common_signature_algs(Config) when is_list(Config) ->
-
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{signature_algs, [{sha256, rsa}]}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{signature_algs, [{sha384, rsa}]}
- | ClientOpts]}]),
-
- ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
-
-%%--------------------------------------------------------------------
-
-tls_dont_crash_on_handshake_garbage() ->
- [{doc, "Ensure SSL server worker thows an alert on garbage during handshake "
- "instead of crashing and exposing state to user code"}].
-
-tls_dont_crash_on_handshake_garbage(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- unlink(Server), monitor(process, Server),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
-
- % Send hello and garbage record
- ok = gen_tcp:send(Socket,
- [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello
- 16#deadbeef:256, % 32 'random' bytes = 256 bits
- 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values
-
- <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage
- ]),
- % Send unexpected change_cipher_spec
- ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>),
-
- % Ensure we receive an alert, not sudden disconnect
- {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000).
-
-drop_handshakes(Socket, Timeout) ->
- {ok, <<RecType:8, _RecMajor:8, _RecMinor:8, RecLen:16>> = Header} = gen_tcp:recv(Socket, 5, Timeout),
- {ok, <<Frag:RecLen/binary>>} = gen_tcp:recv(Socket, RecLen, Timeout),
- case RecType of
- 22 -> drop_handshakes(Socket, Timeout);
- _ -> {ok, <<Header/binary, Frag/binary>>}
- end.
-
-
-%%--------------------------------------------------------------------
-
-hibernate() ->
- [{doc,"Check that an SSL connection that is started with option "
- "{hibernate_after, 1000} indeed hibernates after 1000ms of "
- "inactivity"}].
-
-hibernate(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{hibernate_after, 1000}|ClientOpts]}]),
- {current_function, _} =
- process_info(Pid, current_function),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- timer:sleep(1500),
- {current_function, {erlang, hibernate, 3}} =
- process_info(Pid, current_function),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-hibernate_right_away() ->
- [{doc,"Check that an SSL connection that is configured to hibernate "
- "after 0 or 1 milliseconds hibernates as soon as possible and not "
- "crashes"}].
-
-hibernate_right_away(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- StartServerOpts = [{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}],
- StartClientOpts = [return_socket,
- {node, ClientNode},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}}],
-
- Server1 = ssl_test_lib:start_server(StartServerOpts),
- Port1 = ssl_test_lib:inet_port(Server1),
- {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++
- [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]),
-
- ssl_test_lib:check_result(Server1, ok, Client1, ok),
-
- {current_function, {erlang, hibernate, 3}} =
- process_info(Pid1, current_function),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1),
-
- Server2 = ssl_test_lib:start_server(StartServerOpts),
- Port2 = ssl_test_lib:inet_port(Server2),
- {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++
- [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]),
-
- ssl_test_lib:check_result(Server2, ok, Client2, ok),
-
- ct:sleep(1000), %% Schedule out
-
- {current_function, {erlang, hibernate, 3}} =
- process_info(Pid2, current_function),
-
- ssl_test_lib:close(Server2),
- ssl_test_lib:close(Client2).
-
-%%--------------------------------------------------------------------
-listen_socket() ->
- [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}].
-
-listen_socket(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ok, ListenSocket} = ssl:listen(0, ServerOpts),
-
- %% This can be a valid thing to do as
- %% options are inherited by the accept socket
- ok = ssl:controlling_process(ListenSocket, self()),
-
- {ok, _} = ssl:sockname(ListenSocket),
-
- {error, enotconn} = ssl:send(ListenSocket, <<"data">>),
- {error, enotconn} = ssl:recv(ListenSocket, 0),
- {error, enotconn} = ssl:connection_information(ListenSocket),
- {error, enotconn} = ssl:peername(ListenSocket),
- {error, enotconn} = ssl:peercert(ListenSocket),
- {error, enotconn} = ssl:renegotiate(ListenSocket),
- {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, [client_random], 256),
- {error, enotconn} = ssl:shutdown(ListenSocket, read_write),
-
- ok = ssl:close(ListenSocket).
-%%--------------------------------------------------------------------
-tls_ssl_accept_timeout() ->
- [{doc,"Test ssl:ssl_accept timeout"}].
-
-tls_ssl_accept_timeout(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {ssl_test_lib,
- no_result_msg, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]),
-
- receive
- {tcp_closed, CSocket} ->
- ssl_test_lib:check_result(Server, {error, timeout}),
- receive
- {'EXIT', Server, _} ->
- %% Make sure supervisor had time to react on process exit
- %% Could we come up with a better solution to this?
- ct:sleep(500),
- [] = supervisor:which_children(tls_connection_sup)
- end
- end.
-
-%%--------------------------------------------------------------------
-ssl_recv_timeout() ->
- [{doc,"Test ssl:ssl_accept timeout"}].
-
-ssl_recv_timeout(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_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_timeout_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,
- send_recv_result_timeout_client, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-connect_twice() ->
- [{doc,""}].
-connect_twice(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, send_recv_result, []}},
- {options, [{keepalive, true},{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, {ssl_test_lib, send_recv_result, []}},
- {options, [{keepalive, true},{active, false}
- | ClientOpts]}]),
- Server ! listen,
-
- {Client1, #sslsocket{}} =
- ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{keepalive, true},{active, false}
- | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:check_result(Server, ok, Client1, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_active() ->
- [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
- "immediately after each other"}].
-renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate_immediately, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_passive() ->
- [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
- "immediately after each other"}].
-renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {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,
- renegotiate_immediately, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_absolute() ->
- [{doc, "Mitigate DOS computational attack by not allowing client to initiate renegotiation"}].
-renegotiate_dos_mitigate_absolute(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{client_renegotiation, 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,
- renegotiate_rejected,
- []}},
+ {mfa, {?MODULE, connect_dist_c, []}},
{options, ClientOpts}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_tcp_error_propagation_in_active_mode() ->
- [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}].
-tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, receive_msg, []}},
- {options, ClientOpts}]),
- {status, _, _, StatusInfo} = sys:get_status(Pid),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- StaticEnv = element(2, State),
- Socket = element(11, StaticEnv),
- %% Fake tcp error
- Pid ! {tcp_error, Socket, etimedout},
-
- ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
-
-%%--------------------------------------------------------------------
-recv_error_handling() ->
- [{doc,"Special case of call error handling"}].
-recv_error_handling(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, recv_close, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- {_Client, #sslsocket{} = SslSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
- ssl:close(SslSocket),
- ssl_test_lib:check_result(Server, ok).
-
-
-
-%%--------------------------------------------------------------------
-call_in_error_state() ->
- [{doc,"Special case of call error handling"}].
-call_in_error_state(Config) when is_list(Config) ->
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
- Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]),
- receive
- {Pid, Port} ->
- spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
- end,
- receive
- {error, closed} ->
- ok;
- Other ->
- ct:fail(Other)
- end.
-
-run_client_error([Port, Opts]) ->
- ssl:connect("localhost", Port, Opts).
-
-run_error_server([ Pid | Opts]) ->
- {ok, Listen} = ssl:listen(0, Opts),
- {ok,{_, Port}} = ssl:sockname(Listen),
- Pid ! {self(), Port},
- {ok, Socket} = ssl:transport_accept(Listen),
- Pid ! ssl:controlling_process(Socket, self()).
-
-%%--------------------------------------------------------------------
-
-close_in_error_state() ->
- [{doc,"Special case of closing socket in error state"}].
-close_in_error_state(Config) when is_list(Config) ->
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
- ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]),
- receive
- {_Pid, Port} ->
- spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
- end,
- receive
- ok ->
- ok;
- Other ->
- ct:fail(Other)
- end.
-%%--------------------------------------------------------------------
-abuse_transport_accept_socket() ->
- [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
-abuse_transport_accept_socket(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
- Server = ssl_test_lib:start_server_transport_abuse_socket([{node, ServerNode},
- {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
- ssl_test_lib:check_result(Server, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-controlling_process_transport_accept_socket() ->
- [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
-controlling_process_transport_accept_socket(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_transport_control([{node, ServerNode},
- {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- _Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server).
-
-%%--------------------------------------------------------------------
-run_error_server_close([Pid | Opts]) ->
- {ok, Listen} = ssl:listen(0, Opts),
- {ok,{_, Port}} = ssl:sockname(Listen),
- Pid ! {self(), Port},
- {ok, Socket} = ssl:transport_accept(Listen),
- Pid ! ssl:close(Socket).
-
-%%--------------------------------------------------------------------
-
-rizzo() ->
- [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is
- vunrable to Rizzo/Dungon attack"}].
-
-rizzo(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion),
- [{key_exchange,
- fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa->
- true;
- (_) ->
- false
- end},
- {cipher,
- fun(rc4_128) ->
- false;
- (chacha20_poly1305) ->
- false;
- (_) ->
- true
- end}]),
-
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_rizzo, []}).
-%%--------------------------------------------------------------------
-no_rizzo_rc4() ->
- [{doc,"Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"}].
-
-no_rizzo_rc4(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- %% Test uses RSA certs
- Ciphers = ssl:filter_cipher_suites(ssl_test_lib:rc4_suites(NVersion),
- [{key_exchange,
- fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa->
- true;
- (_) ->
- false
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_no_rizzo, []}).
-
-rizzo_one_n_minus_one() ->
- [{doc,"Test that the 1/n-1-split mitigation of Rizzo/Dungon attack can be explicitly selected"}].
-
-rizzo_one_n_minus_one(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion),
- [{key_exchange,
- fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa->
- true;
- (_) ->
- false
- end},
- {cipher,
- fun(rc4_128) ->
- false;
- %% TODO: remove this clause when chacha is fixed!
- (chacha20_poly1305) ->
- false;
- (_) ->
- true
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_rizzo, []}).
-
-rizzo_zero_n() ->
- [{doc,"Test that the 0/n-split mitigation of Rizzo/Dungon attack can be explicitly selected"}].
-
-rizzo_zero_n(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion),
- [{cipher,
- fun(rc4_128) ->
- false;
- (_) ->
- true
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_no_rizzo, []}).
-
-rizzo_disabled() ->
- [{doc,"Test that the mitigation of Rizzo/Dungon attack can be explicitly disabled"}].
-
-rizzo_disabled(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion),
- [{cipher,
- fun(rc4_128) ->
- false;
- (_) ->
- true
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_no_rizzo, []}).
-
-%%--------------------------------------------------------------------
-new_server_wants_peer_cert() ->
- [{doc, "Test that server configured to do client certification does"
- " not reuse session without a client certificate."}].
-new_server_wants_peer_cert(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- VServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_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, peercert_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, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
-
- Monitor = erlang:monitor(process, Server),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- receive
- {'DOWN', Monitor, _, _, _} ->
- ok
- end,
-
- Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, VServerOpts}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [ClientOpts]}]),
-
- CertFile = proplists:get_value(certfile, ClientOpts),
- [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
-
- ServerMsg = {error, no_peercert},
- Sever1Msg = {ok, BinCert},
-
- ssl_test_lib:check_result(Server, ServerMsg, Server1, Sever1Msg),
-
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-session_cache_process_list() ->
- [{doc,"Test reuse of sessions (short handshake)"}].
-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(Config) when is_list(Config) ->
- session_cache_process(mnesia,Config).
+eccs() ->
+ [{doc, "Test API functions eccs/0 and eccs/1"}].
-%%--------------------------------------------------------------------
+eccs(Config) when is_list(Config) ->
+ [_|_] = All = ssl:eccs(),
+ [] = ssl:eccs(sslv3),
+ [_|_] = Tls = ssl:eccs(tlsv1),
+ [_|_] = Tls1 = ssl:eccs('tlsv1.1'),
+ [_|_] = Tls2 = ssl:eccs('tlsv1.2'),
+ [_|_] = Tls1 = ssl:eccs('dtlsv1'),
+ [_|_] = Tls2 = ssl:eccs('dtlsv1.2'),
+ %% ordering is currently not verified by the test
+ true = lists:sort(All) =:= lists:usort(Tls ++ Tls1 ++ Tls2),
+ ok.
tls_versions_option() ->
[{doc,"Test API versions option to connect/listen."}].
@@ -4402,165 +452,6 @@ tls_versions_option(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-unordered_protocol_versions_server() ->
- [{doc,"Test that the highest protocol is selected even"
- " when it is not first in the versions list."}].
-
-unordered_protocol_versions_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, protocol_info_result, []}},
- {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, ClientOpts}]),
-
- ServerMsg = ClientMsg = {ok,'tlsv1.2'},
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
-
-%%--------------------------------------------------------------------
-unordered_protocol_versions_client() ->
- [{doc,"Test that the highest protocol is selected even"
- " when it is not first in the versions list."}].
-
-unordered_protocol_versions_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, protocol_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, protocol_info_result, []}},
- {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]),
-
- ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
-
-%%--------------------------------------------------------------------
-max_handshake_size() ->
- [{doc,"Test that we can set max_handshake_size to max value."}].
-
-max_handshake_size(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{max_handshake_size, 8388607} |ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{max_handshake_size, 8388607} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok).
-
-%%--------------------------------------------------------------------
-
-server_name_indication_option() ->
- [{doc,"Test API server_name_indication option to connect."}].
-server_name_indication_option(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{server_name_indication, disable} |
- ClientOpts]}
- ]),
-
- ssl_test_lib:check_result(Server, ok, Client0, ok),
- Server ! listen,
-
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{server_name_indication, Hostname} | ClientOpts]
- }]),
- ssl_test_lib:check_result(Server, ok, Client1, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1).
-%%--------------------------------------------------------------------
-
-accept_pool() ->
- [{doc,"Test having an accept pool."}].
-accept_pool(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {accepters, 3},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server0),
- [Server1, Server2] = ssl_test_lib:accepters(2),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}
- ]),
-
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}
- ]),
-
- Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}
- ]),
-
- ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]),
-
- ssl_test_lib:close(Server0),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Server2),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1),
- ssl_test_lib:close(Client2).
-
-
-%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
send_recv_result(Socket) ->
@@ -4572,632 +463,9 @@ tcp_send_recv_result(Socket) ->
{ok,"Hello world"} = gen_tcp:recv(Socket, 11),
ok.
-basic_verify_test_no_close(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- {Server, Client}.
-
-basic_test(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(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, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-prf_create_plan(TlsVersions, PRFs, Results) ->
- lists:foldl(fun(Ver, Acc) ->
- A = prf_ciphers_and_expected(Ver, PRFs, Results),
- [A|Acc]
- end, [], TlsVersions).
-prf_ciphers_and_expected(TlsVer, PRFs, Results) ->
- case TlsVer of
- TlsVer when TlsVer == sslv3 orelse TlsVer == tlsv1
- orelse TlsVer == 'tlsv1.1' orelse TlsVer == 'dtlsv1' ->
- Ciphers = ssl:cipher_suites(),
- {_, Expected} = lists:keyfind(md5sha, 1, Results),
- [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, {prf, md5sha}]];
- TlsVer when TlsVer == 'tlsv1.2' orelse TlsVer == 'dtlsv1.2'->
- lists:foldl(
- fun(PRF, Acc) ->
- Ciphers = prf_get_ciphers(TlsVer, PRF),
- case Ciphers of
- [] ->
- ct:log("No ciphers for PRF algorithm ~p. Skipping.", [PRF]),
- Acc;
- Ciphers ->
- {_, Expected} = lists:keyfind(PRF, 1, Results),
- [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected},
- {prf, PRF}] | Acc]
- end
- end, [], PRFs)
- end.
-prf_get_ciphers(_, PRF) ->
- lists:filter(
- fun(C) when tuple_size(C) == 4 andalso
- element(4, C) == PRF ->
- true;
- (_) ->
- false
- end,
- ssl:cipher_suites()).
-prf_run_test(_, TlsVer, [], _, Prf) ->
- ct:fail({error, cipher_list_empty, TlsVer, Prf});
-prf_run_test(Config, TlsVer, Ciphers, Expected, Prf) ->
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- BaseOpts = [{active, true}, {versions, [TlsVer]}, {ciphers, Ciphers}, {protocol, tls_or_dtls(TlsVer)}],
- ServerOpts = BaseOpts ++ proplists:get_value(server_opts, Config),
- ClientOpts = BaseOpts ++ proplists:get_value(client_opts, Config),
- Server = ssl_test_lib:start_server(
- [{node, ServerNode}, {port, 0}, {from, self()},
- {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}},
- {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, prf_verify_value, [TlsVer, Expected, Prf]}},
- {options, ClientOpts}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-prf_verify_value(Socket, TlsVer, Expected, Algo) ->
- Ret = ssl:prf(Socket, <<>>, <<>>, [<<>>], 16),
- case TlsVer of
- sslv3 ->
- case Ret of
- {error, undefined} -> ok;
- _ ->
- {error, {expected, {error, undefined},
- got, Ret, tls_ver, TlsVer, prf_algorithm, Algo}}
- end;
- _ ->
- case Ret of
- {ok, Expected} -> ok;
- {ok, Val} -> {error, {expected, Expected, got, Val, tls_ver, TlsVer,
- prf_algorithm, Algo}}
- end
- end.
-
-send_recv_result_timeout_client(Socket) ->
- {error, timeout} = ssl:recv(Socket, 11, 500),
- {error, timeout} = ssl:recv(Socket, 11, 0),
- ssl:send(Socket, "Hello world"),
- receive
- Msg ->
- io:format("Msg ~p~n",[Msg])
- after 500 ->
- ok
- end,
- {ok, "Hello world"} = ssl:recv(Socket, 11, 500),
- ok.
-send_recv_result_timeout_server(Socket) ->
- ssl:send(Socket, "Hello"),
- {ok, "Hello world"} = ssl:recv(Socket, 11),
- ssl:send(Socket, " world"),
- ok.
-
-recv_close(Socket) ->
- {error, closed} = ssl:recv(Socket, 11),
- receive
- {_,{error,closed}} ->
- error_extra_close_sent_to_user_process
- after 500 ->
- ok
- end.
-
-
-send_recv_result_active_rizzo(Socket) ->
- ssl:send(Socket, "Hello world"),
- "Hello world" = ssl_test_lib:active_recv(Socket, 11),
- ok.
-
-send_recv_result_active_no_rizzo(Socket) ->
- ssl:send(Socket, "Hello world"),
- "Hello world" = ssl_test_lib:active_recv(Socket, 11),
- ok.
-
-
-ssl_active_recv(N) ->
- ssl_active_recv(N, []).
-
-ssl_active_recv(0, Acc) ->
- Acc;
-ssl_active_recv(N, Acc) ->
- receive
- {ssl, _, Bytes} ->
- ssl_active_recv(N-length(Bytes), Acc ++ Bytes)
- end.
-
result_ok(_Socket) ->
ok.
-renegotiate(Socket, Data) ->
- ct:log("Renegotiating ~n", []),
- Result = ssl:renegotiate(Socket),
- ct:log("Result ~p~n", [Result]),
- ssl:send(Socket, Data),
- case Result of
- ok ->
- ok;
- Other ->
- Other
- end.
-
-renegotiate_reuse_session(Socket, Data) ->
- %% Make sure session is registered
- ct:sleep(?SLEEP),
- renegotiate(Socket, Data).
-
-renegotiate_immediately(Socket) ->
- _ = ssl_test_lib:active_recv(Socket, 11),
- ok = ssl:renegotiate(Socket),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP),
- ok = ssl:renegotiate(Socket),
- ct:log("Renegotiated again"),
- ssl:send(Socket, "Hello world"),
- ok.
-
-renegotiate_rejected(Socket) ->
- _ = ssl_test_lib:active_recv(Socket, 11),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- ct:log("Failed to renegotiate again"),
- ssl:send(Socket, "Hello world"),
- ok.
-
-rizzo_add_mitigation_option(Value, Config) ->
- lists:foldl(fun(Opt, Acc) ->
- case proplists:get_value(Opt, Acc) of
- undefined -> Acc;
- C ->
- N = lists:keystore(beast_mitigation, 1, C,
- {beast_mitigation, Value}),
- lists:keystore(Opt, 1, Acc, {Opt, N})
- end
- end, Config,
- [client_opts, client_dsa_opts, server_opts, server_dsa_opts,
- server_ecdsa_opts, server_ecdh_rsa_opts]).
-
-new_config(PrivDir, ServerOpts0) ->
- CaCertFile = proplists:get_value(cacertfile, ServerOpts0),
- CertFile = proplists:get_value(certfile, ServerOpts0),
- KeyFile = proplists:get_value(keyfile, ServerOpts0),
- NewCaCertFile = filename:join(PrivDir, "new_ca.pem"),
- NewCertFile = filename:join(PrivDir, "new_cert.pem"),
- NewKeyFile = filename:join(PrivDir, "new_key.pem"),
- file:copy(CaCertFile, NewCaCertFile),
- file:copy(CertFile, NewCertFile),
- file:copy(KeyFile, NewKeyFile),
- ServerOpts1 = proplists:delete(cacertfile, ServerOpts0),
- ServerOpts2 = proplists:delete(certfile, ServerOpts1),
- ServerOpts = proplists:delete(keyfile, ServerOpts2),
-
- {ok, PEM} = file:read_file(NewCaCertFile),
- ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
-
- [{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
- {keyfile, NewKeyFile} | ServerOpts].
-
-session_cache_process(_Type,Config) when is_list(Config) ->
- reuse_session(Config).
-
-init([Type]) ->
- ets:new(ssl_test, [named_table, public, set]),
- ets:insert(ssl_test, {type, Type}),
- case Type of
- list ->
- spawn(fun() -> session_loop([]) end);
- mnesia ->
- mnesia:start(),
- {atomic,ok} = mnesia:create_table(sess_cache, []),
- sess_cache
- end.
-
-session_cb() ->
- [{type, Type}] = ets:lookup(ssl_test, type),
- Type.
-
-terminate(Cache) ->
- case session_cb() of
- list ->
- Cache ! terminate;
- mnesia ->
- catch {atomic,ok} =
- mnesia:delete_table(sess_cache)
- end.
-
-lookup(Cache, Key) ->
- 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, [{sess_cache, Key, Value}]} ->
- Value;
- _ ->
- undefined
- end
- end.
-
-update(Cache, Key, Value) ->
- case session_cb() of
- list ->
- Cache ! {update, Key, Value};
- mnesia ->
- {atomic, ok} =
- mnesia:transaction(fun() ->
- mnesia:write(sess_cache,
- {sess_cache, Key, Value}, write)
- end)
- end.
-
-delete(Cache, Key) ->
- 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) ->
- 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) ->
- case session_cb() of
- list ->
- Cache ! {self(),select_session, PartialKey},
- receive
- {Cache, Res} ->
- Res
- end;
- mnesia ->
- Sel = fun() ->
- mnesia:select(Cache,
- [{{sess_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} ->
- NewSess = [{Key,Value}| lists:keydelete(Key,1,Sess)],
- session_loop(NewSess);
- {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({{PKey0, Id},Session}, Acc) when PKey == PKey0 ->
- [[Id, Session]|Acc];
- (_,Acc) ->
- Acc
- end,
- Sessions = lists:foldl(Sel, [], Sess),
- Pid ! {self(), Sessions},
- session_loop(Sess)
- end.
-
-
-erlang_ssl_receive(Socket, Data) ->
- case ssl_test_lib:active_recv(Socket, length(Data)) of
- Data ->
- ok;
- Other ->
- ct:fail({{expected, Data}, {got, Other}})
- end.
-
-receive_msg(_) ->
- receive
- Msg ->
- Msg
- end.
-
-controlling_process_result(Socket, Pid, Msg) ->
- ok = ssl:controlling_process(Socket, Pid),
- %% Make sure other side has evaluated controlling_process
- %% before message is sent
- ct:sleep(?SLEEP),
- ssl:send(Socket, Msg),
- no_result_msg.
-
-
-controller_dies_result(_Socket, _Pid, _Msg) ->
- receive Result -> Result end.
-
-get_close(Pid, Where) ->
- receive
- {'EXIT', Pid, _Reason} ->
- receive
- {_, {ssl_closed, Socket}} ->
- ct:log("Socket closed ~p~n",[Socket]);
- Unexpected ->
- ct:log("Unexpected ~p~n",[Unexpected]),
- ct:fail({line, ?LINE-1})
- after 5000 ->
- ct:fail({timeout, {line, ?LINE, Where}})
- end;
- Unexpected ->
- ct:log("Unexpected ~p~n",[Unexpected]),
- ct:fail({line, ?LINE-1})
- after 5000 ->
- ct:fail({timeout, {line, ?LINE, Where}})
- end.
-
-run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
- Result = lists:map(fun(Cipher) ->
- rizzo_test(Cipher, Config, Version, Mfa) end,
- Ciphers),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- ct:log("Cipher suite errors: ~p~n", [Error]),
- ct:fail(cipher_suite_failed_see_test_case_log)
- end.
-
-rizzo_test(Cipher, Config, Version, Mfa) ->
- {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, Mfa},
- {options, [{active, true}, {ciphers, [Cipher]},
- {versions, [Version]}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, Mfa},
- {options, [{active, true}, {ciphers, [Cipher]}| ClientOpts]}]),
-
- Result = ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- case Result of
- ok ->
- [];
- Error ->
- [{Cipher, Error}]
- end.
-
-client_server_opts(#{key_exchange := KeyAlgo}, Config)
- when KeyAlgo == rsa orelse
- KeyAlgo == dhe_rsa orelse
- KeyAlgo == ecdhe_rsa orelse
- KeyAlgo == rsa_psk orelse
- KeyAlgo == srp_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
- ssl_test_lib:ssl_options(server_opts, Config)};
-client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
- {ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ssl_test_lib:ssl_options(server_dsa_opts, Config)};
-client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)};
-client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)}.
-
-run_suites(Ciphers, Config, Type) ->
- Version = ssl_test_lib:protocol_version(Config),
- ct:log("Running cipher suites ~p~n", [Ciphers]),
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_opts, Config)]};
- dsa ->
- {ssl_test_lib:ssl_options(client_dsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_dsa_opts, Config)]};
- anonymous ->
- %% No certs in opts!
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options([], Config)]};
- psk ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk, Config)]};
- psk_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_hint, Config)
- ]};
- psk_anon ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_anon, Config)]};
- psk_anon_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_anon_hint, Config)]};
- srp ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp, Config)]};
- srp_anon ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp_anon, Config)]};
- srp_dsa ->
- {ssl_test_lib:ssl_options(client_srp_dsa, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp_dsa, Config)]};
- ecdsa ->
- {ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
- ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
- rc4_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- rc4_ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
- rc4_ecdsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
- des_dhe_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_verification_opts, Config)]};
- des_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- chacha_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- chacha_ecdsa ->
- {ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]}
- end,
- Suites = ssl_test_lib:filter_suites(Ciphers, Version),
- ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, Suites]),
- Results0 = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- ssl_test_lib:filter_suites(Ciphers, Version)),
- Results = lists:flatten(Results0),
- true = length(Results) == length(Suites),
- check_cipher_result(Results).
-
-check_cipher_result([]) ->
- ok;
-check_cipher_result([ok | Rest]) ->
- check_cipher_result(Rest);
-check_cipher_result([_ |_] = Error) ->
- ct:fail(Error).
-
-erlang_cipher_suite(Suite) when is_list(Suite)->
- ssl_cipher_format:suite_definition(ssl_cipher_format:openssl_suite(Suite));
-erlang_cipher_suite(Suite) ->
- Suite.
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- %% process_flag(trap_exit, true),
- ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
- ct:log("Server Opts ~p~n", [ServerOpts]),
- ct:log("Client Opts ~p~n", [ClientOpts]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
-
- ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- case Result of
- ok ->
- [ok];
- Error ->
- [{ErlangCipherSuite, Error}]
- end.
-
-connection_information_result(Socket) ->
- {ok, Info = [_ | _]} = ssl:connection_information(Socket),
- case length(Info) > 3 of
- true ->
- %% Atleast one ssl_option() is set
- ct:log("Info ~p", [Info]),
- ok;
- false ->
- ct:fail(no_ssl_options_returned)
- end.
-
-connection_info_result(Socket) ->
- {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]),
- {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}.
protocol_info_result(Socket) ->
{ok, [{protocol, PVersion}]} = ssl:connection_information(Socket, [protocol]),
@@ -5207,11 +475,7 @@ version_info_result(Socket) ->
{ok, [{version, Version}]} = ssl:connection_information(Socket, [version]),
{ok, Version}.
-secret_connection_info_result(Socket) ->
- {ok, [{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}]}
- = ssl:connection_information(Socket, [client_random, server_random, master_secret]),
- is_binary(ClientRand) andalso is_binary(ServerRand) andalso is_binary(MasterSecret).
-
+
connect_dist_s(S) ->
Msg = term_to_binary({erlang,term}),
ok = ssl:send(S, Msg).
@@ -5221,88 +485,11 @@ connect_dist_c(S) ->
{ok, Test} = ssl:recv(S, 0, 10000),
ok.
-tls_downgrade_result(Socket, Pid) ->
- ok = ssl_test_lib:send_recv_result(Socket),
- Pid ! {self(), ready},
- receive
- go ->
- ok
- end,
- case ssl:close(Socket, {self(), 10000}) of
- {ok, TCPSocket} ->
- inet:setopts(TCPSocket, [{active, true}]),
- gen_tcp:send(TCPSocket, "Downgraded"),
- receive
- {tcp, TCPSocket, <<"Downgraded">>} ->
- ok;
- {tcp_closed, TCPSocket} ->
- ct:fail("Peer timed out, downgrade aborted"),
- ok;
- Other ->
- {error, Other}
- end;
- {error, timeout} ->
- ct:fail("Timed out, downgrade aborted"),
- ok;
- Fail ->
- {error, Fail}
- end.
-
-tls_close(Socket) ->
- ok = ssl_test_lib:send_recv_result(Socket),
- case ssl:close(Socket, 5000) of
- ok ->
- ok;
- {error, closed} ->
- ok;
- Other ->
- ct:fail(Other)
- end.
-
- %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
-treashold(N, {3,0}) ->
- (N div 2) + 1;
-treashold(N, {3,1}) ->
- (N div 2) + 1;
-treashold(N, _) ->
- N + 1.
-
-get_invalid_inet_option(Socket) ->
- {error, {options, {socket_options, foo, _}}} = ssl:getopts(Socket, [foo]),
- ok.
-
-tls_shutdown_result(Socket, server) ->
- ssl:send(Socket, "Hej"),
- ok = ssl:shutdown(Socket, write),
- {ok, "Hej hopp"} = ssl:recv(Socket, 8),
- ok;
-
-tls_shutdown_result(Socket, client) ->
- ssl:send(Socket, "Hej hopp"),
- ok = ssl:shutdown(Socket, write),
- {ok, "Hej"} = ssl:recv(Socket, 3),
- ok.
-
-tls_shutdown_write_result(Socket, server) ->
- ct:sleep(?SLEEP),
- ssl:shutdown(Socket, write);
-tls_shutdown_write_result(Socket, client) ->
- ssl:recv(Socket, 0).
-
dummy(_Socket) ->
%% Should not happen as the ssl connection will not be established
%% due to fatal handshake failiure
exit(kill).
-tls_shutdown_both_result(Socket, server) ->
- ct:sleep(?SLEEP),
- ssl:shutdown(Socket, read_write);
-tls_shutdown_both_result(Socket, client) ->
- ssl:recv(Socket, 0).
-
-peername_result(S) ->
- ssl:peername(S).
-
version_option_test(Config, Version) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
@@ -5328,22 +515,3 @@ version_option_test(Config, Version) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-try_recv_active(Socket) ->
- ssl:send(Socket, "Hello world"),
- {error, einval} = ssl:recv(Socket, 11),
- ok.
-try_recv_active_once(Socket) ->
- {error, einval} = ssl:recv(Socket, 11),
- ok.
-
-
-wait_for_send(Socket) ->
- %% Make sure TLS process processed send message event
- _ = ssl:connection_information(Socket).
-
-tls_or_dtls('dtlsv1') ->
- dtls;
-tls_or_dtls('dtlsv1.2') ->
- dtls;
-tls_or_dtls(_) ->
- tls.
diff --git a/lib/ssl/test/ssl_bench.spec b/lib/ssl/test/ssl_bench.spec
index 8b746c5ca9..217cc6fc83 100644
--- a/lib/ssl/test/ssl_bench.spec
+++ b/lib/ssl/test/ssl_bench.spec
@@ -1 +1,2 @@
{suites,"../ssl_test",[ssl_bench_SUITE, ssl_dist_bench_SUITE]}.
+{skip_groups,"../ssl_test",ssl_bench_SUITE,basic,"Benchmarks run separately"}.
diff --git a/lib/ssl/test/ssl_bench_SUITE.erl b/lib/ssl/test/ssl_bench_SUITE.erl
index 13097b08b6..a297539c36 100644
--- a/lib/ssl/test/ssl_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_bench_SUITE.erl
@@ -25,10 +25,11 @@
suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
-all() -> [{group, setup}, {group, payload}, {group, pem_cache}].
+all() -> [{group, basic}, {group, setup}, {group, payload}, {group, pem_cache}].
groups() ->
- [{setup, [{repeat, 3}], [setup_sequential, setup_concurrent]},
+ [{basic, [], [basic_pem_cache]},
+ {setup, [{repeat, 3}], [setup_sequential, setup_concurrent]},
{payload, [{repeat, 3}], [payload_simple]},
{pem_cache, [{repeat, 3}], [use_pem_cache, bypass_pem_cache]}
].
@@ -40,6 +41,7 @@ end_per_group(_GroupName, _Config) ->
ok.
init_per_suite(Config) ->
+ ct:timetrap({minutes, 1}),
case node() of
nonode@nohost ->
{skipped, "Node not distributed"};
@@ -51,29 +53,21 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
-init_per_testcase(use_pem_cache, Conf) ->
+init_per_testcase(TC, Conf) when TC =:= use_pem_cache;
+ TC =:= bypass_pem_cache;
+ TC =:= basic_pem_cache ->
case bypass_pem_cache_supported() of
false -> {skipped, "PEM cache bypass support required"};
true ->
application:set_env(ssl, bypass_pem_cache, false),
Conf
end;
-init_per_testcase(bypass_pem_cache, Conf) ->
- case bypass_pem_cache_supported() of
- false -> {skipped, "PEM cache bypass support required"};
- true ->
- application:set_env(ssl, bypass_pem_cache, true),
- Conf
- end;
init_per_testcase(_Func, Conf) ->
Conf.
-end_per_testcase(use_pem_cache, _Config) ->
- case bypass_pem_cache_supported() of
- false -> ok;
- true -> application:set_env(ssl, bypass_pem_cache, false)
- end;
-end_per_testcase(bypass_pem_cache, _Config) ->
+end_per_testcase(TC, _Config) when TC =:= use_pem_cache;
+ TC =:= bypass_pem_cache;
+ TC =:= basic_pem_cache ->
case bypass_pem_cache_supported() of
false -> ok;
true -> application:set_env(ssl, bypass_pem_cache, false)
@@ -119,6 +113,9 @@ payload_simple(Config) ->
{suite, "ssl"}, {name, "Payload simple"}]}),
ok.
+basic_pem_cache(_Config) ->
+ do_test(ssl, pem_cache, 10, 5, node()).
+
use_pem_cache(_Config) ->
{ok, Result} = do_test(ssl, pem_cache, 100, 500, node()),
ct_event:notify(#event{name = benchmark_data,
@@ -167,7 +164,7 @@ do_test(Type, TC, Loop, ParallellConnections, Server) ->
end
end,
Spawn = fun(Id) ->
- Pid = spawn(fun() -> Test(Id) end),
+ Pid = spawn_link(fun() -> Test(Id) end),
receive {Pid, init} -> Pid end
end,
Pids = [Spawn(Id) || Id <- lists:seq(ParallellConnections, 1, -1)],
@@ -177,49 +174,54 @@ do_test(Type, TC, Loop, ParallellConnections, Server) ->
end,
{TimeInMicro, _} = timer:tc(Run),
TotalTests = ParallellConnections * Loop,
- TestPerSecond = 1000000 * TotalTests div TimeInMicro,
+ TestPerSecond = case TimeInMicro of
+ 0 ->
+ undefined;
+ _ ->
+ 1000000 * TotalTests div TimeInMicro
+ end,
io:format("TC ~p ~p ~p ~p 1/s~n", [TC, Type, ParallellConnections, TestPerSecond]),
unlink(SPid),
SPid ! quit,
{ok, TestPerSecond}.
server_init(ssl, setup_connection, _, _, Server) ->
- {ok, Socket} = ssl:listen(0, ssl_opts(listen)),
- {ok, {_Host, Port}} = ssl:sockname(Socket),
+ {ok, LSocket} = ssl:listen(0, ssl_opts(listen)),
+ {ok, {_Host, Port}} = ssl:sockname(LSocket),
{ok, Host} = inet:gethostname(),
?FPROF_SERVER andalso start_profile(fprof, [whereis(ssl_manager), new]),
%%?EPROF_SERVER andalso start_profile(eprof, [ssl_connection_sup, ssl_manager]),
?EPROF_SERVER andalso start_profile(eprof, [ssl_manager]),
Server ! {self(), {init, Host, Port}},
Test = fun(TSocket) ->
- ok = ssl:ssl_accept(TSocket),
- ssl:close(TSocket)
+ {ok, Socket} = ssl:handshake(TSocket),
+ ssl:close(Socket)
end,
- setup_server_connection(Socket, Test);
+ setup_server_connection(LSocket, Test);
server_init(ssl, payload, Loop, _, Server) ->
- {ok, Socket} = ssl:listen(0, ssl_opts(listen)),
- {ok, {_Host, Port}} = ssl:sockname(Socket),
+ {ok, LSocket} = ssl:listen(0, ssl_opts(listen)),
+ {ok, {_Host, Port}} = ssl:sockname(LSocket),
{ok, Host} = inet:gethostname(),
Server ! {self(), {init, Host, Port}},
Test = fun(TSocket) ->
- ok = ssl:ssl_accept(TSocket),
+ {ok, Socket} = ssl:handshake(TSocket),
Size = byte_size(msg()),
- server_echo(TSocket, Size, Loop),
- ssl:close(TSocket)
+ server_echo(Socket, Size, Loop),
+ ssl:close(Socket)
end,
- setup_server_connection(Socket, Test);
+ setup_server_connection(LSocket, Test);
server_init(ssl, pem_cache, Loop, _, Server) ->
- {ok, Socket} = ssl:listen(0, ssl_opts(listen_der)),
- {ok, {_Host, Port}} = ssl:sockname(Socket),
+ {ok, LSocket} = ssl:listen(0, ssl_opts(listen_der)),
+ {ok, {_Host, Port}} = ssl:sockname(LSocket),
{ok, Host} = inet:gethostname(),
Server ! {self(), {init, Host, Port}},
Test = fun(TSocket) ->
- ok = ssl:ssl_accept(TSocket),
+ {ok, Socket} = ssl:handshake(TSocket),
Size = byte_size(msg()),
- server_echo(TSocket, Size, Loop),
- ssl:close(TSocket)
+ server_echo(Socket, Size, Loop),
+ ssl:close(Socket)
end,
- setup_server_connection(Socket, Test);
+ setup_server_connection(LSocket, Test);
server_init(Type, Tc, _, _, Server) ->
io:format("No server init code for ~p ~p~n",[Type, Tc]),
diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl
new file mode 100644
index 0000000000..fb1695f38a
--- /dev/null
+++ b/lib/ssl/test/ssl_cert_SUITE.erl
@@ -0,0 +1,563 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_cert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], tls_1_3_protocol_groups()},
+ {'tlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1.1', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1', [], pre_tls_1_3_protocol_groups()},
+ {'sslv3', [], ssl_protocol_groups()},
+ {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'dtlsv1', [], pre_tls_1_3_protocol_groups()},
+ {rsa, [], all_version_tests()},
+ {ecdsa, [], all_version_tests()},
+ {dsa, [], all_version_tests()},
+ {rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_client_auth,
+ unsupported_sign_algo_cert_client_auth]},
+ {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
+ ].
+
+ssl_protocol_groups() ->
+ [{group, rsa},
+ {group, dsa}].
+
+pre_tls_1_3_protocol_groups() ->
+ [{group, rsa},
+ {group, ecdsa},
+ {group, dsa}].
+
+tls_1_3_protocol_groups() ->
+ [{group, rsa_1_3},
+ {group, ecdsa_1_3}].
+
+tls_1_3_tests() ->
+ [
+ hello_retry_request,
+ custom_groups,
+ hello_retry_client_auth,
+ hello_retry_client_auth_empty_cert_accepted,
+ hello_retry_client_auth_empty_cert_rejected
+ ].
+
+all_version_tests() ->
+ [
+ no_auth,
+ auth,
+ client_auth_empty_cert_accepted,
+ client_auth_empty_cert_rejected,
+ client_auth_partial_chain,
+ client_auth_allow_partial_chain,
+ client_auth_do_not_allow_partial_chain,
+ client_auth_partial_chain_fun_fail,
+ missing_root_cert_no_auth,
+ missing_root_cert_auth,
+ missing_root_cert_auth_user_verify_fun_accept,
+ missing_root_cert_auth_user_verify_fun_reject,
+ verify_fun_always_run_client,
+ verify_fun_always_run_server,
+ incomplete_chain_auth
+ %%invalid_signature_client
+ ].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(Group, Config0) when Group == rsa;
+ Group == rsa_1_3 ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, COpts},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+init_per_group(Group, Config0) when Group == ecdsa;
+ Group == ecdsa_1_3 ->
+
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, COpts},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+
+init_per_group(Group, Config0) when Group == dsa ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ Config = ssl_test_lib:make_dsa_cert(Config0),
+ COpts = proplists:get_value(client_dsa_opts, Config),
+ SOpts = proplists:get_value(server_dsa_opts, Config),
+ [{cert_key_alg, dsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, COpts},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ [{client_type, erlang},
+ {server_type, erlang}, {version, GroupName}
+ | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+no_auth() ->
+ ssl_cert_tests:no_auth().
+
+no_auth(Config) ->
+ ssl_cert_tests:no_auth(Config).
+%%--------------------------------------------------------------------
+auth() ->
+ ssl_cert_tests:auth().
+auth(Config) ->
+ ssl_cert_tests:auth(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:client_auth_empty_cert_accepted().
+client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:client_auth_empty_cert_rejected().
+client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_rejected(Config).
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ ssl_cert_tests:client_auth_partial_chain().
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_allow_partial_chain().
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_allow_partial_chain(Config).
+%%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain().
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail().
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail(Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ ssl_cert_tests:missing_root_cert_no_auth().
+missing_root_cert_no_auth(Config) when is_list(Config) ->
+ ssl_cert_tests:missing_root_cert_no_auth(Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth() ->
+ [{doc,"Must have ROOT certs to be able to verify verify peer"}].
+missing_root_cert_auth(Config) when is_list(Config) ->
+ ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_cert_opts, Config)),
+ {ClientNode, 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, {options, {cacertfile, ""}}}),
+
+ ClientOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(client_cert_opts, Config)),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {options, [{verify, verify_peer}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, {error, {options, {cacertfile, ""}}}).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth_user_verify_fun_accept() ->
+ [{doc, "Test that the client succeds if the ROOT CA is unknown in verify_peer mode"
+ " with a verify_fun that accepts the unknown CA error"}].
+
+missing_root_cert_auth_user_verify_fun_accept(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) ->
+ {valid, UserState};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {verify_fun, FunAndState}], Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth_user_backwardscompatibility_verify_fun_accept() ->
+ [{doc, "Test old style verify fun"}].
+
+missing_root_cert_auth_user_backwardscompatibility_verify_fun_accept(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
+ (Other, Acc) -> [Other | Acc]
+ end,
+ VerifyFun =
+ fun(ErrorList) ->
+ case lists:foldl(AcceptBadCa, [], ErrorList) of
+ [] -> true;
+ [_|_] -> false
+ end
+ end,
+
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {verify_fun, VerifyFun}], Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth_user_verify_fun_reject() ->
+ [{doc, "Test that the client fails if the ROOT CA is unknown in verify_peer mode"
+ " with a verify_fun that rejects the unknown CA error"}].
+
+missing_root_cert_auth_user_verify_fun_reject(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _UserState) ->
+ {fail, Reason};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, UserState}, _) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {verify_fun, FunAndState}], Config),
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+%%--------------------------------------------------------------------
+incomplete_chain_auth() ->
+ [{doc,"Test that we can verify an incompleat chain when we have the certs to rebuild it"}].
+incomplete_chain_auth(Config) when is_list(Config) ->
+ DefaultCertConf = ssl_test_lib:default_cert_chain_conf(),
+ #{client_config := ClientOpts0,
+ server_config := ServerOpts0} = ssl_test_lib:make_cert_chains_der(proplists:get_value(cert_key_alg, Config),
+ [{server_chain, DefaultCertConf},
+ {client_chain, DefaultCertConf}]),
+ [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerOpts0),
+ ClientCas = proplists:get_value(cacerts, ClientOpts0),
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {cacerts, ServerCas ++ ClientCas} |
+ proplists:delete(cacerts, ClientOpts0)], Config),
+ ServerOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {cacerts, [ServerRoot]} |
+ proplists:delete(cacerts, ServerOpts0)], Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+verify_fun_always_run_client() ->
+ [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
+
+verify_fun_always_run_client(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we cannot tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [1]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
+
+%%--------------------------------------------------------------------
+verify_fun_always_run_server() ->
+ [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
+verify_fun_always_run_server(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we cannot tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [1]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState} |
+ ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_client(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_server(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test cases -----------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ [{doc,"Test that ssl server can request a new group when the client's first key share"
+ "is not supported"}].
+
+hello_retry_request(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ [{doc,"Test that ssl server can select a common group for key-exchange"}].
+
+custom_groups(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0],
+ ClientOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ClientOpts = [{supported_groups,[secp384r1, secp256r1, x25519]}|ClientOpts1],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+%% Triggers a Server Alert as ssl client does not have a certificate with a
+%% signature algorithm supported by the server (signature_algorithms_cert extension
+%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% ssl client sends an empty certificate.
+unsupported_sign_algo_cert_client_auth() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
+
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required).
+
+%%--------------------------------------------------------------------
+unsupported_sign_algo_client_auth() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
+
+unsupported_sign_algo_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, insufficient_security).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ [{doc, "TLS 1.3 (HelloRetryRequest): Test client authentication."}].
+
+hello_retry_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts1 = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ ServerOpts = [{verify, verify_peer},
+ {fail_if_no_peer_cert, true} | ServerOpts1],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty "
+ "certificate and fail_if_no_peer_cert is set to true."}].
+
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client "
+ "sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required).
diff --git a/lib/ssl/test/ssl_cert_tests.erl b/lib/ssl/test/ssl_cert_tests.erl
new file mode 100644
index 0000000000..c88daa2185
--- /dev/null
+++ b/lib/ssl/test/ssl_cert_tests.erl
@@ -0,0 +1,386 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_cert_tests).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+no_auth() ->
+ [{doc,"Test connection without authentication"}].
+
+no_auth(Config) ->
+ ClientOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+auth() ->
+ [{doc,"Test connection with mutual authentication"}].
+
+auth(Config) ->
+ ClientOpts = [{verify, verify_peer} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{verify, verify_peer} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ [{doc,"Test client authentication when client sends an empty certificate and "
+ "fail_if_no_peer_cert is set to false."}].
+
+client_auth_empty_cert_accepted(Config) ->
+ ClientOpts = proplists:delete(keyfile,
+ proplists:delete(certfile,
+ ssl_test_lib:ssl_options(client_cert_opts, Config))),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{verify, verify_peer},
+ {fail_if_no_peer_cert, false} | ServerOpts0],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ [{doc,"Test client authentication when client sends an empty certificate and "
+ "fail_if_no_peer_cert is set to true."}].
+
+client_auth_empty_cert_rejected(Config) ->
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts0 = ssl_test_lib:ssl_options([], Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts = proplists:delete(keyfile, ClientOpts1),
+
+ Version = proplists:get_value(version,Config),
+ case Version of
+ 'tlsv1.3' ->
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required);
+ _ ->
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, handshake_failure)
+ end.
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ [{doc, "Client sends an incompleate chain, by default not acceptable."}].
+
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts0)),
+ [{_,RootCA,_} | _] = public_key:pem_decode(ClientCAs),
+ ClientOpts = [{cacerts, [RootCA]} |
+ proplists:delete(cacertfile, ClientOpts0)],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ [{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}].
+
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ClientCAs),
+
+ PartialChain = fun(CertChain) ->
+ case lists:member(IntermidiateCA, CertChain) of
+ true ->
+ {trusted_ca, IntermidiateCA};
+ false ->
+ unknown_ca
+ end
+ end,
+ ServerOpts = [{cacerts, [IntermidiateCA]},
+ {partial_chain, PartialChain} |
+ proplists:delete(cacertfile, ServerOpts0)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+ %%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ [{doc, "Server does not accept the chain sent by the client as ROOT CA is unkown, "
+ "and we do not choose to trust the intermediate CA. (partial_chain option)"}].
+
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts0)),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
+
+ PartialChain = fun(_CertChain) ->
+ unknown_ca
+ end,
+ ServerOpts = [{cacerts, [IntermidiateCA]},
+ {partial_chain, PartialChain} |
+ proplists:delete(cacertfile, ServerOpts0)],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+ %%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ [{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}].
+
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+
+ {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts0)),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
+
+ PartialChain = fun(_CertChain) ->
+ true = false %% crash on purpose
+ end,
+ ServerOpts = [{cacerts, [IntermidiateCA]},
+ {partial_chain, PartialChain} |
+ proplists:delete(cacertfile, ServerOpts0)],
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ [{doc,"Test that the client succeds if the ROOT CA is unknown in verify_none mode"}].
+
+missing_root_cert_no_auth(Config) ->
+ ClientOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ [{doc,"Test server with invalid signature"}].
+
+invalid_signature_client(Config) when is_list(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+
+ KeyFile = proplists:get_value(keyfile, ClientOpts0),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ClientCertFile = proplists:get_value(certfile, ClientOpts0),
+ NewClientCertFile = filename:join(PrivDir, "client_invalid_cert.pem"),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
+ ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
+ NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
+ ClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts0)],
+ ServerOpts = [{verify, verify_peer} | ServerOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ [{doc,"Test client with invalid signature"}].
+
+invalid_signature_server(Config) when is_list(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+
+ KeyFile = proplists:get_value(keyfile, ServerOpts0),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts0),
+ NewServerCertFile = filename:join(PrivDir, "server_invalid_cert.pem"),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
+ ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
+ NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
+ ServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts0)],
+ ClientOpts = [{verify, verify_peer} | ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ [{doc,"Test that ssl server can request a new group when the client's first key share"
+ "is not supported"}].
+
+hello_retry_request(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ [{doc,"Test that ssl server can select a common group for key-exchange"}].
+
+custom_groups(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config_custom(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+%% Triggers a Server Alert as ssl client does not have a certificate with a
+%% signature algorithm supported by the server (signature_algorithms_cert extension
+%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% ssl client sends an empty certificate.
+unsupported_sign_algo_cert_client_auth() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
+
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required).
+%%--------------------------------------------------------------------
+unsupported_sign_algo_client_auth() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
+
+unsupported_sign_algo_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, insufficient_security).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ [{doc, "TLS 1.3 (HelloRetryRequest): Test client authentication."}].
+
+hello_retry_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty "
+ "certificate and fail_if_no_peer_cert is set to false."}].
+
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ClientOpts0 = proplists:delete(keyfile,
+ proplists:delete(certfile,
+ ssl_test_lib:ssl_options(client_cert_opts, Config))),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client "
+ "sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ClientOpts0 = proplists:delete(keyfile,
+ proplists:delete(certfile,
+ ssl_test_lib:ssl_options(client_cert_opts, Config))),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]),
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions -----------------------------------------------
+%%--------------------------------------------------------------------
+
+group_config_custom(Config, ServerOpts, ClientOpts) ->
+ case proplists:get_value(client_type, Config) of
+ erlang ->
+ {[{groups,"X448:P-256:P-384"} | ServerOpts],
+ [{supported_groups, [secp384r1, secp256r1, x25519]} | ClientOpts]};
+ openssl ->
+ {[{supported_groups, [x448, secp256r1, secp384r1]} | ServerOpts],
+ [{groups,"P-384:P-256:X25519"} | ClientOpts]}
+ end.
+
+group_config(Config, ServerOpts, ClientOpts) ->
+ case proplists:get_value(client_type, Config) of
+ erlang ->
+ {[{groups,"X448:X25519"} | ServerOpts],
+ [{supported_groups, [secp256r1, x25519]} | ClientOpts]};
+ openssl ->
+ {[{supported_groups, [x448, x25519]} | ServerOpts],
+ [{groups,"P-256:X25519"} | ClientOpts]}
+ end.
+
+test_ciphers(_, 'tlsv1.3' = Version) ->
+ Ciphers = ssl:cipher_suites(default, Version),
+ ct:log("Version ~p Testing ~p~n", [Version, Ciphers]),
+ OpenSSLCiphers = openssl_ciphers(),
+ ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]),
+ lists:filter(fun(C) ->
+ ct:log("Cipher ~p~n", [C]),
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers)
+ end, Ciphers);
+test_ciphers(Kex, Version) ->
+ Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, Version),
+ [{key_exchange, Kex}]),
+ ct:log("Version ~p Testing ~p~n", [Version, Ciphers]),
+ OpenSSLCiphers = openssl_ciphers(),
+ ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]),
+ lists:filter(fun(C) ->
+ ct:log("Cipher ~p~n", [C]),
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers)
+ end, Ciphers).
+
+
+
+openssl_ciphers() ->
+ Str = os:cmd("openssl ciphers"),
+ string:split(string:strip(Str, right, $\n), ":", all).
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index e89104a999..f38858e0bf 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -40,6 +40,7 @@
%%--------------------------------------------------------------------
all() ->
[
+ {group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -50,6 +51,7 @@ all() ->
groups() ->
[
+ {'tlsv1.3', [], all_protocol_groups()},
{'tlsv1.2', [], all_protocol_groups()},
{'tlsv1.1', [], all_protocol_groups()},
{'tlsv1', [], all_protocol_groups()},
@@ -69,36 +71,20 @@ all_protocol_groups() ->
{group, error_handling}].
tests() ->
- [verify_peer,
- verify_none,
- server_require_peer_cert_ok,
- server_require_peer_cert_fail,
- server_require_peer_cert_empty_ok,
- server_require_peer_cert_partial_chain,
- server_require_peer_cert_allow_partial_chain,
- server_require_peer_cert_do_not_allow_partial_chain,
- server_require_peer_cert_partial_chain_fun_fail,
- verify_fun_always_run_client,
- verify_fun_always_run_server,
- cert_expired,
- invalid_signature_client,
- invalid_signature_server,
+ [cert_expired,
+ %invalid_signature_client,
+ %%invalid_signature_server,
extended_key_usage_verify_both,
extended_key_usage_verify_server,
critical_extension_verify_client,
critical_extension_verify_server,
critical_extension_verify_none,
- customize_hostname_check,
- incomplete_chain
+ long_chain
].
error_handling_tests()->
[client_with_cert_cipher_suites_handshake,
- server_verify_no_cacerts,
- unknown_server_ca_fail,
- unknown_server_ca_accept_verify_none,
- unknown_server_ca_accept_verify_peer,
- unknown_server_ca_accept_backwardscompatibility,
+ %%unknown_server_ca_accept_backwardscompatibility,
no_authority_key_identifier,
no_authority_key_identifier_keyEncipherment].
@@ -147,6 +133,7 @@ init_per_testcase(_TestCase, Config) ->
ssl:stop(),
ssl:start(),
ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:pal(" ~p", [ dtls_record:supported_protocol_versions()]),
ct:timetrap({seconds, 10}),
Config.
@@ -156,61 +143,6 @@ end_per_testcase(_TestCase, Config) ->
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-
-verify_peer() ->
- [{doc,"Test option verify_peer"}].
-verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {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, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {verify, verify_peer} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-verify_none() ->
- [{doc,"Test option verify_none"}].
-
-verify_none(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {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, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active},
- {verify, verify_none} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
server_verify_client_once() ->
[{doc,"Test server option verify_client_once"}].
@@ -249,303 +181,6 @@ server_verify_client_once(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_require_peer_cert_ok() ->
- [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}].
-
-server_require_peer_cert_ok(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_require_peer_cert_fail() ->
- [{doc,"Test server option fail_if_no_peer_cert when peer doesn't send cert"}].
-
-server_require_peer_cert_fail(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- BadClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- Active = proplists:get_value(active, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{active, Active} | ServerOpts]}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{active, Active} | BadClientOpts]}]),
-
- ssl_test_lib:check_server_alert(Server, Client, handshake_failure).
-
-%%--------------------------------------------------------------------
-server_require_peer_cert_empty_ok() ->
- [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}].
-
-server_require_peer_cert_empty_ok(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, false}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ClientOpts = proplists:delete(keyfile, proplists:delete(certfile, ClientOpts0)),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_require_peer_cert_partial_chain() ->
- [{doc, "Client sends an incompleate chain, by default not acceptable."}].
-
-server_require_peer_cert_partial_chain(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
- [{_,RootCA,_} | _] = public_key:pem_decode(ClientCAs),
-
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, Active} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, Active},
- {cacerts, [RootCA]} |
- proplists:delete(cacertfile, ClientOpts)]}]),
- ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
-
-%%--------------------------------------------------------------------
-server_require_peer_cert_allow_partial_chain() ->
- [{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}].
-
-server_require_peer_cert_allow_partial_chain(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
-
- {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
- [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ClientCAs),
-
- PartialChain = fun(CertChain) ->
- case lists:member(IntermidiateCA, CertChain) of
- true ->
- {trusted_ca, IntermidiateCA};
- false ->
- unknown_ca
- end
- end,
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active},
- {cacerts, [IntermidiateCA]},
- {partial_chain, PartialChain} |
- proplists:delete(cacertfile, ServerOpts)]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
- %%--------------------------------------------------------------------
-server_require_peer_cert_do_not_allow_partial_chain() ->
- [{doc, "Server does not accept the chain sent by the client as ROOT CA is unkown, "
- "and we do not choose to trust the intermediate CA. (partial_chain option)"}].
-
-server_require_peer_cert_do_not_allow_partial_chain(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
- [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
-
- PartialChain = fun(_CertChain) ->
- unknown_ca
- end,
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{cacerts, [IntermidiateCA]},
- {partial_chain, PartialChain} |
- proplists:delete(cacertfile, ServerOpts)]}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
- ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
- %%--------------------------------------------------------------------
-server_require_peer_cert_partial_chain_fun_fail() ->
- [{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}].
-
-server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
- [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
-
- PartialChain = fun(_CertChain) ->
- true = false %% crash on purpose
- end,
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{cacerts, [IntermidiateCA]},
- {partial_chain, PartialChain} |
- proplists:delete(cacertfile, ServerOpts)]}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
- ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
-
-%%--------------------------------------------------------------------
-verify_fun_always_run_client() ->
- [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
-
-verify_fun_always_run_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- %% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
- %% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, [ChainLen]) ->
- {valid, [ChainLen + 1]};
- (_, valid_peer, [1]) ->
- {fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, [0]},
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}
- | ClientOpts]}]),
-
- ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
-
-%%--------------------------------------------------------------------
-verify_fun_always_run_server() ->
- [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
-verify_fun_always_run_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
- %% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, [ChainLen]) ->
- {valid, [ChainLen + 1]};
- (_, valid_peer, [1]) ->
- {fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, [0]},
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState} |
- ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
-%%--------------------------------------------------------------------
-
cert_expired() ->
[{doc,"Test server with expired certificate"}].
@@ -852,6 +487,7 @@ invalid_signature_server(Config) when is_list(Config) ->
{from, self()},
{options, [{verify, verify_peer} | ClientOpts]}]),
ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
+
%%--------------------------------------------------------------------
invalid_signature_client() ->
@@ -926,214 +562,22 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_verify_no_cacerts() ->
- [{doc,"Test server must have cacerts if it wants to verify client"}].
-server_verify_no_cacerts(Config) when is_list(Config) ->
- ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_rsa_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, {options, {cacertfile, ""}}}).
-
-
-%%--------------------------------------------------------------------
-unknown_server_ca_fail() ->
- [{doc,"Test that the client fails if the ca is unknown in verify_peer mode"}].
-unknown_server_ca_fail(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) ->
- {fail, Reason};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, [test_to_update_user_state | UserState]};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}
- | ClientOpts]}]),
- ssl_test_lib:check_client_alert(Server, Client, unknown_ca).
-%%--------------------------------------------------------------------
-unknown_server_ca_accept_verify_none() ->
- [{doc,"Test that the client succeds if the ca is unknown in verify_none mode"}].
-unknown_server_ca_accept_verify_none(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_none}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-unknown_server_ca_accept_verify_peer() ->
- [{doc, "Test that the client succeds if the ca is unknown in verify_peer mode"
- " with a verify_fun that accepts the unknown ca error"}].
-unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) ->
- {valid, UserState};
- (_,{bad_cert, _} = Reason, _) ->
- {fail, Reason};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, UserState};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-unknown_server_ca_accept_backwardscompatibility() ->
- [{doc,"Test that old style verify_funs will work"}].
-unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
- (Other, Acc) -> [Other | Acc]
- end,
- VerifyFun =
- fun(ErrorList) ->
- case lists:foldl(AcceptBadCa, [], ErrorList) of
- [] -> true;
- [_|_] -> false
- end
- end,
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, VerifyFun}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-customize_hostname_check() ->
- [{doc,"Test option customize_hostname_check."}].
-customize_hostname_check(Config) when is_list(Config) ->
- Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName',
- extnValue = [{dNSName, "*.example.org"}],
- critical = false}
- ],
- {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
- [[],
- [],
- [{extensions, Ext}]
- ]}],
- Config, "https_hostname_convention"),
- ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
- ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- CustomFun = public_key:pkix_verify_hostname_match_fun(https),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{server_name_indication, "other.example.org"},
- {customize_hostname_check,
- [{match_fun, CustomFun}]} | ClientOpts]
- }]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}
- ]),
- ssl_test_lib:check_client_alert(Server, Client1, handshake_failure).
-
-incomplete_chain() ->
+long_chain() ->
[{doc,"Test option verify_peer"}].
-incomplete_chain(Config) when is_list(Config) ->
- DefConf = ssl_test_lib:default_cert_chain_conf(),
- CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+long_chain(Config) when is_list(Config) ->
#{server_config := ServerConf,
- client_config := ClientConf} = public_key:pkix_test_data(CertChainConf),
+ client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(3)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(4)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(5)}]},
+ client_chain => #{root => [{key, ssl_test_lib:hardcode_rsa_key(3)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(1)}]}}),
[ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerConf),
ClientCas = proplists:get_value(cacerts, ClientConf),
-
+
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1150,6 +594,7 @@ incomplete_chain(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, ReceiveFunction, []}},
{options, [{active, Active},
{verify, verify_peer},
+ {depth, 5},
{cacerts, ServerCas ++ ClientCas} |
proplists:delete(cacerts, ClientConf)]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
new file mode 100644
index 0000000000..e598d662e9
--- /dev/null
+++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
@@ -0,0 +1,777 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_cipher_suite_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.2', [], kex()},
+ {'tlsv1.1', [], kex()},
+ {'tlsv1', [], kex()},
+ {'sslv3', [], ssl3_kex()},
+ {'dtlsv1.2', [], kex()},
+ {'dtlsv1', [], kex()},
+ {dhe_rsa, [],[dhe_rsa_3des_ede_cbc,
+ dhe_rsa_aes_128_cbc,
+ dhe_rsa_aes_256_cbc,
+ dhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc,
+ ecdhe_rsa_aes_128_cbc,
+ ecdhe_rsa_aes_128_gcm,
+ ecdhe_rsa_aes_256_cbc,
+ ecdhe_rsa_aes_256_gcm,
+ ecdhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128,
+ ecdhe_ecdsa_3des_ede_cbc,
+ ecdhe_ecdsa_aes_128_cbc,
+ ecdhe_ecdsa_aes_128_gcm,
+ ecdhe_ecdsa_aes_256_cbc,
+ ecdhe_ecdsa_aes_256_gcm,
+ ecdhe_ecdsa_chacha20_poly1305
+ ]},
+ {rsa, [], [rsa_3des_ede_cbc,
+ rsa_aes_128_cbc,
+ rsa_aes_256_cbc,
+ rsa_rc4_128
+ ]},
+ {dhe_dss, [], [dhe_dss_3des_ede_cbc,
+ dhe_dss_aes_128_cbc,
+ dhe_dss_aes_256_cbc]},
+ {srp_rsa, [], [srp_rsa_3des_ede_cbc,
+ srp_rsa_aes_128_cbc,
+ srp_rsa_aes_256_cbc]},
+ {srp_dss, [], [srp_dss_3des_ede_cbc,
+ srp_dss_aes_128_cbc,
+ srp_dss_aes_256_cbc]},
+ {rsa_psk, [], [rsa_psk_3des_ede_cbc,
+ rsa_psk_rc4_128,
+ rsa_psk_aes_128_cbc,
+ rsa_psk_aes_256_cbc
+ ]},
+ {dh_anon, [], [dh_anon_rc4_128,
+ dh_anon_3des_ede_cbc,
+ dh_anon_aes_128_cbc,
+ dh_anon_aes_128_gcm,
+ dh_anon_aes_256_cbc,
+ dh_anon_aes_256_gcm]},
+ {ecdh_anon, [], [ecdh_anon_3des_ede_cbc,
+ ecdh_anon_aes_128_cbc,
+ ecdh_anon_aes_256_cbc
+ ]},
+ {srp_anon, [], [srp_anon_3des_ede_cbc,
+ srp_anon_aes_128_cbc,
+ srp_anon_aes_256_cbc]},
+ {psk, [], [psk_3des_ede_cbc,
+ psk_rc4_128,
+ psk_aes_128_cbc,
+ psk_aes_128_ccm,
+ psk_aes_128_ccm_8,
+ psk_aes_256_cbc,
+ psk_aes_256_ccm,
+ psk_aes_256_ccm_8
+ ]},
+ {dhe_psk, [], [dhe_psk_3des_ede_cbc,
+ dhe_psk_rc4_128,
+ dhe_psk_aes_128_cbc,
+ dhe_psk_aes_128_ccm,
+ dhe_psk_aes_128_ccm_8,
+ dhe_psk_aes_256_cbc,
+ dhe_psk_aes_256_ccm,
+ dhe_psk_aes_256_ccm_8
+ ]},
+ {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc,
+ ecdhe_psk_rc4_128,
+ ecdhe_psk_aes_128_cbc,
+ ecdhe_psk_aes_128_ccm,
+ ecdhe_psk_aes_128_ccm_8,
+ ecdhe_psk_aes_256_cbc
+ ]}
+ ].
+
+kex() ->
+ rsa() ++ ecdsa() ++ dss() ++ anonymous().
+
+
+ssl3_kex() ->
+ ssl3_rsa() ++ ssl3_dss() ++ ssl3_anonymous().
+
+
+rsa() ->
+ [{group, dhe_rsa},
+ {group, ecdhe_rsa},
+ {group, rsa},
+ {group, srp_rsa},
+ {group, rsa_psk}
+ ].
+
+ssl3_rsa() ->
+ [{group, dhe_rsa},
+ {group, rsa}
+ ].
+
+ecdsa() ->
+ [{group, ecdhe_ecdsa}].
+
+dss() ->
+ [{group, dhe_dss},
+ {group, srp_dss}].
+
+ssl3_dss() ->
+ [{group, dhe_dss}
+ ].
+
+anonymous() ->
+ [{group, dh_anon},
+ {group, ecdh_anon},
+ {group, psk},
+ {group, dhe_psk},
+ {group, ecdhe_psk},
+ {group, srp_anon}
+ ].
+
+ssl3_anonymous() ->
+ [{group, dh_anon}].
+
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) when GroupName == ecdh_anon;
+ GroupName == ecdhe_rsa;
+ GroupName == ecdhe_psk ->
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(ecdhe_ecdsa = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(dhe_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(srp_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS_SRP crypto support"}
+ end;
+init_per_group(GroupName, Config) when GroupName == srp_anon;
+ GroupName == srp_rsa ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+init_per_group(dhe_psk = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+init_per_group(GroupName, Config0) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, end_per_group(GroupName, Config0));
+ false ->
+ init_certs(GroupName, Config0)
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc;
+ TestCase == srp_anon_3des_ede_cbc;
+ TestCase == dhe_psk_3des_ede_cbc;
+ TestCase == ecdhe_psk_3des_ede_cbc;
+ TestCase == srp_rsa_3des_ede_cbc;
+ TestCase == srp_dss_3des_ede_cbc;
+ TestCase == rsa_psk_3des_ede_cbc;
+ TestCase == rsa_3des_ede_cbc;
+ TestCase == dhe_rsa_3des_ede_cbc;
+ TestCase == dhe_dss_3des_ede_cbc;
+ TestCase == ecdhe_rsa_3des_ede_cbc;
+ TestCase == srp_anon_dss_3des_ede_cbc;
+ TestCase == dh_anon_3des_ede_cbc;
+ TestCase == ecdh_anon_3des_ede_cbc;
+ TestCase == ecdhe_ecdsa_3des_ede_cbc ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(des_ede3, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing 3DES crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128;
+ TestCase == ecdhe_psk_rc4_128;
+ TestCase == dhe_psk_rc4_128;
+ TestCase == rsa_psk_rc4_128;
+ TestCase == rsa_rc4_128;
+ TestCase == ecdhe_rsa_rc4_128;
+ TestCase == ecdhe_ecdsa_rc4_128;
+ TestCase == dh_anon_rc4_128 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(rc4, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing RC4 crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8;
+ TestCase == rsa_psk_aes_128_ccm_8;
+ TestCase == psk_aes_128_ccm_8;
+ TestCase == dhe_psk_aes_128_ccm_8;
+ TestCase == ecdhe_psk_aes_128_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_128_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8;
+ TestCase == rsa_psk_aes_256_ccm_8;
+ TestCase == psk_aes_256_ccm_8;
+ TestCase == dhe_psk_aes_256_ccm_8;
+ TestCase == ecdhe_psk_aes_256_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_256_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_256_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) ->
+ Cipher = ssl_test_lib:test_cipher(TestCase, Config),
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(Cipher, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, {Cipher, SupCiphers}}
+ end.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Initializtion ------------------------------------------
+%%--------------------------------------------------------------------
+
+init_certs(srp_rsa, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_anon, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa_psk, Config) ->
+ ClientExt = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],[],[{extensions, ClientExt}]]}],
+ Config, "_peer_keyEncipherment"),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ServerOpts],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa, Config) ->
+ ClientExt = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],[],[{extensions, ClientExt}]]}],
+ Config, "_peer_keyEncipherment"),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(dhe_dss, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(dsa, dsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_dss, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(dsa, dsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_rsa;
+ GroupName == ecdhe_rsa ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_ecdsa;
+ GroupName == ecdhe_ecdsa ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(ecdsa, ecdsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == psk;
+ GroupName == dhe_psk;
+ GroupName == ecdhe_psk ->
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(_GroupName, Config) ->
+ %% Anonymous does not need certs
+ [{tls_config, #{server_config => [],
+ client_config => []}} |
+ proplists:delete(tls_config, Config)].
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% SRP --------------------------------------------------------
+%%--------------------------------------------------------------------
+srp_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, '3des_ede_cbc', Config).
+
+srp_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_128_cbc', Config).
+
+srp_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_256_cbc', Config).
+
+srp_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, '3des_ede_cbc', Config).
+
+srp_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_128_cbc', Config).
+
+srp_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_256_cbc', Config).
+
+%%--------------------------------------------------------------------
+%% PSK --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, '3des_ede_cbc', Config).
+
+rsa_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_cbc', Config).
+
+rsa_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm', Config).
+
+rsa_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm_8', Config).
+
+rsa_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_cbc', Config).
+
+rsa_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm', Config).
+
+rsa_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm_8', Config).
+
+rsa_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'rc4_128', Config).
+
+%%--------------------------------------------------------------------
+%% RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'des_cbc', Config).
+
+rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, '3des_ede_cbc', Config).
+
+rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_cbc', Config).
+
+rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_cbc', Config).
+
+rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_gcm', Config).
+
+rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_gcm', Config).
+
+rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'rc4_128', Config).
+%%--------------------------------------------------------------------
+%% DHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, '3des_ede_cbc', Config).
+
+dhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_cbc', Config).
+
+dhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_gcm', Config).
+
+dhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config).
+
+dhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config).
+
+dhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% ECDHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, '3des_ede_cbc', Config).
+
+ecdhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_cbc', Config).
+
+ecdhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_gcm', Config).
+
+ecdhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_cbc', Config).
+
+ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_gcm', Config).
+
+ecdhe_rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'rc4_128', Config).
+
+ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config).
+
+%%--------------------------------------------------------------------
+%% ECDHE_ECDSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_ecdsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'rc4_128', Config).
+
+ecdhe_ecdsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, '3des_ede_cbc', Config).
+
+ecdhe_ecdsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_cbc', Config).
+
+ecdhe_ecdsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_gcm', Config).
+
+ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_cbc', Config).
+
+ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config).
+
+ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% DHE_DSS --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_dss_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'des_cbc', Config).
+
+dhe_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, '3des_ede_cbc', Config).
+
+dhe_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_cbc', Config).
+
+dhe_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_cbc', Config).
+
+dhe_dss_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_gcm', Config).
+
+dhe_dss_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_gcm', Config).
+
+%%--------------------------------------------------------------------
+%% Anonymous --------------------------------------------------------
+%%--------------------------------------------------------------------
+dh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, '3des_ede_cbc', Config).
+
+dh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_cbc', Config).
+
+dh_anon_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_gcm', Config).
+
+dh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_cbc', Config).
+
+dh_anon_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_gcm', Config).
+
+dh_anon_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'rc4_128', Config).
+
+ecdh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, '3des_ede_cbc', Config).
+
+ecdh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_128_cbc', Config).
+
+ecdh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config).
+
+srp_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, '3des_ede_cbc', Config).
+
+srp_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_128_cbc', Config).
+
+srp_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_256_cbc', Config).
+
+dhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'des_cbc', Config).
+
+dhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'rc4_128', Config).
+
+dhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, '3des_ede_cbc', Config).
+
+dhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_cbc', Config).
+
+dhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_cbc', Config).
+
+dhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_gcm', Config).
+
+dhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_gcm', Config).
+
+dhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm', Config).
+
+dhe_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm', Config).
+
+dhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm_8', Config).
+
+dhe_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config).
+
+ecdhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'des_cbc', Config).
+
+ecdhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'rc4_128', Config).
+
+ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config).
+
+ecdhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config).
+
+ecdhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config).
+
+ecdhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config).
+
+ecdhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config).
+
+ecdhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config).
+
+ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config).
+
+psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'des_cbc', Config).
+
+psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'rc4_128', Config).
+
+psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, '3des_ede_cbc', Config).
+
+psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_cbc', Config).
+
+psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_cbc', Config).
+
+psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_gcm', Config).
+
+psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_gcm', Config).
+
+psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm', Config).
+
+psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm', Config).
+
+psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm_8', Config).
+
+psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm_8', Config).
+
+%%--------------------------------------------------------------------
+%% Internal functions ----------------------------------------------
+%%--------------------------------------------------------------------
+run_ciphers_test(Kex, Cipher, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ TestCiphers = test_ciphers(Kex, Cipher, Version),
+
+ case TestCiphers of
+ [_|_] ->
+ lists:foreach(fun(TestCipher) ->
+ cipher_suite_test(TestCipher, Version, Config)
+ end, TestCiphers);
+ [] ->
+ {skip, {not_sup, Kex, Cipher, Version}}
+ end.
+
+cipher_suite_test(ErlangCipherSuite, Version, Config) ->
+ #{server_config := SOpts,
+ client_config := COpts} = proplists:get_value(tls_config, Config),
+ ServerOpts = ssl_test_lib:ssl_options(SOpts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(COpts, Config),
+ ct:log("Testing CipherSuite ~p~n", [ErlangCipherSuite]),
+ ct:log("Server Opts ~p~n", [ServerOpts]),
+ ct:log("Client Opts ~p~n", [ClientOpts]),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options, [{versions, [Version]}, {ciphers, [ErlangCipherSuite]} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options, [{versions, [Version]}, {ciphers, [ErlangCipherSuite]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+test_ciphers(Kex, Cipher, Version) ->
+ ssl:filter_cipher_suites(ssl:cipher_suites(all, Version) ++ ssl:cipher_suites(anonymous, Version),
+ [{key_exchange,
+ fun(Kex0) when Kex0 == Kex -> true;
+ (_) -> false
+ end},
+ {cipher,
+ fun(Cipher0) when Cipher0 == Cipher -> true;
+ (_) -> false
+ end}]).
+
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 003e1fc448..7cfb2ac0c5 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -311,9 +311,11 @@ listen_port_options(Config) when is_list(Config) ->
catch
_:Reason ->
stop_ssl_node(NH2),
+ stop_ssl_node(NH1),
ct:fail(Reason)
end,
stop_ssl_node(NH2),
+ stop_ssl_node(NH1),
success(Config).
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_dist_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl
index 618ad0789e..67944c74d2 100644
--- a/lib/ssl/test/ssl_dist_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_bench_SUITE.erl
@@ -32,6 +32,7 @@
-export(
[setup/1,
roundtrip/1,
+ sched_utilization/1,
throughput_0/1,
throughput_64/1,
throughput_1024/1,
@@ -48,14 +49,19 @@
suite() -> [{ct_hooks, [{ts_install_cth, [{nodenames, 2}]}]}].
-all() -> [{group, ssl}, {group, plain}].
+all() ->
+ [{group, ssl},
+ {group, crypto},
+ {group, plain}].
groups() ->
[{ssl, all_groups()},
+ {crypto, all_groups()},
{plain, all_groups()},
%%
{setup, [{repeat, 1}], [setup]},
{roundtrip, [{repeat, 1}], [roundtrip]},
+ {sched_utilization,[{repeat, 1}], [sched_utilization]},
{throughput, [{repeat, 1}],
[throughput_0,
throughput_64,
@@ -69,7 +75,9 @@ groups() ->
all_groups() ->
[{group, setup},
{group, roundtrip},
- {group, throughput}].
+ {group, throughput},
+ {group, sched_utilization}
+ ].
init_per_suite(Config) ->
Digest = sha1,
@@ -160,6 +168,11 @@ end_per_suite(Config) ->
init_per_group(ssl, Config) ->
[{ssl_dist, true}, {ssl_dist_prefix, "SSL"}|Config];
+init_per_group(crypto, Config) ->
+ [{ssl_dist, false}, {ssl_dist_prefix, "Crypto"},
+ {ssl_dist_args,
+ "-proto_dist inet_crypto"}
+ |Config];
init_per_group(plain, Config) ->
[{ssl_dist, false}, {ssl_dist_prefix, "Plain"}|Config];
init_per_group(_GroupName, Config) ->
@@ -351,6 +364,120 @@ roundtrip_client(Pid, Mon, StartTime, N) ->
roundtrip_client(Pid, Mon, StartTime, N - 1)
end.
+%%---------------------------------------
+%% Scheduler utilization at constant load
+
+
+sched_utilization(Config) ->
+ run_nodepair_test(
+ fun(A, B, Prefix, HA, HB) ->
+ sched_utilization(A, B, Prefix, HA, HB, proplists:get_value(ssl_dist, Config))
+ end, Config).
+
+sched_utilization(A, B, Prefix, HA, HB, SSL) ->
+ [] = ssl_apply(HA, erlang, nodes, []),
+ [] = ssl_apply(HB, erlang, nodes, []),
+ {ClientMsacc, ServerMsacc, Msgs} =
+ ssl_apply(HA, fun () -> sched_util_runner(A, B, SSL) end),
+ [B] = ssl_apply(HA, erlang, nodes, []),
+ [A] = ssl_apply(HB, erlang, nodes, []),
+ msacc:print(ClientMsacc),
+ msacc:print(ServerMsacc),
+ ct:pal("Got ~p busy_dist_port msgs",[length(Msgs)]),
+ ct:log("Stats of B from A: ~p",
+ [ssl_apply(HA, net_kernel, node_info, [B])]),
+ ct:log("Stats of A from B: ~p",
+ [ssl_apply(HB, net_kernel, node_info, [A])]),
+ SchedUtilClient =
+ round(10000 * msacc:stats(system_runtime,ClientMsacc) /
+ msacc:stats(system_realtime,ClientMsacc)),
+ SchedUtilServer =
+ round(10000 * msacc:stats(system_runtime,ServerMsacc) /
+ msacc:stats(system_realtime,ServerMsacc)),
+ Verdict =
+ case Msgs of
+ [] ->
+ "";
+ _ ->
+ " ???"
+ end,
+ {comment, ClientComment} =
+ report(Prefix ++ " Sched Utilization Client" ++ Verdict,
+ SchedUtilClient, "/100 %" ++ Verdict),
+ {comment, ServerComment} =
+ report(Prefix++" Sched Utilization Server" ++ Verdict,
+ SchedUtilServer, "/100 %" ++ Verdict),
+ {comment, "Client " ++ ClientComment ++ ", Server " ++ ServerComment}.
+
+%% Runs on node A and spawns a server on node B
+%% We want to avoid getting busy_dist_port as it hides the true SU usage
+%% of the receiver and sender.
+sched_util_runner(A, B, true) ->
+ sched_util_runner(A, B, 250);
+sched_util_runner(A, B, false) ->
+ sched_util_runner(A, B, 250);
+sched_util_runner(A, B, Senders) ->
+ Payload = payload(5),
+ [A] = rpc:call(B, erlang, nodes, []),
+ ServerPids =
+ [erlang:spawn_link(
+ B, fun () -> throughput_server() end)
+ || _ <- lists:seq(1, Senders)],
+ ServerMsacc =
+ erlang:spawn(
+ B,
+ fun() ->
+ receive
+ {start,Pid} ->
+ msacc:start(10000),
+ receive
+ {done,Pid} ->
+ Pid ! {self(),msacc:stats()}
+ end
+ end
+ end),
+ erlang:system_monitor(self(),[busy_dist_port]),
+ %% We spawn 250 senders which should mean that we
+ %% have a load of 250 msgs/msec
+ [spawn_link(
+ fun() ->
+ throughput_client(Pid, Payload)
+ end) || Pid <- ServerPids],
+ %%
+ receive after 1000 -> ok end,
+ ServerMsacc ! {start,self()},
+ msacc:start(10000),
+ ClientMsaccStats = msacc:stats(),
+ receive after 1000 -> ok end,
+ ServerMsacc ! {done,self()},
+ ServerMsaccStats = receive {ServerMsacc,Stats} -> Stats end,
+ %%
+ {ClientMsaccStats,ServerMsaccStats, flush()}.
+
+flush() ->
+ receive
+ M ->
+ [M | flush()]
+ after 0 ->
+ []
+ end.
+
+throughput_server() ->
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ throughput_server().
+
+throughput_client(Pid, Payload) ->
+ Pid ! Payload,
+ receive after 1 -> throughput_client(Pid, Payload) end.
%%-----------------
%% Throughput speed
@@ -425,15 +552,20 @@ throughput(A, B, Prefix, HA, HB, Packets, Size) ->
+ byte_size(erlang:term_to_binary([0|<<>>])), % Benchmark overhead
Bytes = Packets * (Size + Overhead),
io:format("~w bytes, ~.4g s~n", [Bytes,Time/1000000]),
+ SizeString = integer_to_list(Size),
ClientMsaccStats =:= undefined orelse
- io:format(
- "Sender core usage ratio: ~.4g ns/byte~n",
- [msacc:stats(system_runtime, ClientMsaccStats)*1000/Bytes]),
+ report(
+ Prefix ++ " Sender_RelativeCoreLoad_" ++ SizeString,
+ round(msacc:stats(system_runtime, ClientMsaccStats)
+ * 1000000 / Bytes),
+ "ps/byte"),
ServerMsaccStats =:= undefined orelse
begin
- io:format(
- "Receiver core usage ratio: ~.4g ns/byte~n",
- [msacc:stats(system_runtime, ServerMsaccStats)*1000/Bytes]),
+ report(
+ Prefix ++ " Receiver_RelativeCoreLoad_" ++ SizeString,
+ round(msacc:stats(system_runtime, ServerMsaccStats)
+ * 1000000 / Bytes),
+ "ps/byte"),
msacc:print(ServerMsaccStats)
end,
io:format("******* ClientProf:~n", []), prof_print(ClientProf),
@@ -441,7 +573,7 @@ throughput(A, B, Prefix, HA, HB, Packets, Size) ->
io:format("******* Server GC Before:~n~p~n", [Server_GC_Before]),
io:format("******* Server GC After:~n~p~n", [Server_GC_After]),
Speed = round((Bytes * 1000000) / (1024 * Time)),
- report(Prefix++" Throughput_"++integer_to_list(Size), Speed, "kB/s").
+ report(Prefix ++ " Throughput_" ++ SizeString, Speed, "kB/s").
%% Runs on node A and spawns a server on node B
throughput_runner(A, B, Rounds, Size) ->
@@ -449,11 +581,12 @@ throughput_runner(A, B, Rounds, Size) ->
[A] = rpc:call(B, erlang, nodes, []),
ClientPid = self(),
ServerPid =
- erlang:spawn(
+ erlang:spawn_opt(
B,
- fun () -> throughput_server(ClientPid, Rounds) end),
+ fun () -> throughput_server(ClientPid, Rounds) end,
+ [{message_queue_data, off_heap}]),
ServerMon = erlang:monitor(process, ServerPid),
- msacc:available() andalso
+ msacc_available() andalso
begin
msacc:stop(),
msacc:reset(),
@@ -465,7 +598,7 @@ throughput_runner(A, B, Rounds, Size) ->
throughput_client(ServerPid, ServerMon, Payload, Rounds),
prof_stop(),
MsaccStats =
- case msacc:available() of
+ case msacc_available() of
true ->
MStats = msacc:stats(),
msacc:stop(),
@@ -505,7 +638,7 @@ throughput_server(Pid, N) ->
GC_Before = get_server_gc_info(),
%% dbg:tracer(port, dbg:trace_port(file, "throughput_server_gc.log")),
%% dbg:p(TLSDistReceiver, garbage_collection),
- msacc:available() andalso
+ msacc_available() andalso
begin
msacc:stop(),
msacc:reset(),
@@ -518,7 +651,7 @@ throughput_server(Pid, N) ->
throughput_server_loop(_Pid, GC_Before, 0) ->
prof_stop(),
MsaccStats =
- case msacc:available() of
+ case msacc_available() of
true ->
msacc:stop(),
MStats = msacc:stats(),
@@ -535,8 +668,13 @@ throughput_server_loop(_Pid, GC_Before, 0) ->
server_gc_after => get_server_gc_info()});
throughput_server_loop(Pid, GC_Before, N) ->
receive
- {Pid, N, _} ->
- throughput_server_loop(Pid, GC_Before, N-1)
+ Msg ->
+ case Msg of
+ {Pid, N, _} ->
+ throughput_server_loop(Pid, GC_Before, N - 1);
+ Other ->
+ erlang:error({self(),?FUNCTION_NAME,Other})
+ end
end.
get_server_gc_info() ->
@@ -676,7 +814,7 @@ get_node_args(Tag, Config) ->
true ->
proplists:get_value(Tag, Config);
false ->
- ""
+ proplists:get_value(ssl_dist_args, Config, "")
end.
@@ -731,3 +869,6 @@ report(Name, Value, Unit) ->
term_to_string(Term) ->
unicode:characters_to_list(
io_lib:write(Term, [{encoding, unicode}])).
+
+msacc_available() ->
+ msacc:available().
diff --git a/lib/ssl/test/ssl_dist_test_lib.erl b/lib/ssl/test/ssl_dist_test_lib.erl
index 1b9c853fc4..b8b805b2c4 100644
--- a/lib/ssl/test/ssl_dist_test_lib.erl
+++ b/lib/ssl/test/ssl_dist_test_lib.erl
@@ -144,6 +144,8 @@ mk_node_cmdline(ListenPort, Name, Args) ->
++ integer_to_list(ListenPort) ++ " "
++ Args ++ " "
++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ Name ++ " "
+ ++ "-kernel inet_dist_connect_options \"[{recbuf,12582912},{sndbuf,12582912},{high_watermark,8388608},{low_watermark,4194304}]\" "
+ ++ "-kernel inet_dist_listen_options \"[{recbuf,12582912},{sndbuf,12582912},{high_watermark,8388608},{low_watermark,4194304}]\" "
++ "-kernel error_logger \"{file,\\\"" ++ Pwd ++ "/error_log." ++ Name ++ "\\\"}\" "
++ "-setcookie " ++ atom_to_list(erlang:get_cookie()).
@@ -179,8 +181,9 @@ check_ssl_node_up(Socket, Name, Bin) ->
Parent = self(),
Go = make_ref(),
%% Spawn connection handler on test server side
- Pid = spawn_link(
+ Pid = spawn(
fun () ->
+ link(group_leader()),
receive Go -> ok end,
process_flag(trap_exit, true),
tstsrvr_con_loop(Name, Socket, Parent)
diff --git a/lib/ssl/test/ssl_eqc_SUITE.erl b/lib/ssl/test/ssl_eqc_SUITE.erl
new file mode 100644
index 0000000000..bfdb1a3d54
--- /dev/null
+++ b/lib/ssl/test/ssl_eqc_SUITE.erl
@@ -0,0 +1,70 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2015. 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_eqc_SUITE).
+
+-compile(export_all).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ tls_handshake_encoding,
+ tls_cipher_suite_names,
+ tls_cipher_openssl_suite_names
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ct_property_test:init_per_suite(Config).
+end_per_suite(Config) ->
+ Config.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_,Config) ->
+ Config.
+
+init_per_testcase(_, Config0) ->
+ Config0.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_handshake_encoding(Config) when is_list(Config) ->
+ %% manual test: proper:quickcheck(ssl_eqc_handshake:prop_tls_hs_encode_decode()).
+ true = ct_property_test:quickcheck(ssl_eqc_handshake:prop_tls_hs_encode_decode(),
+ Config).
+
+tls_cipher_suite_names(Config) when is_list(Config) ->
+ %% manual test: proper:quickcheck(ssl_eqc_cipher_format:prop_tls_cipher_suite_rfc_name()).
+ true = ct_property_test:quickcheck(ssl_eqc_cipher_format:prop_tls_cipher_suite_rfc_name(),
+ Config).
+
+tls_cipher_openssl_suite_names(Config) when is_list(Config) ->
+ %% manual test: proper:quickcheck(ssl_eqc_handshake:prop_tls_cipher_suite_openssl_name()).
+ true = ct_property_test:quickcheck(ssl_eqc_cipher_format:prop_tls_cipher_suite_openssl_name(),
+ Config).
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 1fa6029963..2750a4a9dc 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -25,6 +25,7 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
+-include("ssl_alert.hrl").
-include("ssl_handshake.hrl").
-include("ssl_internal.hrl").
-include("tls_handshake.hrl").
@@ -42,7 +43,7 @@ all() -> [decode_hello_handshake,
decode_empty_server_sni_correctly,
select_proper_tls_1_2_rsa_default_hashsign,
ignore_hassign_extension_pre_tls_1_2,
- unorded_chain,
+ unorded_chain, signature_algorithms,
encode_decode_srp].
%%--------------------------------------------------------------------
@@ -57,7 +58,9 @@ init_per_group(_GroupName, Config) ->
end_per_group(_,Config) ->
Config.
-init_per_testcase(ignore_hassign_extension_pre_tls_1_2, Config0) ->
+init_per_testcase(TC, Config0) when
+ TC =:= ignore_hassign_extension_pre_tls_1_2 orelse
+ TC =:= signature_algorithms ->
catch crypto:stop(),
try crypto:start() of
ok ->
@@ -106,15 +109,13 @@ decode_hello_handshake(_Config) ->
#ssl_options{}),
{Hello, _Data} = hd(Records),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = (Hello#server_hello.extensions)#hello_extensions.renegotiation_info.
-
+ Extensions = Hello#server_hello.extensions,
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
decode_single_hello_extension_correctly(_Config) ->
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:decode_hello_extensions(Renegotiation),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = Extensions#hello_extensions.renegotiation_info.
+ Extensions = ssl_handshake:decode_extensions(Renegotiation, {3,3}, undefined),
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
decode_supported_elliptic_curves_hello_extension_correctly(_Config) ->
% List of supported and unsupported curves (RFC4492:S5.1.1)
@@ -125,37 +126,34 @@ decode_supported_elliptic_curves_hello_extension_correctly(_Config) ->
Len = ListLen + 2,
Extension = <<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary>>,
% after decoding we should see only valid curves
- #hello_extensions{elliptic_curves = DecodedCurves} = ssl_handshake:decode_hello_extensions(Extension),
- #elliptic_curves{elliptic_curve_list = [?sect233k1, ?sect193r2]} = DecodedCurves.
+ Extensions = ssl_handshake:decode_hello_extensions(Extension, {3,2}, {3,2}, client),
+ #{elliptic_curves := #elliptic_curves{elliptic_curve_list = [?sect233k1, ?sect193r2]}} = Extensions.
decode_unknown_hello_extension_correctly(_Config) ->
FourByteUnknown = <<16#CA,16#FE, ?UINT16(4), 3, 0, 1, 2>>,
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:decode_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = Extensions#hello_extensions.renegotiation_info.
+ Extensions = ssl_handshake:decode_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>, {3,2}, {3,2}, client),
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
+
encode_single_hello_sni_extension_correctly(_Config) ->
- Exts = #hello_extensions{sni = #sni{hostname = "test.com"}},
SNI = <<16#00, 16#00, 16#00, 16#0d, 16#00, 16#0b, 16#00, 16#00, 16#08,
$t, $e, $s, $t, $., $c, $o, $m>>,
ExtSize = byte_size(SNI),
HelloExt = <<ExtSize:16/unsigned-big-integer, SNI/binary>>,
- Encoded = ssl_handshake:encode_hello_extensions(Exts),
+ Encoded = ssl_handshake:encode_extensions([#sni{hostname = "test.com"}]),
HelloExt = Encoded.
decode_single_hello_sni_extension_correctly(_Config) ->
- Exts = #hello_extensions{sni = #sni{hostname = "test.com"}},
SNI = <<16#00, 16#00, 16#00, 16#0d, 16#00, 16#0b, 16#00, 16#00, 16#08,
$t, $e, $s, $t, $., $c, $o, $m>>,
- Decoded = ssl_handshake:decode_hello_extensions(SNI),
- Exts = Decoded.
+ Decoded = ssl_handshake:decode_hello_extensions(SNI, {3,3}, {3,3}, client),
+ #{sni := #sni{hostname = "test.com"}} = Decoded.
decode_empty_server_sni_correctly(_Config) ->
- Exts = #hello_extensions{sni = #sni{hostname = ""}},
SNI = <<?UINT16(?SNI_EXT),?UINT16(0)>>,
- Decoded = ssl_handshake:decode_hello_extensions(SNI),
- Exts = Decoded.
+ Decoded = ssl_handshake:decode_hello_extensions(SNI, {3,3}, {3,3}, server),
+ #{sni := #sni{hostname = ""}} = Decoded.
select_proper_tls_1_2_rsa_default_hashsign(_Config) ->
@@ -170,11 +168,11 @@ ignore_hassign_extension_pre_tls_1_2(Config) ->
Opts = proplists:get_value(server_opts, Config),
CertFile = proplists:get_value(certfile, Opts),
[{_, Cert, _}] = ssl_test_lib:pem_to_der(CertFile),
- HashSigns = #hash_sign_algos{hash_sign_algos = [{sha512, rsa}, {sha, dsa}]},
- {sha512, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,3}), {3,3}),
+ HashSigns = #hash_sign_algos{hash_sign_algos = [{sha512, rsa}, {sha, dsa}, {sha, rsa}]},
+ {sha512, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,3}), {3,3}),
%%% Ignore
- {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,2}), {3,2}),
- {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,0}), {3,0}).
+ {md5sha, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,2}), {3,2}),
+ {md5sha, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,0}), {3,0}).
unorded_chain(Config) when is_list(Config) ->
DefConf = ssl_test_lib:default_cert_chain_conf(),
@@ -195,30 +193,78 @@ unorded_chain(Config) when is_list(Config) ->
ssl_certificate:certificate_chain(PeerCert, ets:new(foo, []), ExtractedCerts, UnordedChain).
encode_decode_srp(_Config) ->
- Exts = #hello_extensions{
- srp = #srp{username = <<"foo">>},
- sni = #sni{hostname = "bar"},
- renegotiation_info = undefined,
- signature_algs = undefined,
- alpn = undefined,
- next_protocol_negotiation = undefined,
- ec_point_formats = undefined,
- elliptic_curves = undefined
- },
- EncodedExts = <<0,20, % Length
+ Exts = #{srp => #srp{username = <<"foo">>},
+ sni => #sni{hostname = "bar"},
+ renegotiation_info => undefined,
+ signature_algs => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ ec_point_formats => undefined,
+ elliptic_curves => undefined
+ },
+ EncodedExts0 = <<0,20, % Length
+ 0,12, % SRP extension
+ 0,4, % Length
+ 3, % srp_I length
+ 102,111,111, % username = "foo"
0,0, % SNI extension
0,8, % Length
0,6, % ServerNameLength
0, % NameType (host_name)
0,3, % HostNameLength
- 98,97,114, % hostname = "bar"
- 0,12, % SRP extension
- 0,4, % Length
- 3, % srp_I length
- 102,111,111>>, % username = "foo"
- EncodedExts = ssl_handshake:encode_hello_extensions(Exts),
- Exts = ssl_handshake:decode_hello_extensions({client, EncodedExts}).
+ 98,97,114>>, % hostname = "bar"
+ EncodedExts0 = <<?UINT16(_),EncodedExts/binary>> =
+ ssl_handshake:encode_hello_extensions(Exts, {3,3}),
+ Exts = ssl_handshake:decode_hello_extensions(EncodedExts, {3,3}, {3,3}, client).
+signature_algorithms(Config) ->
+ Opts = proplists:get_value(server_opts, Config),
+ CertFile = proplists:get_value(certfile, Opts),
+ io:format("Cert = ~p~n", [CertFile]),
+ [{_, Cert, _}] = ssl_test_lib:pem_to_der(CertFile),
+ HashSigns0 = #hash_sign_algos{
+ hash_sign_algos = [{sha512, rsa},
+ {sha, dsa},
+ {sha, rsa}]},
+ Schemes0 = #signature_algorithms_cert{
+ signature_scheme_list = [rsa_pkcs1_sha1,
+ ecdsa_sha1]},
+ {sha512, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns0, Schemes0},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ HashSigns1 = #hash_sign_algos{
+ hash_sign_algos = [{sha, dsa},
+ {sha, rsa}]},
+ {sha, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns1, Schemes0},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ Schemes1 = #signature_algorithms_cert{
+ signature_scheme_list = [rsa_pkcs1_sha256,
+ ecdsa_sha1]},
+ %% Signature not supported
+ #alert{} = ssl_handshake:select_hashsign(
+ {HashSigns1, Schemes1},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ %% No scheme, hashsign is used
+ {sha, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns1, undefined},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ HashSigns2 = #hash_sign_algos{
+ hash_sign_algos = [{sha, dsa}]},
+ %% Signature not supported
+ #alert{} = ssl_handshake:select_hashsign(
+ {HashSigns2, Schemes1},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}).
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_SUITE.erl
index 878e983bb9..8a76a3a82b 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_SUITE.erl
@@ -19,7 +19,7 @@
%%
%%
--module(ssl_npn_handshake_SUITE).
+-module(ssl_npn_SUITE).
%% Note: This directive should only be used in test suites.
-compile(export_all).
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 35af666e9e..7dbc0c5134 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -24,10 +24,11 @@
%% Note: This directive should only be used in test suites.
-compile(export_all).
--include("ssl_cipher.hrl").
--include("ssl_internal.hrl").
--include("tls_handshake.hrl").
--include("tls_record.hrl").
+
+-include_lib("ssl/src/tls_record.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+-include_lib("ssl/src/ssl_cipher.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
@@ -71,44 +72,46 @@ encode_and_decode_client_hello_test(Config) ->
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#client_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = undefined.
+ Extensions = DecodedHandshakeMessage#client_hello.extensions,
+ #{next_protocol_negotiation := undefined} = Extensions.
%%--------------------------------------------------------------------
encode_and_decode_npn_client_hello_test(Config) ->
HandShakeData = create_client_handshake(#next_protocol_negotiation{extension_data = <<>>}),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#client_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<>>}.
+ Extensions = DecodedHandshakeMessage#client_hello.extensions,
+ #{next_protocol_negotiation := #next_protocol_negotiation{extension_data = <<>>}} = Extensions.
%%--------------------------------------------------------------------
encode_and_decode_server_hello_test(Config) ->
HandShakeData = create_server_handshake(undefined),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#server_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = undefined.
+ Extensions = DecodedHandshakeMessage#server_hello.extensions,
+ #{next_protocol_negotiation := undefined} = Extensions.
+
%%--------------------------------------------------------------------
encode_and_decode_npn_server_hello_test(Config) ->
HandShakeData = create_server_handshake(#next_protocol_negotiation{extension_data = <<6, "spdy/2">>}),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#server_hello.extensions)#hello_extensions.next_protocol_negotiation,
- ct:log("~p ~n", [NextProtocolNegotiation]),
- NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
+ Extensions = DecodedHandshakeMessage#server_hello.extensions,
+ ct:log("~p ~n", [Extensions]),
+ #{next_protocol_negotiation := #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}} = Extensions.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), #hello_extensions{}),
- undefined = (Hello#server_hello.extensions)#hello_extensions.next_protocol_negotiation.
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), #{}),
+ Extensions = Hello#server_hello.extensions,
+ #{} = Extensions.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- #hello_extensions{next_protocol_negotiation = [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]}),
- [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>] =
- (Hello#server_hello.extensions)#hello_extensions.next_protocol_negotiation.
+ #{next_protocol_negotiation => [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]}),
+ Extensions = Hello#server_hello.extensions,
+ #{next_protocol_negotiation := [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]} = Extensions.
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -120,9 +123,8 @@ create_client_handshake(Npn) ->
session_id = <<>>,
cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA],
compression_methods = "",
- extensions = #hello_extensions{
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}}
+ extensions = #{next_protocol_negotiation => Npn,
+ renegotiation_info => #renegotiation_info{}}
}, Vsn).
create_server_handshake(Npn) ->
@@ -133,9 +135,8 @@ create_server_handshake(Npn) ->
session_id = <<>>,
cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA,
compression_method = 1,
- extensions = #hello_extensions{
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}}
+ extensions = #{next_protocol_negotiation => Npn,
+ renegotiation_info => #renegotiation_info{}}
}, Vsn).
create_connection_states() ->
@@ -146,5 +147,5 @@ create_connection_states() ->
}
},
current_read => #{secure_renegotiation => false
- }
+ }
}.
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 27b9c258a0..2d0ffd03d7 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -48,21 +48,27 @@ groups() ->
payload_tests() ->
[server_echos_passive_small,
+ server_echos_passive_chunk_small,
server_echos_active_once_small,
server_echos_active_small,
client_echos_passive_small,
+ client_echos_passive_chunk_small,
client_echos_active_once_small,
client_echos_active_small,
server_echos_passive_big,
+ server_echos_passive_chunk_big,
server_echos_active_once_big,
server_echos_active_big,
client_echos_passive_big,
+ client_echos_passive_chunk_big,
client_echos_active_once_big,
client_echos_active_big,
server_echos_passive_huge,
+ server_echos_passive_chunk_huge,
server_echos_active_once_huge,
server_echos_active_huge,
client_echos_passive_huge,
+ client_echos_passive_chunk_huge,
client_echos_active_once_huge,
client_echos_active_huge,
client_active_once_server_close].
@@ -109,9 +115,11 @@ end_per_group(GroupName, Config) ->
init_per_testcase(TestCase, Config)
when TestCase == server_echos_passive_huge;
+ TestCase == server_echos_passive_chunk_huge;
TestCase == server_echos_active_once_huge;
TestCase == server_echos_active_huge;
TestCase == client_echos_passive_huge;
+ TestCase == client_echos_passive_chunk_huge;
TestCase == client_echos_active_once_huge;
TestCase == client_echos_active_huge ->
case erlang:system_info(system_architecture) of
@@ -124,9 +132,11 @@ init_per_testcase(TestCase, Config)
init_per_testcase(TestCase, Config)
when TestCase == server_echos_passive_big;
+ TestCase == server_echos_passive_chunk_big;
TestCase == server_echos_active_once_big;
TestCase == server_echos_active_big;
TestCase == client_echos_passive_big;
+ TestCase == client_echos_passive_chunk_big;
TestCase == client_echos_active_once_big;
TestCase == client_echos_active_big ->
ct:timetrap({seconds, 60}),
@@ -157,6 +167,22 @@ server_echos_passive_small(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
+server_echos_passive_chunk_small() ->
+ [{doc, "Client sends 1000 bytes in passive mode to server, that receives them in chunks, "
+ "sends them back, and closes."}].
+
+server_echos_passive_chunk_small(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ server_echos_passive_chunk(
+ Data, 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."}].
@@ -200,6 +226,21 @@ client_echos_passive_small(Config) when is_list(Config) ->
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
+client_echos_passive_chunk__small() ->
+ [{doc, "Server sends 1000 bytes in passive mode to client, that receives them in chunks, "
+ "sends them back, and closes."}].
+
+client_echos_passive_chunk_small(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+
+%%--------------------------------------------------------------------
client_echos_active_once_small() ->
["Server sends 1000 bytes in active once mode to client, that receives "
"them, sends them back, and closes."].
@@ -241,6 +282,19 @@ server_echos_passive_big(Config) when is_list(Config) ->
Data = binary:copy(<<"1234567890">>, 5000),
server_echos_passive(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+%%--------------------------------------------------------------------
+server_echos_passive_chunk_big() ->
+ [{doc, "Client sends 50000 bytes to server in passive mode, that receives them, "
+ "sends them back, and closes."}].
+
+server_echos_passive_chunk_big(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ server_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
@@ -286,6 +340,22 @@ client_echos_passive_big(Config) when is_list(Config) ->
client_echos_passive(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+%%--------------------------------------------------------------------
+client_echos_passive_chunk_big() ->
+ [{doc, "Server sends 50000 bytes to client in passive mode, that receives them, "
+ "sends them back, and closes."}].
+
+client_echos_passive_chunk_big(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+
%%--------------------------------------------------------------------
client_echos_active_once_big() ->
[{doc, "Server sends 50000 bytes to client in active once mode, that receives"
@@ -329,6 +399,20 @@ server_echos_passive_huge(Config) when is_list(Config) ->
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
+server_echos_passive_chunk_huge() ->
+ [{doc, "Client sends 500000 bytes to server in passive mode, that receives "
+ " them, sends them back, and closes."}].
+
+server_echos_passive_chunk_huge(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ server_echos_passive_chunk(
+ Data, 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."}].
@@ -369,7 +453,19 @@ client_echos_passive_huge(Config) when is_list(Config) ->
Data = binary:copy(<<"1234567890">>, 50000),
client_echos_passive(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+%%--------------------------------------------------------------------
+client_echos_passive_chunk_huge() ->
+ [{doc, "Server sends 500000 bytes to client in passive mode, that receives "
+ "them, sends them back, and closes."}].
+client_echos_passive_chunk_huge(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_once_huge() ->
[{doc, "Server sends 500000 bytes to client in active once mode, that receives "
@@ -442,6 +538,28 @@ server_echos_passive(
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+server_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, echoer_chunk, [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]}},
+ {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, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
@@ -513,6 +631,31 @@ client_echos_passive(
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, sender, [Data]}},
+ {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_chunk, [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, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
Length = byte_size(Data),
@@ -615,6 +758,10 @@ echoer(Socket, Size) ->
ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
echo_recv(Socket, Size * 100).
+echoer_chunk(Socket, Size) ->
+ ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ echo_recv_chunk(Socket, Size, Size * 100).
+
echoer_active_once(Socket, Size) ->
ct:log("Echoer active once: ~p~n", [ssl:getopts(Socket, [active])]),
echo_active_once(Socket, Size * 100).
@@ -632,6 +779,16 @@ echo_recv(Socket, Size) ->
ok = ssl:send(Socket, Data),
echo_recv(Socket, Size - byte_size(Data)).
+
+%% Receive Size bytes
+echo_recv_chunk(_Socket, _, 0) ->
+ ok;
+echo_recv_chunk(Socket, ChunkSize, Size) ->
+ {ok, Data} = ssl:recv(Socket, ChunkSize),
+ ok = ssl:send(Socket, Data),
+ echo_recv_chunk(Socket, ChunkSize, Size - ChunkSize).
+
+
%% Receive Size bytes
echo_active_once(_Socket, 0) ->
ok;
diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl
index 6f11e2bbe8..3c7f6ab20f 100644
--- a/lib/ssl/test/ssl_pem_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl
@@ -34,7 +34,10 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [pem_cleanup, invalid_insert].
+ [
+ pem_cleanup,
+ clear_pem_cache,
+ invalid_insert].
groups() ->
[].
@@ -110,6 +113,37 @@ pem_cleanup(Config)when is_list(Config) ->
ssl_test_lib:close(Client),
false = Size == Size1.
+clear_pem_cache() ->
+ [{doc,"Test that internal reference tabel is cleaned properly even when "
+ " the PEM cache is cleared" }].
+clear_pem_cache(Config) when is_list(Config) ->
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ [_,{FilRefDb, _} |_] = element(6, State),
+ {Server, Client} = basic_verify_test_no_close(Config),
+ CountReferencedFiles = fun({_, -1}, Acc) ->
+ Acc;
+ ({_, N}, Acc) ->
+ N + Acc
+ end,
+
+ 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
+ ssl:clear_pem_cache(),
+ _ = sys:get_status(whereis(ssl_manager)),
+ {Server1, Client1} = basic_verify_test_no_close(Config),
+ 4 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+ ct:sleep(2000),
+ _ = sys:get_status(whereis(ssl_manager)),
+ 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1),
+ ct:sleep(2000),
+ _ = sys:get_status(whereis(ssl_manager)),
+ 0 = ets:foldl(CountReferencedFiles, 0, FilRefDb).
+
invalid_insert() ->
[{doc, "Test that insert of invalid pem does not cause empty cache entry"}].
invalid_insert(Config)when is_list(Config) ->
@@ -163,3 +197,22 @@ later()->
Gregorian = calendar:datetime_to_gregorian_seconds(DateTime),
calendar:gregorian_seconds_to_datetime(Gregorian + (2 * ?CLEANUP_INTERVAL)).
+basic_verify_test_no_close(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ {Server, Client}.
diff --git a/lib/ssl/test/ssl_renegotiate_SUITE.erl b/lib/ssl/test/ssl_renegotiate_SUITE.erl
new file mode 100644
index 0000000000..ef3f9ebb52
--- /dev/null
+++ b/lib/ssl/test/ssl_renegotiate_SUITE.erl
@@ -0,0 +1,499 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_renegotiate_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(SLEEP, 500).
+-define(RENEGOTIATION_DISABLE_TIME, 12000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [{'dtlsv1.2', [], renegotiate_tests()},
+ {'dtlsv1', [], renegotiate_tests()},
+ {'tlsv1.3', [], renegotiate_tests()},
+ {'tlsv1.2', [], renegotiate_tests()},
+ {'tlsv1.1', [], renegotiate_tests()},
+ {'tlsv1', [], renegotiate_tests()},
+ {'sslv3', [], ssl3_renegotiate_tests()}
+ ].
+
+renegotiate_tests() ->
+ [client_renegotiate,
+ server_renegotiate,
+ client_secure_renegotiate,
+ client_secure_renegotiate_fallback,
+ client_renegotiate_reused_session,
+ server_renegotiate_reused_session,
+ client_no_wrap_sequence_number,
+ server_no_wrap_sequence_number,
+ renegotiate_dos_mitigate_active,
+ renegotiate_dos_mitigate_passive,
+ renegotiate_dos_mitigate_absolute].
+
+ssl3_renegotiate_tests() ->
+ [client_renegotiate,
+ server_renegotiate,
+ client_renegotiate_reused_session,
+ server_renegotiate_reused_session,
+ client_no_wrap_sequence_number,
+ server_no_wrap_sequence_number,
+ renegotiate_dos_mitigate_active,
+ renegotiate_dos_mitigate_passive,
+ renegotiate_dos_mitigate_absolute].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+client_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on client."}].
+client_renegotiate(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+client_secure_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on client."}].
+client_secure_renegotiate(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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, [{secure_renegotiate, 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,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false},
+ {secure_renegotiate, true}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+client_secure_renegotiate_fallback() ->
+ [{doc,"Test that we can set secure_renegotiate to false that is "
+ "fallback option, we however do not have a insecure server to test against!"}].
+client_secure_renegotiate_fallback(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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, [{secure_renegotiate, 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,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false},
+ {secure_renegotiate, false}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+server_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on server."}].
+server_renegotiate(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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,
+ renegotiate, [Data]}},
+ {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, erlang_ssl_receive, [Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+client_renegotiate_reused_session() ->
+ [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}].
+client_renegotiate_reused_session(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_reuse_session, [Data]}},
+ {options, [{reuse_sessions, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+server_renegotiate_reused_session() ->
+ [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}].
+server_renegotiate_reused_session(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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,
+ renegotiate_reuse_session, [Data]}},
+ {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, erlang_ssl_receive, [Data]}},
+ {options, [{reuse_sessions, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+client_no_wrap_sequence_number() ->
+ [{doc,"Test that erlang client will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+
+client_no_wrap_sequence_number(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to erlang",
+ N = 12,
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Version = ssl_test_lib:protocol_version(Config, tuple),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[ErlData, treashold(N, Version)]]}},
+ {options, [{reuse_sessions, false},
+ {renegotiate_at, N} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+server_no_wrap_sequence_number() ->
+ [{doc, "Test that erlang server will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+
+server_no_wrap_sequence_number(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+ N = 12,
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[Data, N+2]]}},
+ {options, [{renegotiate_at, N} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+renegotiate_dos_mitigate_active() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"}].
+renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {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,
+ renegotiate_immediately, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+renegotiate_dos_mitigate_passive() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"}].
+renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, 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,
+ renegotiate_immediately, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+renegotiate_dos_mitigate_absolute() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to initiate renegotiation"}].
+renegotiate_dos_mitigate_absolute(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{client_renegotiation, 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,
+ renegotiate_rejected,
+ []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+renegotiate(Socket, Data) ->
+ ct:log("Renegotiating ~n", []),
+ Result = ssl:renegotiate(Socket),
+ ct:log("Result ~p~n", [Result]),
+ ssl:send(Socket, Data),
+ case Result of
+ ok ->
+ ok;
+ Other ->
+ Other
+ end.
+
+renegotiate_reuse_session(Socket, Data) ->
+ %% Make sure session is registered
+ ct:sleep(?SLEEP),
+ renegotiate(Socket, Data).
+
+renegotiate_immediately(Socket) ->
+ _ = ssl_test_lib:active_recv(Socket, 11),
+ ok = ssl:renegotiate(Socket),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP),
+ ok = ssl:renegotiate(Socket),
+ ct:log("Renegotiated again"),
+ ssl:send(Socket, "Hello world"),
+ ok.
+
+renegotiate_rejected(Socket) ->
+ _ = ssl_test_lib:active_recv(Socket, 11),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ ct:log("Failed to renegotiate again"),
+ ssl:send(Socket, "Hello world"),
+ ok.
+
+%% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+treashold(N, {3,0}) ->
+ (N div 2) + 1;
+treashold(N, {3,1}) ->
+ (N div 2) + 1;
+treashold(N, _) ->
+ N + 1.
+
+erlang_ssl_receive(Socket, Data) ->
+ case ssl_test_lib:active_recv(Socket, length(Data)) of
+ Data ->
+ ok;
+ Other ->
+ ct:fail({{expected, Data}, {got, Other}})
+ end.
diff --git a/lib/ssl/test/ssl_rfc_5869_SUITE.erl b/lib/ssl/test/ssl_rfc_5869_SUITE.erl
new file mode 100644
index 0000000000..8b2d1c2082
--- /dev/null
+++ b/lib/ssl/test/ssl_rfc_5869_SUITE.erl
@@ -0,0 +1,316 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_rfc_5869_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [sha_256_basic,
+ sha_256_long,
+ sha_256_no_salt,
+ sha_basic,
+ sha_long,
+ sha_no_salt,
+ sha_default_salt
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+sha_256_basic() ->
+ [{doc, "Basic test case with SHA-256"}].
+sha_256_basic(Config) when is_list(Config) ->
+ %% Hash = SHA-256
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+ %% salt = 0x000102030405060708090a0b0c (13 octets)
+ %% info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
+ %% L = 42
+ %% PRK = 0x077709362c2e32df0ddc3f0dc47bba63
+ %% 90b6c73bb50f9c3122ec844ad7c2b3e5 (32 octets)
+ %% OKM = 0x3cb25f25faacd57a90434f64d0362f2a
+ %% 2d2d0a90cf1a5a4c5db02d56ecc4c5bf
+ %% 34007208d5b887185865 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = hexstr2bin("000102030405060708090a0b0c"),
+ Info = hexstr2bin("f0f1f2f3f4f5f6f7f8f9"),
+ PRK = hexstr2bin("077709362c2e32df0ddc3f0dc47bba63"
+ "90b6c73bb50f9c3122ec844ad7c2b3e5"),
+ OKM = hexstr2bin("3cb25f25faacd57a90434f64d0362f2a"
+ "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
+ "34007208d5b887185865"),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 42, OKM).
+
+sha_256_long() ->
+ [{doc, "Test with SHA-256 and longer inputs/outputs"}].
+sha_256_long(Config) when is_list(Config) ->
+ %% Hash = SHA-256
+ %% IKM = 0x000102030405060708090a0b0c0d0e0f
+ %% 101112131415161718191a1b1c1d1e1f
+ %% 202122232425262728292a2b2c2d2e2f
+ %% 303132333435363738393a3b3c3d3e3f
+ %% 404142434445464748494a4b4c4d4e4f (80 octets)
+ %% salt = 0x606162636465666768696a6b6c6d6e6f
+ %% 707172737475767778797a7b7c7d7e7f
+ %% 808182838485868788898a8b8c8d8e8f
+ %% 909192939495969798999a9b9c9d9e9f
+ %% a0a1a2a3a4a5a6a7a8a9aaabacadaeaf (80 octets)
+ %% info = 0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+ %% c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+ %% d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+ %% e0e1e2e3e4e5e6e7e8e9eaebecedeeef
+ %% f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff (80 octets)
+ %% L = 82
+
+ %% PRK = 0x06a6b88c5853361a06104c9ceb35b45c
+ %% ef760014904671014a193f40c15fc244 (32 octets)
+ %% OKM = 0xb11e398dc80327a1c8e7f78c596a4934
+ %% 4f012eda2d4efad8a050cc4c19afa97c
+ %% 59045a99cac7827271cb41c65e590e09
+ %% da3275600c2f09b8367793a9aca3db71
+ %% cc30c58179ec3e87c14c01d5c1f3434f
+ %% 1d87 (82 octets)
+ IKM = hexstr2bin("000102030405060708090a0b0c0d0e0f"
+ "101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f"
+ "303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f"
+ ),
+ Salt = hexstr2bin("606162636465666768696a6b6c6d6e6f"
+ "707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+ ),
+ Info = hexstr2bin("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
+ ),
+ PRK = hexstr2bin("06a6b88c5853361a06104c9ceb35b45c"
+ "ef760014904671014a193f40c15fc244"),
+ OKM = hexstr2bin("b11e398dc80327a1c8e7f78c596a4934"
+ "4f012eda2d4efad8a050cc4c19afa97c"
+ "59045a99cac7827271cb41c65e590e09"
+ "da3275600c2f09b8367793a9aca3db71"
+ "cc30c58179ec3e87c14c01d5c1f3434f"
+ "1d87"
+ ),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 82, OKM).
+sha_256_no_salt() ->
+ [{doc, "Test with SHA-256 and zero-length salt/info"}].
+sha_256_no_salt(Config) when is_list(Config) ->
+ %% Hash = SHA-256
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+ %% salt = (0 octets)
+ %% info = (0 octets)
+ %% L = 42
+
+ %% PRK = 0x19ef24a32c717b167f33a91d6f648bdf
+ %% 96596776afdb6377ac434c1c293ccb04 (32 octets)
+ %% OKM = 0x8da4e775a563c18f715f802a063c5a31
+ %% b8a11f5c5ee1879ec3454e5f3c738d2d
+ %% 9d201395faa4b61a96c8 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = <<>>,
+ Info = <<>>,
+ PRK = hexstr2bin("19ef24a32c717b167f33a91d6f648bdf"
+ "96596776afdb6377ac434c1c293ccb04"),
+ OKM = hexstr2bin("8da4e775a563c18f715f802a063c5a31"
+ "b8a11f5c5ee1879ec3454e5f3c738d2d"
+ "9d201395faa4b61a96c8"),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 42, OKM).
+
+sha_basic() ->
+ [{doc, " Basic test case with SHA-1"}].
+sha_basic(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b (11 octets)
+ %% salt = 0x000102030405060708090a0b0c (13 octets)
+ %% info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
+ %% L = 42
+
+ %% PRK = 0x9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243 (20 octets)
+ %% OKM = 0x085a01ea1b10f36933068b56efa5ad81
+ %% a4f14b822f5b091568a9cdd4f155fda2
+ %% c22e422478d305f3f896 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = hexstr2bin("000102030405060708090a0b0c"),
+ Info = hexstr2bin("f0f1f2f3f4f5f6f7f8f9"),
+ PRK = hexstr2bin("077709362c2e32df0ddc3f0dc47bba63"
+ "90b6c73bb50f9c3122ec844ad7c2b3e5"),
+ OKM = hexstr2bin("3cb25f25faacd57a90434f64d0362f2a"
+ "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
+ "34007208d5b887185865"),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 42, OKM).
+
+sha_long() ->
+ [{doc, "Test with SHA-1 and longer inputs/outputs"}].
+sha_long(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x000102030405060708090a0b0c0d0e0f
+ %% 101112131415161718191a1b1c1d1e1f
+ %% 202122232425262728292a2b2c2d2e2f
+ %% 303132333435363738393a3b3c3d3e3f
+ %% 404142434445464748494a4b4c4d4e4f (80 octets)
+ %% salt = 0x606162636465666768696a6b6c6d6e6f
+ %% 707172737475767778797a7b7c7d7e7f
+ %% 808182838485868788898a8b8c8d8e8f
+ %% 909192939495969798999a9b9c9d9e9f
+ %% a0a1a2a3a4a5a6a7a8a9aaabacadaeaf (80 octets)
+ %% info = 0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+ %% c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+ %% d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+ %% e0e1e2e3e4e5e6e7e8e9eaebecedeeef
+ %% f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff (80 octets)
+ %% L = 82
+
+ %% PRK = 0x8adae09a2a307059478d309b26c4115a224cfaf6 (20 octets)
+ %% OKM = 0x0bd770a74d1160f7c9f12cd5912a06eb
+ %% ff6adcae899d92191fe4305673ba2ffe
+ %% 8fa3f1a4e5ad79f3f334b3b202b2173c
+ %% 486ea37ce3d397ed034c7f9dfeb15c5e
+ %% 927336d0441f4c4300e2cff0d0900b52
+ %% d3b4 (82 octets)
+ IKM = hexstr2bin("000102030405060708090a0b0c0d0e0f"
+ "101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f"
+ "303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f"
+ ),
+ Salt = hexstr2bin("606162636465666768696a6b6c6d6e6f"
+ "707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+ ),
+ Info = hexstr2bin("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
+ ),
+ PRK = hexstr2bin("8adae09a2a307059478d309b26c4115a224cfaf6"),
+ OKM = hexstr2bin("0bd770a74d1160f7c9f12cd5912a06eb"
+ "ff6adcae899d92191fe4305673ba2ffe"
+ "8fa3f1a4e5ad79f3f334b3b202b2173c"
+ "486ea37ce3d397ed034c7f9dfeb15c5e"
+ "927336d0441f4c4300e2cff0d0900b52"
+ "d3b4"
+ ),
+ hkdf_test(sha, Salt, IKM, PRK, Info, 82, OKM).
+
+sha_no_salt() ->
+ [{doc, "Test with SHA-1 and zero-length salt/info"}].
+sha_no_salt(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+ %% salt = (0 octets)
+ %% info = (0 octets)
+ %% L = 42
+
+ %% PRK = 0xda8c8a73c7fa77288ec6f5e7c297786aa0d32d01 (20 octets)
+ %% OKM = 0x0ac1af7002b3d761d1e55298da9d0506
+ %% b9ae52057220a306e07b6b87e8df21d0
+ %% ea00033de03984d34918 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = <<>>,
+ Info = <<>>,
+ PRK = hexstr2bin("da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"),
+ OKM = hexstr2bin("0ac1af7002b3d761d1e55298da9d0506"
+ "b9ae52057220a306e07b6b87e8df21d0"
+ "ea00033de03984d34918"),
+ hkdf_test(sha, Salt, IKM, PRK, Info, 42, OKM).
+
+
+sha_default_salt() ->
+ [{doc, "Test with SHA-1, salt not provided (defaults to HashLen zero octets),
+ zero-length info"}].
+sha_default_salt(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c (22 octets)
+ %% salt = not provided (defaults to HashLen zero octets)
+ %% info = (0 octets)
+ %% L = 42
+
+ %% PRK = 0x2adccada18779e7c2077ad2eb19d3f3e731385dd (20 octets)
+ %% OKM = 0x2c91117204d745f3500d636a62f64f0a
+ %% b3bae548aa53d423b0d1f27ebba6f5e5
+ %% 673a081d70cce7acfc48 (42 octets)
+ IKM = hexstr2bin("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"),
+ Salt = binary:copy(<<0>>, 20),
+ Info = <<>>,
+ PRK = hexstr2bin("2adccada18779e7c2077ad2eb19d3f3e731385dd"),
+ OKM = hexstr2bin("2c91117204d745f3500d636a62f64f0a"
+ "b3bae548aa53d423b0d1f27ebba6f5e5"
+ "673a081d70cce7acfc48"),
+ hkdf_test(sha, Salt, IKM, PRK, Info, 42, OKM).
+
+hkdf_test(HashAlg, Salt, KeyingMaterial, PsedoRandKey, ContextInfo, Length, Key) ->
+ PsedoRandKey = tls_v1:hkdf_extract(HashAlg, Salt, KeyingMaterial),
+ Key = tls_v1:hkdf_expand(PsedoRandKey, ContextInfo, Length, HashAlg).
+
+hexstr2bin(S) when is_binary(S) ->
+ list_to_binary(hexstr2list(binary_to_list(S)));
+hexstr2bin(S) ->
+ list_to_binary(hexstr2list(S)).
+
+hexstr2list([$ |T]) ->
+ hexstr2list(T);
+hexstr2list([X,Y|T]) ->
+ [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
+hexstr2list([]) ->
+ [].
+mkint(C) when $0 =< C, C =< $9 ->
+ C - $0;
+mkint(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+mkint(C) when $a =< C, C =< $f ->
+ C - $a + 10.
diff --git a/lib/ssl/test/ssl_session_SUITE.erl b/lib/ssl/test/ssl_session_SUITE.erl
new file mode 100644
index 0000000000..aa79698a72
--- /dev/null
+++ b/lib/ssl/test/ssl_session_SUITE.erl
@@ -0,0 +1,377 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_session_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("tls_handshake.hrl").
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(SLEEP, 500).
+-define(EXPIRE, 10).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [{'dtlsv1.2', [], session_tests()},
+ {'dtlsv1', [], session_tests()},
+ {'tlsv1.3', [], session_tests()},
+ {'tlsv1.2', [], session_tests()},
+ {'tlsv1.1', [], session_tests()},
+ {'tlsv1', [], session_tests()},
+ {'sslv3', [], session_tests()}
+ ].
+
+session_tests() ->
+ [reuse_session,
+ reuse_session_expired,
+ server_does_not_want_to_reuse_session,
+ no_reuses_session_server_restart_new_cert,
+ no_reuses_session_server_restart_new_cert_file].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ ssl_test_lib:make_dsa_cert(Config)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(reuse_session_expired, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ ssl_test_lib:clean_env(),
+ application:set_env(ssl, session_lifetime, ?EXPIRE),
+ application:set_env(ssl, session_delay_cleanup_time, 500),
+ ssl:start(),
+ ct:timetrap({seconds, 30}),
+ Config;
+init_per_testcase(_, Config) ->
+ ct:timetrap({seconds, 15}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+reuse_session() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
+reuse_session(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+
+ ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+reuse_session_expired() ->
+ [{doc,"Test sessions is not reused when it has expired"}].
+reuse_session_expired(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server0 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {tcp_options, [{active, false}]},
+ {options, ServerOpts}]),
+ Port0 = ssl_test_lib:inet_port(Server0),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
+ Server0 ! listen,
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+
+ SID = receive
+ {Client0, Id0} ->
+ Id0
+ end,
+
+ receive
+ {Client1, SID} ->
+ ok
+ after ?SLEEP ->
+ ct:fail(session_not_reused)
+ end,
+
+ Server0 ! listen,
+
+ %% Make sure session is unregistered due to expiration
+ ct:sleep((?EXPIRE*2)),
+
+ make_sure_expired(Hostname, Port0, SID),
+
+ Client2 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client2, SID} ->
+ ct:fail(session_reused_when_session_expired);
+ {Client2, _} ->
+ ok
+ end,
+ process_flag(trap_exit, false),
+ ssl_test_lib:close(Server0),
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Client1),
+ ssl_test_lib:close(Client2).
+
+make_sure_expired(Host, Port, Id) ->
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ ClientCache = element(2, State),
+
+ case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of
+ undefined ->
+ ok;
+ #session{is_resumable = false} ->
+ ok;
+ _ ->
+ ct:sleep(?SLEEP),
+ make_sure_expired(Host, Port, Id)
+ end.
+
+%%--------------------------------------------------------------------
+server_does_not_want_to_reuse_session() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
+server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {options, [{reuse_session, fun(_,_,_,_) ->
+ false
+ end} |
+ ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ %% Make sure session is registered
+ ct:sleep(?SLEEP),
+
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ ct:fail(session_reused_when_server_does_not_want_to);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client1).
+
+no_reuses_session_server_restart_new_cert() ->
+ [{doc,"Check that a session is not reused if the server is restarted with a new cert."}].
+no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
+
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
+ DsaClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ %% Make sure session is registered
+ ct:sleep(?SLEEP),
+ Monitor = erlang:monitor(process, Server),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client0),
+ receive
+ {'DOWN', Monitor, _, _, _} ->
+ ok
+ end,
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{reuseaddr, true} | DsaServerOpts]}]),
+
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {from, self()}, {options, DsaClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ ct:fail(session_reused_when_server_has_new_cert);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+no_reuses_session_server_restart_new_cert_file() ->
+ [{doc,"Check that a session is not reused if a server is restarted with a new "
+ "cert contained in a file with the same name as the old cert."}].
+
+no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+
+ NewServerOpts0 = ssl_test_lib:new_config(PrivDir, ServerOpts),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {options, NewServerOpts0}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ %% Make sure session is registered and we get
+ %% new file time stamp when calling new_config!
+ ct:sleep(?SLEEP* 2),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client0),
+
+ ssl:clear_pem_cache(),
+
+ NewServerOpts1 = ssl_test_lib:new_config(PrivDir, DsaServerOpts),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{reuseaddr, true} | NewServerOpts1]}]),
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ ct:fail(session_reused_when_server_has_new_cert);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 7f33fe3204..b71b15b028 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -186,7 +186,7 @@ session_cleanup() ->
session_cleanup(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 7629d75100..e68ea2c99d 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -36,7 +36,6 @@ all() ->
[{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
- {group, 'sslv3'},
{group, 'dtlsv1.2'},
{group, 'dtlsv1'}
].
@@ -46,7 +45,6 @@ groups() ->
{'tlsv1.2', [], sni_tests()},
{'tlsv1.1', [], sni_tests()},
{'tlsv1', [], sni_tests()},
- {'sslv3', [], sni_tests()},
{'dtlsv1.2', [], sni_tests()},
{'dtlsv1', [], sni_tests()}
].
@@ -61,7 +59,8 @@ sni_tests() ->
dns_name,
ip_fallback,
no_ip_fallback,
- dns_name_reuse].
+ dns_name_reuse,
+ customize_hostname_check].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -88,12 +87,10 @@ end_per_suite(_) ->
ssl:stop(),
application:stop(crypto).
-init_per_testcase(TestCase, Config) when TestCase == ip_fallback;
- TestCase == no_ip_fallback;
- TestCase == dns_name_reuse ->
+init_per_testcase(customize_hostname_check, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
- ct:timetrap({seconds, 20}),
+ ssl_test_lib:clean_start(),
+ ct:timetrap({seconds, 5}),
Config;
init_per_testcase(_TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
@@ -236,7 +233,60 @@ dns_name_reuse(Config) ->
{mfa, {ssl_test_lib, session_info_result, []}},
{from, self()}, {options, [{verify, verify_peer} | ClientConf]}]),
- ssl_test_lib:check_client_alert(Client1, handshake_failure).
+ ssl_test_lib:check_client_alert(Client1, handshake_failure),
+ ssl_test_lib:close(Client0).
+
+
+customize_hostname_check() ->
+ [{doc,"Test option customize_hostname_check."}].
+customize_hostname_check(Config) when is_list(Config) ->
+ Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, "*.example.org"}],
+ critical = false}
+ ],
+ #{server_config := ServerOpts0,
+ client_config := ClientOpts0} = ssl_test_lib:make_cert_chains_pem(rsa, [{server_chain,
+ [[],
+ [],
+ [{extensions, Ext}]
+ ]}],
+ Config, "https_hostname_convention"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CustomFun = public_key:pkix_verify_hostname_match_fun(https),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{verify, verify_peer},
+ {server_name_indication, "other.example.org"},
+ {customize_hostname_check,
+ [{match_fun, CustomFun}]} | ClientOpts]
+ }]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{verify, verify_peer},
+ {server_name_indication, "other.example.org"} | ClientOpts]}
+ ]),
+ ssl_test_lib:check_client_alert(Server, Client1, handshake_failure).
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
diff --git a/lib/ssl/test/ssl_socket_SUITE.erl b/lib/ssl/test/ssl_socket_SUITE.erl
new file mode 100644
index 0000000000..d648f2f9e1
--- /dev/null
+++ b/lib/ssl/test/ssl_socket_SUITE.erl
@@ -0,0 +1,437 @@
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_socket_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(SLEEP, 500).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, tls},
+ {group, dtls}
+ ].
+
+groups() ->
+ [
+ {tls,[], socket_tests() ++ raw_inet_opt()},
+ {dtls,[], socket_tests()}
+ ].
+
+socket_tests() ->
+ [
+ getstat,
+ socket_options,
+ invalid_inet_get_option,
+ invalid_inet_get_option_not_list,
+ invalid_inet_get_option_improper_list,
+ invalid_inet_set_option,
+ invalid_inet_set_option_not_list,
+ invalid_inet_set_option_improper_list
+ ].
+
+raw_inet_opt() ->
+ [
+ raw_inet_option
+ ].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(dtls, Config) ->
+ [{protocol_opts, [{protocol, dtls}]} | proplists:delete(protocol_opts, Config)];
+init_per_group(tls, Config) ->
+ [{protocol_opts, [{protocol, tls}]} | proplists:delete(protocol_opts, Config)];
+init_per_group(_GroupName, Config) ->
+ [{client_type, erlang},
+ {server_type, erlang} | Config].
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(raw_inet_option, Config) ->
+ ct:timetrap({seconds, 5}),
+ case os:type() of
+ {unix,linux} ->
+ Config;
+ _ ->
+ {skip, "Raw options are platform-specific"}
+ end;
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+getstat() ->
+ [{doc,"Test API function getstat/2"}].
+
+getstat(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_rsa_opts, Config),
+ ServerOpts = ?config(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port1 = ssl_test_lib:inet_port(Server1),
+ Server2 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port2 = ssl_test_lib:inet_port(Server2),
+ {ok, ActiveC} = rpc:call(ClientNode, ssl, connect,
+ [Hostname,Port1,[{active, once}|ClientOpts]]),
+ {ok, PassiveC} = rpc:call(ClientNode, ssl, connect,
+ [Hostname,Port2,[{active, false}|ClientOpts]]),
+
+ ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n",
+ [self(), self(), Server1, Server2]),
+
+ %% We only check that the values are non-zero initially
+ %% (due to the handshake), and that sending more changes the values.
+
+ %% Passive socket.
+
+ {ok, InitialStats} = ssl:getstat(PassiveC),
+ ct:pal("InitialStats ~p~n", [InitialStats]),
+ [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats)
+ || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
+
+ ok = ssl:send(PassiveC, "Hello world"),
+ wait_for_send(PassiveC),
+ {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]),
+ ct:pal("SStats ~p~n", [SStats]),
+ [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats)
+ || Name <- [send_cnt, send_oct]]),
+
+ %% Active socket.
+
+ {ok, InitialAStats} = ssl:getstat(ActiveC),
+ ct:pal("InitialAStats ~p~n", [InitialAStats]),
+ [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats)
+ || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
+
+ _ = receive
+ {ssl, ActiveC, _} ->
+ ok
+ after
+ ?SLEEP ->
+ exit(timeout)
+ end,
+
+ ok = ssl:send(ActiveC, "Hello world"),
+ wait_for_send(ActiveC),
+ {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]),
+ ct:pal("ASStats ~p~n", [ASStats]),
+ [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats)
+ || Name <- [send_cnt, send_oct]]),
+
+ ok.
+%%--------------------------------------------------------------------
+socket_options() ->
+ [{doc,"Test API function getopts/2 and setopts/2"}].
+
+socket_options(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Values = [{mode, list}, {active, true}],
+ %% Shall be the reverse order of Values!
+ Options = [active, 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),
+
+ {ok, Listen} = ssl:listen(0, ServerOpts),
+ {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
+ ok = ssl:setopts(Listen, [{mode, binary}]),
+ {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
+ {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
+ ssl:close(Listen).
+
+%%--------------------------------------------------------------------
+raw_inet_option() ->
+ [{doc,"Ensure that a single 'raw' option is passed to ssl:listen correctly."}].
+
+raw_inet_option(Config) when is_list(Config) ->
+ % 'raw' option values are platform-specific; these are the Linux values:
+ IpProtoTcp = 6,
+ % Use TCP_KEEPIDLE, because (e.g.) TCP_MAXSEG can't be read back reliably.
+ TcpKeepIdle = 4,
+ KeepAliveTimeSecs = 55,
+ LOptions = [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}],
+ {ok, LSocket} = ssl:listen(0, LOptions),
+ % Per http://www.erlang.org/doc/man/inet.html#getopts-2, we have to specify
+ % exactly which raw option we want, and the size of the buffer.
+ {ok, [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}]} =
+ ssl:getopts(LSocket, [{raw, IpProtoTcp, TcpKeepIdle, 4}]).
+
+%%--------------------------------------------------------------------
+
+invalid_inet_get_option() ->
+ [{doc,"Test handling of invalid inet options in getopts"}].
+
+invalid_inet_get_option(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, get_invalid_inet_option, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_get_option_not_list() ->
+ [{doc,"Test handling of invalid type in getopts"}].
+
+invalid_inet_get_option_not_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, get_invalid_inet_option_not_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_get_option_improper_list() ->
+ [{doc,"Test handling of invalid type in getopts"}].
+
+invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, get_invalid_inet_option_improper_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option() ->
+ [{doc,"Test handling of invalid inet options in setopts"}].
+
+invalid_inet_set_option(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, set_invalid_inet_option, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option_not_list() ->
+ [{doc,"Test handling of invalid type in setopts"}].
+
+invalid_inet_set_option_not_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, set_invalid_inet_option_not_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option_improper_list() ->
+ [{doc,"Test handling of invalid tye in setopts"}].
+
+invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, set_invalid_inet_option_improper_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+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,[{reuseaddr, _}]} = ssl:getopts(Socket, [reuseaddr]),
+ {ok, All} = ssl:getopts(Socket, []),
+ ct:log("All opts ~p~n", [All]),
+ ok.
+
+get_invalid_inet_option(Socket) ->
+ {error, {options, {socket_options, foo, _}}} = ssl:getopts(Socket, [foo]),
+ ok.
+
+get_invalid_inet_option_not_list(Socket) ->
+ {error, {options, {socket_options, some_invalid_atom_here}}}
+ = ssl:getopts(Socket, some_invalid_atom_here),
+ ok.
+
+get_invalid_inet_option_improper_list(Socket) ->
+ {error, {options, {socket_options, foo,_}}} = ssl:getopts(Socket, [packet | foo]),
+ ok.
+
+set_invalid_inet_option(Socket) ->
+ {error, {options, {socket_options, {packet, foo}}}} = ssl:setopts(Socket, [{packet, foo}]),
+ {error, {options, {socket_options, {header, foo}}}} = ssl:setopts(Socket, [{header, foo}]),
+ {error, {options, {socket_options, {active, foo}}}} = ssl:setopts(Socket, [{active, foo}]),
+ {error, {options, {socket_options, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]),
+ ok.
+
+set_invalid_inet_option_not_list(Socket) ->
+ {error, {options, {not_a_proplist, some_invalid_atom_here}}}
+ = ssl:setopts(Socket, some_invalid_atom_here),
+ ok.
+
+set_invalid_inet_option_improper_list(Socket) ->
+ {error, {options, {not_a_proplist, [{packet, 0} | {foo, 2}]}}} =
+ ssl:setopts(Socket, [{packet, 0} | {foo, 2}]),
+ ok.
+
+wait_for_send(Socket) ->
+ %% Make sure TLS process processed send message event
+ _ = ssl:connection_information(Socket).
+
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index c3e64e62d6..7dd27fb5cb 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -45,26 +45,35 @@ run_where(_, ipv6) ->
Host = rpc:call(ServerNode, net_adm, localhost, []),
{ClientNode, ServerNode, Host}.
-node_to_hostip(Node) ->
+node_to_hostip(Node, Role) ->
[_ , Host] = string:tokens(atom_to_list(Node), "@"),
{ok, Address} = inet:getaddr(Host, inet),
+ %% Convert client addresses in 127.0.0.0/24 subnet to the atom 'localhost'.
+ %% This is a workaround for testcase problems caused by the fact that
+ %% inet:peername/1 and inet:getaddr/2 return different addresses when
+ %% running on localhost.
+ normalize_loopback(Address, Role).
+
+normalize_loopback({127,_,_,_}, client) ->
+ localhost;
+normalize_loopback(Address, _) ->
Address.
start_server(Args) ->
- Result = spawn_link(?MODULE, run_server, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_server, [Args]),
receive
{listen, up} ->
Result
end.
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),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
run_server(ListenSocket, Opts).
@@ -90,13 +99,12 @@ do_run_server(_, ok = Result, Opts) ->
Pid = proplists:get_value(from, Opts),
Pid ! {self(), Result};
do_run_server(ListenSocket, AcceptSocket, Opts) ->
- Node = proplists:get_value(node, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nServer: apply(~p,~p,~p)~n",
[?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
- case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
+ case apply(Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -110,8 +118,8 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
ct:log("~p:~p~nServer closing ~p ~n", [?MODULE,?LINE, self()]),
- Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
- Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
+ Result = Transport:close(AcceptSocket),
+ Result1 = Transport:close(ListenSocket),
ct:log("~p:~p~nResult ~p : ~p ~n", [?MODULE,?LINE, Result, Result1]);
{ssl_closed, _} ->
ok
@@ -132,41 +140,38 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
remove_close_msg(ReconnectTimes),
AcceptSocket
end;
-connect(ListenSocket, Opts) ->
- Node = proplists:get_value(node, Opts),
+connect(ListenSocket, _Opts) ->
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
AcceptSocket.
connect(_, _, 0, AcceptSocket, _, _, _) ->
AcceptSocket;
connect(ListenSocket, Node, _N, _, Timeout, SslOpts, cancel) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]),
- case rpc:call(Node, ssl, handshake, [AcceptSocket, SslOpts, Timeout]) of
+ case ssl:handshake(AcceptSocket, SslOpts, Timeout) of
{ok, Socket0, Ext} ->
ct:log("Ext ~p:~n", [Ext]),
ct:log("~p:~p~nssl:handshake_cancel(~p)~n", [?MODULE,?LINE, Socket0]),
- rpc:call(Node, ssl, handshake_cancel, [Socket0]);
+ ssl:handshake_cancel(Socket0);
Result ->
ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
end;
connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]),
- case rpc:call(Node, ssl, handshake, [AcceptSocket, SslOpts, Timeout]) of
+ case ssl:handshake(AcceptSocket, SslOpts, Timeout) of
{ok, Socket0, Ext} ->
+ [_|_] = maps:get(sni, Ext),
ct:log("Ext ~p:~n", [Ext]),
ct:log("~p:~p~nssl:handshake_continue(~p,~p,~p)~n", [?MODULE,?LINE, Socket0, ContOpts,Timeout]),
- case rpc:call(Node, ssl, handshake_continue, [Socket0, ContOpts, Timeout]) of
+ case ssl:handshake_continue(Socket0, ContOpts, Timeout) of
{ok, Socket} ->
connect(ListenSocket, Node, N-1, Socket, Timeout, SslOpts, ContOpts);
Error ->
@@ -179,71 +184,144 @@ connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) ->
end;
connect(ListenSocket, Node, N, _, Timeout, [], ContOpts) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n", [?MODULE,?LINE, AcceptSocket, Timeout]),
- case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
- ok ->
- connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, [], ContOpts);
+ case ssl:handshake(AcceptSocket, Timeout) of
+ {ok, Socket} ->
+ connect(ListenSocket, Node, N-1, Socket, Timeout, [], ContOpts);
Result ->
- ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
+ ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
end;
-connect(ListenSocket, Node, _, _, Timeout, Opts, _) ->
+connect(ListenSocket, _Node, _, _, Timeout, Opts, _) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
- ct:log("ssl:ssl_accept(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
- rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Opts, Timeout]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ct:log("ssl:handshake(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
+ ssl:handshake(AcceptSocket, Opts, Timeout),
AcceptSocket.
start_server_transport_abuse_socket(Args) ->
- Result = spawn_link(?MODULE, transport_accept_abuse, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, transport_accept_abuse, [Args]),
receive
{listen, up} ->
Result
end.
start_server_transport_control(Args) ->
- Result = spawn_link(?MODULE, transport_switch_control, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, transport_switch_control, [Args]),
receive
{listen, up} ->
Result
end.
+start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ClientOpts = ErlangClientOpts ++ ClientOpts0,
+
+ {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),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = case OpensslServerOpts of
+ [] ->
+ ["s_server", "-accept",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile,"-key", KeyFile];
+ [Opt, Value] ->
+ ["s_server", Opt, Value, "-accept",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile,"-key", KeyFile]
+ end,
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ active_recv, [length(Data)]}},
+ {options, ClientOpts}]),
+
+ Callback(Client, OpensslPort),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
transport_accept_abuse(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),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
- {error, _} = rpc:call(Node, ssl, connection_information, [AcceptSocket]),
- _ = rpc:call(Node, ssl, handshake, [AcceptSocket, infinity]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ {error, _} = ssl:connection_information(AcceptSocket),
+ _ = ssl:handshake(AcceptSocket, infinity),
Pid ! {self(), ok}.
+start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = ErlangServerOpts ++ ServerOpts0,
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, active_recv, [length(Data)]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client"] ++ OpenSSLClientOpts ++ ["-msg", "-connect",
+ hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version)],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
transport_switch_control(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),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
- ok = rpc:call(Node, ssl, controlling_process, [AcceptSocket, self()]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ok = ssl:controlling_process(AcceptSocket, self()),
Pid ! {self(), ok}.
@@ -256,7 +334,8 @@ remove_close_msg(ReconnectTimes) ->
end.
start_client(Args) ->
- Result = spawn_link(?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
receive
{connected, Socket} ->
case lists:member(return_socket, Args) of
@@ -288,8 +367,8 @@ run_client(Opts) ->
client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts)
end.
-client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
- case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
+client_loop(_Node, Host, Port, Pid, Transport, Options, Opts) ->
+ case Transport:connect(Host, Port, Options) of
{ok, Socket} ->
Pid ! {connected, Socket},
ct:log("~p:~p~nClient: connected~n", [?MODULE,?LINE]),
@@ -299,7 +378,7 @@ client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
[?MODULE,?LINE, Module, Function, [Socket | Args]]),
- case rpc:call(Node, Module, Function, [Socket | Args]) of
+ case apply(Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -309,7 +388,7 @@ client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
receive
close ->
ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
- rpc:call(Node, Transport, close, [Socket]);
+ Transport:close(Socket);
{ssl_closed, Socket} ->
ok;
{gen_tcp, closed} ->
@@ -339,16 +418,13 @@ client_loop(Node, Host, Port, Pid, Transport, Options, Opts) ->
end;
{error, Reason} ->
ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
- Pid ! {connect_failed, Reason};
- {badrpc,BadRPC} ->
- ct:log("~p:~p~nBad rpc: ~p",[?MODULE,?LINE, BadRPC]),
- Pid ! {connect_failed, {badrpc,BadRPC}}
+ Pid ! {connect_failed, Reason}
end.
-client_cont_loop(Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
- case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
+client_cont_loop(_Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
+ case Transport:connect(Host, Port, Options) of
{ok, Socket, _} ->
- Result = rpc:call(Node, Transport, handshake_cancel, [Socket]),
+ Result = Transport:handshake_cancel(Socket),
ct:log("~p:~p~nClient: Cancel: ~p ~n", [?MODULE,?LINE, Result]),
Pid ! {connect_failed, Result};
{error, Reason} ->
@@ -356,17 +432,17 @@ client_cont_loop(Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
Pid ! {connect_failed, Reason}
end;
-client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) ->
- case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
+client_cont_loop(_Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) ->
+ case Transport:connect(Host, Port, Options) of
{ok, Socket0, _} ->
ct:log("~p:~p~nClient: handshake_continue(~p, ~p, infinity) ~n", [?MODULE, ?LINE, Socket0, ContOpts]),
- case rpc:call(Node, Transport, handshake_continue, [Socket0, ContOpts]) of
+ case Transport:handshake_continue(Socket0, ContOpts) of
{ok, Socket} ->
Pid ! {connected, Socket},
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
[?MODULE,?LINE, Module, Function, [Socket | Args]]),
- case rpc:call(Node, Module, Function, [Socket | Args]) of
+ case apply(Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -403,14 +479,16 @@ close(Pid, Timeout) ->
exit(Pid, kill)
end.
-check_result(Server, ServerMsg, Client, ClientMsg) ->
+check_result(Server, ServerMsg, Client, ClientMsg) ->
+ {ClientIP, ClientPort} = get_ip_port(ServerMsg),
receive
{Server, ServerMsg} ->
check_result(Client, ClientMsg);
-
+ %% Workaround to accept local addresses (127.0.0.0/24)
+ {Server, {ok, {{127,_,_,_}, ClientPort}}} when ClientIP =:= localhost ->
+ check_result(Client, ClientMsg);
{Client, ClientMsg} ->
check_result(Server, ServerMsg);
-
{Port, {data,Debug}} when is_port(Port) ->
ct:log("~p:~p~n Openssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Server, ServerMsg, Client, ClientMsg);
@@ -423,10 +501,14 @@ check_result(Server, ServerMsg, Client, ClientMsg) ->
ct:fail(Reason)
end.
-check_result(Pid, Msg) ->
+check_result(Pid, Msg) ->
+ {ClientIP, ClientPort} = get_ip_port(Msg),
receive
{Pid, Msg} ->
ok;
+ %% Workaround to accept local addresses (127.0.0.0/24)
+ {Pid, {ok, {{127,_,_,_}, ClientPort}}} when ClientIP =:= localhost ->
+ ok;
{Port, {data,Debug}} when is_port(Port) ->
ct:log("~p:~p~n Openssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Pid,Msg);
@@ -438,37 +520,63 @@ check_result(Pid, Msg) ->
{got, Unexpected}},
ct:fail(Reason)
end.
+
+
+get_ip_port({ok,{ClientIP, ClientPort}}) ->
+ {ClientIP, ClientPort};
+get_ip_port(_) ->
+ {undefined, undefined}.
+
+
check_server_alert(Pid, Alert) ->
receive
- {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ {Pid, {error, {tls_alert, {Alert, STxt}}}} ->
+ check_server_txt(STxt),
+ ok;
+ {Pid, {error, closed}} ->
ok
end.
check_server_alert(Server, Client, Alert) ->
receive
- {Server, {error, {tls_alert, {Alert, _}}}} ->
- receive
- {Client, {error, {tls_alert, {Alert, _}}}} ->
- ok;
- {Client, {error, closed}} ->
- ok
- end
+ {Server, {error, {tls_alert, {Alert, STxt}}}} ->
+ check_server_txt(STxt),
+ check_client_alert(Client, Alert)
end.
check_client_alert(Pid, Alert) ->
receive
- {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ {Pid, {error, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Pid, {ssl_error, _, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Pid, {error, closed}} ->
ok
end.
check_client_alert(Server, Client, Alert) ->
receive
- {Client, {error, {tls_alert, {Alert, _}}}} ->
- receive
- {Server, {error, {tls_alert, {Alert, _}}}} ->
- ok;
- {Server, {error, closed}} ->
- ok
- end
+ {Client, {error, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ check_server_alert(Server, Alert);
+ {Client, {ssl_error, _, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Client, {error, closed}} ->
+ ok
end.
+check_server_txt("TLS server" ++ _) ->
+ ok;
+check_server_txt("DTLS server" ++ _) ->
+ ok;
+check_server_txt(Txt) ->
+ ct:fail({expected_server, {got, Txt}}).
+check_client_txt("TLS client" ++ _) ->
+ ok;
+check_client_txt("DTLS client" ++ _) ->
+ ok;
+check_client_txt(Txt) ->
+ ct:fail({expected_server, {got, Txt}}).
wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
receive
@@ -514,13 +622,6 @@ wait_for_result(Pid, Msg) ->
%% Unexpected
end.
-user_lookup(psk, _Identity, UserState) ->
- {ok, UserState};
-user_lookup(srp, Username, _UserState) ->
- Salt = ssl_cipher:random_bytes(16),
- UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
- {ok, {srp_1024, Salt, UserPassHash}}.
-
cert_options(Config) ->
ClientCaCertFile = filename:join([proplists:get_value(priv_dir, Config),
"client", "cacerts.pem"]),
@@ -547,8 +648,7 @@ cert_options(Config) ->
"badcert.pem"]),
BadKeyFile = filename:join([proplists:get_value(priv_dir, Config),
"badkey.pem"]),
- PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
-
+
[{client_opts, [{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile},
{keyfile, ClientKeyFile}]},
@@ -562,30 +662,6 @@ cert_options(Config) ->
{ssl_imp, new}]},
{server_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
- {client_psk, [{ssl_imp, new},
- {psk_identity, "Test-User"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk, [{ssl_imp, new},{reuseaddr, true},
- {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk_hint, [{ssl_imp, new},{reuseaddr, true},
- {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
- {psk_identity, "HINT"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk_anon, [{ssl_imp, new},{reuseaddr, true},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true},
- {psk_identity, "HINT"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {client_srp, [{ssl_imp, new},
- {srp_identity, {"Test-User", "secret"}}]},
- {server_srp, [{ssl_imp, new},{reuseaddr, true},
- {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
- {user_lookup_fun, {fun user_lookup/3, undefined}},
- {ciphers, srp_suites()}]},
- {server_srp_anon, [{ssl_imp, new},{reuseaddr, true},
- {user_lookup_fun, {fun user_lookup/3, undefined}},
- {ciphers, srp_anon_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -626,15 +702,32 @@ make_dsa_cert(Config) ->
[{server_dsa_opts, ServerConf},
{server_dsa_verify_opts, [{verify, verify_peer} | ServerConf]},
- {client_dsa_opts, ClientConf},
- {server_srp_dsa, [{user_lookup_fun, {fun user_lookup/3, undefined}},
- {ciphers, srp_dss_suites()} | ServerConf]},
- {client_srp_dsa, [{srp_identity, {"Test-User", "secret"}}
- | ClientConf]}
+ {client_dsa_opts, ClientConf}
| Config];
false ->
Config
end.
+
+
+make_cert_chains_der(Alg, UserConf) ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(Alg, Alg, ClientChain, ServerChain),
+ public_key:pkix_test_data(CertChainConf).
+
+make_cert_chains_pem(Alg, UserConf, Config, Suffix) ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(Alg, Alg, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(Alg) ++ Suffix]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(Alg) ++ Suffix]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ Conf = x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ CConf = proplists:get_value(client_config, Conf),
+ SConf = proplists:get_value(server_config, Conf),
+ #{server_config => SConf,
+ client_config => CConf}.
+
make_rsa_cert_chains(UserConf, Config, Suffix) ->
ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
@@ -649,6 +742,40 @@ make_rsa_cert_chains(UserConf, Config, Suffix) ->
[{reuseaddr, true}, {verify, verify_peer} | ServerConf]
}.
+make_ecc_cert_chains(UserConf, Config, Suffix) ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(ecdsa, ecdsa, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "ecdsa" ++ Suffix]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "ecdsa" ++ Suffix]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ {[{verify, verify_peer} | ClientConf],
+ [{reuseaddr, true}, {verify, verify_peer} | ServerConf]
+ }.
+
+
+make_dsa_cert_chains(UserConf, Config, Suffix) ->
+ CryptoSupport = crypto:supports(),
+ case proplists:get_bool(dss, proplists:get_value(public_keys, CryptoSupport)) of
+ true ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(dsa, dsa, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "dsa" ++ Suffix]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "dsa" ++ Suffix]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ {[{verify, verify_peer} | ClientConf],
+ [{reuseaddr, true}, {verify, verify_peer} | ServerConf]};
+ false ->
+ Config
+ end.
+
make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config) ->
make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config, ?DEFAULT_CURVE).
%%
@@ -903,14 +1030,14 @@ make_ecdh_rsa_cert(Config) ->
end.
start_upgrade_server(Args) ->
- Result = spawn_link(?MODULE, run_upgrade_server, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_upgrade_server, [Args]),
receive
{listen, up} ->
Result
end.
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),
@@ -918,43 +1045,41 @@ run_upgrade_server(Opts) ->
Pid = proplists:get_value(from, Opts),
ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
- {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
+ {ok, ListenSocket} = gen_tcp:listen(Port, TcpOptions),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions]);
+ ssl:handshake(AcceptSocket, SslOptions);
_ ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions, TimeOut])
+ ssl:handshake(AcceptSocket, SslOptions, TimeOut)
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
+ Msg = apply(Module, Function, [SslAcceptSocket | Args]),
ct:log("~p:~p~nUpgrade Server Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
ct:log("~p:~p~nUpgrade Server closing~n", [?MODULE,?LINE]),
- rpc:call(Node, ssl, close, [SslAcceptSocket])
+ ssl:close(SslAcceptSocket)
end
catch error:{badmatch, Error} ->
Pid ! {self(), Error}
end.
start_upgrade_client(Args) ->
- spawn_link(?MODULE, run_upgrade_client, [Args]).
+ Node = proplists:get_value(node, Args),
+ spawn_link(Node, ?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),
@@ -963,34 +1088,34 @@ run_upgrade_client(Opts) ->
ct:log("~p:~p~ngen_tcp:connect(~p, ~p, ~p)~n",
[?MODULE,?LINE, Host, Port, TcpOptions]),
- {ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
+ {ok, Socket} = gen_tcp:connect(Host, Port, TcpOptions),
send_selected_port(Pid, Port, Socket),
ct:log("~p:~p~nssl:connect(~p, ~p)~n", [?MODULE,?LINE, Socket, SslOptions]),
- {ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
+ {ok, SslSocket} = ssl:connect(Socket, SslOptions),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~napply(~p, ~p, ~p)~n",
[?MODULE,?LINE, Module, Function, [SslSocket | Args]]),
- Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
+ Msg = apply(Module, Function, [SslSocket | Args]),
ct:log("~p:~p~nUpgrade Client Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
ct:log("~p:~p~nUpgrade Client closing~n", [?MODULE,?LINE]),
- rpc:call(Node, ssl, close, [SslSocket])
+ ssl:close(SslSocket)
end.
start_upgrade_server_error(Args) ->
- Result = spawn_link(?MODULE, run_upgrade_server_error, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node,?MODULE, run_upgrade_server_error, [Args]),
receive
{listen, up} ->
Result
end.
run_upgrade_server_error(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),
@@ -998,22 +1123,20 @@ run_upgrade_server_error(Opts) ->
Pid = proplists:get_value(from, Opts),
ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
- {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
+ {ok, ListenSocket} = gen_tcp:listen(Port, TcpOptions),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
Error = case TimeOut of
infinity ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions]);
+ ssl:handshake(AcceptSocket, SslOptions);
_ ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("~p:~p~nssl:ssl_handshake(~p, ~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions, TimeOut])
+ ssl:handshake(AcceptSocket, SslOptions, TimeOut)
end,
Pid ! {self(), Error}.
@@ -1025,32 +1148,31 @@ start_server_error(Args) ->
end.
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),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- case rpc:call(Node, Transport, listen, [Port, Options]) of
+ case Transport:listen(Port, Options) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
+ case Transport:transport_accept(ListenSocket) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
ct:log("~p:~p~nssl:ssl_accept(~p)~n", [?MODULE,?LINE, AcceptSocket]),
- Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
+ Error = ssl:handshake(AcceptSocket),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~n~p:accept(~p)~n", [?MODULE,?LINE, Transport, ListenSocket]),
- case rpc:call(Node, Transport, accept, [ListenSocket]) of
+ case Transport:accept(ListenSocket) of
{error, _} = Error ->
Pid ! {self(), Error}
end;
@@ -1062,18 +1184,26 @@ run_server_error(Opts) ->
end.
start_client_error(Args) ->
- spawn_link(?MODULE, run_client_error, [Args]).
+ Node = proplists:get_value(node, Args),
+ spawn_link(Node, ?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),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
- Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
- Pid ! {self(), Error}.
+ Error = Transport:connect(Host, Port, Options),
+ case Error of
+ {error, _} ->
+ Pid ! {self(), Error};
+ {ok, _Socket} ->
+ receive
+ {ssl_error, _, {tls_alert, _}} = SslError ->
+ Pid ! {self(), SslError}
+ end
+ end.
accepters(N) ->
accepters([], N).
@@ -1090,11 +1220,57 @@ accepters(Acc, N) ->
basic_test(COpts, SOpts, Config) ->
SType = proplists:get_value(server_type, Config),
CType = proplists:get_value(client_type, Config),
- {Server, Port} = start_server(SType, SOpts, Config),
+ {Server, Port} = start_server(SType, COpts, SOpts, Config),
Client = start_client(CType, Port, COpts, Config),
gen_check_result(Server, SType, Client, CType),
stop(Server, Client).
+basic_alert(ClientOpts, ServerOpts, Config, Alert) ->
+ SType = proplists:get_value(server_type, Config),
+ CType = proplists:get_value(client_type, Config),
+ run_basic_alert(SType, CType, ClientOpts, ServerOpts, Config, Alert).
+
+run_basic_alert(erlang, erlang, ClientOpts, ServerOpts, Config, Alert) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+
+ Port = inet_port(Server),
+
+ Client = start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ check_server_alert(Server, Client, Alert);
+run_basic_alert(openssl = SType, erlang, ClientOpts, ServerOpts, Config, Alert) ->
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ {_Server, Port} = start_server(SType, ClientOpts, ServerOpts, Config),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+ Client = start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ check_client_alert(Client, Alert);
+run_basic_alert(erlang, openssl = CType, ClientOpts, ServerOpts, Config, Alert) ->
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = start_server_error([{node, ServerNode}, {port, 0},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = inet_port(Server),
+ start_client(CType, Port, ClientOpts, Config),
+
+ check_server_alert(Server, Alert).
+
+
ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) ->
{Server, Port} = start_server_ecc(erlang, SOpts, Expect, SECCOpts, Config),
Client = start_client_ecc(erlang, Port, COpts, Expect, CECCOpts, Config),
@@ -1106,16 +1282,52 @@ ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) ->
Client = start_client_ecc_error(erlang, Port, COpts, CECCOpts, Config),
check_server_alert(Server, Client, insufficient_security).
-start_client(openssl, Port, ClientOpts, Config) ->
+start_basic_client(openssl, Version, Port, ClientOpts) ->
Cert = proplists:get_value(certfile, ClientOpts),
Key = proplists:get_value(keyfile, ClientOpts),
CA = proplists:get_value(cacertfile, ClientOpts),
- Version = ssl_test_lib:protocol_version(Config),
+ Groups0 = proplists:get_value(groups, ClientOpts),
Exe = "openssl",
Args0 = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
ssl_test_lib:version_flag(Version),
- "-cert", Cert, "-CAfile", CA,
- "-key", Key, "-host","localhost", "-msg", "-debug"],
+ "-CAfile", CA, "-host", "localhost", "-msg", "-debug"],
+ Args1 =
+ case Groups0 of
+ undefined ->
+ Args0;
+ G ->
+ Args0 ++ ["-groups", G]
+ end,
+ Args =
+ case {Cert, Key} of
+ {C, K} when C =:= undefined orelse
+ K =:= undefined ->
+ Args1;
+ {C, K} ->
+ Args1 ++ ["-cert", C, "-key", K]
+ end,
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, "Hello world"),
+ OpenSslPort.
+
+start_client(openssl, Port, ClientOpts, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Ciphers = proplists:get_value(ciphers, ClientOpts, ssl:cipher_suites(default,Version)),
+ Groups0 = proplists:get_value(groups, ClientOpts),
+ CertArgs = openssl_cert_options(ClientOpts, client),
+ Exe = "openssl",
+ Args0 = case Groups0 of
+ undefined ->
+ ["s_client", "-verify", "2", "-port", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version),
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"];
+ Group ->
+ ["s_client", "-verify", "2", "-port", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version), "-groups", Group,
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"]
+ end,
Args = maybe_force_ipv4(Args0),
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, "Hello world"),
@@ -1128,7 +1340,7 @@ start_client(erlang, Port, ClientOpts, Config) ->
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, check_key_exchange_send_active, [KeyEx]}},
- {options, [{verify, verify_peer} | ClientOpts]}]).
+ {options, ClientOpts}]).
%% Workaround for running tests on machines where openssl
%% s_client would use an IPv6 address with localhost. As
@@ -1163,29 +1375,58 @@ start_client_ecc_error(erlang, Port, ClientOpts, ECCOpts, Config) ->
[{verify, verify_peer} | ClientOpts]}]).
-start_server(openssl, ServerOpts, Config) ->
- Cert = proplists:get_value(certfile, ServerOpts),
- Key = proplists:get_value(keyfile, ServerOpts),
- CA = proplists:get_value(cacertfile, ServerOpts),
+start_server(openssl, ClientOpts, ServerOpts, Config) ->
Port = inet_port(node()),
Version = protocol_version(Config),
Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-verify", "2", "-cert", Cert, "-CAfile", CA,
- "-key", Key, "-msg", "-debug"],
+ CertArgs = openssl_cert_options(ServerOpts, server),
+ Ciphers = proplists:get_value(ciphers, ClientOpts, ssl:cipher_suites(default,Version)),
+ Groups0 = proplists:get_value(groups, ServerOpts),
+ Args = case Groups0 of
+ undefined ->
+ ["s_server", "-accept", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version),
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"];
+ Group ->
+ ["s_server", "-accept", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version), "-groups", Group,
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"]
+ end,
OpenSslPort = portable_open_port(Exe, Args),
true = port_command(OpenSslPort, "Hello world"),
{OpenSslPort, Port};
-start_server(erlang, ServerOpts, Config) ->
+start_server(erlang, _, ServerOpts, Config) ->
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
KeyEx = proplists:get_value(check_keyex, Config, false),
+ Versions = protocol_versions(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib,
check_key_exchange_send_active,
[KeyEx]}},
- {options, [{verify, verify_peer} | ServerOpts]}]),
+ {options, [{verify, verify_peer}, {versions, Versions} | ServerOpts]}]),
{Server, inet_port(Server)}.
+
+cipher_flag('tlsv1.3') ->
+ "-ciphersuites";
+cipher_flag(_) ->
+ "-cipher".
+
+ciphers(Ciphers, Version) ->
+ Strs = [ssl_cipher_format:suite_map_to_openssl_str(Cipher) || Cipher <- Ciphers],
+ ciphers_concat(Version, Strs, "").
+
+ciphers_concat(_, [], [":" | Acc]) ->
+ lists:append(lists:reverse(Acc));
+ciphers_concat('tlsv1.3' = Version, [Head| Tail], Acc) ->
+ case Head of
+ "TLS" ++ _ ->
+ ciphers_concat(Version, Tail, [":", Head | Acc]);
+ _ ->
+ ciphers_concat(Version, Tail, Acc)
+ end;
+ciphers_concat(Version, [Head| Tail], Acc) ->
+ ciphers_concat(Version, Tail, [":", Head | Acc]).
start_server_with_raw_key(erlang, ServerOpts, Config) ->
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
@@ -1239,6 +1480,37 @@ stop(Client, Server) ->
close(Server),
close(Client).
+
+openssl_cert_options(Opts, Role) ->
+ Cert = proplists:get_value(certfile, Opts, undefined),
+ Key = proplists:get_value(keyfile, Opts, undefined),
+ CA = proplists:get_value(cacertfile, Opts, undefined),
+ case CA of
+ undefined ->
+ case cert_option("-cert", Cert) ++ cert_option("-key", Key) of
+ [] when Role == server ->
+ ["-nocert"];
+ Other ->
+ Other
+ end;
+ _ ->
+ cert_option("-cert", Cert) ++ cert_option("-CAfile", CA) ++
+ cert_option("-key", Key) ++ openssl_verify(Opts) ++ ["2"]
+ end.
+
+openssl_verify(Opts) ->
+ case proplists:get_value(fail_if_no_peer_cert, Opts, undefined) of
+ true ->
+ ["-Verify"];
+ _ ->
+ ["-verify"]
+ end.
+
+cert_option(_, undefined) ->
+ [];
+cert_option(Opt, Value) ->
+ [Opt, Value].
+
supported_eccs(Opts) ->
ToCheck = proplists:get_value(eccs, Opts, []),
Supported = ssl:eccs(),
@@ -1335,13 +1607,13 @@ common_ciphers(crypto) ->
common_ciphers(openssl) ->
OpenSslSuites =
string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"),
- [ssl_cipher_format:suite_definition(S)
+ [ssl_cipher_format:suite_bin_to_map(S)
|| S <- ssl_cipher:suites(tls_record:highest_protocol_version([])),
- lists:member(ssl_cipher_format:openssl_suite_name(S), OpenSslSuites)
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(ssl_cipher_format:suite_bin_to_map(S)), OpenSslSuites)
].
available_suites(Version) ->
- [ssl_cipher_format:suite_definition(Suite) ||
+ [ssl_cipher_format:suite_bin_to_map(Suite) ||
Suite <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))].
@@ -1414,7 +1686,7 @@ string_regex_filter(_Str, _Search) ->
false.
ecdh_dh_anonymous_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:anonymous_suites(Version)],
[{key_exchange,
fun(dh_anon) ->
true;
@@ -1424,7 +1696,7 @@ ecdh_dh_anonymous_suites(Version) ->
false
end}]).
psk_suites({3,_} = Version) ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []);
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:psk_suites(Version)], []);
psk_suites(Version) ->
ssl:filter_cipher_suites(psk_suites(dtls_v1:corresponding_tls_version(Version)),
[{cipher,
@@ -1435,7 +1707,7 @@ psk_suites(Version) ->
end}]).
psk_anon_suites({3,_} = Version) ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:psk_suites_anon(Version)],
[{key_exchange,
fun(psk) ->
true;
@@ -1458,7 +1730,7 @@ psk_anon_suites(Version) ->
srp_suites() ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:srp_suites()],
[{key_exchange,
fun(srp_rsa) ->
true;
@@ -1466,10 +1738,10 @@ srp_suites() ->
false
end}]).
srp_anon_suites() ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites_anon()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:srp_suites_anon()],
[]).
srp_dss_suites() ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:srp_suites()],
[{key_exchange,
fun(srp_dss) ->
true;
@@ -1477,14 +1749,14 @@ srp_dss_suites() ->
false
end}]).
chacha_suites(Version) ->
- [ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))].
+ [ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))].
rc4_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <-ssl_cipher:rc4_suites(Version)], []).
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <-ssl_cipher:rc4_suites(Version)], []).
des_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <-ssl_cipher:des_suites(Version)], []).
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <-ssl_cipher:des_suites(Version)], []).
tuple_to_map({Kex, Cipher, Mac}) ->
#{key_exchange => Kex,
@@ -1511,10 +1783,13 @@ cipher_result(Socket, Result) ->
ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
- ssl:send(Socket, "Hello\n"),
- "Hello\n" = active_recv(Socket, length( "Hello\n")),
- ssl:send(Socket, " world\n"),
- " world\n" = active_recv(Socket, length(" world\n")),
+ Hello = "Hello\n",
+ World = " world\n",
+ ssl:send(Socket, Hello),
+ ct:sleep(500),
+ ssl:send(Socket, World),
+ Expected = Hello ++ World,
+ Expected = active_recv(Socket, length(Expected)),
ok.
session_info_result(Socket) ->
@@ -1558,6 +1833,8 @@ is_tls_version('dtlsv1.2') ->
true;
is_tls_version('dtlsv1') ->
true;
+is_tls_version('tlsv1.3') ->
+ true;
is_tls_version('tlsv1.2') ->
true;
is_tls_version('tlsv1.1') ->
@@ -1588,7 +1865,12 @@ init_tls_version(Version, Config) ->
clean_tls_version(Config) ->
proplists:delete(protocol_opts, proplists:delete(protocol, Config)).
-
+
+sufficient_crypto_support(Version)
+ when Version == 'tlsv1.3' ->
+ CryptoSupport = crypto:supports(),
+ lists:member(rsa_pkcs1_pss_padding, proplists:get_value(rsa_opts, CryptoSupport)) andalso
+ lists:member(x448, proplists:get_value(curves, CryptoSupport));
sufficient_crypto_support(Version)
when Version == 'tlsv1.2'; Version == 'dtlsv1.2' ->
CryptoSupport = crypto:supports(),
@@ -1742,6 +2024,15 @@ is_sane_ecc(crypto) ->
is_sane_ecc(_) ->
sufficient_crypto_support(cipher_ec).
+is_sane_oppenssl_client() ->
+ [{_,_, Bin}] = crypto:info_lib(),
+ case binary_to_list(Bin) of
+ "OpenSSL 0.9" ++ _ ->
+ false;
+ _ ->
+ true
+ end.
+
is_fips(openssl) ->
VersionStr = os:cmd("openssl version"),
case re:split(VersionStr, "fips") of
@@ -1874,12 +2165,61 @@ check_sane_openssl_version(Version) ->
false;
{'tlsv1.1', "OpenSSL 0" ++ _} ->
false;
+ {'tlsv1', "OpenSSL 0" ++ _} ->
+ false;
{_, _} ->
true
end;
false ->
false
end.
+check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1';
+ Version == 'tlsv1.2' ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.1c" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1b" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1a" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1 " ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ _ ->
+ check_sane_openssl_renegotaite(Config)
+ end;
+check_sane_openssl_renegotaite(Config, _) ->
+ check_sane_openssl_renegotaite(Config).
+
+check_sane_openssl_renegotaite(Config) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.0" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 0.9.8" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 0.9.7" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ _ ->
+ Config
+ end.
+
+workaround_openssl_s_clinent() ->
+ %% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159
+ %% https://bugs.archlinux.org/task/33919
+ %% Bug seems to manifests it self if TLS version is not
+ %% explicitly specified
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.1c" ++ _ ->
+ ["-no_tls1_2"];
+ "OpenSSL 1.0.1d" ++ _ ->
+ ["-no_tls1_2"];
+ "OpenSSL 1.0.1e" ++ _ ->
+ ["-no_tls1_2"];
+ "OpenSSL 1.0.1f" ++ _ ->
+ ["-no_tls1_2"];
+ _ ->
+ []
+ end.
+
enough_openssl_crl_support("OpenSSL 0." ++ _) -> false;
enough_openssl_crl_support(_) -> true.
@@ -1906,6 +2246,8 @@ version_flag('tlsv1.1') ->
"-tls1_1";
version_flag('tlsv1.2') ->
"-tls1_2";
+version_flag('tlsv1.3') ->
+ "-tls1_3";
version_flag(sslv3) ->
"-ssl3";
version_flag(sslv2) ->
@@ -1916,10 +2258,10 @@ version_flag('dtlsv1') ->
"-dtls1".
filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_list(Cipher)->
- filter_suites([ssl_cipher_format:openssl_suite(S) || S <- Ciphers],
+ filter_suites([ssl_cipher_format:suite_openssl_str_to_map(S) || S <- Ciphers],
AtomVersion);
filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_binary(Cipher)->
- filter_suites([ssl_cipher_format:suite_definition(S) || S <- Ciphers],
+ filter_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- Ciphers],
AtomVersion);
filter_suites(Ciphers0, AtomVersion) ->
Version = tls_version(AtomVersion),
@@ -1927,11 +2269,11 @@ filter_suites(Ciphers0, AtomVersion) ->
++ ssl_cipher:anonymous_suites(Version)
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:psk_suites_anon(Version)
- ++ ssl_cipher:srp_suites()
- ++ ssl_cipher:srp_suites_anon()
+ ++ ssl_cipher:srp_suites(Version)
+ ++ ssl_cipher:srp_suites_anon(Version)
++ ssl_cipher:rc4_suites(Version),
Supported1 = ssl_cipher:filter_suites(Supported0),
- Supported2 = [ssl_cipher_format:suite_definition(S) || S <- Supported1],
+ Supported2 = [ssl_cipher_format:suite_bin_to_map(S) || S <- Supported1],
[Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)].
-define(OPENSSL_QUIT, "Q\n").
@@ -2045,6 +2387,14 @@ protocol_version(Config, atom) ->
tls_record:protocol_version(protocol_version(Config, tuple))
end.
+protocol_versions(Config) ->
+ Version = protocol_version(Config),
+ case Version of
+ 'tlsv1.3' -> %% TLS-1.3 servers shall also support 1.2
+ ['tlsv1.3', 'tlsv1.2'];
+ _ ->
+ [Version]
+ end.
protocol_options(Config, Options) ->
Protocol = proplists:get_value(protocol, Config, tls),
{Protocol, Opts} = lists:keyfind(Protocol, 1, Options),
@@ -2068,7 +2418,8 @@ clean_env() ->
application:unset_env(ssl, session_cache_server_max),
application:unset_env(ssl, ssl_pem_cache_clean),
application:unset_env(ssl, bypass_pem_cache),
- application:unset_env(ssl, alert_timeout).
+ application:unset_env(ssl, alert_timeout),
+ application:unset_env(ssl, internal_active_n).
clean_start() ->
ssl:stop(),
@@ -2342,4 +2693,98 @@ reuse_session(ClientOpts, ServerOpts, Config) ->
ssl_test_lib:close(Server1),
ssl_test_lib:close(Client3),
ssl_test_lib:close(Client4).
-
+
+user_lookup(psk, _Identity, UserState) ->
+ {ok, UserState};
+user_lookup(srp, Username, _UserState) ->
+ Salt = ssl_cipher:random_bytes(16),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
+ {ok, {srp_1024, Salt, UserPassHash}}.
+
+test_cipher(TestCase, Config) ->
+ [{name, Group} |_] = proplists:get_value(tc_group_properties, Config),
+ list_to_atom(re:replace(atom_to_list(TestCase), atom_to_list(Group) ++ "_", "", [{return, list}])).
+
+digest() ->
+ case application:get_env(ssl, protocol_version, application:get_env(ssl, dtls_protocol_version)) of
+ Ver when Ver == 'tlsv1.2';
+ Ver == 'dtlsv1.2' ->
+ {digest, sha256};
+ _ ->
+ {digest, sha1}
+ end.
+
+kill_openssl() ->
+ case os:type() of
+ {unix, _} ->
+ os:cmd("pkill openssl");
+ {win32, _} ->
+ os:cmd("cmd.exe /C \"taskkill /IM openssl.exe /F\"")
+ end.
+
+hostname_format(Hostname) ->
+ case lists:member($., Hostname) of
+ true ->
+ Hostname;
+ false ->
+ "localhost"
+ end.
+
+erlang_ssl_receive_and_assert_negotiated_protocol(Socket, Protocol, Data) ->
+ case ssl:negotiated_protocol(Socket) of
+ {ok, Protocol} ->
+ active_recv(Socket, length(Data));
+ Result ->
+ {error, {{expected, Protocol}, {got, Result}}}
+ end.
+
+check_openssl_npn_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case string:str(HelpText, "nextprotoneg") of
+ 0 ->
+ {skip, "Openssl not compiled with nextprotoneg support"};
+ _ ->
+ Config
+ end.
+
+new_config(PrivDir, ServerOpts0) ->
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts0),
+ CertFile = proplists:get_value(certfile, ServerOpts0),
+ KeyFile = proplists:get_value(keyfile, ServerOpts0),
+ NewCaCertFile = filename:join(PrivDir, "new_ca.pem"),
+ NewCertFile = filename:join(PrivDir, "new_cert.pem"),
+ NewKeyFile = filename:join(PrivDir, "new_key.pem"),
+ file:copy(CaCertFile, NewCaCertFile),
+ file:copy(CertFile, NewCertFile),
+ file:copy(KeyFile, NewKeyFile),
+ ServerOpts1 = proplists:delete(cacertfile, ServerOpts0),
+ ServerOpts2 = proplists:delete(certfile, ServerOpts1),
+ ServerOpts = proplists:delete(keyfile, ServerOpts2),
+
+ {ok, PEM} = file:read_file(NewCaCertFile),
+ ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+
+ [{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
+ {keyfile, NewKeyFile} | ServerOpts].
+
+sane_openssl_alpn_npn_renegotiate() ->
+ case os:cmd("openssl version") of
+ "LibreSSL 2.9.1" ++ _ ->
+ false;
+ "LibreSSL 2.6.4" ++ _ ->
+ false;
+ "OpenSSL 1.1.1a-freebsd" ++ _ ->
+ false;
+ _ ->
+ true
+ end.
+
+openssl_sane_dtls_alpn() ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.1.0g" ++ _ ->
+ false;
+ "OpenSSL 1.1.1a" ++ _ ->
+ false;
+ _->
+ openssl_sane_dtls()
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
deleted file mode 100644
index df84411b6d..0000000000
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ /dev/null
@@ -1,2116 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ssl_to_openssl_SUITE).
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
-
--define(SLEEP, 1000).
--define(OPENSSL_RENEGOTIATE, "R\n").
--define(OPENSSL_QUIT, "Q\n").
--define(OPENSSL_GARBAGE, "P\n").
--define(EXPIRE, 10).
-
-%%--------------------------------------------------------------------
-%% Common Test interface functions -----------------------------------
-%%--------------------------------------------------------------------
-
-all() ->
- case ssl_test_lib:openssl_sane_dtls() of
- true ->
- [{group, basic},
- {group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'sslv3'},
- {group, 'dtlsv1.2'},
- {group, 'dtlsv1'}];
- false ->
- [{group, basic},
- {group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'sslv3'}]
- end.
-
-groups() ->
- case ssl_test_lib:openssl_sane_dtls() of
- true ->
- [{basic, [], basic_tests()},
- {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'sslv3', [], all_versions_tests()},
- {'dtlsv1.2', [], dtls_all_versions_tests()},
- {'dtlsv1', [], dtls_all_versions_tests()}
- ];
- false ->
- [{basic, [], basic_tests()},
- {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'sslv3', [], all_versions_tests()}
- ]
- end.
-
-basic_tests() ->
- [basic_erlang_client_openssl_server,
- basic_erlang_server_openssl_client,
- expired_session
- ].
-
-all_versions_tests() ->
- [
- erlang_client_openssl_server,
- erlang_server_openssl_client,
- erlang_client_openssl_server_dsa_cert,
- erlang_server_openssl_client_dsa_cert,
- erlang_client_openssl_server_anon,
- erlang_server_openssl_client_anon,
- erlang_server_openssl_client_anon_with_cert,
- erlang_server_openssl_client_reuse_session,
- erlang_client_openssl_server_renegotiate,
- erlang_client_openssl_server_renegotiate_after_client_data,
- erlang_client_openssl_server_nowrap_seqnum,
- erlang_server_openssl_client_nowrap_seqnum,
- erlang_client_openssl_server_no_server_ca_cert,
- erlang_client_openssl_server_client_cert,
- erlang_server_openssl_client_client_cert,
- ciphers_rsa_signed_certs,
- ciphers_dsa_signed_certs,
- erlang_client_bad_openssl_server,
- expired_session,
- ssl2_erlang_server_openssl_client
- ].
-
-dtls_all_versions_tests() ->
- case ssl_test_lib:openssl_sane_client_cert() of
- true ->
- [erlang_server_openssl_client_client_cert,
- erlang_client_openssl_server_no_server_ca_cert,
- erlang_client_openssl_server_client_cert
- | dtls_all_versions_tests_2()];
- false ->
- dtls_all_versions_tests_2()
- end.
-
-dtls_all_versions_tests_2() ->
- [erlang_client_openssl_server,
- erlang_server_openssl_client,
- erlang_client_openssl_server_dsa_cert,
- erlang_server_openssl_client_dsa_cert,
- erlang_client_openssl_server_anon,
- erlang_server_openssl_client_anon,
- erlang_server_openssl_client_anon_with_cert,
- erlang_server_openssl_client_reuse_session,
- erlang_client_openssl_server_renegotiate,
- erlang_client_openssl_server_nowrap_seqnum,
- erlang_server_openssl_client_nowrap_seqnum,
- ciphers_rsa_signed_certs,
- ciphers_dsa_signed_certs
- %%expired_session
- ].
-
-alpn_tests() ->
- [erlang_client_alpn_openssl_server_alpn,
- erlang_server_alpn_openssl_client_alpn,
- erlang_client_alpn_openssl_server,
- erlang_client_openssl_server_alpn,
- erlang_server_alpn_openssl_client,
- erlang_server_openssl_client_alpn,
- erlang_client_alpn_openssl_server_alpn_renegotiate,
- erlang_server_alpn_openssl_client_alpn_renegotiate,
- erlang_client_alpn_npn_openssl_server_alpn_npn,
- erlang_server_alpn_npn_openssl_client_alpn_npn].
-
-npn_tests() ->
- [erlang_client_openssl_server_npn,
- erlang_server_openssl_client_npn,
- erlang_server_openssl_client_npn_renegotiate,
- erlang_client_openssl_server_npn_renegotiate,
- erlang_server_openssl_client_npn_only_client,
- erlang_server_openssl_client_npn_only_server,
- erlang_client_openssl_server_npn_only_client,
- erlang_client_openssl_server_npn_only_server].
-
-sni_server_tests() ->
- [erlang_server_openssl_client_sni_match,
- erlang_server_openssl_client_sni_match_fun,
- erlang_server_openssl_client_sni_no_match,
- erlang_server_openssl_client_sni_no_match_fun,
- erlang_server_openssl_client_sni_no_header,
- erlang_server_openssl_client_sni_no_header_fun].
-
-
-init_per_suite(Config0) ->
- case os:find_executable("openssl") of
- false ->
- {skip, "Openssl not found"};
- _ ->
- ct:pal("Version: ~p", [os:cmd("openssl version")]),
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- ssl_test_lib:clean_start(),
- Config =
- case ssl_test_lib:openssl_dsa_support() of
- true ->
- Config1 = ssl_test_lib:make_rsa_cert(Config0),
- ssl_test_lib:make_dsa_cert(Config1);
- false ->
- ssl_test_lib:make_rsa_cert(Config0)
- end,
- ssl_test_lib:cipher_restriction(Config)
- catch _:_ ->
- {skip, "Crypto did not start"}
- end
- end.
-
-end_per_suite(_Config) ->
- ssl:stop(),
- application:stop(crypto).
-
-init_per_group(basic, Config0) ->
- case ssl_test_lib:supports_ssl_tls_version('tlsv1.2')
- orelse ssl_test_lib:supports_ssl_tls_version('tlsv1.1')
- orelse ssl_test_lib:supports_ssl_tls_version('tlsv1')
- of
- true ->
- ssl_test_lib:clean_tls_version(Config0);
- false ->
- {skip, "only sslv3 supported by OpenSSL"}
- end;
-
-init_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
- true ->
- case ssl_test_lib:supports_ssl_tls_version(GroupName) of
- true ->
- case ssl_test_lib:check_sane_openssl_version(GroupName) of
- true ->
- ssl_test_lib:init_tls_version(GroupName, Config);
- false ->
- {skip, openssl_does_not_support_version}
- end;
- false ->
- {skip, openssl_does_not_support_version}
- end;
- _ ->
- ssl:start(),
- Config
- end.
-
-end_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
- true ->
- ssl_test_lib:clean_tls_version(Config);
- false ->
- Config
- end.
-
-init_per_testcase(expired_session, Config) ->
- ct:timetrap(?EXPIRE * 1000 * 5),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, session_lifetime, ?EXPIRE),
- ssl:start(),
- Config;
-
-init_per_testcase(TestCase, Config) when
- TestCase == ciphers_dsa_signed_certs;
- TestCase == erlang_client_openssl_server_dsa_cert;
- TestCase == erlang_server_openssl_client_dsa_cert;
- TestCase == erlang_client_openssl_server_dsa_cert;
- TestCase == erlang_server_openssl_client_dsa_cert ->
- case ssl_test_lib:openssl_dsa_support() of
- true ->
- special_init(TestCase, Config);
- false ->
- {skip, "DSA not supported by OpenSSL"}
- end;
-init_per_testcase(TestCase, Config) ->
- ct:timetrap({seconds, 35}),
- special_init(TestCase, Config).
-
-special_init(TestCase, Config) when
- TestCase == ciphers_rsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs->
- ct:timetrap({seconds, 90}),
- Config;
-special_init(TestCase, Config)
- when TestCase == erlang_client_openssl_server_renegotiate;
- TestCase == erlang_client_openssl_server_nowrap_seqnum;
- TestCase == erlang_server_openssl_client_nowrap_seqnum;
- TestCase == erlang_client_openssl_server_renegotiate_after_client_data
- ->
- {ok, Version} = application:get_env(ssl, protocol_version),
- check_sane_openssl_renegotaite(Config, Version);
-
-special_init(ssl2_erlang_server_openssl_client, Config) ->
- case ssl_test_lib:supports_ssl_tls_version(sslv2) of
- true ->
- Config;
- false ->
- {skip, "sslv2 not supported by openssl"}
- end;
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_openssl_server_alpn;
- TestCase == erlang_server_alpn_openssl_client_alpn;
- TestCase == erlang_client_alpn_openssl_server;
- TestCase == erlang_client_openssl_server_alpn;
- TestCase == erlang_server_alpn_openssl_client;
- TestCase == erlang_server_openssl_client_alpn ->
- check_openssl_alpn_support(Config);
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate;
- TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate ->
- {ok, Version} = application:get_env(ssl, protocol_version),
- case check_sane_openssl_renegotaite(Config, Version) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_alpn_support(Config)
- end;
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn;
- TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn ->
- case check_openssl_alpn_support(Config) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_npn_support(Config)
- end;
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_openssl_server_npn;
- TestCase == erlang_server_openssl_client_npn;
- TestCase == erlang_server_openssl_client_npn_only_server;
- TestCase == erlang_server_openssl_client_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_server ->
- check_openssl_npn_support(Config);
-
-special_init(TestCase, Config)
- when TestCase == erlang_server_openssl_client_npn_renegotiate;
- TestCase == erlang_client_openssl_server_npn_renegotiate ->
- {ok, Version} = application:get_env(ssl, protocol_version),
- case check_sane_openssl_renegotaite(Config, Version) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_npn_support(Config)
- end;
-
-special_init(TestCase, Config0)
- when TestCase == erlang_server_openssl_client_sni_match;
- TestCase == erlang_server_openssl_client_sni_no_match;
- TestCase == erlang_server_openssl_client_sni_no_header;
- TestCase == erlang_server_openssl_client_sni_match_fun;
- TestCase == erlang_server_openssl_client_sni_no_match_fun;
- TestCase == erlang_server_openssl_client_sni_no_header_fun ->
- RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config0),
- Config = [{sni_server_opts, [{sni_hosts,
- [{"a.server", [
- {certfile, proplists:get_value(certfile, RsaOpts)},
- {keyfile, proplists:get_value(keyfile, RsaOpts)}
- ]},
- {"b.server", [
- {certfile, proplists:get_value(certfile, RsaOpts)},
- {keyfile, proplists:get_value(keyfile, RsaOpts)}
- ]}
- ]}]} | Config0],
- check_openssl_sni_support(Config);
-
-special_init(_, Config) ->
- Config.
-
-end_per_testcase(reuse_session_expired, Config) ->
- application:unset_env(ssl, session_lifetime),
- Config;
-end_per_testcase(_, Config) ->
- Config.
-
-%%--------------------------------------------------------------------
-%% Test Cases --------------------------------------------------------
-%%--------------------------------------------------------------------
-basic_erlang_client_openssl_server() ->
- [{doc,"Test erlang client with openssl server"}].
-basic_erlang_client_openssl_server(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_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),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- "-cert", CertFile, "-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
-
- ssl_test_lib:wait_for_openssl_server(Port, tls),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-basic_erlang_server_openssl_client() ->
- [{doc,"Test erlang server with openssl client"}].
-basic_erlang_server_openssl_client(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- 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),
-
- Exe = "openssl",
- Args = case no_low_flag("-no_ssl2") of
- [] ->
- ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3")
- | workaround_openssl_s_clinent()];
- Flag ->
- ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3"), Flag
- | workaround_openssl_s_clinent()]
- end,
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-erlang_client_openssl_server() ->
- [{doc,"Test erlang client with openssl server"}].
-erlang_client_openssl_server(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-erlang_server_openssl_client() ->
- [{doc,"Test erlang server with openssl client"}].
-erlang_server_openssl_client(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- 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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-erlang_client_openssl_server_dsa_cert() ->
- [{doc,"Test erlang server with openssl client"}].
-erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2", "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
-
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_dsa_cert() ->
- [{doc,"Test erlang server with openssl client"}].
-erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
- CaCertFile = proplists:get_value(cacertfile, ClientOpts),
- CertFile = proplists:get_value(certfile, ClientOpts),
- KeyFile = proplists:get_value(keyfile, ClientOpts),
-
- 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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile,
- "-CAfile", CaCertFile,
- "-key", KeyFile, "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
- %%--------------------------------------------------------------------
-erlang_client_openssl_server_anon() ->
- [{doc,"Test erlang client with openssl server, anonymous"}].
-erlang_client_openssl_server_anon(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- %% OpenSSL expects a certificate and key, even if the cipher spec
- %% is restructed to aNULL, so we use 'server_rsa_opts' here
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_anon_opts, Config),
- VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
-
- case openssl_has_common_ciphers(Ciphers) of
- false ->
- {skip, not_supported_by_openssl};
- true ->
-
- {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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile,
- "-cipher", "aNULL", "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | ClientOpts]}]),
-
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false)
- end.
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_anon() ->
- [{doc,"Test erlang server with openssl client, anonymous"}].
-erlang_server_openssl_client_anon(Config) when is_list(Config) ->
-
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config),
- VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
-
- case openssl_has_common_ciphers(Ciphers) of
- false ->
- {skip, not_supported_by_openssl};
- true ->
- {_, ServerNode, Hostname} = 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, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false)
- end.
-
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_anon_with_cert() ->
- [{doc,"Test erlang server with openssl client, anonymous (with cert)"}].
-erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
-
- case openssl_has_common_ciphers(Ciphers) of
- false ->
- {skip, not_supported_by_openssl};
- true ->
- {_, ServerNode, Hostname} = 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, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false)
- end.
-
- %%--------------------------------------------------------------------
-erlang_server_openssl_client_reuse_session() ->
- [{doc, "Test erlang server with openssl client that reconnects with the"
- "same session id, to test reusing of sessions."}].
-erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {reconnect_times, 5},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname)
- ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-reconnect"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_openssl_server_renegotiate() ->
- [{doc,"Test erlang client when openssl server issuses a renegotiate"}].
-erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to openssl",
- OpenSslData = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- delayed_send, [[ErlData, OpenSslData]]}},
- {options, ClientOpts}]),
-
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, OpenSslData),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_renegotiate_after_client_data() ->
- [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}].
-erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to openssl",
- OpenSslData = "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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_wait_send, [[ErlData, OpenSslData]]}},
- {options, ClientOpts}]),
-
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, OpenSslData),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_openssl_server_nowrap_seqnum() ->
- [{doc, "Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to openssl\n",
- N = 10,
-
- 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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[ErlData, N+2]]}},
- {options, [{reuse_sessions, false},
- {renegotiate_at, N} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_nowrap_seqnum() ->
- [{doc, "Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- N = 10,
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[Data, N+2]]}},
- {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client","-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-
-erlang_client_openssl_server_no_server_ca_cert() ->
- [{doc, "Test erlang client when openssl server sends a cert chain not"
- "including the ca cert. Explicitly test this even if it is"
- "implicitly tested eleswhere."}].
-erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
-
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_client_cert() ->
- [{doc,"Test erlang client with openssl server when client sends cert"}].
-erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_client_cert() ->
- [{doc,"Test erlang server with openssl client when client sends cert"}].
-erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
-
- {_, ServerNode, Hostname} = 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),
-
- CaCertFile = proplists:get_value(cacertfile, ClientOpts),
- CertFile = proplists:get_value(certfile, ClientOpts),
- KeyFile = proplists:get_value(keyfile, ClientOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-cert", CertFile,
- "-CAfile", CaCertFile,
- "-key", KeyFile,"-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- true = port_command(OpenSslPort, Data),
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpenSslPort),
- ssl_test_lib:close(Server),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-erlang_server_erlang_client_client_cert() ->
- [{doc,"Test erlang server with erlang client when client sends cert"}].
-erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
- ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
- Version = ssl_test_lib:protocol_version(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,
- %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- [Data]}},
- {options,
- [{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()},
- %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- {mfa, {ssl, send, [Data]}},
- {options,
- [{versions, [Version]} | 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).
-
-%%--------------------------------------------------------------------
-
-ciphers_rsa_signed_certs() ->
- [{doc,"Test cipher suites that uses rsa certs"}].
-ciphers_rsa_signed_certs(Config) when is_list(Config) ->
- Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:rsa_suites(openssl),
- run_suites(Ciphers, Version, Config, rsa).
-%%--------------------------------------------------------------------
-
-ciphers_dsa_signed_certs() ->
- [{doc,"Test cipher suites that uses dsa certs"}].
-ciphers_dsa_signed_certs(Config) when is_list(Config) ->
- Version = ssl_test_lib:protocol_version(Config),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:dsa_suites(NVersion),
- run_suites(Ciphers, Version, Config, dsa).
-
-%%--------------------------------------------------------------------
-erlang_client_bad_openssl_server() ->
- [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}].
-erlang_client_bad_openssl_server(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, server_sent_garbage, []}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
-
- %% Send garbage
- true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
-
- ct:sleep(?SLEEP),
-
- Client0 ! server_sent_garbage,
-
- ssl_test_lib:check_result(Client0, true),
-
- ssl_test_lib:close(Client0),
-
- %% Make sure openssl does not hang and leave zombie process
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result_msg, []}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client1),
- process_flag(trap_exit, false),
- ok.
-
-%%--------------------------------------------------------------------
-
-expired_session() ->
- [{doc, "Test our ssl client handling of expired sessions. Will make"
- "better code coverage of the ssl_manager module"}].
-expired_session(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_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),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- "-cert", CertFile,"-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, tls),
-
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- ssl_test_lib:close(Client0),
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- ssl_test_lib:close(Client1),
- %% Make sure session is unregistered due to expiration
- ct:sleep((?EXPIRE+1) * 1000),
-
- Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client2),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-ssl2_erlang_server_openssl_client() ->
- [{doc,"Test that ssl v2 clients are rejected"}].
-
-ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- "-ssl2", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
- ssl_test_lib:consume_port_exit(OpenSslPort),
- ssl_test_lib:check_server_alert(Server, bad_record_mac),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-
-erlang_client_alpn_openssl_server_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_server_alpn_openssl_client_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_client_alpn_openssl_server(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config,
- [{alpn_advertised_protocols, [<<"spdy/2">>]}],
- [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_client_openssl_server_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config,
- [],
- ["-alpn", "spdy/2"],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_server_alpn_openssl_client(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config,
- [{alpn_preferred_protocols, [<<"spdy/2">>]}],
- [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_server_openssl_client_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config,
- [],
- ["-alpn", "spdy/2"],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_alpn_openssl_server_alpn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_server_alpn_openssl_client_alpn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_alpn_npn_openssl_server_alpn_npn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_server_alpn_npn_openssl_client_alpn_npn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_npn() ->
- [{doc,"Test erlang client with openssl server doing npn negotiation"}].
-
-erlang_client_openssl_server_npn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_npn_renegotiate() ->
- [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}].
-
-erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-%%--------------------------------------------------------------------------
-erlang_server_openssl_client_npn() ->
- [{doc,"Test erlang server with openssl client and npn negotiation"}].
-
-erlang_server_openssl_client_npn(Config) when is_list(Config) ->
-
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-erlang_server_openssl_client_npn_renegotiate() ->
- [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}].
-
-erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-%%--------------------------------------------------------------------------
-erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config, [],
- ["-nextprotoneg", "spdy/2"], Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config,
- [{client_preferred_next_protocols,
- {client, [<<"spdy/2">>], <<"http/1.1">>}}], [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config, [], ["-nextprotoneg", "spdy/2"],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-%--------------------------------------------------------------------------
-erlang_server_openssl_client_sni_no_header(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test(Config, undefined, undefined, "server Peer cert").
-
-erlang_server_openssl_client_sni_no_header_fun(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test_sni_fun(Config, undefined, undefined, "server Peer cert").
-
-erlang_server_openssl_client_sni_match(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test(Config, "a.server", "a.server", "server Peer cert").
-
-erlang_server_openssl_client_sni_match_fun(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test_sni_fun(Config, "a.server", "a.server", "server Peer cert").
-
-erlang_server_openssl_client_sni_no_match(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test(Config, "c.server", undefined, "server Peer cert").
-
-erlang_server_openssl_client_sni_no_match_fun(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test_sni_fun(Config, "c.server", undefined, "server Peer cert").
-
-
-%%--------------------------------------------------------------------
-%% Internal functions ------------------------------------------------
-%%--------------------------------------------------------------------
-run_suites(Ciphers, Version, Config, Type) ->
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ssl_test_lib:ssl_options(server_rsa_opts, Config)};
- dsa ->
- {ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ssl_test_lib:ssl_options(server_dsa_verify_opts, Config)}
- end,
-
- Result = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- Ciphers),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- ct:log("Cipher suite errors: ~p~n", [Error]),
- ct:fail(cipher_suite_failed_see_test_case_log)
- end.
-
-client_read_check([], _Data) ->
- ok;
-client_read_check([Hd | T], Data) ->
- case binary:match(Data, list_to_binary(Hd)) of
- nomatch ->
- nomatch;
- _ ->
- client_read_check(T, Data)
- end.
-client_check_result(Port, DataExpected, DataReceived) ->
- receive
- {Port, {data, TheData}} ->
- Data = list_to_binary(TheData),
- NewData = <<DataReceived/binary, Data/binary>>,
- ct:log("New Data: ~p", [NewData]),
- case client_read_check(DataExpected, NewData) of
- ok ->
- ok;
- _ ->
- client_check_result(Port, DataExpected, NewData)
- end
- after 20000 ->
- ct:fail({"Time out on openSSL Client", {expected, DataExpected},
- {got, DataReceived}})
- end.
-client_check_result(Port, DataExpected) ->
- client_check_result(Port, DataExpected, <<"">>).
-
-send_and_hostname(SSLSocket) ->
- ssl:send(SSLSocket, "OK"),
- case ssl:connection_information(SSLSocket, [sni_hostname]) of
- {ok, []} ->
- undefined;
- {ok, [{sni_hostname, Hostname}]} ->
- Hostname
- end.
-
-erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
- ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
- {options, ServerOptions}]),
- Port = ssl_test_lib:inet_port(Server),
- Exe = "openssl",
- ClientArgs = case SNIHostname of
- undefined ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port);
- _ ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname)
- end,
- ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
-
- ssl_test_lib:check_result(Server, ExpectedSNIHostname),
- ssl_test_lib:close_port(ClientPort),
- ssl_test_lib:close(Server),
- ok.
-
-
-erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
- [{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config),
- SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
- ServerOptions = proplists:get_value(server_rsa_opts, Config) ++ [{sni_fun, SNIFun}],
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
- {options, ServerOptions}]),
- Port = ssl_test_lib:inet_port(Server),
- Exe = "openssl",
- ClientArgs = case SNIHostname of
- undefined ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port);
- _ ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname)
- end,
-
- ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
-
- ssl_test_lib:check_result(Server, ExpectedSNIHostname),
- ssl_test_lib:close_port(ClientPort),
- ssl_test_lib:close(Server).
-
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- process_flag(trap_exit, true),
- ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
- {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),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- ConnectionInfo = {ok, {Version, CipherSuite}},
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- true = port_command(OpenSslPort, "Hello\n"),
-
- receive
- {Port, {data, _}} when is_port(Port) ->
- ok
- after 500 ->
- ct:log("Time out on openssl port, check that"
- " the messages Hello and world are received"
- " during close of port" , []),
- ok
- end,
-
- true = port_command(OpenSslPort, " world\n"),
-
- Result = ssl_test_lib:wait_for_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpenSslPort),
- ssl_test_lib:close(Client),
-
- Return = case Result of
- ok ->
- [];
- Error ->
- [{CipherSuite, Error}]
- end,
- process_flag(trap_exit, false),
- Return.
-
-start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ClientOpts = ErlangClientOpts ++ ClientOpts0,
-
- {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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = case OpensslServerOpts of
- [] ->
- ["s_server", "-accept",
- integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile,"-key", KeyFile];
- [Opt, Value] ->
- ["s_server", Opt, Value, "-accept",
- integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile,"-key", KeyFile]
- end,
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
-
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
- ClientOpts0 = proplists:get_value(client_rsa_verify_opts, Config),
- ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0],
-
- {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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile],
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
-
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = proplists:get_value(server_rsa_opts, Config),
- ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]} | ServerOpts0],
-
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-alpn", "http/1.0,spdy/2", "-msg", "-port",
- integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-host", "localhost"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
-
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = proplists:get_value(server_rsa_opts, Config),
- ClientOpts0 = proplists:get_value(client_rsa_opts, Config),
- ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]},
- {client_preferred_next_protocols, {client, [<<"spdy/3">>, <<"http/1.1">>]}} | ClientOpts0],
-
- {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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg",
- "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
-
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = proplists:get_value(server_rsa_opts, Config),
- ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]},
- {next_protocols_advertised, [<<"spdy/3">>, <<"http/1.1">>]} | ServerOpts0],
-
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3",
- "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-host", "localhost"],
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0],
-
- {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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile],
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
-
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>]}, ServerOpts0],
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-nextprotoneg", "http/1.0,spdy/2", "-msg", "-connect",
- hostname_format(Hostname) ++ ":"
- ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
-
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-
-start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ServerOpts = ErlangServerOpts ++ ServerOpts0,
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- 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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client"] ++ OpenSSLClientOpts ++ ["-msg", "-connect",
- hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
-
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-
-erlang_ssl_receive_and_assert_negotiated_protocol(Socket, Protocol, Data) ->
- {ok, Protocol} = ssl:negotiated_protocol(Socket),
- erlang_ssl_receive(Socket, Data),
- {ok, Protocol} = ssl:negotiated_protocol(Socket),
- ok.
-
-erlang_ssl_receive(Socket, Data) ->
- ct:log("Connection info: ~p~n",
- [ssl:connection_information(Socket)]),
- receive
- {ssl, Socket, "R\n"} ->
- %% Swallow s_client renegotiation command.
- %% openssl s_client connected commands can appear on
- %% server side with some openssl versions.
- erlang_ssl_receive(Socket,Data);
- {ssl, Socket, Data} ->
- io:format("Received ~p~n",[Data]),
- %% open_ssl server sometimes hangs waiting in blocking read
- ssl:send(Socket, "Got it"),
- ok;
- {ssl, Socket, Byte} when length(Byte) == 1 ->
- erlang_ssl_receive(Socket, tl(Data));
- {Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
- erlang_ssl_receive(Socket,Data);
- Other ->
- ct:fail({unexpected_message, Other})
- end.
-
-connection_info(Socket, Version) ->
- case ssl:connection_information(Socket, [version]) of
- {ok, [{version, Version}] = Info} ->
- ct:log("Connection info: ~p~n", [Info]),
- ok;
- {ok, [{version, OtherVersion}]} ->
- {wrong_version, OtherVersion}
- end.
-
-connection_info_result(Socket) ->
- ssl:connection_information(Socket).
-
-
-delayed_send(Socket, [ErlData, OpenSslData]) ->
- ct:sleep(?SLEEP),
- ssl:send(Socket, ErlData),
- erlang_ssl_receive(Socket, OpenSslData).
-
-server_sent_garbage(Socket) ->
- receive
- server_sent_garbage ->
- {error, closed} == ssl:send(Socket, "data")
-
- end.
-
-send_wait_send(Socket, [ErlData, OpenSslData]) ->
- ssl:send(Socket, ErlData),
- ct:sleep(?SLEEP),
- ssl:send(Socket, ErlData),
- erlang_ssl_receive(Socket, OpenSslData).
-
-check_openssl_sni_support(Config) ->
- HelpText = os:cmd("openssl s_client --help"),
- case string:str(HelpText, "-servername") of
- 0 ->
- {skip, "Current openssl doesn't support SNI"};
- _ ->
- Config
- end.
-
-check_openssl_npn_support(Config) ->
- HelpText = os:cmd("openssl s_client --help"),
- case string:str(HelpText, "nextprotoneg") of
- 0 ->
- {skip, "Openssl not compiled with nextprotoneg support"};
- _ ->
- Config
- end.
-
-check_openssl_alpn_support(Config) ->
- HelpText = os:cmd("openssl s_client --help"),
- case string:str(HelpText, "alpn") of
- 0 ->
- {skip, "Openssl not compiled with alpn support"};
- _ ->
- Config
- end.
-
-check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1';
- Version == 'tlsv1.2' ->
- case os:cmd("openssl version") of
- "OpenSSL 1.0.1c" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 1.0.1b" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 1.0.1a" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 1.0.1 " ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- _ ->
- check_sane_openssl_renegotaite(Config)
- end;
-check_sane_openssl_renegotaite(Config, _) ->
- check_sane_openssl_renegotaite(Config).
-
-check_sane_openssl_renegotaite(Config) ->
- case os:cmd("openssl version") of
- "OpenSSL 1.0.0" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 0.9.8" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 0.9.7" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- _ ->
- Config
- end.
-
-workaround_openssl_s_clinent() ->
- %% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159
- %% https://bugs.archlinux.org/task/33919
- %% Bug seems to manifests it self if TLS version is not
- %% explicitly specified
- case os:cmd("openssl version") of
- "OpenSSL 1.0.1c" ++ _ ->
- ["-no_tls1_2"];
- "OpenSSL 1.0.1d" ++ _ ->
- ["-no_tls1_2"];
- "OpenSSL 1.0.1e" ++ _ ->
- ["-no_tls1_2"];
- "OpenSSL 1.0.1f" ++ _ ->
- ["-no_tls1_2"];
- _ ->
- []
- end.
-
-openssl_client_args(false, Hostname, Port) ->
- ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port)];
-openssl_client_args(true, Hostname, Port) ->
- ["s_client", "-no_ssl2", "-connect", Hostname ++ ":" ++ integer_to_list(Port)].
-
-openssl_client_args(false, Hostname, Port, ServerName) ->
- ["s_client", "-connect", Hostname ++ ":" ++
- integer_to_list(Port), "-servername", ServerName];
-openssl_client_args(true, Hostname, Port, ServerName) ->
- ["s_client", "-no_ssl2", "-connect", Hostname ++ ":" ++
- integer_to_list(Port), "-servername", ServerName].
-
-hostname_format(Hostname) ->
- case lists:member($., Hostname) of
- true ->
- Hostname;
- false ->
- "localhost"
- end.
-
-no_low_flag("-no_ssl2" = Flag) ->
- case ssl_test_lib:supports_ssl_tls_version(sslv2) of
- true ->
- Flag;
- false ->
- ""
- end;
-no_low_flag(Flag) ->
- Flag.
-
-
-openssl_has_common_ciphers(Ciphers) ->
- OCiphers = ssl_test_lib:common_ciphers(openssl),
- has_common_ciphers(Ciphers, OCiphers).
-
-has_common_ciphers([], OCiphers) ->
- false;
-has_common_ciphers([Cipher | Rest], OCiphers) ->
- case lists:member(Cipher, OCiphers) of
- true ->
- true;
- _ ->
- has_common_ciphers(Rest, OCiphers)
- end.
diff --git a/lib/ssl/test/ssl_upgrade_SUITE.erl b/lib/ssl/test/ssl_upgrade_SUITE.erl
index 875399db76..ead18aeb73 100644
--- a/lib/ssl/test/ssl_upgrade_SUITE.erl
+++ b/lib/ssl/test/ssl_upgrade_SUITE.erl
@@ -47,10 +47,7 @@ init_per_suite(Config0) ->
{skip, Reason} ->
{skip, Reason};
Config ->
- Result =
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config),
- proplists:get_value(priv_dir, Config)),
- ssl_test_lib:cert_options(Config)
+ ssl_test_lib:make_rsa_cert(Config)
end
catch _:_ ->
{skip, "Crypto did not start"}
@@ -149,8 +146,8 @@ use_connection(Socket) ->
end.
soft_start_connection(Config, ResulProxy) ->
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, ResulProxy},
@@ -166,8 +163,8 @@ soft_start_connection(Config, ResulProxy) ->
{Server, Client}.
restart_start_connection(Config, ResulProxy) ->
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, ResulProxy},
diff --git a/lib/ssl/test/tls_1_3_record_SUITE.erl b/lib/ssl/test/tls_1_3_record_SUITE.erl
new file mode 100644
index 0000000000..5df8853b1b
--- /dev/null
+++ b/lib/ssl/test/tls_1_3_record_SUITE.erl
@@ -0,0 +1,973 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(tls_1_3_record_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/tls_record.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+-include_lib("ssl/src/ssl_cipher.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+
+all() ->
+ [encode_decode,
+ finished_verify_data,
+ '1_RTT_handshake'].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try (ok == crypto:start()) andalso ssl_test_lib:sufficient_crypto_support('tlsv1.3') of
+ true ->
+ ssl_test_lib:clean_start(),
+ Config;
+ false ->
+ {skip, "Not enough crypto support for TLS-1.3"}
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+encode_decode() ->
+ [{doc,"Test TLS 1.3 record encode/decode functions"}].
+
+encode_decode(_Config) ->
+ ConnectionStates =
+ #{current_read =>
+ #{beast_mitigation => one_n_minus_one,
+ cipher_state =>
+ {cipher_state,
+ <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
+ 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
+ <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
+ 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
+ undefined,undefined,undefined,16},
+ client_verify_data => undefined,compression_state => undefined,
+ mac_secret => undefined,secure_renegotiation => undefined,
+ security_parameters =>
+ {security_parameters,
+ <<19,2>>,
+ 0,8,2,undefined,undefined,undefined,undefined,undefined,
+ sha384,undefined,undefined,
+ {handshake_secret,
+ <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
+ 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
+ 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
+ 157>>},
+ undefined,
+ <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
+ 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
+ undefined},
+ sequence_number => 0,server_verify_data => undefined},
+ current_write =>
+ #{beast_mitigation => one_n_minus_one,
+ cipher_state =>
+ {cipher_state,
+ <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
+ 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
+ <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
+ 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
+ undefined,undefined,undefined,16},
+ client_verify_data => undefined,compression_state => undefined,
+ mac_secret => undefined,secure_renegotiation => undefined,
+ security_parameters =>
+ {security_parameters,
+ <<19,2>>,
+ 0,8,2,undefined,undefined,undefined,undefined,undefined,
+ sha384,undefined,undefined,
+ {handshake_secret,
+ <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
+ 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
+ 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
+ 157>>},
+ undefined,
+ <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
+ 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
+ undefined},
+ sequence_number => 0,server_verify_data => undefined}},
+
+ PlainText = [11,
+ <<0,2,175>>,
+ <<0,0,2,171,0,2,166,48,130,2,162,48,130,1,138,2,9,0,186,57,220,137,88,255,
+ 191,235,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,18,49,16,48,14,6,3,85,
+ 4,3,12,7,84,101,115,116,32,67,65,48,30,23,13,49,56,48,53,48,52,49,52,49,50,
+ 51,56,90,23,13,50,56,48,50,48,52,49,52,49,50,51,56,90,48,20,49,18,48,16,6,
+ 3,85,4,3,12,9,108,111,99,97,108,104,111,115,116,48,130,1,34,48,13,6,9,42,
+ 134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,169,40,
+ 144,176,121,63,134,97,144,126,243,183,225,157,37,131,183,225,87,243,23,88,
+ 230,70,9,134,32,147,7,27,167,98,51,81,224,75,199,12,229,251,195,207,75,179,
+ 181,78,128,3,255,44,58,39,43,172,142,45,186,58,51,65,187,199,154,153,245,
+ 70,133,137,1,27,87,42,116,65,251,129,109,145,233,97,171,71,54,213,185,74,
+ 209,166,11,218,189,119,206,86,170,60,212,213,85,189,30,50,215,23,185,53,
+ 132,238,132,176,198,250,139,251,198,221,225,128,109,113,23,220,39,143,71,
+ 30,59,189,51,244,61,158,214,146,180,196,103,169,189,221,136,78,129,216,148,
+ 2,9,8,65,37,224,215,233,13,209,21,235,20,143,33,74,59,53,208,90,152,94,251,
+ 54,114,171,39,88,230,227,158,211,135,37,182,67,205,161,59,20,138,58,253,15,
+ 53,48,8,157,9,95,197,9,177,116,21,54,9,125,78,109,182,83,20,16,234,223,116,
+ 41,155,123,87,77,17,120,153,246,239,124,130,105,219,166,146,242,151,66,198,
+ 75,72,63,28,246,86,16,244,223,22,36,50,15,247,222,98,6,152,136,154,72,150,
+ 73,127,2,3,1,0,1,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,76,
+ 33,54,160,229,219,219,193,150,116,245,252,18,39,235,145,86,12,167,171,52,
+ 117,166,30,83,5,216,245,177,217,247,95,1,136,94,246,212,108,248,230,111,
+ 225,202,189,6,129,8,70,128,245,18,204,215,87,82,129,253,227,122,66,182,184,
+ 189,30,193,169,144,218,216,109,105,110,215,144,60,104,162,178,101,164,218,
+ 122,60,37,41,143,57,150,52,59,51,112,238,113,239,168,114,69,183,143,154,73,
+ 61,58,80,247,172,95,251,55,28,186,28,200,206,230,118,243,92,202,189,49,76,
+ 124,252,76,0,247,112,85,194,69,59,222,163,228,103,49,110,104,109,251,155,
+ 138,9,37,167,49,189,48,134,52,158,185,129,24,96,153,196,251,90,206,76,239,
+ 175,119,174,165,133,108,222,125,237,125,187,149,152,83,190,16,202,94,202,
+ 201,40,218,22,254,63,189,41,174,97,140,203,70,18,196,118,237,175,134,79,78,
+ 246,2,61,54,77,186,112,32,17,193,192,188,217,252,215,200,7,245,180,179,132,
+ 183,212,229,155,15,152,206,135,56,81,88,3,123,244,149,110,182,72,109,70,62,
+ 146,152,146,151,107,126,216,210,9,93,0,0>>],
+
+ {[_Header|Encoded], _} = tls_record_1_3:encode_plain_text(22, PlainText, ConnectionStates),
+ CipherText = #ssl_tls{type = 23, version = {3,3}, fragment = Encoded},
+
+ {#ssl_tls{type = 22, version = {3,4}, fragment = DecodedText}, _} =
+ tls_record_1_3:decode_cipher_text(CipherText, ConnectionStates),
+
+ DecodedText = iolist_to_binary(PlainText),
+ ct:log("Decoded: ~p ~n", [DecodedText]),
+ ok.
+%%--------------------------------------------------------------------
+'1_RTT_handshake'() ->
+ [{doc,"Test TLS 1.3 1-RTT Handshake"}].
+
+'1_RTT_handshake'(_Config) ->
+ %% ConnectionStates with NULL cipher
+ ConnStatesNull =
+ #{current_write =>
+ #{security_parameters =>
+ #security_parameters{cipher_suite = ?TLS_NULL_WITH_NULL_NULL},
+ sequence_number => 0
+ }
+ },
+
+ %% {client} construct a ClientHello handshake message:
+ %%
+ %% ClientHello (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
+ %% ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
+ %% 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
+ %% 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
+ %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
+ %% 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
+ %% 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
+ %% af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
+ %% 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
+ %% 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ %%
+ %% {client} send handshake record:
+ %%
+ %% payload (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 ba
+ %% 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 02
+ %% 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b 00
+ %% 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12
+ %% 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00
+ %% 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d
+ %% 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af
+ %% 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02
+ %% 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02
+ %% 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ %%
+ %% complete record (201 octets): 16 03 01 00 c4 01 00 00 c0 03 03 cb
+ %% 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
+ %% ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
+ %% 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
+ %% 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
+ %% 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
+ %% e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
+ %% 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
+ %% 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
+ %% 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ ClientHello =
+ hexstr2bin("01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
+ ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
+ 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
+ 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
+ 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
+ 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
+ 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
+ af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
+ 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
+ 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
+
+ ClientHelloRecord =
+ %% Current implementation always sets
+ %% legacy_record_version to Ox0303
+ hexstr2bin("16 03 03 00 c4 01 00 00 c0 03 03 cb
+ 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
+ ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
+ 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
+ 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
+ 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
+ e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
+ 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
+ 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
+ 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
+
+ {CHEncrypted, _} =
+ tls_record:encode_handshake(ClientHello, {3,4}, ConnStatesNull),
+ ClientHelloRecord = iolist_to_binary(CHEncrypted),
+
+ %% {server} extract secret "early":
+ %%
+ %% salt: 0 (all zero octets)
+ %%
+ %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %%
+ %% secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
+ %% e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
+ HKDFAlgo = sha256,
+ Salt = binary:copy(<<?BYTE(0)>>, 32),
+ IKM = binary:copy(<<?BYTE(0)>>, 32),
+ EarlySecret =
+ hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
+ e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"),
+
+ {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}),
+
+ %% {client} create an ephemeral x25519 key pair:
+ %%
+ %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78
+ %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05
+ %%
+ %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
+ %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c
+ CPublicKey =
+ hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
+ ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"),
+
+ %% {server} create an ephemeral x25519 key pair:
+ %%
+ %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
+ %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e
+ %%
+ %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
+ %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f
+ SPrivateKey =
+ hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
+ 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"),
+
+ SPublicKey =
+ hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
+ 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"),
+
+ %% {server} construct a ServerHello handshake message:
+ %%
+ %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60
+ %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
+ %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
+ %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
+ %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+ ServerHello =
+ hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60
+ dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
+ d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
+ 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
+ dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
+
+ %% {server} derive secret for handshake "tls13 derived":
+ %%
+ %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2
+ %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
+ %%
+ %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
+ %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
+ Hash =
+ hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
+
+ Hash = crypto:hash(HKDFAlgo, <<>>),
+
+ Info =
+ hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
+
+ Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ Expanded =
+ hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
+ b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"),
+
+ Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo),
+
+ %% {server} extract secret "handshake":
+ %%
+ %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97
+ %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
+ %%
+ %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
+ %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d
+ %%
+ %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
+ %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+
+ %% salt = Expanded
+ HandshakeIKM =
+ hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
+ 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"),
+
+ HandshakeSecret =
+ hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
+ 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"),
+
+ HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519),
+
+ {handshake_secret, HandshakeSecret} =
+ tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM,
+ {early_secret, EarlySecret}),
+
+ %% {server} derive secret "tls13 c hs traffic":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
+ %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
+ %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
+
+ %% PRK = HandshakeSecret
+ CHSTHash =
+ hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ CHSTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
+ 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ CHSTrafficSecret =
+ hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
+ 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"),
+
+ CHSH = <<ClientHello/binary,ServerHello/binary>>,
+ CHSTHash = crypto:hash(HKDFAlgo, CHSH),
+ CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ CHSTrafficSecret =
+ tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
+
+ %% {server} derive secret "tls13 s hs traffic":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
+ %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
+ %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+
+ %% PRK = HandshakeSecret
+ %% hash = CHSTHash
+ SHSTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
+ 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ SHSTrafficSecret =
+ hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
+ 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"),
+
+ SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ SHSTrafficSecret =
+ tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
+
+
+ %% {server} derive secret for master "tls13 derived":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
+ %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
+
+ %% PRK = HandshakeSecret
+ %% hash = Hash
+ %% info = Info
+ MasterDeriveSecret =
+ hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
+ 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"),
+
+ MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo),
+
+ %% {server} extract secret "master":
+ %%
+ %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5
+ %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
+ %%
+ %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %%
+ %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
+ %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+
+ %% salt = MasterDeriveSecret
+ %% IKM = IKM
+ MasterSecret =
+ hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
+ 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"),
+
+ {master_secret, MasterSecret} =
+ tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}),
+
+ %% {server} send handshake record:
+ %%
+ %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e
+ %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2
+ %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11
+ %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69
+ %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+ %%
+ %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6
+ %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
+ %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
+ %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
+ %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+
+ %% payload = ServerHello
+ ServerHelloRecord =
+ hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6
+ af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
+ 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
+ 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
+ cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
+
+ {SHEncrypted, _} =
+ tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull),
+ ServerHelloRecord = iolist_to_binary(SHEncrypted),
+
+ %% {server} derive write traffic keys for handshake data:
+ %%
+ %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
+ %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e
+ %% e4 03 bc
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30
+
+ %% PRK = SHSTrafficSecret
+ WriteKeyInfo =
+ hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"),
+
+ WriteKey =
+ hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"),
+
+ WriteIVInfo =
+ hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"),
+
+ WriteIV =
+ hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"),
+
+ Cipher = aes_128_gcm, %% TODO: get from ServerHello
+
+ WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)),
+ %% TODO: remove hardcoded IV size
+ WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12),
+
+ {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret),
+
+ %% {server} construct an EncryptedExtensions handshake message:
+ %%
+ %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00
+ %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
+ %% 00 02 40 01 00 00 00 00
+ %%
+ %% {server} construct a Certificate handshake message:
+ %%
+ %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
+ %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
+ %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
+ %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
+ %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
+ %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
+ %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
+ %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
+ %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
+ %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
+ %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
+ %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
+ %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
+ %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
+ %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
+ %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
+ %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
+ %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
+ %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
+ %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
+ %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
+ %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00
+ %%
+ %% {server} construct a CertificateVerify handshake message:
+ %%
+ %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c
+ %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
+ %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
+ %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
+ %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
+ %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
+ %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3
+ EncryptedExtensions =
+ hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00
+ 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
+ 00 02 40 01 00 00 00 00"),
+
+ Certificate =
+ hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
+ 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
+ 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
+ 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
+ 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
+ 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
+ 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
+ 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
+ d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
+ 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
+ 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
+ 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
+ ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
+ 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
+ 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
+ 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
+ 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
+ e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
+ 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
+ c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
+ 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
+ 96 12 29 ac 91 87 b4 2b 4d e1 00 00"),
+
+ CertificateVerify =
+ hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c
+ 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
+ b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
+ 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
+ be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
+ 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
+ 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"),
+
+ %% {server} calculate finished "tls13 finished":
+ %%
+ %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
+ %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+ %%
+ %% hash (0 octets): (empty)
+ %%
+ %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
+ %% 64 00
+ %%
+ %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
+ %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8
+ %%
+ %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
+ %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18
+
+ %% PRK = SHSTrafficSecret
+ FInfo =
+ hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
+ 64 00"),
+
+ FExpanded =
+ hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
+ c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"),
+
+ FinishedVerifyData =
+ hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
+ de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"),
+
+ FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)),
+
+ FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo),
+
+ MessageHistory0 = [CertificateVerify,
+ Certificate,
+ EncryptedExtensions,
+ ServerHello,
+ ClientHello],
+
+ FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0),
+
+ %% {server} construct a Finished handshake message:
+ %%
+ %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
+ %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
+ %% 18
+ FinishedHSBin =
+ hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
+ dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
+ 18"),
+
+ FinishedHS = #finished{verify_data = FinishedVerifyData},
+
+ FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}),
+ FinishedHSBin = iolist_to_binary(FinishedIOList),
+
+ %% {server} derive secret "tls13 c ap traffic":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
+ %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
+ %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5
+
+ %% PRK = MasterSecret
+ CAPTHash =
+ hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+ CAPTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
+ 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ CAPTrafficSecret =
+ hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
+ 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"),
+
+ CHSF = <<ClientHello/binary,
+ ServerHello/binary,
+ EncryptedExtensions/binary,
+ Certificate/binary,
+ CertificateVerify/binary,
+ FinishedHSBin/binary>>,
+
+ CAPTHash = crypto:hash(HKDFAlgo, CHSF),
+
+ CAPTInfo =
+ tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ CAPTrafficSecret =
+ tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive secret "tls13 s ap traffic":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
+ %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
+ %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
+
+ %% PRK = MasterSecret
+ %% hash = CAPTHash
+ SAPTInfo =
+ hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
+ 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ SAPTrafficSecret =
+ hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
+ 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"),
+
+ SAPTInfo =
+ tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ SAPTrafficSecret =
+ tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive secret "tls13 exp master":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
+ %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
+ %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
+ %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50
+
+ %% PRK = MasterSecret
+ %% hash = CAPTHash
+ ExporterInfo =
+ hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
+ 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
+ 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ ExporterMasterSecret =
+ hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
+ 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"),
+
+ ExporterInfo =
+ tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ ExporterMasterSecret =
+ tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive write traffic keys for application data:
+ %%
+ %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32
+ %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac
+ %% 92 e3 56
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84
+
+ %% PRK = SAPTrafficsecret
+ %% key info = WriteKeyInfo
+ %% iv info = WrtieIVInfo
+ SWKey =
+ hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"),
+
+ SWIV =
+ hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"),
+
+ {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret),
+
+ %% {server} derive read traffic keys for handshake data:
+ %%
+ %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f
+ %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50
+ %% 25 8d 01
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f
+
+ %% PRK = CHSTrafficsecret
+ %% key info = WriteKeyInfo
+ %% iv info = WrtieIVInfo
+ SRKey =
+ hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"),
+
+ SRIV =
+ hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"),
+
+ {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret).
+
+%%--------------------------------------------------------------------
+finished_verify_data() ->
+ [{doc,"Test TLS 1.3 Finished message handling"}].
+
+finished_verify_data(_Config) ->
+ ClientHello =
+ hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09
+ 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19
+ 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
+ e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
+ f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01
+ 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d
+ 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00
+ 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00
+ 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06
+ 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72
+ d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed
+ 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00
+ 02 01 01 00 2b 00 03 02 03 04"),
+
+ ServerHello =
+ hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79
+ 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89
+ 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
+ e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
+ f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24
+ 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b
+ 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98
+ 28 80 b6 15 00 2b 00 02 03 04"),
+
+ EncryptedExtensions =
+ hexstr2bin("08 00 00 02 00 00"),
+
+ Certificate =
+ hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30
+ 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04
+ 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05
+ 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53
+ 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70
+ 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30
+ 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31
+ 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06
+ 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65
+ 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e
+ 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d
+ 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82
+ 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7
+ b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00
+ 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d
+ bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d
+ f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1
+ f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b
+ 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7
+ f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69
+ ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5
+ ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16
+ 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb
+ 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40
+ 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10
+ d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad
+ 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82
+ 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1
+ ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03
+ 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03
+ 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03
+ 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55
+ 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52
+ cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09
+ 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00
+ 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b
+ fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43
+ 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd
+ 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24
+ f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65
+ 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1
+ 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9
+ 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4
+ ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e
+ 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42
+ c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27
+ cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3
+ 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f
+ 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6
+ 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4
+ 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0
+ 00 00"),
+
+ CertificateVerify =
+ hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d
+ 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75
+ 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8
+ 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13
+ 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73
+ df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b
+ 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2
+ 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84
+ fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c
+ 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5
+ 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79
+ ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a
+ aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7
+ 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b
+ 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36
+ c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe
+ c7 e4 a7 30 f1 36 9f 9e"),
+
+ BaseKey =
+ hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4
+ 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"),
+
+ VerifyData =
+ hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea
+ c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"),
+
+ Messages = [CertificateVerify,
+ Certificate,
+ EncryptedExtensions,
+ ServerHello,
+ ClientHello],
+
+ FinishedKey = tls_v1:finished_key(BaseKey, sha256),
+ VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+hexstr2int(S) ->
+ B = hexstr2bin(S),
+ Bits = size(B) * 8,
+ <<Integer:Bits/integer>> = B,
+ Integer.
+
+hexstr2bin(S) when is_binary(S) ->
+ hexstr2bin(S, <<>>);
+hexstr2bin(S) ->
+ hexstr2bin(list_to_binary(S), <<>>).
+%%
+hexstr2bin(<<>>, Acc) ->
+ Acc;
+hexstr2bin(<<C,T/binary>>, Acc) when C =:= 32; %% SPACE
+ C =:= 10; %% LF
+ C =:= 13 -> %% CR
+ hexstr2bin(T, Acc);
+hexstr2bin(<<X,Y,T/binary>>, Acc) ->
+ I = hex2int(X) * 16 + hex2int(Y),
+ hexstr2bin(T, <<Acc/binary,I>>).
+
+hex2int(C) when $0 =< C, C =< $9 ->
+ C - $0;
+hex2int(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+hex2int(C) when $a =< C, C =< $f ->
+ C - $a + 10.
diff --git a/lib/ssl/test/tls_1_3_version_SUITE.erl b/lib/ssl/test/tls_1_3_version_SUITE.erl
new file mode 100644
index 0000000000..f0b224d4e5
--- /dev/null
+++ b/lib/ssl/test/tls_1_3_version_SUITE.erl
@@ -0,0 +1,153 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(tls_1_3_version_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.3'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], cert_groups()},
+ {rsa, [], tests()},
+ {ecdsa, [], tests()}
+ ].
+
+cert_groups() ->
+ [{group, rsa},
+ {group, ecdsa}].
+
+tests() ->
+ [tls13_client_tls12_server,
+ tls13_client_with_ext_tls12_server,
+ tls12_client_tls13_server].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ [{client_type, erlang}, {server_type, erlang} |
+ Config]
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(rsa, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+init_per_group(ecdsa, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso
+ (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso
+ ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls13_client_tls12_server() ->
+ [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}].
+
+tls13_client_tls12_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+tls13_client_with_ext_tls12_server() ->
+ [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when "
+ "client has TLS 1.3 specsific extensions"}].
+
+tls13_client_with_ext_tls12_server(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {signature_algs_cert, [ecdsa_secp384r1_sha384,
+ ecdsa_secp256r1_sha256,
+ rsa_pss_rsae_sha256,
+ rsa_pkcs1_sha256,
+ {sha256,rsa},{sha256,dsa}]}|ClientOpts0],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+tls12_client_tls13_server() ->
+ [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}].
+
+tls12_client_tls13_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
diff --git a/lib/ssl/test/tls_api_SUITE.erl b/lib/ssl/test/tls_api_SUITE.erl
new file mode 100644
index 0000000000..5a74ec1892
--- /dev/null
+++ b/lib/ssl/test/tls_api_SUITE.erl
@@ -0,0 +1,880 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(tls_api_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/ssl_record.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+
+-define(SLEEP, 500).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], api_tests() -- [sockname]},
+ {'tlsv1.2', [], api_tests()},
+ {'tlsv1.1', [], api_tests()},
+ {'tlsv1', [], api_tests()},
+ {'sslv3', [], api_tests() ++ [ssl3_cipher_suite_limitation]}
+ ].
+
+api_tests() ->
+ [
+ tls_upgrade,
+ tls_upgrade_with_timeout,
+ tls_downgrade,
+ tls_shutdown,
+ tls_shutdown_write,
+ tls_shutdown_both,
+ tls_shutdown_error,
+ tls_client_closes_socket,
+ tls_closed_in_active_once,
+ tls_tcp_msg,
+ tls_tcp_msg_big,
+ tls_dont_crash_on_handshake_garbage,
+ tls_tcp_error_propagation_in_active_mode,
+ peername,
+ sockname,
+ tls_server_handshake_timeout,
+ transport_close,
+ emulated_options,
+ accept_pool,
+ reuseaddr
+ ].
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+tls_upgrade() ->
+ [{doc,"Test that you can upgrade an tcp connection to an ssl connection"}].
+
+tls_upgrade(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ upgrade_result, []}},
+ {tcp_options,
+ [{active, false} | TcpOpts]},
+ {ssl_options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+ {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, upgrade_result, []}},
+ {tcp_options, [binary]},
+ {ssl_options, [{verify, verify_peer},
+ {server_name_indication, Hostname} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+tls_upgrade_with_timeout() ->
+ [{doc,"Test ssl_accept/3"}].
+
+tls_upgrade_with_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE,
+ upgrade_result, []}},
+ {tcp_options,
+ [{active, false} | TcpOpts]},
+ {ssl_options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+ {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, upgrade_result, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, [{verify, verify_peer},
+ {server_name_indication, Hostname} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+tls_downgrade() ->
+ [{doc,"Test that you can downgarde an ssl connection to an tcp connection"}].
+tls_downgrade(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_downgrade_result, [self()]}},
+ {options, [{active, false}, {verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_downgrade_result, [self()]}},
+ {options, [{active, false}, {verify, verify_peer} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ready, Client, ready),
+
+ Server ! go,
+ Client ! go,
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+tls_shutdown() ->
+ [{doc,"Test API function ssl:shutdown/2"}].
+tls_shutdown(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_result, [server]}},
+ {options, [{exit_on_close, false},
+ {active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa,
+ {?MODULE, tls_shutdown_result, [client]}},
+ {options,
+ [{exit_on_close, false},
+ {active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+tls_shutdown_write() ->
+ [{doc,"Test API function ssl:shutdown/2 with option write."}].
+tls_shutdown_write(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_write_result, [server]}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_write_result, [client]}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
+
+%%--------------------------------------------------------------------
+tls_shutdown_both() ->
+ [{doc,"Test API function ssl:shutdown/2 with option both."}].
+tls_shutdown_both(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_both_result, [server]}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_both_result, [client]}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
+
+%%--------------------------------------------------------------------
+tls_shutdown_error() ->
+ [{doc,"Test ssl:shutdown/2 error handling"}].
+tls_shutdown_error(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Port = ssl_test_lib:inet_port(node()),
+ {ok, Listen} = ssl:listen(Port, ServerOpts),
+ {error, enotconn} = ssl:shutdown(Listen, read_write),
+ ok = ssl:close(Listen),
+ {error, closed} = ssl:shutdown(Listen, read_write).
+%%--------------------------------------------------------------------
+tls_client_closes_socket() ->
+ [{doc,"Test what happens when client closes socket before handshake is compleated"}].
+
+tls_client_closes_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Connect = fun() ->
+ {ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect,
+ [Hostname, Port, [binary]]),
+ %% Make sure that ssl_accept is called before
+ %% client process ends and closes socket.
+ ct:sleep(?SLEEP)
+ end,
+
+ _Client = spawn_link(Connect),
+
+ ssl_test_lib:check_result(Server, {error,closed}).
+
+%%--------------------------------------------------------------------
+tls_closed_in_active_once() ->
+ [{doc, "Test that ssl_closed is delivered in active once with non-empty buffer, check ERL-420."}].
+
+tls_closed_in_active_once(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+ Port = ssl_test_lib:inet_port(node()),
+ Server = fun() ->
+ {ok, Listen} = gen_tcp:listen(Port, TcpOpts),
+ {ok, TcpServerSocket} = gen_tcp:accept(Listen),
+ {ok, ServerSocket} = ssl:handshake(TcpServerSocket, ServerOpts),
+ lists:foreach(
+ fun(_) ->
+ ssl:send(ServerSocket, "some random message\r\n")
+ end, lists:seq(1, 20)),
+ %% Close TCP instead of SSL socket to trigger the bug:
+ gen_tcp:close(TcpServerSocket),
+ gen_tcp:close(Listen)
+ end,
+ spawn_link(Server),
+ {ok, Socket} = ssl:connect(Hostname, Port, [{active, false} | ClientOpts]),
+ Result = tls_closed_in_active_once_loop(Socket),
+ ssl:close(Socket),
+ case Result of
+ ok -> ok;
+ _ -> ct:fail(Result)
+ end.
+%%--------------------------------------------------------------------
+tls_tcp_msg() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}].
+
+tls_tcp_msg(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}, {active, false}],
+
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE, dummy, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
+
+ receive
+ {tcp_closed, Socket} ->
+ receive
+ {Server, {error, Error}} ->
+ ct:log("Error ~p", [Error])
+ end
+ end.
+%%--------------------------------------------------------------------
+tls_tcp_msg_big() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"}].
+
+tls_tcp_msg_big(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Rand = crypto:strong_rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE, dummy, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+
+ gen_tcp:send(Socket, <<?BYTE(0),
+ ?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>),
+
+ receive
+ {tcp_closed, Socket} ->
+ receive
+ {Server, {error, timeout}} ->
+ ct:fail("hangs");
+ {Server, {error, Error}} ->
+ ct:log("Error ~p", [Error]);
+ {'EXIT', Server, _} ->
+ ok
+ end
+ end.
+
+%%--------------------------------------------------------------------
+tls_dont_crash_on_handshake_garbage() ->
+ [{doc, "Ensure SSL server worker thows an alert on garbage during handshake "
+ "instead of crashing and exposing state to user code"}].
+
+tls_dont_crash_on_handshake_garbage(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ unlink(Server), monitor(process, Server),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
+
+ % Send hello and garbage record
+ ok = gen_tcp:send(Socket,
+ [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello
+ 16#deadbeef:256, % 32 'random' bytes = 256 bits
+ 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values
+
+ <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage
+ ]),
+ % Send unexpected change_cipher_spec
+ ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>),
+
+ % Ensure we receive an alert, not sudden disconnect
+ {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000).
+
+%%--------------------------------------------------------------------
+tls_tcp_error_propagation_in_active_mode() ->
+ [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}].
+tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, receive_msg, []}},
+ {options, ClientOpts}]),
+
+ {status, _, _, StatusInfo} = sys:get_status(Pid),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ StaticEnv = element(2, State),
+ Socket = element(11, StaticEnv),
+ %% Fake tcp error
+ Pid ! {tcp_error, Socket, etimedout},
+
+ ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
+
+%%--------------------------------------------------------------------
+peername() ->
+ [{doc,"Test API function peername/1"}].
+
+peername(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peername_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peername_result, []}},
+ {options, [{port, 0} | ClientOpts]}]),
+
+ ClientPort = ssl_test_lib:inet_port(Client),
+ ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
+ ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
+ ServerMsg = {ok, {ClientIp, ClientPort}},
+ ClientMsg = {ok, {ServerIp, Port}},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+sockname() ->
+ [{doc,"Test API function sockname/1"}].
+sockname(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, sockname_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, sockname_result, []}},
+ {options, [{port, 0} | ClientOpts]}]),
+
+ ClientPort = ssl_test_lib:inet_port(Client),
+ ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
+ ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
+ ServerMsg = {ok, {ServerIp, Port}},
+ ClientMsg = {ok, {ClientIp, ClientPort}},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+tls_server_handshake_timeout() ->
+ [{doc,"Test server handshake timeout"}].
+
+tls_server_handshake_timeout(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {ssl_test_lib,
+ no_result_msg, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]),
+
+ receive
+ {tcp_closed, CSocket} ->
+ ssl_test_lib:check_result(Server, {error, timeout}),
+ receive
+ {'EXIT', Server, _} ->
+ %% Make sure supervisor had time to react on process exit
+ %% Could we come up with a better solution to this?
+ ct:sleep(500),
+ [] = supervisor:which_children(tls_connection_sup)
+ end
+ end.
+transport_close() ->
+ [{doc, "Test what happens if socket is closed on TCP level after a while of normal operation"}].
+transport_close(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, 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}]]),
+ {ok, SslS} = rpc:call(ClientNode, ssl, connect,
+ [TcpS,[{active, false}|ClientOpts]]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), self(), Server]),
+ ok = ssl:send(SslS, "Hello world"),
+ {ok,<<"Hello world">>} = ssl:recv(SslS, 11),
+ gen_tcp:close(TcpS),
+ {error, _} = ssl:send(SslS, "Hello world").
+
+%%--------------------------------------------------------------------
+ssl3_cipher_suite_limitation() ->
+ [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}].
+ssl3_cipher_suite_limitation(Config) when is_list(Config) ->
+
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
+ ok = gen_tcp:send(Socket,
+ <<22, 3,0, 49:16, % handshake, SSL 3.0, length
+ 1, 45:24, % client_hello, length
+ 3,0, % SSL 3.0
+ 16#deadbeef:256, % 32 'random' bytes = 256 bits
+ 0, % no session ID
+ %% three cipher suites -- null, one with sha256 hash and one with sha hash
+ 6:16, 0,255, 0,61, 0,57,
+ 1, 0 % no compression
+ >>),
+ {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000),
+ {ok, <<HelloBin:HelloLen/binary>>} = gen_tcp:recv(Socket, HelloLen, 5000),
+ ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin),
+ case ServerHello of
+ #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} ->
+ ok;
+ _ ->
+ ct:fail({unexpected_server_hello, ServerHello})
+ end.
+%%--------------------------------------------------------------------
+emulated_options() ->
+ [{doc,"Test API function getopts/2 and setopts/2"}].
+
+emulated_options(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ 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, tls_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, tls_socket_options_result,
+ [Options, Values, NewOptions, NewValues]}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+
+ {ok, Listen} = ssl:listen(0, ServerOpts),
+ {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
+ ok = ssl:setopts(Listen, [{mode, binary}]),
+ {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
+ {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
+ ssl:close(Listen).
+accept_pool() ->
+ [{doc,"Test having an accept pool."}].
+accept_pool(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {accepters, 3},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server0),
+ [Server1, Server2] = ssl_test_lib:accepters(2),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}
+ ]),
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}
+ ]),
+
+ Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}
+ ]),
+
+ ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]),
+
+ ssl_test_lib:close(Server0),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Server2),
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Client1),
+ ssl_test_lib:close(Client2).
+
+%%--------------------------------------------------------------------
+reuseaddr() ->
+ [{doc,"Test reuseaddr option"}].
+
+reuseaddr(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{active, false}, {reuseaddr, true}| ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{active, false} | ClientOpts]}]),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false}, {reuseaddr, true} | ServerOpts]}]),
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server1, ok, Client1, ok),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+upgrade_result(Socket) ->
+ ssl:setopts(Socket, [{active, true}]),
+ ok = ssl:send(Socket, "Hello world"),
+ %% Make sure binary is inherited from tcp socket and that we do
+ %% not get the list default!
+ receive
+ {ssl, _, <<"H">>} ->
+ receive
+ {ssl, _, <<"ello world">>} ->
+ ok
+ end;
+ {ssl, _, <<"Hello world">>} ->
+ ok
+ end.
+tls_downgrade_result(Socket, Pid) ->
+ ok = ssl_test_lib:send_recv_result(Socket),
+ Pid ! {self(), ready},
+ receive
+ go ->
+ ok
+ end,
+ case ssl:close(Socket, {self(), 10000}) of
+ {ok, TCPSocket} ->
+ inet:setopts(TCPSocket, [{active, true}]),
+ gen_tcp:send(TCPSocket, "Downgraded"),
+ receive
+ {tcp, TCPSocket, <<"Downgraded">>} ->
+ ok;
+ {tcp_closed, TCPSocket} ->
+ ct:fail("Peer timed out, downgrade aborted"),
+ ok;
+ Other ->
+ {error, Other}
+ end;
+ {error, timeout} ->
+ ct:fail("Timed out, downgrade aborted"),
+ ok;
+ Fail ->
+ {error, Fail}
+ end.
+
+tls_shutdown_result(Socket, server) ->
+ ssl:send(Socket, "Hej"),
+ ok = ssl:shutdown(Socket, write),
+ {ok, "Hej hopp"} = ssl:recv(Socket, 8),
+ ok;
+
+tls_shutdown_result(Socket, client) ->
+ ssl:send(Socket, "Hej hopp"),
+ ok = ssl:shutdown(Socket, write),
+ {ok, "Hej"} = ssl:recv(Socket, 3),
+ ok.
+
+tls_shutdown_write_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, write);
+tls_shutdown_write_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+tls_shutdown_both_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, read_write);
+tls_shutdown_both_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+tls_closed_in_active_once_loop(Socket) ->
+ case ssl:setopts(Socket, [{active, once}]) of
+ ok ->
+ receive
+ {ssl, Socket, _} ->
+ tls_closed_in_active_once_loop(Socket);
+ {ssl_closed, Socket} ->
+ ok
+ after 5000 ->
+ no_ssl_closed_received
+ end;
+ {error, closed} ->
+ ok
+ end.
+
+drop_handshakes(Socket, Timeout) ->
+ {ok, <<RecType:8, _RecMajor:8, _RecMinor:8, RecLen:16>> = Header} = gen_tcp:recv(Socket, 5, Timeout),
+ {ok, <<Frag:RecLen/binary>>} = gen_tcp:recv(Socket, RecLen, Timeout),
+ case RecType of
+ 22 -> drop_handshakes(Socket, Timeout);
+ _ -> {ok, <<Header/binary, Frag/binary>>}
+ end.
+
+receive_msg(_) ->
+ receive
+ Msg ->
+ Msg
+ end.
+
+sockname_result(S) ->
+ ssl:sockname(S).
+
+peername_result(S) ->
+ ssl:peername(S).
+
+tls_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]),
+ ssl:setopts(Socket, [{nodelay, true}]),
+ {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
+ {ok, All} = ssl:getopts(Socket, []),
+ ct:log("All opts ~p~n", [All]),
+ ok.
+
diff --git a/lib/ssl/test/x509_test.erl b/lib/ssl/test/x509_test.erl
index fea01efdaf..faf223ae35 100644
--- a/lib/ssl/test/x509_test.erl
+++ b/lib/ssl/test/x509_test.erl
@@ -22,7 +22,7 @@
-module(x509_test).
- -include_lib("public_key/include/public_key.hrl").
+-include_lib("public_key/include/public_key.hrl").
-export([extensions/1, gen_pem_config_files/3]).