aboutsummaryrefslogblamecommitdiffstats
path: root/lib/ssl/test/ssl_ECC_SUITE.erl
blob: f38c0a7416dad1c68c0125563e27c6d4c8265c5b (plain) (tree)
1
2
3
4
5


                   
                                                        
  










                                                                           

















                                                                      



                        


                         






                                            

                                             

                                                              

                                                      



                              
                                


                      





























                                                                    
                          





                              
                                     




                                           
                                       











                                            
 


                                             





                                     








                                                             

      
                                                                      

                           

                         
                  




                                          
                          


                                                                      
                                                

                                             

                                                                           



                                              
                                                

                                              

                                                                            






                                                          










                                                                             

                                                   

                 





                                                  

                                                                       



                                           







                                                           


                                                                      
                                      
                                                            
                                                     
                                       
                                
                               

           

                                           





                                                                      




                                                                     


                                                                                

                                                                                                
                                                                 



                                                                                   

                                                                                                 



                                                                                     

                                                                                                 

                                                                 



                                                                                   
                                                                                                  
                                                                  



                                                                                    
                                                                                                   
                                                                    



                                                                                     
                                                                                                   
 

                                                                    




                                                                                                  



                                                                                      






                                                                                                   

                                                                     





                                                                                                 




                                                                                    



                                                                                      

                                                                                                   



                                                                                        

                                                                                                   



                                                                                         
                                                                                                   
 
                                                                       



                                                                                         


                                                        
                                                                                         
                                      

                                                     
                                                     
                                                                                                     
                                                        
                                                      
                                                

                          
                            



                                                                                            



                                                                       
         

                                          



                                                                                            

                                               
                                                                        



                                                   



                                                                                           

                                                 
                                                                        



                                                   



                                                                                           






                                                                         



                                                                                           


                                                      
                                                           



                                                                                     
                                                                        



                                                                        
 
                                                         




                                                                                   




                                                                       
                                                            



                                                                                       

                                                                        
                                                                        


                                                   
                                                          



                                                                                    



                                                                        
         
                                                         




                                                                                                     

                                                                        
                                                                       


                                                   
                                                              



                                                                                        

                                                                        
                                                                       


                                                   
                                                            



                                                                                      

                                                                        
                                                                       


                                                   
                                                              



                                                                                        





                                                                       
                                                            



                                                                                      





                                                                       


                                                                      
                                   

                                                     

                                                        

                                               
 
 
                                                             

                                                                               



                                                           

                                                                             


                                                            
 



                                                     
                                                                                   


                                                                       
                                         


                                                                

                                                    

                                                 
                                                               
                                                            


                                                                
                                                                                              
                                                                                 
 
 
                                                                      






                                                                             
                                                                        
 
                                                                    





                                                                      
                                                                              
 
 



                                                     

                                                                                   

                                                                                             
                                                         
                                           
                                                             

                                                    
                                           
                                                        
                                                            
                                                                      

                                                            

                                                                              
                                                                                          
                                             
 
                                                        

                                                                      




                                                                       
                                                                                 
                                             
 
                                                                





                                                                                      
                                                                                 

                                             
                                                              




                                                                            
                                                                                       

                                             











                                                      
                                                          

                                                               




                                                          












                                                          












                                                                         
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2007-2017. 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_ECC_SUITE).

%% Note: This directive should only be used in test suites.
-compile(export_all).

-include_lib("common_test/include/ct.hrl").
-include_lib("public_key/include/public_key.hrl").

%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------

all() ->
    [
     {group, 'tlsv1.2'},
     {group, 'tlsv1.1'},
     {group, 'tlsv1'},
     {group, 'dtlsv1.2'},
     {group, 'dtlsv1'}
    ].

groups() ->
    [
     {'tlsv1.2', [], all_versions_groups()},
     {'tlsv1.1', [], all_versions_groups()},
     {'tlsv1', [], all_versions_groups()},
     {'dtlsv1.2', [], all_versions_groups()},
     {'dtlsv1', [], all_versions_groups()},
     {'erlang_server', [], openssl_key_cert_combinations()},
     %%{'erlang_client', [], openssl_key_cert_combinations()},
     {'erlang', [], key_cert_combinations() ++ misc() 
      ++ ecc_negotiation()}
    ].

all_versions_groups ()->
    [{group, 'erlang_server'},
     %%{group, 'erlang_client'},
     {group, 'erlang'}
    ].


openssl_key_cert_combinations() ->
    ECDH_RSA = case ssl_test_lib:openssl_filter("ECDH-RSA") of
                   [] ->
                       [];
                   _ ->
                       server_ecdh_rsa()
               end,
    
    ECDHE_RSA = case ssl_test_lib:openssl_filter("ECDHE-RSA") of
                    [] ->
                        [];
                    _ ->
                        server_ecdhe_rsa()
                end,
    ECDH_ECDSA = case ssl_test_lib:openssl_filter("ECDH-ECDSA") of
                     [] ->
                         [];
                     _ ->
                         server_ecdhe_ecdsa()
                 end,
 
    ECDHE_ECDSA = case ssl_test_lib:openssl_filter("ECDHE-ECDSA") of
                      [] ->
                          [];
                      _ ->
                          server_ecdhe_ecdsa()
                  end,
    ECDH_RSA ++  ECDHE_RSA ++ ECDH_ECDSA ++ ECDHE_ECDSA.

key_cert_combinations() ->
    server_ecdh_rsa() ++
        server_ecdhe_rsa() ++
        server_ecdh_ecdsa() ++
        server_ecdhe_ecdsa().

server_ecdh_rsa() ->
    [client_ecdh_rsa_server_ecdh_rsa,
     client_ecdhe_rsa_server_ecdh_rsa,     
     client_ecdhe_ecdsa_server_ecdh_rsa].

server_ecdhe_rsa() ->
    [client_ecdh_rsa_server_ecdhe_rsa,
     client_ecdhe_rsa_server_ecdhe_rsa,
     client_ecdhe_ecdsa_server_ecdhe_rsa].

server_ecdh_ecdsa() ->
    [client_ecdh_ecdsa_server_ecdh_ecdsa,
     client_ecdhe_rsa_server_ecdh_ecdsa,
     client_ecdhe_ecdsa_server_ecdh_ecdsa].

server_ecdhe_ecdsa() ->
    [client_ecdh_rsa_server_ecdhe_ecdsa,
     client_ecdh_ecdsa_server_ecdhe_ecdsa,
     client_ecdhe_ecdsa_server_ecdhe_ecdsa].


misc()->
    [client_ecdsa_server_ecdsa_with_raw_key].

ecc_negotiation() ->
    [ecc_default_order,
     ecc_default_order_custom_curves,
     ecc_client_order,
     ecc_client_order_custom_curves,
     ecc_unknown_curve,
     client_ecdh_rsa_server_ecdhe_ecdsa_server_custom,
     client_ecdh_rsa_server_ecdhe_rsa_server_custom,
     client_ecdhe_rsa_server_ecdhe_ecdsa_server_custom,
     client_ecdhe_rsa_server_ecdhe_rsa_server_custom,
     client_ecdhe_rsa_server_ecdh_rsa_server_custom,
     client_ecdhe_ecdsa_server_ecdhe_ecdsa_server_custom,
     client_ecdhe_ecdsa_server_ecdhe_rsa_server_custom,
     client_ecdhe_ecdsa_server_ecdhe_ecdsa_client_custom,    
     client_ecdhe_rsa_server_ecdhe_ecdsa_client_custom
    ].

%%--------------------------------------------------------------------
init_per_suite(Config0) ->
    end_per_suite(Config0),
    try crypto:start() of
	ok ->
           Config0
    catch _:_ ->
	    {skip, "Crypto did not start"}
    end.

end_per_suite(_Config) ->
    application:stop(ssl),
    application:stop(crypto).

%%--------------------------------------------------------------------
init_per_group(erlang_client = Group, Config) ->
    case ssl_test_lib:is_sane_ecc(openssl) of
	true ->
	    common_init_per_group(Group, [{server_type, openssl},
					  {client_type, erlang} | Config]);
	false ->
	    {skip, "Known ECC bug in openssl"}
    end;

init_per_group(erlang_server = Group, Config) ->
    case ssl_test_lib:is_sane_ecc(openssl) of 
	true ->
	    common_init_per_group(Group, [{server_type, erlang},
					  {client_type, openssl} | Config]);
	false ->
	    {skip, "Known ECC bug in openssl"}
    end;
	
init_per_group(erlang = Group, Config) ->
     case ssl_test_lib:sufficient_crypto_support(Group) of
	 true ->
	     common_init_per_group(Group, [{server_type, erlang},
					   {client_type, erlang} | Config]);
	 false ->
	      {skip, "Crypto does not support ECC"}
     end;

init_per_group(openssl = Group, Config) ->
     case ssl_test_lib:sufficient_crypto_support(Group) of
	 true ->
	     common_init_per_group(Group, [{server_type, openssl},
					   {client_type, openssl} | Config]);
	 false ->
	      {skip, "Crypto does not support ECC"}
     end;
		 
init_per_group(Group, Config) ->
    common_init_per_group(Group, Config).

common_init_per_group(GroupName, Config) ->
    case ssl_test_lib:is_tls_version(GroupName) of
	true ->
	    Config0 = ssl_test_lib:init_tls_version(GroupName, Config),
	    [{tls_version, GroupName} | Config0];
	_ ->
	   openssl_check(GroupName, Config)
    end.

end_per_group(GroupName, Config0) ->
  case ssl_test_lib:is_tls_version(GroupName) of
      true ->
          Config = ssl_test_lib:clean_tls_version(Config0),
          proplists:delete(tls_version, Config);
      false ->
          Config0
  end.

%%--------------------------------------------------------------------

init_per_testcase(TestCase, Config) ->
    ssl_test_lib:ct_log_supported_protocol_versions(Config),
    ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
    end_per_testcase(TestCase, Config),
    ssl_test_lib:clean_start(),	
    ct:timetrap({seconds, 15}),
    Config.

end_per_testcase(_TestCase, Config) ->     
    application:stop(ssl),
    Config.

%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------

%% Test diffrent certificate chain types, note that it is the servers
%% chain that affect what cipher suit that will be choosen

%% ECDH_RSA 
client_ecdh_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdh_rsa, ecdh_rsa, Config),
    basic_test(COpts, SOpts, [{check_keyex, ecdh_rsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_rsa_server_ecdh_rsa(Config)  when is_list(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}], 
                                                      ecdhe_rsa, ecdh_rsa, Config),
    basic_test(COpts, SOpts,  [{check_keyex, ecdh_rsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_ecdsa_server_ecdh_rsa(Config)  when is_list(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdhe_ecdsa, ecdh_rsa, Config),
    basic_test(COpts, SOpts,  [{check_keyex, ecdh_rsa} | proplists:delete(check_keyex, Config)]).

%% ECDHE_RSA    
client_ecdh_rsa_server_ecdhe_rsa(Config)  when is_list(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}], 
                                                      ecdh_rsa, ecdhe_rsa, Config),
    basic_test(COpts, SOpts,  [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_rsa_server_ecdhe_rsa(Config)  when is_list(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}], 
                                                      ecdhe_rsa, ecdhe_rsa, Config),
    basic_test(COpts, SOpts,   [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_ecdsa_server_ecdhe_rsa(Config)  when is_list(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdh_ecdsa, ecdhe_rsa, Config),
    basic_test(COpts, SOpts,   [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).

%% ECDH_ECDSA
client_ecdh_ecdsa_server_ecdh_ecdsa(Config)  when is_list(Config) ->
    Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, 
                                                        [[], [], [{extensions, Ext}]]},
                                                       {client_chain,
                                                         ssl_test_lib:default_cert_chain_conf()}],
                                                      ecdh_ecdsa, ecdh_ecdsa, Config),
    basic_test(COpts, SOpts,
               [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_rsa_server_ecdh_ecdsa(Config)  when is_list(Config) ->
     Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
     {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, 
                                                         [[], [], [{extensions, Ext}]]},
                                                        {client_chain,
                                                         ssl_test_lib:default_cert_chain_conf()}],
                                                       ecdhe_rsa, ecdh_ecdsa, Config),
     basic_test(COpts, SOpts, [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).

client_ecdhe_ecdsa_server_ecdh_ecdsa(Config)  when is_list(Config) ->
    Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, 
                                                        [[], [], [{extensions, Ext}]]},
                                                       {client_chain,
                                                        ssl_test_lib:default_cert_chain_conf()}],
                                                       ecdhe_ecdsa, ecdh_ecdsa, Config),
    basic_test(COpts, SOpts,
               [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).

%% ECDHE_ECDSA
client_ecdh_rsa_server_ecdhe_ecdsa(Config)  when is_list(Config) ->
     Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}], 
                                                      ecdh_rsa, ecdhe_ecdsa, Config), 
    basic_test(COpts, SOpts, [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
client_ecdh_ecdsa_server_ecdhe_ecdsa(Config)  when is_list(Config) ->
     Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}], 
                                                      ecdh_ecdsa, ecdhe_ecdsa, Config), 
    basic_test(COpts, SOpts, [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config)  when is_list(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
     {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                        {client_chain, Default}], 
                                                       ecdhe_ecdsa, ecdhe_ecdsa, Config),
    basic_test(COpts, SOpts, [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).

client_ecdsa_server_ecdsa_with_raw_key(Config)  when is_list(Config) ->
     Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}]
                                                     , ecdhe_ecdsa, ecdhe_ecdsa, Config),
    ServerKeyFile = proplists:get_value(keyfile, SOpts),
    {ok, PemBin} = file:read_file(ServerKeyFile),
    PemEntries = public_key:pem_decode(PemBin),
     {'ECPrivateKey', Key, not_encrypted} = proplists:lookup('ECPrivateKey', PemEntries),
    ServerKey = {'ECPrivateKey', Key},
    SType = proplists:get_value(server_type, Config),
    CType = proplists:get_value(client_type, Config),
    {Server, Port} = start_server_with_raw_key(SType,
                                               [{key, ServerKey} | proplists:delete(keyfile, SOpts)],
                                                Config),
    Client = start_client(CType, Port, COpts, Config),
     check_result(Server, SType, Client, CType),
    close(Server, Client).

ecc_default_order(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
     {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                        {client_chain, Default}],
                                                       ecdhe_ecdsa, ecdhe_ecdsa, Config),   
    ECCOpts = [],
    case supported_eccs([{eccs, [sect571r1]}]) of
        true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
     end.

ecc_default_order_custom_curves(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
     {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                        {client_chain, Default}],
                                                       ecdhe_ecdsa, ecdhe_ecdsa, Config),   
    ECCOpts = [{eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
         true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

ecc_client_order(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdhe_ecdsa, ecdhe_ecdsa, Config),   
    ECCOpts = [{honor_ecc_order, false}],
    case supported_eccs([{eccs, [sect571r1]}]) of
         true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

ecc_client_order_custom_curves(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
                                                        {client_chain, Default}],
                                                      ecdhe_ecdsa, ecdhe_ecdsa, Config),   
    ECCOpts = [{honor_ecc_order, false}, {eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

ecc_unknown_curve(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
                                                       {client_chain, Default}],
                                                      ecdhe_ecdsa, ecdhe_ecdsa, Config),   
    ECCOpts = [{eccs, ['123_fake_curve']}],
    ecc_test_error(COpts, SOpts, [], ECCOpts, Config).

client_ecdh_rsa_server_ecdhe_ecdsa_server_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
                                                       {client_chain, Default}], 
                                                      ecdh_rsa, ecdhe_ecdsa, Config),
    ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
     case supported_eccs(ECCOpts) of
         true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
         false -> {skip, "unsupported named curves"}
     end.

client_ecdh_rsa_server_ecdhe_rsa_server_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdh_rsa, ecdhe_rsa, Config),
     ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

client_ecdhe_rsa_server_ecdhe_ecdsa_server_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
     {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                        {client_chain, Default}],
                                                       ecdhe_rsa, ecdhe_ecdsa, Config),
    ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
         true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

client_ecdhe_rsa_server_ecdhe_rsa_server_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}], 
                                                      ecdhe_rsa, ecdhe_rsa, Config),
    ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
     end.
client_ecdhe_rsa_server_ecdh_rsa_server_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, [[], [], [{extensions, Ext}]]},
                                                       {client_chain, Default}], 
                                                      ecdhe_rsa, ecdh_rsa, Config),
    ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

client_ecdhe_ecdsa_server_ecdhe_ecdsa_server_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}], 
                                                      ecdhe_ecdsa, ecdhe_ecdsa, Config),
    ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

client_ecdhe_ecdsa_server_ecdhe_rsa_server_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdhe_ecdsa, ecdhe_rsa, Config),
    ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
        false -> {skip, "unsupported named curves"}
    end.

client_ecdhe_ecdsa_server_ecdhe_ecdsa_client_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdhe_ecdsa, ecdhe_ecdsa, Config),
    ECCOpts = [{eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
        false -> {skip, "unsupported named curves"}
    end.

client_ecdhe_rsa_server_ecdhe_ecdsa_client_custom(Config) ->
    Default = ssl_test_lib:default_cert_chain_conf(),
    {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, 
                                                       {client_chain, Default}],
                                                      ecdhe_rsa, ecdhe_ecdsa, Config),
    ECCOpts = [{eccs, [secp256r1, sect571r1]}],
    case supported_eccs(ECCOpts) of
        true -> ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
        false -> {skip, "unsupported named curves"}
    end.

%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
basic_test(COpts, SOpts, Config) ->
    SType = proplists:get_value(server_type, Config),
    CType = proplists:get_value(client_type, Config),
    {Server, Port} = start_server(SType, SOpts, Config),
    Client = start_client(CType, Port, COpts, Config),
    check_result(Server, SType, Client, CType),
    close(Server, Client).    


ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) ->
    {Server, Port} = start_server_ecc(erlang, SOpts, Expect, SECCOpts, Config),
    Client = start_client_ecc(erlang, Port, COpts, Expect, CECCOpts, Config),
    ssl_test_lib:check_result(Server, ok, Client, ok),
    close(Server, Client).

ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) ->
    {Server, Port} = start_server_ecc_error(erlang, SOpts, SECCOpts, Config),
    Client = start_client_ecc_error(erlang, Port, COpts, CECCOpts, Config),
    Error = {error, {tls_alert, "insufficient security"}},
    ssl_test_lib:check_result(Server, Error, Client, Error).


start_client(openssl, Port, ClientOpts, _Config) ->
    Cert = proplists:get_value(certfile, ClientOpts),
    Key = proplists:get_value(keyfile, ClientOpts),
    CA = proplists:get_value(cacertfile, ClientOpts),
    Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
    Exe = "openssl",
    Args = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
	    ssl_test_lib:version_flag(Version),
	    "-cert", Cert, "-CAfile", CA,
	    "-key", Key, "-host","localhost", "-msg", "-debug"],

    OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), 
    true = port_command(OpenSslPort, "Hello world"),
    OpenSslPort;

start_client(erlang, Port, ClientOpts, Config) ->
    {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
    KeyEx = proplists:get_value(check_keyex, Config, false),
    ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
			       {host, Hostname},
			       {from, self()},
			       {mfa, {ssl_test_lib, check_key_exchange_send_active, [KeyEx]}},
			       {options, [{verify, verify_peer} | ClientOpts]}]).


start_client_ecc(erlang, Port, ClientOpts, Expect, ECCOpts, Config) ->
    {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
    ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
                               {host, Hostname},
                               {from, self()},
                               {mfa, {?MODULE, check_ecc, [client, Expect]}},
                               {options,
                                ECCOpts ++
                                [{verify, verify_peer} | ClientOpts]}]).

start_client_ecc_error(erlang, Port, ClientOpts, ECCOpts, Config) ->
    {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
    ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
                                     {host, Hostname},
                                     {from, self()},
                                     {options,
                                      ECCOpts ++
                                      [{verify, verify_peer} | ClientOpts]}]).


start_server(openssl, ServerOpts, _Config) ->
    Cert = proplists:get_value(certfile, ServerOpts),
    Key = proplists:get_value(keyfile, ServerOpts),
    CA = proplists:get_value(cacertfile, ServerOpts),
    Port = ssl_test_lib:inet_port(node()),
    Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
    Exe = "openssl",
    Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
	    "-verify", "2", "-cert", Cert, "-CAfile", CA,
	    "-key", Key, "-msg", "-debug"],
    OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
    true = port_command(OpenSslPort, "Hello world"),
    {OpenSslPort, Port};
start_server(erlang, ServerOpts, Config) ->
    {_, ServerNode, _} = ssl_test_lib:run_where(Config),
    KeyEx = proplists:get_value(check_keyex, Config, false),
    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
                                        {from, self()},
                                        {mfa, {ssl_test_lib,
                                               check_key_exchange_send_active,
                                               [KeyEx]}},
                                        {options, [{verify, verify_peer} | ServerOpts]}]),
    {Server, ssl_test_lib:inet_port(Server)}.

start_server_with_raw_key(erlang, ServerOpts, Config) ->
    {_, ServerNode, _} = 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,
					 [{verify, verify_peer} | ServerOpts]}]),
    {Server, ssl_test_lib:inet_port(Server)}.

start_server_ecc(erlang, ServerOpts, Expect, ECCOpts, Config) ->
    {_, ServerNode, _} = ssl_test_lib:run_where(Config),
    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
                                        {from, self()},
                                        {mfa, {?MODULE, check_ecc, [server, Expect]}},
                                        {options,
                                         ECCOpts ++
                                         [{verify, verify_peer} | ServerOpts]}]),
    {Server, ssl_test_lib:inet_port(Server)}.

start_server_ecc_error(erlang, ServerOpts, ECCOpts, Config) ->
    {_, ServerNode, _} = ssl_test_lib:run_where(Config),
    Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
                                              {from, self()},
                                              {options,
                                               ECCOpts ++
                                               [{verify, verify_peer} | ServerOpts]}]),
    {Server, ssl_test_lib:inet_port(Server)}.

check_result(Server, erlang, Client, erlang) ->
    ssl_test_lib:check_result(Server, ok, Client, ok);
check_result(Server, erlang, _, _) ->
    ssl_test_lib:check_result(Server, ok);
check_result(_, _, Client, erlang) ->
    ssl_test_lib:check_result(Client, ok);
check_result(_,openssl, _, openssl) ->
    ok.

openssl_check(erlang, Config) ->
    Config;
openssl_check(_, Config) ->
    TLSVersion = proplists:get_value(tls_version, Config),
    case ssl_test_lib:check_sane_openssl_version(TLSVersion) of
	true ->
	    Config;
	false ->
	    {skip, "TLS version not supported by openssl"}
    end.

close(Port1, Port2) when is_port(Port1), is_port(Port2) ->
    ssl_test_lib:close_port(Port1),
    ssl_test_lib:close_port(Port2);
close(Port, Pid) when is_port(Port) ->
    ssl_test_lib:close_port(Port),
    ssl_test_lib:close(Pid);
close(Pid, Port) when is_port(Port) ->
    ssl_test_lib:close_port(Port),
    ssl_test_lib:close(Pid);
close(Client, Server)  ->
    ssl_test_lib:close(Server),
    ssl_test_lib:close(Client).

supported_eccs(Opts) ->
    ToCheck = proplists:get_value(eccs, Opts, []),
    Supported = ssl:eccs(),
    lists:all(fun(Curve) -> lists:member(Curve, Supported) end, ToCheck).

check_ecc(SSL, Role, Expect) ->
    {ok, Data} = ssl:connection_information(SSL),
    case lists:keyfind(ecc, 1, Data) of
        {ecc, {named_curve, Expect}} -> ok;
        false when Expect =:= undefined -> ok;
        Other -> {error, Role, Expect, Other}
    end.