fix(emqx_schema): move tls version gap validation to emqx_schema

This commit is contained in:
Serge Tupchii 2023-06-14 14:57:55 +03:00
parent 6d88cd7a20
commit 4425942030
4 changed files with 42 additions and 27 deletions

View File

@ -2679,10 +2679,30 @@ validate_ciphers(Ciphers) ->
validate_tls_versions(Collection, Versions) ->
AvailableVersions = available_tls_vsns(Collection),
case lists:filter(fun(V) -> not lists:member(V, AvailableVersions) end, Versions) of
[] -> ok;
[] -> validate_tls_version_gap(Versions);
Vs -> {error, {unsupported_tls_versions, Vs}}
end.
%% See also `validate_version_gap/1` in OTP ssl.erl,
%% e.g: https://github.com/emqx/otp/blob/emqx-OTP-25.1.2/lib/ssl/src/ssl.erl#L2566.
%% Do not allow configuration of TLS 1.3 with a gap where TLS 1.2 is not supported
%% as that configuration can trigger the built in version downgrade protection
%% mechanism and the handshake can fail with an Illegal Parameter alert.
validate_tls_version_gap(Versions) ->
case lists:member('tlsv1.3', Versions) of
true when length(Versions) >= 2 ->
case lists:member('tlsv1.2', Versions) of
true ->
ok;
false ->
{error,
"Using multiple versions that include tlsv1.3 but "
"exclude tlsv1.2 is not allowed"}
end;
_ ->
ok
end.
validations() ->
[
{check_process_watermark, fun check_process_watermark/1},

View File

@ -556,33 +556,9 @@ resolve_cert_path_for_read_strict(Path) ->
resolve_cert_path_for_read(Path) ->
emqx_schema:naive_env_interpolation(Path).
ensure_valid_options(Options, Versions0) ->
Versions = validate_version_gap(Versions0),
ensure_valid_options(Options, Versions) ->
ensure_valid_options(Options, Versions, []).
%% See also lib/ssl/src/ssl.erl#L2617.
%% Do not allow configuration of TLS 1.3 with a gap where TLS 1.2 is not supported
%% as that configuration can trigger the built in version downgrade protection
%% mechanism and the handshake can fail with an Illegal Parameter alert.
validate_version_gap(Versions) ->
case lists:member('tlsv1.3', Versions) of
true when length(Versions) >= 2 ->
case lists:member('tlsv1.2', Versions) of
true ->
Versions;
false ->
NewVersions = ['tlsv1.3'],
?SLOG(warning, #{
msg => "tlsv13_version_gap",
versions => Versions,
new_versions => NewVersions
}),
NewVersions
end;
_ ->
Versions
end.
ensure_valid_options([], _, Acc) ->
lists:reverse(Acc);
ensure_valid_options([{_, undefined} | T], Versions, Acc) ->
@ -607,7 +583,7 @@ ensure_valid_options([{K, V} | T], Versions, Acc) ->
end
end.
%% see lib/ssl/src/ssl.erl, assert_option_dependency/4
%% see otp/lib/ssl/src/ssl.erl, `assert_option_dependency/4`
tls_option_compatible_versions(beast_mitigation) ->
[dtlsv1, 'tlsv1'];
tls_option_compatible_versions(padding_check) ->

View File

@ -94,6 +94,18 @@ ssl_opts_tls_psk_test() ->
Checked = validate(Sc, #{<<"versions">> => [<<"tlsv1.2">>]}),
?assertMatch(#{versions := ['tlsv1.2']}, Checked).
ssl_opts_version_gap_test_() ->
Sc = emqx_schema:server_ssl_opts_schema(#{}, false),
RanchSc = emqx_schema:server_ssl_opts_schema(#{}, true),
Reason = "Using multiple versions that include tlsv1.3 but exclude tlsv1.2 is not allowed",
[
?_assertThrow(
{_, [#{kind := validation_error, reason := Reason}]},
validate(S, #{<<"versions">> => [<<"tlsv1.1">>, <<"tlsv1.3">>]})
)
|| S <- [Sc, RanchSc]
].
bad_cipher_test() ->
Sc = emqx_schema:server_ssl_opts_schema(#{}, false),
Reason = {bad_ciphers, ["foo"]},

View File

@ -0,0 +1,7 @@
Disallow using multiple TLS versions in the listener config that include tlsv1.3 but exclude tlsv1.2.
Using TLS configuration with such version gap caused connection errors.
Additionally, drop and log TLS options that are incompatible with the selected TLS version(s).
Note: any old listener configuration with the version gap described above will fail to load
after applying this fix and must be manually fixed.