]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Support libcrypto for hmac and sha256 (#223)
authorTobias Heider <tobias.heider@canonical.com>
Mon, 25 Sep 2023 08:49:00 +0000 (10:49 +0200)
committerGitHub <noreply@github.com>
Mon, 25 Sep 2023 08:49:00 +0000 (09:49 +0100)
* compat: Add OpenSSL libcrypto compatibility layer

Detect libcrypto in configure script.  Only fall back
to using libcrypto when /usr libs are allowed and no
other compatible implementation is available or when
--with-openssl is passed explicitly.
Make sure libcrypto and libmd are never linked at the
same time.

Add OpenSSL based SHA256 and HMAC compat shims in
compat/crypt_openssl. Depeding on version and build flags,
libcrypto ships with a compatible SHA256 API in
"openssl/sha.h".  OpenSSL 3 has deprecated the SHA API,
so if it is not detected we fall back to an EVP_DIGEST
based version.
Because the API might still be in use in OpenSSL internally,
the compatibility wrappers have a dhcpcd_ prefix to avoid
symbol conflicts.

* Add sha256 tests based on the existing hmac-md5 tests.

compat/crypt_openssl/hmac.c [new file with mode: 0644]
compat/crypt_openssl/hmac.h [new file with mode: 0644]
compat/crypt_openssl/sha256.c [new file with mode: 0644]
compat/crypt_openssl/sha256.h [new file with mode: 0644]
configure
src/dhcpcd.c
tests/crypt/Makefile
tests/crypt/run-test.c
tests/crypt/test.h
tests/crypt/test_sha256.c [new file with mode: 0644]

diff --git a/compat/crypt_openssl/hmac.c b/compat/crypt_openssl/hmac.c
new file mode 100644 (file)
index 0000000..5f55cc3
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2023 Canonical Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+#include "openssl/hmac.h"
+
+ssize_t
+hmac(const char *name,
+    const void *key, size_t klen,
+    const void *text, size_t tlen,
+    void *digest, size_t dlen)
+{
+       const EVP_MD    *md;
+       unsigned int     outlen;
+
+       if (strcmp(name, "md5") == 0)
+               md = EVP_md5();
+       else if (strcmp(name, "sha256") == 0)
+               md = EVP_sha1();
+       else
+               return -1;
+
+       HMAC(md, key, (int)klen, text, tlen, digest, &outlen);
+       if (dlen != outlen)
+               return -1;
+
+       return (ssize_t)outlen;
+}
diff --git a/compat/crypt_openssl/hmac.h b/compat/crypt_openssl/hmac.h
new file mode 100644 (file)
index 0000000..5729ed5
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2023 Canonical Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef HMAC_H
+#define HMAC_H
+
+#include <sys/types.h>
+
+ssize_t         hmac(const char *, const void *, size_t, const void *, size_t, void *,
+   size_t);
+
+#endif
diff --git a/compat/crypt_openssl/sha256.c b/compat/crypt_openssl/sha256.c
new file mode 100644 (file)
index 0000000..a159583
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2023 Canonical Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "sha256.h"
+
+#include "openssl/evp.h"
+
+/* SHA-256 initialization.  Begins a SHA-256 operation. */
+void
+dhcpcd_SHA256_Init(SHA256_CTX *ctx)
+{
+       ctx->c = EVP_MD_CTX_new();
+       EVP_DigestInit_ex2(ctx->c, EVP_sha256(), NULL);
+}
+
+/* Add bytes into the hash */
+void
+dhcpcd_SHA256_Update(SHA256_CTX *ctx, const void *in, size_t len)
+{
+       EVP_DigestUpdate(ctx->c, in, len);
+}
+
+/*
+ * SHA-256 finalization.  Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+dhcpcd_SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
+{
+       EVP_DigestFinal_ex(ctx->c, digest, NULL);
+       EVP_MD_CTX_free(ctx->c);
+}
diff --git a/compat/crypt_openssl/sha256.h b/compat/crypt_openssl/sha256.h
new file mode 100644 (file)
index 0000000..74fabab
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2023 Canonical Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SHA256_H_
+#define SHA256_H_
+
+#define SHA256_DIGEST_LENGTH           32
+
+#include "openssl/evp.h"
+typedef struct dhcpcd_SHA256Context {
+       EVP_MD_CTX *c;
+} dhcpcd_SHA256_CTX;
+
+void   dhcpcd_SHA256_Init(dhcpcd_SHA256_CTX *);
+void   dhcpcd_SHA256_Update(dhcpcd_SHA256_CTX *, const void *, size_t);
+void   dhcpcd_SHA256_Final(unsigned char [32], dhcpcd_SHA256_CTX *);
+
+#define SHA256_Init    dhcpcd_SHA256_Init
+#define SHA256_Update  dhcpcd_SHA256_Update
+#define SHA256_Final   dhcpcd_SHA256_Final
+#define SHA256_CTX     dhcpcd_SHA256_CTX
+
+#endif
index 4fb29b06f19ea3f03d29ea123b88ea226d6b60f2..3d130a04b6ee49511364a0f918bcb816c88aa257 100755 (executable)
--- a/configure
+++ b/configure
@@ -37,6 +37,7 @@ POLL=
 SMALL=
 SANITIZE=no
 STATUSARG=
+OPENSSL=
 
 DHCPCD_DEFS=dhcpcd-definitions.conf
 
@@ -110,6 +111,8 @@ for x do
        --with-udev) DEV=yes; UDEV=yes;;
        --without-udev) UDEV=no;;
        --with-poll) POLL="$var";;
+       --with-openssl) OPENSSL=yes;;
+       --without-openssl) OPENSSL=no;;
        --sanitise|--sanitize) SANITIZEADDRESS="yes";;
        --serviceexists) SERVICEEXISTS=$var;;
        --servicecmd) SERVICECMD=$var;;
@@ -1350,14 +1353,6 @@ if [ "$FLS64" = yes ]; then
        echo "#define   HAVE_SYS_BITOPS_H" >>$CONFIG_H
 fi
 
-# Workaround for DragonFlyBSD import
-if [ "$OS" = dragonfly ]; then
-       echo "#ifdef    USE_PRIVATECRYPTO" >>$CONFIG_H
-       echo "#define   HAVE_MD5_H" >>$CONFIG_H
-       echo "#define   SHA2_H                  <openssl/sha.h>" >>$CONFIG_H
-       echo "#else" >>$CONFIG_H
-fi
-
 if [ -z "$MD5" ]; then
        MD5_LIB=
        printf "Testing for MD5Init ... "
@@ -1388,14 +1383,6 @@ EOF
        echo "$MD5"
        rm -f _md5.c _md5
 fi
-if [ "$MD5" = no ]; then
-       echo "#include                  \"compat/crypt/md5.h\"" >>$CONFIG_H
-       echo "MD5_SRC=  compat/crypt/md5.c" >>$CONFIG_MK
-else
-       echo "MD5_SRC=" >>$CONFIG_MK
-       echo "#define   HAVE_MD5_H" >>$CONFIG_H
-       [ -n "$MD5_LIB" ] && echo "LDADD+=              $MD5_LIB" >>$CONFIG_MK
-fi
 
 if [ -z "$SHA2_H" ]; then
        if [ -z "$SHA2" ] || [ "$SHA2" != no ]; then
@@ -1481,23 +1468,6 @@ EOF
                rm -f _sha256.c _sha256
        fi
 fi
-if [ "$SHA2" = no ]; then
-       echo "#include                  \"compat/crypt/sha256.h\"" >>$CONFIG_H
-       echo "SHA256_SRC=       compat/crypt/sha256.c" >>$CONFIG_MK
-else
-       echo "SHA256_SRC=" >>$CONFIG_MK
-       echo "#define   SHA2_H                  <$SHA2_H>" >>$CONFIG_H
-       if [ "$SHA2_RENAMED" = yes ]; then
-               echo "#define   SHA256_CTX      SHA2_CTX" >>$CONFIG_H
-               echo "#define   SHA256_Init     SHA256Init" >>$CONFIG_H
-               echo "#define   SHA256_Update   SHA256Update" >>$CONFIG_H
-               echo "#define   SHA256_Final    SHA256Final" >>$CONFIG_H
-       fi
-       [ -n "$SHA2_LIB" ] && echo "LDADD+=             $SHA2_LIB" >>$CONFIG_MK
-fi
-
-# Workarond for DragonFlyBSD import
-[ "$OS" = dragonfly ] && echo "#endif" >>$CONFIG_H
 
 if [ -z "$HMAC" ]; then
        HMAC_LIB=
@@ -1530,7 +1500,108 @@ EOF
        echo "$HMAC"
        rm -f _hmac.c _hmac
 fi
-if [ "$HMAC" = no ]; then
+
+if [ "$OPENSSL" = yes ] ||
+   { [ -z "$OPENSSL" ] && [ "$ALLOW_USR_LIBS" = true ] &&
+     [ "$SHA2" = no ] &&  [ "$HMAC" = no ];
+   }; then
+       printf "Testing for openssl ... "
+       if type "$PKG_CONFIG" >/dev/null 2>&1; then
+               LIBCRYPTO_CFLAGS=$("$PKG_CONFIG" --cflags libcrypto 2>&3)
+               LIBCRYPTO_LIBS=$("$PKG_CONFIG" --libs libcrypto 2>&3)
+       fi
+
+       cat <<EOF >_openssl.c
+#include <stdio.h>
+#include <openssl/crypto.h>
+int main(void) {
+       return OPENSSL_init_crypto(0, NULL) == 1;
+}
+EOF
+       if $XCC $LIBCRYPTO_CFLAGS _openssl.c -o _openssl $LIBCRYPTO_LIBS 2>&3;
+       then
+               OPENSSL=yes
+               MD5=yes
+               MD5_LIB=
+               if [ -n "$LIBCRYPTO_CFLAGS" ]; then
+                       echo "CFLAGS+=          $LIBCRYPTO_CFLAGS" >>$CONFIG_MK
+               fi
+               echo "LDADD+=           $LIBCRYPTO_LIBS" >>$CONFIG_MK
+               echo "#define   HAVE_OPENSSL" >>$CONFIG_H
+       else
+               OPENSSL=no
+       fi
+       echo "$OPENSSL"
+       rm -f _openssl.c _openssl
+fi
+
+if [ "$OPENSSL" = yes ]; then
+       printf "Testing for openssl/sha.h ... "
+       cat <<EOF >_openssl_sha.c
+#include <stdio.h>
+#include <openssl/sha.h>
+
+int main(void) {
+       SHA256_CTX ctx;
+       SHA256_Init(&ctx);
+       return 0;
+}
+EOF
+       if $XCC $LIBCRYPTO_CFLAGS _openssl_sha.c -o _openssl_sha \
+          $LIBCRYPTO_LIBS 2>&3; then
+               SHA2_H=openssl/sha.h
+               SHA2="yes (-lcrypto)"
+       else
+               SHA2=no
+       fi
+       SHA2_LIB=
+       SHA2_RENAMED=
+       echo "$SHA2"
+       rm -f _openssl_sha.c _openssl_sha
+fi
+
+# Workaround for DragonFlyBSD import
+if [ "$OS" = dragonfly ]; then
+       echo "#ifdef    USE_PRIVATECRYPTO" >>$CONFIG_H
+       echo "#define   HAVE_MD5_H" >>$CONFIG_H
+       echo "#define   SHA2_H                  <openssl/sha.h>" >>$CONFIG_H
+       echo "#else" >>$CONFIG_H
+fi
+
+if [ "$MD5" = no ]; then
+       echo "#include                  \"compat/crypt/md5.h\"" >>$CONFIG_H
+       echo "MD5_SRC=  compat/crypt/md5.c" >>$CONFIG_MK
+else
+       echo "MD5_SRC=" >>$CONFIG_MK
+       [ "$OPENSSL" != yes ] && echo "#define  HAVE_MD5_H" >>$CONFIG_H
+       [ -n "$MD5_LIB" ] && echo "LDADD+=              $MD5_LIB" >>$CONFIG_MK
+fi
+
+if [ "$OPENSSL" = yes ] && [ "$SHA2" = no ]; then
+       echo "#include                  \"compat/crypt_openssl/sha256.h\"" >>$CONFIG_H
+       echo "SHA256_SRC=       compat/crypt_openssl/sha256.c" >>$CONFIG_MK
+elif [ "$SHA2" = no ]; then
+       echo "#include                  \"compat/crypt/sha256.h\"" >>$CONFIG_H
+       echo "SHA256_SRC=       compat/crypt/sha256.c" >>$CONFIG_MK
+else
+       echo "SHA256_SRC=" >>$CONFIG_MK
+       echo "#define   SHA2_H                  <$SHA2_H>" >>$CONFIG_H
+       if [ "$SHA2_RENAMED" = yes ]; then
+               echo "#define   SHA256_CTX      SHA2_CTX" >>$CONFIG_H
+               echo "#define   SHA256_Init     SHA256Init" >>$CONFIG_H
+               echo "#define   SHA256_Update   SHA256Update" >>$CONFIG_H
+               echo "#define   SHA256_Final    SHA256Final" >>$CONFIG_H
+       fi
+       [ -n "$SHA2_LIB" ] && echo "LDADD+=             $SHA2_LIB" >>$CONFIG_MK
+fi
+
+# Workarond for DragonFlyBSD import
+[ "$OS" = dragonfly ] && echo "#endif" >>$CONFIG_H
+
+if [ "$OPENSSL" = yes ]; then
+       echo "#include                  \"compat/crypt_openssl/hmac.h\"" >>$CONFIG_H
+       echo "HMAC_SRC= compat/crypt_openssl/hmac.c" >>$CONFIG_MK
+elif [ "$HMAC" = no ]; then
        echo "#include                  \"compat/crypt/hmac.h\"" >>$CONFIG_H
        echo "HMAC_SRC= compat/crypt/hmac.c" >>$CONFIG_MK
 else
index 688a3a6d3d5b61183732484aba3de943edd3841a..cc5dfb584c4f0d8453b1bd6ef0ad6aa7d63e1f20 100644 (file)
@@ -75,6 +75,9 @@ static const char dhcpcd_copyright[] = "Copyright (c) 2006-2023 Roy Marples";
 #ifdef HAVE_CAPSICUM
 #include <sys/capsicum.h>
 #endif
+#ifdef HAVE_OPENSSL
+#include <openssl/crypto.h>
+#endif
 #ifdef HAVE_UTIL_H
 #include <util.h>
 #endif
@@ -2197,6 +2200,11 @@ printpidfile:
        }
 #endif
 
+#ifdef HAVE_OPENSSL
+       OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS |
+           OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CONFIG, NULL);
+#endif
+
 #ifdef PRIVSEP
        ps_init(&ctx);
 #endif
index dd676f4b2aa920e405c1ce8ac39b32c92fd1cfb2..c3df1a31f5ad36f9381158384010821d509ec02d 100644 (file)
@@ -3,7 +3,7 @@ include ${TOP}/iconfig.mk
 
 PROG=          run-test
 SRCS=          run-test.c
-SRCS+=         test_hmac_md5.c
+SRCS+=         test_hmac_md5.c test_sha256.c
 
 CFLAGS?=       -O2
 CSTD?=         c99
index 42f52d1fce2d83460204b8b10b33a13f6c3c067a..91cc898303054473fe38b01a4e09e06f72992b26 100644 (file)
@@ -33,6 +33,8 @@ int main(void)
 
        if (test_hmac_md5())
                r = -1;
+       if (test_sha256())
+               r = -1;
 
        return r;
 }
index 4f716f1220f48b716d39c915223290d4b7498d22..3c9070a5c83d782a2ab4e2320c16199cd8358ea2 100644 (file)
@@ -28,5 +28,6 @@
 #ifndef TEST_H
 
 int test_hmac_md5(void);
+int test_sha256(void);
 
 #endif
diff --git a/tests/crypt/test_sha256.c b/tests/crypt/test_sha256.c
new file mode 100644 (file)
index 0000000..986e051
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2023 Tobias Heider <tobias.heider@canonical.com>
+ * Copyright (c) 2006-2018 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "test.h"
+
+#ifdef SHA2_H
+#include SHA2_H
+#endif
+
+# ifndef SHA256_DIGEST_LENGTH
+#  define SHA256_DIGEST_LENGTH          32
+# endif
+
+static void
+print_md(FILE *stream, const uint8_t *md)
+{
+       int i;
+
+       fprintf(stream, "digest = 0x");
+       for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+               fprintf(stream, "%02x", *md++);
+       fprintf(stream, "\n");
+}
+
+static void
+test_md(const uint8_t *md, const uint8_t *tst)
+{
+       print_md(stdout, md);
+       if (memcmp(md, tst, SHA256_DIGEST_LENGTH) == 0)
+               return;
+       fprintf(stderr, "FAILED!\nExpected\t\t\t");
+       print_md(stderr, tst);
+       exit(EXIT_FAILURE);
+}
+
+static void
+sha256_test1(void)
+{
+       const uint8_t text[] = "Hi There";
+       const uint8_t expect[SHA256_DIGEST_LENGTH] = {
+               0xcc, 0x6d, 0x58, 0x96, 0xd7, 0x70, 0x10, 0x1e,
+               0xf0, 0x28, 0x0c, 0x94, 0x3a, 0x2d, 0x3c, 0x3f,
+               0x24, 0xcd ,0x5b, 0x11, 0x46, 0x4a, 0x51, 0x86,
+               0xda, 0xf7, 0xa2, 0x38, 0x47, 0x71, 0x62, 0xac
+       };
+       uint8_t digest[SHA256_DIGEST_LENGTH];
+       SHA256_CTX ctx;
+
+       printf ("SHA256 Test 1:\t\t");
+       SHA256_Init(&ctx);
+       SHA256_Update(&ctx, text, 8);
+       SHA256_Final(digest, &ctx);
+       test_md(digest, expect);
+}
+
+static void
+sha256_test2(void)
+{
+       const uint8_t text[] = "what do ya want for nothing?";
+       const uint8_t expect[SHA256_DIGEST_LENGTH] = {
+               0xb3, 0x81, 0xe7, 0xfe, 0xc6, 0x53, 0xfc, 0x3a,
+               0xb9, 0xb1, 0x78, 0x27, 0x23, 0x66, 0xb8, 0xac,
+               0x87, 0xfe, 0xd8, 0xd3, 0x1c, 0xb2, 0x5e, 0xd1,
+               0xd0, 0xe1, 0xf3, 0x31, 0x86, 0x44, 0xc8, 0x9c,
+       };
+       uint8_t digest[SHA256_DIGEST_LENGTH];
+       SHA256_CTX ctx;
+
+       printf ("SHA256 Test 2:\t\t");
+       SHA256_Init(&ctx);
+       SHA256_Update(&ctx, text, 28);
+       SHA256_Final(digest, &ctx);
+       test_md(digest, expect);
+}
+
+static void
+sha256_test3(void)
+{
+       const uint8_t expect[SHA256_DIGEST_LENGTH] = {
+               0x5c, 0xf6, 0x18, 0xb5, 0xb6, 0xd3, 0x8b, 0xd1,
+               0x6c, 0x2e, 0x55, 0x8e, 0xef, 0x4d, 0x4b, 0x6d,
+               0x52, 0x82, 0x84, 0x54, 0x7f, 0xd4, 0xa0, 0x9d,
+               0xa2, 0xab, 0xb6, 0xf0, 0x98, 0xec, 0x61, 0x93,
+       };
+       uint8_t digest[SHA256_DIGEST_LENGTH];
+       uint8_t text[50];
+       int i;
+       SHA256_CTX ctx;
+
+       printf ("SHA256 Test 3:\t\t");
+       for (i = 0; i < 50; i++)
+               text[i] = 0xdd;
+       SHA256_Init(&ctx);
+       SHA256_Update(&ctx, text, 50);
+       SHA256_Final(digest, &ctx);
+       test_md(digest, expect);
+}
+
+int test_sha256(void)
+{
+       printf ("Starting SHA256 tests...\n\n");
+       sha256_test1();
+       sha256_test2();
+       sha256_test3();
+       printf("\nAll tests pass.\n");
+       return 0;
+}