Kaynağa Gözat

Merge pull request #14305 from qzhuyan/dev/william/bump-mongodb-3.0.24

fix: use safer crypto:pbkdf2_hmac
William Yang 1 yıl önce
ebeveyn
işleme
b3ad958590

+ 0 - 1
apps/emqx/mix.exs

@@ -49,7 +49,6 @@ defmodule EMQX.MixProject do
       UMP.common_dep(:hocon),
       UMP.common_dep(:ranch),
       UMP.common_dep(:bcrypt),
-      UMP.common_dep(:pbkdf2),
       UMP.common_dep(:emqx_http_lib),
     ] ++ UMP.quicer_dep()
   end

+ 0 - 1
apps/emqx/rebar.config

@@ -33,7 +33,6 @@
     {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "3.4.1"}}},
     {hocon, {git, "https://github.com/emqx/hocon.git", {tag, "0.43.4"}}},
     {emqx_http_lib, {git, "https://github.com/emqx/emqx_http_lib.git", {tag, "0.5.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, "1.0.10"}}}
 ]}.

+ 0 - 1
apps/emqx/src/emqx.app.src

@@ -20,7 +20,6 @@
         hocon,
         emqx_ds_backends,
         bcrypt,
-        pbkdf2,
         emqx_http_lib,
         recon,
         os_mon

+ 34 - 15
apps/emqx/src/emqx_passwd.erl

@@ -43,7 +43,7 @@
 -type salt_position() :: disable | prefix | suffix.
 -type salt() :: binary().
 
--type pbkdf2_mac_fun() :: md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512.
+-type pbkdf2_mac_fun() :: sha | sha224 | sha256 | sha384 | sha512.
 -type pbkdf2_iterations() :: pos_integer().
 -type pbkdf2_dk_length() :: pos_integer() | undefined.
 
@@ -65,12 +65,8 @@ check_pass(Algo, Hash, Password) ->
     do_check_pass(Algo, Hash, Password).
 
 do_check_pass({pbkdf2, MacFun, Salt, Iterations, DKLength}, PasswordHash, Password) ->
-    case pbkdf2(MacFun, Password, Salt, Iterations, DKLength) of
-        {ok, HashPasswd} ->
-            compare_secure(hex(HashPasswd), PasswordHash);
-        {error, _Reason} ->
-            false
-    end;
+    HashPasswd = pbkdf2(MacFun, Password, Salt, Iterations, DKLength),
+    compare_secure(hex(HashPasswd), PasswordHash);
 do_check_pass({bcrypt, Salt}, PasswordHash, Password) ->
     case bcrypt:hashpw(Password, Salt) of
         {ok, HashPasswd} ->
@@ -84,12 +80,8 @@ do_check_pass({_SimpleHash, _Salt, _SaltPosition} = HashParams, PasswordHash, Pa
 
 -spec hash(hash_params(), password()) -> password_hash().
 hash({pbkdf2, MacFun, Salt, Iterations, DKLength}, Password) when Iterations > 0 ->
-    case pbkdf2(MacFun, Password, Salt, Iterations, DKLength) of
-        {ok, HashPasswd} ->
-            hex(HashPasswd);
-        {error, Reason} ->
-            error(Reason)
-    end;
+    HashPasswd = pbkdf2(MacFun, Password, Salt, Iterations, DKLength),
+    hex(HashPasswd);
 hash({bcrypt, Salt}, Password) ->
     case bcrypt:hashpw(Password, Salt) of
         {ok, HashPasswd} ->
@@ -139,11 +131,38 @@ compare_secure([X | RestX], [Y | RestY], Result) ->
 compare_secure([], [], Result) ->
     Result == 0.
 
+-define(MAX_DERIVED_KEY_LENGTH, (1 bsl 32 - 1)).
 pbkdf2(MacFun, Password, Salt, Iterations, undefined) ->
-    pbkdf2:pbkdf2(MacFun, Password, Salt, Iterations);
+    crypto:pbkdf2_hmac(MacFun, Password, Salt, Iterations, dk_length(MacFun));
+pbkdf2(_MacFun, _Password, _Salt, _Iterations, DKLength) when DKLength > ?MAX_DERIVED_KEY_LENGTH ->
+    %% backword compatible with the old implementation in pbkdf2
+    error(dklength_too_long);
 pbkdf2(MacFun, Password, Salt, Iterations, DKLength) ->
-    pbkdf2:pbkdf2(MacFun, Password, Salt, Iterations, DKLength).
+    crypto:pbkdf2_hmac(MacFun, Password, Salt, Iterations, DKLength).
 
 hex(X) when is_binary(X) ->
     %% TODO: change to binary:encode_hex(X, lowercase) when OTP version is always > 25
     string:lowercase(binary:encode_hex(X)).
+
+%% @doc default derived key length for PBKDF2, backword compatible with the old implementation in pbkdf2
+-spec dk_length(pbkdf2_mac_fun()) -> non_neg_integer().
+dk_length(sha) -> 20;
+dk_length(sha224) -> 28;
+dk_length(sha256) -> 32;
+dk_length(sha384) -> 48;
+dk_length(sha512) -> 64.
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+len_match(Alg) ->
+    DKLength = byte_size(crypto:mac(hmac, Alg, <<"test key">>, <<"test data">>)),
+    dk_length(Alg) =:= DKLength.
+
+dk_length_test_() ->
+    [
+        ?_assert(len_match(Alg))
+     || Alg <- [sha, sha224, sha256, sha384, sha512]
+    ].
+
+-endif.

+ 4 - 2
apps/emqx/test/emqx_passwd_SUITE.erl

@@ -118,10 +118,12 @@ t_hash(_) ->
         "01dbee7f4a9e243e988b62c73cda935d"
         "a05378b93244ec8f48a99e61ad799d86"
     >>,
-    Pbkdf2 = emqx_passwd:hash({pbkdf2, sha, Pbkdf2Salt, 2, 32}, Password),
+    _Pbkdf2 = emqx_passwd:hash({pbkdf2, sha, Pbkdf2Salt, 2, 32}, Password),
     true = emqx_passwd:check_pass({pbkdf2, sha, Pbkdf2Salt, 2, 32}, Pbkdf2, Password),
     false = emqx_passwd:check_pass({pbkdf2, sha, Pbkdf2Salt, 2, 32}, Pbkdf2, WrongPassword),
-    false = emqx_passwd:check_pass({pbkdf2, sha, Pbkdf2Salt, 2, BadDKlen}, Pbkdf2, Password),
+    ?assertException(
+        error, _, emqx_passwd:check_pass({pbkdf2, sha, Pbkdf2Salt, 2, BadDKlen}, Pbkdf2, Password)
+    ),
 
     %% Invalid derived_length, pbkdf2 fails
     ?assertException(error, _, emqx_passwd:hash({pbkdf2, sha, Pbkdf2Salt, 2, BadDKlen}, Password)),

+ 1 - 1
apps/emqx_auth/src/emqx_auth.app.src

@@ -1,7 +1,7 @@
 %% -*- mode: erlang -*-
 {application, emqx_auth, [
     {description, "EMQX Authentication and authorization"},
-    {vsn, "0.4.2"},
+    {vsn, "0.4.3"},
     {modules, []},
     {registered, [emqx_auth_sup]},
     {applications, [

+ 5 - 1
apps/emqx_auth/src/emqx_authn/emqx_authn_password_hashing.erl

@@ -88,7 +88,11 @@ fields(pbkdf2) ->
         {mac_fun,
             sc(
                 hoconsc:enum([md4, md5, ripemd160, sha, sha224, sha256, sha384, sha512]),
-                #{required => true, desc => "Specifies mac_fun for PBKDF2 hashing algorithm."}
+                #{
+                    required => true,
+                    desc =>
+                        "Specifies mac_fun for PBKDF2 hashing algorithm and md4, md5, ripemd160 are no longer supported since 5.8.3"
+                }
             )},
         {iterations,
             sc(

+ 1 - 1
apps/emqx_mongodb/mix.exs

@@ -25,7 +25,7 @@ defmodule EMQXMongodb.MixProject do
     [
       {:emqx_connector, in_umbrella: true, runtime: false},
       {:emqx_resource, in_umbrella: true},
-      {:mongodb, github: "emqx/mongodb-erlang", tag: "v3.0.23"}
+      {:mongodb, github: "emqx/mongodb-erlang", tag: "v3.0.24"}
     ]
   end
 end

+ 1 - 1
apps/emqx_mongodb/rebar.config

@@ -4,5 +4,5 @@
 {deps, [
     {emqx_connector, {path, "../../apps/emqx_connector"}},
     {emqx_resource, {path, "../../apps/emqx_resource"}},
-    {mongodb, {git, "https://github.com/emqx/mongodb-erlang", {tag, "v3.0.23"}}}
+    {mongodb, {git, "https://github.com/emqx/mongodb-erlang", {tag, "v3.0.24"}}}
 ]}.

+ 6 - 0
changes/ce/breaking-14305.en.md

@@ -0,0 +1,6 @@
+Use safer pbkdf2_hmac implementation in following EMQX functions:
+
+- MongoDB integration
+- authn. Also removes support of md4, md5, ripemd160 as they are not FIPS_DIGEST.
+
+

+ 0 - 4
mix.exs

@@ -121,7 +121,6 @@ defmodule EMQXUmbrella.MixProject do
       common_dep(:minirest),
       common_dep(:ecpool),
       common_dep(:replayq),
-      common_dep(:pbkdf2),
       # maybe forbid to fetch quicer
       common_dep(:emqtt),
       common_dep(:rulesql),
@@ -233,9 +232,6 @@ defmodule EMQXUmbrella.MixProject do
 
   def common_dep(:rulesql), do: {:rulesql, github: "emqx/rulesql", tag: "0.2.1"}
 
-  def common_dep(:pbkdf2),
-    do: {:pbkdf2, github: "emqx/erlang-pbkdf2", tag: "2.0.4", override: true}
-
   def common_dep(:bcrypt),
     do: {:bcrypt, github: "emqx/erlang-bcrypt", tag: "0.6.2", override: true}
 

+ 0 - 1
rebar.config

@@ -89,7 +89,6 @@
     {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.4.4"}}},
     {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.12"}}},
     {replayq, {git, "https://github.com/emqx/replayq.git", {tag, "0.3.10"}}},
-    {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}},
     {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.13.5"}}},
     {rulesql, {git, "https://github.com/emqx/rulesql", {tag, "0.2.1"}}},
     % NOTE: depends on recon 2.5.x