File 2541-Add-crypto-hash_equals-2.patch of Package erlang

From ad1341151c840612280575d7ae6b49f5e66ea175 Mon Sep 17 00:00:00 2001
From: gearnode <bryan@frimin.fr>
Date: Tue, 20 Apr 2021 13:43:12 +0200
Subject: [PATCH] Add crypto:hash_equals/2

---
 lib/crypto/c_src/Makefile.in     |   8 ++-
 lib/crypto/c_src/crypto.c        |   5 ++
 lib/crypto/c_src/hash_equals.c   |  51 +++++++++++++++
 lib/crypto/c_src/hash_equals.h   |  28 ++++++++
 lib/crypto/configure             | 107 +++++++++++++++++++++++++++++++
 lib/crypto/configure.in          |  42 ++++++++++++
 lib/crypto/doc/src/crypto.xml    |  14 ++++
 lib/crypto/src/crypto.erl        |  12 +++-
 lib/crypto/test/crypto_SUITE.erl |  17 ++++-
 9 files changed, 279 insertions(+), 5 deletions(-)
 create mode 100644 lib/crypto/c_src/hash_equals.c
 create mode 100644 lib/crypto/c_src/hash_equals.h

diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 2eee53bd31..669107e3e0 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -110,7 +110,9 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \
 	$(OBJDIR)/pkey$(TYPEMARKER).o \
 	$(OBJDIR)/rand$(TYPEMARKER).o \
 	$(OBJDIR)/rsa$(TYPEMARKER).o \
-	$(OBJDIR)/srp$(TYPEMARKER).o
+	$(OBJDIR)/srp$(TYPEMARKER).o \
+	$(OBJDIR)/hash_equals$(TYPEMARKER).o
+
 CALLBACK_OBJS = $(OBJDIR)/crypto_callback$(TYPEMARKER).o
 CRYPTO_STATIC_OBJS = $(patsubst $(OBJDIR)/%$(TYPEMARKER).o,$(OBJDIR)/%_static$(TYPEMARKER).o,$(CRYPTO_OBJS) $(CALLBACK_OBJS))
 
@@ -141,7 +143,7 @@ CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPT
 EXTRA_FLAGS = -DHAVE_DYNAMIC_CRYPTO_LIB
 else
 SSL_DED_LD_RUNTIME_LIBRARY_PATH=
-CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a 
+CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a
 EXTRA_FLAGS =
 CRYPTO_OBJS := $(CRYPTO_OBJS) $(CALLBACK_OBJS)
 CALLBACK_OBJS =
@@ -243,7 +245,7 @@ docs:
 
 # ----------------------------------------------------
 # Release Target
-# ---------------------------------------------------- 
+# ----------------------------------------------------
 include $(ERL_TOP)/make/otp_release_targets.mk
 
 release_spec: opt
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 5c0a1ccf6a..c1720ef869 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -42,6 +42,7 @@
 #include "evp.h"
 #include "fips.h"
 #include "hash.h"
+#include "hash_equals.h"
 #include "hmac.h"
 #include "info.h"
 #include "math.h"
@@ -89,6 +90,9 @@ static ErlNifFunc nif_funcs[] = {
     {"rand_uniform_nif", 2, rand_uniform_nif, 0},
     {"mod_exp_nif", 4, mod_exp_nif, 0},
     {"do_exor", 2, do_exor, 0},
+
+    {"hash_equals_nif", 2, hash_equals_nif, 0},
+    
     {"pkey_sign_nif", 5, pkey_sign_nif, 0},
     {"pkey_verify_nif", 6, pkey_verify_nif, 0},
     {"pkey_crypt_nif", 6, pkey_crypt_nif, 0},
diff --git a/lib/crypto/c_src/hash_equals.c b/lib/crypto/c_src/hash_equals.c
new file mode 100644
index 0000000000..85f54b14eb
--- /dev/null
+++ b/lib/crypto/c_src/hash_equals.c
@@ -0,0 +1,51 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2021. 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.
+ *
+ * %CopyrightEnd%
+
+ */
+
+#include "common.h"
+#include "hash_equals.h"
+
+ERL_NIF_TERM hash_equals_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#ifdef HAVE_OPENSSL_CRYPTO_MEMCMP
+    ErlNifBinary s1, s2;
+
+    ASSERT(argc == 2);
+
+    if (!enif_inspect_binary(env, argv[0], &s1))
+        goto bad_arg;
+    if (!enif_inspect_binary(env, argv[1], &s2))
+        goto bad_arg;
+
+    if (s1.size != s2.size)
+        goto err;
+
+    if (CRYPTO_memcmp(s1.data, s2.data, s1.size) == 0)
+        return enif_make_atom(env, "true");
+
+    return enif_make_atom(env, "false");
+
+ bad_arg:
+ err:
+    return enif_make_badarg(env);
+#else
+    return EXCP_NOTSUP(env, "Unsupported CRYPTO_memcmp");
+#endif
+}
diff --git a/lib/crypto/c_src/hash_equals.h b/lib/crypto/c_src/hash_equals.h
new file mode 100644
index 0000000000..966862c828
--- /dev/null
+++ b/lib/crypto/c_src/hash_equals.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2021. 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.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_HASH_EQUALS_H__
+#define E_HASH_EQUALS_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM hash_equals_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_HASH_EQUALS_H__ */
diff --git a/lib/crypto/configure b/lib/crypto/configure
index 82e882c337..fca74ed407 100755
--- a/lib/crypto/configure
+++ b/lib/crypto/configure
@@ -2130,6 +2130,52 @@ rm -f conftest.val
   as_fn_set_status $ac_retval
 
 } # ac_fn_c_compute_int
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
@@ -6259,6 +6305,67 @@ else
    SSL_FLAGS=
 fi
 
+saveCFLAGS="$CFLAGS"
+saveLDFLAGS="$LDFLAGS"
+saveLIBS="$LIBS"
+CFLAGS="$DED_BASIC_CFLAGS $SSL_INCLUDE"
+if test $SSL_DYNAMIC_ONLY = yes; then
+   LDFLAGS="$DED_LDFLAGS_CONFTEST $ded_ld_rpath -L$SSL_LIBDIR"
+   LIBS="$LIBS -l$SSL_CRYPTO_LIBNAME $SSL_EXTRA_LIBS"
+else
+   LDFLAGS="$DED_LDFLAGS_CONFTEST"
+   if test "$host_os" = "win32" ; then
+      LIBS="$LIBS $SSL_LIBDIR/$SSL_CRYPTO_LIBNAME.lib $SSL_EXTRA_LIBS"
+   else
+      LIBS="$LIBS $SSL_LIBDIR/lib$SSL_CRYPTO_LIBNAME.a $SSL_EXTRA_LIBS"
+   fi
+fi
+ac_fn_c_check_decl "$LINENO" "CRYPTO_memcmp" "ac_cv_have_decl_CRYPTO_memcmp" "#include <openssl/crypto.h>
+"
+if test "x$ac_cv_have_decl_CRYPTO_memcmp" = xyes; then :
+  have_crypto_memcmp_decl=yes
+else
+  have_crypto_memcmp_decl=no
+fi
+
+if test $have_crypto_memcmp_decl = yes; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CRYPTO_memcmp can be linked" >&5
+$as_echo_n "checking whether CRYPTO_memcmp can be linked... " >&6; }
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		#include <openssl/crypto.h>
+
+int
+main ()
+{
+
+		CRYPTO_memcmp("a", "b", 1);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+	    SSL_FLAGS="-DHAVE_OPENSSL_CRYPTO_MEMCMP $SSL_FLAGS"
+   	    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+   	    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+CFLAGS="$saveCFLAGS"
+LDFLAGS="$saveLDFLAGS"
+LIBS="$saveLIBS"
+
 
 
 
diff --git a/lib/crypto/configure.in b/lib/crypto/configure.in
index e71b2482c6..f7f98fe930 100644
--- a/lib/crypto/configure.in
+++ b/lib/crypto/configure.in
@@ -791,6 +791,48 @@ else
    SSL_FLAGS=
 fi
 
+saveCFLAGS="$CFLAGS"
+saveLDFLAGS="$LDFLAGS"
+saveLIBS="$LIBS"
+CFLAGS="$DED_BASIC_CFLAGS $SSL_INCLUDE"
+if test $SSL_DYNAMIC_ONLY = yes; then
+   LDFLAGS="$DED_LDFLAGS_CONFTEST $ded_ld_rpath -L$SSL_LIBDIR"
+   LIBS="$LIBS -l$SSL_CRYPTO_LIBNAME $SSL_EXTRA_LIBS"
+else
+   LDFLAGS="$DED_LDFLAGS_CONFTEST"
+   if test "$host_os" = "win32" ; then
+      LIBS="$LIBS $SSL_LIBDIR/$SSL_CRYPTO_LIBNAME.lib $SSL_EXTRA_LIBS"
+   else
+      LIBS="$LIBS $SSL_LIBDIR/lib$SSL_CRYPTO_LIBNAME.a $SSL_EXTRA_LIBS"
+   fi
+fi
+AC_CHECK_DECL(CRYPTO_memcmp,
+	      [have_crypto_memcmp_decl=yes],
+	      [have_crypto_memcmp_decl=no],
+	      [#include <openssl/crypto.h>])
+if test $have_crypto_memcmp_decl = yes; then
+   AC_MSG_CHECKING([whether CRYPTO_memcmp can be linked])
+   AC_LINK_IFELSE(
+	[AC_LANG_PROGRAM(
+	    [[
+		#include <openssl/crypto.h>
+	    ]],
+	    [[ 
+		CRYPTO_memcmp("a", "b", 1);
+	    ]])],
+	[
+	    SSL_FLAGS="-DHAVE_OPENSSL_CRYPTO_MEMCMP $SSL_FLAGS"
+   	    AC_MSG_RESULT([yes])
+	],
+	[
+   	    AC_MSG_RESULT([no])
+	])
+fi
+
+CFLAGS="$saveCFLAGS"
+LDFLAGS="$saveLDFLAGS"
+LIBS="$saveLIBS"
+
 AC_SUBST(SSL_INCLUDE)
 AC_SUBST(SSL_INCDIR)
 AC_SUBST(SSL_LIBDIR)
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 9a38ec53f4..6c9c154c05 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -2042,6 +2042,20 @@ FloatValue = rand:uniform().     % again
       </desc>
     </func>
 
+    <func>
+      <name name="hash_equals" arity="2" since=""/>
+      <fsummary>Constant time memory comparison for fixed length binaries</fsummary>
+      <desc>
+        <p>
+          Constant time memory comparison for fixed length binaries, such as results of HMAC computations.
+        </p>
+        <p>
+          Returns true if the binaries are identical, false if they are of the same length but not identical.
+          The function raises an <c>error:badarg</c> exception if the binaries are of different size.
+        </p>
+      </desc>
+    </func>
+
  </funcs>
 
  <funcs>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index d917caeae9..138f239b54 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -228,6 +228,8 @@
          crypto_final/1,
          crypto_get_data/1,
 
+         hash_equals/2,
+
          supports/1,
          mac/3, mac/4, macN/4, macN/5,
          mac_init/2, mac_init/3, mac_update/2, mac_final/1, mac_finalN/2
@@ -831,7 +833,6 @@ mac(Type, SubType, Key0, Data) ->
 mac(Type, SubType, Key, Data) -> mac_nif(Type, SubType, Key, Data).
 
 
-
 -spec macN(Type :: poly1305, Key, Data, MacLength) -> Mac | descriptive_error()
                      when Key :: iodata(),
                           Data :: iodata(),
@@ -2794,6 +2795,15 @@ exor(Data1, Data2, _Size, MaxByts, Acc) ->
 
 do_exor(_A, _B) -> ?nif_stub.
 
+-spec hash_equals(BinA, BinB) -> Result
+          when BinA :: binary(),
+               BinB :: binary(),
+               Result :: boolean().
+hash_equals(A, B) ->
+  hash_equals_nif(A, B).
+
+hash_equals_nif(_A, _B) -> ?nif_stub.
+
 hash_algorithms() -> ?nif_stub.
 pubkey_algorithms() -> ?nif_stub.
 cipher_algorithms() -> ?nif_stub.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index dcc43fa01e..af83e726f0 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -128,6 +128,8 @@
          rand_threads/1,
          rand_uniform/0,
          rand_uniform/1,
+         hash_equals/0,
+         hash_equals/1,
          sign_verify/0,
          sign_verify/1,
          stream/0,
@@ -236,7 +238,8 @@ all() ->
      rand_plugin,
      rand_plugin_s,
      cipher_info,
-     hash_info
+     hash_info,
+     hash_equals
     ].
 
 -define(NEW_CIPHER_TYPE_SCHEMA,
@@ -1332,6 +1335,18 @@ exor(Config) when is_list(Config) ->
     do_exor(<<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>),
     do_exor(term_to_binary(lists:seq(1, 1000000))).
 %%--------------------------------------------------------------------
+hash_equals() ->
+    [{doc, "Test the hash_equals function"}].
+hash_equals(Config) when is_list(Config) ->
+    try
+        true = crypto:hash_equals(<<>>, <<>>),
+        true = crypto:hash_equals(<<"abc">>, <<"abc">>),
+        false = crypto:hash_equals(<<"abc">>, <<"abe">>)
+    catch
+        error:{notsup,{"hash_equals.c",_Line},"Unsupported CRYPTO_memcmp"} ->
+            {skip, "No CRYPTO_memcmp"}
+    end.
+%%--------------------------------------------------------------------
 rand_uniform() ->
     [{doc, "rand_uniform and random_bytes testing"}].
 rand_uniform(Config) when is_list(Config) ->
-- 
2.26.2

openSUSE Build Service is sponsored by