From abb11dec132a4667f5ebb95c79a0b7ff5cda72e1 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 10 Jul 2019 11:32:11 +0200 Subject: ssl: Better grouping of test Regroup testes after functionality making it easier to test all variants (all protocols, all cert types etc). Also extend OpenSSL interop --- lib/ssl/src/ssl_handshake.erl | 2 + lib/ssl/test/Makefile | 22 +- lib/ssl/test/openssl_alpn_SUITE.erl | 417 ++ lib/ssl/test/openssl_cipher_suite_SUITE.erl | 801 ++++ lib/ssl/test/openssl_client_cert_SUITE.erl | 331 ++ lib/ssl/test/openssl_npn_SUITE.erl | 326 ++ lib/ssl/test/openssl_reject_SUITE.erl | 209 + lib/ssl/test/openssl_renegotiate_SUITE.erl | 341 ++ lib/ssl/test/openssl_server_cert_SUITE.erl | 324 ++ lib/ssl/test/openssl_server_cipher_suite_SUITE.erl | 775 ---- lib/ssl/test/openssl_session_SUITE.erl | 262 ++ lib/ssl/test/openssl_sni_SUITE.erl | 251 ++ lib/ssl/test/openssl_tls_1_3_version_SUITE.erl | 172 + lib/ssl/test/property_test/ssl_eqc_handshake.erl | 16 + lib/ssl/test/ssl_alpn_SUITE.erl | 397 ++ lib/ssl/test/ssl_alpn_handshake_SUITE.erl | 391 -- lib/ssl/test/ssl_basic_SUITE.erl | 4674 ++++---------------- lib/ssl/test/ssl_cert_SUITE.erl | 547 +++ lib/ssl/test/ssl_cert_tests.erl | 350 ++ lib/ssl/test/ssl_certificate_verify_SUITE.erl | 612 +-- lib/ssl/test/ssl_cipher_suite_SUITE.erl | 20 +- lib/ssl/test/ssl_handshake_SUITE.erl | 2 +- lib/ssl/test/ssl_npn_SUITE.erl | 333 ++ lib/ssl/test/ssl_npn_handshake_SUITE.erl | 333 -- lib/ssl/test/ssl_npn_hello_SUITE.erl | 9 +- lib/ssl/test/ssl_renegotiate_SUITE.erl | 499 +++ lib/ssl/test/ssl_session_SUITE.erl | 378 ++ lib/ssl/test/ssl_sni_SUITE.erl | 68 +- lib/ssl/test/ssl_test_lib.erl | 265 +- lib/ssl/test/ssl_to_openssl_SUITE.erl | 2021 --------- lib/ssl/test/ssl_version_SUITE.erl | 151 + lib/ssl/test/tls_1_3_record_SUITE.erl | 973 ++++ lib/ssl/test/tls_1_3_version_SUITE.erl | 153 + 33 files changed, 8456 insertions(+), 7969 deletions(-) create mode 100644 lib/ssl/test/openssl_alpn_SUITE.erl create mode 100644 lib/ssl/test/openssl_cipher_suite_SUITE.erl create mode 100644 lib/ssl/test/openssl_client_cert_SUITE.erl create mode 100644 lib/ssl/test/openssl_npn_SUITE.erl create mode 100644 lib/ssl/test/openssl_reject_SUITE.erl create mode 100644 lib/ssl/test/openssl_renegotiate_SUITE.erl create mode 100644 lib/ssl/test/openssl_server_cert_SUITE.erl delete mode 100644 lib/ssl/test/openssl_server_cipher_suite_SUITE.erl create mode 100644 lib/ssl/test/openssl_session_SUITE.erl create mode 100644 lib/ssl/test/openssl_sni_SUITE.erl create mode 100644 lib/ssl/test/openssl_tls_1_3_version_SUITE.erl create mode 100644 lib/ssl/test/ssl_alpn_SUITE.erl delete mode 100644 lib/ssl/test/ssl_alpn_handshake_SUITE.erl create mode 100644 lib/ssl/test/ssl_cert_SUITE.erl create mode 100644 lib/ssl/test/ssl_cert_tests.erl create mode 100644 lib/ssl/test/ssl_npn_SUITE.erl delete mode 100644 lib/ssl/test/ssl_npn_handshake_SUITE.erl create mode 100644 lib/ssl/test/ssl_renegotiate_SUITE.erl create mode 100644 lib/ssl/test/ssl_session_SUITE.erl delete mode 100644 lib/ssl/test/ssl_to_openssl_SUITE.erl create mode 100644 lib/ssl/test/ssl_version_SUITE.erl create mode 100644 lib/ssl/test/tls_1_3_record_SUITE.erl create mode 100644 lib/ssl/test/tls_1_3_version_SUITE.erl (limited to 'lib') diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index c6698bc74a..f2fd049ee3 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -3065,6 +3065,8 @@ empty_extensions({3,4}, hello_retry_request) -> key_share => undefined, pre_shared_key => undefined }; +empty_extensions({3,0}, _) -> + empty_extensions(); empty_extensions(_, server_hello) -> #{renegotiation_info => undefined, alpn => undefined, diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index dba90aaff0..01e7a062b5 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -39,12 +39,23 @@ MODULES = \ ssl_test_lib \ ssl_bench_test_lib \ ssl_dist_test_lib \ - ssl_alpn_handshake_SUITE \ ssl_basic_SUITE \ ssl_bench_SUITE \ ssl_cipher_SUITE \ ssl_cipher_suite_SUITE \ - openssl_server_cipher_suite_SUITE\ + openssl_cipher_suite_SUITE\ + ssl_alpn_SUITE \ + openssl_alpn_SUITE\ + ssl_npn_SUITE \ + openssl_npn_SUITE\ + openssl_sni_SUITE\ + ssl_renegotiate_SUITE\ + openssl_renegotiate_SUITE\ + openssl_reject_SUITE\ + ssl_cert_tests\ + ssl_cert_SUITE\ + openssl_server_cert_SUITE\ + openssl_client_cert_SUITE\ ssl_certificate_verify_SUITE\ ssl_crl_SUITE\ ssl_dist_SUITE \ @@ -52,12 +63,12 @@ MODULES = \ ssl_engine_SUITE\ ssl_handshake_SUITE \ ssl_npn_hello_SUITE \ - ssl_npn_handshake_SUITE \ ssl_packet_SUITE \ ssl_payload_SUITE \ ssl_pem_cache_SUITE \ + ssl_session_SUITE \ ssl_session_cache_SUITE \ - ssl_to_openssl_SUITE \ + openssl_session_SUITE \ ssl_ECC_SUITE \ ssl_ECC_openssl_SUITE \ ssl_ECC\ @@ -65,6 +76,9 @@ MODULES = \ ssl_sni_SUITE \ ssl_eqc_SUITE \ ssl_rfc_5869_SUITE \ + tls_1_3_record_SUITE\ + openssl_tls_1_3_version_SUITE\ + tls_1_3_version_SUITE\ make_certs \ x509_test \ inet_crypto_dist diff --git a/lib/ssl/test/openssl_alpn_SUITE.erl b/lib/ssl/test/openssl_alpn_SUITE.erl new file mode 100644 index 0000000000..fa095b4bdb --- /dev/null +++ b/lib/ssl/test/openssl_alpn_SUITE.erl @@ -0,0 +1,417 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(openssl_alpn_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(OPENSSL_QUIT, "Q\n"). +-define(OPENSSL_RENEGOTIATE, "R\n"). +-define(SLEEP, 1000). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + %% Note: ALPN not supported in sslv3 + case ssl_test_lib:openssl_sane_dtls() of + true -> + [ + {group, 'tlsv1.3'}, + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'}]; + false -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}] + end. + +groups() -> + case ssl_test_lib:openssl_sane_dtls() of + true -> + [ + {'tlsv1.3', [], alpn_tests()}, + {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()}, + {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()}, + {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()}, + {'dtlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()}, + {'dtlsv1', [], alpn_tests() ++ alpn_npn_coexist()} + ]; + false -> + [ + {'tlsv1.3', [], alpn_tests()}, + {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()}, + {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()}, + {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()} + ] + end. + +alpn_tests() -> + [erlang_client_alpn_openssl_server_alpn, + erlang_server_alpn_openssl_client_alpn, + erlang_client_alpn_openssl_server, + erlang_client_openssl_server_alpn, + erlang_server_alpn_openssl_client, + erlang_server_openssl_client_alpn]. + +alpn_npn_coexist() -> + [ + erlang_client_alpn_npn_openssl_server_alpn_npn, + erlang_server_alpn_npn_openssl_client_alpn_npn + ]. +rengotiation_tests() -> + [erlang_client_alpn_openssl_server_alpn_renegotiate, + erlang_server_alpn_openssl_client_alpn_renegotiate]. + +init_per_suite(Config0) -> + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + case check_openssl_alpn_support(Config0) of + {skip, _} = Skip -> + Skip; + _ -> + ct:pal("Version: ~p", [os:cmd("openssl version")]), + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + ssl_test_lib:make_rsa_cert(Config0) + catch _:_ -> + {skip, "Crypto did not start"} + end + end + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto), + ssl_test_lib:kill_openssl(). + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:supports_ssl_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, openssl_does_not_support_version} + end; + false -> + {skip, openssl_does_not_support_version} + end; + _ -> + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(TestCase, Config) -> + ct:timetrap({seconds, 10}), + special_init(TestCase, Config). + +special_init(TestCase, Config) + when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate; + TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate -> + {ok, Version} = application:get_env(ssl, protocol_version), + ssl_test_lib:check_sane_openssl_renegotaite(Config, Version); +special_init(TestCase, Config) + when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn; + TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn -> + ssl_test_lib:check_openssl_npn_support(Config); +special_init(_, Config) -> + Config. + +end_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +erlang_client_alpn_openssl_server_alpn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). + +%%-------------------------------------------------------------------- + +erlang_server_alpn_openssl_client_alpn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). + +%%-------------------------------------------------------------------------- + +erlang_client_alpn_openssl_server(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config, + [{alpn_advertised_protocols, [<<"spdy/2">>]}], + [], + Data, fun(Client, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). + +%%-------------------------------------------------------------------------- + +erlang_client_openssl_server_alpn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config, + [], + ["-alpn", "spdy/2"], + Data, fun(Client, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). + +%%-------------------------------------------------------------------------- + +erlang_server_alpn_openssl_client(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config, + [{alpn_preferred_protocols, [<<"spdy/2">>]}], + [], + Data, fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +%%-------------------------------------------------------------------------- + +erlang_server_openssl_client_alpn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config, + [], + ["-alpn", "spdy/2"], + Data, fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +%%-------------------------------------------------------------------- + +erlang_client_alpn_openssl_server_alpn_renegotiate(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) -> + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). + +%%-------------------------------------------------------------------- + +erlang_server_alpn_openssl_client_alpn_renegotiate(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Server, OpensslPort) -> + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +%%-------------------------------------------------------------------- + +erlang_client_alpn_npn_openssl_server_alpn_npn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). + +%%-------------------------------------------------------------------- + +erlang_server_alpn_npn_openssl_client_alpn_npn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + + +%%-------------------------------------------------------------------- +%% Internal functions ----------------------------------------------- +%%-------------------------------------------------------------------- +check_openssl_alpn_support(Config) -> + HelpText = os:cmd("openssl s_client --help"), + case string:str(HelpText, "alpn") of + 0 -> + {skip, "Openssl not compiled with alpn support"}; + _ -> + Config + end. + +start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0], + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile, "-key", KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, + {options, [{reuse_sessions, false} | ClientOpts]}]), + + Callback(Client, OpensslPort), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + + ssl_test_lib:close(Client), + process_flag(trap_exit, false). + +start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]} | ServerOpts0], + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_client", "-alpn", "http/1.0,spdy/2", "-msg", "-port", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-host", "localhost"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + Callback(Server, OpenSslPort), + + ssl_test_lib:close(Server), + + ssl_test_lib:close_port(OpenSslPort), + process_flag(trap_exit, false). + +start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]}, + {client_preferred_next_protocols, {client, [<<"spdy/3">>, <<"http/1.1">>]}} | ClientOpts0], + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", + "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, + {options, [{reuse_sessions, false} | ClientOpts]}]), + + Callback(Client, OpensslPort), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + + ssl_test_lib:close(Client), + process_flag(trap_exit, false). + +start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]}, + {next_protocols_advertised, [<<"spdy/3">>, <<"http/1.1">>]} | ServerOpts0], + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + Exe = "openssl", + Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3", + "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-host", "localhost"], + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + Callback(Server, OpenSslPort), + + ssl_test_lib:close(Server), + ssl_test_lib:close_port(OpenSslPort), + process_flag(trap_exit, false). + diff --git a/lib/ssl/test/openssl_cipher_suite_SUITE.erl b/lib/ssl/test/openssl_cipher_suite_SUITE.erl new file mode 100644 index 0000000000..955eb914c0 --- /dev/null +++ b/lib/ssl/test/openssl_cipher_suite_SUITE.erl @@ -0,0 +1,801 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(openssl_cipher_suite_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, openssl_server}, + {group, openssl_client} + ]. + +all_protocol_groups() -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'} + ]. + +groups() -> + %% TODO: Enable SRP, PSK suites (needs OpenSSL s_server conf) + %% TODO: Enable all "kex" on DTLS + [ + {openssl_server, all_protocol_groups()}, + {openssl_client, all_protocol_groups()}, + {'tlsv1.2', [], kex()}, + {'tlsv1.1', [], kex()}, + {'tlsv1', [], kex()}, + {'sslv3', [], kex()}, + {'dtlsv1.2', [], dtls_kex()}, + {'dtlsv1', [], dtls_kex()}, + {dhe_rsa, [],[dhe_rsa_3des_ede_cbc, + dhe_rsa_aes_128_cbc, + dhe_rsa_aes_256_cbc, + dhe_rsa_chacha20_poly1305 + ]}, + {ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc, + ecdhe_rsa_aes_128_cbc, + ecdhe_rsa_aes_128_gcm, + ecdhe_rsa_aes_256_cbc, + ecdhe_rsa_aes_256_gcm, + ecdhe_rsa_chacha20_poly1305 + ]}, + {ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128, + ecdhe_ecdsa_3des_ede_cbc, + ecdhe_ecdsa_aes_128_cbc, + ecdhe_ecdsa_aes_128_gcm, + ecdhe_ecdsa_aes_256_cbc, + ecdhe_ecdsa_aes_256_gcm, + ecdhe_ecdsa_chacha20_poly1305 + ]}, + {rsa, [], [rsa_3des_ede_cbc, + rsa_aes_128_cbc, + rsa_aes_256_cbc, + rsa_rc4_128 + ]}, + {dhe_dss, [], [dhe_dss_3des_ede_cbc, + dhe_dss_aes_128_cbc, + dhe_dss_aes_256_cbc]}, + %% {srp_rsa, [], [srp_rsa_3des_ede_cbc, + %% srp_rsa_aes_128_cbc, + %% srp_rsa_aes_256_cbc]}, + %% {srp_dss, [], [srp_dss_3des_ede_cbc, + %% srp_dss_aes_128_cbc, + %% srp_dss_aes_256_cbc]}, + %% {rsa_psk, [], [rsa_psk_3des_ede_cbc, + %% rsa_psk_rc4_128, + %% rsa_psk_aes_128_cbc, + %% rsa_psk_aes_256_cbc + %% ]}, + {dh_anon, [], [dh_anon_rc4_128, + dh_anon_3des_ede_cbc, + dh_anon_aes_128_cbc, + dh_anon_aes_128_gcm, + dh_anon_aes_256_cbc, + dh_anon_aes_256_gcm]}, + {ecdh_anon, [], [ecdh_anon_3des_ede_cbc, + ecdh_anon_aes_128_cbc, + ecdh_anon_aes_256_cbc + ]} + %% {srp_anon, [], [srp_anon_3des_ede_cbc, + %% srp_anon_aes_128_cbc, + %% srp_anon_aes_256_cbc]}, + %% {psk, [], [psk_3des_ede_cbc, + %% psk_rc4_128, + %% psk_aes_128_cbc, + %% psk_aes_128_ccm, + %% psk_aes_128_ccm_8, + %% psk_aes_256_cbc, + %% psk_aes_256_ccm, + %% psk_aes_256_ccm_8 + %% ]}, + %% {dhe_psk, [], [dhe_psk_3des_ede_cbc, + %% dhe_psk_rc4_128, + %% dhe_psk_aes_128_cbc, + %% dhe_psk_aes_128_ccm, + %% dhe_psk_aes_128_ccm_8, + %% dhe_psk_aes_256_cbc, + %% dhe_psk_aes_256_ccm, + %% dhe_psk_aes_256_ccm_8 + %% ]}, + %% {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc, + %% ecdhe_psk_rc4_128, + %% ecdhe_psk_aes_128_cbc, + %% ecdhe_psk_aes_128_ccm, + %% ecdhe_psk_aes_128_ccm_8, + %% ecdhe_psk_aes_256_cbc + %% ]} + ]. + +kex() -> + rsa() ++ ecdsa() ++ dss() ++ anonymous(). + +dtls_kex() -> %% Should be all kex in the future + dtls_rsa() ++ dss() ++ anonymous(). + +ssl3_kex() -> + ssl3_rsa() ++ ssl3_dss() ++ ssl3_anonymous(). + +rsa() -> + [{group, dhe_rsa}, + {group, ecdhe_rsa}, + {group, rsa} %%, {group, srp_rsa}, + %%{group, rsa_psk} + ]. + +dtls_rsa() -> + [ + {group, rsa} + %%,{group, rsa_psk} + ]. + +ssl3_rsa() -> + [{group, dhe_rsa}, + {group, rsa} + ]. + +ecdsa() -> + [{group, ecdhe_ecdsa}]. + +dss() -> + [{group, dhe_dss} + %%{group, srp_dss} + ]. + +ssl3_dss() -> + [{group, dhe_dss} + ]. + +anonymous() -> + [{group, dh_anon}, + {group, ecdh_anon} + %% {group, psk}, + %%{group, dhe_psk}, + %%{group, ecdhe_psk} + %%{group, srp_anon} + ]. + +ssl3_anonymous() -> + [{group, dh_anon}]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto), + ssl_test_lib:kill_openssl(). + +%%-------------------------------------------------------------------- +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:supports_ssl_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config), + do_init_per_group(GroupName, Config); + false -> + {skip, openssl_does_not_support_version} + end; + false -> + {skip, {openssl_does_not_support, GroupName}} + end; + false -> + do_init_per_group(GroupName, Config) + end. +do_init_per_group(openssl_client, Config0) -> + Config = proplists:delete(server_type, proplists:delete(client_type, Config0)), + [{client_type, openssl}, {server_type, erlang} | Config]; +do_init_per_group(openssl_server, Config0) -> + Config = proplists:delete(server_type, proplists:delete(client_type, Config0)), + [{client_type, erlang}, {server_type, openssl} | Config]; +do_init_per_group(GroupName, Config) when GroupName == ecdh_anon; + GroupName == ecdhe_rsa; + GroupName == ecdhe_psk -> + case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of + true -> + init_certs(GroupName, Config); + false -> + {skip, "Missing EC crypto support"} + end; +do_init_per_group(ecdhe_ecdsa = GroupName, Config) -> + PKAlg = proplists:get_value(public_keys, crypto:supports()), + case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of + true -> + init_certs(GroupName, Config); + false -> + {skip, "Missing EC crypto support"} + end; +do_init_per_group(dhe_dss = GroupName, Config) -> + PKAlg = proplists:get_value(public_keys, crypto:supports()), + case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of + true -> + init_certs(GroupName, Config); + false -> + {skip, "Missing DSS crypto support"} + end; +do_init_per_group(srp_dss = GroupName, Config) -> + PKAlg = proplists:get_value(public_keys, crypto:supports()), + case lists:member(dss, PKAlg) andalso lists:member(srp, PKAlg) of + true -> + init_certs(GroupName, Config); + false -> + {skip, "Missing DSS_SRP crypto support"} + end; +do_init_per_group(GroupName, Config) when GroupName == srp_anon; + GroupName == srp_rsa -> + PKAlg = proplists:get_value(public_keys, crypto:supports()), + case lists:member(srp, PKAlg) of + true -> + init_certs(GroupName, Config); + false -> + {skip, "Missing SRP crypto support"} + end; +do_init_per_group(dhe_psk = GroupName, Config) -> + PKAlg = proplists:get_value(public_keys, crypto:supports()), + case lists:member(dh, PKAlg) of + true -> + init_certs(GroupName, Config); + false -> + {skip, "Missing SRP crypto support"} + end; +do_init_per_group(GroupName, Config0) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, end_per_group(GroupName, Config0)); + false -> + init_certs(GroupName, Config0) + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc; + TestCase == srp_anon_3des_ede_cbc; + TestCase == dhe_psk_3des_ede_cbc; + TestCase == ecdhe_psk_3des_ede_cbc; + TestCase == srp_rsa_3des_ede_cbc; + TestCase == srp_dss_3des_ede_cbc; + TestCase == rsa_psk_3des_ede_cbc; + TestCase == rsa_3des_ede_cbc; + TestCase == dhe_rsa_3des_ede_cbc; + TestCase == dhe_dss_3des_ede_cbc; + TestCase == ecdhe_rsa_3des_ede_cbc; + TestCase == srp_anon_dss_3des_ede_cbc; + TestCase == dh_anon_3des_ede_cbc; + TestCase == ecdh_anon_3des_ede_cbc; + TestCase == ecdhe_ecdsa_3des_ede_cbc -> + SupCiphers = proplists:get_value(ciphers, crypto:supports()), + case lists:member(des_ede3, SupCiphers) of + true -> + ct:timetrap({seconds, 5}), + Config; + _ -> + {skip, "Missing 3DES crypto support"} + end; +init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128; + TestCase == ecdhe_psk_rc4_128; + TestCase == dhe_psk_rc4_128; + TestCase == rsa_psk_rc4_128; + TestCase == rsa_rc4_128; + TestCase == ecdhe_rsa_rc4_128; + TestCase == ecdhe_ecdsa_rc4_128; + TestCase == dh_anon_rc4_128 -> + SupCiphers = proplists:get_value(ciphers, crypto:supports()), + case lists:member(rc4, SupCiphers) of + true -> + ct:timetrap({seconds, 5}), + Config; + _ -> + {skip, "Missing RC4 crypto support"} + end; +init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8; + TestCase == rsa_psk_aes_128_ccm_8; + TestCase == psk_aes_128_ccm_8; + TestCase == dhe_psk_aes_128_ccm_8; + TestCase == ecdhe_psk_aes_128_ccm_8 -> + SupCiphers = proplists:get_value(ciphers, crypto:supports()), + case lists:member(aes_128_ccm, SupCiphers) of + true -> + ct:timetrap({seconds, 5}), + Config; + _ -> + {skip, "Missing AES_128_CCM crypto support"} + end; +init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8; + TestCase == rsa_psk_aes_256_ccm_8; + TestCase == psk_aes_256_ccm_8; + TestCase == dhe_psk_aes_256_ccm_8; + TestCase == ecdhe_psk_aes_256_ccm_8 -> + SupCiphers = proplists:get_value(ciphers, crypto:supports()), + case lists:member(aes_256_ccm, SupCiphers) of + true -> + ct:timetrap({seconds, 5}), + Config; + _ -> + {skip, "Missing AES_256_CCM crypto support"} + end; +init_per_testcase(TestCase, Config) -> + Cipher = ssl_test_lib:test_cipher(TestCase, Config), + SupCiphers = proplists:get_value(ciphers, crypto:supports()), + case lists:member(Cipher, SupCiphers) of + true -> + ct:timetrap({seconds, 5}), + Config; + _ -> + {skip, {Cipher, SupCiphers}} + end. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Initializtion ------------------------------------------ +%%-------------------------------------------------------------------- +init_certs(srp_rsa, Config) -> + {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, + {client_chain, ssl_test_lib:default_cert_chain_conf()}], + Config, ""), + [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts], + client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} | + proplists:delete(tls_config, Config)]; +init_certs(srp_anon, Config) -> + [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}], + client_config => [{srp_identity, {"Test-User", "secret"}}]}} | + proplists:delete(tls_config, Config)]; +init_certs(rsa_psk, Config) -> + Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]), + {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, + [[ssl_test_lib:digest()],[ssl_test_lib:digest()], + [ssl_test_lib:digest(), {extensions, Ext}]]}, + {client_chain, ssl_test_lib:default_cert_chain_conf()}], + Config, "_peer_keyEncipherment"), + PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>, + [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ServerOpts], + client_config => [{psk_identity, "Test-User"}, + {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ClientOpts]}} | + proplists:delete(tls_config, Config)]; +init_certs(rsa, Config) -> + Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]), + {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, + [[ssl_test_lib:digest()],[ssl_test_lib:digest()], + [ssl_test_lib:digest(), {extensions, Ext}]]} + ], + Config, "_peer_keyEncipherment"), + [{tls_config, #{server_config => ServerOpts, + client_config => ClientOpts}} | + proplists:delete(tls_config, Config)]; +init_certs(dhe_dss, Config) -> + {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, + {client_chain, ssl_test_lib:default_cert_chain_conf()}], + Config, ""), + [{tls_config, #{server_config => ServerOpts, + client_config => ClientOpts}} | + proplists:delete(tls_config, Config)]; +init_certs(srp_dss, Config) -> + {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, + {client_chain, ssl_test_lib:default_cert_chain_conf()}], + Config, ""), + [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts], + client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} | + proplists:delete(tls_config, Config)]; +init_certs(GroupName, Config) when GroupName == dhe_rsa; + GroupName == ecdhe_rsa -> + {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, + {client_chain, ssl_test_lib:default_cert_chain_conf()}], + Config, ""), + [{tls_config, #{server_config => ServerOpts, + client_config => ClientOpts}} | + proplists:delete(tls_config, Config)]; +init_certs(GroupName, Config) when GroupName == dhe_ecdsa; + GroupName == ecdhe_ecdsa -> + {ClientOpts, ServerOpts} = ssl_test_lib:make_ecc_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, + {client_chain, ssl_test_lib:default_cert_chain_conf()}], + Config, ""), + [{tls_config, #{server_config => ServerOpts, + client_config => ClientOpts}} | + proplists:delete(tls_config, Config)]; +init_certs(GroupName, Config) when GroupName == psk; + GroupName == dhe_psk; + GroupName == ecdhe_psk -> + PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>, + [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}], + client_config => [{psk_identity, "Test-User"}, + {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}]}} | + proplists:delete(tls_config, Config)]; +init_certs(srp, Config) -> + [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}], + client_config => [{srp_identity, {"Test-User", "secret"}}]}} | + proplists:delete(tls_config, Config)]; +init_certs(_GroupName, Config) -> + %% Anonymous does not need certs + [{tls_config, #{server_config => [], + client_config => []}} | + proplists:delete(tls_config, Config)]. +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% SRP -------------------------------------------------------- +%%-------------------------------------------------------------------- +srp_rsa_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_rsa, '3des_ede_cbc', Config). + +srp_rsa_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_rsa, 'aes_128_cbc', Config). + +srp_rsa_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_rsa, 'aes_256_cbc', Config). + +srp_dss_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_dss, '3des_ede_cbc', Config). + +srp_dss_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_dss, 'aes_128_cbc', Config). + +srp_dss_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_dss, 'aes_256_cbc', Config). + +%%-------------------------------------------------------------------- +%% PSK -------------------------------------------------------- +%%-------------------------------------------------------------------- +rsa_psk_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, '3des_ede_cbc', Config). + +rsa_psk_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, 'aes_128_cbc', Config). + +rsa_psk_aes_128_ccm(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, 'aes_128_ccm', Config). + +rsa_psk_aes_128_ccm_8(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, 'aes_128_ccm_8', Config). + +rsa_psk_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, 'aes_256_cbc', Config). + +rsa_psk_aes_256_ccm(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, 'aes_256_ccm', Config). + +rsa_psk_aes_256_ccm_8(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, 'aes_256_ccm_8', Config). + +rsa_psk_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(rsa_psk, 'rc4_128', Config). + +%%-------------------------------------------------------------------- +%% RSA -------------------------------------------------------- +%%-------------------------------------------------------------------- +rsa_des_cbc(Config) when is_list(Config) -> + run_ciphers_test(rsa, 'des_cbc', Config). + +rsa_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(rsa, '3des_ede_cbc', Config). + +rsa_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(rsa, 'aes_128_cbc', Config). + +rsa_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(rsa, 'aes_256_cbc', Config). + +rsa_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(rsa, 'aes_128_gcm', Config). + +rsa_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(rsa, 'aes_256_gcm', Config). + +rsa_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(rsa, 'rc4_128', Config). +%%-------------------------------------------------------------------- +%% DHE_RSA -------------------------------------------------------- +%%-------------------------------------------------------------------- +dhe_rsa_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_rsa, '3des_ede_cbc', Config). + +dhe_rsa_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_rsa, 'aes_128_cbc', Config). + +dhe_rsa_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(dhe_rsa, 'aes_128_gcm', Config). + +dhe_rsa_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config). + +dhe_rsa_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config). + +dhe_rsa_chacha20_poly1305(Config) when is_list(Config) -> + run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config). +%%-------------------------------------------------------------------- +%% ECDHE_RSA -------------------------------------------------------- +%%-------------------------------------------------------------------- +ecdhe_rsa_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_rsa, '3des_ede_cbc', Config). + +ecdhe_rsa_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_rsa, 'aes_128_cbc', Config). + +ecdhe_rsa_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_rsa, 'aes_128_gcm', Config). + +ecdhe_rsa_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_rsa, 'aes_256_cbc', Config). + +ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_rsa, 'aes_256_gcm', Config). + +ecdhe_rsa_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_rsa, 'rc4_128', Config). + +ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config). + +%%-------------------------------------------------------------------- +%% ECDHE_ECDSA -------------------------------------------------------- +%%-------------------------------------------------------------------- +ecdhe_ecdsa_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_ecdsa, 'rc4_128', Config). + +ecdhe_ecdsa_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_ecdsa, '3des_ede_cbc', Config). + +ecdhe_ecdsa_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_ecdsa, 'aes_128_cbc', Config). + +ecdhe_ecdsa_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_ecdsa, 'aes_128_gcm', Config). + +ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_ecdsa, 'aes_256_cbc', Config). + +ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config). + +ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config). +%%-------------------------------------------------------------------- +%% DHE_DSS -------------------------------------------------------- +%%-------------------------------------------------------------------- +dhe_dss_des_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_dss, 'des_cbc', Config). + +dhe_dss_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_dss, '3des_ede_cbc', Config). + +dhe_dss_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_dss, 'aes_128_cbc', Config). + +dhe_dss_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_dss, 'aes_256_cbc', Config). + +dhe_dss_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(dhe_dss, 'aes_128_gcm', Config). + +dhe_dss_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(dhe_dss, 'aes_256_gcm', Config). + +%%-------------------------------------------------------------------- +%% Anonymous -------------------------------------------------------- +%%-------------------------------------------------------------------- +dh_anon_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(dh_anon, '3des_ede_cbc', Config). + +dh_anon_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(dh_anon, 'aes_128_cbc', Config). + +dh_anon_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(dh_anon, 'aes_128_gcm', Config). + +dh_anon_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(dh_anon, 'aes_256_cbc', Config). + +dh_anon_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(dh_anon, 'aes_256_gcm', Config). + +dh_anon_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(dh_anon, 'rc4_128', Config). + +ecdh_anon_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdh_anon, '3des_ede_cbc', Config). + +ecdh_anon_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdh_anon, 'aes_128_cbc', Config). + +ecdh_anon_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config). + +srp_anon_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_anon, '3des_ede_cbc', Config). + +srp_anon_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_anon, 'aes_128_cbc', Config). + +srp_anon_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(srp_anon, 'aes_256_cbc', Config). + +dhe_psk_des_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'des_cbc', Config). + +dhe_psk_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'rc4_128', Config). + +dhe_psk_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, '3des_ede_cbc', Config). + +dhe_psk_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_128_cbc', Config). + +dhe_psk_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_256_cbc', Config). + +dhe_psk_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_128_gcm', Config). + +dhe_psk_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_256_gcm', Config). + +dhe_psk_aes_128_ccm(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_128_ccm', Config). + +dhe_psk_aes_256_ccm(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_256_ccm', Config). + +dhe_psk_aes_128_ccm_8(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_128_ccm_8', Config). + +dhe_psk_aes_256_ccm_8(Config) when is_list(Config) -> + run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config). + +ecdhe_psk_des_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'des_cbc', Config). + +ecdhe_psk_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'rc4_128', Config). + +ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config). + +ecdhe_psk_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config). + +ecdhe_psk_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config). + +ecdhe_psk_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config). + +ecdhe_psk_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config). + +ecdhe_psk_aes_128_ccm(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config). + +ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) -> + run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config). + +psk_des_cbc(Config) when is_list(Config) -> + run_ciphers_test(psk, 'des_cbc', Config). + +psk_rc4_128(Config) when is_list(Config) -> + run_ciphers_test(psk, 'rc4_128', Config). + +psk_3des_ede_cbc(Config) when is_list(Config) -> + run_ciphers_test(psk, '3des_ede_cbc', Config). + +psk_aes_128_cbc(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_128_cbc', Config). + +psk_aes_256_cbc(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_256_cbc', Config). + +psk_aes_128_gcm(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_128_gcm', Config). + +psk_aes_256_gcm(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_256_gcm', Config). + +psk_aes_128_ccm(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_128_ccm', Config). + +psk_aes_256_ccm(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_256_ccm', Config). + +psk_aes_128_ccm_8(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_128_ccm_8', Config). + +psk_aes_256_ccm_8(Config) when is_list(Config) -> + run_ciphers_test(psk, 'aes_256_ccm_8', Config). + +%%-------------------------------------------------------------------- +%% Internal functions ---------------------------------------------- +%%-------------------------------------------------------------------- +run_ciphers_test(Kex, Cipher, Config) -> + Version = ssl_test_lib:protocol_version(Config), + TestCiphers = test_ciphers(Kex, Cipher, Version), + + case TestCiphers of + [_|_] -> + lists:foreach(fun(TestCipher) -> + cipher_suite_test(TestCipher, Version, Config) + end, TestCiphers); + [] -> + {skip, {not_sup, Kex, Cipher, Version}} + end. + +cipher_suite_test(CipherSuite, _Version, Config) -> + #{server_config := SOpts, + client_config := COpts} = proplists:get_value(tls_config, Config), + ServerOpts = ssl_test_lib:ssl_options(SOpts, Config), + ClientOpts = ssl_test_lib:ssl_options(COpts, Config), + ct:log("Testing CipherSuite ~p~n", [CipherSuite]), + ct:log("Server Opts ~p~n", [ServerOpts]), + ct:log("Client Opts ~p~n", [ClientOpts]), + ssl_test_lib:basic_test([{ciphers, [CipherSuite]} | COpts], SOpts, Config). + + +test_ciphers(Kex, Cipher, Version) -> + Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, Version) ++ ssl:cipher_suites(anonymous, Version), + [{key_exchange, + fun(Kex0) when Kex0 == Kex -> true; + (_) -> false + end}, + {cipher, + fun(Cipher0) when Cipher0 == Cipher -> true; + (_) -> false + end}]), + ct:log("Version ~p Testing ~p~n", [Version, Ciphers]), + OpenSSLCiphers = openssl_ciphers(), + ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]), + lists:filter(fun(C) -> + ct:log("Cipher ~p~n", [C]), + lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers) + end, Ciphers). + + +openssl_ciphers() -> + Str = os:cmd("openssl ciphers"), + string:split(string:strip(Str, right, $\n), ":", all). diff --git a/lib/ssl/test/openssl_client_cert_SUITE.erl b/lib/ssl/test/openssl_client_cert_SUITE.erl new file mode 100644 index 0000000000..08c1534eb0 --- /dev/null +++ b/lib/ssl/test/openssl_client_cert_SUITE.erl @@ -0,0 +1,331 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(openssl_client_cert_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, openssl_client} + ]. + +groups() -> + [ + {openssl_client, [], protocol_groups()}, + %%{'tlsv1.3', [], tls_1_3_protocol_groups()}, + {'tlsv1.2', [], pre_tls_1_3_protocol_groups()}, + {'tlsv1.1', [], pre_tls_1_3_protocol_groups()}, + {'tlsv1', [], pre_tls_1_3_protocol_groups()}, + {'sslv3', [], ssl_protocol_groups()}, + {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()}, + {'dtlsv1', [], pre_tls_1_3_protocol_groups()}, + {rsa, [], all_version_tests()}, + {ecdsa, [], all_version_tests()}, + {dsa, [], all_version_tests()} + %%{rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_cert_client_auth]}, + %%{ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()} + ]. + +protocol_groups() -> + [%%{group, 'tlsv1.3'}, + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'} + ]. + +ssl_protocol_groups() -> + [{group, rsa}, + {group, dsa}]. + +pre_tls_1_3_protocol_groups() -> + [{group, rsa}, + {group, ecdsa}, + {group, dsa}]. + +tls_1_3_protocol_groups() -> + [{group, rsa_1_3}, + {group, ecdsa_1_3}]. + +tls_1_3_tests() -> + [ + hello_retry_request, + custom_groups, + hello_retry_client_auth, + hello_retry_client_auth_empty_cert_accepted, + hello_retry_client_auth_empty_cert_rejected + ]. + +all_version_tests() -> + [ + no_auth, + auth, + client_auth_empty_cert_accepted, + client_auth_empty_cert_rejected, + client_auth_partial_chain, + client_auth_allow_partial_chain, + client_auth_do_not_allow_partial_chain, + client_auth_partial_chain_fun_fail, + missing_root_cert_no_auth + %%invalid_signature_client + ]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:unload(ssl), + application:stop(crypto). + +init_per_group(openssl_client, Config0) -> + Config = proplists:delete(server_type, proplists:delete(client_type, Config0)), + [{client_type, openssl}, {server_type, erlang} | Config]; +init_per_group(Group, Config0) when Group == rsa; + Group == rsa_1_3 -> + Config = ssl_test_lib:make_rsa_cert(Config0), + COpts = proplists:get_value(client_rsa_opts, Config), + SOpts = proplists:get_value(server_rsa_opts, Config), + %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server + Version = proplists:get_value(version,Config), + Ciphers = ssl_cert_tests:test_ciphers(fun(dhe_rsa) -> + true; + (ecdhe_rsa) -> + true; + (_) -> + false + end, Version), + case Ciphers of + [_|_] -> + [{cert_key_alg, rsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, [{ciphers, Ciphers} | COpts]}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))])]; + [] -> + {skip, {no_sup, Group, Version}} + end; +init_per_group(Group, Config0) when Group == ecdsa; + Group == ecdsa_1_3 -> + PKAlg = crypto:supports(public_keys), + case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse + lists:member(dh, PKAlg)) of + true -> + Config = ssl_test_lib:make_ecdsa_cert(Config0), + COpts = proplists:get_value(client_ecdsa_opts, Config), + SOpts = proplists:get_value(server_ecdsa_opts, Config), + %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server + Version = proplists:get_value(version,Config), + Ciphers = ssl_cert_tests:test_ciphers(fun(ecdh_ecdsa) -> + true; + (ecdhe_ecdsa) -> + true; + (_) -> + false + end, Version), + case Ciphers of + [_|_] -> + [{cert_key_alg, ecdsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, [{ciphers, Ciphers} | COpts]}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))] + )]; + [] -> + {skip, {no_sup, Group, Version}} + end; + false -> + {skip, "Missing EC crypto support"} + end; +init_per_group(Group, Config0) when Group == dsa -> + PKAlg = crypto:supports(public_keys), + case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of + true -> + Config = ssl_test_lib:make_dsa_cert(Config0), + COpts = proplists:get_value(client_dsa_opts, Config), + SOpts = proplists:get_value(server_dsa_opts, Config), + %% Make sure dhe_dss* suite is choosen by ssl_test_lib:start_server + Version = proplists:get_value(version,Config), + Ciphers = ssl_cert_tests:test_ciphers(fun(dh_dss) -> + true; + (dhe_dss) -> + true; + (_) -> + false + end, Version), + case Ciphers of + [_|_] -> + [{cert_key_alg, dsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, [{ciphers, Ciphers} | COpts]}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))])]; + [] -> + {skip, {no_sup, Group, Version}} + end; + false -> + {skip, "Missing DSS crypto support"} + end; +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + [{version, GroupName} + | ssl_test_lib:init_tls_version(GroupName, Config)]; + false -> + {skip, "Missing openssl support"} + end; + _ -> + ssl:start(), + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(_TestCase, Config) -> + ssl_test_lib:ct_log_supported_protocol_versions(Config), + ct:timetrap({seconds, 10}), + Config. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +no_auth() -> + ssl_cert_tests:no_auth(). + +no_auth(Config) -> + ssl_cert_tests:no_auth(Config). +%%-------------------------------------------------------------------- +auth() -> + ssl_cert_tests:auth(). +auth(Config) -> + ssl_cert_tests:auth(Config). +%%-------------------------------------------------------------------- +client_auth_empty_cert_accepted() -> + ssl_cert_tests:client_auth_empty_cert_accepted(). +client_auth_empty_cert_accepted(Config) -> + ssl_cert_tests:client_auth_empty_cert_accepted(Config). +%%-------------------------------------------------------------------- +client_auth_empty_cert_rejected() -> + ssl_cert_tests:client_auth_empty_cert_rejected(). +client_auth_empty_cert_rejected(Config) -> + ssl_cert_tests:client_auth_empty_cert_rejected(Config). +%%-------------------------------------------------------------------- +client_auth_partial_chain() -> + ssl_cert_tests:client_auth_partial_chain(). +client_auth_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_partial_chain(Config). + +%%-------------------------------------------------------------------- +client_auth_allow_partial_chain() -> + ssl_cert_tests:client_auth_allow_partial_chain(). +client_auth_allow_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_allow_partial_chain(Config). +%%-------------------------------------------------------------------- +client_auth_do_not_allow_partial_chain() -> + ssl_cert_tests:client_auth_do_not_allow_partial_chain(). +client_auth_do_not_allow_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config). + +%%-------------------------------------------------------------------- +client_auth_partial_chain_fun_fail() -> + ssl_cert_tests:client_auth_partial_chain_fun_fail(). +client_auth_partial_chain_fun_fail(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_partial_chain_fun_fail(Config). + +%%-------------------------------------------------------------------- +missing_root_cert_no_auth() -> + ssl_cert_tests:missing_root_cert_no_auth(). +missing_root_cert_no_auth(Config) when is_list(Config) -> + ssl_cert_tests:missing_root_cert_no_auth(Config). + +%%-------------------------------------------------------------------- +invalid_signature_client() -> + ssl_cert_tests:invalid_signature_client(). +invalid_signature_client(Config) when is_list(Config) -> + ssl_cert_tests:invalid_signature_client(Config). +%%-------------------------------------------------------------------- +invalid_signature_server() -> + ssl_cert_tests:invalid_signature_client(). +invalid_signature_server(Config) when is_list(Config) -> + ssl_cert_tests:invalid_signature_client(Config). + +%%-------------------------------------------------------------------- +%% TLS 1.3 Test Cases ------------------------------------------------ +%%-------------------------------------------------------------------- +hello_retry_request() -> + ssl_cert_tests:hello_retry_request(). +hello_retry_request(Config) -> + ssl_cert_tests:hello_retry_request(Config). +%%-------------------------------------------------------------------- +custom_groups() -> + ssl_cert_tests:custom_groups(). +custom_groups(Config) -> + ssl_cert_tests:custom_groups(Config). +unsupported_sign_algo_cert_client_auth() -> + ssl_cert_tests:unsupported_sign_algo_cert_client_auth(). +unsupported_sign_algo_cert_client_auth(Config) -> + ssl_cert_tests:unsupported_sign_algo_cert_client_auth(Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth() -> + ssl_cert_tests:hello_retry_client_auth(). +hello_retry_client_auth(Config) -> + ssl_cert_tests:hello_retry_client_auth(Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_accepted() -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(). +hello_retry_client_auth_empty_cert_accepted(Config) -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_rejected() -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(). +hello_retry_client_auth_empty_cert_rejected(Config) -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(Config). diff --git a/lib/ssl/test/openssl_npn_SUITE.erl b/lib/ssl/test/openssl_npn_SUITE.erl new file mode 100644 index 0000000000..9bd11f05d6 --- /dev/null +++ b/lib/ssl/test/openssl_npn_SUITE.erl @@ -0,0 +1,326 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(openssl_npn_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(OPENSSL_QUIT, "Q\n"). +-define(OPENSSL_RENEGOTIATE, "R\n"). +-define(SLEEP, 1000). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + %% Note: NPN not supported in sslv3 + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'}]; + false -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}] + end. + +groups() -> + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{'tlsv1.2', [], npn_tests()}, + {'tlsv1.1', [], npn_tests()}, + {'tlsv1', [], npn_tests()}, + {'dtlsv1.2', [], npn_tests() -- [erlang_server_openssl_client_npn_renegotiate, + erlang_client_openssl_server_npn_renegotiate]}, + {'dtlsv1', [], npn_tests() -- [erlang_server_openssl_client_npn_renegotiate, + erlang_client_openssl_server_npn_renegotiate] + } + ]; + false -> + [{'tlsv1.2', [], npn_tests()}, + {'tlsv1.1', [], npn_tests()}, + {'tlsv1', [], npn_tests()} + ] + end. + +npn_tests() -> + [erlang_client_openssl_server_npn, + erlang_server_openssl_client_npn, + erlang_server_openssl_client_npn_renegotiate, + erlang_client_openssl_server_npn_renegotiate, + erlang_server_openssl_client_npn_only_client, + erlang_server_openssl_client_npn_only_server, + erlang_client_openssl_server_npn_only_client, + erlang_client_openssl_server_npn_only_server]. + +init_per_suite(Config0) -> + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + case check_openssl_npn_support(Config0) of + {skip, _} = Skip -> + Skip; + _ -> + ct:pal("Version: ~p", [os:cmd("openssl version")]), + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + ssl_test_lib:make_rsa_cert(Config0) + catch _:_ -> + {skip, "Crypto did not start"} + end + end + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto), + ssl_test_lib:kill_openssl(). + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:supports_ssl_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, openssl_does_not_support_version} + end; + false -> + {skip, openssl_does_not_support_version} + end; + _ -> + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(TestCase, Config) -> + ct:timetrap({seconds, 10}), + special_init(TestCase, Config). + +special_init(TestCase, Config) + when TestCase == erlang_client_npn_openssl_server_npn_renegotiate; + TestCase == erlang_server_npn_openssl_client_npn_renegotiate -> + {ok, Version} = application:get_env(ssl, protocol_version), + ssl_test_lib:check_sane_openssl_renegotaite(Config, Version); +special_init(_, Config) -> + Config. + +end_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +erlang_client_openssl_server_npn() -> + [{doc,"Test erlang client with openssl server doing npn negotiation"}]. + +erlang_client_openssl_server_npn(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, + fun(Client, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). + +%%-------------------------------------------------------------------- +erlang_client_openssl_server_npn_renegotiate() -> + [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}]. + +erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, + fun(Client, OpensslPort) -> + true = port_command(OpensslPort, + ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Client, Data) + end). +%%-------------------------------------------------------------------------- +erlang_server_openssl_client_npn() -> + [{doc,"Test erlang server with openssl client and npn negotiation"}]. + +erlang_server_openssl_client_npn(Config) when is_list(Config) -> + + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, + fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +%%-------------------------------------------------------------------------- +erlang_server_openssl_client_npn_renegotiate() -> + [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}]. + +erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) -> + Data = "From openssl to erlang", + start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, + fun(Server, OpensslPort) -> + true = port_command(OpensslPort, + ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). +%%-------------------------------------------------------------------------- +erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config, [], + ["-nextprotoneg", "spdy/2"], Data, + fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +%%-------------------------------------------------------------------------- + +erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config, + [{client_preferred_next_protocols, + {client, [<<"spdy/2">>], <<"http/1.1">>}}], [], + Data, + fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +%%-------------------------------------------------------------------------- +erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config, + [{next_protocols_advertised, [<<"spdy/2">>]}], [], + Data, + fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) -> + Data = "From openssl to erlang", + ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config, [], ["-nextprotoneg", "spdy/2"], + Data, + fun(Server, OpensslPort) -> + true = port_command(OpensslPort, Data), + ssl_test_lib:check_result(Server, Data) + end). + +%%-------------------------------------------------------------------- +%% Internal functions ----------------------------------------------- +%%-------------------------------------------------------------------- + +start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0], + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile, "-key", KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, + {options, ClientOpts}]), + + Callback(Client, OpensslPort), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + + ssl_test_lib:close(Client), + process_flag(trap_exit, false). + +start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>]} | ServerOpts0], + + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_client", "-nextprotoneg", "http/1.0,spdy/2", "-msg", "-connect", + ssl_test_lib:hostname_format(Hostname) ++ ":" + ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + Callback(Server, OpenSslPort), + + ssl_test_lib:close(Server), + + ssl_test_lib:close_port(OpenSslPort), + process_flag(trap_exit, false). + +check_openssl_npn_support(Config) -> + HelpText = os:cmd("openssl s_client --help"), + case string:str(HelpText, "nextprotoneg") of + 0 -> + {skip, "Openssl not compiled with nextprotoneg support"}; + _ -> + Config + end. diff --git a/lib/ssl/test/openssl_reject_SUITE.erl b/lib/ssl/test/openssl_reject_SUITE.erl new file mode 100644 index 0000000000..deefd11823 --- /dev/null +++ b/lib/ssl/test/openssl_reject_SUITE.erl @@ -0,0 +1,209 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(openssl_reject_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(SLEEP, 1000). +-define(OPENSSL_GARBAGE, "P\n"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}]. + +groups() -> + [{'tlsv1.2', [], all_versions_tests()}, + {'tlsv1.1', [], all_versions_tests()}, + {'tlsv1', [], all_versions_tests()}, + {'sslv3', [], all_versions_tests()} + ]. + +all_versions_tests() -> + [ + erlang_client_bad_openssl_server, + ssl2_erlang_server_openssl_client + ]. + +init_per_suite(Config0) -> + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + ct:pal("Version: ~p", [os:cmd("openssl version")]), + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + ssl_test_lib:make_rsa_cert(Config0) + catch _:_ -> + {skip, "Crypto did not start"} + end + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto), + ssl_test_lib:kill_openssl(). + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:supports_ssl_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, openssl_does_not_support_version} + end; + false -> + {skip, openssl_does_not_support_version} + end; + _ -> + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(TestCase, Config) -> + ct:timetrap({seconds, 10}), + special_init(TestCase, Config). + +special_init(ssl2_erlang_server_openssl_client, Config) -> + case ssl_test_lib:supports_ssl_tls_version(sslv2) of + true -> + Config; + false -> + {skip, "sslv2 not supported by openssl"} + end; +special_init(_, Config) -> + Config. + +end_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +erlang_client_bad_openssl_server() -> + [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}]. +erlang_client_bad_openssl_server(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, server_sent_garbage, []}}, + {options, + [{versions, [Version]} | ClientOpts]}]), + + %% Send garbage + true = port_command(OpensslPort, ?OPENSSL_GARBAGE), + + ct:sleep(?SLEEP), + + Client0 ! server_sent_garbage, + + ssl_test_lib:check_result(Client0, true), + + ssl_test_lib:close(Client0), + + %% Make sure openssl does not hang and leave zombie process + Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, + [{versions, [Version]} | ClientOpts]}]), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + ssl_test_lib:close(Client1), + process_flag(trap_exit, false). + +%%-------------------------------------------------------------------- +ssl2_erlang_server_openssl_client() -> + [{doc,"Test that ssl v2 clients are rejected"}]. + +ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Exe = "openssl", + Args = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), + "-ssl2", "-msg"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]), + ssl_test_lib:consume_port_exit(OpenSslPort), + ssl_test_lib:check_server_alert(Server, unexpected_message), + process_flag(trap_exit, false). + + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- + +server_sent_garbage(Socket) -> + receive + server_sent_garbage -> + {error, closed} == ssl:send(Socket, "data") + + end. diff --git a/lib/ssl/test/openssl_renegotiate_SUITE.erl b/lib/ssl/test/openssl_renegotiate_SUITE.erl new file mode 100644 index 0000000000..91a8175ac6 --- /dev/null +++ b/lib/ssl/test/openssl_renegotiate_SUITE.erl @@ -0,0 +1,341 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(openssl_renegotiate_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(SLEEP, 1000). +-define(OPENSSL_RENEGOTIATE, "R\n"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'}]; + false -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}] + end. + +groups() -> + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{'tlsv1.2', [], all_versions_tests()}, + {'tlsv1.1', [], all_versions_tests()}, + {'tlsv1', [], all_versions_tests()}, + {'sslv3', [], all_versions_tests()}, + {'dtlsv1.2', [], all_versions_tests()}, + {'dtlsv1', [], all_versions_tests()} + ]; + false -> + [{'tlsv1.2', [], all_versions_tests()}, + {'tlsv1.1', [], all_versions_tests()}, + {'tlsv1', [], all_versions_tests()}, + {'sslv3', [], all_versions_tests()} + ] + end. + +all_versions_tests() -> + [ + erlang_client_openssl_server_renegotiate, + erlang_client_openssl_server_renegotiate_after_client_data, + erlang_client_openssl_server_nowrap_seqnum, + erlang_server_openssl_client_nowrap_seqnum + ]. + + +init_per_suite(Config0) -> + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + ct:pal("Version: ~p", [os:cmd("openssl version")]), + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + ssl_test_lib:make_rsa_cert(Config0) + catch _:_ -> + {skip, "Crypto did not start"} + end + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto), + ssl_test_lib:kill_openssl(). + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:supports_ssl_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, openssl_does_not_support_version} + end; + false -> + {skip, openssl_does_not_support_version} + end; + _ -> + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(TestCase, Config) -> + ct:timetrap({seconds, 10}), + special_init(TestCase, Config). + +special_init(TestCase, Config) + when TestCase == erlang_client_openssl_server_renegotiate; + TestCase == erlang_client_openssl_server_nowrap_seqnum; + TestCase == erlang_server_openssl_client_nowrap_seqnum; + TestCase == erlang_client_openssl_server_renegotiate_after_client_data + -> + {ok, Version} = application:get_env(ssl, protocol_version), + ssl_test_lib:check_sane_openssl_renegotaite(Config, Version); +special_init(_, Config) -> + Config. + +end_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +erlang_client_openssl_server_renegotiate() -> + [{doc,"Test erlang client when openssl server issuses a renegotiate"}]. +erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + ErlData = "From erlang to openssl", + OpenSslData = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile, "-key", KeyFile, "-msg"], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + delayed_send, [[ErlData, OpenSslData]]}}, + {options, [{reuse_sessions, false} | ClientOpts]}]), + + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + true = port_command(OpensslPort, OpenSslData), + + ssl_test_lib:check_result(Client, OpenSslData), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. +%%-------------------------------------------------------------------- +erlang_client_openssl_server_renegotiate_after_client_data() -> + [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}]. +erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + ErlData = "From erlang to openssl", + OpenSslData = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile, "-key", KeyFile, "-msg"], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_wait_send, [[ErlData, OpenSslData]]}}, + {options, [{reuse_sessions, false} |ClientOpts]}]), + + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + true = port_command(OpensslPort, OpenSslData), + + ssl_test_lib:check_result(Client, OpenSslData), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. + +%%-------------------------------------------------------------------- +erlang_client_openssl_server_nowrap_seqnum() -> + [{doc, "Test that erlang client will renegotiate session when", + "max sequence number celing is about to be reached. Although" + "in the testcase we use the test option renegotiate_at" + " to lower treashold substantially."}]. +erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + ErlData = "From erlang to openssl\n", + N = 10, + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile, "-key", KeyFile, "-msg"], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + trigger_renegotiate, [[ErlData, N+2]]}}, + {options, [{reuse_sessions, false}, + {renegotiate_at, N} | ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + ssl_test_lib:close(Client), + process_flag(trap_exit, false). +%%-------------------------------------------------------------------- +erlang_server_openssl_client_nowrap_seqnum() -> + [{doc, "Test that erlang client will renegotiate session when", + "max sequence number celing is about to be reached. Although" + "in the testcase we use the test option renegotiate_at" + " to lower treashold substantially."}]. +erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + N = 10, + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + trigger_renegotiate, [[Data, N+2]]}}, + {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + Exe = "openssl", + Args = ["s_client","-connect", ssl_test_lib:hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-msg"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + true = port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, ok), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close(Server), + ssl_test_lib:close_port(OpenSslPort), + process_flag(trap_exit, false). + + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +delayed_send(Socket, [ErlData, OpenSslData]) -> + ct:sleep(?SLEEP), + ssl:send(Socket, ErlData), + ssl_test_lib:active_recv(Socket, length(OpenSslData)). + + +send_wait_send(Socket, [ErlData, OpenSslData]) -> + ssl:send(Socket, ErlData), + ct:sleep(?SLEEP), + ssl:send(Socket, ErlData), + ssl_test_lib:active_recv(Socket, length(OpenSslData)). + diff --git a/lib/ssl/test/openssl_server_cert_SUITE.erl b/lib/ssl/test/openssl_server_cert_SUITE.erl new file mode 100644 index 0000000000..abac2647a9 --- /dev/null +++ b/lib/ssl/test/openssl_server_cert_SUITE.erl @@ -0,0 +1,324 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(openssl_server_cert_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, openssl_server}]. + +groups() -> + [ + {openssl_server, [], protocol_groups()}, + %%{'tlsv1.3', [], tls_1_3_protocol_groups()}, + {'tlsv1.2', [], pre_tls_1_3_protocol_groups()}, + {'tlsv1.1', [], pre_tls_1_3_protocol_groups()}, + {'tlsv1', [], pre_tls_1_3_protocol_groups()}, + {'sslv3', [], ssl_protocol_groups()}, + {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()}, + {'dtlsv1', [], pre_tls_1_3_protocol_groups()}, + {rsa, [], all_version_tests()}, + {ecdsa, [], all_version_tests()}, + {dsa, [], all_version_tests()} + %%{rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_cert_client_auth]}, + %%{ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()} + ]. + +protocol_groups() -> + [%%{group, 'tlsv1.3'}, + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'} + ]. + +ssl_protocol_groups() -> + [{group, rsa}, + {group, dsa}]. + +pre_tls_1_3_protocol_groups() -> + [{group, rsa}, + {group, ecdsa}, + {group, dsa}]. + +tls_1_3_protocol_groups() -> + [{group, rsa_1_3}, + {group, ecdsa_1_3}]. + +tls_1_3_tests() -> + [ + hello_retry_request, + custom_groups, + hello_retry_client_auth, + hello_retry_client_auth_empty_cert_accepted, + hello_retry_client_auth_empty_cert_rejected + ]. + +all_version_tests() -> + [ + no_auth, + auth, + missing_root_cert_no_auth + %%invalid_signature_client + ]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:unload(ssl), + application:stop(crypto). + +init_per_group(openssl_server, Config0) -> + Config = proplists:delete(server_type, proplists:delete(client_type, Config0)), + [{client_type, erlang}, {server_type, openssl} | Config]; +init_per_group(Group, Config0) when Group == rsa; + Group == rsa_1_3 -> + Config = ssl_test_lib:make_rsa_cert(Config0), + COpts = proplists:get_value(client_rsa_opts, Config), + SOpts = proplists:get_value(server_rsa_opts, Config), + %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server + Version = proplists:get_value(version,Config), + Ciphers = ssl_cert_tests:test_ciphers(fun(dhe_rsa) -> + true; + (ecdhe_rsa) -> + true; + (_) -> + false + end, Version), + case Ciphers of + [_|_] -> + [{cert_key_alg, rsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, [{ciphers, Ciphers} | COpts]}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))])]; + [] -> + {skip, {no_sup, Group, Version}} + end; +init_per_group(Group, Config0) when Group == ecdsa; + Group == ecdsa_1_3 -> + PKAlg = crypto:supports(public_keys), + case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse + lists:member(dh, PKAlg)) of + true -> + Config = ssl_test_lib:make_ecdsa_cert(Config0), + COpts = proplists:get_value(client_ecdsa_opts, Config), + SOpts = proplists:get_value(server_ecdsa_opts, Config), + %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server + Version = proplists:get_value(version,Config), + Ciphers = ssl_cert_tests:test_ciphers(fun(ecdh_ecdsa) -> + true; + (ecdhe_ecdsa) -> + true; + (_) -> + false + end, Version), + case Ciphers of + [_|_] -> + [{cert_key_alg, ecdsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, [{ciphers, Ciphers} | COpts]}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))] + )]; + [] -> + {skip, {no_sup, Group, Version}} + end; + false -> + {skip, "Missing EC crypto support"} + end; +init_per_group(Group, Config0) when Group == dsa -> + PKAlg = crypto:supports(public_keys), + case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of + true -> + Config = ssl_test_lib:make_dsa_cert(Config0), + COpts = proplists:get_value(client_dsa_opts, Config), + SOpts = proplists:get_value(server_dsa_opts, Config), + %% Make sure dhe_dss* suite is choosen by ssl_test_lib:start_server + Version = proplists:get_value(version,Config), + Ciphers = ssl_cert_tests:test_ciphers(fun(dh_dss) -> + true; + (dhe_dss) -> + true; + (_) -> + false + end, Version), + case Ciphers of + [_|_] -> + [{cert_key_alg, dsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, [{ciphers, Ciphers} | COpts]}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))])]; + [] -> + {skip, {no_sup, Group, Version}} + end; + false -> + {skip, "Missing DSS crypto support"} + end; +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + [{version, GroupName} + | ssl_test_lib:init_tls_version(GroupName, Config)]; + false -> + {skip, "Missing openssl support"} + end; + _ -> + ssl:start(), + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(_TestCase, Config) -> + ssl_test_lib:ct_log_supported_protocol_versions(Config), + ct:timetrap({seconds, 10}), + Config. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +no_auth() -> + ssl_cert_tests:no_auth(). + +no_auth(Config) -> + ssl_cert_tests:no_auth(Config). +%%-------------------------------------------------------------------- +auth() -> + ssl_cert_tests:auth(). +auth(Config) -> + ssl_cert_tests:auth(Config). +%%-------------------------------------------------------------------- +client_auth_empty_cert_accepted() -> + ssl_cert_tests:client_auth_empty_cert_accepted(). +client_auth_empty_cert_accepted(Config) -> + ssl_cert_tests:client_auth_empty_cert_accepted(Config). +%%-------------------------------------------------------------------- +client_auth_empty_cert_rejected() -> + ssl_cert_tests:client_auth_empty_cert_rejected(). +client_auth_empty_cert_rejected(Config) -> + ssl_cert_tests:client_auth_empty_cert_rejected(Config). +%%-------------------------------------------------------------------- +client_auth_partial_chain() -> + ssl_cert_tests:client_auth_partial_chain(). +client_auth_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_partial_chain(Config). + +%%-------------------------------------------------------------------- +client_auth_allow_partial_chain() -> + ssl_cert_tests:client_auth_allow_partial_chain(). +client_auth_allow_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_allow_partial_chain(Config). +%%-------------------------------------------------------------------- +client_auth_do_not_allow_partial_chain() -> + ssl_cert_tests:client_auth_do_not_allow_partial_chain(). +client_auth_do_not_allow_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config). + +%%-------------------------------------------------------------------- +client_auth_partial_chain_fun_fail() -> + ssl_cert_tests:client_auth_partial_chain_fun_fail(). +client_auth_partial_chain_fun_fail(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_partial_chain_fun_fail(Config). + +%%-------------------------------------------------------------------- +missing_root_cert_no_auth() -> + ssl_cert_tests:missing_root_cert_no_auth(). +missing_root_cert_no_auth(Config) when is_list(Config) -> + ssl_cert_tests:missing_root_cert_no_auth(Config). + +%%-------------------------------------------------------------------- +invalid_signature_client() -> + ssl_cert_tests:invalid_signature_client(). +invalid_signature_client(Config) when is_list(Config) -> + ssl_cert_tests:invalid_signature_client(Config). +%%-------------------------------------------------------------------- +invalid_signature_server() -> + ssl_cert_tests:invalid_signature_client(). +invalid_signature_server(Config) when is_list(Config) -> + ssl_cert_tests:invalid_signature_client(Config). + +%%-------------------------------------------------------------------- +%% TLS 1.3 Test Cases ------------------------------------------------ +%%-------------------------------------------------------------------- +hello_retry_request() -> + ssl_cert_tests:hello_retry_request(). +hello_retry_request(Config) -> + ssl_cert_tests:hello_retry_request(Config). +%%-------------------------------------------------------------------- +custom_groups() -> + ssl_cert_tests:custom_groups(). +custom_groups(Config) -> + ssl_cert_tests:custom_groups(Config). +unsupported_sign_algo_cert_client_auth() -> + ssl_cert_tests:unsupported_sign_algo_cert_client_auth(). +unsupported_sign_algo_cert_client_auth(Config) -> + ssl_cert_tests:unsupported_sign_algo_cert_client_auth(Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth() -> + ssl_cert_tests:hello_retry_client_auth(). +hello_retry_client_auth(Config) -> + ssl_cert_tests:hello_retry_client_auth(Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_accepted() -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(). +hello_retry_client_auth_empty_cert_accepted(Config) -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_rejected() -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(). +hello_retry_client_auth_empty_cert_rejected(Config) -> + ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(Config). diff --git a/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl b/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl deleted file mode 100644 index 0d68d84d61..0000000000 --- a/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl +++ /dev/null @@ -1,775 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2019-2019. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% - --module(openssl_server_cipher_suite_SUITE). - -%% Note: This directive should only be used in test suites. --compile(export_all). - --include_lib("common_test/include/ct.hrl"). - -%%-------------------------------------------------------------------- -%% Common Test interface functions ----------------------------------- -%%-------------------------------------------------------------------- -all() -> - [ - {group, 'tlsv1.2'}, - {group, 'tlsv1.1'}, - {group, 'tlsv1'}, - {group, 'sslv3'}, - {group, 'dtlsv1.2'}, - {group, 'dtlsv1'} - ]. - -groups() -> - %% TODO: Enable SRP, PSK suites (needs OpenSSL s_server conf) - %% TODO: Enable all "kex" on DTLS - [ - {'tlsv1.2', [], kex()}, - {'tlsv1.1', [], kex()}, - {'tlsv1', [], kex()}, - {'sslv3', [], kex()}, - {'dtlsv1.2', [], dtls_kex()}, - {'dtlsv1', [], dtls_kex()}, - {dhe_rsa, [],[dhe_rsa_3des_ede_cbc, - dhe_rsa_aes_128_cbc, - dhe_rsa_aes_256_cbc, - dhe_rsa_chacha20_poly1305 - ]}, - {ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc, - ecdhe_rsa_aes_128_cbc, - ecdhe_rsa_aes_128_gcm, - ecdhe_rsa_aes_256_cbc, - ecdhe_rsa_aes_256_gcm, - ecdhe_rsa_chacha20_poly1305 - ]}, - {ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128, - ecdhe_ecdsa_3des_ede_cbc, - ecdhe_ecdsa_aes_128_cbc, - ecdhe_ecdsa_aes_128_gcm, - ecdhe_ecdsa_aes_256_cbc, - ecdhe_ecdsa_aes_256_gcm, - ecdhe_ecdsa_chacha20_poly1305 - ]}, - {rsa, [], [rsa_3des_ede_cbc, - rsa_aes_128_cbc, - rsa_aes_256_cbc, - rsa_rc4_128 - ]}, - {dhe_dss, [], [dhe_dss_3des_ede_cbc, - dhe_dss_aes_128_cbc, - dhe_dss_aes_256_cbc]}, - %% {srp_rsa, [], [srp_rsa_3des_ede_cbc, - %% srp_rsa_aes_128_cbc, - %% srp_rsa_aes_256_cbc]}, - %% {srp_dss, [], [srp_dss_3des_ede_cbc, - %% srp_dss_aes_128_cbc, - %% srp_dss_aes_256_cbc]}, - %% {rsa_psk, [], [rsa_psk_3des_ede_cbc, - %% rsa_psk_rc4_128, - %% rsa_psk_aes_128_cbc, - %% rsa_psk_aes_256_cbc - %% ]}, - {dh_anon, [], [dh_anon_rc4_128, - dh_anon_3des_ede_cbc, - dh_anon_aes_128_cbc, - dh_anon_aes_128_gcm, - dh_anon_aes_256_cbc, - dh_anon_aes_256_gcm]}, - {ecdh_anon, [], [ecdh_anon_3des_ede_cbc, - ecdh_anon_aes_128_cbc, - ecdh_anon_aes_256_cbc - ]} - %% {srp_anon, [], [srp_anon_3des_ede_cbc, - %% srp_anon_aes_128_cbc, - %% srp_anon_aes_256_cbc]}, - %% {psk, [], [psk_3des_ede_cbc, - %% psk_rc4_128, - %% psk_aes_128_cbc, - %% psk_aes_128_ccm, - %% psk_aes_128_ccm_8, - %% psk_aes_256_cbc, - %% psk_aes_256_ccm, - %% psk_aes_256_ccm_8 - %% ]}, - %% {dhe_psk, [], [dhe_psk_3des_ede_cbc, - %% dhe_psk_rc4_128, - %% dhe_psk_aes_128_cbc, - %% dhe_psk_aes_128_ccm, - %% dhe_psk_aes_128_ccm_8, - %% dhe_psk_aes_256_cbc, - %% dhe_psk_aes_256_ccm, - %% dhe_psk_aes_256_ccm_8 - %% ]}, - %% {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc, - %% ecdhe_psk_rc4_128, - %% ecdhe_psk_aes_128_cbc, - %% ecdhe_psk_aes_128_ccm, - %% ecdhe_psk_aes_128_ccm_8, - %% ecdhe_psk_aes_256_cbc - %% ]} - ]. - -kex() -> - rsa() ++ ecdsa() ++ dss() ++ anonymous(). - -dtls_kex() -> %% Should be all kex in the future - dtls_rsa() ++ dss() ++ anonymous(). - -rsa() -> - [{group, dhe_rsa}, - {group, ecdhe_rsa}, - {group, rsa} %%, {group, srp_rsa}, - %%{group, rsa_psk} - ]. - -dtls_rsa() -> - [ - {group, rsa} - %%,{group, rsa_psk} - ]. - -ecdsa() -> - [{group, ecdhe_ecdsa}]. - -dss() -> - [{group, dhe_dss} - %%{group, srp_dss} - ]. - -anonymous() -> - [{group, dh_anon}, - {group, ecdh_anon} - %% {group, psk}, - %%{group, dhe_psk}, - %%{group, ecdhe_psk} - %%{group, srp_anon} - ]. - -init_per_suite(Config) -> - catch crypto:stop(), - try crypto:start() of - ok -> - ssl_test_lib:clean_start(), - Config - catch _:_ -> - {skip, "Crypto did not start"} - end. - -end_per_suite(_Config) -> - ssl:stop(), - application:stop(crypto), - ssl_test_lib:kill_openssl(). - -%%-------------------------------------------------------------------- -init_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - case ssl_test_lib:supports_ssl_tls_version(GroupName) of - true -> - case ssl_test_lib:check_sane_openssl_version(GroupName) of - true -> - ssl_test_lib:init_tls_version(GroupName, Config), - do_init_per_group(GroupName, Config); - false -> - {skip, openssl_does_not_support_version} - end; - false -> - {skip, {openssl_does_not_support, GroupName}} - end; - false -> - do_init_per_group(GroupName, Config) - end. - -do_init_per_group(GroupName, Config) when GroupName == ecdh_anon; - GroupName == ecdhe_rsa; - GroupName == ecdhe_psk -> - case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of - true -> - init_certs(GroupName, Config); - false -> - {skip, "Missing EC crypto support"} - end; -do_init_per_group(ecdhe_ecdsa = GroupName, Config) -> - PKAlg = proplists:get_value(public_keys, crypto:supports()), - case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of - true -> - init_certs(GroupName, Config); - false -> - {skip, "Missing EC crypto support"} - end; -do_init_per_group(dhe_dss = GroupName, Config) -> - PKAlg = proplists:get_value(public_keys, crypto:supports()), - case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of - true -> - init_certs(GroupName, Config); - false -> - {skip, "Missing DSS crypto support"} - end; -do_init_per_group(srp_dss = GroupName, Config) -> - PKAlg = proplists:get_value(public_keys, crypto:supports()), - case lists:member(dss, PKAlg) andalso lists:member(srp, PKAlg) of - true -> - init_certs(GroupName, Config); - false -> - {skip, "Missing DSS_SRP crypto support"} - end; -do_init_per_group(GroupName, Config) when GroupName == srp_anon; - GroupName == srp_rsa -> - PKAlg = proplists:get_value(public_keys, crypto:supports()), - case lists:member(srp, PKAlg) of - true -> - init_certs(GroupName, Config); - false -> - {skip, "Missing SRP crypto support"} - end; -do_init_per_group(dhe_psk = GroupName, Config) -> - PKAlg = proplists:get_value(public_keys, crypto:supports()), - case lists:member(dh, PKAlg) of - true -> - init_certs(GroupName, Config); - false -> - {skip, "Missing SRP crypto support"} - end; -do_init_per_group(GroupName, Config0) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - ssl_test_lib:init_tls_version(GroupName, end_per_group(GroupName, Config0)); - false -> - init_certs(GroupName, Config0) - end. - -end_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - ssl_test_lib:clean_tls_version(Config); - false -> - Config - end. - -init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc; - TestCase == srp_anon_3des_ede_cbc; - TestCase == dhe_psk_3des_ede_cbc; - TestCase == ecdhe_psk_3des_ede_cbc; - TestCase == srp_rsa_3des_ede_cbc; - TestCase == srp_dss_3des_ede_cbc; - TestCase == rsa_psk_3des_ede_cbc; - TestCase == rsa_3des_ede_cbc; - TestCase == dhe_rsa_3des_ede_cbc; - TestCase == dhe_dss_3des_ede_cbc; - TestCase == ecdhe_rsa_3des_ede_cbc; - TestCase == srp_anon_dss_3des_ede_cbc; - TestCase == dh_anon_3des_ede_cbc; - TestCase == ecdh_anon_3des_ede_cbc; - TestCase == ecdhe_ecdsa_3des_ede_cbc -> - SupCiphers = proplists:get_value(ciphers, crypto:supports()), - case lists:member(des_ede3, SupCiphers) of - true -> - ct:timetrap({seconds, 5}), - Config; - _ -> - {skip, "Missing 3DES crypto support"} - end; -init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128; - TestCase == ecdhe_psk_rc4_128; - TestCase == dhe_psk_rc4_128; - TestCase == rsa_psk_rc4_128; - TestCase == rsa_rc4_128; - TestCase == ecdhe_rsa_rc4_128; - TestCase == ecdhe_ecdsa_rc4_128; - TestCase == dh_anon_rc4_128 -> - SupCiphers = proplists:get_value(ciphers, crypto:supports()), - case lists:member(rc4, SupCiphers) of - true -> - ct:timetrap({seconds, 5}), - Config; - _ -> - {skip, "Missing RC4 crypto support"} - end; -init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8; - TestCase == rsa_psk_aes_128_ccm_8; - TestCase == psk_aes_128_ccm_8; - TestCase == dhe_psk_aes_128_ccm_8; - TestCase == ecdhe_psk_aes_128_ccm_8 -> - SupCiphers = proplists:get_value(ciphers, crypto:supports()), - case lists:member(aes_128_ccm, SupCiphers) of - true -> - ct:timetrap({seconds, 5}), - Config; - _ -> - {skip, "Missing AES_128_CCM crypto support"} - end; -init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8; - TestCase == rsa_psk_aes_256_ccm_8; - TestCase == psk_aes_256_ccm_8; - TestCase == dhe_psk_aes_256_ccm_8; - TestCase == ecdhe_psk_aes_256_ccm_8 -> - SupCiphers = proplists:get_value(ciphers, crypto:supports()), - case lists:member(aes_256_ccm, SupCiphers) of - true -> - ct:timetrap({seconds, 5}), - Config; - _ -> - {skip, "Missing AES_256_CCM crypto support"} - end; -init_per_testcase(TestCase, Config) -> - Cipher = ssl_test_lib:test_cipher(TestCase, Config), - SupCiphers = proplists:get_value(ciphers, crypto:supports()), - case lists:member(Cipher, SupCiphers) of - true -> - ct:timetrap({seconds, 5}), - Config; - _ -> - {skip, {Cipher, SupCiphers}} - end. - -end_per_testcase(_TestCase, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Initializtion ------------------------------------------ -%%-------------------------------------------------------------------- -init_certs(srp_rsa, Config) -> - {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, - {client_chain, ssl_test_lib:default_cert_chain_conf()}], - Config, ""), - [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts], - client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} | - proplists:delete(tls_config, Config)]; -init_certs(srp_anon, Config) -> - [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}], - client_config => [{srp_identity, {"Test-User", "secret"}}]}} | - proplists:delete(tls_config, Config)]; -init_certs(rsa_psk, Config) -> - Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]), - {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, - [[ssl_test_lib:digest()],[ssl_test_lib:digest()], - [ssl_test_lib:digest(), {extensions, Ext}]]}, - {client_chain, ssl_test_lib:default_cert_chain_conf()}], - Config, "_peer_keyEncipherment"), - PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>, - [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ServerOpts], - client_config => [{psk_identity, "Test-User"}, - {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ClientOpts]}} | - proplists:delete(tls_config, Config)]; -init_certs(rsa, Config) -> - Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]), - {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, - [[ssl_test_lib:digest()],[ssl_test_lib:digest()], - [ssl_test_lib:digest(), {extensions, Ext}]]} - ], - Config, "_peer_keyEncipherment"), - [{tls_config, #{server_config => ServerOpts, - client_config => ClientOpts}} | - proplists:delete(tls_config, Config)]; -init_certs(dhe_dss, Config) -> - {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, - {client_chain, ssl_test_lib:default_cert_chain_conf()}], - Config, ""), - [{tls_config, #{server_config => ServerOpts, - client_config => ClientOpts}} | - proplists:delete(tls_config, Config)]; -init_certs(srp_dss, Config) -> - {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, - {client_chain, ssl_test_lib:default_cert_chain_conf()}], - Config, ""), - [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts], - client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} | - proplists:delete(tls_config, Config)]; -init_certs(GroupName, Config) when GroupName == dhe_rsa; - GroupName == ecdhe_rsa -> - {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, - {client_chain, ssl_test_lib:default_cert_chain_conf()}], - Config, ""), - [{tls_config, #{server_config => ServerOpts, - client_config => ClientOpts}} | - proplists:delete(tls_config, Config)]; -init_certs(GroupName, Config) when GroupName == dhe_ecdsa; - GroupName == ecdhe_ecdsa -> - {ClientOpts, ServerOpts} = ssl_test_lib:make_ecc_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()}, - {client_chain, ssl_test_lib:default_cert_chain_conf()}], - Config, ""), - [{tls_config, #{server_config => ServerOpts, - client_config => ClientOpts}} | - proplists:delete(tls_config, Config)]; -init_certs(GroupName, Config) when GroupName == psk; - GroupName == dhe_psk; - GroupName == ecdhe_psk -> - PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>, - [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}], - client_config => [{psk_identity, "Test-User"}, - {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}]}} | - proplists:delete(tls_config, Config)]; -init_certs(srp, Config) -> - [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}], - client_config => [{srp_identity, {"Test-User", "secret"}}]}} | - proplists:delete(tls_config, Config)]; -init_certs(_GroupName, Config) -> - %% Anonymous does not need certs - [{tls_config, #{server_config => [], - client_config => []}} | - proplists:delete(tls_config, Config)]. -%%-------------------------------------------------------------------- -%% Test Cases -------------------------------------------------------- -%%-------------------------------------------------------------------- - -%%-------------------------------------------------------------------- -%% SRP -------------------------------------------------------- -%%-------------------------------------------------------------------- -srp_rsa_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_rsa, '3des_ede_cbc', Config). - -srp_rsa_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_rsa, 'aes_128_cbc', Config). - -srp_rsa_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_rsa, 'aes_256_cbc', Config). - -srp_dss_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_dss, '3des_ede_cbc', Config). - -srp_dss_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_dss, 'aes_128_cbc', Config). - -srp_dss_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_dss, 'aes_256_cbc', Config). - -%%-------------------------------------------------------------------- -%% PSK -------------------------------------------------------- -%%-------------------------------------------------------------------- -rsa_psk_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, '3des_ede_cbc', Config). - -rsa_psk_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, 'aes_128_cbc', Config). - -rsa_psk_aes_128_ccm(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, 'aes_128_ccm', Config). - -rsa_psk_aes_128_ccm_8(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, 'aes_128_ccm_8', Config). - -rsa_psk_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, 'aes_256_cbc', Config). - -rsa_psk_aes_256_ccm(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, 'aes_256_ccm', Config). - -rsa_psk_aes_256_ccm_8(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, 'aes_256_ccm_8', Config). - -rsa_psk_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(rsa_psk, 'rc4_128', Config). - -%%-------------------------------------------------------------------- -%% RSA -------------------------------------------------------- -%%-------------------------------------------------------------------- -rsa_des_cbc(Config) when is_list(Config) -> - run_ciphers_test(rsa, 'des_cbc', Config). - -rsa_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(rsa, '3des_ede_cbc', Config). - -rsa_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(rsa, 'aes_128_cbc', Config). - -rsa_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(rsa, 'aes_256_cbc', Config). - -rsa_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(rsa, 'aes_128_gcm', Config). - -rsa_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(rsa, 'aes_256_gcm', Config). - -rsa_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(rsa, 'rc4_128', Config). -%%-------------------------------------------------------------------- -%% DHE_RSA -------------------------------------------------------- -%%-------------------------------------------------------------------- -dhe_rsa_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_rsa, '3des_ede_cbc', Config). - -dhe_rsa_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_rsa, 'aes_128_cbc', Config). - -dhe_rsa_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(dhe_rsa, 'aes_128_gcm', Config). - -dhe_rsa_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config). - -dhe_rsa_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config). - -dhe_rsa_chacha20_poly1305(Config) when is_list(Config) -> - run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config). -%%-------------------------------------------------------------------- -%% ECDHE_RSA -------------------------------------------------------- -%%-------------------------------------------------------------------- -ecdhe_rsa_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_rsa, '3des_ede_cbc', Config). - -ecdhe_rsa_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_rsa, 'aes_128_cbc', Config). - -ecdhe_rsa_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_rsa, 'aes_128_gcm', Config). - -ecdhe_rsa_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_rsa, 'aes_256_cbc', Config). - -ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_rsa, 'aes_256_gcm', Config). - -ecdhe_rsa_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_rsa, 'rc4_128', Config). - -ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config). - -%%-------------------------------------------------------------------- -%% ECDHE_ECDSA -------------------------------------------------------- -%%-------------------------------------------------------------------- -ecdhe_ecdsa_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_ecdsa, 'rc4_128', Config). - -ecdhe_ecdsa_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_ecdsa, '3des_ede_cbc', Config). - -ecdhe_ecdsa_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_ecdsa, 'aes_128_cbc', Config). - -ecdhe_ecdsa_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_ecdsa, 'aes_128_gcm', Config). - -ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_ecdsa, 'aes_256_cbc', Config). - -ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config). - -ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config). -%%-------------------------------------------------------------------- -%% DHE_DSS -------------------------------------------------------- -%%-------------------------------------------------------------------- -dhe_dss_des_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_dss, 'des_cbc', Config). - -dhe_dss_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_dss, '3des_ede_cbc', Config). - -dhe_dss_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_dss, 'aes_128_cbc', Config). - -dhe_dss_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_dss, 'aes_256_cbc', Config). - -dhe_dss_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(dhe_dss, 'aes_128_gcm', Config). - -dhe_dss_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(dhe_dss, 'aes_256_gcm', Config). - -%%-------------------------------------------------------------------- -%% Anonymous -------------------------------------------------------- -%%-------------------------------------------------------------------- -dh_anon_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(dh_anon, '3des_ede_cbc', Config). - -dh_anon_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(dh_anon, 'aes_128_cbc', Config). - -dh_anon_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(dh_anon, 'aes_128_gcm', Config). - -dh_anon_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(dh_anon, 'aes_256_cbc', Config). - -dh_anon_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(dh_anon, 'aes_256_gcm', Config). - -dh_anon_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(dh_anon, 'rc4_128', Config). - -ecdh_anon_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdh_anon, '3des_ede_cbc', Config). - -ecdh_anon_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdh_anon, 'aes_128_cbc', Config). - -ecdh_anon_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config). - -srp_anon_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_anon, '3des_ede_cbc', Config). - -srp_anon_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_anon, 'aes_128_cbc', Config). - -srp_anon_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(srp_anon, 'aes_256_cbc', Config). - -dhe_psk_des_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'des_cbc', Config). - -dhe_psk_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'rc4_128', Config). - -dhe_psk_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, '3des_ede_cbc', Config). - -dhe_psk_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_128_cbc', Config). - -dhe_psk_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_256_cbc', Config). - -dhe_psk_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_128_gcm', Config). - -dhe_psk_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_256_gcm', Config). - -dhe_psk_aes_128_ccm(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_128_ccm', Config). - -dhe_psk_aes_256_ccm(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_256_ccm', Config). - -dhe_psk_aes_128_ccm_8(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_128_ccm_8', Config). - -dhe_psk_aes_256_ccm_8(Config) when is_list(Config) -> - run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config). - -ecdhe_psk_des_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'des_cbc', Config). - -ecdhe_psk_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'rc4_128', Config). - -ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config). - -ecdhe_psk_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config). - -ecdhe_psk_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config). - -ecdhe_psk_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config). - -ecdhe_psk_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config). - -ecdhe_psk_aes_128_ccm(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config). - -ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) -> - run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config). - -psk_des_cbc(Config) when is_list(Config) -> - run_ciphers_test(psk, 'des_cbc', Config). - -psk_rc4_128(Config) when is_list(Config) -> - run_ciphers_test(psk, 'rc4_128', Config). - -psk_3des_ede_cbc(Config) when is_list(Config) -> - run_ciphers_test(psk, '3des_ede_cbc', Config). - -psk_aes_128_cbc(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_128_cbc', Config). - -psk_aes_256_cbc(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_256_cbc', Config). - -psk_aes_128_gcm(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_128_gcm', Config). - -psk_aes_256_gcm(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_256_gcm', Config). - -psk_aes_128_ccm(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_128_ccm', Config). - -psk_aes_256_ccm(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_256_ccm', Config). - -psk_aes_128_ccm_8(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_128_ccm_8', Config). - -psk_aes_256_ccm_8(Config) when is_list(Config) -> - run_ciphers_test(psk, 'aes_256_ccm_8', Config). - -%%-------------------------------------------------------------------- -%% Internal functions ---------------------------------------------- -%%-------------------------------------------------------------------- -run_ciphers_test(Kex, Cipher, Config) -> - Version = ssl_test_lib:protocol_version(Config), - TestCiphers = test_ciphers(Kex, Cipher, Version), - - case TestCiphers of - [_|_] -> - lists:foreach(fun(TestCipher) -> - cipher_suite_test(TestCipher, Version, Config) - end, TestCiphers); - [] -> - {skip, {not_sup, Kex, Cipher, Version}} - end. - -cipher_suite_test(CipherSuite, _Version, Config) -> - #{server_config := SOpts, - client_config := COpts} = proplists:get_value(tls_config, Config), - ServerOpts = ssl_test_lib:ssl_options(SOpts, Config), - ClientOpts = ssl_test_lib:ssl_options(COpts, Config), - ct:log("Testing CipherSuite ~p~n", [CipherSuite]), - ct:log("Server Opts ~p~n", [ServerOpts]), - ct:log("Client Opts ~p~n", [ClientOpts]), - ssl_test_lib:basic_test([{ciphers, [CipherSuite]} | COpts], SOpts, [{client_type, erlang}, - {server_type, openssl} | Config]). - - -test_ciphers(Kex, Cipher, Version) -> - Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, Version) ++ ssl:cipher_suites(anonymous, Version), - [{key_exchange, - fun(Kex0) when Kex0 == Kex -> true; - (_) -> false - end}, - {cipher, - fun(Cipher0) when Cipher0 == Cipher -> true; - (_) -> false - end}]), - ct:log("Version ~p Testing ~p~n", [Version, Ciphers]), - OpenSSLCiphers = openssl_ciphers(), - ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]), - lists:filter(fun(C) -> - ct:log("Cipher ~p~n", [C]), - lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers) - end, Ciphers). - - -openssl_ciphers() -> - Str = os:cmd("openssl ciphers"), - string:split(string:strip(Str, right, $\n), ":", all). diff --git a/lib/ssl/test/openssl_session_SUITE.erl b/lib/ssl/test/openssl_session_SUITE.erl new file mode 100644 index 0000000000..24dcaa7817 --- /dev/null +++ b/lib/ssl/test/openssl_session_SUITE.erl @@ -0,0 +1,262 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(openssl_session_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(SLEEP, 1000). +-define(EXPIRE, 10). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'}]; + false -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}] + end. + +groups() -> + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{'tlsv1.2', [], tests()}, + {'tlsv1.1', [], tests()}, + {'tlsv1', [], tests()}, + {'sslv3', [], tests()}, + {'dtlsv1.2', [], dtls_tests()}, + {'dtlsv1', [], dtls_tests()} + ]; + false -> + [{'tlsv1.2', [], tests()}, + {'tlsv1.1', [], tests()}, + {'tlsv1', [], tests()}, + {'sslv3', [], tests()} + ] + end. + +tests() -> + [ + reuse_session_erlang_server, + reuse_session_erlang_client + ]. + +dtls_tests() -> + [ + reuse_session_erlang_server + ]. + + +init_per_suite(Config0) -> + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + ct:pal("Version: ~p", [os:cmd("openssl version")]), + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + ssl_test_lib:make_rsa_cert(Config0) + catch _:_ -> + {skip, "Crypto did not start"} + end + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto), + ssl_test_lib:kill_openssl(). + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:supports_ssl_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, openssl_does_not_support_version} + end; + false -> + {skip, openssl_does_not_support_version} + end; + _ -> + ssl:start(), + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(reuse_session_erlang_client, Config) -> + ct:timetrap(?EXPIRE * 1000 * 5), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_lifetime, ?EXPIRE), + ssl:start(), + Config; + +init_per_testcase(TestCase, Config) -> + ct:timetrap({seconds, 10}), + Config. + +end_per_testcase(reuse_session_erlang_client, Config) -> + application:unset_env(ssl, session_lifetime), + Config; +end_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +reuse_session_erlang_server() -> + [{doc, "Test erlang server with openssl client that reconnects with the" + "same session id, to test reusing of sessions."}]. +reuse_session_erlang_server(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, active_recv, [length(Data)]}}, + {reconnect_times, 5}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname) + ++ ":" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-reconnect"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + true = port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, Data), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close(Server), + ssl_test_lib:close_port(OpenSslPort). + +%%-------------------------------------------------------------------- + +reuse_session_erlang_client() -> + [{doc, "Test erlang ssl client that wants to reuse sessions"}]. +reuse_session_erlang_client(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + CACertFile = proplists:get_value(cacertfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + "-cert", CertFile,"-key", KeyFile, "-CAfile", CACertFile], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, tls), + + Client0 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_sessions, save}, {verify, verify_peer}| ClientOpts]}]), + + SID = receive + {Client0, Id0} -> + Id0 + end, + + ssl_test_lib:close(Client0), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_session, SID} | ClientOpts]}]), + receive + {Client1, SID} -> + ok + after ?SLEEP -> + ct:fail(session_not_reused) + end, + + + ssl_test_lib:close(Client1), + %% Make sure session is unregistered due to expiration + ct:sleep(20000), + + Client2 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client2, ID} -> + case ID of + SID -> + ct:fail(expired_session_reused); + _ -> + ok + end + end, + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + ssl_test_lib:close(Client2). + + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- diff --git a/lib/ssl/test/openssl_sni_SUITE.erl b/lib/ssl/test/openssl_sni_SUITE.erl new file mode 100644 index 0000000000..26f08e36c0 --- /dev/null +++ b/lib/ssl/test/openssl_sni_SUITE.erl @@ -0,0 +1,251 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(openssl_sni_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(OPENSSL_QUIT, "Q\n"). +-define(OPENSSL_RENEGOTIATE, "R\n"). +-define(SLEEP, 1000). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + %% Note: SNI not supported in sslv3 + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'} + %% Seems broken in openssl + %%{group, 'dtlsv1.2'}, + %%{group, 'dtlsv1'} + ]; + false -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}] + end. + +groups() -> + case ssl_test_lib:openssl_sane_dtls() of + true -> + [{'tlsv1.2', [], sni_tests()}, + {'tlsv1.1', [], sni_tests()}, + {'tlsv1', [], sni_tests()} + %% Seems broken in openssl + %%{'dtlsv1.2', [], sni_tests()}, + %%{'dtlsv1', [], sni_tests()} + ]; + false -> + [{'tlsv1.2', [], sni_tests()}, + {'tlsv1.1', [], sni_tests()}, + {'tlsv1', [], sni_tests()} + ] + end. + +sni_tests() -> + [erlang_server_openssl_client_sni_match, + erlang_server_openssl_client_sni_match_fun, + erlang_server_openssl_client_sni_no_match, + erlang_server_openssl_client_sni_no_match_fun, + erlang_server_openssl_client_sni_no_header, + erlang_server_openssl_client_sni_no_header_fun]. + +init_per_suite(Config0) -> + case os:find_executable("openssl") of + false -> + {skip, "Openssl not found"}; + _ -> + case check_openssl_sni_support(Config0) of + {skip, _} = Skip -> + Skip; + _ -> + ct:pal("Version: ~p", [os:cmd("openssl version")]), + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config = ssl_test_lib:make_rsa_cert(Config0), + RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + [{sni_server_opts, [{sni_hosts, + [{"a.server", [ + {certfile, proplists:get_value(certfile, RsaOpts)}, + {keyfile, proplists:get_value(keyfile, RsaOpts)} + ]}, + {"b.server", [ + {certfile, proplists:get_value(certfile, RsaOpts)}, + {keyfile, proplists:get_value(keyfile, RsaOpts)} + ]} + ]}]} | Config] + catch _:_ -> + {skip, "Crypto did not start"} + end + end + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto), + ssl_test_lib:kill_openssl(). + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:supports_ssl_tls_version(GroupName) of + true -> + case ssl_test_lib:check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, openssl_does_not_support_version} + end; + false -> + {skip, openssl_does_not_support_version} + end; + _ -> + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(_TestCase, Config) -> + ct:timetrap({seconds, 10}), + Config. + + +end_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +erlang_server_openssl_client_sni_no_header(Config) when is_list(Config) -> + erlang_server_openssl_client_sni_test(Config, undefined, undefined, "server Peer cert"). + +erlang_server_openssl_client_sni_no_header_fun(Config) when is_list(Config) -> + erlang_server_openssl_client_sni_test_sni_fun(Config, undefined, undefined, "server Peer cert"). + +erlang_server_openssl_client_sni_match(Config) when is_list(Config) -> + erlang_server_openssl_client_sni_test(Config, "a.server", "a.server", "server Peer cert"). + +erlang_server_openssl_client_sni_match_fun(Config) when is_list(Config) -> + erlang_server_openssl_client_sni_test_sni_fun(Config, "a.server", "a.server", "server Peer cert"). + +erlang_server_openssl_client_sni_no_match(Config) when is_list(Config) -> + erlang_server_openssl_client_sni_test(Config, "c.server", undefined, "server Peer cert"). + +erlang_server_openssl_client_sni_no_match_fun(Config) when is_list(Config) -> + erlang_server_openssl_client_sni_test_sni_fun(Config, "c.server", undefined, "server Peer cert"). + + +erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) -> + Version = ssl_test_lib:protocol_version(Config), + ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", + [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]), + ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config), + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, + {options, ServerOptions}]), + Port = ssl_test_lib:inet_port(Server), + Exe = "openssl", + ClientArgs = case SNIHostname of + undefined -> + openssl_client_args(Version, Hostname,Port); + _ -> + openssl_client_args(Version, Hostname, Port, SNIHostname) + end, + ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), + + ssl_test_lib:check_result(Server, ExpectedSNIHostname), + ssl_test_lib:close_port(ClientPort), + ssl_test_lib:close(Server), + ok. + + +erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) -> + Version = ssl_test_lib:protocol_version(Config), + ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", + [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]), + [{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config), + SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end, + ServerOptions = proplists:get_value(server_rsa_opts, Config) ++ [{sni_fun, SNIFun}], + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, + {options, ServerOptions}]), + Port = ssl_test_lib:inet_port(Server), + Exe = "openssl", + ClientArgs = case SNIHostname of + undefined -> + openssl_client_args(Version, Hostname,Port); + _ -> + openssl_client_args(Version, Hostname, Port, SNIHostname) + end, + + ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), + + ssl_test_lib:check_result(Server, ExpectedSNIHostname), + ssl_test_lib:close_port(ClientPort), + ssl_test_lib:close(Server). + +send_and_hostname(SSLSocket) -> + ssl:send(SSLSocket, "OK"), + case ssl:connection_information(SSLSocket, [sni_hostname]) of + {ok, []} -> + undefined; + {ok, [{sni_hostname, Hostname}]} -> + Hostname + end. + +openssl_client_args(Version, Hostname, Port) -> + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)]. + +openssl_client_args(Version, Hostname, Port, ServerName) -> + ["s_client", "-connect", Hostname ++ ":" ++ + integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName]. + +check_openssl_sni_support(Config) -> + HelpText = os:cmd("openssl s_client --help"), + case ssl_test_lib:is_sane_oppenssl_client() of + true -> + case string:str(HelpText, "-servername") of + 0 -> + {skip, "Current openssl doesn't support SNI"}; + _ -> + Config + end; + false -> + {skip, "Current openssl doesn't support SNI or extension handling is flawed"} + end. diff --git a/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl b/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl new file mode 100644 index 0000000000..8a2692ec1d --- /dev/null +++ b/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl @@ -0,0 +1,172 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(openssl_tls_1_3_version_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + %%{group, openssl_server}, + {group, openssl_client} + ]. + +groups() -> + [ + %%{openssl_server, [{group, 'tlsv1.3'}]}, + {openssl_client, [{group, 'tlsv1.3'}]}, + {'tlsv1.3', [], cert_groups()}, + {rsa, [], tests()}, + {ecdsa, [], tests()} + ]. + +cert_groups() -> + [{group, rsa}, + {group, ecdsa}]. + +tests() -> + [tls13_client_tls12_server, + %%tls13_client_with_ext_tls12_server, + tls12_client_tls13_server]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + case ssl_test_lib:check_sane_openssl_version('tlsv1.3') of + true -> + ssl_test_lib:clean_start(), + Config; + false -> + {skip, openssl_does_not_support_version} + end + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +init_per_group(openssl_client, Config0) -> + Config = proplists:delete(server_type, proplists:delete(client_type, Config0)), + [{client_type, openssl}, {server_type, erlang} | Config]; +init_per_group(openssl_server, Config0) -> + Config = proplists:delete(server_type, proplists:delete(client_type, Config0)), + [{client_type, erlang}, {server_type, openssl} | Config]; +init_per_group(rsa, Config0) -> + Config = ssl_test_lib:make_rsa_cert(Config0), + COpts = proplists:get_value(client_rsa_opts, Config), + SOpts = proplists:get_value(server_rsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; +init_per_group(ecdsa, Config0) -> + PKAlg = crypto:supports(public_keys), + case lists:member(ecdsa, PKAlg) andalso + (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of + true -> + Config = ssl_test_lib:make_ecdsa_cert(Config0), + COpts = proplists:get_value(client_ecdsa_opts, Config), + SOpts = proplists:get_value(server_ecdsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; + false -> + {skip, "Missing EC crypto support"} + end; +init_per_group(GroupName, Config) -> + ssl_test_lib:clean_tls_version(Config), + case ssl_test_lib:is_tls_version(GroupName) andalso + ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + _ -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl:start(), + Config; + false -> + {skip, "Missing crypto support"} + end + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +tls13_client_tls12_server() -> + [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}]. + +tls13_client_tls12_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%% tls13_client_with_ext_tls12_server() -> +%% [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when " +%% "client has TLS 1.3 specsific extensions"}]. + +%% tls13_client_with_ext_tls12_server(Config) -> +%% ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), +%% ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + +%% {ServerOpts, ClientOpts} = +%% case proplists:get_value(client_type) of +%% erlang -> +%% {[{versions, ['tlsv1.2']}|ServerOpts0], +%% [{versions, ['tlsv1.2','tlsv1.3']}, +%% {signature_algs_cert, [ecdsa_secp384r1_sha384, +%% ecdsa_secp256r1_sha256, +%% rsa_pss_rsae_sha256, +%% rsa_pkcs1_sha256, +%% {sha256,rsa},{sha256,dsa}]}|ClientOpts0]}; +%% openssl -> + + +%% ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls12_client_tls13_server() -> + [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}]. + +tls12_client_tls13_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + diff --git a/lib/ssl/test/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl index 38a4b7fb11..31934ada2b 100644 --- a/lib/ssl/test/property_test/ssl_eqc_handshake.erl +++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl @@ -133,6 +133,14 @@ client_hello(Version) -> random = client_random(Version), extensions = client_hello_extensions(Version) }. +client_hello(?'SSL_v3' = Version) -> + #client_hello{session_id = session_id(), + client_version = Version, + cipher_suites = cipher_suites(Version), + compression_methods = compressions(Version), + random = client_random(Version), + extensions = undefined + }. server_hello(?'TLS_v1.3' = Version) -> #server_hello{server_version = ?'TLS_v1.2', @@ -142,6 +150,14 @@ server_hello(?'TLS_v1.3' = Version) -> compression_method = compression(Version), extensions = server_hello_extensions(Version) }; +server_hello(?'SSL_v3' = Version) -> + #server_hello{server_version = Version, + session_id = session_id(), + random = server_random(Version), + cipher_suite = cipher_suite(Version), + compression_method = compression(Version), + extensions = undefined + }; server_hello(Version) -> #server_hello{server_version = Version, session_id = session_id(), diff --git a/lib/ssl/test/ssl_alpn_SUITE.erl b/lib/ssl/test/ssl_alpn_SUITE.erl new file mode 100644 index 0000000000..82a49e1469 --- /dev/null +++ b/lib/ssl/test/ssl_alpn_SUITE.erl @@ -0,0 +1,397 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_alpn_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). + +-define(SLEEP, 500). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + [ + {group, 'tlsv1.3'}, + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'} + ]. + +groups() -> + [ + {'tlsv1.3', [], alpn_tests() -- [client_renegotiate, session_reused]}, + {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()}, + {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist()}, + {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist()}, + {'sslv3', [], alpn_not_supported()}, + {'dtlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()}, + {'dtlsv1', [], alpn_tests() ++ alpn_npn_coexist()} + ]. + +alpn_tests() -> + [empty_protocols_are_not_allowed, + protocols_must_be_a_binary_list, + empty_client, + empty_server, + empty_client_empty_server, + no_matching_protocol, + client_alpn_and_server_alpn, + client_alpn_and_server_no_support, + client_no_support_and_server_alpn, + client_alpn_npn_and_server_alpn, + client_renegotiate, + session_reused + ]. + +alpn_npn_coexist() -> + [ + client_alpn_npn_and_server_alpn_npn, + client_alpn_and_server_alpn_npn + ]. + +alpn_not_supported() -> + [alpn_not_supported_client, + alpn_not_supported_server + ]. + +init_per_suite(Config0) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + ssl_test_lib:make_rsa_cert(Config0) + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:unload(ssl), + application:stop(crypto). + + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, "Missing crypto support"} + end; + _ -> + ssl:start(), + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + + +init_per_testcase(_TestCase, Config) -> + ssl_test_lib:ct_log_supported_protocol_versions(Config), + ct:timetrap({seconds, 10}), + Config. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +empty_protocols_are_not_allowed(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + {error, {options, {alpn_preferred_protocols, {invalid_protocol, <<>>}}}} + = (catch ssl:listen(9443, + [{alpn_preferred_protocols, [<<"foo/1">>, <<"">>]}| ServerOpts])), + {error, {options, {alpn_advertised_protocols, {invalid_protocol, <<>>}}}} + = (catch ssl:connect({127,0,0,1}, 9443, + [{alpn_advertised_protocols, [<<"foo/1">>, <<"">>]} | ServerOpts])). + +%-------------------------------------------------------------------------------- + +protocols_must_be_a_binary_list(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + Option1 = {alpn_preferred_protocols, hello}, + {error, {options, Option1}} = (catch ssl:listen(9443, [Option1 | ServerOpts])), + Option2 = {alpn_preferred_protocols, [<<"foo/1">>, hello]}, + {error, {options, {alpn_preferred_protocols, {invalid_protocol, hello}}}} + = (catch ssl:listen(9443, [Option2 | ServerOpts])), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + Option3 = {alpn_advertised_protocols, hello}, + {error, {options, Option3}} = (catch ssl:connect({127,0,0,1}, 9443, [Option3 | ClientOpts])), + Option4 = {alpn_advertised_protocols, [<<"foo/1">>, hello]}, + {error, {options, {alpn_advertised_protocols, {invalid_protocol, hello}}}} + = (catch ssl:connect({127,0,0,1}, 9443, [Option4 | ClientOpts])). + +%-------------------------------------------------------------------------------- + +empty_client(Config) when is_list(Config) -> + run_failing_handshake(Config, + [{alpn_advertised_protocols, []}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], + no_application_protocol). + +%-------------------------------------------------------------------------------- + +empty_server(Config) when is_list(Config) -> + run_failing_handshake(Config, + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], + [{alpn_preferred_protocols, []}], + no_application_protocol). + +%-------------------------------------------------------------------------------- + +empty_client_empty_server(Config) when is_list(Config) -> + run_failing_handshake(Config, + [{alpn_advertised_protocols, []}], + [{alpn_preferred_protocols, []}], + no_application_protocol). + +%-------------------------------------------------------------------------------- + +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">>]}], + no_application_protocol). + +%-------------------------------------------------------------------------------- + +client_alpn_and_server_alpn(Config) when is_list(Config) -> + run_handshake(Config, + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). + +%-------------------------------------------------------------------------------- + +client_alpn_and_server_no_support(Config) when is_list(Config) -> + run_handshake(Config, + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], + [], + {error, protocol_not_negotiated}). + +%-------------------------------------------------------------------------------- + +client_no_support_and_server_alpn(Config) when is_list(Config) -> + run_handshake(Config, + [], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {error, protocol_not_negotiated}). + +%-------------------------------------------------------------------------------- + +client_alpn_npn_and_server_alpn(Config) when is_list(Config) -> + run_handshake(Config, + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}, + {client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"spdy/3">>}}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). + +%-------------------------------------------------------------------------------- + +client_alpn_npn_and_server_alpn_npn(Config) when is_list(Config) -> + run_handshake(Config, + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}, + {client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"spdy/3">>}}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, + {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). + +%-------------------------------------------------------------------------------- + +client_alpn_and_server_alpn_npn(Config) when is_list(Config) -> + run_handshake(Config, + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, + {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). + +%-------------------------------------------------------------------------------- + +client_renegotiate(Config) when is_list(Config) -> + Data = "hello world", + + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ClientOpts = [{alpn_advertised_protocols, [<<"http/1.0">>]}] ++ ClientOpts0, + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, + ExpectedProtocol = {ok, <<"http/1.0">>}, + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, ssl_receive_and_assert_alpn, [ExpectedProtocol, Data]}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, assert_alpn_and_renegotiate_and_send_data, [ExpectedProtocol, Data]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + +%-------------------------------------------------------------------------------- + +session_reused(Config) when is_list(Config)-> + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts = [{alpn_advertised_protocols, [<<"http/1.0">>]}] ++ ClientOpts0, + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, + + ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). +%-------------------------------------------------------------------------------- + +alpn_not_supported_client(Config) when is_list(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), + PrefProtocols = {client_preferred_next_protocols, + {client, [<<"http/1.0">>], <<"http/1.1">>}}, + ClientOpts = [PrefProtocols] ++ ClientOpts0, + {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, + {port, 8888}, {host, Hostname}, + {from, self()}, {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, {error, + {options, + {not_supported_in_sslv3, PrefProtocols}}}). + +%-------------------------------------------------------------------------------- + +alpn_not_supported_server(Config) when is_list(Config)-> + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, + ServerOpts = [AdvProtocols] ++ ServerOpts0, + + {error, {options, {not_supported_in_sslv3, AdvProtocols}}} = ssl:listen(0, ServerOpts). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- + +run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedAlert) -> + ClientOpts = ClientExtraOpts ++ ssl_test_lib:ssl_options(client_rsa_opts, Config), + 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_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, placeholder, []}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, placeholder, []}}, + {options, ClientOpts}]), + ssl_test_lib:check_client_alert(Server, Client, ExpectedAlert). + +run_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> + Data = "hello world", + + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ClientOpts = ClientExtraOpts ++ ClientOpts0, + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = ServerExtraOpts ++ ServerOpts0, + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, ssl_receive_and_assert_alpn, [ExpectedProtocol, Data]}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, ssl_send_and_assert_alpn, [ExpectedProtocol, Data]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + +assert_alpn(Socket, Protocol) -> + ct:log("Negotiated Protocol ~p, Expecting: ~p ~n", + [ssl:negotiated_protocol(Socket), Protocol]), + Protocol = ssl:negotiated_protocol(Socket). + +assert_alpn_and_renegotiate_and_send_data(Socket, Protocol, Data) -> + assert_alpn(Socket, Protocol), + ct:log("Renegotiating ~n", []), + ok = ssl:renegotiate(Socket), + ssl:send(Socket, Data), + assert_alpn(Socket, Protocol), + ok. + +ssl_send_and_assert_alpn(Socket, Protocol, Data) -> + assert_alpn(Socket, Protocol), + ssl_send(Socket, Data). + +ssl_receive_and_assert_alpn(Socket, Protocol, Data) -> + assert_alpn(Socket, Protocol), + ssl_receive(Socket, Data). + +ssl_send(Socket, Data) -> + ct:log("Connection info: ~p~n", + [ssl:connection_information(Socket)]), + ssl:send(Socket, Data). + +ssl_receive(Socket, Data) -> + ssl_receive(Socket, Data, []). + +ssl_receive(Socket, Data, Buffer) -> + ct:log("Connection info: ~p~n", + [ssl:connection_information(Socket)]), + receive + {ssl, Socket, MoreData} -> + ct:log("Received ~p~n",[MoreData]), + NewBuffer = Buffer ++ MoreData, + case NewBuffer of + Data -> + ssl:send(Socket, "Got it"), + ok; + _ -> + ssl_receive(Socket, Data, NewBuffer) + end; + Other -> + ct:fail({unexpected_message, Other}) + after 4000 -> + ct:fail({did_not_get, Data}) + end. + +connection_info_result(Socket) -> + ssl:connection_information(Socket). diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl deleted file mode 100644 index dfc780479e..0000000000 --- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl +++ /dev/null @@ -1,391 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2018. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% --module(ssl_alpn_handshake_SUITE). - -%% Note: This directive should only be used in test suites. --compile(export_all). --include_lib("common_test/include/ct.hrl"). - --define(SLEEP, 500). - -%%-------------------------------------------------------------------- -%% Common Test interface functions ----------------------------------- -%%-------------------------------------------------------------------- - -all() -> - [{group, 'tlsv1.2'}, - {group, 'tlsv1.1'}, - {group, 'tlsv1'}, - {group, 'sslv3'}, - {group, 'dtlsv1.2'}, - {group, 'dtlsv1'} - ]. - -groups() -> - [ - {'tlsv1.2', [], alpn_tests()}, - {'tlsv1.1', [], alpn_tests()}, - {'tlsv1', [], alpn_tests()}, - {'sslv3', [], alpn_not_supported()}, - {'dtlsv1.2', [], alpn_tests() -- [client_renegotiate]}, - {'dtlsv1', [], alpn_tests() -- [client_renegotiate]} - ]. - -alpn_tests() -> - [empty_protocols_are_not_allowed, - protocols_must_be_a_binary_list, - empty_client, - empty_server, - empty_client_empty_server, - no_matching_protocol, - client_alpn_and_server_alpn, - client_alpn_and_server_no_support, - client_no_support_and_server_alpn, - client_alpn_npn_and_server_alpn, - client_alpn_npn_and_server_alpn_npn, - client_alpn_and_server_alpn_npn, - client_renegotiate, - session_reused - ]. - -alpn_not_supported() -> - [alpn_not_supported_client, - alpn_not_supported_server - ]. - -init_per_suite(Config0) -> - catch crypto:stop(), - try crypto:start() of - ok -> - ssl_test_lib:clean_start(), - Config = ssl_test_lib:make_rsa_cert(Config0), - ssl_test_lib:cert_options(Config) - catch _:_ -> - {skip, "Crypto did not start"} - end. - -end_per_suite(_Config) -> - ssl:stop(), - application:unload(ssl), - application:stop(crypto). - - -init_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - case ssl_test_lib:sufficient_crypto_support(GroupName) of - true -> - ssl_test_lib:init_tls_version(GroupName, Config); - false -> - {skip, "Missing crypto support"} - end; - _ -> - ssl:start(), - Config - end. - -end_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - ssl_test_lib:clean_tls_version(Config); - false -> - Config - end. - - -init_per_testcase(_TestCase, Config) -> - ssl_test_lib:ct_log_supported_protocol_versions(Config), - ct:timetrap({seconds, 10}), - Config. - -end_per_testcase(_TestCase, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Test Cases -------------------------------------------------------- -%%-------------------------------------------------------------------- - -empty_protocols_are_not_allowed(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {error, {options, {alpn_preferred_protocols, {invalid_protocol, <<>>}}}} - = (catch ssl:listen(9443, - [{alpn_preferred_protocols, [<<"foo/1">>, <<"">>]}| ServerOpts])), - {error, {options, {alpn_advertised_protocols, {invalid_protocol, <<>>}}}} - = (catch ssl:connect({127,0,0,1}, 9443, - [{alpn_advertised_protocols, [<<"foo/1">>, <<"">>]} | ServerOpts])). - -%-------------------------------------------------------------------------------- - -protocols_must_be_a_binary_list(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - Option1 = {alpn_preferred_protocols, hello}, - {error, {options, Option1}} = (catch ssl:listen(9443, [Option1 | ServerOpts])), - Option2 = {alpn_preferred_protocols, [<<"foo/1">>, hello]}, - {error, {options, {alpn_preferred_protocols, {invalid_protocol, hello}}}} - = (catch ssl:listen(9443, [Option2 | ServerOpts])), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - Option3 = {alpn_advertised_protocols, hello}, - {error, {options, Option3}} = (catch ssl:connect({127,0,0,1}, 9443, [Option3 | ClientOpts])), - Option4 = {alpn_advertised_protocols, [<<"foo/1">>, hello]}, - {error, {options, {alpn_advertised_protocols, {invalid_protocol, hello}}}} - = (catch ssl:connect({127,0,0,1}, 9443, [Option4 | ClientOpts])). - -%-------------------------------------------------------------------------------- - -empty_client(Config) when is_list(Config) -> - run_failing_handshake(Config, - [{alpn_advertised_protocols, []}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], - no_application_protocol). - -%-------------------------------------------------------------------------------- - -empty_server(Config) when is_list(Config) -> - run_failing_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], - [{alpn_preferred_protocols, []}], - no_application_protocol). - -%-------------------------------------------------------------------------------- - -empty_client_empty_server(Config) when is_list(Config) -> - run_failing_handshake(Config, - [{alpn_advertised_protocols, []}], - [{alpn_preferred_protocols, []}], - no_application_protocol). - -%-------------------------------------------------------------------------------- - -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">>]}], - no_application_protocol). - -%-------------------------------------------------------------------------------- - -client_alpn_and_server_alpn(Config) when is_list(Config) -> - run_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). - -%-------------------------------------------------------------------------------- - -client_alpn_and_server_no_support(Config) when is_list(Config) -> - run_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], - [], - {error, protocol_not_negotiated}). - -%-------------------------------------------------------------------------------- - -client_no_support_and_server_alpn(Config) when is_list(Config) -> - run_handshake(Config, - [], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {error, protocol_not_negotiated}). - -%-------------------------------------------------------------------------------- - -client_alpn_npn_and_server_alpn(Config) when is_list(Config) -> - run_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}, - {client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"spdy/3">>}}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). - -%-------------------------------------------------------------------------------- - -client_alpn_npn_and_server_alpn_npn(Config) when is_list(Config) -> - run_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}, - {client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"spdy/3">>}}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, - {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). - -%-------------------------------------------------------------------------------- - -client_alpn_and_server_alpn_npn(Config) when is_list(Config) -> - run_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, - {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). - -%-------------------------------------------------------------------------------- - -client_renegotiate(Config) when is_list(Config) -> - Data = "hello world", - - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ClientOpts = [{alpn_advertised_protocols, [<<"http/1.0">>]}] ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, - ExpectedProtocol = {ok, <<"http/1.0">>}, - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, ssl_receive_and_assert_alpn, [ExpectedProtocol, Data]}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, assert_alpn_and_renegotiate_and_send_data, [ExpectedProtocol, Data]}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok). - -%-------------------------------------------------------------------------------- - -session_reused(Config) when is_list(Config)-> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ClientOpts = [{alpn_advertised_protocols, [<<"http/1.0">>]}] ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, - - ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). -%-------------------------------------------------------------------------------- - -alpn_not_supported_client(Config) when is_list(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - PrefProtocols = {client_preferred_next_protocols, - {client, [<<"http/1.0">>], <<"http/1.1">>}}, - ClientOpts = [PrefProtocols] ++ ClientOpts0, - {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, - {port, 8888}, {host, Hostname}, - {from, self()}, {options, ClientOpts}]), - - ssl_test_lib:check_result(Client, {error, - {options, - {not_supported_in_sslv3, PrefProtocols}}}). - -%-------------------------------------------------------------------------------- - -alpn_not_supported_server(Config) when is_list(Config)-> - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, - ServerOpts = [AdvProtocols] ++ ServerOpts0, - - {error, {options, {not_supported_in_sslv3, AdvProtocols}}} = ssl:listen(0, ServerOpts). - -%%-------------------------------------------------------------------- -%% Internal functions ------------------------------------------------ -%%-------------------------------------------------------------------- - -run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedAlert) -> - ClientOpts = ClientExtraOpts ++ ssl_test_lib:ssl_options(client_rsa_opts, Config), - 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_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, placeholder, []}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, placeholder, []}}, - {options, ClientOpts}]), - ssl_test_lib:check_client_alert(Server, Client, ExpectedAlert). - -run_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> - Data = "hello world", - - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ClientOpts = ClientExtraOpts ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts = ServerExtraOpts ++ ServerOpts0, - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, ssl_receive_and_assert_alpn, [ExpectedProtocol, Data]}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, ssl_send_and_assert_alpn, [ExpectedProtocol, Data]}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok). - -assert_alpn(Socket, Protocol) -> - ct:log("Negotiated Protocol ~p, Expecting: ~p ~n", - [ssl:negotiated_protocol(Socket), Protocol]), - Protocol = ssl:negotiated_protocol(Socket). - -assert_alpn_and_renegotiate_and_send_data(Socket, Protocol, Data) -> - assert_alpn(Socket, Protocol), - ct:log("Renegotiating ~n", []), - ok = ssl:renegotiate(Socket), - ssl:send(Socket, Data), - assert_alpn(Socket, Protocol), - ok. - -ssl_send_and_assert_alpn(Socket, Protocol, Data) -> - assert_alpn(Socket, Protocol), - ssl_send(Socket, Data). - -ssl_receive_and_assert_alpn(Socket, Protocol, Data) -> - assert_alpn(Socket, Protocol), - ssl_receive(Socket, Data). - -ssl_send(Socket, Data) -> - ct:log("Connection info: ~p~n", - [ssl:connection_information(Socket)]), - ssl:send(Socket, Data). - -ssl_receive(Socket, Data) -> - ssl_receive(Socket, Data, []). - -ssl_receive(Socket, Data, Buffer) -> - ct:log("Connection info: ~p~n", - [ssl:connection_information(Socket)]), - receive - {ssl, Socket, MoreData} -> - ct:log("Received ~p~n",[MoreData]), - NewBuffer = Buffer ++ MoreData, - case NewBuffer of - Data -> - ssl:send(Socket, "Got it"), - ok; - _ -> - ssl_receive(Socket, Data, NewBuffer) - end; - Other -> - ct:fail({unexpected_message, Other}) - after 4000 -> - ct:fail({did_not_get, Data}) - end. - -connection_info_result(Socket) -> - ssl:connection_information(Socket). diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 86a0aaf67b..dc86f01495 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -52,10 +52,9 @@ all() -> {group, basic_tls}, {group, options}, {group, options_tls}, - {group, session}, {group, 'dtlsv1.2'}, {group, 'dtlsv1'}, - {group, 'tlsv1.3'}, + %%{group, 'tlsv1.3'}, {group, 'tlsv1.2'}, {group, 'tlsv1.1'}, {group, 'tlsv1'}, @@ -69,15 +68,16 @@ groups() -> {options_tls, [], options_tests_tls()}, {'dtlsv1.2', [], all_versions_groups()}, {'dtlsv1', [], all_versions_groups()}, - {'tlsv1.3', [], tls13_test_group()}, {'tlsv1.2', [], all_versions_groups() ++ tls_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]}, {'tlsv1.1', [], all_versions_groups() ++ tls_versions_groups()}, {'tlsv1', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests()}, - {'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() ++ [tls_ciphersuite_vs_version]}, + {'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() -- [tls_ciphersuite_vs_version, + handshake_continue, + handshake_continue_timeout, + hello_client_cancel, + hello_server_cancel]}, {api,[], api_tests()}, {api_tls,[], api_tests_tls()}, - {session, [], session_tests()}, - {renegotiate, [], renegotiate_tests()}, {ciphers, [], cipher_tests()}, {error_handling_tests, [], error_handling_tests()}, {error_handling_tests_tls, [], error_handling_tests_tls()} @@ -90,7 +90,6 @@ tls_versions_groups ()-> all_versions_groups ()-> [{group, api}, - {group, renegotiate}, {group, ciphers}, {group, error_handling_tests}]. @@ -188,26 +187,6 @@ api_tests_tls() -> new_options_in_accept ]. -session_tests() -> - [reuse_session, - reuse_session_expired, - server_does_not_want_to_reuse_session, - no_reuses_session_server_restart_new_cert, - no_reuses_session_server_restart_new_cert_file]. - -renegotiate_tests() -> - [client_renegotiate, - server_renegotiate, - client_secure_renegotiate, - client_secure_renegotiate_fallback, - client_renegotiate_reused_session, - server_renegotiate_reused_session, - client_no_wrap_sequence_number, - server_no_wrap_sequence_number, - renegotiate_dos_mitigate_active, - renegotiate_dos_mitigate_passive, - renegotiate_dos_mitigate_absolute]. - cipher_tests() -> [old_cipher_suites, cipher_suites_mix, @@ -242,48 +221,6 @@ rizzo_tests() -> rizzo_zero_n, rizzo_disabled]. -%% For testing TLS 1.3 features and possible regressions -tls13_test_group() -> - [handshake_continue_tls13_client, - tls13_enable_client_side, - tls13_enable_server_side, - tls_record_1_3_encode_decode, - tls13_finished_verify_data, - tls13_1_RTT_handshake, - tls12_ssl_server_tls13_ssl_client, - tls13_basic_ssl_server_openssl_client, - tls13_basic_ssl_server_ssl_client, - tls13_basic_openssl_server_ssl_client, - tls13_custom_groups_ssl_server_openssl_client, - tls13_custom_groups_ssl_server_ssl_client, - tls13_hello_retry_request_ssl_server_openssl_client, - tls13_hello_retry_request_ssl_server_ssl_client, - tls13_client_auth_empty_cert_alert_ssl_server_openssl_client, - tls13_client_auth_empty_cert_alert_ssl_server_ssl_client, - tls13_client_auth_empty_cert_ssl_server_openssl_client, - tls13_client_auth_empty_cert_ssl_server_ssl_client, - tls13_client_auth_ssl_server_openssl_client, - tls13_client_auth_ssl_server_ssl_client, - tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client, - tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client, - tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client, - tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client, - tls13_hrr_client_auth_ssl_server_openssl_client, - tls13_hrr_client_auth_ssl_server_ssl_client, - tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client, - tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client, - tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client, - tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client, - tls13_connection_information, - tls13_ssl_server_with_alpn_ssl_client, - tls13_ssl_server_with_alpn_ssl_client_empty_alpn, - tls13_ssl_server_with_alpn_ssl_client_bad_alpn, - tls13_ssl_server_with_alpn_ssl_client_alpn, - tls13_ecdsa_ssl_server_openssl_client, - tls13_ecdsa_ssl_server_ssl_client, - tls13_ecdsa_openssl_server_ssl_client, - tls13_ecdsa_client_auth_ssl_server_ssl_client - ]. %%-------------------------------------------------------------------- init_per_suite(Config0) -> @@ -368,16 +305,6 @@ init_per_testcase(protocol_versions, Config) -> ct:timetrap({seconds, 5}), Config; -init_per_testcase(reuse_session_expired, Config) -> - ssl:stop(), - application:load(ssl), - ssl_test_lib:clean_env(), - application:set_env(ssl, session_lifetime, ?EXPIRE), - application:set_env(ssl, session_delay_cleanup_time, 500), - ssl:start(), - ct:timetrap({seconds, 30}), - Config; - init_per_testcase(empty_protocol_versions, Config) -> ssl:stop(), application:load(ssl), @@ -396,20 +323,6 @@ init_per_testcase(fallback, Config) -> {skip, "Not relevant if highest supported version is less than 3.2"} end; -init_per_testcase(TestCase, Config) when TestCase == client_renegotiate; - TestCase == server_renegotiate; - TestCase == client_secure_renegotiate; - TestCase == client_renegotiate_reused_session; - TestCase == server_renegotiate_reused_session; - TestCase == client_no_wrap_sequence_number; - TestCase == server_no_wrap_sequence_number; - TestCase == renegotiate_dos_mitigate_active; - TestCase == renegotiate_dos_mitigate_passive; - TestCase == renegotiate_dos_mitigate_absolute -> - ssl_test_lib:ct_log_supported_protocol_versions(Config), - ct:timetrap({seconds, ?SEC_RENEGOTIATION_TIMEOUT + 5}), - Config; - init_per_testcase(TestCase, Config) when TestCase == versions_option; TestCase == tls_tcp_connect_big -> ssl_test_lib:ct_log_supported_protocol_versions(Config), @@ -451,12 +364,6 @@ init_per_testcase(rizzo_disabled, Config) -> ct:timetrap({seconds, 60}), rizzo_add_mitigation_option(disabled, Config); -init_per_testcase(TestCase, Config) when TestCase == no_reuses_session_server_restart_new_cert_file; - TestCase == no_reuses_session_server_restart_new_cert -> - ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), - ct:timetrap({seconds, 15}), - Config; - init_per_testcase(prf, Config) -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:timetrap({seconds, 40}), @@ -702,42 +609,6 @@ handshake_continue(Config) when is_list(Config) -> ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -handshake_continue_tls13_client() -> - [{doc, "Test API function ssl:handshake_continue/3"}]. -handshake_continue_tls13_client(Config) when is_list(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], - - ClientOptsHello0 = ssl_test_lib:ssl_options([{handshake, hello}], Config), - ClientOptsHello = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOptsHello0], - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}], - Config)}, - {continue_options, proplists:delete(reuseaddr, ServerOpts)} - ]), - - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOptsHello}, - {continue_options, proplists:delete(reuseaddr, ClientOpts)}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - - %%------------------------------------------------------------------ handshake_continue_timeout() -> [{doc, "Test API function ssl:handshake_continue/3 with short timeout"}]. @@ -2794,3667 +2665,1103 @@ default_reject_anonymous(Config) when is_list(Config) -> ssl_test_lib:check_server_alert(Server, Client, insufficient_security). + %%-------------------------------------------------------------------- -reuse_session() -> - [{doc,"Test reuse of sessions (short handshake)"}]. -reuse_session(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - - ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). -%%-------------------------------------------------------------------- -reuse_session_expired() -> - [{doc,"Test sessions is not reused when it has expired"}]. -reuse_session_expired(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server0 = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {tcp_options, [{active, false}]}, - {options, ServerOpts}]), - Port0 = ssl_test_lib:inet_port(Server0), - - Client0 = ssl_test_lib:start_client([{node, ClientNode}, - {port, Port0}, {host, Hostname}, - {mfa, {ssl_test_lib, session_id, []}}, - {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]), - Server0 ! listen, - - Client1 = ssl_test_lib:start_client([{node, ClientNode}, - {port, Port0}, {host, Hostname}, - {mfa, {ssl_test_lib, session_id, []}}, - {from, self()}, {options, ClientOpts}]), - - SID = receive - {Client0, Id0} -> - Id0 - end, - - receive - {Client1, SID} -> - ok - after ?SLEEP -> - ct:fail(session_not_reused) - end, - - Server0 ! listen, - - %% Make sure session is unregistered due to expiration - ct:sleep((?EXPIRE*2)), +der_input() -> + [{doc,"Test to input certs and key as der"}]. - make_sure_expired(Hostname, Port0, SID), - - Client2 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port0}, {host, Hostname}, - {mfa, {ssl_test_lib, session_id, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client2, SID} -> - ct:fail(session_reused_when_session_expired); - {Client2, _} -> - ok - end, - process_flag(trap_exit, false), - ssl_test_lib:close(Server0), - ssl_test_lib:close(Client0), - ssl_test_lib:close(Client1), - ssl_test_lib:close(Client2). +der_input(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + DHParamFile = filename:join(DataDir, "dHParam.pem"), -make_sure_expired(Host, Port, Id) -> {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, State = ssl_test_lib:state(Prop), - ClientCache = element(2, State), + [CADb | _] = element(6, State), - case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of - undefined -> - ok; - #session{is_resumable = false} -> - ok; - _ -> - ct:sleep(?SLEEP), - make_sure_expired(Host, Port, Id) - end. + Size = ets:info(CADb, size), -%%-------------------------------------------------------------------- -server_does_not_want_to_reuse_session() -> - [{doc,"Test reuse of sessions (short handshake)"}]. -server_does_not_want_to_reuse_session(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | + SeverVerifyOpts]), + ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | + ClientVerifyOpts]), + ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, + {dh, DHParams}, + {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}], + ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, + {dh, DHParams}, + {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, [{reuse_session, fun(_,_,_,_) -> - false - end} | - ServerOpts]}]), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - - %% Make sure session is registered - ct:sleep(?SLEEP), - ssl_test_lib:close(Client0), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client1, SessionInfo} -> - ct:fail(session_reused_when_server_does_not_want_to); - {Client1, _Other} -> - ok - end, + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), - ssl_test_lib:close(Client1). + ssl_test_lib:close(Client), + Size = ets:info(CADb, size). %%-------------------------------------------------------------------- -client_renegotiate() -> - [{doc,"Test ssl:renegotiate/1 on client."}]. -client_renegotiate(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", +der_input_opts(Opts) -> + Certfile = proplists:get_value(certfile, Opts), + CaCertsfile = proplists:get_value(cacertfile, Opts), + Keyfile = proplists:get_value(keyfile, Opts), + Dhfile = proplists:get_value(dhfile, Opts), + [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile), + [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile), + [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile), + CaCerts = + lists:map(fun(Entry) -> + {_, CaCert, _} = Entry, + CaCert + end, ssl_test_lib:pem_to_der(CaCertsfile)), + {Cert, {Asn1Type, Key}, CaCerts, DHParams}. - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate, [Data]}}, - {options, [{reuse_sessions, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +defaults(Config) when is_list(Config)-> + Versions = ssl:versions(), + true = lists:member(sslv3, proplists:get_value(available, Versions)), + false = lists:member(sslv3, proplists:get_value(supported, Versions)), + true = lists:member('tlsv1', proplists:get_value(available, Versions)), + false = lists:member('tlsv1', proplists:get_value(supported, Versions)), + true = lists:member('tlsv1.1', proplists:get_value(available, Versions)), + false = lists:member('tlsv1.1', proplists:get_value(supported, Versions)), + true = lists:member('tlsv1.2', proplists:get_value(available, Versions)), + true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)), + false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()), + true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)), + false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()), + true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)), + false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()), + true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)), + true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)), + true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)), + true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)), + false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)). %%-------------------------------------------------------------------- -client_secure_renegotiate() -> - [{doc,"Test ssl:renegotiate/1 on client."}]. -client_secure_renegotiate(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), +reuseaddr() -> + [{doc,"Test reuseaddr option"}]. +reuseaddr(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{secure_renegotiate, true} | ServerOpts]}]), + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate, [Data]}}, - {options, [{reuse_sessions, false}, - {secure_renegotiate, true}| ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), + Client = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{active, false} | ClientOpts]}]), ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + ssl_test_lib:close(Client), + + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ClientOpts]}]), -%%-------------------------------------------------------------------- -client_secure_renegotiate_fallback() -> - [{doc,"Test that we can set secure_renegotiate to false that is " - "fallback option, we however do not have a insecure server to test against!"}]. -client_secure_renegotiate_fallback(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ssl_test_lib:check_result(Server1, ok, Client1, ok), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1). +%%-------------------------------------------------------------------- +tls_tcp_reuseaddr() -> + [{doc, "Reference test case."}]. +tls_tcp_reuseaddr(Config) when is_list(Config) -> {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{secure_renegotiate, false} | ServerOpts]}]), + {transport, gen_tcp}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{active, false}, {reuseaddr, true}]}]), Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate, [Data]}}, - {options, [{reuse_sessions, false}, - {secure_renegotiate, false}| ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), + Client = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {transport, gen_tcp}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{active, false}]}]), ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -server_renegotiate() -> - [{doc,"Test ssl:renegotiate/1 on server."}]. -server_renegotiate(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - renegotiate, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{reuse_sessions, false} | ClientOpts]}]), + ssl_test_lib:close(Client), - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, + {from, self()}, + {transport, gen_tcp}, + {mfa, {?MODULE, tcp_send_recv_result, []}}, + {options, [{active, false}, {reuseaddr, true}]}]), + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {transport, gen_tcp}, + {mfa, {?MODULE, tcp_send_recv_result, []}}, + {options, [{active, false}]}]), -%%-------------------------------------------------------------------- -client_renegotiate_reused_session() -> - [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}]. -client_renegotiate_reused_session(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ssl_test_lib:check_result(Server1, ok, Client1, ok), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1). - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +%%-------------------------------------------------------------------- - Data = "From erlang to erlang", +honor_server_cipher_order() -> + [{doc,"Test API honor server cipher order."}]. +honor_server_cipher_order(Config) when is_list(Config) -> + ClientCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac => sha, + prf => default_prf}], + ServerCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac =>sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}], + honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac => sha, + prf => default_prf}). - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), +honor_client_cipher_order() -> + [{doc,"Test API honor server cipher order."}]. +honor_client_cipher_order(Config) when is_list(Config) -> + ClientCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac => sha, + prf => default_prf}], + ServerCiphers = [#{key_exchange => dhe_rsa, + cipher => aes_256_cbc, + mac =>sha, + prf => default_prf}, + #{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}], +honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa, + cipher => aes_128_cbc, + mac => sha, + prf => default_prf}). - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate_reuse_session, [Data]}}, - {options, [{reuse_sessions, true} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -server_renegotiate_reused_session() -> - [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}]. -server_renegotiate_reused_session(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), +honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, - renegotiate_reuse_session, [Data]}}, - {options, ServerOpts}]), + {mfa, {?MODULE, connection_info_result, []}}, + {options, [{ciphers, ServerCiphers}, {honor_cipher_order, Honor} + | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{reuse_sessions, true} | ClientOpts]}]), + {mfa, {?MODULE, connection_info_result, []}}, + {options, [{ciphers, ClientCiphers}, {honor_cipher_order, Honor} + | ClientOpts]}]), + + Version = ssl_test_lib:protocol_version(Config), + + ServerMsg = ClientMsg = {ok, {Version, Expected}}, + + ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), - ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -client_no_wrap_sequence_number() -> - [{doc,"Test that erlang client will renegotiate session when", - "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."}]. -client_no_wrap_sequence_number(Config) when is_list(Config) -> +%%-------------------------------------------------------------------- +tls_ciphersuite_vs_version() -> + [{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), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]), + ok = gen_tcp:send(Socket, + <<22, 3,0, 49:16, % handshake, SSL 3.0, length + 1, 45:24, % client_hello, length + 3,0, % SSL 3.0 + 16#deadbeef:256, % 32 'random' bytes = 256 bits + 0, % no session ID + %% three cipher suites -- null, one with sha256 hash and one with sha hash + 6:16, 0,255, 0,61, 0,57, + 1, 0 % no compression + >>), + {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000), + {ok, <>} = gen_tcp:recv(Socket, HelloLen, 5000), + ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin), + case ServerHello of + #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} -> + ok; + _ -> + ct:fail({unexpected_server_hello, ServerHello}) + end. + +%%-------------------------------------------------------------------- +conf_signature_algs() -> + [{doc,"Test to set the signature_algs option on both client and server"}]. +conf_signature_algs(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - ErlData = "From erlang to erlang", - N = 12, - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ServerOpts}]), + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - - Version = ssl_test_lib:protocol_version(Config, tuple), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - trigger_renegotiate, [[ErlData, treashold(N, Version)]]}}, - {options, [{reuse_sessions, false}, - {renegotiate_at, N} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), + 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, [{sha, rsa}]} | ClientOpts]}]), + + ct:log("Testcase ~p, Client ~p Server ~p ~n", + [self(), Client, Server]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -server_no_wrap_sequence_number() -> - [{doc, "Test that erlang server will renegotiate session when", - "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."}]. -server_no_wrap_sequence_number(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), +%%-------------------------------------------------------------------- +no_common_signature_algs() -> + [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}]. +no_common_signature_algs(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Data = "From erlang to erlang", - N = 12, - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - trigger_renegotiate, [[Data, N+2]]}}, - {options, [{renegotiate_at, N} | ServerOpts]}]), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{signature_algs, [{sha256, rsa}]} + | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{reuse_sessions, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{signature_algs, [{sha384, rsa}]} + | ClientOpts]}]), + + ssl_test_lib:check_server_alert(Server, Client, insufficient_security). %%-------------------------------------------------------------------- -der_input() -> - [{doc,"Test to input certs and key as der"}]. -der_input(Config) when is_list(Config) -> - DataDir = proplists:get_value(data_dir, Config), - DHParamFile = filename:join(DataDir, "dHParam.pem"), +tls_dont_crash_on_handshake_garbage() -> + [{doc, "Ensure SSL server worker thows an alert on garbage during handshake " + "instead of crashing and exposing state to user code"}]. - {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), - [_, _,_, _, Prop] = StatusInfo, - State = ssl_test_lib:state(Prop), - [CADb | _] = element(6, State), +tls_dont_crash_on_handshake_garbage(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - Size = ets:info(CADb, size), + {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | - SeverVerifyOpts]), - ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | - ClientVerifyOpts]), - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, - {dh, DHParams}, - {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}], - ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, - {dh, DHParams}, - {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{active, false} | ServerOpts]}]), + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + unlink(Server), monitor(process, Server), Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{active, false} | ClientOpts]}]), - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - Size = ets:info(CADb, size). + {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]), + + % Send hello and garbage record + ok = gen_tcp:send(Socket, + [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello + 16#deadbeef:256, % 32 'random' bytes = 256 bits + 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values + + <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage + ]), + % Send unexpected change_cipher_spec + ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>), + + % Ensure we receive an alert, not sudden disconnect + {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000). + +drop_handshakes(Socket, Timeout) -> + {ok, <> = Header} = gen_tcp:recv(Socket, 5, Timeout), + {ok, <>} = gen_tcp:recv(Socket, RecLen, Timeout), + case RecType of + 22 -> drop_handshakes(Socket, Timeout); + _ -> {ok, <
>} + end. -%%-------------------------------------------------------------------- -der_input_opts(Opts) -> - Certfile = proplists:get_value(certfile, Opts), - CaCertsfile = proplists:get_value(cacertfile, Opts), - Keyfile = proplists:get_value(keyfile, Opts), - Dhfile = proplists:get_value(dhfile, Opts), - [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile), - [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile), - [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile), - CaCerts = - lists:map(fun(Entry) -> - {_, CaCert, _} = Entry, - CaCert - end, ssl_test_lib:pem_to_der(CaCertsfile)), - {Cert, {Asn1Type, Key}, CaCerts, DHParams}. %%-------------------------------------------------------------------- -no_reuses_session_server_restart_new_cert() -> - [{doc,"Check that a session is not reused if the server is restarted with a new cert."}]. -no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> +hibernate() -> + [{doc,"Check that an SSL connection that is started with option " + "{hibernate_after, 1000} indeed hibernates after 1000ms of " + "inactivity"}]. + +hibernate(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, ServerOpts}]), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, + {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, [{hibernate_after, 1000}|ClientOpts]}]), + {current_function, _} = + process_info(Pid, current_function), - %% Make sure session is registered - ct:sleep(?SLEEP), - Monitor = erlang:monitor(process, Server), + ssl_test_lib:check_result(Server, ok, Client, ok), + + ct:sleep(1500), + {current_function, {erlang, hibernate, 3}} = + process_info(Pid, current_function), + ssl_test_lib:close(Server), - ssl_test_lib:close(Client0), - receive - {'DOWN', Monitor, _, _, _} -> - ok - end, + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +hibernate_right_away() -> + [{doc,"Check that an SSL connection that is configured to hibernate " + "after 0 or 1 milliseconds hibernates as soon as possible and not " + "crashes"}]. + +hibernate_right_away(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + StartServerOpts = [{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}], + StartClientOpts = [return_socket, + {node, ClientNode}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}], + + Server1 = ssl_test_lib:start_server(StartServerOpts), + Port1 = ssl_test_lib:inet_port(Server1), + {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++ + [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]), + + ssl_test_lib:check_result(Server1, ok, Client1, ok), - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{reuseaddr, true} | DsaServerOpts]}]), + ct:sleep(1000), %% Schedule out + + {current_function, {erlang, hibernate, 3}} = + process_info(Pid1, current_function), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1), + + Server2 = ssl_test_lib:start_server(StartServerOpts), + Port2 = ssl_test_lib:inet_port(Server2), + {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++ + [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]), + + ssl_test_lib:check_result(Server2, ok, Client2, ok), + + ct:sleep(1000), %% Schedule out + + {current_function, {erlang, hibernate, 3}} = + process_info(Pid2, current_function), + + ssl_test_lib:close(Server2), + ssl_test_lib:close(Client2). + +%%-------------------------------------------------------------------- +listen_socket() -> + [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}]. + +listen_socket(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + {ok, ListenSocket} = ssl:listen(0, ServerOpts), + + %% This can be a valid thing to do as + %% options are inherited by the accept socket + ok = ssl:controlling_process(ListenSocket, self()), + + {ok, _} = ssl:sockname(ListenSocket), + + {error, enotconn} = ssl:send(ListenSocket, <<"data">>), + {error, enotconn} = ssl:recv(ListenSocket, 0), + {error, enotconn} = ssl:connection_information(ListenSocket), + {error, enotconn} = ssl:peername(ListenSocket), + {error, enotconn} = ssl:peercert(ListenSocket), + {error, enotconn} = ssl:renegotiate(ListenSocket), + {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, [client_random], 256), + {error, enotconn} = ssl:shutdown(ListenSocket, read_write), + + ok = ssl:close(ListenSocket). +%%-------------------------------------------------------------------- +tls_ssl_accept_timeout() -> + [{doc,"Test ssl:ssl_accept timeout"}]. + +tls_ssl_accept_timeout(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {timeout, 5000}, + {mfa, {ssl_test_lib, + no_result_msg, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]), - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), receive - {Client1, SessionInfo} -> - ct:fail(session_reused_when_server_has_new_cert); - {Client1, _Other} -> - ok - end, - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client1). + {tcp_closed, CSocket} -> + ssl_test_lib:check_result(Server, {error, timeout}), + receive + {'EXIT', Server, _} -> + %% Make sure supervisor had time to react on process exit + %% Could we come up with a better solution to this? + ct:sleep(500), + [] = supervisor:which_children(tls_connection_sup) + end + end. %%-------------------------------------------------------------------- -no_reuses_session_server_restart_new_cert_file() -> - [{doc,"Check that a session is not reused if a server is restarted with a new " - "cert contained in a file with the same name as the old cert."}]. +ssl_recv_timeout() -> + [{doc,"Test ssl:ssl_accept timeout"}]. -no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> +ssl_recv_timeout(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config), - DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config), - PrivDir = proplists:get_value(priv_dir, Config), - NewServerOpts0 = new_config(PrivDir, ServerOpts), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, NewServerOpts0}]), + {mfa, {?MODULE, send_recv_result_timeout_server, []}}, + {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - %% Make sure session is registered and we get - %% new file time stamp when calling new_config! - ct:sleep(?SLEEP* 2), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client0), - - ssl:clear_pem_cache(), - NewServerOpts1 = new_config(PrivDir, DsaServerOpts), - - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{reuseaddr, true} | NewServerOpts1]}]), - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client1, SessionInfo} -> - ct:fail(session_reused_when_server_has_new_cert); - {Client1, _Other} -> - ok - end, - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client1). + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_timeout_client, []}}, + {options, [{active, false} | ClientOpts]}]), -%%-------------------------------------------------------------------- -defaults(Config) when is_list(Config)-> - Versions = ssl:versions(), - true = lists:member(sslv3, proplists:get_value(available, Versions)), - false = lists:member(sslv3, proplists:get_value(supported, Versions)), - true = lists:member('tlsv1', proplists:get_value(available, Versions)), - false = lists:member('tlsv1', proplists:get_value(supported, Versions)), - true = lists:member('tlsv1.1', proplists:get_value(available, Versions)), - false = lists:member('tlsv1.1', proplists:get_value(supported, Versions)), - true = lists:member('tlsv1.2', proplists:get_value(available, Versions)), - true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)), - false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()), - true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)), - false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()), - true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)), - false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()), - true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)), - true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)), - true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)), - true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)), - false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)). + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -reuseaddr() -> - [{doc,"Test reuseaddr option"}]. - -reuseaddr(Config) when is_list(Config) -> +connect_twice() -> + [{doc,""}]. +connect_twice(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{active, false} | ServerOpts]}]), + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{keepalive, true},{active, false} + | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{active, false} | ClientOpts]}]), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{active, false} | ServerOpts]}]), - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {options, [{keepalive, true},{active, false} + | ClientOpts]}]), + Server ! listen, + + {Client1, #sslsocket{}} = + ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{active, false} | ClientOpts]}]), + {options, [{keepalive, true},{active, false} + | ClientOpts]}]), - ssl_test_lib:check_result(Server1, ok, Client1, ok), - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client1). + ct:log("Testcase ~p, Client ~p Server ~p ~n", + [self(), Client, Server]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:check_result(Server, ok, Client1, ok), -%%-------------------------------------------------------------------- -tls_tcp_reuseaddr() -> - [{doc, "Reference test case."}]. -tls_tcp_reuseaddr(Config) when is_list(Config) -> - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {transport, gen_tcp}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{active, false}, {reuseaddr, true}]}]), - Port = ssl_test_lib:inet_port(Server), - Client = - ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {transport, gen_tcp}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{active, false}]}]), ssl_test_lib:close(Server), ssl_test_lib:close(Client), - - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, - {from, self()}, - {transport, gen_tcp}, - {mfa, {?MODULE, tcp_send_recv_result, []}}, - {options, [{active, false}, {reuseaddr, true}]}]), - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {transport, gen_tcp}, - {mfa, {?MODULE, tcp_send_recv_result, []}}, - {options, [{active, false}]}]), - - ssl_test_lib:check_result(Server1, ok, Client1, ok), - ssl_test_lib:close(Server1), ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- - -honor_server_cipher_order() -> - [{doc,"Test API honor server cipher order."}]. -honor_server_cipher_order(Config) when is_list(Config) -> - ClientCiphers = [#{key_exchange => dhe_rsa, - cipher => aes_128_cbc, - mac => sha, - prf => default_prf}, - #{key_exchange => dhe_rsa, - cipher => aes_256_cbc, - mac => sha, - prf => default_prf}], - ServerCiphers = [#{key_exchange => dhe_rsa, - cipher => aes_256_cbc, - mac =>sha, - prf => default_prf}, - #{key_exchange => dhe_rsa, - cipher => aes_128_cbc, - mac => sha, - prf => default_prf}], - honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa, - cipher => aes_256_cbc, - mac => sha, - prf => default_prf}). - -honor_client_cipher_order() -> - [{doc,"Test API honor server cipher order."}]. -honor_client_cipher_order(Config) when is_list(Config) -> - ClientCiphers = [#{key_exchange => dhe_rsa, - cipher => aes_128_cbc, - mac => sha, - prf => default_prf}, - #{key_exchange => dhe_rsa, - cipher => aes_256_cbc, - mac => sha, - prf => default_prf}], - ServerCiphers = [#{key_exchange => dhe_rsa, - cipher => aes_256_cbc, - mac =>sha, - prf => default_prf}, - #{key_exchange => dhe_rsa, - cipher => aes_128_cbc, - mac => sha, - prf => default_prf}], -honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa, - cipher => aes_128_cbc, - mac => sha, - prf => default_prf}). - -honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) -> +tls_tcp_error_propagation_in_active_mode() -> + [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}]. +tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, connection_info_result, []}}, - {options, [{ciphers, ServerCiphers}, {honor_cipher_order, Honor} - | ServerOpts]}]), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, connection_info_result, []}}, - {options, [{ciphers, ClientCiphers}, {honor_cipher_order, Honor} - | ClientOpts]}]), - - Version = ssl_test_lib:protocol_version(Config), - - ServerMsg = ClientMsg = {ok, {Version, Expected}}, - - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), + {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, receive_msg, []}}, + {options, ClientOpts}]), + + {status, _, _, StatusInfo} = sys:get_status(Pid), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + StaticEnv = element(2, State), + Socket = element(11, StaticEnv), + %% Fake tcp error + Pid ! {tcp_error, Socket, etimedout}, - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}). %%-------------------------------------------------------------------- -tls_ciphersuite_vs_version() -> - [{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), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]), - ok = gen_tcp:send(Socket, - <<22, 3,0, 49:16, % handshake, SSL 3.0, length - 1, 45:24, % client_hello, length - 3,0, % SSL 3.0 - 16#deadbeef:256, % 32 'random' bytes = 256 bits - 0, % no session ID - %% three cipher suites -- null, one with sha256 hash and one with sha hash - 6:16, 0,255, 0,61, 0,57, - 1, 0 % no compression - >>), - {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000), - {ok, <>} = gen_tcp:recv(Socket, HelloLen, 5000), - ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin), - case ServerHello of - #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} -> - ok; - _ -> - ct:fail({unexpected_server_hello, ServerHello}) - end. - -%%-------------------------------------------------------------------- -conf_signature_algs() -> - [{doc,"Test to set the signature_algs option on both client and server"}]. -conf_signature_algs(Config) when is_list(Config) -> +recv_error_handling() -> + [{doc,"Special case of call error handling"}]. +recv_error_handling(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ServerOpts]}]), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, recv_close, []}}, + {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - Client = - 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, [{sha, rsa}]} | ClientOpts]}]), - - ct:log("Testcase ~p, Client ~p Server ~p ~n", - [self(), Client, Server]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + {_Client, #sslsocket{} = SslSocket} = ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ClientOpts}]), + ssl:close(SslSocket), + ssl_test_lib:check_result(Server, ok). + %%-------------------------------------------------------------------- -no_common_signature_algs() -> - [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}]. -no_common_signature_algs(Config) when is_list(Config) -> - +call_in_error_state() -> + [{doc,"Special case of call error handling"}]. +call_in_error_state(Config) when is_list(Config) -> + ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)], + Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]), + receive + {Pid, Port} -> + spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]]) + end, + receive + {error, closed} -> + ok; + Other -> + ct:fail(Other) + end. - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +run_client_error([Port, Opts]) -> + ssl:connect("localhost", Port, Opts). + +run_error_server([ Pid | Opts]) -> + {ok, Listen} = ssl:listen(0, Opts), + {ok,{_, Port}} = ssl:sockname(Listen), + Pid ! {self(), Port}, + {ok, Socket} = ssl:transport_accept(Listen), + Pid ! ssl:controlling_process(Socket, self()). +%%-------------------------------------------------------------------- - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, [{signature_algs, [{sha256, rsa}]} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, [{signature_algs, [{sha384, rsa}]} - | ClientOpts]}]), - - ssl_test_lib:check_server_alert(Server, Client, insufficient_security). - -%%-------------------------------------------------------------------- - -tls_dont_crash_on_handshake_garbage() -> - [{doc, "Ensure SSL server worker thows an alert on garbage during handshake " - "instead of crashing and exposing state to user code"}]. - -tls_dont_crash_on_handshake_garbage(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - unlink(Server), monitor(process, Server), - Port = ssl_test_lib:inet_port(Server), - - {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]), - - % Send hello and garbage record - ok = gen_tcp:send(Socket, - [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello - 16#deadbeef:256, % 32 'random' bytes = 256 bits - 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values - - <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage - ]), - % Send unexpected change_cipher_spec - ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>), - - % Ensure we receive an alert, not sudden disconnect - {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000). - -drop_handshakes(Socket, Timeout) -> - {ok, <> = Header} = gen_tcp:recv(Socket, 5, Timeout), - {ok, <>} = gen_tcp:recv(Socket, RecLen, Timeout), - case RecType of - 22 -> drop_handshakes(Socket, Timeout); - _ -> {ok, <
>} - end. - - -%%-------------------------------------------------------------------- - -hibernate() -> - [{doc,"Check that an SSL connection that is started with option " - "{hibernate_after, 1000} indeed hibernates after 1000ms of " - "inactivity"}]. - -hibernate(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket, - {node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, [{hibernate_after, 1000}|ClientOpts]}]), - {current_function, _} = - process_info(Pid, current_function), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ct:sleep(1500), - {current_function, {erlang, hibernate, 3}} = - process_info(Pid, current_function), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -hibernate_right_away() -> - [{doc,"Check that an SSL connection that is configured to hibernate " - "after 0 or 1 milliseconds hibernates as soon as possible and not " - "crashes"}]. - -hibernate_right_away(Config) -> +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), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - StartServerOpts = [{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}], - StartClientOpts = [return_socket, - {node, ClientNode}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}], - - Server1 = ssl_test_lib:start_server(StartServerOpts), - Port1 = ssl_test_lib:inet_port(Server1), - {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++ - [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]), - - ssl_test_lib:check_result(Server1, ok, Client1, ok), - - ct:sleep(1000), %% Schedule out - - {current_function, {erlang, hibernate, 3}} = - process_info(Pid1, current_function), - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client1), - - Server2 = ssl_test_lib:start_server(StartServerOpts), - Port2 = ssl_test_lib:inet_port(Server2), - {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++ - [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]), - - ssl_test_lib:check_result(Server2, ok, Client2, ok), - - ct:sleep(1000), %% Schedule out - - {current_function, {erlang, hibernate, 3}} = - process_info(Pid2, current_function), - - ssl_test_lib:close(Server2), - ssl_test_lib:close(Client2). - -%%-------------------------------------------------------------------- -listen_socket() -> - [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}]. - -listen_socket(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - {ok, ListenSocket} = ssl:listen(0, ServerOpts), - - %% This can be a valid thing to do as - %% options are inherited by the accept socket - ok = ssl:controlling_process(ListenSocket, self()), - - {ok, _} = ssl:sockname(ListenSocket), - - {error, enotconn} = ssl:send(ListenSocket, <<"data">>), - {error, enotconn} = ssl:recv(ListenSocket, 0), - {error, enotconn} = ssl:connection_information(ListenSocket), - {error, enotconn} = ssl:peername(ListenSocket), - {error, enotconn} = ssl:peercert(ListenSocket), - {error, enotconn} = ssl:renegotiate(ListenSocket), - {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, [client_random], 256), - {error, enotconn} = ssl:shutdown(ListenSocket, read_write), - - ok = ssl:close(ListenSocket). -%%-------------------------------------------------------------------- -tls_ssl_accept_timeout() -> - [{doc,"Test ssl:ssl_accept timeout"}]. - -tls_ssl_accept_timeout(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {timeout, 5000}, - {mfa, {ssl_test_lib, - no_result_msg, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]), - + _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]), receive - {tcp_closed, CSocket} -> - ssl_test_lib:check_result(Server, {error, timeout}), - receive - {'EXIT', Server, _} -> - %% Make sure supervisor had time to react on process exit - %% Could we come up with a better solution to this? - ct:sleep(500), - [] = supervisor:which_children(tls_connection_sup) - end + {_Pid, Port} -> + spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]]) + end, + receive + ok -> + ok; + Other -> + ct:fail(Other) end. - %%-------------------------------------------------------------------- -ssl_recv_timeout() -> - [{doc,"Test ssl:ssl_accept timeout"}]. - -ssl_recv_timeout(Config) -> +abuse_transport_accept_socket() -> + [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}]. +abuse_transport_accept_socket(Config) when is_list(Config) -> ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_timeout_server, []}}, - {options, [{active, false} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - send_recv_result_timeout_client, []}}, - {options, [{active, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -connect_twice() -> - [{doc,""}]. -connect_twice(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{keepalive, true},{active, false} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = - ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{keepalive, true},{active, false} - | ClientOpts]}]), - Server ! listen, - - {Client1, #sslsocket{}} = - ssl_test_lib:start_client([return_socket, - {node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{keepalive, true},{active, false} - | ClientOpts]}]), - - ct:log("Testcase ~p, Client ~p Server ~p ~n", - [self(), Client, Server]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:check_result(Server, ok, Client1, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - ssl_test_lib:close(Client1). - -%%-------------------------------------------------------------------- -renegotiate_dos_mitigate_active() -> - [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", - "immediately after each other"}]. -renegotiate_dos_mitigate_active(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate_immediately, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -renegotiate_dos_mitigate_passive() -> - [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", - "immediately after each other"}]. -renegotiate_dos_mitigate_passive(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result, []}}, - {options, [{active, false} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate_immediately, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -renegotiate_dos_mitigate_absolute() -> - [{doc, "Mitigate DOS computational attack by not allowing client to initiate renegotiation"}]. -renegotiate_dos_mitigate_absolute(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, [{client_renegotiation, false} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate_rejected, - []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -tls_tcp_error_propagation_in_active_mode() -> - [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}]. -tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket, - {node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, receive_msg, []}}, - {options, ClientOpts}]), - - {status, _, _, StatusInfo} = sys:get_status(Pid), - [_, _,_, _, Prop] = StatusInfo, - State = ssl_test_lib:state(Prop), - StaticEnv = element(2, State), - Socket = element(11, StaticEnv), - %% Fake tcp error - Pid ! {tcp_error, Socket, etimedout}, - - ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}). - -%%-------------------------------------------------------------------- -recv_error_handling() -> - [{doc,"Special case of call error handling"}]. -recv_error_handling(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, recv_close, []}}, - {options, [{active, false} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - {_Client, #sslsocket{} = SslSocket} = ssl_test_lib:start_client([return_socket, - {node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ClientOpts}]), - ssl:close(SslSocket), - ssl_test_lib:check_result(Server, ok). - - - -%%-------------------------------------------------------------------- -call_in_error_state() -> - [{doc,"Special case of call error handling"}]. -call_in_error_state(Config) when is_list(Config) -> - ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)], - Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]), - receive - {Pid, Port} -> - spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]]) - end, - receive - {error, closed} -> - ok; - Other -> - ct:fail(Other) - end. - -run_client_error([Port, Opts]) -> - ssl:connect("localhost", Port, Opts). - -run_error_server([ Pid | Opts]) -> - {ok, Listen} = ssl:listen(0, Opts), - {ok,{_, Port}} = ssl:sockname(Listen), - Pid ! {self(), Port}, - {ok, Socket} = ssl:transport_accept(Listen), - Pid ! ssl:controlling_process(Socket, self()). - -%%-------------------------------------------------------------------- - -close_in_error_state() -> - [{doc,"Special case of closing socket in error state"}]. -close_in_error_state(Config) when is_list(Config) -> - ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), - ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)], - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]), - receive - {_Pid, Port} -> - spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]]) - end, - receive - ok -> - ok; - Other -> - ct:fail(Other) - end. -%%-------------------------------------------------------------------- -abuse_transport_accept_socket() -> - [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}]. -abuse_transport_accept_socket(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_transport_abuse_socket([{node, ServerNode}, - {port, 0}, - {from, self()}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ClientOpts}]), - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - - -%%-------------------------------------------------------------------- -controlling_process_transport_accept_socket() -> - [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}]. -controlling_process_transport_accept_socket(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_transport_control([{node, ServerNode}, - {port, 0}, - {from, self()}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - _Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, ClientOpts}]), - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server). - -%%-------------------------------------------------------------------- -run_error_server_close([Pid | Opts]) -> - {ok, Listen} = ssl:listen(0, Opts), - {ok,{_, Port}} = ssl:sockname(Listen), - Pid ! {self(), Port}, - {ok, Socket} = ssl:transport_accept(Listen), - Pid ! ssl:close(Socket). - -%%-------------------------------------------------------------------- - -rizzo() -> - [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is - vunrable to Rizzo/Dungon attack"}]. - -rizzo(Config) when is_list(Config) -> - Prop = proplists:get_value(tc_group_properties, Config), - Version = proplists:get_value(name, Prop), - NVersion = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion), - [{key_exchange, - fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> - true; - (_) -> - false - end}, - {cipher, - fun(rc4_128) -> - false; - (chacha20_poly1305) -> - false; - (_) -> - true - end}]), - - run_send_recv_rizzo(Ciphers, Config, Version, - {?MODULE, send_recv_result_active_rizzo, []}). -%%-------------------------------------------------------------------- -no_rizzo_rc4() -> - [{doc,"Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"}]. - -no_rizzo_rc4(Config) when is_list(Config) -> - Prop = proplists:get_value(tc_group_properties, Config), - Version = proplists:get_value(name, Prop), - NVersion = ssl_test_lib:protocol_version(Config, tuple), - %% Test uses RSA certs - Ciphers = ssl:filter_cipher_suites(ssl_test_lib:rc4_suites(NVersion), - [{key_exchange, - fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> - true; - (_) -> - false - end}]), - run_send_recv_rizzo(Ciphers, Config, Version, - {?MODULE, send_recv_result_active_no_rizzo, []}). - -rizzo_one_n_minus_one() -> - [{doc,"Test that the 1/n-1-split mitigation of Rizzo/Dungon attack can be explicitly selected"}]. - -rizzo_one_n_minus_one(Config) when is_list(Config) -> - Prop = proplists:get_value(tc_group_properties, Config), - Version = proplists:get_value(name, Prop), - NVersion = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion), - [{key_exchange, - fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> - true; - (_) -> - false - end}, - {cipher, - fun(rc4_128) -> - false; - %% TODO: remove this clause when chacha is fixed! - (chacha20_poly1305) -> - false; - (_) -> - true - end}]), - run_send_recv_rizzo(Ciphers, Config, Version, - {?MODULE, send_recv_result_active_rizzo, []}). - -rizzo_zero_n() -> - [{doc,"Test that the 0/n-split mitigation of Rizzo/Dungon attack can be explicitly selected"}]. - -rizzo_zero_n(Config) when is_list(Config) -> - Prop = proplists:get_value(tc_group_properties, Config), - Version = proplists:get_value(name, Prop), - NVersion = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion), - [{cipher, - fun(rc4_128) -> - false; - (_) -> - true - end}]), - run_send_recv_rizzo(Ciphers, Config, Version, - {?MODULE, send_recv_result_active_no_rizzo, []}). - -rizzo_disabled() -> - [{doc,"Test that the mitigation of Rizzo/Dungon attack can be explicitly disabled"}]. - -rizzo_disabled(Config) when is_list(Config) -> - Prop = proplists:get_value(tc_group_properties, Config), - Version = proplists:get_value(name, Prop), - NVersion = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion), - [{cipher, - fun(rc4_128) -> - false; - (_) -> - true - end}]), - run_send_recv_rizzo(Ciphers, Config, Version, - {?MODULE, send_recv_result_active_no_rizzo, []}). - -%%-------------------------------------------------------------------- -new_server_wants_peer_cert() -> - [{doc, "Test that server configured to do client certification does" - " not reuse session without a client certificate."}]. -new_server_wants_peer_cert(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - VServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ssl_test_lib:ssl_options(server_verification_opts, Config)], - ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, peercert_result, []}}, - {options, [ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = - ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ClientOpts}]), - - Monitor = erlang:monitor(process, Server), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - receive - {'DOWN', Monitor, _, _, _} -> - ok - end, - - Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, - {from, self()}, - {mfa, {?MODULE, peercert_result, []}}, - {options, VServerOpts}]), - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [ClientOpts]}]), - - CertFile = proplists:get_value(certfile, ClientOpts), - [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile), - - ServerMsg = {error, no_peercert}, - Sever1Msg = {ok, BinCert}, - - ssl_test_lib:check_result(Server, ServerMsg, Server1, Sever1Msg), - - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client), - ssl_test_lib:close(Client1). - -%%-------------------------------------------------------------------- -session_cache_process_list() -> - [{doc,"Test reuse of sessions (short handshake)"}]. -session_cache_process_list(Config) when is_list(Config) -> - session_cache_process(list,Config). -%%-------------------------------------------------------------------- -session_cache_process_mnesia() -> - [{doc,"Test reuse of sessions (short handshake)"}]. -session_cache_process_mnesia(Config) when is_list(Config) -> - session_cache_process(mnesia,Config). - -%%-------------------------------------------------------------------- - -tls_versions_option() -> - [{doc,"Test API versions option to connect/listen."}]. -tls_versions_option(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - Supported = proplists:get_value(supported, ssl:versions()), - Available = proplists:get_value(available, ssl:versions()), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, [{versions, Supported} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - Server ! listen, - - ErrClient = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, [{versions , Available -- Supported} | ClientOpts]}]), - receive - {Server, _} -> - ok - end, - ssl_test_lib:check_client_alert(ErrClient, protocol_version). - - -%%-------------------------------------------------------------------- -unordered_protocol_versions_server() -> - [{doc,"Test that the highest protocol is selected even" - " when it is not first in the versions list."}]. - -unordered_protocol_versions_server(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, ClientOpts}]), - - ServerMsg = ClientMsg = {ok,'tlsv1.2'}, - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). - -%%-------------------------------------------------------------------- -unordered_protocol_versions_client() -> - [{doc,"Test that the highest protocol is selected even" - " when it is not first in the versions list."}]. - -unordered_protocol_versions_client(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, ServerOpts }]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]), - - ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). - -%%-------------------------------------------------------------------- -max_handshake_size() -> - [{doc,"Test that we can set max_handshake_size to max value."}]. - -max_handshake_size(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, [{max_handshake_size, 8388607} |ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, [{max_handshake_size, 8388607} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok). - -%%-------------------------------------------------------------------- - -server_name_indication_option() -> - [{doc,"Test API server_name_indication option to connect."}]. -server_name_indication_option(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, - [{server_name_indication, disable} | - ClientOpts]} - ]), - - ssl_test_lib:check_result(Server, ok, Client0, ok), - Server ! listen, - - Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, - [{server_name_indication, Hostname} | ClientOpts] - }]), - ssl_test_lib:check_result(Server, ok, Client1, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client0), - ssl_test_lib:close(Client1). -%%-------------------------------------------------------------------- - -accept_pool() -> - [{doc,"Test having an accept pool."}]. -accept_pool(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {accepters, 3}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server0), - [Server1, Server2] = ssl_test_lib:accepters(2), - - Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts} - ]), - - Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts} - ]), - - Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts} - ]), - - ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]), - - ssl_test_lib:close(Server0), - ssl_test_lib:close(Server1), - ssl_test_lib:close(Server2), - ssl_test_lib:close(Client0), - ssl_test_lib:close(Client1), - ssl_test_lib:close(Client2). - -%%-------------------------------------------------------------------- -%% TLS 1.3 -%%-------------------------------------------------------------------- - -tls13_enable_client_side() -> - [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}]. - -tls13_enable_client_side(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.1', 'tlsv1.2']} | ServerOpts] }]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.2', 'tlsv1.3']} | ClientOpts]}]), - - ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). - -tls13_enable_server_side() -> - [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}]. - -tls13_enable_server_side(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.2', 'tlsv1.3']} | ServerOpts] }]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.2', 'tlsv1.1']} | ClientOpts]}]), - - ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). - -tls_record_1_3_encode_decode() -> - [{doc,"Test TLS 1.3 record encode/decode functions"}]. - -tls_record_1_3_encode_decode(_Config) -> - ConnectionStates = - #{current_read => - #{beast_mitigation => one_n_minus_one, - cipher_state => - {cipher_state, - <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14, - 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, - <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, - 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, - undefined,undefined,undefined,16}, - client_verify_data => undefined,compression_state => undefined, - mac_secret => undefined,secure_renegotiation => undefined, - security_parameters => - {security_parameters, - <<19,2>>, - 0,8,2,undefined,undefined,undefined,undefined,undefined, - sha384,undefined,undefined, - {handshake_secret, - <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121, - 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218, - 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56, - 157>>}, - undefined, - <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207, - 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>, - undefined}, - sequence_number => 0,server_verify_data => undefined}, - current_write => - #{beast_mitigation => one_n_minus_one, - cipher_state => - {cipher_state, - <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14, - 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, - <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, - 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, - undefined,undefined,undefined,16}, - client_verify_data => undefined,compression_state => undefined, - mac_secret => undefined,secure_renegotiation => undefined, - security_parameters => - {security_parameters, - <<19,2>>, - 0,8,2,undefined,undefined,undefined,undefined,undefined, - sha384,undefined,undefined, - {handshake_secret, - <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121, - 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218, - 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56, - 157>>}, - undefined, - <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207, - 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>, - undefined}, - sequence_number => 0,server_verify_data => undefined}}, - - PlainText = [11, - <<0,2,175>>, - <<0,0,2,171,0,2,166,48,130,2,162,48,130,1,138,2,9,0,186,57,220,137,88,255, - 191,235,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,18,49,16,48,14,6,3,85, - 4,3,12,7,84,101,115,116,32,67,65,48,30,23,13,49,56,48,53,48,52,49,52,49,50, - 51,56,90,23,13,50,56,48,50,48,52,49,52,49,50,51,56,90,48,20,49,18,48,16,6, - 3,85,4,3,12,9,108,111,99,97,108,104,111,115,116,48,130,1,34,48,13,6,9,42, - 134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,169,40, - 144,176,121,63,134,97,144,126,243,183,225,157,37,131,183,225,87,243,23,88, - 230,70,9,134,32,147,7,27,167,98,51,81,224,75,199,12,229,251,195,207,75,179, - 181,78,128,3,255,44,58,39,43,172,142,45,186,58,51,65,187,199,154,153,245, - 70,133,137,1,27,87,42,116,65,251,129,109,145,233,97,171,71,54,213,185,74, - 209,166,11,218,189,119,206,86,170,60,212,213,85,189,30,50,215,23,185,53, - 132,238,132,176,198,250,139,251,198,221,225,128,109,113,23,220,39,143,71, - 30,59,189,51,244,61,158,214,146,180,196,103,169,189,221,136,78,129,216,148, - 2,9,8,65,37,224,215,233,13,209,21,235,20,143,33,74,59,53,208,90,152,94,251, - 54,114,171,39,88,230,227,158,211,135,37,182,67,205,161,59,20,138,58,253,15, - 53,48,8,157,9,95,197,9,177,116,21,54,9,125,78,109,182,83,20,16,234,223,116, - 41,155,123,87,77,17,120,153,246,239,124,130,105,219,166,146,242,151,66,198, - 75,72,63,28,246,86,16,244,223,22,36,50,15,247,222,98,6,152,136,154,72,150, - 73,127,2,3,1,0,1,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,76, - 33,54,160,229,219,219,193,150,116,245,252,18,39,235,145,86,12,167,171,52, - 117,166,30,83,5,216,245,177,217,247,95,1,136,94,246,212,108,248,230,111, - 225,202,189,6,129,8,70,128,245,18,204,215,87,82,129,253,227,122,66,182,184, - 189,30,193,169,144,218,216,109,105,110,215,144,60,104,162,178,101,164,218, - 122,60,37,41,143,57,150,52,59,51,112,238,113,239,168,114,69,183,143,154,73, - 61,58,80,247,172,95,251,55,28,186,28,200,206,230,118,243,92,202,189,49,76, - 124,252,76,0,247,112,85,194,69,59,222,163,228,103,49,110,104,109,251,155, - 138,9,37,167,49,189,48,134,52,158,185,129,24,96,153,196,251,90,206,76,239, - 175,119,174,165,133,108,222,125,237,125,187,149,152,83,190,16,202,94,202, - 201,40,218,22,254,63,189,41,174,97,140,203,70,18,196,118,237,175,134,79,78, - 246,2,61,54,77,186,112,32,17,193,192,188,217,252,215,200,7,245,180,179,132, - 183,212,229,155,15,152,206,135,56,81,88,3,123,244,149,110,182,72,109,70,62, - 146,152,146,151,107,126,216,210,9,93,0,0>>], - - {[_Header|Encoded], _} = tls_record_1_3:encode_plain_text(22, PlainText, ConnectionStates), - CipherText = #ssl_tls{type = 23, version = {3,3}, fragment = Encoded}, - - {#ssl_tls{type = 22, version = {3,4}, fragment = DecodedText}, _} = - tls_record_1_3:decode_cipher_text(CipherText, ConnectionStates), - - DecodedText = iolist_to_binary(PlainText), - ct:log("Decoded: ~p ~n", [DecodedText]), - ok. - -tls13_1_RTT_handshake() -> - [{doc,"Test TLS 1.3 1-RTT Handshake"}]. - -tls13_1_RTT_handshake(_Config) -> - %% ConnectionStates with NULL cipher - ConnStatesNull = - #{current_write => - #{security_parameters => - #security_parameters{cipher_suite = ?TLS_NULL_WITH_NULL_NULL}, - sequence_number => 0 - } - }, - - %% {client} construct a ClientHello handshake message: - %% - %% ClientHello (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 - %% ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 - %% 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b - %% 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 - %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 - %% 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 - %% 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a - %% af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 - %% 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 - %% 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 - %% - %% {client} send handshake record: - %% - %% payload (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 ba - %% 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 02 - %% 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b 00 - %% 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12 - %% 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00 - %% 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d - %% 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af - %% 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02 - %% 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02 - %% 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 - %% - %% complete record (201 octets): 16 03 01 00 c4 01 00 00 c0 03 03 cb - %% 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 - %% ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 - %% 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 - %% 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 - %% 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d - %% e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d - %% 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e - %% 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 - %% 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 - ClientHello = - hexstr2bin("01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 - ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 - 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b - 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 - 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 - 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 - 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a - af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 - 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 - 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"), - - ClientHelloRecord = - %% Current implementation always sets - %% legacy_record_version to Ox0303 - hexstr2bin("16 03 03 00 c4 01 00 00 c0 03 03 cb - 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 - ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 - 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 - 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 - 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d - e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d - 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e - 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 - 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"), - - {CHEncrypted, _} = - tls_record:encode_handshake(ClientHello, {3,4}, ConnStatesNull), - ClientHelloRecord = iolist_to_binary(CHEncrypted), - - %% {server} extract secret "early": - %% - %% salt: 0 (all zero octets) - %% - %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% - %% secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c - %% e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a - HKDFAlgo = sha256, - Salt = binary:copy(<>, 32), - IKM = binary:copy(<>, 32), - EarlySecret = - hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c - e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"), - - {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}), - - %% {client} create an ephemeral x25519 key pair: - %% - %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78 - %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05 - %% - %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d - %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c - CPublicKey = - hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d - ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"), - - %% {server} create an ephemeral x25519 key pair: - %% - %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 - %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e - %% - %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 - %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f - SPrivateKey = - hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 - 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"), - - SPublicKey = - hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 - 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"), - - %% {server} construct a ServerHello handshake message: - %% - %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 - %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e - %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 - %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 - %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 - ServerHello = - hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60 - dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e - d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 - 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 - dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), - - %% {server} derive secret for handshake "tls13 derived": - %% - %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2 - %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a - %% - %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 - %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 - %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 - %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba - %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba - Hash = - hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 - 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), - - Hash = crypto:hash(HKDFAlgo, <<>>), - - Info = - hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 - 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 - 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), - - Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)), - - Expanded = - hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba - b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"), - - Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo), - - %% {server} extract secret "handshake": - %% - %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97 - %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba - %% - %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d - %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d - %% - %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b - %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - - %% salt = Expanded - HandshakeIKM = - hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d - 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"), - - HandshakeSecret = - hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b - 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"), - - HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519), - - {handshake_secret, HandshakeSecret} = - tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM, - {early_secret, EarlySecret}), - - %% {server} derive secret "tls13 c hs traffic": - %% - %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 - %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - %% - %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed - %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 - %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e - %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 - - %% PRK = HandshakeSecret - CHSTHash = - hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed - d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), - - CHSTInfo = - hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 - 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), - - CHSTrafficSecret = - hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e - 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"), - - CHSH = <>, - CHSTHash = crypto:hash(HKDFAlgo, CHSH), - CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), - - CHSTrafficSecret = - tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), - - %% {server} derive secret "tls13 s hs traffic": - %% - %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 - %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - %% - %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed - %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 - %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d - %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 - - %% PRK = HandshakeSecret - %% hash = CHSTHash - SHSTInfo = - hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 - 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), - - SHSTrafficSecret = - hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d - 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"), - - SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), - - SHSTrafficSecret = - tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), - - - %% {server} derive secret for master "tls13 derived": - %% - %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 - %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - %% - %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 - %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 - %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 - %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 - %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 - - %% PRK = HandshakeSecret - %% hash = Hash - %% info = Info - MasterDeriveSecret = - hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 - 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"), - - MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo), - - %% {server} extract secret "master": - %% - %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5 - %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 - %% - %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% - %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a - %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - - %% salt = MasterDeriveSecret - %% IKM = IKM - MasterSecret = - hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a - 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"), - - {master_secret, MasterSecret} = - tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}), - - %% {server} send handshake record: - %% - %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e - %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2 - %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11 - %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 - %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 - %% - %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6 - %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 - %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 - %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 - %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 - - %% payload = ServerHello - ServerHelloRecord = - hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6 - af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 - 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 - 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 - cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), - - {SHEncrypted, _} = - tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull), - ServerHelloRecord = iolist_to_binary(SHEncrypted), - - %% {server} derive write traffic keys for handshake data: - %% - %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 - %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 - %% - %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 - %% - %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e - %% e4 03 bc - %% - %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 - %% - %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30 - - %% PRK = SHSTrafficSecret - WriteKeyInfo = - hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"), - - WriteKey = - hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"), - - WriteIVInfo = - hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"), - - WriteIV = - hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"), - - Cipher = aes_128_gcm, %% TODO: get from ServerHello - - WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)), - %% TODO: remove hardcoded IV size - WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12), - - {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret), - - %% {server} construct an EncryptedExtensions handshake message: - %% - %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00 - %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c - %% 00 02 40 01 00 00 00 00 - %% - %% {server} construct a Certificate handshake message: - %% - %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 - %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 - %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 - %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 - %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 - %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 - %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f - %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 - %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c - %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 - %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 - %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 - %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 - %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 - %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 - %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a - %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea - %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 - %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be - %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b - %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 - %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00 - %% - %% {server} construct a CertificateVerify handshake message: - %% - %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c - %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a - %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 - %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b - %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 - %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a - %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3 - EncryptedExtensions = - hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00 - 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c - 00 02 40 01 00 00 00 00"), - - Certificate = - hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 - 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 - 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 - 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 - 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 - 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 - 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f - 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 - d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c - 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 - 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 - 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 - ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 - 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 - 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 - 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a - 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea - e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 - 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be - c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b - 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 - 96 12 29 ac 91 87 b4 2b 4d e1 00 00"), - - CertificateVerify = - hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c - 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a - b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 - 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b - be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 - 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a - 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"), - - %% {server} calculate finished "tls13 finished": - %% - %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 - %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 - %% - %% hash (0 octets): (empty) - %% - %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 - %% 64 00 - %% - %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 - %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8 - %% - %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 - %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18 - - %% PRK = SHSTrafficSecret - FInfo = - hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 - 64 00"), - - FExpanded = - hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 - c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"), - - FinishedVerifyData = - hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 - de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"), - - FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)), - - FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo), - - MessageHistory0 = [CertificateVerify, - Certificate, - EncryptedExtensions, - ServerHello, - ClientHello], - - FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0), - - %% {server} construct a Finished handshake message: - %% - %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb - %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 - %% 18 - FinishedHSBin = - hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb - dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 - 18"), - - FinishedHS = #finished{verify_data = FinishedVerifyData}, - - FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}), - FinishedHSBin = iolist_to_binary(FinishedIOList), - - %% {server} derive secret "tls13 c ap traffic": - %% - %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 - %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - %% - %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 - %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce - %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5 - - %% PRK = MasterSecret - CAPTHash = - hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - CAPTInfo = - hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 - 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - - CAPTrafficSecret = - hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce - 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"), - - CHSF = <>, - - CAPTHash = crypto:hash(HKDFAlgo, CHSF), - - CAPTInfo = - tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), - - CAPTrafficSecret = - tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), - - %% {server} derive secret "tls13 s ap traffic": - %% - %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 - %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - %% - %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 - %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 - %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 - - %% PRK = MasterSecret - %% hash = CAPTHash - SAPTInfo = - hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 - 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - - SAPTrafficSecret = - hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 - 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"), - - SAPTInfo = - tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), - - SAPTrafficSecret = - tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), - - %% {server} derive secret "tls13 exp master": - %% - %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 - %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - %% - %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 - %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 - %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 - %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50 - - %% PRK = MasterSecret - %% hash = CAPTHash - ExporterInfo = - hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 - 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 - 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - - ExporterMasterSecret = - hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 - 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"), - - ExporterInfo = - tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), - - ExporterMasterSecret = - tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF), - - %% {server} derive write traffic keys for application data: - %% - %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32 - %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 - %% - %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 - %% - %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac - %% 92 e3 56 - %% - %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 - %% - %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84 - - %% PRK = SAPTrafficsecret - %% key info = WriteKeyInfo - %% iv info = WrtieIVInfo - SWKey = - hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"), - - SWIV = - hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"), - - {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret), - - %% {server} derive read traffic keys for handshake data: - %% - %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f - %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 - %% - %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 - %% - %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 - %% 25 8d 01 - %% - %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 - %% - %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f - - %% PRK = CHSTrafficsecret - %% key info = WriteKeyInfo - %% iv info = WrtieIVInfo - SRKey = - hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"), - - SRIV = - hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"), - - {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret). - - -tls13_finished_verify_data() -> - [{doc,"Test TLS 1.3 Finished message handling"}]. - -tls13_finished_verify_data(_Config) -> - ClientHello = - hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09 - 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 - 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 - e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 - f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01 - 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d - 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00 - 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00 - 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06 - 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72 - d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed - 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00 - 02 01 01 00 2b 00 03 02 03 04"), - - ServerHello = - hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79 - 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 - 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 - e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 - f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24 - 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b - 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 - 28 80 b6 15 00 2b 00 02 03 04"), - - EncryptedExtensions = - hexstr2bin("08 00 00 02 00 00"), - - Certificate = - hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30 - 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 - 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 - 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 - 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 - 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 - 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 - 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 - 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 - 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e - 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d - 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 - 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 - b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 - 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d - bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d - f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 - f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b - 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 - f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 - ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 - ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 - 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb - 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 - 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 - d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad - 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 - 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 - ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 - 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 - 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 - 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 - 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 - cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 - 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 - 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b - fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 - 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd - 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 - f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 - 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 - 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 - 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 - ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e - 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 - c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 - cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 - 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f - 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 - 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 - 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0 - 00 00"), - - CertificateVerify = - hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d - 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75 - 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8 - 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13 - 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73 - df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b - 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2 - 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84 - fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c - 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5 - 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79 - ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a - aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7 - 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b - 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36 - c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe - c7 e4 a7 30 f1 36 9f 9e"), - - BaseKey = - hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4 - 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"), - - VerifyData = - hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea - c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"), - - Messages = [CertificateVerify, - Certificate, - EncryptedExtensions, - ServerHello, - ClientHello], - - FinishedKey = tls_v1:finished_key(BaseKey, sha256), - VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages). - - -tls12_ssl_server_tls13_ssl_client() -> - [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client"}]. - -tls12_ssl_server_tls13_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {signature_algs_cert, [ecdsa_secp384r1_sha384, - rsa_pss_rsae_sha256, - rsa_pkcs1_sha256, - {sha256,rsa},{sha256,dsa}]}|ClientOpts0], - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_basic_ssl_server_openssl_client() -> - [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client"}]. - -tls13_basic_ssl_server_openssl_client(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - -tls13_basic_ssl_server_ssl_client() -> - [{doc,"Test TLS 1.3 basic connection between ssl server and ssl client"}]. - -tls13_basic_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_basic_openssl_server_ssl_client() -> - [{doc,"Test TLS 1.3 basic connection between openssl server and ssl client"}]. - -tls13_basic_openssl_server_ssl_client(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - "-tls1_3", - "-cert", CertFile, "-CAfile", CaCertFile, - "-key", KeyFile, "-Verify", "2"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, tls), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - - -tls13_custom_groups_ssl_server_openssl_client() -> - [{doc,"Test that ssl server can select a common group for key-exchange"}]. - -tls13_custom_groups_ssl_server_openssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - ClientOpts = [{groups,"P-384:P-256:X25519"}|ClientOpts0], - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_custom_groups_ssl_server_ssl_client() -> - [{doc,"Test that ssl server can select a common group for key-exchange"}]. - -tls13_custom_groups_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0], - ClientOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - ClientOpts = [{supported_groups,[secp384r1, secp256r1, x25519]}|ClientOpts1], - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hello_retry_request_ssl_server_openssl_client() -> - [{doc,"Test that ssl server can request a new group when the client's first key share" - "is not supported"}]. - -tls13_hello_retry_request_ssl_server_openssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [x448, x25519]}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0], - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hello_retry_request_ssl_server_ssl_client() -> - [{doc,"Test that ssl server can request a new group when the client's first key share" - "is not supported"}]. - -tls13_hello_retry_request_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [x448, x25519]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [secp256r1, x25519]}|ClientOpts0], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - -tls13_client_auth_empty_cert_alert_ssl_server_openssl_client() -> - [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}]. - -tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts = proplists:delete(keyfile, ClientOpts1), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_server_alert(Server, certificate_required), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_client_auth_empty_cert_alert_ssl_server_ssl_client() -> - [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}]. - -tls13_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts2 = proplists:delete(keyfile, ClientOpts1), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_server_alert(Server, certificate_required), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_client_auth_empty_cert_ssl_server_openssl_client() -> - [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}]. - -tls13_client_auth_empty_cert_ssl_server_openssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts = proplists:delete(keyfile, ClientOpts1), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, false}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_client_auth_empty_cert_ssl_server_ssl_client() -> - [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}]. - -tls13_client_auth_empty_cert_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts2 = proplists:delete(keyfile, ClientOpts1), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, false}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_client_auth_ssl_server_openssl_client() -> - [{doc,"TLS 1.3: Test client authentication."}]. - -tls13_client_auth_ssl_server_openssl_client(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_client_auth_ssl_server_ssl_client() -> - [{doc,"TLS 1.3: Test client authentication."}]. - -tls13_client_auth_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - %%Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client() -> - [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}]. - -tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts2 = proplists:delete(keyfile, ClientOpts1), - ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2], - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}, - {supported_groups, [x448, x25519]}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_server_alert(Server, certificate_required), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client() -> - [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}]. - -tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts2 = proplists:delete(keyfile, ClientOpts1), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}, - {supported_groups, [x448, x25519]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [secp256r1, x25519]}|ClientOpts2], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_server_alert(Server, certificate_required), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client() -> - [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}]. - -tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts2 = proplists:delete(keyfile, ClientOpts1), - ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2], - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, false}, - {supported_groups, [x448, x25519]}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client() -> - [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}]. - -tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - %% Delete Client Cert and Key - ClientOpts1 = proplists:delete(certfile, ClientOpts0), - ClientOpts2 = proplists:delete(keyfile, ClientOpts1), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, false}, - {supported_groups, [x448, x25519]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [secp256r1, x25519]}|ClientOpts2], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hrr_client_auth_ssl_server_openssl_client() -> - [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}]. - -tls13_hrr_client_auth_ssl_server_openssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0], - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}, - {supported_groups, [x448, x25519]}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_hrr_client_auth_ssl_server_ssl_client() -> - [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}]. - -tls13_hrr_client_auth_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}, - {supported_groups, [x448, x25519]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {supported_groups, [secp256r1, x25519]}|ClientOpts0], - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client() -> - [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}]. - -tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - %% Skip rsa_pkcs1_sha256! - {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]}, - {fail_if_no_peer_cert, true}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_server_alert(Server, insufficient_security), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client() -> - [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}]. - -tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - %% Skip rsa_pkcs1_sha256! - {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]}, - {fail_if_no_peer_cert, true}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), + Server = ssl_test_lib:start_server_transport_abuse_socket([{node, ServerNode}, + {port, 0}, + {from, self()}, + {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_server_alert(Server, insufficient_security), + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ClientOpts}]), + ssl_test_lib:check_result(Server, ok), ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -%% Triggers a Server Alert as openssl s_client does not have a certificate with a -%% signature algorithm supported by the server (signature_algorithms_cert extension -%% of CertificateRequest does not contain the algorithm of the client certificate). -%% openssl s_client sends an empty certificate. -tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client() -> - [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}]. - -tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {log_level, debug}, - {verify, verify_peer}, - {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]}, - %% Skip rsa_pkcs1_sha256! - {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]}, - {fail_if_no_peer_cert, true}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + ssl_test_lib:close(Client). + - ssl_test_lib:check_server_alert(Server, certificate_required), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -%% Triggers a Server Alert as ssl client does not have a certificate with a -%% signature algorithm supported by the server (signature_algorithms_cert extension -%% of CertificateRequest does not contain the algorithm of the client certificate). -%% ssl client sends an empty certificate. -tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client() -> - [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}]. - -tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {log_level, debug}, - {verify, verify_peer}, - {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]}, - %% Skip rsa_pkcs1_sha256! - {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]}, - {fail_if_no_peer_cert, true}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], +%%-------------------------------------------------------------------- +controlling_process_transport_accept_socket() -> + [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}]. +controlling_process_transport_accept_socket(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), + Server = ssl_test_lib:start_server_transport_control([{node, ServerNode}, + {port, 0}, + {from, self()}, + {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), + + _Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, ClientOpts}]), + ssl_test_lib:check_result(Server, ok), + ssl_test_lib:close(Server). - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_server_alert(Server, certificate_required), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_connection_information() -> - [{doc,"Test the API function ssl:connection_information/1 in a TLS 1.3 connection"}]. - -tls13_connection_information(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, connection_information_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), +%%-------------------------------------------------------------------- +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). - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), +%%-------------------------------------------------------------------- - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). +rizzo() -> + [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is + vunrable to Rizzo/Dungon attack"}]. +rizzo(Config) when is_list(Config) -> + Prop = proplists:get_value(tc_group_properties, Config), + Version = proplists:get_value(name, Prop), + NVersion = ssl_test_lib:protocol_version(Config, tuple), + Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion), + [{key_exchange, + fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> + true; + (_) -> + false + end}, + {cipher, + fun(rc4_128) -> + false; + (chacha20_poly1305) -> + false; + (_) -> + true + end}]), -tls13_ssl_server_with_alpn_ssl_client() -> - [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client"}]. + run_send_recv_rizzo(Ciphers, Config, Version, + {?MODULE, send_recv_result_active_rizzo, []}). +%%-------------------------------------------------------------------- +no_rizzo_rc4() -> + [{doc,"Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"}]. -tls13_ssl_server_with_alpn_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +no_rizzo_rc4(Config) when is_list(Config) -> + Prop = proplists:get_value(tc_group_properties, Config), + Version = proplists:get_value(name, Prop), + NVersion = ssl_test_lib:protocol_version(Config, tuple), + %% Test uses RSA certs + Ciphers = ssl:filter_cipher_suites(ssl_test_lib:rc4_suites(NVersion), + [{key_exchange, + fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> + true; + (_) -> + false + end}]), + run_send_recv_rizzo(Ciphers, Config, Version, + {?MODULE, send_recv_result_active_no_rizzo, []}). - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], +rizzo_one_n_minus_one() -> + [{doc,"Test that the 1/n-1-split mitigation of Rizzo/Dungon attack can be explicitly selected"}]. - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), +rizzo_one_n_minus_one(Config) when is_list(Config) -> + Prop = proplists:get_value(tc_group_properties, Config), + Version = proplists:get_value(name, Prop), + NVersion = ssl_test_lib:protocol_version(Config, tuple), + Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion), + [{key_exchange, + fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa-> + true; + (_) -> + false + end}, + {cipher, + fun(rc4_128) -> + false; + %% TODO: remove this clause when chacha is fixed! + (chacha20_poly1305) -> + false; + (_) -> + true + end}]), + run_send_recv_rizzo(Ciphers, Config, Version, + {?MODULE, send_recv_result_active_rizzo, []}). - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), +rizzo_zero_n() -> + [{doc,"Test that the 0/n-split mitigation of Rizzo/Dungon attack can be explicitly selected"}]. - ssl_test_lib:check_result(Server, ok, Client, ok), +rizzo_zero_n(Config) when is_list(Config) -> + Prop = proplists:get_value(tc_group_properties, Config), + Version = proplists:get_value(name, Prop), + NVersion = ssl_test_lib:protocol_version(Config, tuple), + Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion), + [{cipher, + fun(rc4_128) -> + false; + (_) -> + true + end}]), + run_send_recv_rizzo(Ciphers, Config, Version, + {?MODULE, send_recv_result_active_no_rizzo, []}). - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). +rizzo_disabled() -> + [{doc,"Test that the mitigation of Rizzo/Dungon attack can be explicitly disabled"}]. +rizzo_disabled(Config) when is_list(Config) -> + Prop = proplists:get_value(tc_group_properties, Config), + Version = proplists:get_value(name, Prop), + NVersion = ssl_test_lib:protocol_version(Config, tuple), + Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion), + [{cipher, + fun(rc4_128) -> + false; + (_) -> + true + end}]), + run_send_recv_rizzo(Ciphers, Config, Version, + {?MODULE, send_recv_result_active_no_rizzo, []}). -tls13_ssl_server_with_alpn_ssl_client_empty_alpn() -> - [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with empty ALPN"}]. +%%-------------------------------------------------------------------- +new_server_wants_peer_cert() -> + [{doc, "Test that server configured to do client certification does" + " not reuse session without a client certificate."}]. +new_server_wants_peer_cert(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + VServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ssl_test_lib:ssl_options(server_verification_opts, Config)], + ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), -tls13_ssl_server_with_alpn_ssl_client_empty_alpn(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_advertised_protocols, []}|ClientOpts0], - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, [ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), + Client = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ClientOpts}]), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_server_alert(Server, no_application_protocol), - + Monitor = erlang:monitor(process, Server), ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). + ssl_test_lib:close(Client), + receive + {'DOWN', Monitor, _, _, _} -> + ok + end, + + Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, + {from, self()}, + {mfa, {?MODULE, peercert_result, []}}, + {options, VServerOpts}]), + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [ClientOpts]}]), + + CertFile = proplists:get_value(certfile, ClientOpts), + [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile), + ServerMsg = {error, no_peercert}, + Sever1Msg = {ok, BinCert}, + + ssl_test_lib:check_result(Server, ServerMsg, Server1, Sever1Msg), -tls13_ssl_server_with_alpn_ssl_client_bad_alpn() -> - [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with bad ALPN"}]. + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client), + ssl_test_lib:close(Client1). -tls13_ssl_server_with_alpn_ssl_client_bad_alpn(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), +%%-------------------------------------------------------------------- - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_advertised_protocols, [<<1,2,3,4>>]}|ClientOpts0], +tls_versions_option() -> + [{doc,"Test API versions option to connect/listen."}]. +tls_versions_option(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, + Supported = proplists:get_value(supported, ssl:versions()), + Available = proplists:get_value(available, ssl:versions()), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), + {options, [{versions, Supported} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, + {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + Server ! listen, + + ErrClient = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{versions , Available -- Supported} | ClientOpts]}]), + receive + {Server, _} -> + ok + end, + ssl_test_lib:check_client_alert(ErrClient, protocol_version). - ssl_test_lib:check_server_alert(Server, no_application_protocol), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). +%%-------------------------------------------------------------------- +unordered_protocol_versions_server() -> + [{doc,"Test that the highest protocol is selected even" + " when it is not first in the versions list."}]. -tls13_ssl_server_with_alpn_ssl_client_alpn() -> - [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with correct ALPN"}]. +unordered_protocol_versions_server(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), -tls13_ssl_server_with_alpn_ssl_client_alpn(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_advertised_protocols, [<<1,2,3,4>>, <<5,6>>]}|ClientOpts0], - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, protocol_info_result, []}}, + {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {from, self()}, + {mfa, {?MODULE, protocol_info_result, []}}, {options, ClientOpts}]), - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - + ServerMsg = ClientMsg = {ok,'tlsv1.2'}, + ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). -tls13_ecdsa_ssl_server_openssl_client() -> - [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client using ECDSA certificates"}]. +%%-------------------------------------------------------------------- +unordered_protocol_versions_client() -> + [{doc,"Test that the highest protocol is selected even" + " when it is not first in the versions list."}]. -tls13_ecdsa_ssl_server_openssl_client(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_ecdsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_ecdsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), +unordered_protocol_versions_client(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, protocol_info_result, []}}, + {options, ServerOpts }]), Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, protocol_info_result, []}}, + {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]), - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). + ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, + ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). + +%%-------------------------------------------------------------------- +max_handshake_size() -> + [{doc,"Test that we can set max_handshake_size to max value."}]. -tls13_ecdsa_ssl_server_ssl_client() -> - [{doc,"Test TLS 1.3 basic connection between ssl server and ssl client using ECDSA certificates"}]. +max_handshake_size(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), -tls13_ecdsa_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_ecdsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_ecdsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), + {options, [{max_handshake_size, 8388607} |ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, + {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_ecdsa_openssl_server_ssl_client() -> - [{doc,"Test TLS 1.3 basic connection between openssl server and ssl client using ECDSA certificates"}]. - -tls13_ecdsa_openssl_server_ssl_client(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_ecdsa_verify_opts, Config), - ClientOpts0 = ssl_test_lib:ssl_options(client_ecdsa_opts, Config), - - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - "-tls1_3", - "-cert", CertFile, "-CAfile", CaCertFile, - "-key", KeyFile, "-Verify", "2"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, tls), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - - -tls13_ecdsa_client_auth_ssl_server_ssl_client() -> - [{doc,"TLS 1.3: Test client authentication with ECDSA certificates."}]. + {options, [{max_handshake_size, 8388607} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + +%%-------------------------------------------------------------------- -tls13_ecdsa_client_auth_ssl_server_ssl_client(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_ecdsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_ecdsa_opts, Config), +server_name_indication_option() -> + [{doc,"Test API server_name_indication option to connect."}]. +server_name_indication_option(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true}|ServerOpts0], - ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), + + Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, + [{server_name_indication, disable} | + ClientOpts]} + ]), + + ssl_test_lib:check_result(Server, ok, Client0, ok), + Server ! listen, + + Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, + [{server_name_indication, Hostname} | ClientOpts] + }]), + ssl_test_lib:check_result(Server, ok, Client1, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1). +%%-------------------------------------------------------------------- - %%Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ClientOpts}]), +accept_pool() -> + [{doc,"Test having an accept pool."}]. +accept_pool(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {accepters, 3}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server0), + [Server1, Server2] = ssl_test_lib:accepters(2), + Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ClientOpts} + ]), + + Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ClientOpts} + ]), + + Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ClientOpts} + ]), + ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]), + + ssl_test_lib:close(Server0), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Server2), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1), + ssl_test_lib:close(Client2). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ @@ -6636,42 +3943,7 @@ ssl_active_recv(N, Acc) -> result_ok(_Socket) -> ok. -renegotiate(Socket, Data) -> - ct:log("Renegotiating ~n", []), - Result = ssl:renegotiate(Socket), - ct:log("Result ~p~n", [Result]), - ssl:send(Socket, Data), - case Result of - ok -> - ok; - Other -> - Other - end. - -renegotiate_reuse_session(Socket, Data) -> - %% Make sure session is registered - ct:sleep(?SLEEP), - renegotiate(Socket, Data). - -renegotiate_immediately(Socket) -> - _ = ssl_test_lib:active_recv(Socket, 11), - ok = ssl:renegotiate(Socket), - {error, renegotiation_rejected} = ssl:renegotiate(Socket), - ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP), - ok = ssl:renegotiate(Socket), - ct:log("Renegotiated again"), - ssl:send(Socket, "Hello world"), - ok. -renegotiate_rejected(Socket) -> - _ = ssl_test_lib:active_recv(Socket, 11), - {error, renegotiation_rejected} = ssl:renegotiate(Socket), - {error, renegotiation_rejected} = ssl:renegotiate(Socket), - ct:sleep(?RENEGOTIATION_DISABLE_TIME +1), - {error, renegotiation_rejected} = ssl:renegotiate(Socket), - ct:log("Failed to renegotiate again"), - ssl:send(Socket, "Hello world"), - ok. rizzo_add_mitigation_option(Value, Config) -> lists:foldl(fun(Opt, Acc) -> @@ -6686,157 +3958,6 @@ rizzo_add_mitigation_option(Value, Config) -> [client_opts, client_dsa_opts, server_opts, server_dsa_opts, server_ecdsa_opts, server_ecdh_rsa_opts]). -new_config(PrivDir, ServerOpts0) -> - CaCertFile = proplists:get_value(cacertfile, ServerOpts0), - CertFile = proplists:get_value(certfile, ServerOpts0), - KeyFile = proplists:get_value(keyfile, ServerOpts0), - NewCaCertFile = filename:join(PrivDir, "new_ca.pem"), - NewCertFile = filename:join(PrivDir, "new_cert.pem"), - NewKeyFile = filename:join(PrivDir, "new_key.pem"), - file:copy(CaCertFile, NewCaCertFile), - file:copy(CertFile, NewCertFile), - file:copy(KeyFile, NewKeyFile), - ServerOpts1 = proplists:delete(cacertfile, ServerOpts0), - ServerOpts2 = proplists:delete(certfile, ServerOpts1), - ServerOpts = proplists:delete(keyfile, ServerOpts2), - - {ok, PEM} = file:read_file(NewCaCertFile), - ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]), - - [{cacertfile, NewCaCertFile}, {certfile, NewCertFile}, - {keyfile, NewKeyFile} | ServerOpts]. - -session_cache_process(_Type,Config) when is_list(Config) -> - reuse_session(Config). - -init([Type]) -> - ets:new(ssl_test, [named_table, public, set]), - ets:insert(ssl_test, {type, Type}), - case Type of - list -> - spawn(fun() -> session_loop([]) end); - mnesia -> - mnesia:start(), - {atomic,ok} = mnesia:create_table(sess_cache, []), - sess_cache - end. - -session_cb() -> - [{type, Type}] = ets:lookup(ssl_test, type), - Type. - -terminate(Cache) -> - case session_cb() of - list -> - Cache ! terminate; - mnesia -> - catch {atomic,ok} = - mnesia:delete_table(sess_cache) - end. - -lookup(Cache, Key) -> - case session_cb() of - list -> - Cache ! {self(), lookup, Key}, - receive {Cache, Res} -> Res end; - mnesia -> - case mnesia:transaction(fun() -> - mnesia:read(sess_cache, - Key, read) - end) of - {atomic, [{sess_cache, Key, Value}]} -> - Value; - _ -> - undefined - end - end. - -update(Cache, Key, Value) -> - case session_cb() of - list -> - Cache ! {update, Key, Value}; - mnesia -> - {atomic, ok} = - mnesia:transaction(fun() -> - mnesia:write(sess_cache, - {sess_cache, Key, Value}, write) - end) - end. - -delete(Cache, Key) -> - case session_cb() of - list -> - Cache ! {delete, Key}; - mnesia -> - {atomic, ok} = - mnesia:transaction(fun() -> - mnesia:delete(sess_cache, Key) - end) - end. - -foldl(Fun, Acc, Cache) -> - case session_cb() of - list -> - Cache ! {self(),foldl,Fun,Acc}, - receive {Cache, Res} -> Res end; - mnesia -> - Foldl = fun() -> - mnesia:foldl(Fun, Acc, sess_cache) - end, - {atomic, Res} = mnesia:transaction(Foldl), - Res - end. - -select_session(Cache, PartialKey) -> - case session_cb() of - list -> - Cache ! {self(),select_session, PartialKey}, - receive - {Cache, Res} -> - Res - end; - mnesia -> - Sel = fun() -> - mnesia:select(Cache, - [{{sess_cache,{PartialKey,'$1'}, '$2'}, - [],['$$']}]) - end, - {atomic, Res} = mnesia:transaction(Sel), - Res - end. - -session_loop(Sess) -> - receive - terminate -> - ok; - {Pid, lookup, Key} -> - case lists:keysearch(Key,1,Sess) of - {value, {Key,Value}} -> - Pid ! {self(), Value}; - _ -> - Pid ! {self(), undefined} - end, - session_loop(Sess); - {update, Key, Value} -> - NewSess = [{Key,Value}| lists:keydelete(Key,1,Sess)], - session_loop(NewSess); - {delete, Key} -> - session_loop(lists:keydelete(Key,1,Sess)); - {Pid,foldl,Fun,Acc} -> - Res = lists:foldl(Fun, Acc,Sess), - Pid ! {self(), Res}, - session_loop(Sess); - {Pid,select_session,PKey} -> - Sel = fun({{PKey0, Id},Session}, Acc) when PKey == PKey0 -> - [[Id, Session]|Acc]; - (_,Acc) -> - Acc - end, - Sessions = lists:foldl(Sel, [], Sess), - Pid ! {self(), Sessions}, - session_loop(Sess) - end. - erlang_ssl_receive(Socket, Data) -> case ssl_test_lib:active_recv(Socket, length(Data)) of @@ -7014,14 +4135,6 @@ tls_close(Socket) -> ct:fail(Other) end. - %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast -treashold(N, {3,0}) -> - (N div 2) + 1; -treashold(N, {3,1}) -> - (N div 2) + 1; -treashold(N, _) -> - N + 1. - get_invalid_inet_option(Socket) -> {error, {options, {socket_options, foo, _}}} = ssl:getopts(Socket, [foo]), ok. @@ -7103,30 +4216,3 @@ tls_or_dtls('dtlsv1.2') -> tls_or_dtls(_) -> tls. -hexstr2int(S) -> - B = hexstr2bin(S), - Bits = size(B) * 8, - <> = B, - Integer. - -hexstr2bin(S) when is_binary(S) -> - hexstr2bin(S, <<>>); -hexstr2bin(S) -> - hexstr2bin(list_to_binary(S), <<>>). -%% -hexstr2bin(<<>>, Acc) -> - Acc; -hexstr2bin(<>, Acc) when C =:= 32; %% SPACE - C =:= 10; %% LF - C =:= 13 -> %% CR - hexstr2bin(T, Acc); -hexstr2bin(<>, Acc) -> - I = hex2int(X) * 16 + hex2int(Y), - hexstr2bin(T, <>). - -hex2int(C) when $0 =< C, C =< $9 -> - C - $0; -hex2int(C) when $A =< C, C =< $F -> - C - $A + 10; -hex2int(C) when $a =< C, C =< $f -> - C - $a + 10. diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl new file mode 100644 index 0000000000..571e7428ea --- /dev/null +++ b/lib/ssl/test/ssl_cert_SUITE.erl @@ -0,0 +1,547 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_cert_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + [ + {group, 'tlsv1.3'}, + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'} + ]. + +groups() -> + [ + {'tlsv1.3', [], tls_1_3_protocol_groups()}, + {'tlsv1.2', [], pre_tls_1_3_protocol_groups()}, + {'tlsv1.1', [], pre_tls_1_3_protocol_groups()}, + {'tlsv1', [], pre_tls_1_3_protocol_groups()}, + {'sslv3', [], ssl_protocol_groups()}, + {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()}, + {'dtlsv1', [], pre_tls_1_3_protocol_groups()}, + {rsa, [], all_version_tests()}, + {ecdsa, [], all_version_tests()}, + {dsa, [], all_version_tests()}, + {rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_cert_client_auth]}, + {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()} + ]. + +ssl_protocol_groups() -> + [{group, rsa}, + {group, dsa}]. + +pre_tls_1_3_protocol_groups() -> + [{group, rsa}, + {group, ecdsa}, + {group, dsa}]. + +tls_1_3_protocol_groups() -> + [{group, rsa_1_3}, + {group, ecdsa_1_3}]. + +tls_1_3_tests() -> + [ + hello_retry_request, + custom_groups, + hello_retry_client_auth, + hello_retry_client_auth_empty_cert_accepted, + hello_retry_client_auth_empty_cert_rejected + ]. + +all_version_tests() -> + [ + no_auth, + auth, + client_auth_empty_cert_accepted, + client_auth_empty_cert_rejected, + client_auth_partial_chain, + client_auth_allow_partial_chain, + client_auth_do_not_allow_partial_chain, + client_auth_partial_chain_fun_fail, + missing_root_cert_no_auth, + missing_root_cert_auth, + missing_root_cert_auth_user_verify_fun_accept, + missing_root_cert_auth_user_verify_fun_reject, + verify_fun_always_run_client, + verify_fun_always_run_server, + incomplete_chain_auth + %%invalid_signature_client + ]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:unload(ssl), + application:stop(crypto). + +init_per_group(Group, Config0) when Group == rsa; + Group == rsa_1_3 -> + Config = ssl_test_lib:make_rsa_cert(Config0), + COpts = proplists:get_value(client_rsa_opts, Config), + SOpts = proplists:get_value(server_rsa_opts, Config), + [{cert_key_alg, rsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, COpts}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))])]; +init_per_group(Group, Config0) when Group == ecdsa; + Group == ecdsa_1_3 -> + + PKAlg = crypto:supports(public_keys), + case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of + true -> + Config = ssl_test_lib:make_ecdsa_cert(Config0), + COpts = proplists:get_value(client_ecdsa_opts, Config), + SOpts = proplists:get_value(server_ecdsa_opts, Config), + [{cert_key_alg, ecdsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, COpts}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))] + )]; + false -> + {skip, "Missing EC crypto support"} + end; + +init_per_group(Group, Config0) when Group == dsa -> + PKAlg = crypto:supports(public_keys), + case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of + true -> + Config = ssl_test_lib:make_dsa_cert(Config0), + COpts = proplists:get_value(client_dsa_opts, Config), + SOpts = proplists:get_value(server_dsa_opts, Config), + [{cert_key_alg, dsa} | + lists:delete(cert_key_alg, + [{client_cert_opts, COpts}, + {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, + lists:delete(client_cert_opts, Config))])]; + false -> + {skip, "Missing DSS crypto support"} + end; +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + [{client_type, erlang}, + {server_type, erlang}, {version, GroupName} + | ssl_test_lib:init_tls_version(GroupName, Config)]; + false -> + {skip, "Missing crypto support"} + end; + _ -> + ssl:start(), + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(_TestCase, Config) -> + ssl_test_lib:ct_log_supported_protocol_versions(Config), + ct:timetrap({seconds, 10}), + Config. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +no_auth() -> + ssl_cert_tests:no_auth(). + +no_auth(Config) -> + ssl_cert_tests:no_auth(Config). +%%-------------------------------------------------------------------- +auth() -> + ssl_cert_tests:auth(). +auth(Config) -> + ssl_cert_tests:auth(Config). +%%-------------------------------------------------------------------- +client_auth_empty_cert_accepted() -> + ssl_cert_tests:client_auth_empty_cert_accepted(). +client_auth_empty_cert_accepted(Config) -> + ssl_cert_tests:client_auth_empty_cert_accepted(Config). +%%-------------------------------------------------------------------- +client_auth_empty_cert_rejected() -> + ssl_cert_tests:client_auth_empty_cert_rejected(). +client_auth_empty_cert_rejected(Config) -> + ssl_cert_tests:client_auth_empty_cert_rejected(Config). +%%-------------------------------------------------------------------- +client_auth_partial_chain() -> + ssl_cert_tests:client_auth_partial_chain(). +client_auth_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_partial_chain(Config). + +%%-------------------------------------------------------------------- +client_auth_allow_partial_chain() -> + ssl_cert_tests:client_auth_allow_partial_chain(). +client_auth_allow_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_allow_partial_chain(Config). +%%-------------------------------------------------------------------- +client_auth_do_not_allow_partial_chain() -> + ssl_cert_tests:client_auth_do_not_allow_partial_chain(). +client_auth_do_not_allow_partial_chain(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config). + +%%-------------------------------------------------------------------- +client_auth_partial_chain_fun_fail() -> + ssl_cert_tests:client_auth_partial_chain_fun_fail(). +client_auth_partial_chain_fun_fail(Config) when is_list(Config) -> + ssl_cert_tests:client_auth_partial_chain_fun_fail(Config). + + +%%-------------------------------------------------------------------- +missing_root_cert_no_auth() -> + ssl_cert_tests:missing_root_cert_no_auth(). +missing_root_cert_no_auth(Config) when is_list(Config) -> + ssl_cert_tests:missing_root_cert_no_auth(Config). + +%%-------------------------------------------------------------------- +missing_root_cert_auth() -> + [{doc,"Must have ROOT certs to be able to verify verify peer"}]. +missing_root_cert_auth(Config) when is_list(Config) -> + ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_cert_opts, Config)), + {ClientNode, ServerNode, _} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{verify, verify_peer} + | ServerOpts]}]), + + ssl_test_lib:check_result(Server, {error, {options, {cacertfile, ""}}}), + + ClientOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(client_cert_opts, Config)), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0}, + {from, self()}, + {options, [{verify, verify_peer} + | ClientOpts]}]), + + ssl_test_lib:check_result(Client, {error, {options, {cacertfile, ""}}}). + +%%-------------------------------------------------------------------- +missing_root_cert_auth_user_verify_fun_accept() -> + [{doc, "Test that the client succeds if the ROOT CA is unknown in verify_peer mode" + " with a verify_fun that accepts the unknown CA error"}]. + +missing_root_cert_auth_user_verify_fun_accept(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config), + FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, []}, + ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer}, + {verify_fun, FunAndState}], Config), + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +missing_root_cert_auth_user_backwardscompatibility_verify_fun_accept() -> + [{doc, "Test old style verify fun"}]. + +missing_root_cert_auth_user_backwardscompatibility_verify_fun_accept(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config), + AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc; + (Other, Acc) -> [Other | Acc] + end, + VerifyFun = + fun(ErrorList) -> + case lists:foldl(AcceptBadCa, [], ErrorList) of + [] -> true; + [_|_] -> false + end + end, + + ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer}, + {verify_fun, VerifyFun}], Config), + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +missing_root_cert_auth_user_verify_fun_reject() -> + [{doc, "Test that the client fails if the ROOT CA is unknown in verify_peer mode" + " with a verify_fun that rejects the unknown CA error"}]. + +missing_root_cert_auth_user_verify_fun_reject(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config), + FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _UserState) -> + {fail, Reason}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, UserState}, _) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, []}, + ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer}, + {verify_fun, FunAndState}], Config), + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca). +%%-------------------------------------------------------------------- +incomplete_chain_auth() -> + [{doc,"Test that we can verify an incompleat chain when we have the certs to rebuild it"}]. +incomplete_chain_auth(Config) when is_list(Config) -> + DefaultCertConf = ssl_test_lib:default_cert_chain_conf(), + #{client_config := ClientOpts0, + server_config := ServerOpts0} = ssl_test_lib:make_cert_chains_der(proplists:get_value(cert_key_alg, Config), + [{server_chain, DefaultCertConf}, + {client_chain, DefaultCertConf}]), + [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerOpts0), + ClientCas = proplists:get_value(cacerts, ClientOpts0), + ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer}, + {cacerts, ServerCas ++ ClientCas} | + proplists:delete(cacerts, ClientOpts0)], Config), + ServerOpts = ssl_test_lib:ssl_options([{verify, verify_peer}, + {cacerts, [ServerRoot]} | + proplists:delete(cacerts, ServerOpts0)], Config), + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +verify_fun_always_run_client() -> + [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}]. + +verify_fun_always_run_client(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + %% If user verify fun is called correctly we fail the connection. + %% otherwise we cannot tell this case apart form where we miss + %% to call users verify fun + FunAndState = {fun(_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, [ChainLen]) -> + {valid, [ChainLen + 1]}; + (_, valid_peer, [1]) -> + {fail, "verify_fun_was_always_run"}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, [0]}, + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} + | ClientOpts]}]), + + ssl_test_lib:check_client_alert(Server, Client, handshake_failure). + +%%-------------------------------------------------------------------- +verify_fun_always_run_server() -> + [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}]. +verify_fun_always_run_server(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + %% If user verify fun is called correctly we fail the connection. + %% otherwise we cannot tell this case apart form where we miss + %% to call users verify fun + FunAndState = {fun(_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, [ChainLen]) -> + {valid, [ChainLen + 1]}; + (_, valid_peer, [1]) -> + {fail, "verify_fun_was_always_run"}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, [0]}, + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} | + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_client_alert(Server, Client, handshake_failure). + +%%-------------------------------------------------------------------- +invalid_signature_client() -> + ssl_cert_tests:invalid_signature_client(). +invalid_signature_client(Config) when is_list(Config) -> + ssl_cert_tests:invalid_signature_client(Config). +%%-------------------------------------------------------------------- +invalid_signature_server() -> + ssl_cert_tests:invalid_signature_client(). +invalid_signature_server(Config) when is_list(Config) -> + ssl_cert_tests:invalid_signature_client(Config). + +%%-------------------------------------------------------------------- +%% TLS 1.3 Test cases ----------------------------------------------- +%%-------------------------------------------------------------------- +hello_retry_request() -> + [{doc,"Test that ssl server can request a new group when the client's first key share" + "is not supported"}]. + +hello_retry_request(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {supported_groups, [x448, x25519]}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {supported_groups, [secp256r1, x25519]}|ClientOpts0], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +custom_groups() -> + [{doc,"Test that ssl server can select a common group for key-exchange"}]. + +custom_groups(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + %% Set versions + ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0], + ClientOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], + ClientOpts = [{supported_groups,[secp384r1, secp256r1, x25519]}|ClientOpts1], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +%% Triggers a Server Alert as ssl client does not have a certificate with a +%% signature algorithm supported by the server (signature_algorithms_cert extension +%% of CertificateRequest does not contain the algorithm of the client certificate). +%% ssl client sends an empty certificate. +unsupported_sign_algo_cert_client_auth() -> + [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}]. + +unsupported_sign_algo_cert_client_auth(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {verify, verify_peer}, + %% Skip rsa_pkcs1_sha256! + {signature_algs, [rsa_pkcs1_sha384, rsa_pss_rsae_sha256]}, + {fail_if_no_peer_cert, true}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, handshake_failure). +%%-------------------------------------------------------------------- +hello_retry_client_auth() -> + [{doc, "TLS 1.3 (HelloRetryRequest): Test client authentication."}]. + +hello_retry_client_auth(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + ServerOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}, + {supported_groups, [x448, x25519]}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {supported_groups, [secp256r1, x25519]}|ClientOpts0], + ServerOpts = [{verify, verify_peer}, + {fail_if_no_peer_cert, true} | ServerOpts1], + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_accepted() -> + [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty " + "certificate and fail_if_no_peer_cert is set to true."}]. + +hello_retry_client_auth_empty_cert_accepted(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + %% Delete Client Cert and Key + ClientOpts1 = proplists:delete(certfile, ClientOpts0), + ClientOpts2 = proplists:delete(keyfile, ClientOpts1), + + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + %% Set versions + ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}, + {supported_groups, [x448, x25519]}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {supported_groups, [secp256r1, x25519]}|ClientOpts2], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_rejected() -> + [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client " + "sends an empty certificate and fail_if_no_peer_cert is set to true."}]. + +hello_retry_client_auth_empty_cert_rejected(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + %% Delete Client Cert and Key + ClientOpts1 = proplists:delete(certfile, ClientOpts0), + ClientOpts2 = proplists:delete(keyfile, ClientOpts1), + + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + %% Set versions + ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {verify, verify_peer}, + {fail_if_no_peer_cert, true}, + {supported_groups, [x448, x25519]}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {supported_groups, [secp256r1, x25519]}|ClientOpts2], + + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required). diff --git a/lib/ssl/test/ssl_cert_tests.erl b/lib/ssl/test/ssl_cert_tests.erl new file mode 100644 index 0000000000..f330c716bc --- /dev/null +++ b/lib/ssl/test/ssl_cert_tests.erl @@ -0,0 +1,350 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_cert_tests). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +no_auth() -> + [{doc,"Test connection without authentication"}]. + +no_auth(Config) -> + ClientOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +auth() -> + [{doc,"Test connection with mutual authentication"}]. + +auth(Config) -> + ClientOpts = [{verify, verify_peer} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{verify, verify_peer} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +client_auth_empty_cert_accepted() -> + [{doc,"Test client authentication when client sends an empty certificate and " + "fail_if_no_peer_cert is set to false."}]. + +client_auth_empty_cert_accepted(Config) -> + ClientOpts = proplists:delete(keyfile, + proplists:delete(certfile, + ssl_test_lib:ssl_options(client_cert_opts, Config))), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + ServerOpts = [{verify, verify_peer}, + {fail_if_no_peer_cert, false} | ServerOpts0], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +client_auth_empty_cert_rejected() -> + [{doc,"Test client authentication when client sends an empty certificate and " + "fail_if_no_peer_cert is set to true."}]. + +client_auth_empty_cert_rejected(Config) -> + ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ClientOpts0 = ssl_test_lib:ssl_options([], Config), + %% Delete Client Cert and Key + ClientOpts1 = proplists:delete(certfile, ClientOpts0), + ClientOpts = proplists:delete(keyfile, ClientOpts1), + + Version = proplists:get_value(version,Config), + case Version of + 'tlsv1.3' -> + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required); + _ -> + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, handshake_failure) + end. +%%-------------------------------------------------------------------- +client_auth_partial_chain() -> + [{doc, "Client sends an incompleate chain, by default not acceptable."}]. + +client_auth_partial_chain(Config) when is_list(Config) -> + ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts0)), + [{_,RootCA,_} | _] = public_key:pem_decode(ClientCAs), + ClientOpts = [{cacerts, [RootCA]} | + proplists:delete(cacertfile, ClientOpts0)], + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca). + +%%-------------------------------------------------------------------- +client_auth_allow_partial_chain() -> + [{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}]. + +client_auth_allow_partial_chain(Config) when is_list(Config) -> + ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config), + {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)), + [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ClientCAs), + + PartialChain = fun(CertChain) -> + case lists:member(IntermidiateCA, CertChain) of + true -> + {trusted_ca, IntermidiateCA}; + false -> + unknown_ca + end + end, + ServerOpts = [{cacerts, [IntermidiateCA]}, + {partial_chain, PartialChain} | + proplists:delete(cacertfile, ServerOpts0)], + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + + %%-------------------------------------------------------------------- +client_auth_do_not_allow_partial_chain() -> + [{doc, "Server does not accept the chain sent by the client as ROOT CA is unkown, " + "and we do not choose to trust the intermediate CA. (partial_chain option)"}]. + +client_auth_do_not_allow_partial_chain(Config) when is_list(Config) -> + ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config), + {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts0)), + [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs), + + PartialChain = fun(_CertChain) -> + unknown_ca + end, + ServerOpts = [{cacerts, [IntermidiateCA]}, + {partial_chain, PartialChain} | + proplists:delete(cacertfile, ServerOpts0)], + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca). + + %%-------------------------------------------------------------------- +client_auth_partial_chain_fun_fail() -> + [{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}]. + +client_auth_partial_chain_fun_fail(Config) when is_list(Config) -> + ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true} + | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config), + + {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts0)), + [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs), + + PartialChain = fun(_CertChain) -> + true = false %% crash on purpose + end, + ServerOpts = [{cacerts, [IntermidiateCA]}, + {partial_chain, PartialChain} | + proplists:delete(cacertfile, ServerOpts0)], + + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca). + +%%-------------------------------------------------------------------- +missing_root_cert_no_auth() -> + [{doc,"Test that the client succeds if the ROOT CA is unknown in verify_none mode"}]. + +missing_root_cert_no_auth(Config) -> + ClientOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +invalid_signature_client() -> + [{doc,"Test server with invalid signature"}]. + +invalid_signature_client(Config) when is_list(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + PrivDir = proplists:get_value(priv_dir, Config), + + KeyFile = proplists:get_value(keyfile, ClientOpts0), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + ClientCertFile = proplists:get_value(certfile, ClientOpts0), + NewClientCertFile = filename:join(PrivDir, "client_invalid_cert.pem"), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), + ClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts0)], + ServerOpts = [{verify, verify_peer} | ServerOpts0], + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca). + +%%-------------------------------------------------------------------- +invalid_signature_server() -> + [{doc,"Test client with invalid signature"}]. + +invalid_signature_server(Config) when is_list(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + PrivDir = proplists:get_value(priv_dir, Config), + + KeyFile = proplists:get_value(keyfile, ServerOpts0), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + ServerCertFile = proplists:get_value(certfile, ServerOpts0), + NewServerCertFile = filename:join(PrivDir, "server_invalid_cert.pem"), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), + ServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts0)], + ClientOpts = [{verify, verify_peer} | ClientOpts0], + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca). + +%%-------------------------------------------------------------------- +%% TLS 1.3 Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +hello_retry_request() -> + [{doc,"Test that ssl server can request a new group when the client's first key share" + "is not supported"}]. + +hello_retry_request(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + {ServerOpts, ClientOpts} = group_config(Config, + [{versions, ['tlsv1.2','tlsv1.3']} | ServerOpts0], + [{versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0]), + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +custom_groups() -> + [{doc,"Test that ssl server can select a common group for key-exchange"}]. + +custom_groups(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + {ServerOpts, ClientOpts} = group_config(Config, + [{versions, ['tlsv1.2','tlsv1.3']} | ServerOpts0], + [{versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0]), + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +%% Triggers a Server Alert as ssl client does not have a certificate with a +%% signature algorithm supported by the server (signature_algorithms_cert extension +%% of CertificateRequest does not contain the algorithm of the client certificate). +%% ssl client sends an empty certificate. +unsupported_sign_algo_cert_client_auth() -> + [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}]. + +unsupported_sign_algo_cert_client_auth(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {verify, verify_peer}, + %% Skip rsa_pkcs1_sha256! + {signature_algs, [rsa_pkcs1_sha384, rsa_pss_rsae_sha256]}, + {fail_if_no_peer_cert, true}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0], + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, handshake_failure). +%%-------------------------------------------------------------------- +hello_retry_client_auth() -> + [{doc, "TLS 1.3 (HelloRetryRequest): Test client authentication."}]. + +hello_retry_client_auth(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + {ServerOpts, ClientOpts} = group_config(Config, + [{versions, ['tlsv1.2','tlsv1.3']}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false} | ServerOpts0], + [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]), + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_accepted() -> + [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty " + "certificate and fail_if_no_peer_cert is set to true."}]. + +hello_retry_client_auth_empty_cert_accepted(Config) -> + ClientOpts0 = proplists:delete(keyfile, + proplists:delete(certfile, + ssl_test_lib:ssl_options(client_cert_opts, Config))), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + {ServerOpts, ClientOpts} = group_config(Config, + [{versions, ['tlsv1.2','tlsv1.3']}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false} | ServerOpts0], + [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]), + + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +hello_retry_client_auth_empty_cert_rejected() -> + [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client " + "sends an empty certificate and fail_if_no_peer_cert is set to true."}]. + +hello_retry_client_auth_empty_cert_rejected(Config) -> + ClientOpts0 = proplists:delete(keyfile, + proplists:delete(certfile, + ssl_test_lib:ssl_options(client_cert_opts, Config))), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + {ServerOpts, ClientOpts} = group_config(Config, + [{versions, ['tlsv1.2','tlsv1.3']}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false} | ServerOpts0], + [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]), + + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required). + + +%%-------------------------------------------------------------------- +%% Internal functions ----------------------------------------------- +%%-------------------------------------------------------------------- + +group_config(Config, ServerOpts, ClientOpts) -> + case proplists:get_value(client_type, Config) of + erlang -> + {[{groups,"P-256:X25519"} | ServerOpts], + [{supported_groups, [secp256r1, x25519]} | ClientOpts]}; + openssl -> + {[{supported_groups, [x448, x25519]} | ServerOpts], + [{groups,"P-256:X25519"} | ClientOpts]} + end. + +test_ciphers(Kex, Version) -> + Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, Version), + [{key_exchange, Kex}]), + ct:log("Version ~p Testing ~p~n", [Version, Ciphers]), + OpenSSLCiphers = openssl_ciphers(), + ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]), + lists:filter(fun(C) -> + ct:log("Cipher ~p~n", [C]), + lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers) + end, Ciphers). + +openssl_ciphers() -> + Str = os:cmd("openssl ciphers"), + string:split(string:strip(Str, right, $\n), ":", all). diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 4de4a35e59..f38858e0bf 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -71,37 +71,20 @@ all_protocol_groups() -> {group, error_handling}]. tests() -> - [verify_peer, - verify_none, - server_require_peer_cert_ok, - server_require_peer_cert_fail, - server_require_peer_cert_empty_ok, - server_require_peer_cert_partial_chain, - server_require_peer_cert_allow_partial_chain, - server_require_peer_cert_do_not_allow_partial_chain, - server_require_peer_cert_partial_chain_fun_fail, - verify_fun_always_run_client, - verify_fun_always_run_server, - cert_expired, - invalid_signature_client, - invalid_signature_server, + [cert_expired, + %invalid_signature_client, + %%invalid_signature_server, extended_key_usage_verify_both, extended_key_usage_verify_server, critical_extension_verify_client, critical_extension_verify_server, critical_extension_verify_none, - customize_hostname_check, - incomplete_chain, long_chain ]. error_handling_tests()-> [client_with_cert_cipher_suites_handshake, - server_verify_no_cacerts, - unknown_server_ca_fail, - unknown_server_ca_accept_verify_none, - unknown_server_ca_accept_verify_peer, - unknown_server_ca_accept_backwardscompatibility, + %%unknown_server_ca_accept_backwardscompatibility, no_authority_key_identifier, no_authority_key_identifier_keyEncipherment]. @@ -160,61 +143,6 @@ end_per_testcase(_TestCase, Config) -> %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- - -verify_peer() -> - [{doc,"Test option verify_peer"}]. -verify_peer(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - Active = proplists:get_value(active, Config), - ReceiveFunction = proplists:get_value(receive_function, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active}, {verify, verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active}, {verify, verify_peer} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -verify_none() -> - [{doc,"Test option verify_none"}]. - -verify_none(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - Active = proplists:get_value(active, Config), - ReceiveFunction = proplists:get_value(receive_function, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active}, {verify, verify_none} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active}, - {verify, verify_none} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - server_verify_client_once() -> [{doc,"Test server option verify_client_once"}]. @@ -253,309 +181,6 @@ server_verify_client_once(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -server_require_peer_cert_ok() -> - [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}]. - -server_require_peer_cert_ok(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ssl_test_lib:ssl_options(server_rsa_opts, Config)], - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - Active = proplists:get_value(active, Config), - ReceiveFunction = proplists:get_value(receive_function, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -server_require_peer_cert_fail() -> - [{doc,"Test server option fail_if_no_peer_cert when peer doesn't send cert"}]. - -server_require_peer_cert_fail(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ssl_test_lib:ssl_options(server_rsa_opts, Config)], - BadClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config), - Active = proplists:get_value(active, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, [{active, Active} | ServerOpts]}]), - - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, [{active, Active} | BadClientOpts]}]), - - Version = proplists:get_value(version,Config), - case Version of - 'tlsv1.3' -> - ssl_test_lib:check_server_alert(Server, Client, certificate_required); - _ -> - ssl_test_lib:check_server_alert(Server, Client, handshake_failure) - end. - -%%-------------------------------------------------------------------- -server_require_peer_cert_empty_ok() -> - [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}]. - -server_require_peer_cert_empty_ok(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, false} - | ssl_test_lib:ssl_options(server_rsa_opts, Config)], - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), - Active = proplists:get_value(active, Config), - ReceiveFunction = proplists:get_value(receive_function, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - ClientOpts = proplists:delete(keyfile, proplists:delete(certfile, ClientOpts0)), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -server_require_peer_cert_partial_chain() -> - [{doc, "Client sends an incompleate chain, by default not acceptable."}]. - -server_require_peer_cert_partial_chain(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ssl_test_lib:ssl_options(server_rsa_opts, Config)], - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - Active = proplists:get_value(active, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)), - [{_,RootCA,_} | _] = public_key:pem_decode(ClientCAs), - - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{active, Active} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{active, Active}, - {cacerts, [RootCA]} | - proplists:delete(cacertfile, ClientOpts)]}]), - ssl_test_lib:check_server_alert(Server, Client, unknown_ca). - -%%-------------------------------------------------------------------- -server_require_peer_cert_allow_partial_chain() -> - [{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}]. - -server_require_peer_cert_allow_partial_chain(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ssl_test_lib:ssl_options(server_rsa_opts, Config)], - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Active = proplists:get_value(active, Config), - ReceiveFunction = proplists:get_value(receive_function, Config), - - {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)), - [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ClientCAs), - - PartialChain = fun(CertChain) -> - case lists:member(IntermidiateCA, CertChain) of - true -> - {trusted_ca, IntermidiateCA}; - false -> - unknown_ca - end - end, - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active}, - {cacerts, [IntermidiateCA]}, - {partial_chain, PartialChain} | - proplists:delete(cacertfile, ServerOpts)]}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, ReceiveFunction, []}}, - {options, [{active, Active} | ClientOpts]}]), - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - - %%-------------------------------------------------------------------- -server_require_peer_cert_do_not_allow_partial_chain() -> - [{doc, "Server does not accept the chain sent by the client as ROOT CA is unkown, " - "and we do not choose to trust the intermediate CA. (partial_chain option)"}]. - -server_require_peer_cert_do_not_allow_partial_chain(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ssl_test_lib:ssl_options(server_rsa_opts, Config)], - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)), - [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs), - - PartialChain = fun(_CertChain) -> - unknown_ca - end, - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{cacerts, [IntermidiateCA]}, - {partial_chain, PartialChain} | - proplists:delete(cacertfile, ServerOpts)]}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ClientOpts}]), - ssl_test_lib:check_server_alert(Server, Client, unknown_ca). - %%-------------------------------------------------------------------- -server_require_peer_cert_partial_chain_fun_fail() -> - [{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}]. - -server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) -> - ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true} - | ssl_test_lib:ssl_options(server_rsa_opts, Config)], - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)), - [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs), - - PartialChain = fun(_CertChain) -> - true = false %% crash on purpose - end, - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{cacerts, [IntermidiateCA]}, - {partial_chain, PartialChain} | - proplists:delete(cacertfile, ServerOpts)]}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ClientOpts}]), - ssl_test_lib:check_server_alert(Server, Client, unknown_ca). - -%%-------------------------------------------------------------------- -verify_fun_always_run_client() -> - [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}]. - -verify_fun_always_run_client(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - %% If user verify fun is called correctly we fail the connection. - %% otherwise we cannot tell this case apart form where we miss - %% to call users verify fun - FunAndState = {fun(_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, [ChainLen]) -> - {valid, [ChainLen + 1]}; - (_, valid_peer, [1]) -> - {fail, "verify_fun_was_always_run"}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, [0]}, - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState} - | ClientOpts]}]), - - ssl_test_lib:check_client_alert(Server, Client, handshake_failure). - -%%-------------------------------------------------------------------- -verify_fun_always_run_server() -> - [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}]. -verify_fun_always_run_server(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - %% If user verify fun is called correctly we fail the connection. - %% otherwise we cannot tell this case apart form where we miss - %% to call users verify fun - FunAndState = {fun(_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, [ChainLen]) -> - {valid, [ChainLen + 1]}; - (_, valid_peer, [1]) -> - {fail, "verify_fun_was_always_run"}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, [0]}, - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState} | - ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, ClientOpts}]), - - ssl_test_lib:check_client_alert(Server, Client, handshake_failure). -%%-------------------------------------------------------------------- - cert_expired() -> [{doc,"Test server with expired certificate"}]. @@ -937,235 +562,6 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -server_verify_no_cacerts() -> - [{doc,"Test server must have cacerts if it wants to verify client"}]. -server_verify_no_cacerts(Config) when is_list(Config) -> - ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_rsa_opts, Config)), - {_, ServerNode, _} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, [{verify, verify_peer} - | ServerOpts]}]), - - ssl_test_lib:check_result(Server, {error, {options, {cacertfile, ""}}}). - - -%%-------------------------------------------------------------------- -unknown_server_ca_fail() -> - [{doc,"Test that the client fails if the ca is unknown in verify_peer mode"}]. -unknown_server_ca_fail(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) -> - {fail, Reason}; - (_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, UserState) -> - {valid, [test_to_update_user_state | UserState]}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, []}, - - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - no_result, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState} - | ClientOpts]}]), - ssl_test_lib:check_client_alert(Server, Client, unknown_ca). - -%%-------------------------------------------------------------------- -unknown_server_ca_accept_verify_none() -> - [{doc,"Test that the client succeds if the ca is unknown in verify_none mode"}]. -unknown_server_ca_accept_verify_none(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - send_recv_result_active, []}}, - {options, - [{verify, verify_none}| ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -unknown_server_ca_accept_verify_peer() -> - [{doc, "Test that the client succeds if the ca is unknown in verify_peer mode" - " with a verify_fun that accepts the unknown ca error"}]. -unknown_server_ca_accept_verify_peer(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) -> - {valid, UserState}; - (_,{bad_cert, _} = Reason, _) -> - {fail, Reason}; - (_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, UserState) -> - {valid, UserState}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, []}, - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - send_recv_result_active, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, FunAndState}| ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -unknown_server_ca_accept_backwardscompatibility() -> - [{doc,"Test that old style verify_funs will work"}]. -unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc; - (Other, Acc) -> [Other | Acc] - end, - VerifyFun = - fun(ErrorList) -> - case lists:foldl(AcceptBadCa, [], ErrorList) of - [] -> true; - [_|_] -> false - end - end, - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - send_recv_result_active, []}}, - {options, - [{verify, verify_peer}, - {verify_fun, VerifyFun}| ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- - -customize_hostname_check() -> - [{doc,"Test option customize_hostname_check."}]. -customize_hostname_check(Config) when is_list(Config) -> - Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName', - extnValue = [{dNSName, "*.example.org"}], - critical = false} - ], - {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_chain, - [[], - [], - [{extensions, Ext}] - ]}], - Config, "https_hostname_convention"), - ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config), - ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - CustomFun = public_key:pkix_verify_hostname_match_fun(https), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, send_recv_result_active, []}}, - {options, - [{server_name_indication, "other.example.org"}, - {customize_hostname_check, - [{match_fun, CustomFun}]} | ClientOpts] - }]), - ssl_test_lib:check_result(Server, ok, Client, ok), - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - - Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ClientOpts} - ]), - ssl_test_lib:check_client_alert(Server, Client1, handshake_failure). - -incomplete_chain() -> - [{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). long_chain() -> [{doc,"Test option verify_peer"}]. diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl index 51788c29e7..e598d662e9 100644 --- a/lib/ssl/test/ssl_cipher_suite_SUITE.erl +++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl @@ -45,7 +45,7 @@ groups() -> {'tlsv1.2', [], kex()}, {'tlsv1.1', [], kex()}, {'tlsv1', [], kex()}, - {'sslv3', [], kex()}, + {'sslv3', [], ssl3_kex()}, {'dtlsv1.2', [], kex()}, {'dtlsv1', [], kex()}, {dhe_rsa, [],[dhe_rsa_3des_ede_cbc, @@ -130,6 +130,11 @@ groups() -> kex() -> rsa() ++ ecdsa() ++ dss() ++ anonymous(). + +ssl3_kex() -> + ssl3_rsa() ++ ssl3_dss() ++ ssl3_anonymous(). + + rsa() -> [{group, dhe_rsa}, {group, ecdhe_rsa}, @@ -138,6 +143,11 @@ rsa() -> {group, rsa_psk} ]. +ssl3_rsa() -> + [{group, dhe_rsa}, + {group, rsa} + ]. + ecdsa() -> [{group, ecdhe_ecdsa}]. @@ -145,6 +155,10 @@ dss() -> [{group, dhe_dss}, {group, srp_dss}]. +ssl3_dss() -> + [{group, dhe_dss} + ]. + anonymous() -> [{group, dh_anon}, {group, ecdh_anon}, @@ -154,6 +168,10 @@ anonymous() -> {group, srp_anon} ]. +ssl3_anonymous() -> + [{group, dh_anon}]. + + init_per_suite(Config) -> catch crypto:stop(), try crypto:start() of diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl index 1b432970b6..1e6adf3e86 100644 --- a/lib/ssl/test/ssl_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_handshake_SUITE.erl @@ -141,7 +141,7 @@ encode_single_hello_sni_extension_correctly(_Config) -> $t, $e, $s, $t, $., $c, $o, $m>>, ExtSize = byte_size(SNI), HelloExt = <>, - Encoded = ssl_handshake:encode_extensions([#sni{hostname = "test.com"}]), + Encoded = ssl_handshake:encode_extensions([#sni{hostname = "test.com"}], {3,3}), HelloExt = Encoded. decode_single_hello_sni_extension_correctly(_Config) -> diff --git a/lib/ssl/test/ssl_npn_SUITE.erl b/lib/ssl/test/ssl_npn_SUITE.erl new file mode 100644 index 0000000000..8a76a3a82b --- /dev/null +++ b/lib/ssl/test/ssl_npn_SUITE.erl @@ -0,0 +1,333 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_npn_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). + +-define(SLEEP, 500). +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}]. + +groups() -> + [ + {'tlsv1.2', [], next_protocol_tests()}, + {'tlsv1.1', [], next_protocol_tests()}, + {'tlsv1', [], next_protocol_tests()}, + {'sslv3', [], next_protocol_not_supported()} + ]. + +next_protocol_tests() -> + [validate_empty_protocols_are_not_allowed, + validate_empty_advertisement_list_is_allowed, + validate_advertisement_must_be_a_binary_list, + validate_client_protocols_must_be_a_tuple, + normal_npn_handshake_server_preference, + normal_npn_handshake_client_preference, + fallback_npn_handshake, + fallback_npn_handshake_server_preference, + client_negotiate_server_does_not_support, + no_client_negotiate_but_server_supports_npn, + renegotiate_from_client_after_npn_handshake, + npn_handshake_session_reused + ]. + +next_protocol_not_supported() -> + [npn_not_supported_client, + npn_not_supported_server + ]. + +init_per_suite(Config0) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config = ssl_test_lib:make_rsa_cert(Config0), + ssl_test_lib:cert_options(Config) + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + false -> + {skip, "Missing crypto support"} + end; + _ -> + ssl:start(), + Config + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(_TestCase, Config) -> + ssl_test_lib:ct_log_supported_protocol_versions(Config), + ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]), + ct:timetrap({seconds, 10}), + Config. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +validate_empty_protocols_are_not_allowed(Config) when is_list(Config) -> + {error, {options, {next_protocols_advertised, {invalid_protocol, <<>>}}}} + = (catch ssl:listen(9443, + [{next_protocols_advertised, [<<"foo/1">>, <<"">>]}])), + {error, {options, {client_preferred_next_protocols, {invalid_protocol, <<>>}}}} + = (catch ssl:connect({127,0,0,1}, 9443, + [{client_preferred_next_protocols, + {client, [<<"foo/1">>, <<"">>], <<"foox/1">>}}], infinity)), + Option = {client_preferred_next_protocols, {invalid_protocol, <<"">>}}, + {error, {options, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option], infinity)). + +%-------------------------------------------------------------------------------- + +validate_empty_advertisement_list_is_allowed(Config) when is_list(Config) -> + Option = {next_protocols_advertised, []}, + {ok, Socket} = ssl:listen(0, [Option]), + ssl:close(Socket). +%-------------------------------------------------------------------------------- + +validate_advertisement_must_be_a_binary_list(Config) when is_list(Config) -> + Option = {next_protocols_advertised, blah}, + {error, {options, Option}} = (catch ssl:listen(9443, [Option])). +%-------------------------------------------------------------------------------- + +validate_client_protocols_must_be_a_tuple(Config) when is_list(Config) -> + Option = {client_preferred_next_protocols, [<<"foo/1">>]}, + {error, {options, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option])). + +%-------------------------------------------------------------------------------- + +normal_npn_handshake_server_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, + {server, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). +%-------------------------------------------------------------------------------- + +normal_npn_handshake_client_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, + {client, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.0">>}). + +%-------------------------------------------------------------------------------- + +fallback_npn_handshake(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). +%-------------------------------------------------------------------------------- + +fallback_npn_handshake_server_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {server, [<<"spdy/2">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). + +%-------------------------------------------------------------------------------- + +no_client_negotiate_but_server_supports_npn(Config) when is_list(Config) -> + run_npn_handshake(Config, + [], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {error, protocol_not_negotiated}). +%-------------------------------------------------------------------------------- + + +client_negotiate_server_does_not_support(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], + [], + {error, protocol_not_negotiated}). + +%-------------------------------------------------------------------------------- +renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) -> + Data = "hello world", + + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts = [{client_preferred_next_protocols, + {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = [{next_protocols_advertised, + [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, + ExpectedProtocol = {ok, <<"http/1.0">>}, + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, ssl_receive_and_assert_npn, [ExpectedProtocol, Data]}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, assert_npn_and_renegotiate_and_send_data, [ExpectedProtocol, Data]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + +%-------------------------------------------------------------------------------- +npn_not_supported_client(Config) when is_list(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + PrefProtocols = {client_preferred_next_protocols, + {client, [<<"http/1.0">>], <<"http/1.1">>}}, + ClientOpts = [PrefProtocols] ++ ClientOpts0, + {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, + {port, 8888}, {host, Hostname}, + {from, self()}, {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, {error, + {options, + {not_supported_in_sslv3, PrefProtocols}}}). + +%-------------------------------------------------------------------------------- +npn_not_supported_server(Config) when is_list(Config)-> + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, + ServerOpts = [AdvProtocols] ++ ServerOpts0, + + {error, {options, {not_supported_in_sslv3, AdvProtocols}}} = ssl:listen(0, ServerOpts). + +%-------------------------------------------------------------------------------- +npn_handshake_session_reused(Config) when is_list(Config)-> + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts = [{client_preferred_next_protocols, + {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts =[{next_protocols_advertised, + [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, + + ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> + Data = "hello world", + + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts = ClientExtraOpts ++ ClientOpts0, + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = ServerExtraOpts ++ ServerOpts0, + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, ssl_receive_and_assert_npn, [ExpectedProtocol, Data]}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, ssl_send_and_assert_npn, [ExpectedProtocol, Data]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + + +assert_npn(Socket, Protocol) -> + ct:log("Negotiated Protocol ~p, Expecting: ~p ~n", + [ssl:negotiated_protocol(Socket), Protocol]), + Protocol = ssl:negotiated_protocol(Socket). + +assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) -> + assert_npn(Socket, Protocol), + ct:log("Renegotiating ~n", []), + ok = ssl:renegotiate(Socket), + ssl:send(Socket, Data), + assert_npn(Socket, Protocol), + ok. + +ssl_send_and_assert_npn(Socket, Protocol, Data) -> + assert_npn(Socket, Protocol), + ssl_send(Socket, Data). + +ssl_receive_and_assert_npn(Socket, Protocol, Data) -> + assert_npn(Socket, Protocol), + ssl_receive(Socket, Data). + +ssl_send(Socket, Data) -> + ct:log("Connection info: ~p~n", + [ssl:connection_information(Socket)]), + ssl:send(Socket, Data). + +ssl_receive(Socket, Data) -> + ssl_receive(Socket, Data, []). + +ssl_receive(Socket, Data, Buffer) -> + ct:log("Connection info: ~p~n", + [ssl:connection_information(Socket)]), + receive + {ssl, Socket, MoreData} -> + ct:log("Received ~p~n",[MoreData]), + NewBuffer = Buffer ++ MoreData, + case NewBuffer of + Data -> + ssl:send(Socket, "Got it"), + ok; + _ -> + ssl_receive(Socket, Data, NewBuffer) + end; + Other -> + ct:fail({unexpected_message, Other}) + after 4000 -> + ct:fail({did_not_get, Data}) + end. + + +connection_info_result(Socket) -> + ssl:connection_information(Socket). diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl deleted file mode 100644 index 878e983bb9..0000000000 --- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl +++ /dev/null @@ -1,333 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2018. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% --module(ssl_npn_handshake_SUITE). - -%% Note: This directive should only be used in test suites. --compile(export_all). --include_lib("common_test/include/ct.hrl"). - --define(SLEEP, 500). -%%-------------------------------------------------------------------- -%% Common Test interface functions ----------------------------------- -%%-------------------------------------------------------------------- - -all() -> - [{group, 'tlsv1.2'}, - {group, 'tlsv1.1'}, - {group, 'tlsv1'}, - {group, 'sslv3'}]. - -groups() -> - [ - {'tlsv1.2', [], next_protocol_tests()}, - {'tlsv1.1', [], next_protocol_tests()}, - {'tlsv1', [], next_protocol_tests()}, - {'sslv3', [], next_protocol_not_supported()} - ]. - -next_protocol_tests() -> - [validate_empty_protocols_are_not_allowed, - validate_empty_advertisement_list_is_allowed, - validate_advertisement_must_be_a_binary_list, - validate_client_protocols_must_be_a_tuple, - normal_npn_handshake_server_preference, - normal_npn_handshake_client_preference, - fallback_npn_handshake, - fallback_npn_handshake_server_preference, - client_negotiate_server_does_not_support, - no_client_negotiate_but_server_supports_npn, - renegotiate_from_client_after_npn_handshake, - npn_handshake_session_reused - ]. - -next_protocol_not_supported() -> - [npn_not_supported_client, - npn_not_supported_server - ]. - -init_per_suite(Config0) -> - catch crypto:stop(), - try crypto:start() of - ok -> - ssl_test_lib:clean_start(), - Config = ssl_test_lib:make_rsa_cert(Config0), - ssl_test_lib:cert_options(Config) - catch _:_ -> - {skip, "Crypto did not start"} - end. - -end_per_suite(_Config) -> - ssl:stop(), - application:stop(crypto). - - -init_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - case ssl_test_lib:sufficient_crypto_support(GroupName) of - true -> - ssl_test_lib:init_tls_version(GroupName, Config); - false -> - {skip, "Missing crypto support"} - end; - _ -> - ssl:start(), - Config - end. - -end_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - ssl_test_lib:clean_tls_version(Config); - false -> - Config - end. - -init_per_testcase(_TestCase, Config) -> - ssl_test_lib:ct_log_supported_protocol_versions(Config), - ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]), - ct:timetrap({seconds, 10}), - Config. - -end_per_testcase(_TestCase, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Test Cases -------------------------------------------------------- -%%-------------------------------------------------------------------- - -validate_empty_protocols_are_not_allowed(Config) when is_list(Config) -> - {error, {options, {next_protocols_advertised, {invalid_protocol, <<>>}}}} - = (catch ssl:listen(9443, - [{next_protocols_advertised, [<<"foo/1">>, <<"">>]}])), - {error, {options, {client_preferred_next_protocols, {invalid_protocol, <<>>}}}} - = (catch ssl:connect({127,0,0,1}, 9443, - [{client_preferred_next_protocols, - {client, [<<"foo/1">>, <<"">>], <<"foox/1">>}}], infinity)), - Option = {client_preferred_next_protocols, {invalid_protocol, <<"">>}}, - {error, {options, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option], infinity)). - -%-------------------------------------------------------------------------------- - -validate_empty_advertisement_list_is_allowed(Config) when is_list(Config) -> - Option = {next_protocols_advertised, []}, - {ok, Socket} = ssl:listen(0, [Option]), - ssl:close(Socket). -%-------------------------------------------------------------------------------- - -validate_advertisement_must_be_a_binary_list(Config) when is_list(Config) -> - Option = {next_protocols_advertised, blah}, - {error, {options, Option}} = (catch ssl:listen(9443, [Option])). -%-------------------------------------------------------------------------------- - -validate_client_protocols_must_be_a_tuple(Config) when is_list(Config) -> - Option = {client_preferred_next_protocols, [<<"foo/1">>]}, - {error, {options, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option])). - -%-------------------------------------------------------------------------------- - -normal_npn_handshake_server_preference(Config) when is_list(Config) -> - run_npn_handshake(Config, - [{client_preferred_next_protocols, - {server, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). -%-------------------------------------------------------------------------------- - -normal_npn_handshake_client_preference(Config) when is_list(Config) -> - run_npn_handshake(Config, - [{client_preferred_next_protocols, - {client, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.0">>}). - -%-------------------------------------------------------------------------------- - -fallback_npn_handshake(Config) when is_list(Config) -> - run_npn_handshake(Config, - [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). -%-------------------------------------------------------------------------------- - -fallback_npn_handshake_server_preference(Config) when is_list(Config) -> - run_npn_handshake(Config, - [{client_preferred_next_protocols, {server, [<<"spdy/2">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). - -%-------------------------------------------------------------------------------- - -no_client_negotiate_but_server_supports_npn(Config) when is_list(Config) -> - run_npn_handshake(Config, - [], - [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], - {error, protocol_not_negotiated}). -%-------------------------------------------------------------------------------- - - -client_negotiate_server_does_not_support(Config) when is_list(Config) -> - run_npn_handshake(Config, - [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], - [], - {error, protocol_not_negotiated}). - -%-------------------------------------------------------------------------------- -renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) -> - Data = "hello world", - - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ClientOpts = [{client_preferred_next_protocols, - {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts = [{next_protocols_advertised, - [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, - ExpectedProtocol = {ok, <<"http/1.0">>}, - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, ssl_receive_and_assert_npn, [ExpectedProtocol, Data]}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, assert_npn_and_renegotiate_and_send_data, [ExpectedProtocol, Data]}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok). - -%-------------------------------------------------------------------------------- -npn_not_supported_client(Config) when is_list(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - PrefProtocols = {client_preferred_next_protocols, - {client, [<<"http/1.0">>], <<"http/1.1">>}}, - ClientOpts = [PrefProtocols] ++ ClientOpts0, - {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Client = ssl_test_lib:start_client_error([{node, ClientNode}, - {port, 8888}, {host, Hostname}, - {from, self()}, {options, ClientOpts}]), - - ssl_test_lib:check_result(Client, {error, - {options, - {not_supported_in_sslv3, PrefProtocols}}}). - -%-------------------------------------------------------------------------------- -npn_not_supported_server(Config) when is_list(Config)-> - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, - ServerOpts = [AdvProtocols] ++ ServerOpts0, - - {error, {options, {not_supported_in_sslv3, AdvProtocols}}} = ssl:listen(0, ServerOpts). - -%-------------------------------------------------------------------------------- -npn_handshake_session_reused(Config) when is_list(Config)-> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ClientOpts = [{client_preferred_next_protocols, - {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts =[{next_protocols_advertised, - [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, - - ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). - -%%-------------------------------------------------------------------- -%% Internal functions ------------------------------------------------ -%%-------------------------------------------------------------------- -run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> - Data = "hello world", - - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ClientOpts = ClientExtraOpts ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts = ServerExtraOpts ++ ServerOpts0, - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, ssl_receive_and_assert_npn, [ExpectedProtocol, Data]}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, ssl_send_and_assert_npn, [ExpectedProtocol, Data]}}, - {options, ClientOpts}]), - - ssl_test_lib:check_result(Server, ok, Client, ok). - - -assert_npn(Socket, Protocol) -> - ct:log("Negotiated Protocol ~p, Expecting: ~p ~n", - [ssl:negotiated_protocol(Socket), Protocol]), - Protocol = ssl:negotiated_protocol(Socket). - -assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) -> - assert_npn(Socket, Protocol), - ct:log("Renegotiating ~n", []), - ok = ssl:renegotiate(Socket), - ssl:send(Socket, Data), - assert_npn(Socket, Protocol), - ok. - -ssl_send_and_assert_npn(Socket, Protocol, Data) -> - assert_npn(Socket, Protocol), - ssl_send(Socket, Data). - -ssl_receive_and_assert_npn(Socket, Protocol, Data) -> - assert_npn(Socket, Protocol), - ssl_receive(Socket, Data). - -ssl_send(Socket, Data) -> - ct:log("Connection info: ~p~n", - [ssl:connection_information(Socket)]), - ssl:send(Socket, Data). - -ssl_receive(Socket, Data) -> - ssl_receive(Socket, Data, []). - -ssl_receive(Socket, Data, Buffer) -> - ct:log("Connection info: ~p~n", - [ssl:connection_information(Socket)]), - receive - {ssl, Socket, MoreData} -> - ct:log("Received ~p~n",[MoreData]), - NewBuffer = Buffer ++ MoreData, - case NewBuffer of - Data -> - ssl:send(Socket, "Got it"), - ok; - _ -> - ssl_receive(Socket, Data, NewBuffer) - end; - Other -> - ct:fail({unexpected_message, Other}) - after 4000 -> - ct:fail({did_not_get, Data}) - end. - - -connection_info_result(Socket) -> - ssl:connection_information(Socket). diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index 46734ba180..7dbc0c5134 100644 --- a/lib/ssl/test/ssl_npn_hello_SUITE.erl +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -24,10 +24,11 @@ %% Note: This directive should only be used in test suites. -compile(export_all). --include("ssl_cipher.hrl"). --include("ssl_internal.hrl"). --include("tls_handshake.hrl"). --include("tls_record.hrl"). + +-include_lib("ssl/src/tls_record.hrl"). +-include_lib("ssl/src/tls_handshake.hrl"). +-include_lib("ssl/src/ssl_cipher.hrl"). +-include_lib("ssl/src/ssl_internal.hrl"). -include_lib("common_test/include/ct.hrl"). %%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_renegotiate_SUITE.erl b/lib/ssl/test/ssl_renegotiate_SUITE.erl new file mode 100644 index 0000000000..ef3f9ebb52 --- /dev/null +++ b/lib/ssl/test/ssl_renegotiate_SUITE.erl @@ -0,0 +1,499 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssl_renegotiate_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +-define(SLEEP, 500). +-define(RENEGOTIATION_DISABLE_TIME, 12000). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'} + ]. + +groups() -> + [{'dtlsv1.2', [], renegotiate_tests()}, + {'dtlsv1', [], renegotiate_tests()}, + {'tlsv1.3', [], renegotiate_tests()}, + {'tlsv1.2', [], renegotiate_tests()}, + {'tlsv1.1', [], renegotiate_tests()}, + {'tlsv1', [], renegotiate_tests()}, + {'sslv3', [], ssl3_renegotiate_tests()} + ]. + +renegotiate_tests() -> + [client_renegotiate, + server_renegotiate, + client_secure_renegotiate, + client_secure_renegotiate_fallback, + client_renegotiate_reused_session, + server_renegotiate_reused_session, + client_no_wrap_sequence_number, + server_no_wrap_sequence_number, + renegotiate_dos_mitigate_active, + renegotiate_dos_mitigate_passive, + renegotiate_dos_mitigate_absolute]. + +ssl3_renegotiate_tests() -> + [client_renegotiate, + server_renegotiate, + client_renegotiate_reused_session, + server_renegotiate_reused_session, + client_no_wrap_sequence_number, + server_no_wrap_sequence_number, + renegotiate_dos_mitigate_active, + renegotiate_dos_mitigate_passive, + renegotiate_dos_mitigate_absolute]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + ssl_test_lib:make_rsa_cert(Config) + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +init_per_group(GroupName, Config) -> + ssl_test_lib:clean_tls_version(Config), + case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + _ -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl:start(), + Config; + false -> + {skip, "Missing crypto support"} + end + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +client_renegotiate() -> + [{doc,"Test ssl:renegotiate/1 on client."}]. +client_renegotiate(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate, [Data]}}, + {options, [{reuse_sessions, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +client_secure_renegotiate() -> + [{doc,"Test ssl:renegotiate/1 on client."}]. +client_secure_renegotiate(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, [{secure_renegotiate, true} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate, [Data]}}, + {options, [{reuse_sessions, false}, + {secure_renegotiate, true}| ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +client_secure_renegotiate_fallback() -> + [{doc,"Test that we can set secure_renegotiate to false that is " + "fallback option, we however do not have a insecure server to test against!"}]. +client_secure_renegotiate_fallback(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, [{secure_renegotiate, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate, [Data]}}, + {options, [{reuse_sessions, false}, + {secure_renegotiate, false}| ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +server_renegotiate() -> + [{doc,"Test ssl:renegotiate/1 on server."}]. +server_renegotiate(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + renegotiate, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, [{reuse_sessions, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +client_renegotiate_reused_session() -> + [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}]. +client_renegotiate_reused_session(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_reuse_session, [Data]}}, + {options, [{reuse_sessions, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +server_renegotiate_reused_session() -> + [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}]. +server_renegotiate_reused_session(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_reuse_session, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, [{reuse_sessions, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +client_no_wrap_sequence_number() -> + [{doc,"Test that erlang client will renegotiate session when", + "max sequence number celing is about to be reached. Although" + "in the testcase we use the test option renegotiate_at" + " to lower treashold substantially."}]. + +client_no_wrap_sequence_number(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + ErlData = "From erlang to erlang", + N = 12, + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Version = ssl_test_lib:protocol_version(Config, tuple), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + trigger_renegotiate, [[ErlData, treashold(N, Version)]]}}, + {options, [{reuse_sessions, false}, + {renegotiate_at, N} | ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +server_no_wrap_sequence_number() -> + [{doc, "Test that erlang server will renegotiate session when", + "max sequence number celing is about to be reached. Although" + "in the testcase we use the test option renegotiate_at" + " to lower treashold substantially."}]. + +server_no_wrap_sequence_number(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + N = 12, + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + trigger_renegotiate, [[Data, N+2]]}}, + {options, [{renegotiate_at, N} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{reuse_sessions, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +renegotiate_dos_mitigate_active() -> + [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", + "immediately after each other"}]. +renegotiate_dos_mitigate_active(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_immediately, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +renegotiate_dos_mitigate_passive() -> + [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", + "immediately after each other"}]. +renegotiate_dos_mitigate_passive(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_immediately, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +renegotiate_dos_mitigate_absolute() -> + [{doc, "Mitigate DOS computational attack by not allowing client to initiate renegotiation"}]. +renegotiate_dos_mitigate_absolute(Config) when is_list(Config) -> + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, [{client_renegotiation, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_rejected, + []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +renegotiate(Socket, Data) -> + ct:log("Renegotiating ~n", []), + Result = ssl:renegotiate(Socket), + ct:log("Result ~p~n", [Result]), + ssl:send(Socket, Data), + case Result of + ok -> + ok; + Other -> + Other + end. + +renegotiate_reuse_session(Socket, Data) -> + %% Make sure session is registered + ct:sleep(?SLEEP), + renegotiate(Socket, Data). + +renegotiate_immediately(Socket) -> + _ = ssl_test_lib:active_recv(Socket, 11), + ok = ssl:renegotiate(Socket), + {error, renegotiation_rejected} = ssl:renegotiate(Socket), + ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP), + ok = ssl:renegotiate(Socket), + ct:log("Renegotiated again"), + ssl:send(Socket, "Hello world"), + ok. + +renegotiate_rejected(Socket) -> + _ = ssl_test_lib:active_recv(Socket, 11), + {error, renegotiation_rejected} = ssl:renegotiate(Socket), + {error, renegotiation_rejected} = ssl:renegotiate(Socket), + ct:sleep(?RENEGOTIATION_DISABLE_TIME +1), + {error, renegotiation_rejected} = ssl:renegotiate(Socket), + ct:log("Failed to renegotiate again"), + ssl:send(Socket, "Hello world"), + ok. + +%% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast +treashold(N, {3,0}) -> + (N div 2) + 1; +treashold(N, {3,1}) -> + (N div 2) + 1; +treashold(N, _) -> + N + 1. + +erlang_ssl_receive(Socket, Data) -> + case ssl_test_lib:active_recv(Socket, length(Data)) of + Data -> + ok; + Other -> + ct:fail({{expected, Data}, {got, Other}}) + end. diff --git a/lib/ssl/test/ssl_session_SUITE.erl b/lib/ssl/test/ssl_session_SUITE.erl new file mode 100644 index 0000000000..159a4e208b --- /dev/null +++ b/lib/ssl/test/ssl_session_SUITE.erl @@ -0,0 +1,378 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssl_session_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("tls_handshake.hrl"). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +-define(SLEEP, 500). +-define(EXPIRE, 10). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}, + {group, 'dtlsv1.2'}, + {group, 'dtlsv1'} + ]. + +groups() -> + [{'dtlsv1.2', [], session_tests()}, + {'dtlsv1', [], session_tests()}, + {'tlsv1.3', [], session_tests()}, + {'tlsv1.2', [], session_tests()}, + {'tlsv1.1', [], session_tests()}, + {'tlsv1', [], session_tests()}, + {'sslv3', [], session_tests()} + ]. + +session_tests() -> + [reuse_session, + reuse_session_expired, + server_does_not_want_to_reuse_session, + no_reuses_session_server_restart_new_cert, + no_reuses_session_server_restart_new_cert_file]. + + +init_per_suite(Config0) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config = ssl_test_lib:make_rsa_cert(Config0), + ssl_test_lib:make_dsa_cert(Config) + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +init_per_group(GroupName, Config) -> + ssl_test_lib:clean_tls_version(Config), + case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + _ -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl:start(), + Config; + false -> + {skip, "Missing crypto support"} + end + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +init_per_testcase(reuse_session_expired, Config) -> + ssl:stop(), + application:load(ssl), + ssl_test_lib:clean_env(), + application:set_env(ssl, session_lifetime, ?EXPIRE), + application:set_env(ssl, session_delay_cleanup_time, 500), + ssl:start(), + ct:timetrap({seconds, 30}), + Config; +init_per_testcase(_, Config) -> + ct:timetrap({seconds, 15}), + Config. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +reuse_session() -> + [{doc,"Test reuse of sessions (short handshake)"}]. +reuse_session(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + + ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). +%%-------------------------------------------------------------------- +reuse_session_expired() -> + [{doc,"Test sessions is not reused when it has expired"}]. +reuse_session_expired(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server0 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {tcp_options, [{active, false}]}, + {options, ServerOpts}]), + Port0 = ssl_test_lib:inet_port(Server0), + + Client0 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]), + Server0 ! listen, + + Client1 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, ClientOpts}]), + + SID = receive + {Client0, Id0} -> + Id0 + end, + + receive + {Client1, SID} -> + ok + after ?SLEEP -> + ct:fail(session_not_reused) + end, + + Server0 ! listen, + + %% Make sure session is unregistered due to expiration + ct:sleep((?EXPIRE*2)), + + make_sure_expired(Hostname, Port0, SID), + + Client2 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client2, SID} -> + ct:fail(session_reused_when_session_expired); + {Client2, _} -> + ok + end, + process_flag(trap_exit, false), + ssl_test_lib:close(Server0), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1), + ssl_test_lib:close(Client2). + +make_sure_expired(Host, Port, Id) -> + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + ClientCache = element(2, State), + + case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of + undefined -> + ok; + #session{is_resumable = false} -> + ok; + _ -> + ct:sleep(?SLEEP), + make_sure_expired(Host, Port, Id) + end. + +%%-------------------------------------------------------------------- +server_does_not_want_to_reuse_session() -> + [{doc,"Test reuse of sessions (short handshake)"}]. +server_does_not_want_to_reuse_session(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {options, [{reuse_session, fun(_,_,_,_) -> + false + end} | + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client0 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + + %% Make sure session is registered + ct:sleep(?SLEEP), + ssl_test_lib:close(Client0), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client1, SessionInfo} -> + ct:fail(session_reused_when_server_does_not_want_to); + {Client1, _Other} -> + ok + end, + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client1). + +no_reuses_session_server_restart_new_cert() -> + [{doc,"Check that a session is not reused if the server is restarted with a new cert."}]. +no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> + + ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config), + DsaClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client0 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + %% Make sure session is registered + ct:sleep(?SLEEP), + Monitor = erlang:monitor(process, Server), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client0), + receive + {'DOWN', Monitor, _, _, _} -> + ok + end, + + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{reuseaddr, true} | DsaServerOpts]}]), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {from, self()}, {options, DsaClientOpts}]), + receive + {Client1, SessionInfo} -> + ct:fail(session_reused_when_server_has_new_cert); + {Client1, _Other} -> + ok + end, + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1). + +%%-------------------------------------------------------------------- +no_reuses_session_server_restart_new_cert_file() -> + [{doc,"Check that a session is not reused if a server is restarted with a new " + "cert contained in a file with the same name as the old cert."}]. + +no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config), + PrivDir = proplists:get_value(priv_dir, Config), + + NewServerOpts0 = ssl_test_lib:new_config(PrivDir, ServerOpts), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {options, NewServerOpts0}]), + Port = ssl_test_lib:inet_port(Server), + Client0 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + %% Make sure session is registered and we get + %% new file time stamp when calling new_config! + ct:sleep(?SLEEP* 2), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client0), + + ssl:clear_pem_cache(), + + NewServerOpts1 = ssl_test_lib:new_config(PrivDir, DsaServerOpts), + + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{reuseaddr, true} | NewServerOpts1]}]), + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {from, self()}, {options, ClientOpts}]), + receive + {Client1, SessionInfo} -> + ct:fail(session_reused_when_server_has_new_cert); + {Client1, _Other} -> + ok + end, + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl index 7629d75100..e68ea2c99d 100644 --- a/lib/ssl/test/ssl_sni_SUITE.erl +++ b/lib/ssl/test/ssl_sni_SUITE.erl @@ -36,7 +36,6 @@ all() -> [{group, 'tlsv1.2'}, {group, 'tlsv1.1'}, {group, 'tlsv1'}, - {group, 'sslv3'}, {group, 'dtlsv1.2'}, {group, 'dtlsv1'} ]. @@ -46,7 +45,6 @@ groups() -> {'tlsv1.2', [], sni_tests()}, {'tlsv1.1', [], sni_tests()}, {'tlsv1', [], sni_tests()}, - {'sslv3', [], sni_tests()}, {'dtlsv1.2', [], sni_tests()}, {'dtlsv1', [], sni_tests()} ]. @@ -61,7 +59,8 @@ sni_tests() -> dns_name, ip_fallback, no_ip_fallback, - dns_name_reuse]. + dns_name_reuse, + customize_hostname_check]. init_per_suite(Config0) -> catch crypto:stop(), @@ -88,12 +87,10 @@ end_per_suite(_) -> ssl:stop(), application:stop(crypto). -init_per_testcase(TestCase, Config) when TestCase == ip_fallback; - TestCase == no_ip_fallback; - TestCase == dns_name_reuse -> +init_per_testcase(customize_hostname_check, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), - ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]), - ct:timetrap({seconds, 20}), + ssl_test_lib:clean_start(), + ct:timetrap({seconds, 5}), Config; init_per_testcase(_TestCase, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), @@ -236,7 +233,60 @@ dns_name_reuse(Config) -> {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, [{verify, verify_peer} | ClientConf]}]), - ssl_test_lib:check_client_alert(Client1, handshake_failure). + ssl_test_lib:check_client_alert(Client1, handshake_failure), + ssl_test_lib:close(Client0). + + +customize_hostname_check() -> + [{doc,"Test option customize_hostname_check."}]. +customize_hostname_check(Config) when is_list(Config) -> + Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName', + extnValue = [{dNSName, "*.example.org"}], + critical = false} + ], + #{server_config := ServerOpts0, + client_config := ClientOpts0} = ssl_test_lib:make_cert_chains_pem(rsa, [{server_chain, + [[], + [], + [{extensions, Ext}] + ]}], + Config, "https_hostname_convention"), + ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config), + ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + CustomFun = public_key:pkix_verify_hostname_match_fun(https), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, + [{verify, verify_peer}, + {server_name_indication, "other.example.org"}, + {customize_hostname_check, + [{match_fun, CustomFun}]} | ClientOpts] + }]), + ssl_test_lib:check_result(Server, ok, Client, ok), + + Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + + Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, [{verify, verify_peer}, + {server_name_indication, "other.example.org"} | ClientOpts]} + ]), + ssl_test_lib:check_client_alert(Server, Client1, handshake_failure). %%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index c791f438d0..bf2c0e7edf 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -218,6 +218,55 @@ start_server_transport_control(Args) -> Result end. +start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts = ErlangClientOpts ++ ClientOpts0, + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = case OpensslServerOpts of + [] -> + ["s_server", "-accept", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile,"-key", KeyFile]; + [Opt, Value] -> + ["s_server", Opt, Value, "-accept", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile,"-key", KeyFile] + end, + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + active_recv, [length(Data)]}}, + {options, ClientOpts}]), + + Callback(Client, OpensslPort), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + + ssl_test_lib:close(Client), + process_flag(trap_exit, false). + transport_accept_abuse(Opts) -> Port = proplists:get_value(port, Opts), @@ -233,6 +282,34 @@ transport_accept_abuse(Opts) -> _ = ssl:handshake(AcceptSocket, infinity), Pid ! {self(), ok}. +start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) -> + process_flag(trap_exit, true), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = ErlangServerOpts ++ ServerOpts0, + + {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, active_recv, [length(Data)]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_client"] ++ OpenSSLClientOpts ++ ["-msg", "-connect", + hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version)], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + Callback(Server, OpenSslPort), + + ssl_test_lib:close(Server), + + ssl_test_lib:close_port(OpenSslPort), + process_flag(trap_exit, false). transport_switch_control(Opts) -> Port = proplists:get_value(port, Opts), @@ -586,30 +663,6 @@ cert_options(Config) -> {ssl_imp, new}]}, {server_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ServerCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, - {client_psk, [{ssl_imp, new}, - {psk_identity, "Test-User"}, - {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}, - {server_psk, [{ssl_imp, new},{reuseaddr, true}, - {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, - {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}, - {server_psk_hint, [{ssl_imp, new},{reuseaddr, true}, - {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, - {psk_identity, "HINT"}, - {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}, - {server_psk_anon, [{ssl_imp, new},{reuseaddr, true}, - {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}, - {server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true}, - {psk_identity, "HINT"}, - {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}, - {client_srp, [{ssl_imp, new}, - {srp_identity, {"Test-User", "secret"}}]}, - {server_srp, [{ssl_imp, new},{reuseaddr, true}, - {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, - {user_lookup_fun, {fun user_lookup/3, undefined}}, - {ciphers, srp_suites()}]}, - {server_srp_anon, [{ssl_imp, new},{reuseaddr, true}, - {user_lookup_fun, {fun user_lookup/3, undefined}}, - {ciphers, srp_anon_suites()}]}, {server_verification_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ClientCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, @@ -659,6 +712,27 @@ make_dsa_cert(Config) -> false -> Config end. + + +make_cert_chains_der(Alg, UserConf) -> + ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()), + ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()), + CertChainConf = gen_conf(Alg, Alg, ClientChain, ServerChain), + public_key:pkix_test_data(CertChainConf). + +make_cert_chains_pem(Alg, UserConf, Config, Suffix) -> + ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()), + ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()), + CertChainConf = gen_conf(Alg, Alg, ClientChain, ServerChain), + ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(Alg) ++ Suffix]), + ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(Alg) ++ Suffix]), + GenCertData = public_key:pkix_test_data(CertChainConf), + Conf = x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase), + CConf = proplists:get_value(client_config, Conf), + SConf = proplists:get_value(server_config, Conf), + #{server_config => SConf, + client_config => CConf}. + make_rsa_cert_chains(UserConf, Config, Suffix) -> ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()), ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()), @@ -1156,6 +1230,24 @@ basic_test(COpts, SOpts, Config) -> gen_check_result(Server, SType, Client, CType), stop(Server, Client). +basic_alert(ClientOpts, ServerOpts, Config, Alert) -> + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ServerOpts}]), + + Port = inet_port(Server), + + Client = start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ClientOpts}]), + + check_server_alert(Server, Client, Alert). + 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), @@ -1202,11 +1294,27 @@ start_client(openssl, Port, ClientOpts, Config) -> CA = proplists:get_value(cacertfile, ClientOpts), Version = ssl_test_lib:protocol_version(Config), Exe = "openssl", + Groups0 = proplists:get_value(groups, ClientOpts), + Exe = "openssl", Args0 = ["s_client", "-verify", "2", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-cert", Cert, "-CAfile", CA, - "-key", Key, "-host","localhost", "-msg", "-debug"], - Args = maybe_force_ipv4(Args0), + "-CAfile", CA, "-host", "localhost", "-msg", "-debug"], + Args1 = + case Groups0 of + undefined -> + Args0; + G -> + Args0 ++ ["-groups", G] + end, + Args2 = + case {Cert, Key} of + {C, K} when C =:= undefined orelse + K =:= undefined -> + Args1; + {C, K} -> + Args1 ++ ["-cert", C, "-key", K] + end, + Args = maybe_force_ipv4(Args2), OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, "Hello world"), OpenSslPort; @@ -1268,12 +1376,13 @@ start_server(openssl, ClientOpts, ServerOpts, Config) -> start_server(erlang, _, ServerOpts, Config) -> {_, ServerNode, _} = ssl_test_lib:run_where(Config), KeyEx = proplists:get_value(check_keyex, Config, false), + Versions = protocol_versions(Config), Server = start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {ssl_test_lib, check_key_exchange_send_active, [KeyEx]}}, - {options, [{verify, verify_peer} | ServerOpts]}]), + {options, [{verify, verify_peer}, {versions, Versions} | ServerOpts]}]), {Server, inet_port(Server)}. start_server_with_raw_key(erlang, ServerOpts, Config) -> @@ -2011,6 +2120,53 @@ check_sane_openssl_version(Version) -> false -> false end. +check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1'; + Version == 'tlsv1.2' -> + case os:cmd("openssl version") of + "OpenSSL 1.0.1c" ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + "OpenSSL 1.0.1b" ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + "OpenSSL 1.0.1a" ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + "OpenSSL 1.0.1 " ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + _ -> + check_sane_openssl_renegotaite(Config) + end; +check_sane_openssl_renegotaite(Config, _) -> + check_sane_openssl_renegotaite(Config). + +check_sane_openssl_renegotaite(Config) -> + case os:cmd("openssl version") of + "OpenSSL 1.0.0" ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + "OpenSSL 0.9.8" ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + "OpenSSL 0.9.7" ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + _ -> + Config + end. + +workaround_openssl_s_clinent() -> + %% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159 + %% https://bugs.archlinux.org/task/33919 + %% Bug seems to manifests it self if TLS version is not + %% explicitly specified + case os:cmd("openssl version") of + "OpenSSL 1.0.1c" ++ _ -> + ["-no_tls1_2"]; + "OpenSSL 1.0.1d" ++ _ -> + ["-no_tls1_2"]; + "OpenSSL 1.0.1e" ++ _ -> + ["-no_tls1_2"]; + "OpenSSL 1.0.1f" ++ _ -> + ["-no_tls1_2"]; + _ -> + [] + end. + enough_openssl_crl_support("OpenSSL 0." ++ _) -> false; enough_openssl_crl_support(_) -> true. @@ -2178,6 +2334,14 @@ protocol_version(Config, atom) -> tls_record:protocol_version(protocol_version(Config, tuple)) end. +protocol_versions(Config) -> + Version = protocol_version(Config), + case Version of + 'tlsv1.3' -> %% TLS-1.3 servers shall also support 1.2 + ['tlsv1.3', 'tlsv1.2']; + _ -> + [Version] + end. protocol_options(Config, Options) -> Protocol = proplists:get_value(protocol, Config, tls), {Protocol, Opts} = lists:keyfind(Protocol, 1, Options), @@ -2504,3 +2668,48 @@ kill_openssl() -> {win32, _} -> os:cmd("cmd.exe /C \"taskkill /IM openssl.exe /F\"") end. + +hostname_format(Hostname) -> + case lists:member($., Hostname) of + true -> + Hostname; + false -> + "localhost" + end. + +erlang_ssl_receive_and_assert_negotiated_protocol(Socket, Protocol, Data) -> + case ssl:negotiated_protocol(Socket) of + {ok, Protocol} -> + active_recv(Socket, length(Data)); + Result -> + {error, {{expected, Protocol}, {got, Result}}} + end. + +check_openssl_npn_support(Config) -> + HelpText = os:cmd("openssl s_client --help"), + case string:str(HelpText, "nextprotoneg") of + 0 -> + {skip, "Openssl not compiled with nextprotoneg support"}; + _ -> + Config + end. + +new_config(PrivDir, ServerOpts0) -> + CaCertFile = proplists:get_value(cacertfile, ServerOpts0), + CertFile = proplists:get_value(certfile, ServerOpts0), + KeyFile = proplists:get_value(keyfile, ServerOpts0), + NewCaCertFile = filename:join(PrivDir, "new_ca.pem"), + NewCertFile = filename:join(PrivDir, "new_cert.pem"), + NewKeyFile = filename:join(PrivDir, "new_key.pem"), + file:copy(CaCertFile, NewCaCertFile), + file:copy(CertFile, NewCertFile), + file:copy(KeyFile, NewKeyFile), + ServerOpts1 = proplists:delete(cacertfile, ServerOpts0), + ServerOpts2 = proplists:delete(certfile, ServerOpts1), + ServerOpts = proplists:delete(keyfile, ServerOpts2), + + {ok, PEM} = file:read_file(NewCaCertFile), + ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]), + + [{cacertfile, NewCaCertFile}, {certfile, NewCertFile}, + {keyfile, NewKeyFile} | ServerOpts]. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl deleted file mode 100644 index 31d9af5298..0000000000 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ /dev/null @@ -1,2021 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2018. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% -%% - --module(ssl_to_openssl_SUITE). - -%% Note: This directive should only be used in test suites. --compile(export_all). - --include_lib("common_test/include/ct.hrl"). - --define(SLEEP, 1000). --define(OPENSSL_RENEGOTIATE, "R\n"). --define(OPENSSL_QUIT, "Q\n"). --define(OPENSSL_GARBAGE, "P\n"). --define(EXPIRE, 10). - -%%-------------------------------------------------------------------- -%% Common Test interface functions ----------------------------------- -%%-------------------------------------------------------------------- - -all() -> - case ssl_test_lib:openssl_sane_dtls() of - true -> - [{group, 'tlsv1.2'}, - {group, 'tlsv1.1'}, - {group, 'tlsv1'}, - {group, 'sslv3'}, - {group, 'dtlsv1.2'}, - {group, 'dtlsv1'}]; - false -> - [{group, 'tlsv1.2'}, - {group, 'tlsv1.1'}, - {group, 'tlsv1'}, - {group, 'sslv3'}] - end. - -groups() -> - case ssl_test_lib:openssl_sane_dtls() of - true -> - [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()}, - {'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()}, - {'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()}, - {'sslv3', [], all_versions_tests()}, - {'dtlsv1.2', [], dtls_all_versions_tests()}, - {'dtlsv1', [], dtls_all_versions_tests()} - ]; - false -> - [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()}, - {'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()}, - {'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()}, - {'sslv3', [], all_versions_tests()} - ] - end. - -all_versions_tests() -> - [ - erlang_client_openssl_server, - erlang_server_openssl_client, - erlang_client_openssl_server_dsa_cert, - erlang_server_openssl_client_dsa_cert, - erlang_client_openssl_server_anon, - erlang_server_openssl_client_anon, - erlang_server_openssl_client_anon_with_cert, - erlang_server_openssl_client_reuse_session, - erlang_client_openssl_server_renegotiate, - erlang_client_openssl_server_renegotiate_after_client_data, - erlang_client_openssl_server_nowrap_seqnum, - erlang_server_openssl_client_nowrap_seqnum, - erlang_client_openssl_server_no_server_ca_cert, - erlang_client_openssl_server_client_cert, - erlang_server_openssl_client_client_cert, - ciphers_rsa_signed_certs, - ciphers_dsa_signed_certs, - erlang_client_bad_openssl_server, - expired_session, - ssl2_erlang_server_openssl_client - ]. - -dtls_all_versions_tests() -> - case ssl_test_lib:openssl_sane_client_cert() of - true -> - [erlang_server_openssl_client_client_cert, - erlang_client_openssl_server_no_server_ca_cert, - erlang_client_openssl_server_client_cert - | dtls_all_versions_tests_2()]; - false -> - dtls_all_versions_tests_2() - end. - -dtls_all_versions_tests_2() -> - [erlang_client_openssl_server, - erlang_server_openssl_client, - erlang_client_openssl_server_dsa_cert, - erlang_server_openssl_client_dsa_cert, - erlang_client_openssl_server_anon, - erlang_server_openssl_client_anon, - erlang_server_openssl_client_anon_with_cert, - erlang_server_openssl_client_reuse_session, - erlang_client_openssl_server_renegotiate, - erlang_client_openssl_server_nowrap_seqnum, - erlang_server_openssl_client_nowrap_seqnum, - ciphers_rsa_signed_certs, - ciphers_dsa_signed_certs - %%expired_session - ]. - -alpn_tests() -> - [erlang_client_alpn_openssl_server_alpn, - erlang_server_alpn_openssl_client_alpn, - erlang_client_alpn_openssl_server, - erlang_client_openssl_server_alpn, - erlang_server_alpn_openssl_client, - erlang_server_openssl_client_alpn, - erlang_client_alpn_openssl_server_alpn_renegotiate, - erlang_server_alpn_openssl_client_alpn_renegotiate, - erlang_client_alpn_npn_openssl_server_alpn_npn, - erlang_server_alpn_npn_openssl_client_alpn_npn]. - -npn_tests() -> - [erlang_client_openssl_server_npn, - erlang_server_openssl_client_npn, - erlang_server_openssl_client_npn_renegotiate, - erlang_client_openssl_server_npn_renegotiate, - erlang_server_openssl_client_npn_only_client, - erlang_server_openssl_client_npn_only_server, - erlang_client_openssl_server_npn_only_client, - erlang_client_openssl_server_npn_only_server]. - -sni_server_tests() -> - [erlang_server_openssl_client_sni_match, - erlang_server_openssl_client_sni_match_fun, - erlang_server_openssl_client_sni_no_match, - erlang_server_openssl_client_sni_no_match_fun, - erlang_server_openssl_client_sni_no_header, - erlang_server_openssl_client_sni_no_header_fun]. - - -init_per_suite(Config0) -> - case os:find_executable("openssl") of - false -> - {skip, "Openssl not found"}; - _ -> - ct:pal("Version: ~p", [os:cmd("openssl version")]), - catch crypto:stop(), - try crypto:start() of - ok -> - ssl_test_lib:clean_start(), - Config = - case ssl_test_lib:openssl_dsa_support() of - true -> - Config1 = ssl_test_lib:make_rsa_cert(Config0), - ssl_test_lib:make_dsa_cert(Config1); - false -> - ssl_test_lib:make_rsa_cert(Config0) - end, - ssl_test_lib:cipher_restriction(Config) - catch _:_ -> - {skip, "Crypto did not start"} - end - end. - -end_per_suite(_Config) -> - ssl:stop(), - application:stop(crypto), - ssl_test_lib:kill_openssl(). - -init_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - case ssl_test_lib:supports_ssl_tls_version(GroupName) of - true -> - case ssl_test_lib:check_sane_openssl_version(GroupName) of - true -> - ssl_test_lib:init_tls_version(GroupName, Config); - false -> - {skip, openssl_does_not_support_version} - end; - false -> - {skip, openssl_does_not_support_version} - end; - _ -> - ssl:start(), - Config - end. - -end_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of - true -> - ssl_test_lib:clean_tls_version(Config); - false -> - Config - end. - -init_per_testcase(expired_session, Config) -> - ct:timetrap(?EXPIRE * 1000 * 5), - ssl:stop(), - application:load(ssl), - application:set_env(ssl, session_lifetime, ?EXPIRE), - ssl:start(), - Config; - -init_per_testcase(TestCase, Config) when - TestCase == ciphers_dsa_signed_certs; - TestCase == erlang_client_openssl_server_dsa_cert; - TestCase == erlang_server_openssl_client_dsa_cert; - TestCase == erlang_client_openssl_server_dsa_cert; - TestCase == erlang_server_openssl_client_dsa_cert -> - case ssl_test_lib:openssl_dsa_support() andalso ssl_test_lib:is_sane_oppenssl_client() of - true -> - special_init(TestCase, Config); - false -> - {skip, "DSA not supported by OpenSSL"} - end; -init_per_testcase(TestCase, Config) -> - ct:timetrap({seconds, 35}), - special_init(TestCase, Config). - -special_init(TestCase, Config) when - TestCase == ciphers_rsa_signed_certs; - TestCase == ciphers_dsa_signed_certs-> - ct:timetrap({seconds, 90}), - Config; -special_init(TestCase, Config) - when TestCase == erlang_client_openssl_server_renegotiate; - TestCase == erlang_client_openssl_server_nowrap_seqnum; - TestCase == erlang_server_openssl_client_nowrap_seqnum; - TestCase == erlang_client_openssl_server_renegotiate_after_client_data - -> - {ok, Version} = application:get_env(ssl, protocol_version), - check_sane_openssl_renegotaite(Config, Version); - -special_init(ssl2_erlang_server_openssl_client, Config) -> - case ssl_test_lib:supports_ssl_tls_version(sslv2) of - true -> - Config; - false -> - {skip, "sslv2 not supported by openssl"} - end; - -special_init(TestCase, Config) - when TestCase == erlang_client_alpn_openssl_server_alpn; - TestCase == erlang_server_alpn_openssl_client_alpn; - TestCase == erlang_client_alpn_openssl_server; - TestCase == erlang_client_openssl_server_alpn; - TestCase == erlang_server_alpn_openssl_client; - TestCase == erlang_server_openssl_client_alpn -> - check_openssl_alpn_support(Config); - -special_init(TestCase, Config) - when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate; - TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate -> - {ok, Version} = application:get_env(ssl, protocol_version), - case check_sane_openssl_renegotaite(Config, Version) of - {skip, _} = Skip -> - Skip; - _ -> - check_openssl_alpn_support(Config) - end; - -special_init(TestCase, Config) - when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn; - TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn -> - case check_openssl_alpn_support(Config) of - {skip, _} = Skip -> - Skip; - _ -> - check_openssl_npn_support(Config) - end; - -special_init(TestCase, Config) - when TestCase == erlang_client_openssl_server_npn; - TestCase == erlang_server_openssl_client_npn; - TestCase == erlang_server_openssl_client_npn_only_server; - TestCase == erlang_server_openssl_client_npn_only_client; - TestCase == erlang_client_openssl_server_npn_only_client; - TestCase == erlang_client_openssl_server_npn_only_server -> - check_openssl_npn_support(Config); - -special_init(TestCase, Config) - when TestCase == erlang_server_openssl_client_npn_renegotiate; - TestCase == erlang_client_openssl_server_npn_renegotiate -> - {ok, Version} = application:get_env(ssl, protocol_version), - case check_sane_openssl_renegotaite(Config, Version) of - {skip, _} = Skip -> - Skip; - _ -> - check_openssl_npn_support(Config) - end; - -special_init(TestCase, Config0) - when TestCase == erlang_server_openssl_client_sni_match; - TestCase == erlang_server_openssl_client_sni_no_match; - TestCase == erlang_server_openssl_client_sni_no_header; - TestCase == erlang_server_openssl_client_sni_match_fun; - TestCase == erlang_server_openssl_client_sni_no_match_fun; - TestCase == erlang_server_openssl_client_sni_no_header_fun -> - RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config0), - Config = [{sni_server_opts, [{sni_hosts, - [{"a.server", [ - {certfile, proplists:get_value(certfile, RsaOpts)}, - {keyfile, proplists:get_value(keyfile, RsaOpts)} - ]}, - {"b.server", [ - {certfile, proplists:get_value(certfile, RsaOpts)}, - {keyfile, proplists:get_value(keyfile, RsaOpts)} - ]} - ]}]} | Config0], - check_openssl_sni_support(Config); -special_init(TestCase, Config) - when TestCase == erlang_server_openssl_client; - TestCase == erlang_server_openssl_client_client_cert; - TestCase == erlang_server_openssl_client_reuse_session -> - case ssl_test_lib:is_sane_oppenssl_client() of - true -> - Config; - false -> - {skip, "Broken OpenSSL client"} - end; -special_init(_, Config) -> - Config. - -end_per_testcase(reuse_session_expired, Config) -> - application:unset_env(ssl, session_lifetime), - Config; -end_per_testcase(_, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Test Cases -------------------------------------------------------- -%%-------------------------------------------------------------------- - -erlang_client_openssl_server() -> - [{doc,"Test erlang client with openssl server"}]. -erlang_client_openssl_server(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-key", KeyFile], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- -erlang_server_openssl_client() -> - [{doc,"Test erlang server with openssl client"}]. -erlang_server_openssl_client(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) ++":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version)], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). - -erlang_client_openssl_server_dsa_cert() -> - [{doc,"Test erlang server with openssl client"}]. -erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-CAfile", CaCertFile, - "-key", KeyFile, "-Verify", "2", "-msg"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. -%%-------------------------------------------------------------------- -erlang_server_openssl_client_dsa_cert() -> - [{doc,"Test erlang server with openssl client"}]. -erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config), - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - CaCertFile = proplists:get_value(cacertfile, ClientOpts), - CertFile = proplists:get_value(certfile, ClientOpts), - KeyFile = proplists:get_value(keyfile, ClientOpts), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cert", CertFile, - "-CAfile", CaCertFile, - "-key", KeyFile, "-msg"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). - - %%-------------------------------------------------------------------- -erlang_client_openssl_server_anon() -> - [{doc,"Test erlang client with openssl server, anonymous"}]. -erlang_client_openssl_server_anon(Config) when is_list(Config) -> - process_flag(trap_exit, true), - %% OpenSSL expects a certificate and key, even if the cipher spec - %% is restructed to aNULL, so we use 'server_rsa_opts' here - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_anon_opts, Config), - VersionTuple = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple), - - case openssl_has_common_ciphers(Ciphers) of - false -> - {skip, not_supported_by_openssl}; - true -> - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-key", KeyFile, - "-cipher", "aNULL", "-msg"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, [{ciphers, Ciphers} | ClientOpts]}]), - - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false) - end. -%%-------------------------------------------------------------------- -erlang_server_openssl_client_anon() -> - [{doc,"Test erlang server with openssl client, anonymous"}]. -erlang_server_openssl_client_anon(Config) when is_list(Config) -> - - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config), - VersionTuple = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple), - - case openssl_has_common_ciphers(Ciphers) of - false -> - {skip, not_supported_by_openssl}; - true -> - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{ciphers, Ciphers} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cipher", "aNULL", "-msg"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false) - end. - -%%-------------------------------------------------------------------- -erlang_server_openssl_client_anon_with_cert() -> - [{doc,"Test erlang server with openssl client, anonymous (with cert)"}]. -erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - VersionTuple = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple), - - case openssl_has_common_ciphers(Ciphers) of - false -> - {skip, not_supported_by_openssl}; - true -> - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{ciphers, Ciphers} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cipher", "aNULL", "-msg"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false) - end. - - %%-------------------------------------------------------------------- -erlang_server_openssl_client_reuse_session() -> - [{doc, "Test erlang server with openssl client that reconnects with the" - "same session id, to test reusing of sessions."}]. -erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {reconnect_times, 5}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) - ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-reconnect"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- - -erlang_client_openssl_server_renegotiate() -> - [{doc,"Test erlang client when openssl server issuses a renegotiate"}]. -erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - ErlData = "From erlang to openssl", - OpenSslData = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-CAfile", CaCertFile, - "-cert", CertFile, "-key", KeyFile, "-msg"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - delayed_send, [[ErlData, OpenSslData]]}}, - {options, ClientOpts}]), - - true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), - ct:sleep(?SLEEP), - true = port_command(OpensslPort, OpenSslData), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. -%%-------------------------------------------------------------------- -erlang_client_openssl_server_renegotiate_after_client_data() -> - [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}]. -erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - ErlData = "From erlang to openssl", - OpenSslData = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-CAfile", CaCertFile, - "-cert", CertFile, "-key", KeyFile, "-msg"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - send_wait_send, [[ErlData, OpenSslData]]}}, - {options, ClientOpts}]), - - true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), - ct:sleep(?SLEEP), - true = port_command(OpensslPort, OpenSslData), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- - -erlang_client_openssl_server_nowrap_seqnum() -> - [{doc, "Test that erlang client will renegotiate session when", - "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."}]. -erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - ErlData = "From erlang to openssl\n", - N = 10, - - Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-CAfile", CaCertFile, - "-cert", CertFile, "-key", KeyFile, "-msg"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - trigger_renegotiate, [[ErlData, N+2]]}}, - {options, [{reuse_sessions, false}, - {renegotiate_at, N} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false). -%%-------------------------------------------------------------------- -erlang_server_openssl_client_nowrap_seqnum() -> - [{doc, "Test that erlang client will renegotiate session when", - "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."}]. -erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - N = 10, - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - trigger_renegotiate, [[Data, N+2]]}}, - {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client","-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-msg"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - true = port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- - -erlang_client_openssl_server_no_server_ca_cert() -> - [{doc, "Test erlang client when openssl server sends a cert chain not" - "including the ca cert. Explicitly test this even if it is" - "implicitly tested eleswhere."}]. -erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-key", KeyFile, "-msg"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- -erlang_client_openssl_server_client_cert() -> - [{doc,"Test erlang client with openssl server when client sends cert"}]. -erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-CAfile", CaCertFile, - "-key", KeyFile, "-Verify", "2"], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- -erlang_server_openssl_client_client_cert() -> - [{doc,"Test erlang server with openssl client when client sends cert"}]. -erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, - [{verify , verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - CaCertFile = proplists:get_value(cacertfile, ClientOpts), - CertFile = proplists:get_value(certfile, ClientOpts), - KeyFile = proplists:get_value(keyfile, ClientOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client", "-cert", CertFile, - "-CAfile", CaCertFile, - "-key", KeyFile,"-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version)], - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - true = port_command(OpenSslPort, Data), - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpenSslPort), - ssl_test_lib:close(Server), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- -erlang_server_erlang_client_client_cert() -> - [{doc,"Test erlang server with erlang client when client sends cert"}]. -erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), - ClientOpts = proplists:get_value(client_rsa_verify_opts, Config), - Version = ssl_test_lib:protocol_version(Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, - %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast - [Data]}}, - {options, - [{verify , verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast - {mfa, {ssl, send, [Data]}}, - {options, - [{versions, [Version]} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- - -ciphers_rsa_signed_certs() -> - [{doc,"Test cipher suites that uses rsa certs"}]. -ciphers_rsa_signed_certs(Config) when is_list(Config) -> - Version = ssl_test_lib:protocol_version(Config), - Ciphers = ssl_test_lib:rsa_suites(openssl), - run_suites(Ciphers, Version, Config, rsa). -%%-------------------------------------------------------------------- - -ciphers_dsa_signed_certs() -> - [{doc,"Test cipher suites that uses dsa certs"}]. -ciphers_dsa_signed_certs(Config) when is_list(Config) -> - Version = ssl_test_lib:protocol_version(Config), - NVersion = ssl_test_lib:protocol_version(Config, tuple), - Ciphers = ssl_test_lib:dsa_suites(NVersion), - run_suites(Ciphers, Version, Config, dsa). - -%%-------------------------------------------------------------------- -erlang_client_bad_openssl_server() -> - [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}]. -erlang_client_bad_openssl_server(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-key", KeyFile], - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, server_sent_garbage, []}}, - {options, - [{versions, [Version]} | ClientOpts]}]), - - %% Send garbage - true = port_command(OpensslPort, ?OPENSSL_GARBAGE), - - ct:sleep(?SLEEP), - - Client0 ! server_sent_garbage, - - ssl_test_lib:check_result(Client0, true), - - ssl_test_lib:close(Client0), - - %% Make sure openssl does not hang and leave zombie process - Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, - [{versions, [Version]} | ClientOpts]}]), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client1), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- - -expired_session() -> - [{doc, "Test our ssl client handling of expired sessions. Will make" - "better code coverage of the ssl_manager module"}]. -expired_session(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), - "-cert", CertFile,"-key", KeyFile], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, tls), - - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - - ssl_test_lib:close(Client0), - - %% Make sure session is registered - ct:sleep(?SLEEP), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - - ssl_test_lib:close(Client1), - %% Make sure session is unregistered due to expiration - ct:sleep((?EXPIRE+1) * 1000), - - Client2 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - ssl_test_lib:close(Client2), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- -ssl2_erlang_server_openssl_client() -> - [{doc,"Test that ssl v2 clients are rejected"}]. - -ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Exe = "openssl", - Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - "-ssl2", "-msg"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]), - ssl_test_lib:consume_port_exit(OpenSslPort), - ssl_test_lib:check_server_alert(Server, unexpected_message), - process_flag(trap_exit, false). - -%%-------------------------------------------------------------------- - -erlang_client_alpn_openssl_server_alpn(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok) - end), - ok. - -%%-------------------------------------------------------------------- - -erlang_server_alpn_openssl_client_alpn(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok) - end), - ok. - -%%-------------------------------------------------------------------------- - -erlang_client_alpn_openssl_server(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_with_opts(Config, - [{alpn_advertised_protocols, [<<"spdy/2">>]}], - [], - Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -%%-------------------------------------------------------------------------- - -erlang_client_openssl_server_alpn(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_with_opts(Config, - [], - ["-alpn", "spdy/2"], - Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -%%-------------------------------------------------------------------------- - -erlang_server_alpn_openssl_client(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_with_opts(Config, - [{alpn_preferred_protocols, [<<"spdy/2">>]}], - [], - Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -%%-------------------------------------------------------------------------- - -erlang_server_openssl_client_alpn(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_with_opts(Config, - [], - ["-alpn", "spdy/2"], - Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -%%-------------------------------------------------------------------- - -erlang_client_alpn_openssl_server_alpn_renegotiate(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), - ct:sleep(?SLEEP), - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok) - end), - ok. - -%%-------------------------------------------------------------------- - -erlang_server_alpn_openssl_client_alpn_renegotiate(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), - ct:sleep(?SLEEP), - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok) - end), - ok. - -%%-------------------------------------------------------------------- - -erlang_client_alpn_npn_openssl_server_alpn_npn(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok) - end), - ok. - -%%-------------------------------------------------------------------- - -erlang_server_alpn_npn_openssl_client_alpn_npn(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok) - end), - ok. - -%%-------------------------------------------------------------------- -erlang_client_openssl_server_npn() -> - [{doc,"Test erlang client with openssl server doing npn negotiation"}]. - -erlang_client_openssl_server_npn(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok) - end), - ok. - -%%-------------------------------------------------------------------- -erlang_client_openssl_server_npn_renegotiate() -> - [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}]. - -erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> - true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), - ct:sleep(?SLEEP), - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Client, ok) - end), - ok. -%%-------------------------------------------------------------------------- -erlang_server_openssl_client_npn() -> - [{doc,"Test erlang server with openssl client and npn negotiation"}]. - -erlang_server_openssl_client_npn(Config) when is_list(Config) -> - - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -%%-------------------------------------------------------------------------- -erlang_server_openssl_client_npn_renegotiate() -> - [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}]. - -erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), - ct:sleep(?SLEEP), - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. -%%-------------------------------------------------------------------------- -erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_with_opts(Config, [], - ["-nextprotoneg", "spdy/2"], Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -%%-------------------------------------------------------------------------- - -erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_client_and_openssl_server_with_opts(Config, - [{client_preferred_next_protocols, - {client, [<<"spdy/2">>], <<"http/1.1">>}}], [], - Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -%%-------------------------------------------------------------------------- -erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], [], - Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. - -erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) -> - Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_with_opts(Config, [], ["-nextprotoneg", "spdy/2"], - Data, fun(Server, OpensslPort) -> - true = port_command(OpensslPort, Data), - ssl_test_lib:check_result(Server, ok) - end), - ok. -%-------------------------------------------------------------------------- -erlang_server_openssl_client_sni_no_header(Config) when is_list(Config) -> - erlang_server_openssl_client_sni_test(Config, undefined, undefined, "server Peer cert"). - -erlang_server_openssl_client_sni_no_header_fun(Config) when is_list(Config) -> - erlang_server_openssl_client_sni_test_sni_fun(Config, undefined, undefined, "server Peer cert"). - -erlang_server_openssl_client_sni_match(Config) when is_list(Config) -> - erlang_server_openssl_client_sni_test(Config, "a.server", "a.server", "server Peer cert"). - -erlang_server_openssl_client_sni_match_fun(Config) when is_list(Config) -> - erlang_server_openssl_client_sni_test_sni_fun(Config, "a.server", "a.server", "server Peer cert"). - -erlang_server_openssl_client_sni_no_match(Config) when is_list(Config) -> - erlang_server_openssl_client_sni_test(Config, "c.server", undefined, "server Peer cert"). - -erlang_server_openssl_client_sni_no_match_fun(Config) when is_list(Config) -> - erlang_server_openssl_client_sni_test_sni_fun(Config, "c.server", undefined, "server Peer cert"). - - -%%-------------------------------------------------------------------- -%% Internal functions ------------------------------------------------ -%%-------------------------------------------------------------------- -run_suites(Ciphers, Version, Config, Type) -> - {ClientOpts, ServerOpts} = - case Type of - rsa -> - {ssl_test_lib:ssl_options(client_rsa_opts, Config), - ssl_test_lib:ssl_options(server_rsa_opts, Config)}; - dsa -> - {ssl_test_lib:ssl_options(client_dsa_opts, Config), - ssl_test_lib:ssl_options(server_dsa_verify_opts, Config)} - end, - - Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, - Ciphers), - case lists:flatten(Result) of - [] -> - ok; - Error -> - ct:log("Cipher suite errors: ~p~n", [Error]), - ct:fail(cipher_suite_failed_see_test_case_log) - end. - -client_read_check([], _Data) -> - ok; -client_read_check([Hd | T], Data) -> - case binary:match(Data, list_to_binary(Hd)) of - nomatch -> - nomatch; - _ -> - client_read_check(T, Data) - end. -client_check_result(Port, DataExpected, DataReceived) -> - receive - {Port, {data, TheData}} -> - Data = list_to_binary(TheData), - NewData = <>, - ct:log("New Data: ~p", [NewData]), - case client_read_check(DataExpected, NewData) of - ok -> - ok; - _ -> - client_check_result(Port, DataExpected, NewData) - end - after 20000 -> - ct:fail({"Time out on openSSL Client", {expected, DataExpected}, - {got, DataReceived}}) - end. -client_check_result(Port, DataExpected) -> - client_check_result(Port, DataExpected, <<"">>). - -send_and_hostname(SSLSocket) -> - ssl:send(SSLSocket, "OK"), - case ssl:connection_information(SSLSocket, [sni_hostname]) of - {ok, []} -> - undefined; - {ok, [{sni_hostname, Hostname}]} -> - Hostname - end. - -erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) -> - Version = ssl_test_lib:protocol_version(Config), - ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]), - ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config), - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, - {options, ServerOptions}]), - Port = ssl_test_lib:inet_port(Server), - Exe = "openssl", - ClientArgs = case SNIHostname of - undefined -> - openssl_client_args(Version, Hostname,Port); - _ -> - openssl_client_args(Version, Hostname, Port, SNIHostname) - end, - ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), - - ssl_test_lib:check_result(Server, ExpectedSNIHostname), - ssl_test_lib:close_port(ClientPort), - ssl_test_lib:close(Server), - ok. - - -erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) -> - Version = ssl_test_lib:protocol_version(Config), - ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]), - [{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config), - SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end, - ServerOptions = proplists:get_value(server_rsa_opts, Config) ++ [{sni_fun, SNIFun}], - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, - {options, ServerOptions}]), - Port = ssl_test_lib:inet_port(Server), - Exe = "openssl", - ClientArgs = case SNIHostname of - undefined -> - openssl_client_args(Version, Hostname,Port); - _ -> - openssl_client_args(Version, Hostname, Port, SNIHostname) - end, - - ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), - - ssl_test_lib:check_result(Server, ExpectedSNIHostname), - ssl_test_lib:close_port(ClientPort), - ssl_test_lib:close(Server). - - -cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> - process_flag(trap_exit, true), - ct:log("Testing CipherSuite ~p~n", [CipherSuite]), - {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - - Exe = "openssl", - Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-key", KeyFile], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - ConnectionInfo = {ok, {Version, CipherSuite}}, - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, - {options, - [{ciphers,[CipherSuite]} | - ClientOpts]}]), - - true = port_command(OpenSslPort, "Hello\n"), - - receive - {Port, {data, _}} when is_port(Port) -> - ok - after 500 -> - ct:log("Time out on openssl port, check that" - " the messages Hello and world are received" - " during close of port" , []), - ok - end, - - true = port_command(OpenSslPort, " world\n"), - - Result = ssl_test_lib:wait_for_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpenSslPort), - ssl_test_lib:close(Client), - - Return = case Result of - ok -> - []; - Error -> - [{CipherSuite, Error}] - end, - process_flag(trap_exit, false), - Return. - -start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ClientOpts = ErlangClientOpts ++ ClientOpts0, - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = case OpensslServerOpts of - [] -> - ["s_server", "-accept", - integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-CAfile", CaCertFile, - "-cert", CertFile,"-key", KeyFile]; - [Opt, Value] -> - ["s_server", Opt, Value, "-accept", - integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-CAfile", CaCertFile, - "-cert", CertFile,"-key", KeyFile] - end, - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - - Callback(Client, OpensslPort), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), - ClientOpts0 = proplists:get_value(client_rsa_verify_opts, Config), - ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0], - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-CAfile", CaCertFile, - "-cert", CertFile, "-key", KeyFile], - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, - {options, ClientOpts}]), - - Callback(Client, OpensslPort), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts0 = proplists:get_value(server_rsa_opts, Config), - ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]} | ServerOpts0], - - {_, ServerNode, _} = ssl_test_lib:run_where(Config), - - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_client", "-alpn", "http/1.0,spdy/2", "-msg", "-port", - integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-host", "localhost"], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - Callback(Server, OpenSslPort), - - ssl_test_lib:close(Server), - - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). - -start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts = proplists:get_value(server_rsa_opts, Config), - ClientOpts0 = proplists:get_value(client_rsa_opts, Config), - ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]}, - {client_preferred_next_protocols, {client, [<<"spdy/3">>, <<"http/1.1">>]}} | ClientOpts0], - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", - "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-cert", CertFile, "-key", KeyFile], - - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, - {options, ClientOpts}]), - - Callback(Client, OpensslPort), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts0 = proplists:get_value(server_rsa_opts, Config), - ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]}, - {next_protocols_advertised, [<<"spdy/3">>, <<"http/1.1">>]} | ServerOpts0], - - {_, ServerNode, _} = ssl_test_lib:run_where(Config), - - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - Exe = "openssl", - Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3", - "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version), - "-host", "localhost"], - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - Callback(Server, OpenSslPort), - - ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). - -start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), - ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0], - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port), - ssl_test_lib:version_flag(Version), - "-CAfile", CaCertFile, - "-cert", CertFile, "-key", KeyFile], - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), - - ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, - {options, ClientOpts}]), - - Callback(Client, OpensslPort), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close_port(OpensslPort), - - ssl_test_lib:close(Client), - process_flag(trap_exit, false). - -start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>]}, ServerOpts0], - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_client", "-nextprotoneg", "http/1.0,spdy/2", "-msg", "-connect", - hostname_format(Hostname) ++ ":" - ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - Callback(Server, OpenSslPort), - - ssl_test_lib:close(Server), - - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). - - -start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) -> - process_flag(trap_exit, true), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ServerOpts = ErlangServerOpts ++ ServerOpts0, - - {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Version = ssl_test_lib:protocol_version(Config), - - Exe = "openssl", - Args = ["s_client"] ++ OpenSSLClientOpts ++ ["-msg", "-connect", - hostname_format(Hostname) ++ ":" ++ integer_to_list(Port), - ssl_test_lib:version_flag(Version)], - - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - - Callback(Server, OpenSslPort), - - ssl_test_lib:close(Server), - - ssl_test_lib:close_port(OpenSslPort), - process_flag(trap_exit, false). - - -erlang_ssl_receive_and_assert_negotiated_protocol(Socket, Protocol, Data) -> - {ok, Protocol} = ssl:negotiated_protocol(Socket), - erlang_ssl_receive(Socket, Data), - {ok, Protocol} = ssl:negotiated_protocol(Socket), - ok. - -erlang_ssl_receive(Socket, Data) -> - ct:log("Connection info: ~p~n", - [ssl:connection_information(Socket)]), - receive - {ssl, Socket, "R\n"} -> - %% Swallow s_client renegotiation command. - %% openssl s_client connected commands can appear on - %% server side with some openssl versions. - erlang_ssl_receive(Socket,Data); - {ssl, Socket, Data} -> - io:format("Received ~p~n",[Data]), - %% open_ssl server sometimes hangs waiting in blocking read - ssl:send(Socket, "Got it"), - ok; - {ssl, Socket, Byte} when length(Byte) == 1 -> - erlang_ssl_receive(Socket, tl(Data)); - {Port, {data,Debug}} when is_port(Port) -> - io:format("openssl ~s~n",[Debug]), - erlang_ssl_receive(Socket,Data); - Other -> - ct:fail({unexpected_message, Other}) - end. - -connection_info(Socket, Version) -> - case ssl:connection_information(Socket, [version]) of - {ok, [{version, Version}] = Info} -> - ct:log("Connection info: ~p~n", [Info]), - ok; - {ok, [{version, OtherVersion}]} -> - {wrong_version, OtherVersion} - end. - -connection_info_result(Socket) -> - ssl:connection_information(Socket). - - -delayed_send(Socket, [ErlData, OpenSslData]) -> - ct:sleep(?SLEEP), - ssl:send(Socket, ErlData), - erlang_ssl_receive(Socket, OpenSslData). - -server_sent_garbage(Socket) -> - receive - server_sent_garbage -> - {error, closed} == ssl:send(Socket, "data") - - end. - -send_wait_send(Socket, [ErlData, OpenSslData]) -> - ssl:send(Socket, ErlData), - ct:sleep(?SLEEP), - ssl:send(Socket, ErlData), - erlang_ssl_receive(Socket, OpenSslData). - -check_openssl_sni_support(Config) -> - HelpText = os:cmd("openssl s_client --help"), - case ssl_test_lib:is_sane_oppenssl_client() of - true -> - case string:str(HelpText, "-servername") of - 0 -> - {skip, "Current openssl doesn't support SNI"}; - _ -> - Config - end; - false -> - {skip, "Current openssl doesn't support SNI or extension handling is flawed"} - end. - - -check_openssl_npn_support(Config) -> - HelpText = os:cmd("openssl s_client --help"), - case string:str(HelpText, "nextprotoneg") of - 0 -> - {skip, "Openssl not compiled with nextprotoneg support"}; - _ -> - Config - end. - -check_openssl_alpn_support(Config) -> - HelpText = os:cmd("openssl s_client --help"), - case string:str(HelpText, "alpn") of - 0 -> - {skip, "Openssl not compiled with alpn support"}; - _ -> - Config - end. - -check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1'; - Version == 'tlsv1.2' -> - case os:cmd("openssl version") of - "OpenSSL 1.0.1c" ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - "OpenSSL 1.0.1b" ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - "OpenSSL 1.0.1a" ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - "OpenSSL 1.0.1 " ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - _ -> - check_sane_openssl_renegotaite(Config) - end; -check_sane_openssl_renegotaite(Config, _) -> - check_sane_openssl_renegotaite(Config). - -check_sane_openssl_renegotaite(Config) -> - case os:cmd("openssl version") of - "OpenSSL 1.0.0" ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - "OpenSSL 0.9.8" ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - "OpenSSL 0.9.7" ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - _ -> - Config - end. - -workaround_openssl_s_clinent() -> - %% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159 - %% https://bugs.archlinux.org/task/33919 - %% Bug seems to manifests it self if TLS version is not - %% explicitly specified - case os:cmd("openssl version") of - "OpenSSL 1.0.1c" ++ _ -> - ["-no_tls1_2"]; - "OpenSSL 1.0.1d" ++ _ -> - ["-no_tls1_2"]; - "OpenSSL 1.0.1e" ++ _ -> - ["-no_tls1_2"]; - "OpenSSL 1.0.1f" ++ _ -> - ["-no_tls1_2"]; - _ -> - [] - end. - -openssl_client_args(Version, Hostname, Port) -> - ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)]. - -openssl_client_args(Version, Hostname, Port, ServerName) -> - ["s_client", "-connect", Hostname ++ ":" ++ - integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName]. - - -hostname_format(Hostname) -> - case lists:member($., Hostname) of - true -> - Hostname; - false -> - "localhost" - end. - - -openssl_has_common_ciphers(Ciphers) -> - OCiphers = ssl_test_lib:common_ciphers(openssl), - has_common_ciphers(Ciphers, OCiphers). - -has_common_ciphers([], _) -> - false; -has_common_ciphers([Cipher | Rest], OCiphers) -> - case lists:member(Cipher, OCiphers) of - true -> - true; - _ -> - has_common_ciphers(Rest, OCiphers) - end. diff --git a/lib/ssl/test/ssl_version_SUITE.erl b/lib/ssl/test/ssl_version_SUITE.erl new file mode 100644 index 0000000000..080fba2c36 --- /dev/null +++ b/lib/ssl/test/ssl_version_SUITE.erl @@ -0,0 +1,151 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssl_version_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, 'tlsv1.3'} + ]. + +groups() -> + [ + {'tlsv1.3', [], cert_groups()}, + {rsa, [], tests()}, + {ecdsa, [], tests()} + ]. + +cert_groups() -> + [{group, rsa}, + {group, ecdsa}]. + +tests() -> + [tls13_client_tls12_server, + tls13_client_with_ext_tls12_server, + tls12_client_tls13_server]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +init_per_group(rsa, Config0) -> + Config = ssl_test_lib:make_rsa_cert(Config0), + COpts = proplists:get_value(client_rsa_opts, Config), + SOpts = proplists:get_value(server_rsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; +init_per_group(ecdsa, Config0) -> + PKAlg = crypto:supports(public_keys), + case lists:member(ecdsa, PKAlg) andalso + (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of + true -> + Config = ssl_test_lib:make_ecdsa_cert(Config0), + COpts = proplists:get_value(client_ecdsa_opts, Config), + SOpts = proplists:get_value(server_ecdsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; + false -> + {skip, "Missing EC crypto support"} + end; +init_per_group(GroupName, Config) -> + ssl_test_lib:clean_tls_version(Config), + case ssl_test_lib:is_tls_version(GroupName) andalso + ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + _ -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl:start(), + Config; + false -> + {skip, "Missing crypto support"} + end + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +tls13_client_tls12_server() -> + [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}]. + +tls13_client_tls12_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls13_client_with_ext_tls12_server() -> + [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when " + "client has TLS 1.3 specsific extensions"}]. + +tls13_client_with_ext_tls12_server(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), + + ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {signature_algs_cert, [ecdsa_secp384r1_sha384, + rsa_pss_rsae_sha256, + rsa_pkcs1_sha256, + {sha256,rsa},{sha256,dsa}]}|ClientOpts0], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls12_client_tls13_server() -> + [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}]. + +tls12_client_tls13_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + diff --git a/lib/ssl/test/tls_1_3_record_SUITE.erl b/lib/ssl/test/tls_1_3_record_SUITE.erl new file mode 100644 index 0000000000..5df8853b1b --- /dev/null +++ b/lib/ssl/test/tls_1_3_record_SUITE.erl @@ -0,0 +1,973 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(tls_1_3_record_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("ssl/src/tls_record.hrl"). +-include_lib("ssl/src/tls_handshake.hrl"). +-include_lib("ssl/src/ssl_cipher.hrl"). +-include_lib("ssl/src/ssl_internal.hrl"). + +all() -> + [encode_decode, + finished_verify_data, + '1_RTT_handshake']. + +init_per_suite(Config) -> + catch crypto:stop(), + try (ok == crypto:start()) andalso ssl_test_lib:sufficient_crypto_support('tlsv1.3') of + true -> + ssl_test_lib:clean_start(), + Config; + false -> + {skip, "Not enough crypto support for TLS-1.3"} + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:unload(ssl), + application:stop(crypto). +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +encode_decode() -> + [{doc,"Test TLS 1.3 record encode/decode functions"}]. + +encode_decode(_Config) -> + ConnectionStates = + #{current_read => + #{beast_mitigation => one_n_minus_one, + cipher_state => + {cipher_state, + <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14, + 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, + <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, + 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, + undefined,undefined,undefined,16}, + client_verify_data => undefined,compression_state => undefined, + mac_secret => undefined,secure_renegotiation => undefined, + security_parameters => + {security_parameters, + <<19,2>>, + 0,8,2,undefined,undefined,undefined,undefined,undefined, + sha384,undefined,undefined, + {handshake_secret, + <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121, + 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218, + 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56, + 157>>}, + undefined, + <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207, + 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>, + undefined}, + sequence_number => 0,server_verify_data => undefined}, + current_write => + #{beast_mitigation => one_n_minus_one, + cipher_state => + {cipher_state, + <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14, + 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, + <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, + 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, + undefined,undefined,undefined,16}, + client_verify_data => undefined,compression_state => undefined, + mac_secret => undefined,secure_renegotiation => undefined, + security_parameters => + {security_parameters, + <<19,2>>, + 0,8,2,undefined,undefined,undefined,undefined,undefined, + sha384,undefined,undefined, + {handshake_secret, + <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121, + 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218, + 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56, + 157>>}, + undefined, + <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207, + 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>, + undefined}, + sequence_number => 0,server_verify_data => undefined}}, + + PlainText = [11, + <<0,2,175>>, + <<0,0,2,171,0,2,166,48,130,2,162,48,130,1,138,2,9,0,186,57,220,137,88,255, + 191,235,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,18,49,16,48,14,6,3,85, + 4,3,12,7,84,101,115,116,32,67,65,48,30,23,13,49,56,48,53,48,52,49,52,49,50, + 51,56,90,23,13,50,56,48,50,48,52,49,52,49,50,51,56,90,48,20,49,18,48,16,6, + 3,85,4,3,12,9,108,111,99,97,108,104,111,115,116,48,130,1,34,48,13,6,9,42, + 134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,169,40, + 144,176,121,63,134,97,144,126,243,183,225,157,37,131,183,225,87,243,23,88, + 230,70,9,134,32,147,7,27,167,98,51,81,224,75,199,12,229,251,195,207,75,179, + 181,78,128,3,255,44,58,39,43,172,142,45,186,58,51,65,187,199,154,153,245, + 70,133,137,1,27,87,42,116,65,251,129,109,145,233,97,171,71,54,213,185,74, + 209,166,11,218,189,119,206,86,170,60,212,213,85,189,30,50,215,23,185,53, + 132,238,132,176,198,250,139,251,198,221,225,128,109,113,23,220,39,143,71, + 30,59,189,51,244,61,158,214,146,180,196,103,169,189,221,136,78,129,216,148, + 2,9,8,65,37,224,215,233,13,209,21,235,20,143,33,74,59,53,208,90,152,94,251, + 54,114,171,39,88,230,227,158,211,135,37,182,67,205,161,59,20,138,58,253,15, + 53,48,8,157,9,95,197,9,177,116,21,54,9,125,78,109,182,83,20,16,234,223,116, + 41,155,123,87,77,17,120,153,246,239,124,130,105,219,166,146,242,151,66,198, + 75,72,63,28,246,86,16,244,223,22,36,50,15,247,222,98,6,152,136,154,72,150, + 73,127,2,3,1,0,1,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,76, + 33,54,160,229,219,219,193,150,116,245,252,18,39,235,145,86,12,167,171,52, + 117,166,30,83,5,216,245,177,217,247,95,1,136,94,246,212,108,248,230,111, + 225,202,189,6,129,8,70,128,245,18,204,215,87,82,129,253,227,122,66,182,184, + 189,30,193,169,144,218,216,109,105,110,215,144,60,104,162,178,101,164,218, + 122,60,37,41,143,57,150,52,59,51,112,238,113,239,168,114,69,183,143,154,73, + 61,58,80,247,172,95,251,55,28,186,28,200,206,230,118,243,92,202,189,49,76, + 124,252,76,0,247,112,85,194,69,59,222,163,228,103,49,110,104,109,251,155, + 138,9,37,167,49,189,48,134,52,158,185,129,24,96,153,196,251,90,206,76,239, + 175,119,174,165,133,108,222,125,237,125,187,149,152,83,190,16,202,94,202, + 201,40,218,22,254,63,189,41,174,97,140,203,70,18,196,118,237,175,134,79,78, + 246,2,61,54,77,186,112,32,17,193,192,188,217,252,215,200,7,245,180,179,132, + 183,212,229,155,15,152,206,135,56,81,88,3,123,244,149,110,182,72,109,70,62, + 146,152,146,151,107,126,216,210,9,93,0,0>>], + + {[_Header|Encoded], _} = tls_record_1_3:encode_plain_text(22, PlainText, ConnectionStates), + CipherText = #ssl_tls{type = 23, version = {3,3}, fragment = Encoded}, + + {#ssl_tls{type = 22, version = {3,4}, fragment = DecodedText}, _} = + tls_record_1_3:decode_cipher_text(CipherText, ConnectionStates), + + DecodedText = iolist_to_binary(PlainText), + ct:log("Decoded: ~p ~n", [DecodedText]), + ok. +%%-------------------------------------------------------------------- +'1_RTT_handshake'() -> + [{doc,"Test TLS 1.3 1-RTT Handshake"}]. + +'1_RTT_handshake'(_Config) -> + %% ConnectionStates with NULL cipher + ConnStatesNull = + #{current_write => + #{security_parameters => + #security_parameters{cipher_suite = ?TLS_NULL_WITH_NULL_NULL}, + sequence_number => 0 + } + }, + + %% {client} construct a ClientHello handshake message: + %% + %% ClientHello (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 + %% ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 + %% 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b + %% 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 + %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 + %% 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 + %% 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a + %% af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 + %% 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 + %% 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 + %% + %% {client} send handshake record: + %% + %% payload (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 ba + %% 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 02 + %% 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b 00 + %% 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12 + %% 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00 + %% 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d + %% 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af + %% 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02 + %% 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02 + %% 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 + %% + %% complete record (201 octets): 16 03 01 00 c4 01 00 00 c0 03 03 cb + %% 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 + %% ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 + %% 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 + %% 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 + %% 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d + %% e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d + %% 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e + %% 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 + %% 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 + ClientHello = + hexstr2bin("01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 + ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 + 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b + 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 + 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 + 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 + 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a + af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 + 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 + 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"), + + ClientHelloRecord = + %% Current implementation always sets + %% legacy_record_version to Ox0303 + hexstr2bin("16 03 03 00 c4 01 00 00 c0 03 03 cb + 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 + ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 + 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 + 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 + 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d + e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d + 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e + 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 + 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"), + + {CHEncrypted, _} = + tls_record:encode_handshake(ClientHello, {3,4}, ConnStatesNull), + ClientHelloRecord = iolist_to_binary(CHEncrypted), + + %% {server} extract secret "early": + %% + %% salt: 0 (all zero octets) + %% + %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + %% + %% secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c + %% e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a + HKDFAlgo = sha256, + Salt = binary:copy(<>, 32), + IKM = binary:copy(<>, 32), + EarlySecret = + hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c + e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"), + + {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}), + + %% {client} create an ephemeral x25519 key pair: + %% + %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78 + %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05 + %% + %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d + %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c + CPublicKey = + hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d + ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"), + + %% {server} create an ephemeral x25519 key pair: + %% + %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 + %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e + %% + %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 + %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f + SPrivateKey = + hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 + 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"), + + SPublicKey = + hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 + 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"), + + %% {server} construct a ServerHello handshake message: + %% + %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 + %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e + %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 + %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 + %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 + ServerHello = + hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60 + dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e + d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 + 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 + dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), + + %% {server} derive secret for handshake "tls13 derived": + %% + %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2 + %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a + %% + %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 + %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 + %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 + %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba + %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba + Hash = + hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 + 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), + + Hash = crypto:hash(HKDFAlgo, <<>>), + + Info = + hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 + 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 + 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), + + Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)), + + Expanded = + hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba + b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"), + + Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo), + + %% {server} extract secret "handshake": + %% + %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97 + %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba + %% + %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d + %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d + %% + %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b + %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + + %% salt = Expanded + HandshakeIKM = + hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d + 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"), + + HandshakeSecret = + hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b + 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"), + + HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519), + + {handshake_secret, HandshakeSecret} = + tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM, + {early_secret, EarlySecret}), + + %% {server} derive secret "tls13 c hs traffic": + %% + %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 + %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + %% + %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed + %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 + %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e + %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 + + %% PRK = HandshakeSecret + CHSTHash = + hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed + d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), + + CHSTInfo = + hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 + 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), + + CHSTrafficSecret = + hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e + 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"), + + CHSH = <>, + CHSTHash = crypto:hash(HKDFAlgo, CHSH), + CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), + + CHSTrafficSecret = + tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), + + %% {server} derive secret "tls13 s hs traffic": + %% + %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 + %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + %% + %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed + %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 + %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d + %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 + + %% PRK = HandshakeSecret + %% hash = CHSTHash + SHSTInfo = + hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 + 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), + + SHSTrafficSecret = + hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d + 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"), + + SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), + + SHSTrafficSecret = + tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), + + + %% {server} derive secret for master "tls13 derived": + %% + %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 + %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + %% + %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 + %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 + %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 + %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 + %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 + + %% PRK = HandshakeSecret + %% hash = Hash + %% info = Info + MasterDeriveSecret = + hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 + 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"), + + MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo), + + %% {server} extract secret "master": + %% + %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5 + %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 + %% + %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + %% + %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a + %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + + %% salt = MasterDeriveSecret + %% IKM = IKM + MasterSecret = + hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a + 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"), + + {master_secret, MasterSecret} = + tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}), + + %% {server} send handshake record: + %% + %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e + %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2 + %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11 + %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 + %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 + %% + %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6 + %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 + %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 + %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 + %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 + + %% payload = ServerHello + ServerHelloRecord = + hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6 + af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 + 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 + 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 + cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), + + {SHEncrypted, _} = + tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull), + ServerHelloRecord = iolist_to_binary(SHEncrypted), + + %% {server} derive write traffic keys for handshake data: + %% + %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 + %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e + %% e4 03 bc + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30 + + %% PRK = SHSTrafficSecret + WriteKeyInfo = + hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"), + + WriteKey = + hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"), + + WriteIVInfo = + hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"), + + WriteIV = + hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"), + + Cipher = aes_128_gcm, %% TODO: get from ServerHello + + WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)), + %% TODO: remove hardcoded IV size + WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12), + + {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret), + + %% {server} construct an EncryptedExtensions handshake message: + %% + %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00 + %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c + %% 00 02 40 01 00 00 00 00 + %% + %% {server} construct a Certificate handshake message: + %% + %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 + %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 + %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 + %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 + %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 + %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 + %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f + %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 + %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c + %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 + %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 + %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 + %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 + %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 + %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 + %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a + %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea + %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 + %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be + %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b + %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 + %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00 + %% + %% {server} construct a CertificateVerify handshake message: + %% + %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c + %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a + %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 + %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b + %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 + %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a + %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3 + EncryptedExtensions = + hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00 + 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c + 00 02 40 01 00 00 00 00"), + + Certificate = + hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 + 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 + 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 + 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 + 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 + 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 + 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f + 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 + d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c + 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 + 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 + 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 + ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 + 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 + 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 + 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a + 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea + e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 + 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be + c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b + 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 + 96 12 29 ac 91 87 b4 2b 4d e1 00 00"), + + CertificateVerify = + hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c + 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a + b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 + 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b + be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 + 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a + 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"), + + %% {server} calculate finished "tls13 finished": + %% + %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 + %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 + %% + %% hash (0 octets): (empty) + %% + %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 + %% 64 00 + %% + %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 + %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8 + %% + %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 + %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18 + + %% PRK = SHSTrafficSecret + FInfo = + hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 + 64 00"), + + FExpanded = + hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 + c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"), + + FinishedVerifyData = + hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 + de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"), + + FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)), + + FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo), + + MessageHistory0 = [CertificateVerify, + Certificate, + EncryptedExtensions, + ServerHello, + ClientHello], + + FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0), + + %% {server} construct a Finished handshake message: + %% + %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb + %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 + %% 18 + FinishedHSBin = + hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb + dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 + 18"), + + FinishedHS = #finished{verify_data = FinishedVerifyData}, + + FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}), + FinishedHSBin = iolist_to_binary(FinishedIOList), + + %% {server} derive secret "tls13 c ap traffic": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 + %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce + %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5 + + %% PRK = MasterSecret + CAPTHash = + hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + CAPTInfo = + hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 + 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + CAPTrafficSecret = + hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce + 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"), + + CHSF = <>, + + CAPTHash = crypto:hash(HKDFAlgo, CHSF), + + CAPTInfo = + tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + CAPTrafficSecret = + tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive secret "tls13 s ap traffic": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 + %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 + %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 + + %% PRK = MasterSecret + %% hash = CAPTHash + SAPTInfo = + hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 + 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + SAPTrafficSecret = + hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 + 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"), + + SAPTInfo = + tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + SAPTrafficSecret = + tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive secret "tls13 exp master": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 + %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 + %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 + %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50 + + %% PRK = MasterSecret + %% hash = CAPTHash + ExporterInfo = + hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 + 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 + 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + ExporterMasterSecret = + hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 + 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"), + + ExporterInfo = + tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + ExporterMasterSecret = + tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive write traffic keys for application data: + %% + %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32 + %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac + %% 92 e3 56 + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84 + + %% PRK = SAPTrafficsecret + %% key info = WriteKeyInfo + %% iv info = WrtieIVInfo + SWKey = + hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"), + + SWIV = + hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"), + + {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret), + + %% {server} derive read traffic keys for handshake data: + %% + %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f + %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 + %% 25 8d 01 + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f + + %% PRK = CHSTrafficsecret + %% key info = WriteKeyInfo + %% iv info = WrtieIVInfo + SRKey = + hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"), + + SRIV = + hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"), + + {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret). + +%%-------------------------------------------------------------------- +finished_verify_data() -> + [{doc,"Test TLS 1.3 Finished message handling"}]. + +finished_verify_data(_Config) -> + ClientHello = + hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09 + 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 + 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 + e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 + f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01 + 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d + 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00 + 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00 + 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06 + 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72 + d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed + 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00 + 02 01 01 00 2b 00 03 02 03 04"), + + ServerHello = + hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79 + 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 + 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 + e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 + f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24 + 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b + 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 + 28 80 b6 15 00 2b 00 02 03 04"), + + EncryptedExtensions = + hexstr2bin("08 00 00 02 00 00"), + + Certificate = + hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30 + 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 + 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 + 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 + 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 + 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 + 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 + 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 + 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 + 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e + 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d + 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 + 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 + b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 + 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d + bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d + f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 + f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b + 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 + f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 + ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 + ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 + 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb + 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 + 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 + d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad + 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 + 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 + ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 + 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 + 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 + 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 + 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 + cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 + 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 + 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b + fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 + 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd + 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 + f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 + 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 + 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 + 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 + ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e + 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 + c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 + cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 + 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f + 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 + 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 + 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0 + 00 00"), + + CertificateVerify = + hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d + 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75 + 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8 + 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13 + 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73 + df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b + 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2 + 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84 + fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c + 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5 + 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79 + ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a + aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7 + 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b + 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36 + c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe + c7 e4 a7 30 f1 36 9f 9e"), + + BaseKey = + hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4 + 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"), + + VerifyData = + hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea + c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"), + + Messages = [CertificateVerify, + Certificate, + EncryptedExtensions, + ServerHello, + ClientHello], + + FinishedKey = tls_v1:finished_key(BaseKey, sha256), + VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- + +hexstr2int(S) -> + B = hexstr2bin(S), + Bits = size(B) * 8, + <> = B, + Integer. + +hexstr2bin(S) when is_binary(S) -> + hexstr2bin(S, <<>>); +hexstr2bin(S) -> + hexstr2bin(list_to_binary(S), <<>>). +%% +hexstr2bin(<<>>, Acc) -> + Acc; +hexstr2bin(<>, Acc) when C =:= 32; %% SPACE + C =:= 10; %% LF + C =:= 13 -> %% CR + hexstr2bin(T, Acc); +hexstr2bin(<>, Acc) -> + I = hex2int(X) * 16 + hex2int(Y), + hexstr2bin(T, <>). + +hex2int(C) when $0 =< C, C =< $9 -> + C - $0; +hex2int(C) when $A =< C, C =< $F -> + C - $A + 10; +hex2int(C) when $a =< C, C =< $f -> + C - $a + 10. diff --git a/lib/ssl/test/tls_1_3_version_SUITE.erl b/lib/ssl/test/tls_1_3_version_SUITE.erl new file mode 100644 index 0000000000..f0b224d4e5 --- /dev/null +++ b/lib/ssl/test/tls_1_3_version_SUITE.erl @@ -0,0 +1,153 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(tls_1_3_version_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, 'tlsv1.3'} + ]. + +groups() -> + [ + {'tlsv1.3', [], cert_groups()}, + {rsa, [], tests()}, + {ecdsa, [], tests()} + ]. + +cert_groups() -> + [{group, rsa}, + {group, ecdsa}]. + +tests() -> + [tls13_client_tls12_server, + tls13_client_with_ext_tls12_server, + tls12_client_tls13_server]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + [{client_type, erlang}, {server_type, erlang} | + Config] + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +init_per_group(rsa, Config0) -> + Config = ssl_test_lib:make_rsa_cert(Config0), + COpts = proplists:get_value(client_rsa_opts, Config), + SOpts = proplists:get_value(server_rsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; +init_per_group(ecdsa, Config0) -> + PKAlg = crypto:supports(public_keys), + case lists:member(ecdsa, PKAlg) andalso + (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of + true -> + Config = ssl_test_lib:make_ecdsa_cert(Config0), + COpts = proplists:get_value(client_ecdsa_opts, Config), + SOpts = proplists:get_value(server_ecdsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; + false -> + {skip, "Missing EC crypto support"} + end; +init_per_group(GroupName, Config) -> + ssl_test_lib:clean_tls_version(Config), + case ssl_test_lib:is_tls_version(GroupName) andalso + ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + _ -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl:start(), + Config; + false -> + {skip, "Missing crypto support"} + end + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +tls13_client_tls12_server() -> + [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}]. + +tls13_client_tls12_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls13_client_with_ext_tls12_server() -> + [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when " + "client has TLS 1.3 specsific extensions"}]. + +tls13_client_with_ext_tls12_server(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {signature_algs_cert, [ecdsa_secp384r1_sha384, + ecdsa_secp256r1_sha256, + rsa_pss_rsae_sha256, + rsa_pkcs1_sha256, + {sha256,rsa},{sha256,dsa}]}|ClientOpts0], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls12_client_tls13_server() -> + [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}]. + +tls12_client_tls13_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + -- cgit v1.2.3