Ver código fonte

fix(emqx_schema): make ssl config schema right

Zaiming Shi 4 anos atrás
pai
commit
fbd5701989

Diferenças do arquivo suprimidas por serem muito extensas
+ 13 - 28
apps/emqx/etc/emqx.conf


+ 1 - 1
apps/emqx/rebar.config

@@ -16,7 +16,7 @@
     , {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.8.2"}}}
     , {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.10.8"}}}
     , {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.1"}}}
-    , {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.19.0"}}}
+    , {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.19.3"}}}
     , {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}
     , {recon, {git, "https://github.com/ferd/recon", {tag, "2.5.1"}}}
     , {snabbkaffe, {git, "https://github.com/kafka4beam/snabbkaffe.git", {tag, "0.14.1"}}}

+ 148 - 52
apps/emqx/src/emqx_schema.erl

@@ -23,6 +23,7 @@
 -dialyzer(no_fail_call).
 
 -include_lib("typerefl/include/types.hrl").
+-include_lib("snabbkaffe/include/snabbkaffe.hrl").
 
 -type duration() :: integer().
 -type duration_s() :: integer().
@@ -71,7 +72,7 @@
 
 -export([namespace/0, roots/0, roots/1, fields/1]).
 -export([conf_get/2, conf_get/3, keys/2, filter/1]).
--export([ssl/1]).
+-export([ssl_opts_schema/2, ciphers_schema/1, default_ciphers/1]).
 
 namespace() -> undefined.
 
@@ -461,7 +462,7 @@ fields("mqtt_ssl_listener") ->
           #{})
       }
     , {"ssl",
-       sc(ref("listener_ssl_opts"),
+       sc(ref("ssl_opts"),
           #{})
       }
     ] ++ mqtt_listener();
@@ -483,7 +484,7 @@ fields("mqtt_wss_listener") ->
           #{})
       }
     , {"ssl",
-       sc(ref("listener_ssl_opts"),
+       sc(ref("wss_ssl_opts"),
           #{})
       }
     , {"websocket",
@@ -498,6 +499,7 @@ fields("mqtt_quic_listener") ->
           #{ default => true
            })
       }
+      %% TODO: ensure cacertfile is configurable
     , {"certfile",
        sc(string(),
           #{})
@@ -506,11 +508,7 @@ fields("mqtt_quic_listener") ->
        sc(string(),
           #{})
       }
-    , {"ciphers",
-       sc(comma_separated_list(),
-          #{ default => "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,"
-                        "TLS_CHACHA20_POLY1305_SHA256"
-           })}
+    , {"ciphers", ciphers_schema(quic)}
     , {"idle_timeout",
        sc(duration(),
           #{ default => "15s"
@@ -633,13 +631,21 @@ fields("tcp_opts") ->
       }
     ];
 
-fields("listener_ssl_opts") ->
-    ssl(#{handshake_timeout => "15s"
-        , depth => 10
-        , reuse_sessions => true
-        , versions => default_tls_vsns()
-        , ciphers => default_ciphers()
-        });
+fields("ssl_opts") ->
+    ssl_opts_schema(
+      #{ depth => 10
+       , reuse_sessions => true
+       , versions => tcp
+       , ciphers => tcp_all
+       }, false);
+
+fields("wss_ssl_opts") ->
+    ssl_opts_schema(
+      #{ depth => 10
+       , reuse_sessions => true
+       , versions => tcp
+       , ciphers => tcp_all
+       }, true);
 
 fields("deflate_opts") ->
     [ {"level",
@@ -902,7 +908,10 @@ conf_get(Key, Conf, Default) ->
 filter(Opts) ->
     [{K, V} || {K, V} <- Opts, V =/= undefined].
 
-ssl(Defaults) ->
+%% @doc This function defines the SSL opts only for TLS server (listners).
+%% When it's for ranch listener, an extra field `handshake_timeout' is added.
+-spec ssl_opts_schema(map(), boolean()) -> hocon_schema:field_schema().
+ssl_opts_schema(Defaults, IsRanchListener) ->
     D = fun (Field) -> maps:get(to_atom(Field), Defaults, undefined) end,
     Df = fun (Field, Default) -> maps:get(to_atom(Field), Defaults, Default) end,
     [ {"enable",
@@ -933,6 +942,14 @@ ssl(Defaults) ->
     , {"fail_if_no_peer_cert",
        sc(boolean(),
           #{ default => Df("fail_if_no_peer_cert", false)
+           , desc =>
+"""
+Used together with {verify, verify_peer} by an TLS/DTLS server. 
+If set to true, the server fails if the client does not have a 
+certificate to send, that is, sends an empty certificate. 
+If set to false, it fails only if the client sends an invalid 
+certificate (an empty certificate is considered valid).
+"""
            })
       }
     , {"secure_renegotiate",
@@ -971,11 +988,6 @@ the number of messages the underlying cipher suite can encipher.
           #{ default => Df("honor_cipher_order", true)
            })
       }
-    , {"handshake_timeout",
-       sc(duration(),
-          #{ default => Df("handshake_timeout", "15s")
-           })
-      }
     , {"depth",
        sc(integer(),
           #{default => Df("depth", 10)
@@ -983,50 +995,118 @@ the number of messages the underlying cipher suite can encipher.
       }
     , {"password",
        sc(string(),
-          #{ default => D("key_password")
-           , sensitive => true
+          #{ sensitive => true
+           , nullable => true
+           , desc =>
+"""String containing the user's password. Only used if the private 
+keyfile is password-protected."""
            })
       }
     , {"dhfile",
        sc(string(),
           #{ default => D("dhfile")
-           })
-      }
-    , {"server_name_indication",
-       sc(hoconsc:union([disable, string()]),
-          #{ default => D("server_name_indication")
+           , nullable => true
+           , desc =>
+"""Path to a file containing PEM-encoded Diffie Hellman parameters 
+to be used by the server if a cipher suite using Diffie Hellman 
+key exchange is negotiated. If not specified, default parameters 
+are used.<br>
+NOTE: The dhfile option is not supported by TLS 1.3."""
            })
       }
     , {"versions",
-       sc(typerefl:alias("string", list(atom())),
-          #{ default => maps:get(versions, Defaults, default_tls_vsns())
-           , converter => fun (Vsns) -> [tls_vsn(iolist_to_binary(V)) || V <- Vsns] end
-           })
-      }
-    , {"ciphers",
-       sc(hoconsc:array(string()),
-          #{ default => D("ciphers")
+       sc(hoconsc:array(typerefl:atom()),
+          #{ default => default_tls_vsns(maps:get(versions, Defaults, tcp))
+           , desc =>
+"""All TLS/DTLS versions to be supported.<br>
+NOTE: PSK ciphers are suppresed by 'tlsv1.3' version config<br>
+In case PSK cipher suites are intended, make sure to configured
+<code>['tlsv1.2', 'tlsv1.1']</code> here<br>.
+"""
            })
       }
-    , {"user_lookup_fun",
+    , {"ciphers", ciphers_schema(D("ciphers"))}
+    , {user_lookup_fun,
        sc(typerefl:alias("string", any()),
           #{ default => "emqx_psk:lookup"
            , converter => fun ?MODULE:parse_user_lookup_fun/1
            })
       }
+    | [ {"handshake_timeout",
+         sc(duration(),
+            #{ default => Df("handshake_timeout", "15s")
+             , desc => "Maximum time duration allowed for the handshake to complete"
+             })}
+       || IsRanchListener]
     ].
 
-%% on erl23.2.7.2-emqx-2, sufficient_crypto_support('tlsv1.3') -> false
-default_tls_vsns() -> [<<"tlsv1.2">>, <<"tlsv1.1">>, <<"tlsv1">>].
-
-tls_vsn(<<"tlsv1.3">>) -> 'tlsv1.3';
-tls_vsn(<<"tlsv1.2">>) -> 'tlsv1.2';
-tls_vsn(<<"tlsv1.1">>) -> 'tlsv1.1';
-tls_vsn(<<"tlsv1">>) -> 'tlsv1'.
-
-default_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",
+default_tls_vsns(dtls) ->
+    [<<"dtlsv1.2">>, <<"dtlsv1">>];
+default_tls_vsns(tcp) ->
+    [<<"tlsv1.3">>, <<"tlsv1.2">>, <<"tlsv1.1">>, <<"tlsv1">>].
+
+-spec ciphers_schema(quic | dtls | tcp_all | undefined) -> hocon_schema:field_schema().
+ciphers_schema(Default) ->
+    sc(hoconsc:union([string(), hoconsc:array(string())]),
+       #{ default => default_ciphers(Default)
+        , converter => fun(Ciphers) when is_binary(Ciphers) ->
+                               binary:split(Ciphers, <<",">>, [global]);
+                          (Ciphers) when is_list(Ciphers) ->
+                               Ciphers
+                       end
+        , validator => fun validate_ciphers/1
+        , desc =>
+"""TLS cipher suite names separated by comma, or as an array of strings 
+<code>\"TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256\"</code> or 
+<code>[\"TLS_AES_256_GCM_SHA384\",\"TLS_AES_128_GCM_SHA256\"]</code].
+<br>
+Ciphers (and their ordering) define the way in which the 
+client and server encrypts information over the wire. 
+Selecting a good cipher suite is critical for the 
+application's data security, confidentiality and performance. 
+The names should be in OpenSSL sting format (not RFC format). 
+Default values and examples proveded by EMQ X config 
+documentation are all in OpenSSL format.<br>
+
+NOTE: Certain cipher suites are only compatible with 
+specific TLS <code>versions</code> ('tlsv1.1', 'tlsv1.2' or 'tlsv1.3') 
+incompatible cipher suites will be silently dropped. 
+For instance, if only 'tlsv1.3' is given in the <code>versions</code>, 
+configuring cipher suites for other versions will have no effect.
+<br>
+
+NOTE: PSK ciphers are suppresed by 'tlsv1.3' version config<br>
+If PSK cipher suites are intended, 'tlsv1.3' should be disabled from <code>versions</code>.<br>
+PSK cipher suites: <code>\"RSA-PSK-AES256-GCM-SHA384,RSA-PSK-AES256-CBC-SHA384,
+RSA-PSK-AES128-GCM-SHA256,RSA-PSK-AES128-CBC-SHA256,
+RSA-PSK-AES256-CBC-SHA,RSA-PSK-AES128-CBC-SHA,
+RSA-PSK-DES-CBC3-SHA,RSA-PSK-RC4-SHA\"</code><br>
+""" ++ case Default of
+           quic -> "NOTE: QUIC listener supports only 'tlsv1.3' ciphers<br>";
+           _ -> ""
+       end}).
+
+default_ciphers(undefined) ->
+    default_ciphers(tcp_all);
+default_ciphers(quic) -> [
+    "TLS_AES_256_GCM_SHA384",
+    "TLS_AES_128_GCM_SHA256",
+    "TLS_CHACHA20_POLY1305_SHA256"
+    ];
+default_ciphers(tcp_all) ->
+    default_ciphers('tlsv1.3') ++
+    default_ciphers('tlsv1.2') ++
+    default_ciphers(psk);
+default_ciphers(dtls) ->
+    %% as of now, dtls does not support tlsv1.3 ciphers
+    default_ciphers('tlsv1.2') ++ default_ciphers('psk');
+default_ciphers('tlsv1.3') ->
+    ["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"]
+    ++ default_ciphers('tlsv1.2');
+default_ciphers('tlsv1.2') -> [
+    "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",
@@ -1039,10 +1119,12 @@ default_ciphers() -> [
     "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"
-    ] ++ psk_ciphers().
-
-psk_ciphers() -> [
-        "PSK-AES128-CBC-SHA", "PSK-AES256-CBC-SHA", "PSK-3DES-EDE-CBC-SHA", "PSK-RC4-SHA"
+    ];
+default_ciphers(psk) ->
+    [ "RSA-PSK-AES256-GCM-SHA384","RSA-PSK-AES256-CBC-SHA384",
+      "RSA-PSK-AES128-GCM-SHA256","RSA-PSK-AES128-CBC-SHA256",
+      "RSA-PSK-AES256-CBC-SHA","RSA-PSK-AES128-CBC-SHA",
+      "RSA-PSK-DES-CBC3-SHA","RSA-PSK-RC4-SHA"
     ].
 
 %% @private return a list of keys in a parent field
@@ -1160,3 +1242,17 @@ parse_user_lookup_fun(StrConf) ->
     Mod = list_to_atom(ModStr),
     Fun = list_to_atom(FunStr),
     {fun Mod:Fun/3, <<>>}.
+
+validate_ciphers(Ciphers) ->
+    All = ssl:cipher_suites(all, 'tlsv1.3', openssl) ++
+          ssl:cipher_suites(all, 'tlsv1.2', openssl), %% includes older version ciphers
+    lists:foreach(
+        fun(Cipher) ->
+                case lists:member(Cipher, All) of
+                    true ->
+                        ok;
+                    false ->
+                        ?tp(error, bad_tls_cipher_suite, #{ciphers => Cipher}),
+                        error({bad_tls_cipher_suite, Cipher})
+                end
+        end, Ciphers).

+ 108 - 0
apps/emqx/test/emqx_schema_tests.erl

@@ -0,0 +1,108 @@
+%%--------------------------------------------------------------------
+%% Copyright (c) 2017-2021 EMQ Technologies Co., Ltd. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%--------------------------------------------------------------------
+
+-module(emqx_schema_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("snabbkaffe/include/snabbkaffe.hrl").
+
+ssl_opts_dtls_test() ->
+    Sc = emqx_schema:ssl_opts_schema(#{versions => dtls,
+                                           ciphers => dtls}, false),
+    Checked = validate(Sc, #{<<"versions">> => [<<"dtlsv1.2">>, <<"dtlsv1">>]}),
+    ?assertMatch(#{versions := ['dtlsv1.2', 'dtlsv1'],
+                   ciphers := ["ECDHE-ECDSA-AES256-GCM-SHA384" | _]
+                  }, Checked).
+
+ssl_opts_tls_1_3_test() ->
+    Sc = emqx_schema:ssl_opts_schema(#{}, false),
+    Checked = validate(Sc, #{<<"versions">> => [<<"tlsv1.3">>]}),
+    ?assertNot(maps:is_key(handshake_timeout, Checked)),
+    ?assertMatch(#{versions := ['tlsv1.3'],
+                   ciphers := [_ | _]
+                  }, Checked).
+
+ssl_opts_tls_for_ranch_test() ->
+    Sc = emqx_schema:ssl_opts_schema(#{}, true),
+    Checked = validate(Sc, #{<<"versions">> => [<<"tlsv1.3">>]}),
+    ?assertMatch(#{versions := ['tlsv1.3'],
+                   ciphers := [_ | _],
+                   handshake_timeout := _
+                  }, Checked).
+
+ssl_opts_cipher_array_test() ->
+    Sc = emqx_schema:ssl_opts_schema(#{}, false),
+    Checked = validate(Sc, #{<<"versions">> => [<<"tlsv1.3">>],
+                             <<"ciphers">> => [<<"TLS_AES_256_GCM_SHA384">>,
+                                               <<"ECDHE-ECDSA-AES256-GCM-SHA384">>]}),
+    ?assertMatch(#{versions := ['tlsv1.3'],
+                   ciphers := ["TLS_AES_256_GCM_SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384"]
+                  }, Checked).
+
+ssl_opts_cipher_comma_separated_string_test() ->
+    Sc = emqx_schema:ssl_opts_schema(#{}, false),
+    Checked = validate(Sc, #{<<"versions">> => [<<"tlsv1.3">>],
+                             <<"ciphers">> => <<"TLS_AES_256_GCM_SHA384,ECDHE-ECDSA-AES256-GCM-SHA384">>}),
+    ?assertMatch(#{versions := ['tlsv1.3'],
+                   ciphers := ["TLS_AES_256_GCM_SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384"]
+                  }, Checked).
+
+ssl_opts_tls_psk_test() ->
+    Sc = emqx_schema:ssl_opts_schema(#{}, false),
+    Checked = validate(Sc, #{<<"versions">> => [<<"tlsv1.2">>]}),
+    ?assertMatch(#{versions := ['tlsv1.2']}, Checked),
+    #{ciphers := Ciphers} = Checked,
+    PskCiphers = emqx_schema:default_ciphers(psk),
+    lists:foreach(fun(Cipher) ->
+                          ?assert(lists:member(Cipher, Ciphers))
+                  end, PskCiphers).
+
+bad_cipher_test() ->
+    ok = snabbkaffe:start_trace(),
+    Sc = emqx_schema:ssl_opts_schema(#{}, false),
+    ?assertThrow({_Sc, [{validation_error, _Error}]},
+              [validate(Sc, #{<<"versions">> => [<<"tlsv1.2">>],
+                        <<"ciphers">> => [<<"foo">>]})]),
+    Trace = snabbkaffe:collect_trace(),
+    ?assertEqual(1, length(?of_kind(bad_tls_cipher_suite, Trace))),
+    snabbkaffe:stop(),
+    ok.
+
+validate(Schema, Data0) ->
+    Sc = #{ roots => [ssl_opts]
+          , fields => #{ssl_opts => Schema}
+          },
+    Data = Data0#{ cacertfile => <<"cacertfile">>
+                 , certfile => <<"certfile">>
+                 , keyfile => <<"keyfile">>
+                 },
+    #{ssl_opts := Checked} =
+        hocon_schema:check_plain(Sc, #{<<"ssl_opts">> => Data},
+                                 #{atom_key => true}),
+    Checked.
+
+ciperhs_schema_test() ->
+    Sc = emqx_schema:ciphers_schema(undefined),
+    ?assertMatch(
+       #{type := {union, [_, {array, _}]},
+         default := [_ | _],
+         converter := Converter,
+         validator := Validator
+        } when is_function(Converter) andalso is_function(Validator),
+       Sc),
+    WSc = #{roots => [{ciphers, Sc}]},
+    ?assertThrow({_, [{validation_error, _}]},
+                 hocon_schema:check_plain(WSc, #{<<"ciphers">> => <<"foo,bar">>})).

+ 17 - 0
apps/emqx_connector/src/emqx_connector_schema_lib.erl

@@ -61,6 +61,7 @@ fields("ssl") ->
     , {keyfile, fun keyfile/1}
     , {certfile, fun certfile/1}
     , {verify, fun verify/1}
+    , {server_name_indicator, fun server_name_indicator/1}
     ].
 
 ssl_fields() ->
@@ -150,3 +151,19 @@ to_servers(Str) ->
                      [{host, Ip}, {port, list_to_integer(Port)}]
              end
          end, string:tokens(Str, " , "))}.
+
+server_name_indicator(type) -> string();
+server_name_indicator(default) -> disable;
+server_name_indicator(desc) ->
+"""Specify the host name to be used in TLS Server Name Indication extension.<br>
+For instance, when connecting to \"server.example.net\", the genuine server 
+which accedpts the connection and performs TSL handshake may differ from the 
+host the TLS client initially connects to, e.g. when connecting to an IP address 
+or when the host has multiple resolvable DNS records <br>
+If not specified, it will default to the host name string which is used 
+to establish the connection, unless it is IP addressed used.<br>
+The host name is then also used in the host name verification of the peer 
+certificate.<br> The special value 'disable' prevents the Server Name
+Indication extension from being sent and disables the hostname 
+verification check.""";
+server_name_indicator(_) -> undefined.

+ 3 - 1
apps/emqx_dashboard/src/emqx_dashboard_schema.erl

@@ -45,7 +45,9 @@ fields("http") ->
     ];
 
 fields("https") ->
-    proplists:delete("fail_if_no_peer_cert", emqx_schema:ssl(#{})) ++ fields("http").
+    fields("http") ++
+    proplists:delete("fail_if_no_peer_cert",
+                     emqx_schema:ssl_opts_schema(#{}, true)).
 
 default_username(type) -> string();
 default_username(default) -> "admin";

+ 12 - 53
apps/emqx_gateway/src/emqx_gateway_schema.erl

@@ -163,7 +163,9 @@ fields(tcp_listener) ->
 
 fields(ssl_listener) ->
     fields(tcp_listener) ++
-    ssl_opts();
+    [{ssl, sc_meta(hoconsc:ref(emqx_schema, "ssl_opts"),
+                   #{desc => "SSL listener options"})}];
+
 
 fields(udp_listener) ->
     [
@@ -174,7 +176,8 @@ fields(udp_listener) ->
 
 fields(dtls_listener) ->
     fields(udp_listener) ++
-    dtls_opts();
+    [{dtls, sc_meta(ref(dtls_opts),
+                    #{desc => "DTLS listener options"})}];
 
 fields(udp_opts) ->
     [ {active_n, sc(integer(), 100)}
@@ -184,45 +187,13 @@ fields(udp_opts) ->
     , {reuseaddr, sc(boolean(), true)}
     ];
 
-fields(dtls_listener_ssl_opts) ->
-    Base = emqx_schema:fields("listener_ssl_opts"),
-    DtlsVers = hoconsc:mk(
-                 typerefl:alias("string", list(atom())),
-                 #{ default => default_dtls_vsns(),
-                    converter => fun (Vsns) ->
-                      [dtls_vsn(iolist_to_binary(V)) || V <- Vsns]
-                    end
-                  }),
-    Ciphers = sc(hoconsc:array(string()), default_ciphers()),
-    lists:keydelete(
-        "handshake_timeout", 1,
-        lists:keyreplace(
-            "ciphers", 1,
-            lists:keyreplace("versions", 1, Base, {"versions", DtlsVers}),
-            {"ciphers", Ciphers}
-         )
-     ).
-
-default_ciphers() ->
-    ["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"
-    ] ++ psk_ciphers().
-
-psk_ciphers() ->
-    ["PSK-AES128-CBC-SHA", "PSK-AES256-CBC-SHA",
-     "PSK-3DES-EDE-CBC-SHA", "PSK-RC4-SHA"
-    ].
+fields(dtls_opts) ->
+    emqx_schema:ssl_opts_schema(
+        #{ depth => 10
+         , reuse_sessions => true
+         , versions => dtls
+         , ciphers => dtls
+         }, false).
 
 % authentication() ->
 %     hoconsc:union(
@@ -270,23 +241,11 @@ tcp_opts() ->
 udp_opts() ->
     [{udp, sc_meta(ref(udp_opts), #{})}].
 
-ssl_opts() ->
-    [{ssl, sc_meta(ref(emqx_schema, "listener_ssl_opts"), #{})}].
-
-dtls_opts() ->
-    [{dtls, sc_meta(ref(dtls_listener_ssl_opts), #{})}].
-
 proxy_protocol_opts() ->
     [ {proxy_protocol, sc(boolean())}
     , {proxy_protocol_timeout, sc(duration())}
     ].
 
-default_dtls_vsns() ->
-    [<<"dtlsv1.2">>, <<"dtlsv1">>].
-
-dtls_vsn(<<"dtlsv1.2">>) -> 'dtlsv1.2';
-dtls_vsn(<<"dtlsv1">>) -> 'dtlsv1'.
-
 sc(Type) ->
     sc_meta(Type, #{}).
 

+ 1 - 1
apps/emqx_machine/src/emqx_machine_schema.erl

@@ -216,7 +216,7 @@ fields(cluster_etcd) ->
     ];
 
 fields(etcd_ssl_opts) ->
-    emqx_schema:ssl(#{});
+    emqx_schema:ssl_opts_schema(#{}, false);
 
 fields(cluster_k8s) ->
     [ {"apiserver",

+ 1 - 1
rebar.config

@@ -61,7 +61,7 @@
     , {observer_cli, "1.7.1"} % NOTE: depends on recon 2.5.x
     , {getopt, "1.0.2"}
     , {snabbkaffe, {git, "https://github.com/kafka4beam/snabbkaffe.git", {tag, "0.14.1"}}}
-    , {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.19.0"}}}
+    , {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.19.3"}}}
     , {emqx_http_lib, {git, "https://github.com/emqx/emqx_http_lib.git", {tag, "0.4.1"}}}
     , {esasl, {git, "https://github.com/emqx/esasl", {tag, "0.2.0"}}}
     , {jose, {git, "https://github.com/potatosalad/erlang-jose", {tag, "1.11.1"}}}