WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 2858c21

Browse files
gomoripetimergify[bot]
authored andcommitted
Trust store: Overwrite conflicting ssl options and ensure cacerts set
`lists:keymerge/3` was used to merge required options into user provided ssl options, which assumes the input lists are sorted. No matter if the intention was to preserve user provided options or overwrite them in case of conflict, without sorting, the outcome was unpredictable. It is also somewhat surprising to those who are used to the behaviour of `proplists:get_value` that the ssl app (at least since OTP 26) takes the last value not the first when same key with multiple values are provided. This commit makes sure the input lists are ordered. Also changes the behaviour of the plugin that all keys used by the plugin overwrite user provided values (`fail_if_no_peer_cert`, `partial_chain`, `verify`, `verify_fun`) Also if the user did not provide a `cacerts` or `cacertfile` option, an empty `cacerts` list is added, as ssl config validation requires it in case `verify_peer` is enabled. (cherry picked from commit 543720f)
1 parent 1d757e7 commit 2858c21

File tree

2 files changed

+74
-18
lines changed

2 files changed

+74
-18
lines changed

deps/rabbitmq_trust_store/src/rabbit_trust_store_app.erl

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,25 @@ edit(Options) ->
5656
"It will be overwritten by the plugin.", [Val]),
5757
ok
5858
end,
59+
CaCerts =
60+
case lists:keymember(cacerts, 1, Options) orelse
61+
lists:keymember(cacertfile, 1, Options) of
62+
true ->
63+
[];
64+
false ->
65+
%% if verify_peer is enabled, then the ssl app
66+
%% requires a cacerts option to be set even if it is
67+
%% not used, as we rely on verify_fun instead.
68+
[{cacerts, []}]
69+
end,
5970
%% Only enter those options neccessary for this application.
60-
lists:keymerge(1, required_options(),
61-
[{verify_fun, {delegate(), continue}},
62-
{partial_chain, fun partial_chain/1} | Options]).
71+
lists:ukeymerge(
72+
1,
73+
lists:sort(CaCerts ++
74+
[{verify_fun, {delegate(), continue}},
75+
{partial_chain, fun partial_chain/1}
76+
|required_options()]),
77+
lists:sort(Options)).
6378

6479
delegate() -> fun rabbit_trust_store:whitelisted/3.
6580

deps/rabbitmq_trust_store/test/system_SUITE.erl

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
all() ->
3232
[
3333
{group, http_provider_tests},
34-
{group, file_provider_tests}
34+
{group, file_provider_tests},
35+
{group, required_options}
3536
].
3637

3738
groups() ->
@@ -58,7 +59,10 @@ groups() ->
5859
enabled_provider_adds_cerificates |
5960
CommonTests
6061
]},
61-
{http_provider_tests, [], CommonTests}
62+
{http_provider_tests, [], CommonTests},
63+
{required_options, [], [invasive_SSL_option_change,
64+
whitelisted_certificate_accepted_from_AMQP_client_without_server_side_cacerts
65+
]}
6266
].
6367

6468
suite() ->
@@ -68,13 +72,14 @@ suite() ->
6872
%% Testsuite setup/teardown.
6973
%% -------------------------------------------------------------------
7074

71-
set_up_node(Config) ->
75+
set_up_node(Config, ExtraSteps) ->
7276
rabbit_ct_helpers:log_environment(),
7377
Config1 = rabbit_ct_helpers:set_config(Config, [
7478
{rmq_nodename_suffix, ?MODULE},
7579
{rmq_extra_tcp_ports, [tcp_port_amqp_tls_extra]}
7680
]),
7781
rabbit_ct_helpers:run_setup_steps(Config1,
82+
ExtraSteps ++
7883
rabbit_ct_broker_helpers:setup_steps() ++
7984
rabbit_ct_client_helpers:setup_steps()).
8085

@@ -84,7 +89,7 @@ tear_down_node(Config) ->
8489
rabbit_ct_broker_helpers:teardown_steps()).
8590

8691
init_per_group(file_provider_tests, Config) ->
87-
case set_up_node(Config) of
92+
case set_up_node(Config, []) of
8893
{skip, _} = Error -> Error;
8994
Config1 ->
9095
WhitelistDir = filename:join([?config(rmq_certsdir, Config1),
@@ -99,7 +104,7 @@ init_per_group(file_provider_tests, Config) ->
99104
end;
100105

101106
init_per_group(http_provider_tests, Config) ->
102-
case set_up_node(Config) of
107+
case set_up_node(Config, []) of
103108
{skip, _} = Error -> Error;
104109
Config1 ->
105110
WhitelistDir = filename:join([?config(rmq_certsdir, Config1),
@@ -114,8 +119,28 @@ init_per_group(http_provider_tests, Config) ->
114119
{refresh_interval, interval()},
115120
{providers, [rabbit_trust_store_http_provider]}]]),
116121
Config3
122+
end;
123+
124+
init_per_group(required_options, Config) ->
125+
case set_up_node(Config, [fun modify_ssl_options/1]) of
126+
{skip, _} = Error -> Error;
127+
Config1 ->
128+
WhitelistDir = filename:join([?config(rmq_certsdir, Config1),
129+
"trust_store", "file_provider_tests"]),
130+
Config2 = init_whitelist_dir(Config1, WhitelistDir),
131+
ok = rabbit_ct_broker_helpers:rpc(Config2, 0,
132+
?MODULE, change_configuration,
133+
[rabbitmq_trust_store, [{directory, WhitelistDir},
134+
{refresh_interval, interval()},
135+
{providers, [rabbit_trust_store_file_provider]}]]),
136+
Config2
117137
end.
118138

139+
140+
modify_ssl_options(Config) ->
141+
SslOptions = [{verify, verify_none}, {fail_if_no_peer_cert, false}],
142+
rabbit_ct_helpers:merge_app_env(Config, {rabbit, [{ssl_options, SslOptions}]}).
143+
119144
init_provider_server(Config, WhitelistDir) ->
120145
%% Assume we don't have more than 100 ports allocated for tests
121146
PortBase = rabbit_ct_broker_helpers:get_node_config(Config, 0, tcp_ports_base),
@@ -184,9 +209,10 @@ invasive_SSL_option_change1() ->
184209
{ok, Options} = application:get_env(rabbit, ssl_options),
185210

186211
%% Then: all necessary settings are correct.
187-
verify_peer = proplists:get_value(verify, Options),
188-
true = proplists:get_value(fail_if_no_peer_cert, Options),
189-
{Verifyfun, _UserState} = proplists:get_value(verify_fun, Options),
212+
OptionsMap = proplists:to_map(lists:reverse(Options)),
213+
verify_peer = maps:get(verify, OptionsMap),
214+
true = maps:get(fail_if_no_peer_cert, OptionsMap),
215+
{Verifyfun, _UserState} = maps:get(verify_fun, OptionsMap),
190216

191217
{module, rabbit_trust_store} = erlang:fun_info(Verifyfun, module),
192218
ok.
@@ -491,9 +517,15 @@ validate_chain_without_whitelisted1(Config) ->
491517

492518
whitelisted_certificate_accepted_from_AMQP_client_regardless_of_validation_to_root(Config) ->
493519
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
494-
?MODULE, whitelisted_certificate_accepted_from_AMQP_client_regardless_of_validation_to_root1, [Config]).
520+
?MODULE, whitelisted_certificate_accepted_from_AMQP_client,
521+
[Config, _ServerCA = true]).
495522

496-
whitelisted_certificate_accepted_from_AMQP_client_regardless_of_validation_to_root1(Config) ->
523+
whitelisted_certificate_accepted_from_AMQP_client_without_server_side_cacerts(Config) ->
524+
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
525+
?MODULE, whitelisted_certificate_accepted_from_AMQP_client,
526+
[Config, _ServerCA = false]).
527+
528+
whitelisted_certificate_accepted_from_AMQP_client(Config, ServerCA) ->
497529
%% Given: a certificate `CertTrusted` AND that it is whitelisted.
498530
{RootCerts, Cert, Key} = ct_helper:make_certs(),
499531
{_, CertTrusted, KeyTrusted} = ct_helper:make_certs(),
@@ -504,12 +536,21 @@ whitelisted_certificate_accepted_from_AMQP_client_regardless_of_validation_to_ro
504536
ok = whitelist(Config, "alice", CertTrusted),
505537
rabbit_trust_store:refresh(),
506538

507-
%% When: Rabbit validates paths with a different root `R` than
508-
%% that of the certificate `CertTrusted`.
539+
ServerSslOpts0 = [{cert, Cert},
540+
{key, Key}
541+
|lists:keydelete(cacertfile, 1, cfg())],
542+
ServerSslOpts =
543+
case ServerCA of
544+
true ->
545+
%% When: Rabbit validates paths with a different root `R` than
546+
%% that of the certificate `CertTrusted`.
547+
[{cacerts, RootCerts} | ServerSslOpts0];
548+
false ->
549+
%% When: Rabbit has no root CA configured
550+
ServerSslOpts0
551+
end,
509552
catch rabbit_networking:stop_tcp_listener(Port),
510-
ok = rabbit_networking:start_ssl_listener(Port, [{cacerts, RootCerts},
511-
{cert, Cert},
512-
{key, Key} | cfg()], 1, 1),
553+
ok = rabbit_networking:start_ssl_listener(Port, ServerSslOpts, 1, 1),
513554

514555
%% Then: a client presenting the whitelisted certificate `C`
515556
%% is allowed.

0 commit comments

Comments
 (0)