diff options
Diffstat (limited to 'lib/ssl/test')
-rw-r--r-- | lib/ssl/test/Makefile | 3 | ||||
-rw-r--r-- | lib/ssl/test/make_certs.erl | 6 | ||||
-rw-r--r-- | lib/ssl/test/property_test/ssl_eqc_handshake.erl | 534 | ||||
-rw-r--r-- | lib/ssl/test/ssl_alpn_handshake_SUITE.erl | 23 | ||||
-rw-r--r-- | lib/ssl/test/ssl_basic_SUITE.erl | 135 | ||||
-rw-r--r-- | lib/ssl/test/ssl_certificate_verify_SUITE.erl | 94 | ||||
-rw-r--r-- | lib/ssl/test/ssl_engine_SUITE.erl | 15 | ||||
-rw-r--r-- | lib/ssl/test/ssl_eqc_SUITE.erl | 58 | ||||
-rw-r--r-- | lib/ssl/test/ssl_handshake_SUITE.erl | 121 | ||||
-rw-r--r-- | lib/ssl/test/ssl_npn_hello_SUITE.erl | 42 | ||||
-rw-r--r-- | lib/ssl/test/ssl_packet_SUITE.erl | 52 | ||||
-rw-r--r-- | lib/ssl/test/ssl_pem_cache_SUITE.erl | 47 | ||||
-rw-r--r-- | lib/ssl/test/ssl_session_cache_SUITE.erl | 6 | ||||
-rw-r--r-- | lib/ssl/test/ssl_test_lib.erl | 91 | ||||
-rw-r--r-- | lib/ssl/test/ssl_to_openssl_SUITE.erl | 187 |
15 files changed, 1140 insertions, 274 deletions
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 9dfb2eba53..d5ba105478 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -61,6 +61,7 @@ MODULES = \ ssl_ECC\ ssl_upgrade_SUITE\ ssl_sni_SUITE \ + ssl_eqc_SUITE \ make_certs\ x509_test @@ -144,7 +145,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/make_certs.erl b/lib/ssl/test/make_certs.erl index 8fe7c54549..578f6a731a 100644 --- a/lib/ssl/test/make_certs.erl +++ b/lib/ssl/test/make_certs.erl @@ -365,7 +365,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" @@ -415,7 +415,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" @@ -499,7 +499,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..99c6554f15 --- /dev/null +++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl @@ -0,0 +1,534 @@ +%% +%% %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_version() -> + oneof([?'TLS_v1.3', ?'TLS_v1.2', ?'TLS_v1.1', ?'TLS_v1', ?'SSL_v3']). + +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() + 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() + ]). + +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) + }. + +encrypted_extensions() -> + ?LET(Exts, extensions(?'TLS_v1.3'), + #encrypted_extensions{extensions = Exts}). + +certificate() -> + #certificate{ + asn1_certificates = certificate_chain() + }. + +certificate_1_3() -> + ?LET(Certs, certificate_chain(), + #certificate_1_3{ + certificate_request_context = certificate_request_context(), + entries = certificate_entries(Certs, []) + }). + +key_update() -> + #key_update{request_update = request_update()}. + +finished() -> + ?LET(Size, digest_size(), + #finished{verify_data = crypto:strong_rand_bytes(Size)}). + +%%-------------------------------------------------------------------- +%% Messge Data Generators ------------------------------------------- +%%-------------------------------------------------------------------- + + +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(?'TLS_v1.3' = Version) -> + ?LET({Versions, Ext}, {supported_versions(Version), c_hello_extensions(Version)}, + maps:merge(Ext, #{client_hello_versions => client_hello_versions(Versions)}) + ); +client_hello_extensions(?'TLS_v1.2' = Version) -> + ?LET({Versions, Exts}, {supported_versions(Version), c_hello_extensions(Version)}, + maps:merge(Exts, #{client_hello_versions => client_hello_versions(Versions)}) + ); +client_hello_extensions(Version) -> + ?LET(Exts, + c_hello_extensions(Version), + maps:merge(empty_hello_extensions(Version, client), Exts)). + +server_hello_extensions(?'TLS_v1.3' = Version) -> + ?LET(Exts, + s_hello_extensions(Version), + maps:merge(Exts, #{server_hello_selected_version => server_hello_selected_version(Version)})); +server_hello_extensions(Version) -> + ?LET(Exts, + s_hello_extensions(Version), + Exts). + +c_hello_extensions(?'TLS_v1.3'= Version) -> + ?LET({KeyShare, PreShare}, {key_share_client_hello(), + pre_shared_keyextension()}, + maps:merge(empty_hello_extensions(Version, client), + #{key_share => KeyShare, + pre_shared_key => PreShare + }) + ); +c_hello_extensions(Version) -> + ?LET(Exts, extensions(Version), + maps:merge(empty_hello_extensions(Version, client), + Exts)). + +s_hello_extensions(?'TLS_v1.3'= Version) -> + ?LET({KeyShare, PreShare}, {key_share_server_hello(), + pre_shared_keyextension()}, + maps:merge(empty_hello_extensions(Version, server), + #{key_share => KeyShare, + pre_shared_key => PreShare + }) + ); +s_hello_extensions(Version) -> + ?LET(Exts, extensions(Version), + maps:merge(empty_hello_extensions(Version, server), + 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]). + +extensions(?'TLS_v1.3') -> + ?LET({Ext_1_3, Exts}, {extensions_1_3(), extensions(?'TLS_v1.2')}, maps:merge(Ext_1_3, Exts)); +extensions(?'SSL_v3') -> + #{}; +extensions(Version) -> + ?LET({SNI, ECPoitF, ECCurves, ALPN, NextP, SRP}, + {oneof([sni(), undefined]), + oneof([ec_poit_formats(), undefined]), + oneof([elliptic_curves(Version), undefined]), + oneof([alpn(), undefined]), + oneof([next_protocol_negotiation(), undefined]), + oneof([srp(), 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})). + +extensions_1_3() -> + %% ?LET(Entry, key_share_entry(), + %% maps:filter(fun(_, undefined) -> + %% false; + %% (_,_) -> + %% true + %% end, #{key_share_entry => Entry})). + ?LET({HashSign, SigAlgCert}, {oneof([hash_sign_algos(?'TLS_v1.2')]), oneof([signature_scheme_list()])}, + #{signature_algs => HashSign, + signature_algs_cert => SigAlgCert}). + +empty_hello_extensions({3, 4}, server) -> + #{server_hello_selected_version => undefined, + key_share => undefined, + pre_shared_key => undefined, + sni => undefined + }; +empty_hello_extensions({3, 4}, client) -> + #{client_hello_versions => undefined, + signature_algs => undefined, + signature_algs_cert => undefined, + sni => undefined, + alpn => undefined, + key_share => undefined, + pre_shared_key => undefined + }; +empty_hello_extensions({3, 3}, client) -> + Ext = empty_hello_extensions({3,2}, client), + Ext#{client_hello_versions => undefined, + signature_algs => undefined, + signature_algs_cert => undefined}; +empty_hello_extensions(_, client) -> + #{renegotiation_info => undefined, + alpn => undefined, + next_protocol_negotiation => undefined, + srp => undefined, + ec_point_formats => undefined, + elliptic_curves => undefined, + sni => undefined}; +empty_hello_extensions(_, server) -> + #{renegotiation_info => undefined, + alpn => undefined, + next_protocol_negotiation => undefined, + ec_point_formats => undefined, + sni => undefined}. + +signature_algs_cert() -> + ?LET(Algs, signature_scheme_list(), + Algs). + +signature_scheme_list() -> + ?LET(List, sig_scheme_list(), + #signature_scheme_list{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] + ]). + +supported_versions(?'TLS_v1.3') -> + oneof([[{3,4}], + [{3,3},{3,4}], + [{3,4},{3,3},{3,2},{3,1},{3,0}] + ]); +supported_versions(_) -> + oneof([[{3,3}], + [{3,3},{3,2}], + [{3,3},{3,2},{3,1},{3,0}] + ]). + +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() -> + <<>>. +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)>>]). + +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(0,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{}. + +client_hello_versions(Versions) -> + #client_hello_versions{versions = Versions}. + +server_hello_selected_version(Version) -> + #server_hello_selected_version{selected_version = Version}. + +sni() -> + #sni{hostname = net_adm:localhost()}. + +ec_poit_formats() -> + #ec_point_formats{ec_point_format_list = ec_point_format_list()}. + +ec_point_format_list() -> + [?ECPOINT_UNCOMPRESSED]. + +elliptic_curves({_, Minor}) -> + Curves = tls_v1:ecc_curves(Minor), + #elliptic_curves{elliptic_curve_list = Curves}. + +hash_sign_algos(Version) -> + #hash_sign_algos{hash_sign_algos = hash_alg_list(Version)}. + +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(0,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])). diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl index 27062d4801..04c4b257d9 100644 --- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl @@ -155,7 +155,7 @@ empty_client(Config) when is_list(Config) -> run_failing_handshake(Config, [{alpn_advertised_protocols, []}], [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], - {connect_failed,{tls_alert,"no application protocol"}}). + {error,{tls_alert,"no application protocol"}}). %-------------------------------------------------------------------------------- @@ -163,7 +163,7 @@ empty_server(Config) when is_list(Config) -> run_failing_handshake(Config, [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], [{alpn_preferred_protocols, []}], - {connect_failed,{tls_alert,"no application protocol"}}). + {error,{tls_alert,"no application protocol"}}). %-------------------------------------------------------------------------------- @@ -171,7 +171,7 @@ empty_client_empty_server(Config) when is_list(Config) -> run_failing_handshake(Config, [{alpn_advertised_protocols, []}], [{alpn_preferred_protocols, []}], - {connect_failed,{tls_alert,"no application protocol"}}). + {error,{tls_alert,"no application protocol"}}). %-------------------------------------------------------------------------------- @@ -179,7 +179,7 @@ no_matching_protocol(Config) when is_list(Config) -> run_failing_handshake(Config, [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], - {connect_failed,{tls_alert,"no application protocol"}}). + {error,{tls_alert,"no application protocol"}}). %-------------------------------------------------------------------------------- @@ -342,18 +342,19 @@ run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedResult) ServerOpts = ServerExtraOpts ++ ssl_test_lib:ssl_options(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, placeholder, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - ExpectedResult - = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, placeholder, []}}, - {options, ClientOpts}]). + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, placeholder, []}}, + {options, ClientOpts}]), + ssl_test_lib:check_result(Server, ExpectedResult, + Client, ExpectedResult). run_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> Data = "hello world", diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 0381d0d87d..97b794c3e2 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -243,7 +243,8 @@ error_handling_tests()-> recv_active, recv_active_once, recv_error_handling, - call_in_error_state + call_in_error_state, + close_in_error_state ]. error_handling_tests_tls()-> @@ -1182,16 +1183,16 @@ fallback(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(Server), - Client = - ssl_test_lib:start_client_error([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {from, self()}, {options, - [{fallback, true}, - {versions, ['tlsv1']} - | ClientOpts]}]), + Client = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, {options, + [{fallback, true}, + {versions, ['tlsv1']} + | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error,{tls_alert,"inappropriate fallback"}}, - Client, {error,{tls_alert,"inappropriate fallback"}}). + ssl_test_lib:check_result(Server, {error,{tls_alert,"inappropriate fallback"}}, + Client, {error,{tls_alert,"inappropriate fallback"}}). %%-------------------------------------------------------------------- cipher_format() -> @@ -2644,14 +2645,14 @@ default_reject_anonymous(Config) when is_list(Config) -> {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, - [{ciphers,[CipherSuite]} | - ClientOpts]}]), + {host, Hostname}, + {from, self()}, + {options, + [{ciphers,[CipherSuite]} | + ClientOpts]}]), ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}}, - Client, {error, {tls_alert, "insufficient security"}}). + Client, {error, {tls_alert, "insufficient security"}}). %%-------------------------------------------------------------------- ciphers_ecdsa_signed_certs() -> @@ -3269,7 +3270,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, - {options, DsaServerOpts}]), + {options, [{reuseaddr, true} | DsaServerOpts]}]), Client1 = ssl_test_lib:start_client([{node, ClientNode}, @@ -3330,7 +3331,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, - {options, NewServerOpts1}]), + {options, [{reuseaddr, true} | NewServerOpts1]}]), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, @@ -3526,7 +3527,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), @@ -3569,14 +3570,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]), @@ -3604,14 +3605,14 @@ no_common_signature_algs(Config) when is_list(Config) -> | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, [{signature_algs, [{sha384, rsa}]} - | ClientOpts]}]), + {host, Hostname}, + {from, self()}, + {options, [{signature_algs, [{sha384, rsa}]} + | ClientOpts]}]), ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}}, - Client, {error, {tls_alert, "insufficient security"}}). - + Client, {error, {tls_alert, "insufficient security"}}). + %%-------------------------------------------------------------------- tls_dont_crash_on_handshake_garbage() -> @@ -3673,7 +3674,7 @@ hibernate(Config) -> {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - {Client, #sslsocket{pid=Pid}} = ssl_test_lib:start_client([return_socket, + {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket, {node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, @@ -3716,7 +3717,7 @@ hibernate_right_away(Config) -> Server1 = ssl_test_lib:start_server(StartServerOpts), Port1 = ssl_test_lib:inet_port(Server1), - {Client1, #sslsocket{pid = Pid1}} = ssl_test_lib:start_client(StartClientOpts ++ + {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++ [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]), ssl_test_lib:check_result(Server1, ok, Client1, ok), @@ -3728,7 +3729,7 @@ hibernate_right_away(Config) -> Server2 = ssl_test_lib:start_server(StartServerOpts), Port2 = ssl_test_lib:inet_port(Server2), - {Client2, #sslsocket{pid = Pid2}} = ssl_test_lib:start_client(StartClientOpts ++ + {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++ [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]), ssl_test_lib:check_result(Server2, ok, Client2, ok), @@ -3964,13 +3965,13 @@ tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - {Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket, - {node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, receive_msg, []}}, - {options, ClientOpts}]), - + {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, receive_msg, []}}, + {options, ClientOpts}]), + {status, _, _, StatusInfo} = sys:get_status(Pid), [_, _,_, _, Prop] = StatusInfo, State = ssl_test_lib:state(Prop), @@ -4036,6 +4037,33 @@ run_error_server([ Pid | Opts]) -> %%-------------------------------------------------------------------- +close_in_error_state() -> + [{doc,"Special case of closing socket in error state"}]. +close_in_error_state(Config) when is_list(Config) -> + ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), + ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)], + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]), + receive + {_Pid, Port} -> + spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]]) + end, + receive + ok -> + ok; + Other -> + ct:fail(Other) + end. + +run_error_server_close([Pid | Opts]) -> + {ok, Listen} = ssl:listen(0, Opts), + {ok,{_, Port}} = ssl:sockname(Listen), + Pid ! {self(), Port}, + {ok, Socket} = ssl:transport_accept(Listen), + Pid ! ssl:close(Socket). + +%%-------------------------------------------------------------------- + rizzo() -> [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is vunrable to Rizzo/Dungon attack"}]. @@ -4617,6 +4645,7 @@ renegotiate_rejected(Socket) -> ok; %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast {ssl, Socket, "H"} -> + receive {ssl, Socket, "ello world"} -> ok @@ -5004,20 +5033,24 @@ run_suites(Ciphers, Config, Type) -> [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]} end, - ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, ssl_test_lib:filter_suites(Ciphers, Version)]), - Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, - ssl_test_lib:filter_suites(Ciphers, Version)), - case lists:flatten(Result) of - [] -> - ok; - Error -> - ct:log("Cipher suite errors: ~p~n", [Error]), - ct:fail(cipher_suite_failed_see_test_case_log) - end. - + 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:suite_definition(ssl_cipher:openssl_suite(Suite)); + ssl_cipher_format:suite_definition(ssl_cipher_format:openssl_suite(Suite)); erlang_cipher_suite(Suite) -> Suite. @@ -5052,7 +5085,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> case Result of ok -> - []; + [ok]; Error -> [{ErlangCipherSuite, Error}] end. diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 63e9d07d0b..bddcc2514d 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -88,7 +88,8 @@ tests() -> critical_extension_verify_client, critical_extension_verify_server, critical_extension_verify_none, - customize_hostname_check + customize_hostname_check, + incomplete_chain ]. error_handling_tests()-> @@ -513,7 +514,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}; @@ -552,7 +553,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}; @@ -619,8 +620,8 @@ cert_expired(Config) when is_list(Config) -> {from, self()}, {options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]), - tcp_delivery_workaround(Server, {error, {tls_alert, "certificate expired"}}, - Client, {error, {tls_alert, "certificate expired"}}). + ssl_test_lib:check_result(Server, {error, {tls_alert, "certificate expired"}}, + Client, {error, {tls_alert, "certificate expired"}}). two_digits_str(N) when N < 10 -> lists:flatten(io_lib:format("0~p", [N])); @@ -728,8 +729,8 @@ critical_extension_verify_server(Config) when is_list(Config) -> %% This certificate has a critical extension that we don't %% understand. Therefore, verification should fail. - tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}}, - Client, {error, {tls_alert, "unsupported certificate"}}), + ssl_test_lib:check_result(Server, {error, {tls_alert, "unsupported certificate"}}, + Client, {error, {tls_alert, "unsupported certificate"}}), ssl_test_lib:close(Server). %%-------------------------------------------------------------------- @@ -908,8 +909,8 @@ invalid_signature_server(Config) when is_list(Config) -> {from, self()}, {options, [{verify, verify_peer} | ClientOpts]}]), - tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}}, - Client, {error, {tls_alert, "unknown ca"}}). + ssl_test_lib:check_result(Server, {error, {tls_alert, "unknown ca"}}, + Client, {error, {tls_alert, "unknown ca"}}). %%-------------------------------------------------------------------- @@ -945,8 +946,8 @@ invalid_signature_client(Config) when is_list(Config) -> {from, self()}, {options, NewClientOpts}]), - tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}}, - Client, {error, {tls_alert, "unknown ca"}}). + ssl_test_lib:check_result(Server, {error, {tls_alert, "unknown ca"}}, + Client, {error, {tls_alert, "unknown ca"}}). %%-------------------------------------------------------------------- @@ -1198,45 +1199,40 @@ customize_hostname_check(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +incomplete_chain() -> + [{doc,"Test option verify_peer"}]. +incomplete_chain(Config) when is_list(Config) -> + DefConf = ssl_test_lib:default_cert_chain_conf(), + CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf), + #{server_config := ServerConf, + client_config := ClientConf} = public_key:pkix_test_data(CertChainConf), + [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerConf), + ClientCas = proplists:get_value(cacerts, ClientConf), + + Active = proplists:get_value(active, Config), + ReceiveFunction = proplists:get_value(receive_function, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active}, {verify, verify_peer}, + {cacerts, [ServerRoot]} | + proplists:delete(cacerts, ServerConf)]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{active, Active}, + {verify, verify_peer}, + {cacerts, ServerCas ++ ClientCas} | + proplists:delete(cacerts, ClientConf)]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- -tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> - receive - {Server, ServerMsg} -> - client_msg(Client, ClientMsg); - {Client, ClientMsg} -> - server_msg(Server, ServerMsg); - {Client, {error,closed}} -> - server_msg(Server, ServerMsg); - {Server, {error,closed}} -> - client_msg(Client, ClientMsg) - end. - -client_msg(Client, ClientMsg) -> - receive - {Client, ClientMsg} -> - ok; - {Client, {error,closed}} -> - ct:log("client got close"), - ok; - {Client, {error, Reason}} -> - ct:log("client got econnaborted: ~p", [Reason]), - ok; - Unexpected -> - ct:fail(Unexpected) - end. -server_msg(Server, ServerMsg) -> - receive - {Server, ServerMsg} -> - ok; - {Server, {error,closed}} -> - ct:log("server got close"), - ok; - {Server, {error, Reason}} -> - ct:log("server got econnaborted: ~p", [Reason]), - ok; - Unexpected -> - ct:fail(Unexpected) - end. diff --git a/lib/ssl/test/ssl_engine_SUITE.erl b/lib/ssl/test/ssl_engine_SUITE.erl index 7277dad012..1423c99dc2 100644 --- a/lib/ssl/test/ssl_engine_SUITE.erl +++ b/lib/ssl/test/ssl_engine_SUITE.erl @@ -117,8 +117,23 @@ private_key(Config) when is_list(Config) -> EngineServerConf = [{key, #{algorithm => rsa, engine => Engine, key_id => ServerKey}} | proplists:delete(key, ServerConf)], + + EngineFileClientConf = [{key, #{algorithm => rsa, + engine => Engine, + key_id => ClientKey}} | + proplists:delete(keyfile, FileClientConf)], + + EngineFileServerConf = [{key, #{algorithm => rsa, + engine => Engine, + key_id => ServerKey}} | + proplists:delete(keyfile, FileServerConf)], + %% Test with engine test_tls_connection(EngineServerConf, EngineClientConf, Config), + + %% Test with engine and present file arugments + test_tls_connection(EngineFileServerConf, EngineFileClientConf, Config), + %% Test that sofware fallback is available test_tls_connection(ServerConf, [{reuse_sessions, false} |ClientConf], Config). 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 2c7c62407e..861fecc554 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_internal.hrl"). -include("tls_handshake.hrl"). -include_lib("public_key/include/public_key.hrl"). @@ -40,7 +41,8 @@ all() -> [decode_hello_handshake, decode_single_hello_sni_extension_correctly, decode_empty_server_sni_correctly, select_proper_tls_1_2_rsa_default_hashsign, - ignore_hassign_extension_pre_tls_1_2]. + ignore_hassign_extension_pre_tls_1_2, + unorded_chain, signature_algorithms]. %%-------------------------------------------------------------------- init_per_suite(Config) -> @@ -54,7 +56,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 -> @@ -103,15 +107,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), + #{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) @@ -122,37 +124,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}, 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}, 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}, client), + #{sni := #sni{hostname = "test.com"}} = Decoded. decode_empty_server_sni_correctly(_Config) -> - Exts = #hello_extensions{sni = ""}, SNI = <<?UINT16(?SNI_EXT),?UINT16(0)>>, - Decoded = ssl_handshake:decode_hello_extensions(SNI), - Exts = Decoded. + Decoded = ssl_handshake:decode_hello_extensions(SNI, {3,3}, server), + #{sni := #sni{hostname = ""}} = Decoded. select_proper_tls_1_2_rsa_default_hashsign(_Config) -> @@ -167,11 +166,83 @@ 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(), + CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf), + #{server_config := ServerConf, + client_config := _ClientConf} = public_key:pkix_test_data(CertChainConf), + PeerCert = proplists:get_value(cert, ServerConf), + CaCerts = [_, C1, C2] = proplists:get_value(cacerts, ServerConf), + {ok, ExtractedCerts} = ssl_pkix_db:extract_trusted_certs({der, CaCerts}), + UnordedChain = case public_key:pkix_is_self_signed(C1) of + true -> + [C1, C2]; + false -> + [C2, C1] + end, + OrderedChain = [PeerCert | lists:reverse(UnordedChain)], + {ok, _, OrderedChain} = + ssl_certificate:certificate_chain(PeerCert, ets:new(foo, []), ExtractedCerts, UnordedChain). + + +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_scheme_list{ + 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_scheme_list{ + 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 ------------------------------------------------ +%%-------------------------------------------------------------------- is_supported(Hash) -> Algos = crypto:supports(), 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_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 3261244ace..ebf8ddbfac 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -141,6 +141,7 @@ socket_active_packet_tests() -> packet_4_active_some_big, packet_wait_active, packet_size_active, + packet_switch, %% inet header option should be deprecated! header_decode_one_byte_active, header_decode_two_bytes_active, @@ -702,6 +703,34 @@ packet_size_passive(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_switch() -> + [{doc,"Test packet option {packet, 2} followd by {packet, 4}"}]. + +packet_switch(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_switch_packet ,["Hello World", 4]}}, + {options, [{nodelay, true},{packet, 2} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, recv_switch_packet, ["Hello World", 4]}}, + {options, [{nodelay, true}, {packet, 2} | + ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + %%-------------------------------------------------------------------- packet_cdr_decode() -> [{doc,"Test setting the packet option {packet, cdr}, {mode, binary}"}]. @@ -2286,3 +2315,26 @@ client_reject_packet_opt(Config, PacketOpt) -> ClientOpts]}]), ssl_test_lib:check_result(Client, {error, {options, {not_supported, PacketOpt}}}). + + +send_switch_packet(SslSocket, Data, NextPacket) -> + ssl:send(SslSocket, Data), + receive + {ssl, SslSocket, "Hello World"} -> + ssl:setopts(SslSocket, [{packet, NextPacket}]), + ssl:send(SslSocket, Data), + receive + {ssl, SslSocket, "Hello World"} -> + ok + end + end. +recv_switch_packet(SslSocket, Data, NextPacket) -> + receive + {ssl, SslSocket, "Hello World"} -> + ssl:send(SslSocket, Data), + ssl:setopts(SslSocket, [{packet, NextPacket}]), + receive + {ssl, SslSocket, "Hello World"} -> + ssl:send(SslSocket, Data) + end + end. diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl index 96b15d9b51..25d2cb300d 100644 --- a/lib/ssl/test/ssl_pem_cache_SUITE.erl +++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2015-2016. All Rights Reserved. +%% Copyright Ericsson AB 2015-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. @@ -34,7 +34,7 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- all() -> - [pem_cleanup]. + [pem_cleanup, invalid_insert]. groups() -> []. @@ -68,6 +68,10 @@ init_per_testcase(pem_cleanup = Case, Config) -> application:set_env(ssl, ssl_pem_cache_clean, ?CLEANUP_INTERVAL), ssl:start(), ct:timetrap({minutes, 1}), + Config; +init_per_testcase(_, Config) -> + ssl:start(), + ct:timetrap({seconds, 5}), Config. end_per_testcase(_TestCase, Config) -> @@ -108,7 +112,34 @@ pem_cleanup(Config)when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client), false = Size == Size1. - + +invalid_insert() -> + [{doc, "Test that insert of invalid pem does not cause empty cache entry"}]. +invalid_insert(Config)when is_list(Config) -> + process_flag(trap_exit, true), + + ClientOpts = proplists:get_value(client_verification_opts, Config), + ServerOpts = proplists:get_value(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + BadClientOpts = [{cacertfile, "tmp/does_not_exist.pem"} | proplists:delete(cacertfile, ClientOpts)], + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {from, self()}, {options, BadClientOpts}]), + ssl_test_lib:close(Server), + 1 = ssl_pkix_db:db_size(get_fileref_db()). + + + +%%-------------------------------------------------------------------- +%% Internal funcations +%%-------------------------------------------------------------------- + get_pem_cache() -> {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, @@ -120,6 +151,16 @@ get_pem_cache() -> undefined end. +get_fileref_db() -> + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + case element(6, State) of + [_CertDb, {FileRefDb,_} | _] -> + FileRefDb; + _ -> + undefined + end. later()-> DateTime = calendar:now_to_local_time(os:timestamp()), Gregorian = calendar:datetime_to_gregorian_seconds(DateTime), diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index 9862b3ce64..a0fab58b9d 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-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. @@ -487,8 +487,8 @@ test_copts(_, 0, ClientOpts) -> ClientOpts; test_copts(max_table_size, N, ClientOpts) -> Version = tls_record:highest_protocol_version([]), - CipherSuites = %%lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), -[ Y|| Y = {Alg,_, _, _} <- lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), Alg =/= ecdhe_ecdsa, Alg =/= ecdh_ecdsa, Alg =/= ecdh_rsa, Alg =/= ecdhe_rsa, Alg =/= dhe_dss, Alg =/= dss], + CipherSuites = %%lists:map(fun(X) -> ssl_cipher_format:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), +[ Y|| Y = {Alg,_, _, _} <- lists:map(fun(X) -> ssl_cipher_format:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), Alg =/= ecdhe_ecdsa, Alg =/= ecdh_ecdsa, Alg =/= ecdh_rsa, Alg =/= ecdhe_rsa, Alg =/= dhe_dss, Alg =/= dss], case length(CipherSuites) of M when M >= N -> Cipher = lists:nth(N, CipherSuites), diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 91a9c774a6..39a5bcaad6 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -1003,7 +1003,6 @@ ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) -> Error = {error, {tls_alert, "insufficient security"}}, check_result(Server, Error, Client, Error). - start_client(openssl, Port, ClientOpts, Config) -> Cert = proplists:get_value(certfile, ClientOpts), Key = proplists:get_value(keyfile, ClientOpts), @@ -1221,13 +1220,13 @@ common_ciphers(crypto) -> common_ciphers(openssl) -> OpenSslSuites = string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"), - [ssl_cipher:suite_definition(S) + [ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:suites(tls_record:highest_protocol_version([])), - lists:member(ssl_cipher:openssl_suite_name(S), OpenSslSuites) + lists:member(ssl_cipher_format:openssl_suite_name(S), OpenSslSuites) ]. available_suites(Version) -> - [ssl_cipher:suite_definition(Suite) || + [ssl_cipher_format:suite_definition(Suite) || Suite <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))]. @@ -1300,7 +1299,7 @@ string_regex_filter(_Str, _Search) -> false. ecdh_dh_anonymous_suites(Version) -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)], + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)], [{key_exchange, fun(dh_anon) -> true; @@ -1310,7 +1309,7 @@ ecdh_dh_anonymous_suites(Version) -> false end}]). psk_suites({3,_} = Version) -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []); + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []); psk_suites(Version) -> ssl:filter_cipher_suites(psk_suites(dtls_v1:corresponding_tls_version(Version)), [{cipher, @@ -1321,11 +1320,13 @@ psk_suites(Version) -> end}]). psk_anon_suites({3,_} = Version) -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)], + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)], [{key_exchange, fun(psk) -> true; - (psk_dhe) -> + (dhe_psk) -> + true; + (ecdhe_psk) -> true; (_) -> false @@ -1342,7 +1343,7 @@ psk_anon_suites(Version) -> srp_suites() -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()], + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites()], [{key_exchange, fun(srp_rsa) -> true; @@ -1350,10 +1351,10 @@ srp_suites() -> false end}]). srp_anon_suites() -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites_anon()], + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites_anon()], []). srp_dss_suites() -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()], + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites()], [{key_exchange, fun(srp_dss) -> true; @@ -1361,14 +1362,14 @@ srp_dss_suites() -> false end}]). chacha_suites(Version) -> - [ssl_cipher:suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))]. + [ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))]. rc4_suites(Version) -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <-ssl_cipher:rc4_suites(Version)], []). + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <-ssl_cipher:rc4_suites(Version)], []). des_suites(Version) -> - ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <-ssl_cipher:des_suites(Version)], []). + ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <-ssl_cipher:des_suites(Version)], []). tuple_to_map({Kex, Cipher, Mac}) -> #{key_exchange => Kex, @@ -1524,11 +1525,6 @@ v_1_2_check(ecdh_ecdsa, ecdh_rsa) -> true; v_1_2_check(ecdh_rsa, ecdh_ecdsa) -> true; -v_1_2_check(ecdhe_ecdsa, ecdhe_rsa) -> - true; -v_1_2_check(ecdhe_rsa, ecdhe_ecdsa) -> - true; - v_1_2_check(_, _) -> false. @@ -1647,6 +1643,8 @@ openssl_dsa_support() -> true; "LibreSSL" ++ _ -> false; + "OpenSSL 1.1" ++ Rest -> + false; "OpenSSL 1.0.1" ++ Rest -> hd(Rest) >= s; _ -> @@ -1767,10 +1765,10 @@ version_flag('dtlsv1') -> "-dtls1". filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_list(Cipher)-> - filter_suites([ssl_cipher:openssl_suite(S) || S <- Ciphers], + filter_suites([ssl_cipher_format:openssl_suite(S) || S <- Ciphers], AtomVersion); filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_binary(Cipher)-> - filter_suites([ssl_cipher:suite_definition(S) || S <- Ciphers], + filter_suites([ssl_cipher_format:suite_definition(S) || S <- Ciphers], AtomVersion); filter_suites(Ciphers0, AtomVersion) -> Version = tls_version(AtomVersion), @@ -1782,7 +1780,7 @@ filter_suites(Ciphers0, AtomVersion) -> ++ ssl_cipher:srp_suites_anon() ++ ssl_cipher:rc4_suites(Version), Supported1 = ssl_cipher:filter_suites(Supported0), - Supported2 = [ssl_cipher:suite_definition(S) || S <- Supported1], + Supported2 = [ssl_cipher_format:suite_definition(S) || S <- Supported1], [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)]. -define(OPENSSL_QUIT, "Q\n"). @@ -1857,13 +1855,11 @@ do_supports_ssl_tls_version(Port, Acc) -> case Acc ++ Data of "unknown option" ++ _ -> false; - Error when length(Error) >= 11 -> - case lists:member("error", string:tokens(Data, ":")) of - true -> - false; - false -> - do_supports_ssl_tls_version(Port, Error) - end; + "s_client: Option unknown" ++ _-> + false; + Info when length(Info) >= 24 -> + ct:pal("~p", [Info]), + true; _ -> do_supports_ssl_tls_version(Port, Acc ++ Data) end @@ -2064,3 +2060,40 @@ hardcode_dsa_key(3) -> y = 48598545580251057979126570873881530215432219542526130654707948736559463436274835406081281466091739849794036308281564299754438126857606949027748889019480936572605967021944405048011118039171039273602705998112739400664375208228641666852589396502386172780433510070337359132965412405544709871654840859752776060358, x = 1457508827177594730669011716588605181448418352823}. +tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> + receive + {Server, ServerMsg} -> + client_msg(Client, ClientMsg); + {Client, ClientMsg} -> + server_msg(Server, ServerMsg); + {Client, {error,closed}} -> + server_msg(Server, ServerMsg); + {Server, {error,closed}} -> + client_msg(Client, ClientMsg) + end. +client_msg(Client, ClientMsg) -> + receive + {Client, ClientMsg} -> + ok; + {Client, {error,closed}} -> + ct:log("client got close"), + ok; + {Client, {error, Reason}} -> + ct:log("client got econnaborted: ~p", [Reason]), + ok; + Unexpected -> + ct:fail(Unexpected) + end. +server_msg(Server, ServerMsg) -> + receive + {Server, ServerMsg} -> + ok; + {Server, {error,closed}} -> + ct:log("server got close"), + ok; + {Server, {error, Reason}} -> + ct:log("server got econnaborted: ~p", [Reason]), + ok; + Unexpected -> + ct:fail(Unexpected) + end. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 7fc5e13400..5a38f5f9c1 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -598,73 +598,84 @@ erlang_client_openssl_server_anon(Config) when is_list(Config) -> VersionTuple = ssl_test_lib:protocol_version(Config, tuple), Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple), - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-key", KeyFile, - "-cipher", "aNULL", "-msg"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, + case openssl_has_common_ciphers(Ciphers) of + false -> + {skip, not_supported_by_openssl}; + true -> + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile, + "-cipher", "aNULL", "-msg"], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{ciphers, Ciphers} | ClientOpts]}]), - - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. + {options, [{ciphers, Ciphers} | ClientOpts]}]), + + true = port_command(OpensslPort, Data), + + ssl_test_lib:check_result(Client, ok), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + ssl_test_lib:close(Client), + process_flag(trap_exit, false) + end. %%-------------------------------------------------------------------- erlang_server_openssl_client_anon() -> [{doc,"Test erlang server with openssl client, anonymous"}]. erlang_server_openssl_client_anon(Config) when is_list(Config) -> + process_flag(trap_exit, true), ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config), VersionTuple = ssl_test_lib:protocol_version(Config, tuple), Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple), - {_, 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()}, + case openssl_has_common_ciphers(Ciphers) of + false -> + {skip, not_supported_by_openssl}; + true -> + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{ciphers, Ciphers} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cipher", "aNULL", "-msg"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). + {options, [{ciphers, Ciphers} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + Exe = "openssl", + Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cipher", "aNULL", "-msg"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + true = port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, ok), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close(Server), + ssl_test_lib:close_port(OpenSslPort), + process_flag(trap_exit, false) + end. %%-------------------------------------------------------------------- erlang_server_openssl_client_anon_with_cert() -> @@ -675,30 +686,35 @@ erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) -> VersionTuple = ssl_test_lib:protocol_version(Config, tuple), Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple), - {_, 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()}, + case openssl_has_common_ciphers(Ciphers) of + false -> + {skip, not_supported_by_openssl}; + true -> + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{ciphers, Ciphers} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cipher", "aNULL", "-msg"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). + {options, [{ciphers, Ciphers} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + Exe = "openssl", + Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cipher", "aNULL", "-msg"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + true = port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, ok), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close(Server), + ssl_test_lib:close_port(OpenSslPort), + process_flag(trap_exit, false) + end. %%-------------------------------------------------------------------- erlang_server_openssl_client_reuse_session() -> @@ -2012,3 +2028,18 @@ no_low_flag("-no_ssl2" = Flag) -> end; no_low_flag(Flag) -> Flag. + + +openssl_has_common_ciphers(Ciphers) -> + OCiphers = ssl_test_lib:common_ciphers(openssl), + has_common_ciphers(Ciphers, OCiphers). + +has_common_ciphers([], OCiphers) -> + false; +has_common_ciphers([Cipher | Rest], OCiphers) -> + case lists:member(Cipher, OCiphers) of + true -> + true; + _ -> + has_common_ciphers(Rest, OCiphers) + end. |