From a24bdce46f95cbe9efd3b26f157d1eb36584861f Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 12 Dec 2014 13:55:30 -0800 Subject: [PATCH] mesa: Add mesa SHA-1 functions MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The upcoming shader cache uses the SHA-1 algorithm for cryptographic naming. These new mesa_sha1 functions are implemented with any one of several differeny cryptographics libraries. This code was copied from the xserver repository, (where it has apparently been functioning well on a variety of operating systems), and comes licensed with a license identical to that of Mesa. Bug fixes by José Fonseca : Fix to put conditional assignment in Makefile.am, not Makefile.sources to avoid breaking scons build. Fix include file for CryptoAPI section. Fix missing cast in openssl section. Reviewed-by: Matt Turner --- configure.ac | 124 +++++++++++++++ src/util/Makefile.am | 7 + src/util/Makefile.sources | 4 + src/util/sha1.c | 316 ++++++++++++++++++++++++++++++++++++++ src/util/sha1.h | 53 +++++++ 5 files changed, 504 insertions(+) create mode 100644 src/util/sha1.c create mode 100644 src/util/sha1.h diff --git a/configure.ac b/configure.ac index e9d73e4687a..5b867de4814 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,7 @@ dnl Copyright © 2009-2014 Jon TURNEY dnl Copyright © 2011-2012 Benjamin Franzke dnl Copyright © 2008-2014 David Airlie dnl Copyright © 2009-2013 Brian Paul +dnl Copyright © 2003-2007 Keith Packard, Daniel Stone dnl dnl Permission is hereby granted, free of charge, to any person obtaining a dnl copy of this software and associated documentation files (the "Software"), @@ -924,6 +925,129 @@ fi AC_SUBST([MESA_LLVM]) +# SHA1 hashing +AC_ARG_WITH([sha1], + [AS_HELP_STRING([--with-sha1=libc|libmd|libnettle|libgcrypt|libcrypto|libsha1|CommonCrypto|CryptoAPI], + [choose SHA1 implementation])]) +case "x$with_sha1" in +x | xlibc | xlibmd | xlibnettle | xlibgcrypt | xlibcrypto | xlibsha1 | xCommonCrypto | xCryptoAPI) + ;; +*) + AC_MSG_ERROR([Illegal value for --with-sha1: $with_sha1]) +esac + +AC_CHECK_FUNC([SHA1Init], [HAVE_SHA1_IN_LIBC=yes]) +if test "x$with_sha1" = x && test "x$HAVE_SHA1_IN_LIBC" = xyes; then + with_sha1=libc +fi +if test "x$with_sha1" = xlibc && test "x$HAVE_SHA1_IN_LIBC" != xyes; then + AC_MSG_ERROR([sha1 in libc requested but not found]) +fi +if test "x$with_sha1" = xlibc; then + AC_DEFINE([HAVE_SHA1_IN_LIBC], [1], + [Use libc SHA1 functions]) + SHA1_LIBS="" +fi +AC_CHECK_FUNC([CC_SHA1_Init], [HAVE_SHA1_IN_COMMONCRYPTO=yes]) +if test "x$with_sha1" = x && test "x$HAVE_SHA1_IN_COMMONCRYPTO" = xyes; then + with_sha1=CommonCrypto +fi +if test "x$with_sha1" = xCommonCrypto && test "x$HAVE_SHA1_IN_COMMONCRYPTO" != xyes; then + AC_MSG_ERROR([CommonCrypto requested but not found]) +fi +if test "x$with_sha1" = xCommonCrypto; then + AC_DEFINE([HAVE_SHA1_IN_COMMONCRYPTO], [1], + [Use CommonCrypto SHA1 functions]) + SHA1_LIBS="" +fi +dnl stdcall functions cannot be tested with AC_CHECK_LIB +AC_CHECK_HEADER([wincrypt.h], [HAVE_SHA1_IN_CRYPTOAPI=yes], [], [#include ]) +if test "x$with_sha1" = x && test "x$HAVE_SHA1_IN_CRYPTOAPI" = xyes; then + with_sha1=CryptoAPI +fi +if test "x$with_sha1" = xCryptoAPI && test "x$HAVE_SHA1_IN_CRYPTOAPI" != xyes; then + AC_MSG_ERROR([CryptoAPI requested but not found]) +fi +if test "x$with_sha1" = xCryptoAPI; then + AC_DEFINE([HAVE_SHA1_IN_CRYPTOAPI], [1], + [Use CryptoAPI SHA1 functions]) + SHA1_LIBS="" +fi +AC_CHECK_LIB([md], [SHA1Init], [HAVE_LIBMD=yes]) +if test "x$with_sha1" = x && test "x$HAVE_LIBMD" = xyes; then + with_sha1=libmd +fi +if test "x$with_sha1" = xlibmd && test "x$HAVE_LIBMD" != xyes; then + AC_MSG_ERROR([libmd requested but not found]) +fi +if test "x$with_sha1" = xlibmd; then + AC_DEFINE([HAVE_SHA1_IN_LIBMD], [1], + [Use libmd SHA1 functions]) + SHA1_LIBS=-lmd +fi +PKG_CHECK_MODULES([LIBSHA1], [libsha1], [HAVE_LIBSHA1=yes], [HAVE_LIBSHA1=no]) +if test "x$with_sha1" = x && test "x$HAVE_LIBSHA1" = xyes; then + with_sha1=libsha1 +fi +if test "x$with_sha1" = xlibsha1 && test "x$HAVE_LIBSHA1" != xyes; then + AC_MSG_ERROR([libsha1 requested but not found]) +fi +if test "x$with_sha1" = xlibsha1; then + AC_DEFINE([HAVE_SHA1_IN_LIBSHA1], [1], + [Use libsha1 for SHA1]) + SHA1_LIBS=-lsha1 +fi +AC_CHECK_LIB([nettle], [nettle_sha1_init], [HAVE_LIBNETTLE=yes]) +if test "x$with_sha1" = x && test "x$HAVE_LIBNETTLE" = xyes; then + with_sha1=libnettle +fi +if test "x$with_sha1" = xlibnettle && test "x$HAVE_LIBNETTLE" != xyes; then + AC_MSG_ERROR([libnettle requested but not found]) +fi +if test "x$with_sha1" = xlibnettle; then + AC_DEFINE([HAVE_SHA1_IN_LIBNETTLE], [1], + [Use libnettle SHA1 functions]) + SHA1_LIBS=-lnettle +fi +AC_CHECK_LIB([gcrypt], [gcry_md_open], [HAVE_LIBGCRYPT=yes]) +if test "x$with_sha1" = x && test "x$HAVE_LIBGCRYPT" = xyes; then + with_sha1=libgcrypt +fi +if test "x$with_sha1" = xlibgcrypt && test "x$HAVE_LIBGCRYPT" != xyes; then + AC_MSG_ERROR([libgcrypt requested but not found]) +fi +if test "x$with_sha1" = xlibgcrypt; then + AC_DEFINE([HAVE_SHA1_IN_LIBGCRYPT], [1], + [Use libgcrypt SHA1 functions]) + SHA1_LIBS=-lgcrypt +fi +# We don't need all of the OpenSSL libraries, just libcrypto +AC_CHECK_LIB([crypto], [SHA1_Init], [HAVE_LIBCRYPTO=yes]) +PKG_CHECK_MODULES([OPENSSL], [openssl], [HAVE_OPENSSL_PKC=yes], + [HAVE_OPENSSL_PKC=no]) +if test "x$HAVE_LIBCRYPTO" = xyes || test "x$HAVE_OPENSSL_PKC" = xyes; then + if test "x$with_sha1" = x; then + with_sha1=libcrypto + fi +else + if test "x$with_sha1" = xlibcrypto; then + AC_MSG_ERROR([OpenSSL libcrypto requested but not found]) + fi +fi +if test "x$with_sha1" = xlibcrypto; then + if test "x$HAVE_LIBCRYPTO" = xyes; then + SHA1_LIBS=-lcrypto + else + SHA1_LIBS="$OPENSSL_LIBS" + SHA1_CFLAGS="$OPENSSL_CFLAGS" + fi +fi +AC_MSG_CHECKING([for SHA1 implementation]) +AM_CONDITIONAL([HAVE_SHA1], [test x$with_sha1 != x]) +AC_MSG_RESULT([$with_sha1]) +AC_SUBST(SHA1_LIBS) +AC_SUBST(SHA1_CFLAGS) + # Check for libdrm PKG_CHECK_MODULES([LIBDRM], [libdrm >= $LIBDRM_REQUIRED], [have_libdrm=yes], [have_libdrm=no]) diff --git a/src/util/Makefile.am b/src/util/Makefile.am index c7e183e8d61..03b619efeb7 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -31,12 +31,19 @@ libmesautil_la_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/mapi \ -I$(top_srcdir)/src/mesa \ + $(SHA1_CFLAGS) \ $(VISIBILITY_CFLAGS) libmesautil_la_SOURCES = \ $(MESA_UTIL_FILES) \ $(MESA_UTIL_GENERATED_FILES) +if HAVE_SHA1 +libmesautil_la_SOURCES += $(MESA_UTIL_SHA1_FILES) +endif + +libmesautil_la_LIBADD = $(SHA1_LIBS) + check_PROGRAMS = u_atomic_test TESTS = $(check_PROGRAMS) diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources index 154677aa47d..4e54c74600c 100644 --- a/src/util/Makefile.sources +++ b/src/util/Makefile.sources @@ -1,3 +1,7 @@ +MESA_UTIL_SHA1_FILES := \ + sha1.c \ + sha1.h + MESA_UTIL_FILES := \ format_srgb.h \ hash_table.c \ diff --git a/src/util/sha1.c b/src/util/sha1.c new file mode 100644 index 00000000000..658dc27fc19 --- /dev/null +++ b/src/util/sha1.c @@ -0,0 +1,316 @@ +/* Copyright © 2007 Carl Worth + * Copyright © 2009 Jeremy Huddleston, Julien Cristau, and Matthieu Herrb + * Copyright © 2009-2010 Mikhail Gusarov + * Copyright © 2012 Yaakov Selkowitz and Keith Packard + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "sha1.h" + +#if defined(HAVE_SHA1_IN_LIBMD) /* Use libmd for SHA1 */ \ + || defined(HAVE_SHA1_IN_LIBC) /* Use libc for SHA1 */ + +#include + +struct mesa_sha1 * +_mesa_sha1_init(void) +{ + SHA1_CTX *ctx = malloc(sizeof(*ctx)); + + if (!ctx) + return NULL; + + SHA1Init(ctx); + return (struct mesa_sha1 *) ctx; +} + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size) +{ + SHA1_CTX *sha1_ctx = (SHA1_CTX *) ctx; + + SHA1Update(sha1_ctx, data, size); + return 1; +} + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) +{ + SHA1_CTX *sha1_ctx = (SHA1_CTX *) ctx; + + SHA1Final(result, sha1_ctx); + free(sha1_ctx); + return 1; +} + +#elif defined(HAVE_SHA1_IN_COMMONCRYPTO) /* Use CommonCrypto for SHA1 */ + +#include + +struct mesa_sha1 * +_mesa_sha1_init(void) +{ + CC_SHA1_CTX *ctx = malloc(sizeof(*ctx)); + + if (!ctx) + return NULL; + + CC_SHA1_Init(ctx); + return (struct mesa_sha1 *) ctx; +} + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size) +{ + CC_SHA1_CTX *sha1_ctx = (CC_SHA1_CTX *) ctx; + + CC_SHA1_Update(sha1_ctx, data, size); + return 1; +} + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) +{ + CC_SHA1_CTX *sha1_ctx = (CC_SHA1_CTX *) ctx; + + CC_SHA1_Final(result, sha1_ctx); + free(sha1_ctx); + return 1; +} + +#elif defined(HAVE_SHA1_IN_CRYPTOAPI) /* Use CryptoAPI for SHA1 */ + +#define WIN32_LEAN_AND_MEAN +#include +#include + +static HCRYPTPROV hProv; + +struct mesa_sha1 * +_mesa_sha1_init(void) +{ + HCRYPTHASH *ctx = malloc(sizeof(*ctx)); + + if (!ctx) + return NULL; + + CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + CryptCreateHash(hProv, CALG_SHA1, 0, 0, ctx); + return (struct mesa_sha1 *) ctx; +} + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size) +{ + HCRYPTHASH *hHash = (HCRYPTHASH *) ctx; + + CryptHashData(*hHash, data, size, 0); + return 1; +} + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) +{ + HCRYPTHASH *hHash = (HCRYPTHASH *) ctx; + DWORD len = 20; + + CryptGetHashParam(*hHash, HP_HASHVAL, result, &len, 0); + CryptDestroyHash(*hHash); + CryptReleaseContext(hProv, 0); + free(ctx); + return 1; +} + +#elif defined(HAVE_SHA1_IN_LIBNETTLE) /* Use libnettle for SHA1 */ + +#include + +struct mesa_sha1 * +_mesa_sha1_init(void) +{ + struct sha1_ctx *ctx = malloc(sizeof(*ctx)); + + if (!ctx) + return NULL; + sha1_init(ctx); + return (struct mesa_sha1 *) ctx; +} + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size) +{ + sha1_update((struct sha1_ctx *) ctx, size, data); + return 1; +} + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) +{ + sha1_digest((struct sha1_ctx *) ctx, 20, result); + free(ctx); + return 1; +} + +#elif defined(HAVE_SHA1_IN_LIBGCRYPT) /* Use libgcrypt for SHA1 */ + +#include + +struct mesa_sha1 * +_mesa_sha1_init(void) +{ + static int init; + gcry_md_hd_t h; + gcry_error_t err; + + if (!init) { + if (!gcry_check_version(NULL)) + return NULL; + gcry_control(GCRYCTL_DISABLE_SECMEM, 0); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + init = 1; + } + + err = gcry_md_open(&h, GCRY_MD_SHA1, 0); + if (err) + return NULL; + return (struct mesa_sha1 *) h; +} + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size) +{ + gcry_md_hd_t h = (gcry_md_hd_t) ctx; + + gcry_md_write(h, data, size); + return 1; +} + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) +{ + gcry_md_hd_t h = (grcy_md_hd_t) ctx; + + memcpy(result, gcry_md_read(h, GCRY_MD_SHA1), 20); + gcry_md_close(h); + return 1; +} + +#elif defined(HAVE_SHA1_IN_LIBSHA1) /* Use libsha1 */ + +#include + +struct mesa_sha1 * +_mesa_sha1_init(void) +{ + sha1_ctx *ctx = malloc(sizeof(*ctx)); + + if (!ctx) + return NULL; + sha1_begin(ctx); + return (struct mesa_sha1 *) ctx; +} + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size) +{ + sha1_hash(data, size, (sha1_ctx *) ctx); + return 1; +} + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) +{ + sha1_end(result, (sha1_ctx *) ctx); + free(ctx); + return 1; +} + +#else /* Use OpenSSL's libcrypto */ + +#include /* buggy openssl/sha.h wants size_t */ +#include + +struct mesa_sha1 * +_mesa_sha1_init(void) +{ + int ret; + SHA_CTX *ctx = malloc(sizeof(*ctx)); + + if (!ctx) + return NULL; + ret = SHA1_Init(ctx); + if (!ret) { + free(ctx); + return NULL; + } + return (struct mesa_sha1 *) ctx; +} + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size) +{ + int ret; + SHA_CTX *sha_ctx = (SHA_CTX *) ctx; + + ret = SHA1_Update(sha_ctx, data, size); + if (!ret) + free(sha_ctx); + return ret; +} + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) +{ + int ret; + SHA_CTX *sha_ctx = (SHA_CTX *) ctx; + + ret = SHA1_Final(result, (SHA_CTX *) sha_ctx); + free(sha_ctx); + return ret; +} + +#endif + +void +_mesa_sha1_compute(const void *data, size_t size, unsigned char result[20]) +{ + struct mesa_sha1 *ctx; + + ctx = _mesa_sha1_init(); + _mesa_sha1_update(ctx, data, size); + _mesa_sha1_final(ctx, result); +} + +char * +_mesa_sha1_format(char *buf, const unsigned char *sha1) +{ + static const char hex_digits[] = "0123456789abcdef"; + int i; + + for (i = 0; i < 40; i += 2) { + buf[i] = hex_digits[sha1[i >> 1] >> 4]; + buf[i + 1] = hex_digits[sha1[i >> 1] & 0x0f]; + } + buf[i] = '\0'; + + return buf; +} diff --git a/src/util/sha1.h b/src/util/sha1.h new file mode 100644 index 00000000000..1599405cd5a --- /dev/null +++ b/src/util/sha1.h @@ -0,0 +1,53 @@ +/* Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SHA1_H +#define SHA1_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct mesa_sha1; + +struct mesa_sha1 * +_mesa_sha1_init(void); + +int +_mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, int size); + +int +_mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]); + +char * +_mesa_sha1_format(char *buf, const unsigned char *sha1); + +void +_mesa_sha1_compute(const void *data, size_t size, unsigned char result[20]); + +#ifdef __cplusplus +} /* extern C */ +#endif + +#endif -- 2.30.2