diff options
30 files changed, 6102 insertions, 5615 deletions
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_server_cipher_suite_SUITE.erl b/lib/ssl/test/openssl_cipher_suite_SUITE.erl index 0d68d84d61..955eb914c0 100644 --- a/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl +++ b/lib/ssl/test/openssl_cipher_suite_SUITE.erl @@ -20,7 +20,7 @@ %% --module(openssl_server_cipher_suite_SUITE). +-module(openssl_cipher_suite_SUITE). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -31,19 +31,26 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- all() -> - [ - {group, 'tlsv1.2'}, + [ + {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()}, @@ -135,6 +142,9 @@ kex() -> 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}, @@ -148,6 +158,11 @@ dtls_rsa() -> %%,{group, rsa_psk} ]. +ssl3_rsa() -> + [{group, dhe_rsa}, + {group, rsa} + ]. + ecdsa() -> [{group, ecdhe_ecdsa}]. @@ -156,6 +171,10 @@ dss() -> %%{group, srp_dss} ]. +ssl3_dss() -> + [{group, dhe_dss} + ]. + anonymous() -> [{group, dh_anon}, {group, ecdh_anon} @@ -165,6 +184,9 @@ anonymous() -> %%{group, srp_anon} ]. +ssl3_anonymous() -> + [{group, dh_anon}]. + init_per_suite(Config) -> catch crypto:stop(), try crypto:start() of @@ -199,7 +221,12 @@ init_per_group(GroupName, Config) -> 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 -> @@ -747,8 +774,7 @@ cipher_suite_test(CipherSuite, _Version, 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]). + ssl_test_lib:basic_test([{ciphers, [CipherSuite]} | COpts], SOpts, Config). test_ciphers(Kex, Cipher, Version) -> 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_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_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_SUITE.erl index dfc780479e..82a49e1469 100644 --- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_alpn_SUITE.erl @@ -19,7 +19,7 @@ %% %% --module(ssl_alpn_handshake_SUITE). +-module(ssl_alpn_SUITE). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -32,7 +32,9 @@ %%-------------------------------------------------------------------- all() -> - [{group, 'tlsv1.2'}, + [ + {group, 'tlsv1.3'}, + {group, 'tlsv1.2'}, {group, 'tlsv1.1'}, {group, 'tlsv1'}, {group, 'sslv3'}, @@ -42,12 +44,13 @@ all() -> groups() -> [ - {'tlsv1.2', [], alpn_tests()}, - {'tlsv1.1', [], alpn_tests()}, - {'tlsv1', [], alpn_tests()}, + {'tlsv1.3', [], alpn_tests() -- [client_renegotiate, session_reused]}, + {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()}, + {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist()}, + {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist()}, {'sslv3', [], alpn_not_supported()}, - {'dtlsv1.2', [], alpn_tests() -- [client_renegotiate]}, - {'dtlsv1', [], alpn_tests() -- [client_renegotiate]} + {'dtlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()}, + {'dtlsv1', [], alpn_tests() ++ alpn_npn_coexist()} ]. alpn_tests() -> @@ -61,12 +64,16 @@ alpn_tests() -> client_alpn_and_server_no_support, client_no_support_and_server_alpn, client_alpn_npn_and_server_alpn, - client_alpn_npn_and_server_alpn_npn, - client_alpn_and_server_alpn_npn, client_renegotiate, session_reused ]. +alpn_npn_coexist() -> + [ + client_alpn_npn_and_server_alpn_npn, + client_alpn_and_server_alpn_npn + ]. + alpn_not_supported() -> [alpn_not_supported_client, alpn_not_supported_server @@ -77,8 +84,7 @@ init_per_suite(Config0) -> try crypto:start() of ok -> ssl_test_lib:clean_start(), - Config = ssl_test_lib:make_rsa_cert(Config0), - ssl_test_lib:cert_options(Config) + ssl_test_lib:make_rsa_cert(Config0) catch _:_ -> {skip, "Crypto did not start"} end. diff --git a/lib/ssl/test/ssl_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,384 +2665,6 @@ 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)), - - 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_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, [{reuse_session, fun(_,_,_,_) -> - false - end} | - ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - - %% Make sure session is registered - ct:sleep(?SLEEP), - ssl_test_lib:close(Client0), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client1, SessionInfo} -> - ct:fail(session_reused_when_server_does_not_want_to); - {Client1, _Other} -> - ok - end, - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client1). - -%%-------------------------------------------------------------------- -client_renegotiate() -> - [{doc,"Test ssl:renegotiate/1 on client."}]. -client_renegotiate(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate, [Data]}}, - {options, [{reuse_sessions, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -client_secure_renegotiate() -> - [{doc,"Test ssl:renegotiate/1 on client."}]. -client_secure_renegotiate(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{secure_renegotiate, true} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate, [Data]}}, - {options, [{reuse_sessions, false}, - {secure_renegotiate, true}| ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -client_secure_renegotiate_fallback() -> - [{doc,"Test that we can set secure_renegotiate to false that is " - "fallback option, we however do not have a insecure server to test against!"}]. -client_secure_renegotiate_fallback(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{secure_renegotiate, false} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - 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_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:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -client_renegotiate_reused_session() -> - [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}]. -client_renegotiate_reused_session(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - renegotiate_reuse_session, [Data]}}, - {options, [{reuse_sessions, true} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok, Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -server_renegotiate_reused_session() -> - [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}]. -server_renegotiate_reused_session(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - renegotiate_reuse_session, [Data]}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, [{reuse_sessions, true} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). -%%-------------------------------------------------------------------- -client_no_wrap_sequence_number() -> - [{doc,"Test that erlang client will renegotiate session when", - "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."}]. - -client_no_wrap_sequence_number(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - ErlData = "From erlang to erlang", - N = 12, - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Version = ssl_test_lib:protocol_version(Config, tuple), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, - trigger_renegotiate, [[ErlData, treashold(N, Version)]]}}, - {options, [{reuse_sessions, false}, - {renegotiate_at, N} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- -server_no_wrap_sequence_number() -> - [{doc, "Test that erlang server will renegotiate session when", - "max sequence number celing is about to be reached. Although" - "in the testcase we use the test option renegotiate_at" - " to lower treashold substantially."}]. - -server_no_wrap_sequence_number(Config) when is_list(Config) -> - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - N = 12, - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, - trigger_renegotiate, [[Data, N+2]]}}, - {options, [{renegotiate_at, N} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{reuse_sessions, false} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). %%-------------------------------------------------------------------- der_input() -> @@ -3233,122 +2726,6 @@ der_input_opts(Opts) -> end, ssl_test_lib:pem_to_der(CaCertsfile)), {Cert, {Asn1Type, Key}, CaCerts, DHParams}. -%%-------------------------------------------------------------------- -no_reuses_session_server_restart_new_cert() -> - [{doc,"Check that a session is not reused if the server is restarted with a new cert."}]. -no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> - - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - %% Make sure session is registered - ct:sleep(?SLEEP), - Monitor = erlang:monitor(process, Server), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client0), - receive - {'DOWN', Monitor, _, _, _} -> - ok - end, - - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{reuseaddr, true} | DsaServerOpts]}]), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client1, SessionInfo} -> - ct:fail(session_reused_when_server_has_new_cert); - {Client1, _Other} -> - ok - end, - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client1). - -%%-------------------------------------------------------------------- -no_reuses_session_server_restart_new_cert_file() -> - [{doc,"Check that a session is not reused if a server is restarted with a new " - "cert contained in a file with the same name as the old cert."}]. - -no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config), - DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config), - PrivDir = proplists:get_value(priv_dir, Config), - - NewServerOpts0 = new_config(PrivDir, ServerOpts), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, NewServerOpts0}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - %% Make sure session is registered and we get - %% new file time stamp when calling new_config! - ct:sleep(?SLEEP* 2), - ssl_test_lib:close(Server), - ssl_test_lib:close(Client0), - - ssl:clear_pem_cache(), - - NewServerOpts1 = new_config(PrivDir, DsaServerOpts), - - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, Port}, - {from, self()}, - {mfa, {ssl_test_lib, no_result, []}}, - {options, [{reuseaddr, true} | NewServerOpts1]}]), - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client1, SessionInfo} -> - ct:fail(session_reused_when_server_has_new_cert); - {Client1, _Other} -> - ok - end, - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- defaults(Config) when is_list(Config)-> @@ -3873,90 +3250,6 @@ connect_twice(Config) when is_list(Config) -> 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) -> @@ -4275,17 +3568,6 @@ new_server_wants_peer_cert(Config) when is_list(Config) -> 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."}]. @@ -4480,1981 +3762,6 @@ accept_pool(Config) when is_list(Config) -> ssl_test_lib:close(Client1), ssl_test_lib:close(Client2). -%%-------------------------------------------------------------------- -%% TLS 1.3 -%%-------------------------------------------------------------------- - -tls13_enable_client_side() -> - [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}]. - -tls13_enable_client_side(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.1', 'tlsv1.2']} | ServerOpts] }]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.2', 'tlsv1.3']} | ClientOpts]}]), - - ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). - -tls13_enable_server_side() -> - [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}]. - -tls13_enable_server_side(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.2', 'tlsv1.3']} | ServerOpts] }]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, protocol_info_result, []}}, - {options, [{versions, - ['tlsv1.2', 'tlsv1.1']} | ClientOpts]}]), - - ServerMsg = ClientMsg = {ok, 'tlsv1.2'}, - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg). - -tls_record_1_3_encode_decode() -> - [{doc,"Test TLS 1.3 record encode/decode functions"}]. - -tls_record_1_3_encode_decode(_Config) -> - ConnectionStates = - #{current_read => - #{beast_mitigation => one_n_minus_one, - cipher_state => - {cipher_state, - <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14, - 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, - <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, - 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, - undefined,undefined,undefined,16}, - client_verify_data => undefined,compression_state => undefined, - mac_secret => undefined,secure_renegotiation => undefined, - security_parameters => - {security_parameters, - <<19,2>>, - 0,8,2,undefined,undefined,undefined,undefined,undefined, - sha384,undefined,undefined, - {handshake_secret, - <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121, - 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218, - 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56, - 157>>}, - undefined, - <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207, - 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>, - undefined}, - sequence_number => 0,server_verify_data => undefined}, - current_write => - #{beast_mitigation => one_n_minus_one, - cipher_state => - {cipher_state, - <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14, - 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, - <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, - 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, - undefined,undefined,undefined,16}, - client_verify_data => undefined,compression_state => undefined, - mac_secret => undefined,secure_renegotiation => undefined, - security_parameters => - {security_parameters, - <<19,2>>, - 0,8,2,undefined,undefined,undefined,undefined,undefined, - sha384,undefined,undefined, - {handshake_secret, - <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121, - 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218, - 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56, - 157>>}, - undefined, - <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207, - 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>, - undefined}, - sequence_number => 0,server_verify_data => undefined}}, - - PlainText = [11, - <<0,2,175>>, - <<0,0,2,171,0,2,166,48,130,2,162,48,130,1,138,2,9,0,186,57,220,137,88,255, - 191,235,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,18,49,16,48,14,6,3,85, - 4,3,12,7,84,101,115,116,32,67,65,48,30,23,13,49,56,48,53,48,52,49,52,49,50, - 51,56,90,23,13,50,56,48,50,48,52,49,52,49,50,51,56,90,48,20,49,18,48,16,6, - 3,85,4,3,12,9,108,111,99,97,108,104,111,115,116,48,130,1,34,48,13,6,9,42, - 134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,169,40, - 144,176,121,63,134,97,144,126,243,183,225,157,37,131,183,225,87,243,23,88, - 230,70,9,134,32,147,7,27,167,98,51,81,224,75,199,12,229,251,195,207,75,179, - 181,78,128,3,255,44,58,39,43,172,142,45,186,58,51,65,187,199,154,153,245, - 70,133,137,1,27,87,42,116,65,251,129,109,145,233,97,171,71,54,213,185,74, - 209,166,11,218,189,119,206,86,170,60,212,213,85,189,30,50,215,23,185,53, - 132,238,132,176,198,250,139,251,198,221,225,128,109,113,23,220,39,143,71, - 30,59,189,51,244,61,158,214,146,180,196,103,169,189,221,136,78,129,216,148, - 2,9,8,65,37,224,215,233,13,209,21,235,20,143,33,74,59,53,208,90,152,94,251, - 54,114,171,39,88,230,227,158,211,135,37,182,67,205,161,59,20,138,58,253,15, - 53,48,8,157,9,95,197,9,177,116,21,54,9,125,78,109,182,83,20,16,234,223,116, - 41,155,123,87,77,17,120,153,246,239,124,130,105,219,166,146,242,151,66,198, - 75,72,63,28,246,86,16,244,223,22,36,50,15,247,222,98,6,152,136,154,72,150, - 73,127,2,3,1,0,1,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,76, - 33,54,160,229,219,219,193,150,116,245,252,18,39,235,145,86,12,167,171,52, - 117,166,30,83,5,216,245,177,217,247,95,1,136,94,246,212,108,248,230,111, - 225,202,189,6,129,8,70,128,245,18,204,215,87,82,129,253,227,122,66,182,184, - 189,30,193,169,144,218,216,109,105,110,215,144,60,104,162,178,101,164,218, - 122,60,37,41,143,57,150,52,59,51,112,238,113,239,168,114,69,183,143,154,73, - 61,58,80,247,172,95,251,55,28,186,28,200,206,230,118,243,92,202,189,49,76, - 124,252,76,0,247,112,85,194,69,59,222,163,228,103,49,110,104,109,251,155, - 138,9,37,167,49,189,48,134,52,158,185,129,24,96,153,196,251,90,206,76,239, - 175,119,174,165,133,108,222,125,237,125,187,149,152,83,190,16,202,94,202, - 201,40,218,22,254,63,189,41,174,97,140,203,70,18,196,118,237,175,134,79,78, - 246,2,61,54,77,186,112,32,17,193,192,188,217,252,215,200,7,245,180,179,132, - 183,212,229,155,15,152,206,135,56,81,88,3,123,244,149,110,182,72,109,70,62, - 146,152,146,151,107,126,216,210,9,93,0,0>>], - - {[_Header|Encoded], _} = tls_record_1_3:encode_plain_text(22, PlainText, ConnectionStates), - CipherText = #ssl_tls{type = 23, version = {3,3}, fragment = Encoded}, - - {#ssl_tls{type = 22, version = {3,4}, fragment = DecodedText}, _} = - tls_record_1_3:decode_cipher_text(CipherText, ConnectionStates), - - DecodedText = iolist_to_binary(PlainText), - ct:log("Decoded: ~p ~n", [DecodedText]), - ok. - -tls13_1_RTT_handshake() -> - [{doc,"Test TLS 1.3 1-RTT Handshake"}]. - -tls13_1_RTT_handshake(_Config) -> - %% ConnectionStates with NULL cipher - ConnStatesNull = - #{current_write => - #{security_parameters => - #security_parameters{cipher_suite = ?TLS_NULL_WITH_NULL_NULL}, - sequence_number => 0 - } - }, - - %% {client} construct a ClientHello handshake message: - %% - %% ClientHello (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 - %% ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 - %% 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b - %% 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 - %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 - %% 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 - %% 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a - %% af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 - %% 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 - %% 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 - %% - %% {client} send handshake record: - %% - %% payload (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 ba - %% 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 02 - %% 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b 00 - %% 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12 - %% 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00 - %% 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d - %% 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af - %% 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02 - %% 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02 - %% 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 - %% - %% complete record (201 octets): 16 03 01 00 c4 01 00 00 c0 03 03 cb - %% 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 - %% ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 - %% 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 - %% 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 - %% 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d - %% e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d - %% 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e - %% 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 - %% 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 - ClientHello = - hexstr2bin("01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 - ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 - 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b - 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 - 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 - 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 - 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a - af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 - 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 - 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"), - - ClientHelloRecord = - %% Current implementation always sets - %% legacy_record_version to Ox0303 - hexstr2bin("16 03 03 00 c4 01 00 00 c0 03 03 cb - 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 - ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 - 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 - 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 - 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d - e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d - 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e - 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 - 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"), - - {CHEncrypted, _} = - tls_record:encode_handshake(ClientHello, {3,4}, ConnStatesNull), - ClientHelloRecord = iolist_to_binary(CHEncrypted), - - %% {server} extract secret "early": - %% - %% salt: 0 (all zero octets) - %% - %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% - %% secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c - %% e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a - HKDFAlgo = sha256, - Salt = binary:copy(<<?BYTE(0)>>, 32), - IKM = binary:copy(<<?BYTE(0)>>, 32), - EarlySecret = - hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c - e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"), - - {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}), - - %% {client} create an ephemeral x25519 key pair: - %% - %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78 - %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05 - %% - %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d - %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c - CPublicKey = - hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d - ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"), - - %% {server} create an ephemeral x25519 key pair: - %% - %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 - %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e - %% - %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 - %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f - SPrivateKey = - hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 - 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"), - - SPublicKey = - hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 - 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"), - - %% {server} construct a ServerHello handshake message: - %% - %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 - %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e - %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 - %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 - %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 - ServerHello = - hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60 - dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e - d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 - 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 - dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), - - %% {server} derive secret for handshake "tls13 derived": - %% - %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2 - %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a - %% - %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 - %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 - %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 - %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba - %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba - Hash = - hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 - 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), - - Hash = crypto:hash(HKDFAlgo, <<>>), - - Info = - hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 - 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 - 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), - - Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)), - - Expanded = - hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba - b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"), - - Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo), - - %% {server} extract secret "handshake": - %% - %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97 - %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba - %% - %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d - %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d - %% - %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b - %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - - %% salt = Expanded - HandshakeIKM = - hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d - 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"), - - HandshakeSecret = - hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b - 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"), - - HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519), - - {handshake_secret, HandshakeSecret} = - tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM, - {early_secret, EarlySecret}), - - %% {server} derive secret "tls13 c hs traffic": - %% - %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 - %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - %% - %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed - %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 - %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e - %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 - - %% PRK = HandshakeSecret - CHSTHash = - hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed - d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), - - CHSTInfo = - hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 - 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), - - CHSTrafficSecret = - hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e - 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"), - - CHSH = <<ClientHello/binary,ServerHello/binary>>, - CHSTHash = crypto:hash(HKDFAlgo, CHSH), - CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), - - CHSTrafficSecret = - tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), - - %% {server} derive secret "tls13 s hs traffic": - %% - %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 - %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - %% - %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed - %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 - %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 - %% - %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d - %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 - - %% PRK = HandshakeSecret - %% hash = CHSTHash - SHSTInfo = - hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 - 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 - ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), - - SHSTrafficSecret = - hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d - 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"), - - SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), - - SHSTrafficSecret = - tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), - - - %% {server} derive secret for master "tls13 derived": - %% - %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 - %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac - %% - %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 - %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 - %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 - %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 - %% - %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 - %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 - - %% PRK = HandshakeSecret - %% hash = Hash - %% info = Info - MasterDeriveSecret = - hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 - 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"), - - MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo), - - %% {server} extract secret "master": - %% - %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5 - %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 - %% - %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - %% - %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a - %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - - %% salt = MasterDeriveSecret - %% IKM = IKM - MasterSecret = - hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a - 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"), - - {master_secret, MasterSecret} = - tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}), - - %% {server} send handshake record: - %% - %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e - %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2 - %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11 - %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 - %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 - %% - %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6 - %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 - %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 - %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 - %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 - - %% payload = ServerHello - ServerHelloRecord = - hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6 - af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 - 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 - 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 - cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), - - {SHEncrypted, _} = - tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull), - ServerHelloRecord = iolist_to_binary(SHEncrypted), - - %% {server} derive write traffic keys for handshake data: - %% - %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 - %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 - %% - %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 - %% - %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e - %% e4 03 bc - %% - %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 - %% - %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30 - - %% PRK = SHSTrafficSecret - WriteKeyInfo = - hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"), - - WriteKey = - hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"), - - WriteIVInfo = - hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"), - - WriteIV = - hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"), - - Cipher = aes_128_gcm, %% TODO: get from ServerHello - - WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)), - %% TODO: remove hardcoded IV size - WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12), - - {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret), - - %% {server} construct an EncryptedExtensions handshake message: - %% - %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00 - %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c - %% 00 02 40 01 00 00 00 00 - %% - %% {server} construct a Certificate handshake message: - %% - %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 - %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 - %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 - %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 - %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 - %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 - %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f - %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 - %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c - %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 - %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 - %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 - %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 - %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 - %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 - %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a - %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea - %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 - %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be - %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b - %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 - %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00 - %% - %% {server} construct a CertificateVerify handshake message: - %% - %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c - %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a - %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 - %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b - %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 - %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a - %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3 - EncryptedExtensions = - hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00 - 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c - 00 02 40 01 00 00 00 00"), - - Certificate = - hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 - 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 - 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 - 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 - 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 - 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 - 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f - 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 - d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c - 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 - 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 - 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 - ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 - 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 - 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 - 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a - 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea - e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 - 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be - c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b - 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 - 96 12 29 ac 91 87 b4 2b 4d e1 00 00"), - - CertificateVerify = - hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c - 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a - b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 - 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b - be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 - 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a - 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"), - - %% {server} calculate finished "tls13 finished": - %% - %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 - %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 - %% - %% hash (0 octets): (empty) - %% - %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 - %% 64 00 - %% - %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 - %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8 - %% - %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 - %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18 - - %% PRK = SHSTrafficSecret - FInfo = - hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 - 64 00"), - - FExpanded = - hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 - c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"), - - FinishedVerifyData = - hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 - de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"), - - FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)), - - FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo), - - MessageHistory0 = [CertificateVerify, - Certificate, - EncryptedExtensions, - ServerHello, - ClientHello], - - FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0), - - %% {server} construct a Finished handshake message: - %% - %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb - %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 - %% 18 - FinishedHSBin = - hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb - dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 - 18"), - - FinishedHS = #finished{verify_data = FinishedVerifyData}, - - FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}), - FinishedHSBin = iolist_to_binary(FinishedIOList), - - %% {server} derive secret "tls13 c ap traffic": - %% - %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 - %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - %% - %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 - %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce - %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5 - - %% PRK = MasterSecret - CAPTHash = - hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - CAPTInfo = - hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 - 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - - CAPTrafficSecret = - hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce - 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"), - - CHSF = <<ClientHello/binary, - ServerHello/binary, - EncryptedExtensions/binary, - Certificate/binary, - CertificateVerify/binary, - FinishedHSBin/binary>>, - - CAPTHash = crypto:hash(HKDFAlgo, CHSF), - - CAPTInfo = - tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), - - CAPTrafficSecret = - tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), - - %% {server} derive secret "tls13 s ap traffic": - %% - %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 - %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - %% - %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 - %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 - %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 - - %% PRK = MasterSecret - %% hash = CAPTHash - SAPTInfo = - hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 - 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b - 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - - SAPTrafficSecret = - hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 - 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"), - - SAPTInfo = - tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), - - SAPTrafficSecret = - tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), - - %% {server} derive secret "tls13 exp master": - %% - %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 - %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 - %% - %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a - %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 - %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 - %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 - %% - %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 - %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50 - - %% PRK = MasterSecret - %% hash = CAPTHash - ExporterInfo = - hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 - 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 - 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), - - ExporterMasterSecret = - hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 - 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"), - - ExporterInfo = - tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), - - ExporterMasterSecret = - tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF), - - %% {server} derive write traffic keys for application data: - %% - %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32 - %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 - %% - %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 - %% - %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac - %% 92 e3 56 - %% - %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 - %% - %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84 - - %% PRK = SAPTrafficsecret - %% key info = WriteKeyInfo - %% iv info = WrtieIVInfo - SWKey = - hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"), - - SWIV = - hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"), - - {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret), - - %% {server} derive read traffic keys for handshake data: - %% - %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f - %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 - %% - %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 - %% - %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 - %% 25 8d 01 - %% - %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 - %% - %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f - - %% PRK = CHSTrafficsecret - %% key info = WriteKeyInfo - %% iv info = WrtieIVInfo - SRKey = - hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"), - - SRIV = - hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"), - - {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret). - - -tls13_finished_verify_data() -> - [{doc,"Test TLS 1.3 Finished message handling"}]. - -tls13_finished_verify_data(_Config) -> - ClientHello = - hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09 - 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 - 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 - e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 - f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01 - 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d - 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00 - 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00 - 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06 - 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72 - d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed - 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00 - 02 01 01 00 2b 00 03 02 03 04"), - - ServerHello = - hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79 - 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 - 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 - e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 - f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24 - 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b - 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 - 28 80 b6 15 00 2b 00 02 03 04"), - - EncryptedExtensions = - hexstr2bin("08 00 00 02 00 00"), - - Certificate = - hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30 - 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 - 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 - 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 - 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 - 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 - 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 - 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 - 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 - 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e - 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d - 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 - 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 - b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 - 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d - bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d - f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 - f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b - 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 - f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 - ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 - ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 - 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb - 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 - 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 - d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad - 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 - 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 - ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 - 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 - 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 - 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 - 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 - cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 - 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 - 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b - fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 - 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd - 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 - f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 - 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 - 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 - 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 - ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e - 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 - c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 - cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 - 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f - 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 - 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 - 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0 - 00 00"), - - CertificateVerify = - hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d - 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75 - 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8 - 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13 - 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73 - df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b - 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2 - 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84 - fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c - 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5 - 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79 - ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a - aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7 - 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b - 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36 - c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe - c7 e4 a7 30 f1 36 9f 9e"), - - BaseKey = - hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4 - 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"), - - VerifyData = - hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea - c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"), - - Messages = [CertificateVerify, - Certificate, - EncryptedExtensions, - ServerHello, - ClientHello], - - FinishedKey = tls_v1:finished_key(BaseKey, sha256), - VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages). - - -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}]), - 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), - 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: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], - {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_connection_information() -> - [{doc,"Test the API function ssl:connection_information/1 in a TLS 1.3 connection"}]. - -tls13_connection_information(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), - ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], - {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, connection_information_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), - - ssl_test_lib:check_result(Server, ok), - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -tls13_ssl_server_with_alpn_ssl_client() -> - [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client"}]. - -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), - - %% Set versions - ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, - {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|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_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"}]. - -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}]), - 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, no_application_protocol), - - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - - -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"}]. - -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], - - 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, no_application_protocol), - - ssl_test_lib:close(Server), - ssl_test_lib:close_port(Client). - -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"}]. - -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}]), - 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_ecdsa_ssl_server_openssl_client() -> - [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client using ECDSA certificates"}]. - -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), - - 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_ecdsa_ssl_server_ssl_client() -> - [{doc,"Test TLS 1.3 basic connection between ssl server and ssl client using ECDSA certificates"}]. - -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()}, - {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_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."}]. - -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), - - %% 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). - - %%-------------------------------------------------------------------- %% 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, - <<Integer:Bits/integer>> = B, - Integer. - -hexstr2bin(S) when is_binary(S) -> - hexstr2bin(S, <<>>); -hexstr2bin(S) -> - hexstr2bin(list_to_binary(S), <<>>). -%% -hexstr2bin(<<>>, Acc) -> - Acc; -hexstr2bin(<<C,T/binary>>, Acc) when C =:= 32; %% SPACE - C =:= 10; %% LF - C =:= 13 -> %% CR - hexstr2bin(T, Acc); -hexstr2bin(<<X,Y,T/binary>>, Acc) -> - I = hex2int(X) * 16 + hex2int(Y), - hexstr2bin(T, <<Acc/binary,I>>). - -hex2int(C) when $0 =< C, C =< $9 -> - C - $0; -hex2int(C) when $A =< C, C =< $F -> - C - $A + 10; -hex2int(C) when $a =< C, C =< $f -> - C - $a + 10. diff --git a/lib/ssl/test/ssl_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 = <<ExtSize:16/unsigned-big-integer, SNI/binary>>, - 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_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_SUITE.erl index 878e983bb9..8a76a3a82b 100644 --- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_npn_SUITE.erl @@ -19,7 +19,7 @@ %% %% --module(ssl_npn_handshake_SUITE). +-module(ssl_npn_SUITE). %% Note: This directive should only be used in test suites. -compile(export_all). diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index 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 = <<DataReceived/binary, Data/binary>>, - ct:log("New Data: ~p", [NewData]), - case client_read_check(DataExpected, NewData) of - ok -> - ok; - _ -> - client_check_result(Port, DataExpected, NewData) - end - after 20000 -> - ct:fail({"Time out on openSSL Client", {expected, DataExpected}, - {got, DataReceived}}) - end. -client_check_result(Port, DataExpected) -> - client_check_result(Port, DataExpected, <<"">>). - -send_and_hostname(SSLSocket) -> - ssl:send(SSLSocket, "OK"), - case ssl:connection_information(SSLSocket, [sni_hostname]) of - {ok, []} -> - undefined; - {ok, [{sni_hostname, Hostname}]} -> - Hostname - end. - -erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) -> - 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(<<?BYTE(0)>>, 32), + IKM = binary:copy(<<?BYTE(0)>>, 32), + EarlySecret = + hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c + e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"), + + {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}), + + %% {client} create an ephemeral x25519 key pair: + %% + %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78 + %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05 + %% + %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d + %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c + CPublicKey = + hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d + ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"), + + %% {server} create an ephemeral x25519 key pair: + %% + %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 + %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e + %% + %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 + %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f + SPrivateKey = + hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 + 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"), + + SPublicKey = + hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 + 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"), + + %% {server} construct a ServerHello handshake message: + %% + %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 + %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e + %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 + %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 + %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 + ServerHello = + hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60 + dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e + d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 + 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 + dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), + + %% {server} derive secret for handshake "tls13 derived": + %% + %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2 + %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a + %% + %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 + %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 + %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 + %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba + %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba + Hash = + hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 + 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), + + Hash = crypto:hash(HKDFAlgo, <<>>), + + Info = + hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 + 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 + 64 9b 93 4c a4 95 99 1b 78 52 b8 55"), + + Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)), + + Expanded = + hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba + b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"), + + Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo), + + %% {server} extract secret "handshake": + %% + %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97 + %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba + %% + %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d + %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d + %% + %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b + %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + + %% salt = Expanded + HandshakeIKM = + hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d + 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"), + + HandshakeSecret = + hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b + 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"), + + HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519), + + {handshake_secret, HandshakeSecret} = + tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM, + {early_secret, EarlySecret}), + + %% {server} derive secret "tls13 c hs traffic": + %% + %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 + %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + %% + %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed + %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 + %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e + %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 + + %% PRK = HandshakeSecret + CHSTHash = + hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed + d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), + + CHSTInfo = + hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72 + 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), + + CHSTrafficSecret = + hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e + 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"), + + CHSH = <<ClientHello/binary,ServerHello/binary>>, + CHSTHash = crypto:hash(HKDFAlgo, CHSH), + CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), + + CHSTrafficSecret = + tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), + + %% {server} derive secret "tls13 s hs traffic": + %% + %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 + %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + %% + %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed + %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 + %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8 + %% + %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d + %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 + + %% PRK = HandshakeSecret + %% hash = CHSTHash + SHSTInfo = + hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72 + 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 + ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"), + + SHSTrafficSecret = + hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d + 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"), + + SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)), + + SHSTrafficSecret = + tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH), + + + %% {server} derive secret for master "tls13 derived": + %% + %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 + %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac + %% + %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 + %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64 + %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 + %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55 + %% + %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 + %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 + + %% PRK = HandshakeSecret + %% hash = Hash + %% info = Info + MasterDeriveSecret = + hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 + 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"), + + MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo), + + %% {server} extract secret "master": + %% + %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5 + %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 + %% + %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + %% + %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a + %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + + %% salt = MasterDeriveSecret + %% IKM = IKM + MasterSecret = + hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a + 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"), + + {master_secret, MasterSecret} = + tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}), + + %% {server} send handshake record: + %% + %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e + %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2 + %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11 + %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 + %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 + %% + %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6 + %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 + %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 + %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 + %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 + + %% payload = ServerHello + ServerHelloRecord = + hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6 + af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 + 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 + 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 + cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"), + + {SHEncrypted, _} = + tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull), + ServerHelloRecord = iolist_to_binary(SHEncrypted), + + %% {server} derive write traffic keys for handshake data: + %% + %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 + %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e + %% e4 03 bc + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30 + + %% PRK = SHSTrafficSecret + WriteKeyInfo = + hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"), + + WriteKey = + hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"), + + WriteIVInfo = + hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"), + + WriteIV = + hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"), + + Cipher = aes_128_gcm, %% TODO: get from ServerHello + + WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)), + %% TODO: remove hardcoded IV size + WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12), + + {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret), + + %% {server} construct an EncryptedExtensions handshake message: + %% + %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00 + %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c + %% 00 02 40 01 00 00 00 00 + %% + %% {server} construct a Certificate handshake message: + %% + %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 + %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 + %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 + %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 + %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 + %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 + %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f + %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 + %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c + %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 + %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 + %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 + %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 + %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 + %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 + %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a + %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea + %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 + %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be + %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b + %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 + %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00 + %% + %% {server} construct a CertificateVerify handshake message: + %% + %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c + %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a + %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 + %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b + %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 + %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a + %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3 + EncryptedExtensions = + hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00 + 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c + 00 02 40 01 00 00 00 00"), + + Certificate = + hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 + 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 + 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 + 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 + 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 + 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 + 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f + 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 + d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c + 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 + 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 + 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 + ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 + 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 + 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 + 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a + 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea + e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 + 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be + c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b + 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 + 96 12 29 ac 91 87 b4 2b 4d e1 00 00"), + + CertificateVerify = + hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c + 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a + b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 + 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b + be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 + 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a + 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"), + + %% {server} calculate finished "tls13 finished": + %% + %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 + %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 + %% + %% hash (0 octets): (empty) + %% + %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 + %% 64 00 + %% + %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 + %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8 + %% + %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 + %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18 + + %% PRK = SHSTrafficSecret + FInfo = + hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65 + 64 00"), + + FExpanded = + hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 + c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"), + + FinishedVerifyData = + hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 + de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"), + + FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)), + + FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo), + + MessageHistory0 = [CertificateVerify, + Certificate, + EncryptedExtensions, + ServerHello, + ClientHello], + + FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0), + + %% {server} construct a Finished handshake message: + %% + %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb + %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 + %% 18 + FinishedHSBin = + hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb + dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 + 18"), + + FinishedHS = #finished{verify_data = FinishedVerifyData}, + + FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}), + FinishedHSBin = iolist_to_binary(FinishedIOList), + + %% {server} derive secret "tls13 c ap traffic": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 + %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce + %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5 + + %% PRK = MasterSecret + CAPTHash = + hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + CAPTInfo = + hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 + 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + CAPTrafficSecret = + hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce + 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"), + + CHSF = <<ClientHello/binary, + ServerHello/binary, + EncryptedExtensions/binary, + Certificate/binary, + CertificateVerify/binary, + FinishedHSBin/binary>>, + + CAPTHash = crypto:hash(HKDFAlgo, CHSF), + + CAPTInfo = + tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + CAPTrafficSecret = + tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive secret "tls13 s ap traffic": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 + %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 + %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 + + %% PRK = MasterSecret + %% hash = CAPTHash + SAPTInfo = + hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 + 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + SAPTrafficSecret = + hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 + 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"), + + SAPTInfo = + tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + SAPTrafficSecret = + tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive secret "tls13 exp master": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 + %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 + %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 + %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50 + + %% PRK = MasterSecret + %% hash = CAPTHash + ExporterInfo = + hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 + 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 + 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + ExporterMasterSecret = + hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 + 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"), + + ExporterInfo = + tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + ExporterMasterSecret = + tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive write traffic keys for application data: + %% + %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32 + %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac + %% 92 e3 56 + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84 + + %% PRK = SAPTrafficsecret + %% key info = WriteKeyInfo + %% iv info = WrtieIVInfo + SWKey = + hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"), + + SWIV = + hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"), + + {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret), + + %% {server} derive read traffic keys for handshake data: + %% + %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f + %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 + %% 25 8d 01 + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f + + %% PRK = CHSTrafficsecret + %% key info = WriteKeyInfo + %% iv info = WrtieIVInfo + SRKey = + hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"), + + SRIV = + hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"), + + {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret). + +%%-------------------------------------------------------------------- +finished_verify_data() -> + [{doc,"Test TLS 1.3 Finished message handling"}]. + +finished_verify_data(_Config) -> + ClientHello = + hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09 + 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 + 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 + e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 + f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01 + 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d + 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00 + 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00 + 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06 + 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72 + d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed + 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00 + 02 01 01 00 2b 00 03 02 03 04"), + + ServerHello = + hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79 + 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 + 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 + e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 + f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24 + 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b + 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 + 28 80 b6 15 00 2b 00 02 03 04"), + + EncryptedExtensions = + hexstr2bin("08 00 00 02 00 00"), + + Certificate = + hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30 + 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 + 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 + 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 + 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 + 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 + 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 + 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 + 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 + 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e + 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d + 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 + 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 + b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 + 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d + bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d + f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 + f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b + 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 + f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 + ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 + ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 + 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb + 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 + 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 + d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad + 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 + 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 + ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 + 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 + 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 + 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 + 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 + cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 + 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 + 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b + fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 + 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd + 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 + f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 + 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 + 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 + 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 + ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e + 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 + c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 + cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 + 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f + 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 + 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 + 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0 + 00 00"), + + CertificateVerify = + hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d + 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75 + 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8 + 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13 + 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73 + df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b + 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2 + 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84 + fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c + 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5 + 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79 + ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a + aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7 + 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b + 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36 + c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe + c7 e4 a7 30 f1 36 9f 9e"), + + BaseKey = + hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4 + 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"), + + VerifyData = + hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea + c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"), + + Messages = [CertificateVerify, + Certificate, + EncryptedExtensions, + ServerHello, + ClientHello], + + FinishedKey = tls_v1:finished_key(BaseKey, sha256), + VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- + +hexstr2int(S) -> + B = hexstr2bin(S), + Bits = size(B) * 8, + <<Integer:Bits/integer>> = B, + Integer. + +hexstr2bin(S) when is_binary(S) -> + hexstr2bin(S, <<>>); +hexstr2bin(S) -> + hexstr2bin(list_to_binary(S), <<>>). +%% +hexstr2bin(<<>>, Acc) -> + Acc; +hexstr2bin(<<C,T/binary>>, Acc) when C =:= 32; %% SPACE + C =:= 10; %% LF + C =:= 13 -> %% CR + hexstr2bin(T, Acc); +hexstr2bin(<<X,Y,T/binary>>, Acc) -> + I = hex2int(X) * 16 + hex2int(Y), + hexstr2bin(T, <<Acc/binary,I>>). + +hex2int(C) when $0 =< C, C =< $9 -> + C - $0; +hex2int(C) when $A =< C, C =< $F -> + C - $A + 10; +hex2int(C) when $a =< C, C =< $f -> + C - $a + 10. diff --git a/lib/ssl/test/tls_1_3_version_SUITE.erl b/lib/ssl/test/tls_1_3_version_SUITE.erl new file mode 100644 index 0000000000..f0b224d4e5 --- /dev/null +++ b/lib/ssl/test/tls_1_3_version_SUITE.erl @@ -0,0 +1,153 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(tls_1_3_version_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [ + {group, 'tlsv1.3'} + ]. + +groups() -> + [ + {'tlsv1.3', [], cert_groups()}, + {rsa, [], tests()}, + {ecdsa, [], tests()} + ]. + +cert_groups() -> + [{group, rsa}, + {group, ecdsa}]. + +tests() -> + [tls13_client_tls12_server, + tls13_client_with_ext_tls12_server, + tls12_client_tls13_server]. + +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + [{client_type, erlang}, {server_type, erlang} | + Config] + catch _:_ -> + {skip, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + ssl:stop(), + application:stop(crypto). + +init_per_group(rsa, Config0) -> + Config = ssl_test_lib:make_rsa_cert(Config0), + COpts = proplists:get_value(client_rsa_opts, Config), + SOpts = proplists:get_value(server_rsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; +init_per_group(ecdsa, Config0) -> + PKAlg = crypto:supports(public_keys), + case lists:member(ecdsa, PKAlg) andalso + (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of + true -> + Config = ssl_test_lib:make_ecdsa_cert(Config0), + COpts = proplists:get_value(client_ecdsa_opts, Config), + SOpts = proplists:get_value(server_ecdsa_opts, Config), + [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | + lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))]; + false -> + {skip, "Missing EC crypto support"} + end; +init_per_group(GroupName, Config) -> + ssl_test_lib:clean_tls_version(Config), + case ssl_test_lib:is_tls_version(GroupName) andalso + ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName, Config); + _ -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl:start(), + Config; + false -> + {skip, "Missing crypto support"} + end + end. + +end_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:clean_tls_version(Config); + false -> + Config + end. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +tls13_client_tls12_server() -> + [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}]. + +tls13_client_tls12_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls13_client_with_ext_tls12_server() -> + [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when " + "client has TLS 1.3 specsific extensions"}]. + +tls13_client_with_ext_tls12_server(Config) -> + ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), + + ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0], + ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}, + {signature_algs_cert, [ecdsa_secp384r1_sha384, + ecdsa_secp256r1_sha256, + rsa_pss_rsae_sha256, + rsa_pkcs1_sha256, + {sha256,rsa},{sha256,dsa}]}|ClientOpts0], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls12_client_tls13_server() -> + [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}]. + +tls12_client_tls13_server(Config) when is_list(Config) -> + ClientOpts = [{versions, + ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)], + ServerOpts = [{versions, + ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)], + ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + |