File 4621-ssl-Add-missing-state-update.patch of Package erlang
From 530c88c233d5e59438b174fcf3d578d2eae1185f Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Wed, 8 Dec 2021 11:58:05 +0100
Subject: [PATCH 1/2] ssl: Add missing state update
Update server handshake environment to reflect the SNI
value also when it did not result in any new options being used.
Closes #4450
Test cases also needed to be updated to perform tests properly.
The test cases seemed to be modeled after implementation
behavior rather then the expected behavior.
---
lib/ssl/src/ssl_gen_statem.erl | 14 +-
lib/ssl/test/openssl_sni_SUITE.erl | 261 +++++++++++++++--------------
lib/ssl/test/ssl_sni_SUITE.erl | 113 +++++++------
lib/ssl/test/ssl_test_lib.erl | 74 ++++++--
4 files changed, 268 insertions(+), 194 deletions(-)
diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl
index 3bbb820ef7..ddd529d032 100644
--- a/lib/ssl/src/ssl_gen_statem.erl
+++ b/lib/ssl/src/ssl_gen_statem.erl
@@ -1233,12 +1233,18 @@ is_hostname_recognized(_, _) ->
handle_sni_hostname(Hostname,
#state{static_env = #static_env{role = Role} = InitStatEnv0,
handshake_env = HsEnv,
- connection_env = CEnv} = State0) ->
- NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname),
+ connection_env = CEnv,
+ ssl_options = Opts} = State0) ->
+ NewOptions = update_ssl_options_from_sni(Opts, Hostname),
case NewOptions of
undefined ->
- State0;
- _ ->
+ case maps:get(server_name_indication, Opts) of
+ disable when Role == client->
+ State0;
+ _ ->
+ State0#state{handshake_env = HsEnv#handshake_env{sni_hostname = Hostname}}
+ end;
+ _ ->
{ok, #{cert_db_ref := Ref,
cert_db_handle := CertDbHandle,
fileref_db_handle := FileRefHandle,
diff --git a/lib/ssl/test/openssl_sni_SUITE.erl b/lib/ssl/test/openssl_sni_SUITE.erl
index 2ab553d335..4e25ddb467 100644
--- a/lib/ssl/test/openssl_sni_SUITE.erl
+++ b/lib/ssl/test/openssl_sni_SUITE.erl
@@ -33,12 +33,12 @@
end_per_testcase/2]).
%% Testcases
--export([erlang_server_openssl_client_sni_match/1,
- erlang_server_openssl_client_sni_match_fun/1,
- erlang_server_openssl_client_sni_no_match/1,
- erlang_server_openssl_client_sni_no_match_fun/1,
- erlang_server_openssl_client_sni_no_header/1,
- erlang_server_openssl_client_sni_no_header_fun/1
+-export([sni_match/1,
+ sni_match_fun/1,
+ sni_no_match/1,
+ sni_no_match_fun/1,
+ sni_no_header/1,
+ sni_no_header_fun/1
]).
%% Apply exports
@@ -60,10 +60,9 @@ all() ->
[{group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
- {group, 'tlsv1'}
- %% Seems broken in openssl
- %%{group, 'dtlsv1.2'},
- %%{group, 'dtlsv1'}
+ {group, 'tlsv1'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
];
false ->
[{group, 'tlsv1.3'},
@@ -78,10 +77,9 @@ groups() ->
[{'tlsv1.3', [], sni_tests()},
{'tlsv1.2', [], sni_tests()},
{'tlsv1.1', [], sni_tests()},
- {'tlsv1', [], sni_tests()}
- %% Seems broken in openssl
- %%{'dtlsv1.2', [], sni_tests()},
- %%{'dtlsv1', [], sni_tests()}
+ {'tlsv1', [], sni_tests()},
+ {'dtlsv1.2', [], sni_tests()},
+ {'dtlsv1', [], sni_tests()}
];
false ->
[{'tlsv1.3', [], sni_tests()},
@@ -92,45 +90,37 @@ groups() ->
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].
+ [sni_match,
+ sni_match_fun,
+ sni_no_match,
+ sni_no_match_fun,
+ sni_no_header,
+ sni_no_header_fun].
init_per_suite(Config0) ->
- case os:find_executable("openssl") of
- false ->
- {skip, "Openssl not found"};
- _ ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
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
+ Config1 ->
+ %% Needed by version interop test in ssl_test_lib
+ Config = ssl_test_lib:make_rsa_cert(Config1),
+ ssl_test_lib:clean_start(),
+ Hostname = net_adm:localhost(),
+ {#{server_config := ServerConf,
+ client_config := ClientConf},
+ #{server_config := LServerConf,
+ client_config := LClientConf}} = ssl_test_lib:make_rsa_sni_configs(),
+ [{client_opts, ClientConf}, {client_local_opts, LClientConf},
+ {sni_server_opts, [{sni_hosts, [{Hostname, ServerConf}]} | LServerConf]} | Config]
end
+ catch _:_ ->
+ {skip, "Crypto did not start"}
end.
+
end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto),
@@ -153,75 +143,65 @@ end_per_testcase(_, 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").
+sni_no_header(Config) when is_list(Config) ->
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ ServerOptions = ssl_test_lib:ssl_options(proplists:get_value(sni_server_opts, Config), Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, disable} |
+ proplists:get_value(client_local_opts, Config)], Config),
+ case proplists:get_value(openssl_disable, Config) of
+ true ->
+ sni_test(ServerNode, ServerOptions, ClientOptions, Config);
+ false ->
+ {skip, no_openssl_sni_disable_flag}
+ end.
-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").
+sni_no_header_fun(Config) when is_list(Config) ->
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ [{sni_hosts, ServerSNIConf}| DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, []) end,
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config) ++ [{sni_fun, SNIFun}],
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, disable} |
+ proplists:get_value(client_local_opts, Config)], Config),
+ case proplists:get_value(openssl_disable, Config) of
+ true ->
+ sni_test(ServerNode, ServerOptions, ClientOptions, Config);
+ false ->
+ {skip, no_openssl_sni_disable_flag}
+ end.
-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").
+sni_match(Config) when is_list(Config) ->
+ {_, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ ServerOptions = ssl_test_lib:ssl_options(proplists:get_value(sni_server_opts, Config), Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_opts, Config)], Config),
+ sni_test(ServerNode, ServerOptions, ClientOptions, Config).
-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").
+sni_match_fun(Config) when is_list(Config) ->
+ {_, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ [{sni_hosts, ServerSNIConf}| DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config) ++ [{sni_fun, SNIFun}],
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_opts, Config)], Config),
+ sni_test(ServerNode, ServerOptions, ClientOptions, Config).
+sni_no_match(Config) when is_list(Config) ->
+ {_, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ [_ | DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_opts, Config)], Config),
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config),
+ sni_test(ServerNode, ServerOptions, ClientOptions, Config).
-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.
+sni_no_match_fun(Config) when is_list(Config) ->
+ {_, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ [{sni_hosts, _}| DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_local_opts, Config)], Config),
+ sni_test(ServerNode, ServerOptions, ClientOptions, Config).
-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).
%%--------------------------------------------------------------------
%% Callback functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -236,25 +216,60 @@ send_and_hostname(SSLSocket) ->
%%--------------------------------------------------------------------
%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
-openssl_client_args(Version, Hostname, Port) ->
- ssl_test_lib:maybe_force_ipv4(["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)]).
+sni_test(ServerNode, ServerOptions0, ClientOptions, Config) ->
+ %% Test Erlang server SNI handling with OpenSSL client
+ Version = ssl_test_lib:protocol_version(Config),
+ ServerOptions = maybe_add_sigalgs(Version, ServerOptions0),
+
+
+ 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),
+
+ SNIHostname = case proplists:get_value(server_name_indication, ClientOptions) of
+ disable ->
+ undefined;
+ Name ->
+ Name
+ end,
+
+ Sigalgs = maybe_add_openssl_sigalgs(Version),
+ ClientPort = ssl_test_lib:start_client(openssl,
+ Sigalgs ++ [{port, Port},
+ {server_name, SNIHostname} |
+ ClientOptions],
+ Config),
+
+ ssl_test_lib:check_result(Server, SNIHostname),
+ ssl_test_lib:close_port(ClientPort),
+ ssl_test_lib:close(Server),
+ ok.
+
+maybe_add_sigalgs(Version, ServerOptions) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2' ->
+ [{signature_algs, [rsa_pss_rsae_sha512,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha256]} | ServerOptions];
+maybe_add_sigalgs(_, ServerOptions) ->
+ ServerOptions.
-openssl_client_args(Version, Hostname, Port, ServerName) ->
- ssl_test_lib:maybe_force_ipv4(["s_client", "-connect", Hostname ++ ":" ++
- integer_to_list(Port),
- ssl_test_lib:version_flag(Version), "-servername", ServerName]).
+maybe_add_openssl_sigalgs(Version) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2' ->
+ [{sigalgs, "rsa_pss_rsae_sha512:rsa_pss_rsae_sha384:rsa_pss_rsae_sha256"}];
+maybe_add_openssl_sigalgs(_) ->
+ [].
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
+ HelpText = ssl_test_lib:portable_cmd("openssl", ["s_client", "--help"]),
+ case string:str(HelpText, "-servername") of
+ 0 ->
+ {skip, "Current openssl doesn't support SNI"};
+ _ ->
+ case string:str(HelpText, "-noservername") of
0 ->
- {skip, "Current openssl doesn't support SNI"};
+ [{openssl_disable, false} | Config];
_ ->
- Config
- end;
- false ->
- {skip, "Current openssl doesn't support SNI or extension handling is flawed"}
+ [{openssl_disable, true} | Config]
+ end
end.
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index c855f154f5..247ab7e4cc 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -106,18 +106,16 @@ init_per_suite(Config0) ->
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]
+ Hostname = net_adm:localhost(),
+ {#{server_config := ServerConf,
+ client_config := ClientConf},
+ #{server_config := LServerConf,
+ client_config := LClientConf}} = ssl_test_lib:make_rsa_sni_configs(),
+ %% RSA certs files needed by *dot cases
+ ssl_test_lib:make_rsa_cert([{client_opts, ClientConf},
+ {client_local_opts, LClientConf},
+ {sni_server_opts, [{sni_hosts, [{Hostname, ServerConf}]} | LServerConf]}
+ | Config0])
catch _:_ ->
{skip, "Crypto did not start"}
end.
@@ -150,22 +148,52 @@ end_per_testcase(_TestCase, Config) ->
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
no_sni_header(Config) ->
- run_handshake(Config, undefined, undefined, "server Peer cert").
+ {ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ ServerOptions = ssl_test_lib:ssl_options(proplists:get_value(sni_server_opts, Config), Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, disable} |
+ proplists:get_value(client_local_opts, Config)], Config),
+ basic_sni_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName, undefined).
no_sni_header_fun(Config) ->
- run_sni_fun_handshake(Config, undefined, undefined, "server Peer cert").
+ {ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ [{sni_hosts, ServerSNIConf}| DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, []) end,
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config) ++ [{sni_fun, SNIFun}],
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, disable} |
+ proplists:get_value(client_local_opts, Config)], Config),
+ basic_sni_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName, undefined).
sni_match(Config) ->
- run_handshake(Config, "a.server", "a.server", "server Peer cert").
+ {ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ ServerOptions = ssl_test_lib:ssl_options(proplists:get_value(sni_server_opts, Config), Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_opts, Config)], Config),
+ basic_sni_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName, HostName).
sni_match_fun(Config) ->
- run_sni_fun_handshake(Config, "a.server", "a.server", "server Peer cert").
+ {ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ [{sni_hosts, ServerSNIConf}| DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config) ++ [{sni_fun, SNIFun}],
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_opts, Config)], Config),
+ basic_sni_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName, HostName).
sni_no_match(Config) ->
- run_handshake(Config, "c.server", undefined, "server Peer cert").
+ {ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ [_ | DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_opts, Config)], Config),
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config),
+ basic_sni_alert_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName).
sni_no_match_fun(Config) ->
- run_sni_fun_handshake(Config, "c.server", undefined, "server Peer cert").
+ {ClientNode, ServerNode, HostName} = ssl_test_lib:run_where(Config),
+ [{sni_hosts, _}| DefaultConf] = proplists:get_value(sni_server_opts, Config),
+ ServerOptions = ssl_test_lib:ssl_options(DefaultConf, Config),
+ ClientOptions = ssl_test_lib:ssl_options([{server_name_indication, HostName} |
+ proplists:get_value(client_local_opts, Config)], Config),
+ basic_sni_alert_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName).
dns_name(Config) ->
Hostname = "OTP.test.server",
@@ -415,57 +443,28 @@ recv_and_certificate(SSLSocket) ->
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
%%--------------------------------------------------------------------
-run_sni_fun_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- 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 = ssl_test_lib:ssl_options(server_rsa_opts, Config) ++ [{sni_fun, SNIFun}],
- ClientOptions =
- case SNIHostname of
- undefined ->
- ssl_test_lib:ssl_options(client_rsa_opts, Config);
- _ ->
- [{server_name_indication, SNIHostname}] ++ ssl_test_lib:ssl_options(client_rsa_opts, Config)
- end,
- ct:log("Options: ~p", [[ServerOptions, ClientOptions]]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+basic_sni_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName, Expected) ->
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),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname}, {from, self()},
+ {host, HostName}, {from, self()},
{mfa, {?MODULE, recv_and_certificate, []}},
- {options, ClientOptions}]),
- ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN),
+ {options, [{verify, verify_peer} | ClientOptions]}]),
+ ssl_test_lib:check_result(Server, Expected, Client, "server Peer cert"),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-run_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- 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) ++ ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOptions =
- case SNIHostname of
- undefined ->
- ssl_test_lib:ssl_options(client_rsa_opts, Config);
- _ ->
- [{server_name_indication, SNIHostname}] ++ ssl_test_lib:ssl_options(client_rsa_opts, Config)
- end,
- ct:log("Options: ~p", [[ServerOptions, ClientOptions]]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+basic_sni_alert_test(ServerNode, ServerOptions, ClientNode, ClientOptions, HostName) ->
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
+ {from, self()}, {mfa, {ssl_test_lib, no_result, []}},
{options, ServerOptions}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname}, {from, self()},
- {mfa, {?MODULE, recv_and_certificate, []}},
- {options, ClientOptions}]),
- ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, HostName}, {from, self()},
+ {options, [{verify, verify_peer} | ClientOptions]}]),
+ ssl_test_lib:check_client_alert(Client, handshake_failure),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 778913c4b9..fe52b60f98 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -172,6 +172,7 @@
make_ec_cert_chains/5,
make_rsa_1024_cert/1,
make_rsa_pss_pem/4,
+ make_rsa_sni_configs/0,
gen_conf/4,
make_mix_cert/1,
default_cert_chain_conf/0,
@@ -1519,6 +1520,34 @@ make_rsa_pss_pem(Alg, _UserConf, Config, Suffix) ->
#{server_config => SConf,
client_config => CConf}.
+make_rsa_sni_configs() ->
+ Sha = appropriate_sha(crypto:supports()),
+ HostName = net_adm:localhost(),
+ HostConf = make_sni_conf(HostName, Sha),
+ LocalHostConf = make_sni_conf("localhost", Sha),
+ {HostConf, LocalHostConf}.
+
+make_sni_conf(HostName, Sha) ->
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [{digest, Sha},
+ {key, hardcode_rsa_key(1)}],
+ intermediates => [[{digest, Sha},
+ {key, hardcode_rsa_key(2)}]],
+ peer => [{digest, Sha},
+ {extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, HostName}],
+ critical = false}]},
+ {key, hardcode_rsa_key(3)}
+ ]},
+ client_chain =>
+ #{root => [{digest, Sha},
+ {key, hardcode_rsa_key(4)}],
+ intermediates => [[{digest, Sha},
+ {key, hardcode_rsa_key(5)}]],
+ peer => [{digest, Sha},
+ {key, hardcode_rsa_key(6)}]}}).
+
gen_conf(ClientChainType, ServerChainType, UserClient, UserServer) ->
gen_conf(ClientChainType, ServerChainType, UserClient, UserServer, ?DEFAULT_CURVE).
%%
@@ -2113,6 +2142,7 @@ start_client(openssl, Port, ClientOpts, Config) ->
MaxFragLen = openssl_maxfag_option(proplists:get_value(maxfrag, ClientOpts, false)),
SessionArgs = proplists:get_value(session_args, ClientOpts, []),
HostName = proplists:get_value(hostname, ClientOpts, net_adm:localhost()),
+ SNI = openssl_sni(proplists:get_value(server_name_indication, ClientOpts, undefined)),
Debug = openssl_debug_options(),
Exe = "openssl",
@@ -2120,20 +2150,37 @@ start_client(openssl, Port, ClientOpts, Config) ->
undefined ->
["s_client",
"-verify", "2",
- "-connect", hostname_format(HostName) ++ ":" ++ integer_to_list(Port), cipher_flag(Version),
+ "-connect", hostname_format(HostName) ++ ":" ++ integer_to_list(Port),
+ cipher_flag(Version),
ciphers(Ciphers, Version),
- version_flag(Version)]
- ++ CertArgs ++ SigAlgs ++ AlpnArgs ++ NpnArgs ++ Reconnect ++ MaxFragLen ++ SessionArgs
- ++ Debug;
+ version_flag(Version)] ++
+ CertArgs ++
+ SigAlgs ++
+ SNI ++
+ AlpnArgs ++
+ NpnArgs ++
+ Reconnect ++
+ MaxFragLen ++
+ SessionArgs ++
+ Debug;
Group ->
["s_client",
"-verify", "2",
- "-connect", hostname_format(HostName) ++ ":" ++ integer_to_list(Port), cipher_flag(Version),
- ciphers(Ciphers, Version), "-groups", Group,
- version_flag(Version)]
- ++ CertArgs ++ SigAlgs ++ AlpnArgs ++ NpnArgs ++ Reconnect ++ MaxFragLen ++ SessionArgs
- ++ Debug
- end,
+ "-connect", hostname_format(HostName) ++ ":" ++ integer_to_list(Port),
+ cipher_flag(Version),
+ ciphers(Ciphers, Version),
+ "-groups", Group,
+ version_flag(Version)] ++
+ CertArgs ++
+ SigAlgs ++
+ SNI ++
+ AlpnArgs ++
+ NpnArgs ++
+ Reconnect ++
+ MaxFragLen ++
+ SessionArgs ++
+ Debug
+ end,
Args = maybe_force_ipv4(Args0),
OpenSslPort = portable_open_port(Exe, Args),
true = port_command(OpenSslPort, "Hello world"),
@@ -2263,6 +2310,13 @@ openssl_maxfag_option(false) ->
openssl_maxfag_option(Int) ->
["-maxfraglen", integer_to_list(Int)].
+openssl_sni(undefined) ->
+ [];
+openssl_sni(disable) ->
+ ["-noservername"];
+openssl_sni(ServerName) ->
+ ["-servername", ServerName].
+
openssl_debug_options() ->
["-msg", "-debug"].
%%
--
2.31.1