Merge pull request #10952 from SergeTupchiy/EMQX-9586-validate-fail_if_no_peer_cert

fix(emqx_schema): don't allow enabling `fail_if_no_peer_cert` if `verify_none` is set
This commit is contained in:
SergeTupchiy 2023-06-06 17:28:52 +03:00 committed by GitHub
commit e749ae6863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 4 deletions

View File

@ -94,7 +94,8 @@
validate_keepalive_multiplier/1, validate_keepalive_multiplier/1,
non_empty_string/1, non_empty_string/1,
validations/0, validations/0,
naive_env_interpolation/1 naive_env_interpolation/1,
validate_server_ssl_opts/1
]). ]).
-export([qos/0]). -export([qos/0]).
@ -958,7 +959,7 @@ fields("mqtt_wss_listener") ->
{"ssl_options", {"ssl_options",
sc( sc(
ref("listener_wss_opts"), ref("listener_wss_opts"),
#{} #{validator => fun validate_server_ssl_opts/1}
)}, )},
{"websocket", {"websocket",
sc( sc(
@ -2426,8 +2427,21 @@ server_ssl_opts_schema(Defaults, IsRanchListener) ->
] ]
]. ].
validate_server_ssl_opts(#{<<"fail_if_no_peer_cert">> := true, <<"verify">> := Verify}) ->
validate_verify(Verify);
validate_server_ssl_opts(#{fail_if_no_peer_cert := true, verify := Verify}) ->
validate_verify(Verify);
validate_server_ssl_opts(_SSLOpts) ->
ok.
validate_verify(verify_peer) ->
ok;
validate_verify(_) ->
{error, "verify must be verify_peer when fail_if_no_peer_cert is true"}.
mqtt_ssl_listener_ssl_options_validator(Conf) -> mqtt_ssl_listener_ssl_options_validator(Conf) ->
Checks = [ Checks = [
fun validate_server_ssl_opts/1,
fun ocsp_outer_validator/1, fun ocsp_outer_validator/1,
fun crl_outer_validator/1 fun crl_outer_validator/1
], ],

View File

@ -106,6 +106,67 @@ bad_cipher_test() ->
), ),
ok. ok.
fail_if_no_peer_cert_test_() ->
Sc = #{
roots => [mqtt_ssl_listener],
fields => #{mqtt_ssl_listener => emqx_schema:fields("mqtt_ssl_listener")}
},
Opts = #{atom_key => false, required => false},
OptsAtomKey = #{atom_key => true, required => false},
InvalidConf = #{
<<"bind">> => <<"0.0.0.0:9883">>,
<<"ssl_options">> => #{
<<"fail_if_no_peer_cert">> => true,
<<"verify">> => <<"verify_none">>
}
},
InvalidListener = #{<<"mqtt_ssl_listener">> => InvalidConf},
ValidListener = #{
<<"mqtt_ssl_listener">> => InvalidConf#{
<<"ssl_options">> =>
#{
<<"fail_if_no_peer_cert">> => true,
<<"verify">> => <<"verify_peer">>
}
}
},
ValidListener1 = #{
<<"mqtt_ssl_listener">> => InvalidConf#{
<<"ssl_options">> =>
#{
<<"fail_if_no_peer_cert">> => false,
<<"verify">> => <<"verify_none">>
}
}
},
Reason = "verify must be verify_peer when fail_if_no_peer_cert is true",
[
?_assertThrow(
{_Sc, [#{kind := validation_error, reason := Reason}]},
hocon_tconf:check_plain(Sc, InvalidListener, Opts)
),
?_assertThrow(
{_Sc, [#{kind := validation_error, reason := Reason}]},
hocon_tconf:check_plain(Sc, InvalidListener, OptsAtomKey)
),
?_assertMatch(
#{mqtt_ssl_listener := #{}},
hocon_tconf:check_plain(Sc, ValidListener, OptsAtomKey)
),
?_assertMatch(
#{mqtt_ssl_listener := #{}},
hocon_tconf:check_plain(Sc, ValidListener1, OptsAtomKey)
),
?_assertMatch(
#{<<"mqtt_ssl_listener">> := #{}},
hocon_tconf:check_plain(Sc, ValidListener, Opts)
),
?_assertMatch(
#{<<"mqtt_ssl_listener">> := #{}},
hocon_tconf:check_plain(Sc, ValidListener1, Opts)
)
].
validate(Schema, Data0) -> validate(Schema, Data0) ->
Sc = #{ Sc = #{
roots => [ssl_opts], roots => [ssl_opts],

View File

@ -120,7 +120,10 @@ fields(ssl_listener) ->
{ssl_options, {ssl_options,
sc( sc(
hoconsc:ref(emqx_schema, "listener_ssl_opts"), hoconsc:ref(emqx_schema, "listener_ssl_opts"),
#{desc => ?DESC(ssl_listener_options)} #{
desc => ?DESC(ssl_listener_options),
validator => fun emqx_schema:validate_server_ssl_opts/1
}
)} )}
]; ];
fields(udp_listener) -> fields(udp_listener) ->
@ -132,7 +135,13 @@ fields(udp_listener) ->
fields(dtls_listener) -> fields(dtls_listener) ->
[{acceptors, sc(integer(), #{default => 16, desc => ?DESC(dtls_listener_acceptors)})}] ++ [{acceptors, sc(integer(), #{default => 16, desc => ?DESC(dtls_listener_acceptors)})}] ++
fields(udp_listener) ++ fields(udp_listener) ++
[{dtls_options, sc(ref(dtls_opts), #{desc => ?DESC(dtls_listener_dtls_opts)})}]; [
{dtls_options,
sc(ref(dtls_opts), #{
desc => ?DESC(dtls_listener_dtls_opts),
validator => fun emqx_schema:validate_server_ssl_opts/1
})}
];
fields(udp_opts) -> fields(udp_opts) ->
[ [
{active_n, {active_n,

View File

@ -0,0 +1,8 @@
Disallow enabling `fail_if_no_peer_cert` in listener SSL options if `verify_none` is set.
Setting `fail_if_no_peer_cert = true` and `verify = verify_none` caused connection errors
due to incompatible options.
This fix validates the options when creating or updating a listener to avoid these errors.
Note: any old listener configuration with `fail_if_no_peer_cert = true` and `verify = verify_none`
that was previously allowed will fail to load after applying this fix and must be manually fixed.