feat(listeners): Ensure no tlsv1.3 for otp 22 or earlier

This commit is contained in:
Zaiming Shi 2021-03-19 09:56:20 +01:00 committed by Zaiming (Stone) Shi
parent 8f6e02c322
commit 2d150127d4
2 changed files with 70 additions and 2 deletions

View File

@ -134,7 +134,18 @@ start_listener(Proto, ListenOn, Options) when Proto == https; Proto == wss ->
start_http_listener(fun cowboy:start_tls/3, 'mqtt:wss', ListenOn, start_http_listener(fun cowboy:start_tls/3, 'mqtt:wss', ListenOn,
ranch_opts(Options), ws_opts(Options)). ranch_opts(Options), ws_opts(Options)).
start_mqtt_listener(Name, ListenOn, Options) -> replace(Opts, Key, Value) -> [{Key, Value} | proplists:delete(Key, Opts)].
drop_tls13_for_old_otp(Options) ->
case proplists:get_value(ssl_options, Options) of
undefined -> Options;
SslOpts ->
SslOpts1 = emqx_tls_lib:drop_tls13_for_old_otp(SslOpts),
replace(Options, ssl_options, SslOpts1)
end.
start_mqtt_listener(Name, ListenOn, Options0) ->
Options = drop_tls13_for_old_otp(Options0),
SockOpts = esockd:parse_opt(Options), SockOpts = esockd:parse_opt(Options),
esockd:open(Name, ListenOn, merge_default(SockOpts), esockd:open(Name, ListenOn, merge_default(SockOpts),
{emqx_connection, start_link, [Options -- SockOpts]}). {emqx_connection, start_link, [Options -- SockOpts]}).
@ -151,7 +162,8 @@ ws_opts(Options) ->
ProxyProto = proplists:get_value(proxy_protocol, Options, false), ProxyProto = proplists:get_value(proxy_protocol, Options, false),
#{env => #{dispatch => Dispatch}, proxy_header => ProxyProto}. #{env => #{dispatch => Dispatch}, proxy_header => ProxyProto}.
ranch_opts(Options) -> ranch_opts(Options0) ->
Options = drop_tls13_for_old_otp(Options0),
NumAcceptors = proplists:get_value(acceptors, Options, 4), NumAcceptors = proplists:get_value(acceptors, Options, 4),
MaxConnections = proplists:get_value(max_connections, Options, 1024), MaxConnections = proplists:get_value(max_connections, Options, 1024),
TcpOptions = proplists:get_value(tcp_options, Options, []), TcpOptions = proplists:get_value(tcp_options, Options, []),

View File

@ -21,6 +21,7 @@
, default_ciphers/0 , default_ciphers/0
, default_ciphers/1 , default_ciphers/1
, integral_ciphers/2 , integral_ciphers/2
, drop_tls13_for_old_otp/1
]). ]).
%% non-empty string %% non-empty string
@ -140,3 +141,58 @@ split_by_comma(Bin) ->
%% trim spaces %% trim spaces
trim_space(Bin) -> trim_space(Bin) ->
hd([I || I <- binary:split(Bin, <<" ">>), I =/= <<>>]). hd([I || I <- binary:split(Bin, <<" ">>), I =/= <<>>]).
%% @doc Drop tlsv1.3 version and ciphers from ssl options
%% if running on otp 22 or earlier.
drop_tls13_for_old_otp(SslOpts) ->
case list_to_integer(erlang:system_info(otp_release)) < 23 of
true -> drop_tls13(SslOpts);
false -> SslOpts
end.
%% The ciphers that ssl:cipher_suites(exclusive, 'tlsv1.3', openssl)
%% should return when running on otp 23.
%% But we still have to hard-code them because tlsv1.3 on otp 22 is
%% not trustworthy.
-define(TLSV13_EXCLUSIVE_CIPHERS, [ "TLS_AES_256_GCM_SHA384"
, "TLS_AES_128_GCM_SHA256"
, "TLS_CHACHA20_POLY1305_SHA256"
, "TLS_AES_128_CCM_SHA256"
, "TLS_AES_128_CCM_8_SHA256"
]).
drop_tls13(SslOpts0) ->
SslOpts1 = case proplists:get_value(versions, SslOpts0) of
undefined -> SslOpts0;
Vsns -> replace(SslOpts0, versions, Vsns -- ['tlsv1.3'])
end,
case proplists:get_value(ciphers, SslOpts1) of
undefined -> SslOpts1;
Ciphers -> replace(SslOpts1, ciphers, Ciphers -- ?TLSV13_EXCLUSIVE_CIPHERS)
end.
replace(Opts, Key, Value) -> [{Key, Value} | proplists:delete(Key, Opts)].
-if(?OTP_RELEASE > 22).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
drop_tls13_test() ->
Versions = default_versions(),
?assert(lists:member('tlsv1.3', Versions)),
Ciphers = default_ciphers(),
?assert(has_tlsv13_cipher(Ciphers)),
Opts0 = [{versions, Versions}, {ciphers, Ciphers}, other, {bool, true}],
Opts = drop_tls13(Opts0),
?assertNot(lists:member('tlsv1.3', proplists:get_value(versions, Opts))),
?assertNot(has_tlsv13_cipher(proplists:get_value(ciphers, Opts))).
drop_tls13_no_versions_cipers_test() ->
Opts0 = [other, {bool, true}],
Opts = drop_tls13(Opts0),
?_assertEqual(Opts0, Opts).
has_tlsv13_cipher(Ciphers) ->
lists:any(fun(C) -> lists:member(C, Ciphers) end, ?TLSV13_EXCLUSIVE_CIPHERS).
-endif.
-endif.