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