diff options
Diffstat (limited to 'lib/ssl/test')
| -rw-r--r-- | lib/ssl/test/Makefile | 10 | ||||
| -rw-r--r-- | lib/ssl/test/inet_crypto_dist.erl | 1323 | ||||
| -rw-r--r-- | lib/ssl/test/make_certs.erl | 6 | ||||
| -rw-r--r-- | lib/ssl/test/property_test/ssl_eqc_handshake.erl | 812 | ||||
| -rw-r--r-- | lib/ssl/test/ssl.spec | 16 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_basic_SUITE.erl | 1721 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_bench.spec | 1 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_bench_SUITE.erl | 65 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_certificate_verify_SUITE.erl | 5 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_cipher_suite_SUITE.erl | 772 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_dist_bench_SUITE.erl | 183 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_dist_test_lib.erl | 5 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_eqc_SUITE.erl | 58 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_handshake_SUITE.erl | 132 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_npn_hello_SUITE.erl | 42 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_rfc_5869_SUITE.erl | 316 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_session_cache_SUITE.erl | 2 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_test_lib.erl | 277 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_to_openssl_SUITE.erl | 177 | ||||
| -rw-r--r-- | lib/ssl/test/ssl_upgrade_SUITE.erl | 13 | ||||
| -rw-r--r-- | lib/ssl/test/x509_test.erl | 2 | 
21 files changed, 5169 insertions, 769 deletions
| diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index a10f71a3de..f7fae16088 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -43,6 +43,7 @@ MODULES = \  	ssl_basic_SUITE \  	ssl_bench_SUITE \  	ssl_cipher_SUITE \ +        ssl_cipher_suite_SUITE \  	ssl_certificate_verify_SUITE\  	ssl_crl_SUITE\  	ssl_dist_SUITE \ @@ -61,8 +62,11 @@ MODULES = \  	ssl_ECC\  	ssl_upgrade_SUITE\  	ssl_sni_SUITE \ -	make_certs\ -        x509_test +	ssl_eqc_SUITE \ +	ssl_rfc_5869_SUITE \ +	make_certs \ +        x509_test \ +	inet_crypto_dist  ERL_FILES = $(MODULES:%=%.erl) @@ -144,7 +148,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..5aafaac983 --- /dev/null +++ b/lib/ssl/test/inet_crypto_dist.erl @@ -0,0 +1,1323 @@ +%% +%% %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). + +-define(PROTOCOL, inet_crypto_dist_v1). +-define(DEFAULT_BLOCK_CRYPTO, aes_128_gcm). +-define(DEFAULT_HASH_ALGORITHM, sha256). +-define(DEFAULT_REKEY_INTERVAL, 32768). + +-export([listen/1, accept/1, accept_connection/5, +	 setup/5, close/1, select/1, is_node_name/1]). +-export([is_supported/0]). + +%% 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"). + +%% Test if crypto has got enough capabilities for this module to run +%% +is_supported() -> +    try {crypto:cipher_info(?DEFAULT_BLOCK_CRYPTO), +         crypto:hash_info(?DEFAULT_HASH_ALGORITHM)} +    of +        {#{block_size := _, iv_length := _, key_length := _}, +         #{size := _}} -> +            true +    catch +        error:undef -> +            false +    end. + +%% ------------------------------------------------------------------------- +%% 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 as 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'. +%% ------------------------------------------------------------------------- + +%% ------------------------------------------------------------------------- +%% 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, [binary, {nodelay, true}]), +            {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 +    %% +    Config = config(), +    monitor_dist_proc( +      spawn_opt( +        fun () -> +                accept_loop(Listen, Driver, NetKernel, Config) +        end, +        [link, {priority, max}])). + +accept_loop(Listen, Driver, NetKernel, Config) -> +    case Driver:accept(Listen) of +        {ok, Socket} -> +            wait_for_code_server(), +            Timeout = net_kernel:connecttime(), +            DistCtrl = start_dist_ctrl(Socket, Config, Timeout), +            %% DistCtrl is a "socket" +            NetKernel ! +                {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, Config); +        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, +                  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( +              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, Version); +		Other -> +		    ?shutdown2( +                       Node, +                       trace( +                         {port_please_failed, ErlEpmd, Name, Ip, Other})) +	    end; +	Other -> +	    ?shutdown2( +               Node, +               trace({getaddr_failed, Driver, Address, Other})) +    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( +            [binary, {active, false}, {packet, 2}, {nodelay, true}])), +    case Driver:connect(Ip, TcpPort, ConnectOpts) of +        {ok, Socket} -> +            Config = config(), +            DistCtrl = +                start_dist_ctrl(Socket, Config, net_kernel:connecttime()), +            %% 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 -> +            ?shutdown2(Node, +                       trace({connect_failed, Ip, TcpPort, ConnectError})) +    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) -> +    trace(Driver:close(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 = +           fun (S, Packet) when S =:= DistCtrl -> +                   call_dist_ctrl(S, {send, Packet}) +           end, +       f_recv = +           fun (S, 0, infinity) when S =:= DistCtrl -> +                   case call_dist_ctrl(S, recv) of +                       {ok, Bin} when is_binary(Bin) -> +                           {ok, binary_to_list(Bin)}; +                       Error -> +                           Error +                   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 = +           fun (S, Node) when S =:= DistCtrl -> +                   case 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}; +                               _ -> +                                   {error, no_node} +                           end +                   end +           end, +       f_handshake_complete = +           fun (S, _Node, DistHandle) when S =:= DistCtrl -> +                   call_dist_ctrl(S, {handshake_complete, DistHandle}) +           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 = +           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 -> +                           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. + +config() -> +    case init:get_argument(?DIST_NAME) of +        error -> +            error({missing_argument, ?DIST_NAME}); +        {ok, [[String]]} -> +            {ok, Tokens, _} = erl_scan:string(String ++ "."), +            case erl_parse:parse_term(Tokens) of +                {ok, #{secret := Secret} = Config} +                  when is_binary(Secret); is_list(Secret) -> +                    Config; +                {ok, #{} = Config} -> +                    error({missing_secret, [{?DIST_NAME,Config}]}); +                _ -> +                    error({bad_argument_value, [{?DIST_NAME,String}]}) +            end; +        {ok, Value} -> +            error({malformed_argument, [{?DIST_NAME,Value}]}) +    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 +%%% * Proof of usefulness +%%% * Unifying exit reasons using a death_row() function +%%% * Verification (and rejection) of other end's crypto parameters +%%% * OTP:ification (proc_lib?) +%%% * An application to belong to (crypto|kernel?) +%%% * Secret on file (cookie as default?), parameter handling +%%% * Restart and/or code reload policy + +%% Debug client and server + +test_config() -> +    #{secret => <<"Secret Cluster Password 123456">>}. + +test_server() -> +    {ok, Listen} = gen_tcp:listen(0, [{packet, 2}, {active, false}, binary]), +    {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, [{packet, 2}, {active, false}, binary]), +    test(Socket). + +test(Socket) -> +    start_dist_ctrl(Socket, test_config(), 10000). + +%% ------------------------------------------------------------------------- + +start_dist_ctrl(Socket, Config, Timeout) -> +    Protocol = ?PROTOCOL, +    Controller = self(), +    Server = +        monitor_dist_proc( +          spawn_opt( +            fun () -> +                    receive +                        {?MODULE, From, start} -> +                            {SendParams, RecvParams} = +                                init(Socket, Config, Protocol), +                            reply(From, self()), +                            handshake(SendParams, 0, RecvParams, 0, 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} -> +            exit({?PROTOCOL, Reason}) +    after Timeout -> +            exit(Server, timeout), +            receive +                {'DOWN', Ref, process, Server, _} -> +                    exit({?PROTOCOL, timeout}) +            end +    end. + +reply({Ref, Pid}, Msg) -> +    Pid ! {Ref, Msg}, +    ok. + +%% ------------------------------------------------------------------------- + +-record(params, +        {protocol, % Encryption protocol tag +         socket, +         dist_handle, +         hash_algorithm, +         block_crypto, +         rekey_interval, +         iv, +         key, +         tag_len}). + +-define(TCP_ACTIVE, 64). +-define(CHUNK_SIZE, (65536 - 512)). +%% The start chunk starts with zeros, so it seems logical to not have +%% a chunk type with value 0 +-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 message is unencrypted and contains the block cipher and hash +%% algorithms the sender will use, the IV and a key salt.  Both sides' +%% key salt is used with the mutual secret as input to the hash algorithm +%% to create different encryption/decryption keys for both directions. +%% +%% The start message is the first encrypted message and contains just +%% encrypted zeros the width of the key, with the header of the init +%% message as AAD data.  Successfully decrypting this message +%% verifies that we have an encrypted channel. +%% +%% Subsequent encrypted messages has the sequence number and the length +%% of the message as AAD data.  These messages has got a message type +%% differentiating data from ticks.  Ticks have a random size in an +%% attempt to make them less obvious to spot. +%% +%% 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, Config, Protocol) -> +    Secret = maps:get(secret, Config), +    HashAlgorithm = +        maps:get(hash_algorithm, Config, ?DEFAULT_HASH_ALGORITHM), +    BlockCrypto = +        maps:get(block_crypto, Config, ?DEFAULT_BLOCK_CRYPTO), +    RekeyInterval = +        maps:get(rekey_interval, Config, ?DEFAULT_REKEY_INTERVAL), +    %% +    SendParams = +        init_params( +          Socket, Protocol, HashAlgorithm, BlockCrypto, RekeyInterval), +    send_init(SendParams, Secret). + +send_init( +  #params{ +     protocol = Protocol, +     socket = Socket, +     block_crypto = BlockCrypto, +     iv = IVLen, +     key = KeyLen, +     hash_algorithm = HashAlgorithm} = SendParams, +  Secret) -> +    %% +    ProtocolString = atom_to_binary(Protocol, utf8), +    BlockCryptoString = atom_to_binary(BlockCrypto, utf8), +    HashAlgorithmString = atom_to_binary(HashAlgorithm, utf8), +    SendHeader = +        <<ProtocolString/binary, 0, +          HashAlgorithmString/binary, 0, +          BlockCryptoString/binary, 0>>, +    <<IV:IVLen/binary, KeySalt:KeyLen/binary>> = IV_KeySalt = +        crypto:strong_rand_bytes(IVLen + KeyLen), +    InitPacket = [SendHeader, IV_KeySalt], +    ok = gen_tcp:send(Socket, InitPacket), +    recv_init(SendParams#params{iv = IV, key = KeySalt}, Secret, SendHeader). + +recv_init( +  #params{ +     socket = Socket, +     hash_algorithm = SendHashAlgorithm, +     key = SendKeySalt} = SendParams, Secret, SendHeader) -> +    %% +    {ok, InitPacket} = gen_tcp:recv(Socket, 0), +    [ProtocolString, Rest_1] = binary:split(InitPacket, <<0>>), +    Protocol = binary_to_existing_atom(ProtocolString, utf8), +    case Protocol of +        ?PROTOCOL -> +            [HashAlgorithmString, Rest_2] = binary:split(Rest_1, <<0>>), +            HashAlgorithm = binary_to_existing_atom(HashAlgorithmString, utf8), +            [BlockCryptoString, Rest_3] = binary:split(Rest_2, <<0>>), +            BlockCrypto = binary_to_existing_atom(BlockCryptoString, utf8), +            #params{ +               hash_algorithm = RecvHashAlgorithm, +               iv = RecvIVLen, +               key = RecvKeyLen} = RecvParams = +                init_params( +                  Socket, Protocol, HashAlgorithm, BlockCrypto, undefined), +            <<RecvIV:RecvIVLen/binary, +              RecvKeySalt:RecvKeyLen/binary>> = Rest_3, +            SendKey = +                hash_key(SendHashAlgorithm, SendKeySalt, [RecvKeySalt, Secret]), +            RecvKey = +                hash_key(RecvHashAlgorithm, RecvKeySalt, [SendKeySalt, Secret]), +            SendParams_1 = SendParams#params{key = SendKey}, +            RecvParams_1 = RecvParams#params{iv = RecvIV, key = RecvKey}, +            RecvHeaderLen = byte_size(InitPacket) - RecvIVLen - RecvKeyLen, +            <<RecvHeader:RecvHeaderLen/binary, _/binary>> = InitPacket, +            send_start(SendParams_1, SendHeader), +            RecvRekeyInterval = recv_start(RecvParams_1, RecvHeader), +            {SendParams_1, +             RecvParams_1#params{rekey_interval = RecvRekeyInterval}} +    end. + +send_start( +  #params{ +     socket = Socket, +     block_crypto = BlockCrypto, +     rekey_interval= RekeyInterval, +     iv = IV, +     key = Key, +     tag_len = TagLen}, AAD) -> +    %% +    KeyLen = byte_size(Key), +    Zeros = binary:copy(<<0>>, KeyLen), +    {Ciphertext, CipherTag} = +        crypto:block_encrypt( +          crypto_cipher_name(BlockCrypto), +          Key, IV, {AAD, [Zeros, <<RekeyInterval:32>>], TagLen}), +    ok = gen_tcp:send(Socket,  [Ciphertext, CipherTag]). + +recv_start( +  #params{ +     socket = Socket, +     block_crypto = BlockCrypto, +     iv = IV, +     key = Key, +     tag_len = TagLen}, AAD) -> +    {ok, Packet} = gen_tcp:recv(Socket, 0), +    KeyLen = byte_size(Key), +    PacketLen = KeyLen + 4, +    <<Ciphertext:PacketLen/binary, CipherTag:TagLen/binary>> = Packet, +    Zeros = binary:copy(<<0>>, KeyLen), +    case +        crypto:block_decrypt( +          crypto_cipher_name(BlockCrypto), +          Key, IV, {AAD, Ciphertext, CipherTag}) +    of +        <<Zeros:KeyLen/binary, RekeyInterval:32>> +          when 1 =< RekeyInterval -> +            RekeyInterval; +        _ -> +            error(decrypt_error) +    end. + +init_params(Socket, Protocol, HashAlgorithm, BlockCrypto, RekeyInterval) -> +    #{block_size := 1, +      iv_length := IVLen, +      key_length := KeyLen} = crypto:cipher_info(BlockCrypto), +    case crypto:hash_info(HashAlgorithm) of +        #{size := HashSize} when HashSize >= KeyLen -> +            #params{ +               socket = Socket, +               protocol = Protocol, +               hash_algorithm = HashAlgorithm, +               block_crypto = BlockCrypto, +               rekey_interval = RekeyInterval, +               iv = IVLen, +               key = KeyLen, +               tag_len = 16} +    end. + +crypto_cipher_name(BlockCrypto) -> +    case BlockCrypto of +        aes_128_gcm -> aes_gcm; +        aes_192_gcm -> aes_gcm; +        aes_256_gcm -> aes_gcm +    end. + +hash_key(HashAlgorithm, KeySalt, OtherSalt) -> +    KeyLen = byte_size(KeySalt), +    <<Key:KeyLen/binary, _/binary>> = +        crypto:hash(HashAlgorithm, [KeySalt, OtherSalt]), +    Key. + +%% ------------------------------------------------------------------------- +%% 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}} -> +            reply(From, ok), +            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, +            process_flag(priority, normal), +            erlang:dist_ctrl_get_data_notification(DistHandle), +            crypto:rand_seed_alg(crypto_cache), +            output_handler( +              SendParams#params{dist_handle = DistHandle}, SendSeq); +        %% +        {?MODULE, From, {send, Data}} -> +            {SendParams_1, SendSeq_1} = +                encrypt_and_send_chunk( +                  SendParams, SendSeq, [?HANDSHAKE_CHUNK, Data]), +            reply(From, ok), +            handshake( +              SendParams_1, SendSeq_1, RecvParams, RecvSeq, Controller); +        {?MODULE, From, recv} -> +            {RecvParams_1, RecvSeq_1, Reply} = +                recv_and_decrypt_chunk(RecvParams, RecvSeq), +            reply(From, Reply), +            handshake( +              SendParams, SendSeq, RecvParams_1, RecvSeq_1, Controller); +        {?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}}; +                #params{} = RecvParams_1 -> +                    recv_and_decrypt_chunk(RecvParams_1, 0); +                _ -> +                    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 +                    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 +                    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, true), +            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 +                    output_handler_tick(Params, Seq) +            end +    after 0 -> +            TickSize = 8 + rand:uniform(56), +            TickData = binary:copy(<<0>>, TickSize), +            {Params_1, Seq_1} = +                encrypt_and_send_chunk(Params, Seq, [?TICK_CHUNK, TickData]), +            output_handler(Params_1, Seq_1) +    end. + +output_handler_send( +  #params{dist_handle = DistHandle} = Params, Seq, {_, Size, _} = Q, Retry) -> +    %% +    if +        ?CHUNK_SIZE < Size -> +            {Cleartext, Q_1} = deq_iovec(?CHUNK_SIZE, Q), +            {Params_1, Seq_1} = +                encrypt_and_send_chunk(Params, Seq, [?DATA_CHUNK, Cleartext]), +            output_handler_send(Params_1, Seq_1, Q_1, Retry); +        Retry -> +            Q_1 = get_data(DistHandle, Q), +            output_handler_send(Params, Seq, Q_1, false); +        true -> +            {Cleartext, _} = deq_iovec(Size, Q), +            encrypt_and_send_chunk(Params, Seq, [?DATA_CHUNK, Cleartext]) +    end. + +%% ------------------------------------------------------------------------- +%% Input handler process +%% +%% Here is T 0 or 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, Chunk); +                {tcp_closed, Socket} -> +                    error(connection_closed); +                _Other -> +                    %% Ignore... +                    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, 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, 0); +        #params{} = Params_1 -> +            input_handler(Params_1, 0, Q, 0); +        _ -> +            error(decrypt_error) +    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, +     key = Key, iv = IV, hash_algorithm = HashAlgorithm} = Params, +  Seq, Cleartext) -> +    %% +    KeyLen = byte_size(Key), +    IVLen = byte_size(IV), +    Chunk = <<IV_1:IVLen/binary, KeySalt:KeyLen/binary>> = +        crypto:strong_rand_bytes(IVLen + KeyLen), +    ok = gen_tcp:send(Socket, encrypt_chunk(Params, Seq, [?REKEY_CHUNK, Chunk])), +    Key_1 = hash_key(HashAlgorithm, Key, KeySalt), +    Params_1 = Params#params{key = Key_1, iv = IV_1}, +    ok = gen_tcp:send(Socket, encrypt_chunk(Params_1, 0, Cleartext)), +    {Params_1, 1}; +encrypt_and_send_chunk(#params{socket = Socket} = Params, Seq, Cleartext) -> +    ok = gen_tcp:send(Socket, encrypt_chunk(Params, Seq, Cleartext)), +    {Params, Seq + 1}. + +encrypt_chunk( +  #params{ +     block_crypto = BlockCrypto, +     iv = IV, key = Key, tag_len = TagLen}, Seq, Cleartext) -> +    %% +    ChunkLen = iolist_size(Cleartext) + TagLen, +    AAD = <<Seq:32, ChunkLen:32>>, +    {Ciphertext, CipherTag} = +        crypto:block_encrypt( +          crypto_cipher_name(BlockCrypto), Key, IV, {AAD, Cleartext, TagLen}), +    Chunk = [Ciphertext,CipherTag], +    Chunk. + +decrypt_chunk( +  #params{ +     block_crypto = BlockCrypto, +     iv = IV, key = Key, tag_len = TagLen} = Params, Seq, Chunk) -> +    %% +    ChunkLen = byte_size(Chunk), +    true = TagLen =< ChunkLen, % Assert +    AAD = <<Seq:32, ChunkLen:32>>, +    CiphertextLen = ChunkLen - TagLen, +    <<Ciphertext:CiphertextLen/binary, CipherTag:TagLen/binary>> = Chunk, +    block_decrypt( +      Params, Seq, crypto_cipher_name(BlockCrypto), +      Key, IV, {AAD, Ciphertext, CipherTag}). + +block_decrypt( +  #params{rekey_interval = Seq} = Params, Seq, CipherName, Key, IV, Data) -> +    %% +    KeyLen = byte_size(Key), +    IVLen = byte_size(IV), +    case crypto:block_decrypt(CipherName, Key, IV, Data) of +        <<?REKEY_CHUNK, IV_1:IVLen/binary, KeySalt:KeyLen/binary>> -> +            Key_1 = hash_key(Params#params.hash_algorithm, Key, KeySalt), +            Params#params{iv = IV_1, key = Key_1}; +        _ -> +            error(decrypt_error) +    end; +block_decrypt(_Params, _Seq, CipherName, Key, IV, Data) -> +    crypto:block_decrypt(CipherName, Key, IV, Data). + +%% ------------------------------------------------------------------------- +%% 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. + +%% ------------------------------------------------------------------------- + +%% Trace point +trace(Term) -> Term. + +%% Keep an eye on this Pid (debug) +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. + +dbg() -> +    dbg:stop(), +    dbg:tracer(), +    dbg:p(all, c), +    dbg:tpl(?MODULE, 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/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl new file mode 100644 index 0000000000..38a4b7fb11 --- /dev/null +++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl @@ -0,0 +1,812 @@ +%% +%% %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)     +                 }. + +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(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, 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(client_hello), undefined]), +           %% oneof([pre_shared_key(), 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_exhange_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, server_hello) -> +    ?LET({ +          KeyShare, +          %% PreSharedKeys, +          SupportedVersions +         }, +         { +          oneof([key_share(server_hello), undefined]), +          %% oneof([pre_shared_keys(),  undefined]), +          oneof([server_hello_selected_version()]) +         }, +         maps:filter(fun(_, undefined) -> +                             false; +                        (_,_) -> +                             true +                     end, +                     #{ +                       key_share => KeyShare, +                       %% pre_shared_keys => PreSharedKeys, +                       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]). 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_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index f55d1c8ea7..7b98209b31 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -29,6 +29,7 @@  -include_lib("public_key/include/public_key.hrl").  -include("ssl_api.hrl"). +-include("ssl_cipher.hrl").  -include("ssl_internal.hrl").  -include("ssl_alert.hrl").  -include("ssl_internal.hrl"). @@ -53,7 +54,8 @@ all() ->       {group, options_tls},       {group, session},       {group, 'dtlsv1.2'}, -     {group, 'dtlsv1'},  +     {group, 'dtlsv1'}, +     {group, 'tlsv1.3'},       {group, 'tlsv1.2'},       {group, 'tlsv1.1'},       {group, 'tlsv1'}, @@ -67,17 +69,16 @@ groups() ->       {options_tls, [], options_tests_tls()},       {'dtlsv1.2', [], all_versions_groups()},       {'dtlsv1', [], all_versions_groups()}, +     {'tlsv1.3', [], tls13_test_group()},       {'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()}      ]. @@ -85,14 +86,12 @@ groups() ->  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}]. @@ -208,38 +207,11 @@ renegotiate_tests() ->       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, +     cipher_suites_mix,            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, @@ -269,6 +241,26 @@ rizzo_tests() ->       rizzo_zero_n,       rizzo_disabled]. +%% For testing TLS 1.3 features and possible regressions +tls13_test_group() -> +    [tls13_enable_client_side, +     tls13_enable_server_side, +     tls_record_1_3_encode_decode, +     tls13_finished_verify_data, +     tls13_1_RTT_handshake, +     tls13_basic_ssl_server_openssl_client, +     tls13_custom_groups_ssl_server_openssl_client, +     tls13_hello_retry_request_ssl_server_openssl_client, +     tls13_client_auth_empty_cert_alert_ssl_server_openssl_client, +     tls13_client_auth_empty_cert_ssl_server_openssl_client, +     tls13_client_auth_ssl_server_openssl_client, +     tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client, +     tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client, +     tls13_hrr_client_auth_ssl_server_openssl_client, +     tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client, +     tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client, +     tls13_connection_information]. +  %%--------------------------------------------------------------------  init_per_suite(Config0) ->      catch crypto:stop(), @@ -298,7 +290,8 @@ init_per_group(GroupName, Config) when GroupName == basic_tls;                                         GroupName == options;                                         GroupName == basic;                                         GroupName == session; -                                       GroupName == error_handling_tests_tls +                                       GroupName == error_handling_tests_tls; +                                       GroupName == tls13_test_group                                         ->      ssl_test_lib:clean_tls_version(Config);                            init_per_group(GroupName, Config) -> @@ -386,26 +379,7 @@ init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;      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; +init_per_testcase(TestCase, Config) when TestCase == versions_option;  					 TestCase == tls_tcp_connect_big ->      ssl_test_lib:ct_log_supported_protocol_versions(Config),      ct:timetrap({seconds, 60}), @@ -2685,144 +2659,6 @@ tls_shutdown_error(Config) when is_list(Config) ->      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 "}]. @@ -2849,36 +2685,6 @@ default_reject_anonymous(Config) when is_list(Config) ->      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) ->  @@ -2969,8 +2775,8 @@ make_sure_expired(Host, Port, Id) ->  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), +    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),      Server =  @@ -3440,9 +3246,9 @@ defaults(Config) when is_list(Config)->      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)), +    false = 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)), +    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()), @@ -3454,7 +3260,7 @@ defaults(Config) when is_list(Config)->      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)). +    false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)).  %%--------------------------------------------------------------------  reuseaddr() -> @@ -3615,7 +3421,7 @@ honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->  %%--------------------------------------------------------------------  tls_ciphersuite_vs_version()  -> -    [{doc,"Test a SSLv3 client can not negotiate a TLSv* cipher suite."}]. +    [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}].  tls_ciphersuite_vs_version(Config) when is_list(Config) ->      {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -3658,14 +3464,14 @@ conf_signature_algs(Config) when is_list(Config) ->  	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]}]), +				   {options,  [{active, false}, {signature_algs, [{sha, 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]}]), +				   {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ClientOpts]}]),      ct:log("Testcase ~p, Client ~p  Server ~p ~n",  			 [self(), Client, Server]), @@ -4562,6 +4368,1292 @@ accept_pool(Config) when is_list(Config) ->      ssl_test_lib:close(Client1),      ssl_test_lib:close(Client2). +%%-------------------------------------------------------------------- +%% TLS 1.3 +%%-------------------------------------------------------------------- + +tls13_enable_client_side() -> +    [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}]. + +tls13_enable_client_side(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,  [{versions, +                                                     ['tlsv1.2', 'tlsv1.3']} | ClientOpts]}]), + +    ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, +    ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). + +tls13_enable_server_side() -> +    [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}]. + +tls13_enable_server_side(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.2', 'tlsv1.3']} | 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.2', 'tlsv1.1']} | ClientOpts]}]), + +    ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, +    ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). + +tls_record_1_3_encode_decode() -> +     [{doc,"Test TLS 1.3 record encode/decode functions"}]. + +tls_record_1_3_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. + +tls13_1_RTT_handshake() -> +     [{doc,"Test TLS 1.3 1-RTT Handshake"}]. + +tls13_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). + + +tls13_finished_verify_data() -> +     [{doc,"Test TLS 1.3 Finished message handling"}]. + +tls13_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). + +tls13_basic_ssl_server_openssl_client() -> +     [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client"}]. + +tls13_basic_ssl_server_openssl_client(Config) -> +    ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + +tls13_custom_groups_ssl_server_openssl_client() -> +    [{doc,"Test that ssl server can select a common group for key-exchange"}]. + +tls13_custom_groups_ssl_server_openssl_client(Config) -> +    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0], +    {_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), + +    ClientOpts = [{groups,"P-384:P-256:X25519"}|ClientOpts0], +    Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + +tls13_hello_retry_request_ssl_server_openssl_client() -> +    [{doc,"Test that ssl server can request a new group when the client's first key share" +      "is not supported"}]. + +tls13_hello_retry_request_ssl_server_openssl_client(Config) -> +    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {supported_groups, [x448, x25519]}|ServerOpts0], +    {_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), + +    ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0], +    Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + +tls13_client_auth_empty_cert_alert_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}]. + +tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) -> +    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    %% Delete Client Cert and Key +    ClientOpts1 = proplists:delete(certfile, ClientOpts0), +    ClientOpts = proplists:delete(keyfile, ClientOpts1), + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {verify, verify_peer}, +                  {fail_if_no_peer_cert, true}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, +                              {error, +                               {tls_alert, +                                {certificate_required, +                                 "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + +tls13_client_auth_empty_cert_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}]. + +tls13_client_auth_empty_cert_ssl_server_openssl_client(Config) -> +    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    %% Delete Client Cert and Key +    ClientOpts1 = proplists:delete(certfile, ClientOpts0), +    ClientOpts = proplists:delete(keyfile, ClientOpts1), + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {verify, verify_peer}, +                  {fail_if_no_peer_cert, false}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + + +tls13_client_auth_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3: Test client authentication."}]. + +tls13_client_auth_ssl_server_openssl_client(Config) -> +    ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {verify, verify_peer}, +                  {fail_if_no_peer_cert, true}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + + +tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}]. + +tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) -> +    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    %% Delete Client Cert and Key +    ClientOpts1 = proplists:delete(certfile, ClientOpts0), +    ClientOpts2 = proplists:delete(keyfile, ClientOpts1), +    ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2], + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {verify, verify_peer}, +                  {fail_if_no_peer_cert, true}, +                  {supported_groups, [x448, x25519]}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, +                              {error, +                               {tls_alert, +                                {certificate_required, +                                 "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + + +tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}]. + +tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client(Config) -> +    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    %% Delete Client Cert and Key +    ClientOpts1 = proplists:delete(certfile, ClientOpts0), +    ClientOpts2 = proplists:delete(keyfile, ClientOpts1), +    ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2], + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {verify, verify_peer}, +                  {fail_if_no_peer_cert, false}, +                  {supported_groups, [x448, x25519]}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + + +tls13_hrr_client_auth_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}]. + +tls13_hrr_client_auth_ssl_server_openssl_client(Config) -> +    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0], + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {verify, verify_peer}, +                  {fail_if_no_peer_cert, true}, +                  {supported_groups, [x448, x25519]}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + + +tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}]. + +tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) -> +    ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    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], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result( +      Server, +      {error, +       {tls_alert, +        {insufficient_security, +         "received SERVER ALERT: Fatal - Insufficient Security - " +         "\"No suitable signature algorithm\""}}}), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + + +%% Triggers Client Alert as openssl s_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). +tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client() -> +     [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}]. + +tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) -> +    ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, +                  {log_level, debug}, +                  {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], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result( +      Server, +      {error, +       {tls_alert, +        {illegal_parameter, +         "received CLIENT ALERT: Fatal - Illegal Parameter"}}}), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). + + +tls13_connection_information() -> +     [{doc,"Test the API function ssl:connection_information/1 in a TLS 1.3 connection"}]. + +tls13_connection_information(Config) -> +    ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), +    ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), +    %% Set versions +    ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], +    {_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_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + +    ssl_test_lib:check_result(Server, ok), +    ssl_test_lib:close(Server), +    ssl_test_lib:close_port(Client). +  %%--------------------------------------------------------------------  %% Internal functions ------------------------------------------------ @@ -5046,147 +6138,6 @@ 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 @@ -5350,3 +6301,31 @@ tls_or_dtls('dtlsv1.2') ->      dtls;  tls_or_dtls(_) ->      tls. + +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/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..35efa2b8a3 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)], @@ -184,42 +181,42 @@ do_test(Type, TC, Loop, ParallellConnections, Server) ->      {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_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index c0a5367a57..4f340af4f5 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -147,6 +147,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. @@ -481,7 +482,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->      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 +    %% otherwise we cannot tell this case apart form where we miss      %% to call users verify fun      FunAndState =  {fun(_,{extension, _}, UserState) ->  			    {unknown, UserState}; @@ -514,7 +515,7 @@ verify_fun_always_run_server(Config) when is_list(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 +    %% otherwise we cannot tell this case apart form where we miss      %% to call users verify fun      FunAndState =  {fun(_,{extension, _}, UserState) ->  			    {unknown, UserState}; 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..8805df7b52 --- /dev/null +++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl @@ -0,0 +1,772 @@ +%% +%% %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', [], 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(). + +rsa() -> +    [{group, dhe_rsa}, +     {group, ecdhe_rsa}, +     {group, rsa}, +     {group, srp_rsa}, +     {group, rsa_psk} +    ]. + +ecdsa() -> +    [{group, ecdhe_ecdsa}]. +     +dss() -> +    [{group, dhe_dss}, +     {group, srp_dss}]. + +anonymous() -> +    [{group, dh_anon}, +     {group, ecdh_anon}, +     {group, psk}, +     {group, dhe_psk}, +     {group, ecdhe_psk}, +     {group, srp_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 = test_cipher(TestCase, Config), +    %%Reason = io_lib:format("Missing ~p crypto support", [Cipher]), +    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. + +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 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 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 user_lookup/3, PskSharedSecret}} | ServerOpts], +                    client_config => [{psk_identity, "Test-User"}, +                                      {user_lookup_fun, {fun 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 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 user_lookup/3, PskSharedSecret}}], +                    client_config => [{psk_identity, "Test-User"}, +                                      {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}} | +     proplists:delete(tls_config, Config)];  +init_certs(srp, Config) ->  +      [{tls_config, #{server_config => [{user_lookup_fun, {fun 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  ---------------------------------------------- +%%-------------------------------------------------------------------- +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}])). + +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]), +    {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, [{versions, [Version]}, {ciphers, [CipherSuite]} | 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, [CipherSuite]} | +                                                   ClientOpts]}]), + +    ssl_test_lib:check_result(Server, ok, Client, ok), +     +    ssl_test_lib:close(Server), +    ssl_test_lib:close(Client). + +erlang_cipher_suite(Suite) when is_list(Suite)-> +    ssl_cipher_format:suite_definition(ssl_cipher_format:suite_openssl_str_to_map(Suite)); +erlang_cipher_suite(Suite) -> +    Suite. + +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_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_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl index 618ad0789e..1fea6f6f72 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,17 @@ end_per_suite(Config) ->  init_per_group(ssl, Config) ->      [{ssl_dist, true}, {ssl_dist_prefix, "SSL"}|Config]; +init_per_group(crypto, Config) -> +    case inet_crypto_dist:is_supported() of +        true -> +            [{ssl_dist, false}, {ssl_dist_prefix, "Crypto"}, +             {ssl_dist_args, +              "-proto_dist inet_crypto " +              "-inet_crypto '#{secret => \"123456\"}'"} +             |Config]; +        false -> +            {skip, "Not supported on this OTP version"} +    end;  init_per_group(plain, Config) ->      [{ssl_dist, false}, {ssl_dist_prefix, "Plain"}|Config];  init_per_group(_GroupName, Config) -> @@ -351,6 +370,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 +558,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 +579,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 +587,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 +604,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 +644,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 +657,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 +674,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 +820,7 @@ get_node_args(Tag, Config) ->          true ->              proplists:get_value(Tag, Config);          false -> -            "" +            proplists:get_value(ssl_dist_args, Config, "")      end. @@ -731,3 +875,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..bd36d35c02 --- /dev/null +++ b/lib/ssl/test/ssl_eqc_SUITE.erl @@ -0,0 +1,58 @@ +%% +%% %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 +    ]. + +%%-------------------------------------------------------------------- +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). diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl index 1fa6029963..1b432970b6 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), +    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_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index 35af666e9e..46734ba180 100644 --- a/lib/ssl/test/ssl_npn_hello_SUITE.erl +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -71,44 +71,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 +122,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 +134,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 +146,5 @@ create_connection_states() ->  						 }  		       },        current_read => #{secure_renegotiation => false -       } +                       }       }. 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_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_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index c6a4a45dce..798bdf0416 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -51,20 +51,20 @@ node_to_hostip(Node) ->      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 +90,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 +109,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 +131,37 @@ 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} ->              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,35 +174,35 @@ 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 @@ -215,35 +210,31 @@ start_server_transport_control(Args) ->  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}.  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 +247,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 +280,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 +291,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 +301,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 +331,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 +345,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 -> @@ -514,13 +503,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"]), @@ -903,14 +885,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 +900,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 +943,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 +978,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 +1003,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,17 +1039,17 @@ 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]), +    Error = Transport:connect(Host, Port, Options),      Pid ! {self(), Error}.  accepters(N) -> @@ -1106,6 +1083,35 @@ 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_basic_client(openssl, Version, Port, ClientOpts) -> +    Cert = proplists:get_value(certfile, ClientOpts), +    Key = proplists:get_value(keyfile, ClientOpts), +    CA = proplists:get_value(cacertfile, ClientOpts), +    Groups0 = proplists:get_value(groups, ClientOpts), +    Exe = "openssl", +    Args0 = ["s_client", "-verify", "2", "-port", integer_to_list(Port), +	    ssl_test_lib:version_flag(Version), +	    "-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) ->      Cert = proplists:get_value(certfile, ClientOpts),      Key = proplists:get_value(keyfile, ClientOpts), @@ -1335,13 +1341,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 +1420,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 +1430,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 +1441,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 +1464,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 +1472,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 +1483,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 +1517,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) -> @@ -1588,7 +1597,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 +1756,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 @@ -1906,6 +1929,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 +1941,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), @@ -1931,7 +1956,7 @@ filter_suites(Ciphers0, AtomVersion) ->          ++ ssl_cipher:srp_suites_anon()   	++ 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"). @@ -2342,4 +2367,10 @@ 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}}. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index df84411b6d..07abddbcf7 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -39,16 +39,14 @@  all() ->       case ssl_test_lib:openssl_sane_dtls() of           true -> -            [{group, basic}, -             {group, 'tlsv1.2'}, +            [{group, 'tlsv1.2'},               {group, 'tlsv1.1'},               {group, 'tlsv1'},               {group, 'sslv3'},               {group, 'dtlsv1.2'},               {group, 'dtlsv1'}];          false -> -            [{group, basic}, -             {group, 'tlsv1.2'}, +            [{group, 'tlsv1.2'},               {group, 'tlsv1.1'},               {group, 'tlsv1'},               {group, 'sslv3'}] @@ -57,8 +55,7 @@ all() ->  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.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()}, @@ -66,20 +63,13 @@ groups() ->                {'dtlsv1', [], dtls_all_versions_tests()}               ];          false -> -             [{basic, [], basic_tests()}, -              {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_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, @@ -191,16 +181,6 @@ 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 @@ -243,7 +223,7 @@ init_per_testcase(TestCase, Config) when        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 +    case ssl_test_lib:openssl_dsa_support() andalso ssl_test_lib:is_sane_oppenssl_client() of          true ->              special_init(TestCase, Config);          false -> @@ -344,7 +324,16 @@ special_init(TestCase, Config0)                                                  ]}                                    ]}]} | Config0],       check_openssl_sni_support(Config); - +special_init(TestCase, Config) +  when TestCase == erlang_server_openssl_client;        +       TestCase == erlang_server_openssl_client_client_cert; +       TestCase == erlang_server_openssl_client_reuse_session -> +    case ssl_test_lib:is_sane_oppenssl_client() of +        true -> +            Config; +        false -> +            {skip, "Broken OpenSSL client"} +    end;  special_init(_, Config) ->       Config. @@ -357,85 +346,7 @@ end_per_testcase(_, 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) -> @@ -1161,7 +1072,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->      Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},                                           {host, Hostname},                                           {from, self()}, -                                         {mfa, {ssl_test_lib, no_result_msg, []}}, +                                         {mfa, {ssl_test_lib, no_result, []}},                                           {options,                                            [{versions, [Version]} | ClientOpts]}]), @@ -1249,7 +1160,7 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->      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), +    ssl_test_lib:check_server_alert(Server, unexpected_message),      process_flag(trap_exit, false).  %%-------------------------------------------------------------------- @@ -1550,6 +1461,7 @@ send_and_hostname(SSLSocket) ->      end.  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), @@ -1560,9 +1472,9 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname,      Exe = "openssl",      ClientArgs = case SNIHostname of  		     undefined -> -			 openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port); +			 openssl_client_args(Version, Hostname,Port);  		     _ -> -			 openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname) +			 openssl_client_args(Version, Hostname, Port, SNIHostname)  		 end,             ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),   @@ -1573,6 +1485,7 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname,  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, @@ -1585,9 +1498,9 @@ erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHo      Exe = "openssl",      ClientArgs = case SNIHostname of  		     undefined -> -			 openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port); +			 openssl_client_args(Version, Hostname,Port);  		     _ -> -			 openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname) +			 openssl_client_args(Version, Hostname, Port, SNIHostname)  		 end,             ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),  @@ -1998,13 +1911,19 @@ send_wait_send(Socket, [ErlData, 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 +    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. +              check_openssl_npn_support(Config) ->      HelpText = os:cmd("openssl s_client --help"),      case string:str(HelpText, "nextprotoneg") of @@ -2070,17 +1989,13 @@ workaround_openssl_s_clinent() ->  	    []      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(Version, Hostname, Port) -> +    ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)]. -openssl_client_args(false, Hostname, Port, ServerName) -> +openssl_client_args(Version, 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]. +	 integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName]. +  hostname_format(Hostname) ->      case lists:member($., Hostname) of @@ -2090,22 +2005,12 @@ hostname_format(Hostname) ->              "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) -> +has_common_ciphers([], _) ->      false;  has_common_ciphers([Cipher | Rest], OCiphers) ->      case lists:member(Cipher, OCiphers) of 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/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]). | 
