fix(tls): Ensure tls config integrity
For default tsl version and ciphers, we try to use otp release number to determin if we want to use tlsv1.3 For default configs, we try to porivde both tlsv1.3 and ciphers in config (even for commented out configs)
This commit is contained in:
parent
2852ac79d4
commit
f000b6583c
|
@ -74,11 +74,10 @@ translate_env(EnvName) ->
|
|||
(_) ->
|
||||
true
|
||||
end, [{keyfile, KeyFile}, {certfile, CertFile}, {cacertfile, CACertFile}]),
|
||||
TlsVers = ['tlsv1.2','tlsv1.1',tlsv1],
|
||||
NTLSOpts = [{versions, TlsVers},
|
||||
{ciphers, lists:foldl(fun(TlsVer, Ciphers) ->
|
||||
Ciphers ++ ssl:cipher_suites(all, TlsVer)
|
||||
end, [], TlsVers)} | TLSOpts],
|
||||
NTLSOpts = [ {versions, emqx_tls_lib:default_versions()}
|
||||
, {ciphers, emqx_tls_lib:default_ciphers()}
|
||||
| TLSOpts
|
||||
],
|
||||
[{transport, ssl}, {transport_opts, [Inet | NTLSOpts]}]
|
||||
end,
|
||||
PoolOpts = [{host, Host},
|
||||
|
|
|
@ -43,7 +43,7 @@ auth.pgsql.ssl = off
|
|||
## You can configure multi-version use "," split,
|
||||
## default value is :tlsv1.2
|
||||
## Example:
|
||||
## tlsv1.1,tlsv1.2,tlsv1.3
|
||||
## tlsv1.2,tlsv1.1
|
||||
##
|
||||
#auth.pgsql.ssl.tls_versions = tlsv1.2
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ bridge.mqtt.emqx2.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-S
|
|||
bridge.mqtt.emqx2.keepalive = 60s
|
||||
|
||||
## Supported TLS version
|
||||
bridge.mqtt.emqx2.tls_versions = tlsv1.2,tlsv1.1,tlsv1
|
||||
bridge.mqtt.emqx2.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
|
||||
|
||||
## Forwarding topics of the message
|
||||
bridge.mqtt.emqx2.forwards = sensor1/#,sensor2/#
|
||||
|
|
|
@ -133,9 +133,6 @@ EMQ X MQTT bridging principle: Create an MQTT client on the EMQ X broker, and co
|
|||
## Key file of Client SSL connection
|
||||
bridge.mqtt.emqx2.keyfile = etc/certs/client-key.pem
|
||||
|
||||
## SSL encryption
|
||||
bridge.mqtt.emqx2.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384
|
||||
|
||||
## TTLS PSK password
|
||||
## Note 'listener.ssl.external.ciphers' and 'listener.ssl.external.psk_ciphers' cannot be configured at the same time
|
||||
##
|
||||
|
@ -146,7 +143,10 @@ EMQ X MQTT bridging principle: Create an MQTT client on the EMQ X broker, and co
|
|||
bridge.mqtt.emqx2.keepalive = 60s
|
||||
|
||||
## Supported TLS version
|
||||
bridge.mqtt.emqx2.tls_versions = tlsv1.2,tlsv1.1,tlsv1
|
||||
bridge.mqtt.emqx2.tls_versions = tlsv1.2
|
||||
|
||||
## SSL encryption
|
||||
bridge.mqtt.emqx2.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384
|
||||
|
||||
## Forwarding topics of the message
|
||||
bridge.mqtt.emqx2.forwards = sensor1/#,sensor2/#
|
||||
|
|
|
@ -128,6 +128,7 @@ bridge.mqtt.aws.keepalive = 60s
|
|||
|
||||
## TLS versions used by the bridge.
|
||||
##
|
||||
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
|
||||
## Value: String
|
||||
bridge.mqtt.aws.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
|
||||
{mapping, "bridge.mqtt.$name.tls_versions", "emqx_bridge_mqtt.bridges", [
|
||||
{datatype, string},
|
||||
{default, "tlsv1,tlsv1.1,tlsv1.2"}
|
||||
{default, "tlsv1.3,tlsv1.2,tlsv1.1,tlsv1"}
|
||||
]}.
|
||||
|
||||
{mapping, "bridge.mqtt.$name.reconnect_interval", "emqx_bridge_mqtt.bridges", [
|
||||
|
|
|
@ -671,12 +671,6 @@ format_data([], Msg) ->
|
|||
format_data(Tokens, Msg) ->
|
||||
emqx_rule_utils:proc_tmpl(Tokens, Msg).
|
||||
|
||||
tls_versions() ->
|
||||
['tlsv1.2','tlsv1.1', tlsv1].
|
||||
|
||||
ciphers(Ciphers) ->
|
||||
string:tokens(str(Ciphers), ", ").
|
||||
|
||||
subscriptions(Subscriptions) ->
|
||||
scan_binary(<<"[", Subscriptions/binary, "].">>).
|
||||
|
||||
|
@ -749,6 +743,8 @@ options(Options, PoolName) ->
|
|||
Topic ->
|
||||
[{subscriptions, [{Topic, Get(<<"qos">>)}]} | Subscriptions]
|
||||
end,
|
||||
%% TODO check why only ciphers are configurable but not versions
|
||||
TlsVersions = emqx_tls_lib:default_versions(),
|
||||
[{address, binary_to_list(Address)},
|
||||
{bridge_mode, GetD(<<"bridge_mode">>, true)},
|
||||
{clean_start, true},
|
||||
|
@ -761,12 +757,13 @@ options(Options, PoolName) ->
|
|||
{proto_ver, mqtt_ver(Get(<<"proto_ver">>))},
|
||||
{retry_interval, cuttlefish_duration:parse(str(GetD(<<"retry_interval">>, "30s")), s)},
|
||||
{ssl, cuttlefish_flag:parse(str(Get(<<"ssl">>)))},
|
||||
{ssl_opts, [{versions, tls_versions()},
|
||||
{ciphers, ciphers(Get(<<"ciphers">>))},
|
||||
{keyfile, str(Get(<<"keyfile">>))},
|
||||
{certfile, str(Get(<<"certfile">>))},
|
||||
{cacertfile, str(Get(<<"cacertfile">>))}
|
||||
]}] ++ Subscriptions1
|
||||
{ssl_opts, [ {keyfile, str(Get(<<"keyfile">>))}
|
||||
, {certfile, str(Get(<<"certfile">>))}
|
||||
, {cacertfile, str(Get(<<"cacertfile">>))}
|
||||
, {versions, TlsVersions}
|
||||
, {ciphers, emqx_tls_lib:integral_ciphers(TlsVersions, Get(<<"ciphers">>))}
|
||||
]}
|
||||
] ++ Subscriptions1
|
||||
end.
|
||||
|
||||
|
||||
|
|
|
@ -75,10 +75,7 @@ end}.
|
|||
Ciphers =
|
||||
case cuttlefish:conf_get("coap.dtls.ciphers", Conf, undefined) of
|
||||
undefined ->
|
||||
lists:foldl(
|
||||
fun(TlsVer, Ciphers) ->
|
||||
Ciphers ++ ssl:cipher_suites(all, TlsVer)
|
||||
end, [], ['dtlsv1', 'dtlsv1.2']);
|
||||
lists:append([ssl:cipher_suites(all, V, openssl) || V <- ['dtlsv1.2', 'dtlsv1']]);
|
||||
C ->
|
||||
SplitFun(C)
|
||||
end,
|
||||
|
|
|
@ -105,7 +105,8 @@ dashboard.listener.http.ipv6_v6only = false
|
|||
## TLS versions only to protect from POODLE attack.
|
||||
##
|
||||
## Value: String, seperated by ','
|
||||
## dashboard.listener.https.tls_versions = tlsv1.2,tlsv1.1,tlsv1
|
||||
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
|
||||
## dashboard.listener.https.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
|
||||
|
||||
## See: 'listener.ssl.<name>.ciphers' in emq.conf
|
||||
##
|
||||
|
|
|
@ -425,8 +425,8 @@ udp_opts() ->
|
|||
|
||||
ssl_opts() ->
|
||||
Certs = certs("key.pem", "cert.pem", "cacert.pem"),
|
||||
[{versions, ['tlsv1.2','tlsv1.1',tlsv1]},
|
||||
{ciphers, ciphers('tlsv1.2')},
|
||||
[{versions, emqx_tls_lib:default_versions()},
|
||||
{ciphers, emqx_tls_lib:default_ciphers()},
|
||||
{verify, verify_peer},
|
||||
{fail_if_no_peer_cert, true},
|
||||
{secure_renegotiate, false},
|
||||
|
@ -437,9 +437,6 @@ dtls_opts() ->
|
|||
Opts = ssl_opts(),
|
||||
lists:keyreplace(versions, 1, Opts, {versions, ['dtlsv1.2', 'dtlsv1']}).
|
||||
|
||||
ciphers(Version) ->
|
||||
proplists:get_value(ciphers, emqx_ct_helpers:client_ssl(Version)).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Client-Opts
|
||||
|
||||
|
|
|
@ -45,7 +45,8 @@ management.listener.http.ipv6_v6only = false
|
|||
## management.listener.https.keyfile = etc/certs/key.pem
|
||||
## management.listener.https.cacertfile = etc/certs/cacert.pem
|
||||
## management.listener.https.verify = verify_peer
|
||||
## management.listener.https.tls_versions = tlsv1.2,tlsv1.1,tlsv1
|
||||
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
|
||||
## management.listener.https.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
|
||||
## management.listener.https.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,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA
|
||||
## management.listener.https.fail_if_no_peer_cert = true
|
||||
## management.listener.https.inet6 = false
|
||||
|
|
|
@ -58,7 +58,8 @@ stomp.listener.max_connections = 512
|
|||
## TLS versions only to protect from POODLE attack.
|
||||
##
|
||||
## Value: String, seperated by ','
|
||||
## stomp.listener.tls_versions = tlsv1.2,tlsv1.1,tlsv1
|
||||
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
|
||||
## stomp.listener.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
|
||||
|
||||
## SSL Handshake timeout.
|
||||
##
|
||||
|
|
|
@ -354,12 +354,11 @@ pool_opts(Params = #{<<"url">> := URL}) ->
|
|||
(_) ->
|
||||
true
|
||||
end, [{keyfile, KeyFile}, {certfile, CertFile}, {cacertfile, CACertFile}]),
|
||||
TlsVers = ['tlsv1.2', 'tlsv1.1', tlsv1],
|
||||
NTLSOpts = [{verify, VerifyType},
|
||||
{versions, TlsVers},
|
||||
{ciphers, lists:foldl(fun(TlsVer, Ciphers) ->
|
||||
Ciphers ++ ssl:cipher_suites(all, TlsVer)
|
||||
end, [], TlsVers)} | TLSOpts],
|
||||
NTLSOpts = [ {verify, VerifyType}
|
||||
, {versions, emqx_tls_lib:default_versions()}
|
||||
, {ciphers, emqx_tls_lib:default_ciphers()}
|
||||
| TLSOpts
|
||||
],
|
||||
[{transport, ssl}, {transport_opts, [Inet | NTLSOpts]}]
|
||||
end,
|
||||
[{host, Host},
|
||||
|
@ -397,4 +396,4 @@ test_http_connect(Conf) ->
|
|||
Err:Reason:ST ->
|
||||
?LOG(error, "check http_connectivity failed: ~p, ~0p", [Conf, {Err, Reason, ST}]),
|
||||
false
|
||||
end.
|
||||
end.
|
||||
|
|
|
@ -75,12 +75,11 @@ translate_env() ->
|
|||
TLSOpts = lists:filter(fun({_K, V}) ->
|
||||
V /= <<>> andalso V /= undefined andalso V /= "" andalso true
|
||||
end, [{keyfile, KeyFile}, {certfile, CertFile}, {cacertfile, CACertFile}]),
|
||||
TlsVers = ['tlsv1.2','tlsv1.1',tlsv1],
|
||||
NTLSOpts = [{verify, VerifyType},
|
||||
{versions, TlsVers},
|
||||
{ciphers, lists:foldl(fun(TlsVer, Ciphers) ->
|
||||
Ciphers ++ ssl:cipher_suites(all, TlsVer)
|
||||
end, [], TlsVers)} | TLSOpts],
|
||||
NTLSOpts = [ {verify, VerifyType}
|
||||
, {versions, emqx_tls_lib:default_versions()}
|
||||
, {ciphers, emqx_tls_lib:default_ciphers()}
|
||||
| TLSOpts
|
||||
],
|
||||
[{transport, ssl}, {transport_opts, [Inet | NTLSOpts]}]
|
||||
end,
|
||||
PoolOpts = [{host, Host},
|
||||
|
@ -114,4 +113,4 @@ parse_host(Host) ->
|
|||
{ok, _} -> {inet6, Host};
|
||||
{error, _} -> {inet, Host}
|
||||
end
|
||||
end.
|
||||
end.
|
||||
|
|
|
@ -1317,7 +1317,8 @@ listener.ssl.external.access.1 = allow all
|
|||
## See: http://erlang.org/doc/man/ssl.html
|
||||
##
|
||||
## Value: String, seperated by ','
|
||||
## listener.ssl.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1
|
||||
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
|
||||
## listener.ssl.external.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
|
||||
|
||||
## TLS Handshake timeout.
|
||||
##
|
||||
|
@ -1785,7 +1786,7 @@ listener.wss.external.access.1 = allow all
|
|||
## Supported subprotocols
|
||||
##
|
||||
## Default: mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5
|
||||
## listener.ws.external.supported_protocols = mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5
|
||||
## listener.wss.external.supported_protocols = mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5
|
||||
|
||||
## Enable the Proxy Protocol V1/2 support.
|
||||
##
|
||||
|
@ -1806,7 +1807,8 @@ listener.wss.external.access.1 = allow all
|
|||
## See: listener.ssl.$name.tls_versions
|
||||
##
|
||||
## Value: String, seperated by ','
|
||||
## listener.wss.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1
|
||||
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
|
||||
## listener.wss.external.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
|
||||
|
||||
## Path to the file containing the user's private PEM-encoded key.
|
||||
##
|
||||
|
|
|
@ -47,7 +47,7 @@ integral_versions(Desired) ->
|
|||
|
||||
%% @doc Return a list of default (openssl string format) cipher suites.
|
||||
-spec default_ciphers() -> [string()].
|
||||
default_ciphers() -> default_ciphers(tls_versions()).
|
||||
default_ciphers() -> default_ciphers(default_versions()).
|
||||
|
||||
%% @doc Return a list of (openssl string format) cipher suites.
|
||||
-spec default_ciphers([ssl:tls_version()]) -> [string()].
|
||||
|
@ -68,7 +68,7 @@ integral_ciphers(Versions, Ciphers) when Ciphers =:= [] orelse Ciphers =:= undef
|
|||
integral_ciphers(Versions, default_ciphers(Versions));
|
||||
integral_ciphers(Versions, Ciphers) when ?IS_STRING_LIST(Ciphers) ->
|
||||
%% ensure tlsv1.3 ciphers if none of them is found in Ciphers
|
||||
dedup(ensure_tls1_3_cipher(lists:member('tlsv1.3', Versions), Ciphers));
|
||||
dedup(ensure_tls13_cipher(lists:member('tlsv1.3', Versions), Ciphers));
|
||||
integral_ciphers(Versions, Ciphers) when is_binary(Ciphers) ->
|
||||
%% parse binary
|
||||
integral_ciphers(Versions, binary_to_list(Ciphers));
|
||||
|
@ -78,20 +78,20 @@ integral_ciphers(Versions, Ciphers) ->
|
|||
|
||||
%% In case tlsv1.3 is present, ensure tlsv1.3 cipher is added if user
|
||||
%% did not provide it from config --- which is a common mistake
|
||||
ensure_tls1_3_cipher(true, Ciphers) ->
|
||||
ensure_tls13_cipher(true, Ciphers) ->
|
||||
Tls13Ciphers = default_ciphers(['tlsv1.3']),
|
||||
case lists:any(fun(C) -> lists:member(C, Tls13Ciphers) end, Ciphers) of
|
||||
true -> Ciphers;
|
||||
false -> Tls13Ciphers ++ Ciphers
|
||||
end;
|
||||
ensure_tls1_3_cipher(false, Ciphers) ->
|
||||
ensure_tls13_cipher(false, Ciphers) ->
|
||||
Ciphers.
|
||||
|
||||
%% tlsv1.3 is available from OTP-22 but we do not want to use until 23.
|
||||
default_versions(OtpRelease) when OtpRelease >= 23 ->
|
||||
['tlsv1.3' | default_tls_versions(22)];
|
||||
['tlsv1.3' | default_versions(22)];
|
||||
default_versions(_) ->
|
||||
['tlsv1.2','tlsv1.1', tlsv1].
|
||||
['tlsv1.2', 'tlsv1.1', tlsv1].
|
||||
|
||||
%% Deduplicate a list without re-ordering the elements.
|
||||
dedup([]) -> [];
|
||||
|
|
Loading…
Reference in New Issue