From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54115) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yxxri-0002Rv-I3 for qemu-devel@nongnu.org; Thu, 28 May 2015 09:28:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Yxxrb-00078H-Je for qemu-devel@nongnu.org; Thu, 28 May 2015 09:28:54 -0400 Received: from szxga03-in.huawei.com ([119.145.14.66]:65090) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yxxra-00077E-6e for qemu-devel@nongnu.org; Thu, 28 May 2015 09:28:47 -0400 Message-ID: <556717F4.7000104@huawei.com> Date: Thu, 28 May 2015 21:28:20 +0800 From: Gonglei MIME-Version: 1.0 References: <1432205817-16414-1-git-send-email-berrange@redhat.com> <1432205817-16414-2-git-send-email-berrange@redhat.com> In-Reply-To: <1432205817-16414-2-git-send-email-berrange@redhat.com> Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 01/10] crypto: introduce new module for computing hash digests List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: "Daniel P. Berrange" , qemu-devel@nongnu.org Cc: Kevin Wolf , Paolo Bonzini , Gerd Hoffmann On 2015/5/21 18:56, Daniel P. Berrange wrote: > Introduce a new crypto/ directory that will (eventually) contain > all the cryptographic related code. This initially defines a > wrapper for initializing gnutls and for computing hashes with > gnutls. The former ensures that gnutls is guaranteed to be > initialized exactly once in QEMU regardless of CLI args. The > block quorum code currently fails to initialize gnutls so it > only works by luck, if VNC server TLS is not requested. The > hash APIs avoids the need to litter the rest of the code with > preprocessor checks and simplifies callers by allocating the > correct amount of memory for the requested hash. > > Signed-off-by: Daniel P. Berrange > --- > MAINTAINERS | 7 ++ > Makefile.objs | 1 + > configure | 46 +++++++++++ > crypto/Makefile.objs | 2 + > crypto/hash.c | 202 +++++++++++++++++++++++++++++++++++++++++++++ > crypto/init.c | 62 ++++++++++++++ > include/crypto/hash.h | 189 ++++++++++++++++++++++++++++++++++++++++++ > include/crypto/init.h | 29 +++++++ > tests/.gitignore | 1 + > tests/Makefile | 2 + > tests/test-crypto-hash.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++ > vl.c | 8 ++ > 12 files changed, 758 insertions(+) > create mode 100644 crypto/Makefile.objs > create mode 100644 crypto/hash.c > create mode 100644 crypto/init.c > create mode 100644 include/crypto/hash.h > create mode 100644 include/crypto/init.h > create mode 100644 tests/test-crypto-hash.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index b3552b2..3dde9b6 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1015,6 +1015,13 @@ S: Supported > F: qemu-seccomp.c > F: include/sysemu/seccomp.h > > +Cryptography > +M: Daniel P. Berrange > +S: Maintained > +F: crypto/ > +F: include/crypto/ > +F: tests/test-crypto-* > + > Usermode Emulation > ------------------ > Overall > diff --git a/Makefile.objs b/Makefile.objs > index 28999d3..0f4dd84 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -2,6 +2,7 @@ > # Common libraries for tools and emulators > stub-obj-y = stubs/ > util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o > +util-obj-y += crypto/ > > ####################################################################### > # block-obj-y is code used by both qemu system emulation and qemu-img > diff --git a/configure b/configure > index 1f0f485..6530e7a 100755 > --- a/configure > +++ b/configure > @@ -330,6 +330,8 @@ glusterfs_zerofill="no" > archipelago="no" > gtk="" > gtkabi="" > +gnutls="" > +gnutls_hash="" > vte="" > tpm="yes" > libssh2="" > @@ -1105,6 +1107,10 @@ for opt do > ;; > --enable-gtk) gtk="yes" > ;; > + --disable-gnutls) gnutls="no" > + ;; > + --enable-gnutls) gnutls="yes" > + ;; > --enable-rdma) rdma="yes" > ;; > --disable-rdma) rdma="no" > @@ -1286,6 +1292,8 @@ Advanced options (experts only): > --disable-gtk disable gtk UI > --enable-gtk enable gtk UI > --with-gtkabi select preferred GTK ABI 2.0 or 3.0 > + --disable-gnutls disable gnutls crypto features > + --enable-gnutls enable gnutls crypto features > --disable-virtfs disable VirtFS > --enable-virtfs enable VirtFS > --disable-vnc disable VNC > @@ -2150,6 +2158,36 @@ if test "$gtk" != "no"; then > fi > fi > > + > +########################################## > +# GNUTLS probe > + > +if test "$gnutls" != "no"; then > + if $pkg_config --exists "gnutls"; then > + gnutls_cflags=`$pkg_config --cflags gnutls` > + gnutls_libs=`$pkg_config --libs gnutls` > + libs_softmmu="$gnutls_libs $libs_softmmu" > + libs_tools="$gnutls_libs $libs_tools" > + QEMU_CFLAGS="$QEMU_CFLAGS $gnutls_cflags" > + gnutls="yes" > + > + # gnutls_hash_init requires >= 2.9.10 why 2.9.10 ? Isn't since 2.10.0 ? > + if $pkg_config --exists "gnutls >= 2.9.10"; then > + gnutls_hash="yes" > + else > + gnutls_hash="no" > + fi > + elif test "$gnutls" = "yes"; then > + feature_not_found "gnutls" "Install gnutls devel" > + else > + gnutls="no" > + gnutls_hash="no" > + fi > +else > + gnutls_hash="no" > +fi > + > + > ########################################## > # VTE probe > > @@ -4393,6 +4431,8 @@ fi > echo "pixman $pixman" > echo "SDL support $sdl" > echo "GTK support $gtk" > +echo "GNUTLS support $gnutls" > +echo "GNUTLS hash $gnutls_hash" > echo "VTE support $vte" > echo "curses support $curses" > echo "curl support $curl" > @@ -4745,6 +4785,12 @@ if test "$gtk" = "yes" ; then > echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak > echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak > fi > +if test "$gnutls" = "yes" ; then > + echo "CONFIG_GNUTLS=y" >> $config_host_mak > +fi > +if test "$gnutls_hash" = "yes" ; then > + echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak > +fi > if test "$vte" = "yes" ; then > echo "CONFIG_VTE=y" >> $config_host_mak > echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak > diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs > new file mode 100644 > index 0000000..03cc1b2 > --- /dev/null > +++ b/crypto/Makefile.objs > @@ -0,0 +1,2 @@ > +util-obj-y += init.o > +util-obj-y += hash.o > diff --git a/crypto/hash.c b/crypto/hash.c > new file mode 100644 > index 0000000..044a0a5 > --- /dev/null > +++ b/crypto/hash.c > @@ -0,0 +1,202 @@ > +/* > + * QEMU Crypto hash algorithms > + * > + * Copyright (c) 2015 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see . > + * > + */ > + > +#include "crypto/hash.h" > + > +#include > + > +#ifdef CONFIG_GNUTLS_HASH > +#include > +#include > + > +static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG_LAST] = { > + [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5, > + [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1, > + [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256, > +}; > + > +gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) > +{ > + if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map)) { > + return true; > + } > + return false; > +} > + > +int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg, > + const struct iovec *iov, > + size_t niov, > + uint8_t **result, > + size_t *resultlen, > + Error **errp) > +{ > + int i, ret; > + gnutls_hash_hd_t dig; > + > + if (alg > G_N_ELEMENTS(qcrypto_hash_alg_map)) { > + error_setg(errp, > + _("Unknown hash algorithm %d"), > + alg); > + return -1; > + } > + > + ret = gnutls_hash_init(&dig, qcrypto_hash_alg_map[alg]); > + > + if (ret < 0) { > + error_setg(errp, > + _("Unable to initialize hash algorithm: %s"), > + gnutls_strerror(ret)); > + return -1; > + } > + > + for (i = 0; i < niov; i++) { > + ret = gnutls_hash(dig, iov[i].iov_base, iov[i].iov_len); > + if (ret < 0) { > + error_setg(errp, > + _("Unable process hash data: %s"), > + gnutls_strerror(ret)); > + goto error; > + } > + } > + > + ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]); > + if (ret <= 0) { > + error_setg(errp, > + _("Unable to get hash length: %s"), > + gnutls_strerror(ret)); > + goto error; > + } > + if (*resultlen == 0) { > + *resultlen = ret; > + *result = g_new0(uint8_t, *resultlen); > + } else if (*resultlen != ret) { > + error_setg(errp, > + _("Result buffer size %zu is smaller than hash %d"), > + *resultlen, ret); > + goto error; > + } > + > + gnutls_hash_deinit(dig, *result); > + return 0; > + > + error: > + gnutls_hash_deinit(dig, NULL); > + return -1; > +} > + > +#else /* ! CONFIG_GNUTLS_HASH */ > + > +gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg G_GNUC_UNUSED) > +{ > + return false; > +} > + > +int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg, > + const struct iovec *iov G_GNUC_UNUSED, > + size_t niov G_GNUC_UNUSED, > + uint8_t **result G_GNUC_UNUSED, > + size_t *resultlen G_GNUC_UNUSED, > + Error **errp) > +{ > + error_setg(errp, > + _("Hash algorithm %d not supported without GNUTLS"), > + alg); > + return -1; > +} > + > +#endif /* ! CONFIG_GNUTLS_HASH */ > + > +int qcrypto_hash_bytes(QCryptoHashAlgorithm alg, > + const char *buf, > + size_t len, > + uint8_t **result, > + size_t *resultlen, > + Error **errp) > +{ > + struct iovec iov = { .iov_base = (char *)buf, > + .iov_len = len }; > + return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp); > +} > + > +static const char hex[] = "0123456789abcdef"; > + > +int qcrypto_hash_digestv(QCryptoHashAlgorithm alg, > + const struct iovec *iov, > + size_t niov, > + char **digest, > + Error **errp) > +{ > + uint8_t *result = NULL; > + size_t resultlen = 0; > + size_t i; > + > + if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) { > + return -1; > + } > + > + *digest = g_new0(char, (resultlen * 2) + 1); > + for (i = 0 ; i < resultlen ; i++) { > + (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf]; > + (*digest)[(i * 2) + 1] = hex[result[i] & 0xf]; > + } > + (*digest)[resultlen * 2] = '\0'; > + g_free(result); > + return 0; > +} > + > +int qcrypto_hash_digest(QCryptoHashAlgorithm alg, > + const char *buf, > + size_t len, > + char **digest, > + Error **errp) > +{ > + struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; > + > + return qcrypto_hash_digestv(alg, &iov, 1, digest, errp); > +} > + > +int qcrypto_hash_base64v(QCryptoHashAlgorithm alg, > + const struct iovec *iov, > + size_t niov, > + char **base64, > + Error **errp) > +{ > + uint8_t *result = NULL; > + size_t resultlen = 0; > + > + if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) { > + return -1; > + } > + > + *base64 = g_base64_encode(result, resultlen); > + g_free(result); > + return 0; > +} > + > +int qcrypto_hash_base64(QCryptoHashAlgorithm alg, > + const char *buf, > + size_t len, > + char **base64, > + Error **errp) > +{ > + struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; > + > + return qcrypto_hash_base64v(alg, &iov, 1, base64, errp); > +} > diff --git a/crypto/init.c b/crypto/init.c > new file mode 100644 > index 0000000..8fd66d4 > --- /dev/null > +++ b/crypto/init.c > @@ -0,0 +1,62 @@ > +/* > + * QEMU Crypto initialization > + * > + * Copyright (c) 2015 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see . > + * > + */ > + > +#include "crypto/init.h" > + > +#include > + > +#ifdef CONFIG_GNUTLS > +#include > +#include > + > +/* #define DEBUG_GNUTLS */ > + > +#ifdef DEBUG_GNUTLS > +static void qcrypto_gnutls_log(int level, const char *str) > +{ > + fprintf(stderr, "%d: %s", level, str); > +} > +#endif > + > +int qcrypto_init(Error **errp) > +{ > + int ret; > + ret = gnutls_global_init(); > + if (ret < 0) { > + error_setg(errp, > + _("Unable to initialize GNUTLS library: %s"), > + gnutls_strerror(ret)); > + return -1; > + } > +#ifdef DEBUG_GNUTLS > + gnutls_global_set_log_level(10); > + gnutls_global_set_log_function(qcrypto_gnutls_log); > +#endif > + return 0; > +} > + > +#else /* ! CONFIG_GNUTLS */ > + > +int qcrypto_init(Error **errp G_GNUC_UNUSED) > +{ > + return 0; > +} > + > +#endif /* ! CONFIG_GNUTLS */ > diff --git a/include/crypto/hash.h b/include/crypto/hash.h > new file mode 100644 > index 0000000..b5acbf6 > --- /dev/null > +++ b/include/crypto/hash.h > @@ -0,0 +1,189 @@ > +/* > + * QEMU Crypto hash algorithms > + * > + * Copyright (c) 2015 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see . > + * > + */ > + > +#ifndef QCRYPTO_HASH_H__ > +#define QCRYPTO_HASH_H__ > + > +#include "qemu-common.h" > +#include "qapi/error.h" > + > +typedef enum { > + QCRYPTO_HASH_ALG_MD5, > + QCRYPTO_HASH_ALG_SHA1, > + QCRYPTO_HASH_ALG_SHA256, > + > + QCRYPTO_HASH_ALG_LAST > +} QCryptoHashAlgorithm; > + > + > +/** > + * qcrypto_hash_supports: > + * @alg: the hash algorithm > + * > + * Determine if @alg hash algorithm is supported by the > + * current configured build. > + * > + * Returns: true if the algorithm is supported, false otherwise > + */ > +gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg); > + > +/** > + * qcrypto_hash_bytesv: > + * @alg: the hash algorithm > + * @iov: the array of memory regions to hash > + * @niov: the length of @iov > + * @result: pointer to hold output hash > + * @resultlen: pointer to hold length of @result > + * @errp: pointer to uninitialized error object > + * > + * Computes the hash across all the memory regions > + * present in @iov. The @result pointer will be > + * filled with raw bytes representing the computed > + * hash, which will have length @resultlen. The > + * memory pointer in @result must be released > + * with a call to g_free() when no longer required. > + * > + * Returns: 0 on success, -1 on error > + */ > +int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg, > + const struct iovec *iov, > + size_t niov, > + uint8_t **result, > + size_t *resultlen, > + Error **errp); > + > +/** > + * qcrypto_hash_bytes: > + * @alg: the hash algorithm > + * @buf: the memory region to hash > + * @len: the length of @buf > + * @result: pointer to hold output hash > + * @resultlen: pointer to hold length of @result > + * @errp: pointer to uninitialized error object > + * > + * Computes the hash across all the memory region > + * @buf of length @len. The @result pointer will be > + * filled with raw bytes representing the computed > + * hash, which will have length @resultlen. The > + * memory pointer in @result must be released > + * with a call to g_free() when no longer required. > + * > + * Returns: 0 on success, -1 on error > + */ > +int qcrypto_hash_bytes(QCryptoHashAlgorithm alg, > + const char *buf, > + size_t len, > + uint8_t **result, > + size_t *resultlen, > + Error **errp); > + > +/** > + * qcrypto_hash_digestv: > + * @alg: the hash algorithm > + * @iov: the array of memory regions to hash > + * @niov: the length of @iov > + * @digest: pointer to hold output hash > + * @errp: pointer to uninitialized error object > + * > + * Computes the hash across all the memory regions > + * present in @iov. The @digest pointer will be > + * filled with the printable hex digest of the computed > + * hash, which will be terminated by '\0'. The > + * memory pointer in @digest must be released > + * with a call to g_free() when no longer required. > + * > + * Returns: 0 on success, -1 on error > + */ > +int qcrypto_hash_digestv(QCryptoHashAlgorithm alg, > + const struct iovec *iov, > + size_t niov, > + char **digest, > + Error **errp); > + > +/** > + * qcrypto_hash_digest: > + * @alg: the hash algorithm > + * @buf: the memory region to hash > + * @len: the length of @buf > + * @digest: pointer to hold output hash > + * @errp: pointer to uninitialized error object > + * > + * Computes the hash across all the memory region > + * @buf of length @len. The @digest pointer will be > + * filled with the printable hex digest of the computed > + * hash, which will be terminated by '\0'. The > + * memory pointer in @digest must be released > + * with a call to g_free() when no longer required. > + * > + * Returns: 0 on success, -1 on error > + */ > +int qcrypto_hash_digest(QCryptoHashAlgorithm alg, > + const char *buf, > + size_t len, > + char **digest, > + Error **errp); > + > +/** > + * qcrypto_hash_base64v: > + * @alg: the hash algorithm > + * @iov: the array of memory regions to hash > + * @niov: the length of @iov > + * @base64: pointer to hold output hash > + * @errp: pointer to uninitialized error object > + * > + * Computes the hash across all the memory regions > + * present in @iov. The @base64 pointer will be > + * filled with the base64 encoding of the computed > + * hash, which will be terminated by '\0'. The > + * memory pointer in @base64 must be released > + * with a call to g_free() when no longer required. > + * > + * Returns: 0 on success, -1 on error > + */ > +int qcrypto_hash_base64v(QCryptoHashAlgorithm alg, > + const struct iovec *iov, > + size_t niov, > + char **base64, > + Error **errp); > + > +/** > + * qcrypto_hash_base64: > + * @alg: the hash algorithm > + * @buf: the memory region to hash > + * @len: the length of @buf > + * @base64: pointer to hold output hash > + * @errp: pointer to uninitialized error object > + * > + * Computes the hash across all the memory region > + * @buf of length @len. The @base64 pointer will be > + * filled with the base64 encoding of the computed > + * hash, which will be terminated by '\0'. The > + * memory pointer in @base64 must be released > + * with a call to g_free() when no longer required. > + * > + * Returns: 0 on success, -1 on error > + */ > +int qcrypto_hash_base64(QCryptoHashAlgorithm alg, > + const char *buf, > + size_t len, > + char **base64, > + Error **errp); > + > +#endif /* QCRYPTO_HASH_H__ */ > diff --git a/include/crypto/init.h b/include/crypto/init.h > new file mode 100644 > index 0000000..5fc510c > --- /dev/null > +++ b/include/crypto/init.h > @@ -0,0 +1,29 @@ > +/* > + * QEMU Crypto initialization > + * > + * Copyright (c) 2015 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see . > + * > + */ > + > +#ifndef QCRYPTO_INIT_H__ > +#define QCRYPTO_INIT_H__ > + > +#include "qemu-common.h" > +#include "qapi/error.h" > + > +int qcrypto_init(Error **errp); > + > +#endif /* QCRYPTO_INIT_H__ */ > diff --git a/tests/.gitignore b/tests/.gitignore > index 0dcb618..12d2373 100644 > --- a/tests/.gitignore > +++ b/tests/.gitignore > @@ -9,6 +9,7 @@ rcutorture > test-aio > test-bitops > test-coroutine > +test-crypto-hash > test-cutils > test-hbitmap > test-int128 > diff --git a/tests/Makefile b/tests/Makefile > index 729b969..05f1dff 100644 > --- a/tests/Makefile > +++ b/tests/Makefile > @@ -72,6 +72,7 @@ check-unit-y += tests/test-qemu-opts$(EXESUF) > gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c > check-unit-y += tests/test-write-threshold$(EXESUF) > gcov-files-test-write-threshold-y = block/write-threshold.c > +check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF) > > check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh > > @@ -333,6 +334,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) l > > tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a > tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a > +tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a > > libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o > libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o > diff --git a/tests/test-crypto-hash.c b/tests/test-crypto-hash.c > new file mode 100644 > index 0000000..911437e > --- /dev/null > +++ b/tests/test-crypto-hash.c > @@ -0,0 +1,209 @@ > +/* > + * QEMU Crypto hash algorithms > + * > + * Copyright (c) 2015 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see . > + * > + */ > + > +#include > + > +#include "crypto/init.h" > +#include "crypto/hash.h" > + > +#define INPUT_TEXT "Hiss hisss Hissss hiss Hiss hisss Hiss hiss" > +#define INPUT_TEXT1 "Hiss hisss " > +#define INPUT_TEXT2 "Hissss hiss " > +#define INPUT_TEXT3 "Hiss hisss Hiss hiss" > + > +#define OUTPUT_MD5 "628d206371563035ab8ef62f492bdec9" > +#define OUTPUT_SHA1 "b2e74f26758a3a421e509cee045244b78753cc02" > +#define OUTPUT_SHA256 "bc757abb0436586f392b437e5dd24096" \ > + "f7f224de6b74d4d86e2abc6121b160d0" > + > +#define OUTPUT_MD5_B64 "Yo0gY3FWMDWrjvYvSSveyQ==" > +#define OUTPUT_SHA1_B64 "sudPJnWKOkIeUJzuBFJEt4dTzAI=" > +#define OUTPUT_SHA256_B64 "vHV6uwQ2WG85K0N+XdJAlvfyJN5rdNTYbiq8YSGxYNA=" > + > +static const char *expected_outputs[] = { > + [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5, > + [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1, > + [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256, > +}; > +static const char *expected_outputs_b64[] = { > + [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5_B64, > + [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1_B64, > + [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256_B64, > +}; > +static const int expected_lens[] = { > + [QCRYPTO_HASH_ALG_MD5] = 16, > + [QCRYPTO_HASH_ALG_SHA1] = 20, > + [QCRYPTO_HASH_ALG_SHA256] = 32, > +}; > + > +static const char hex[] = "0123456789abcdef"; > + > +/* Test with dynamic allocation */ > +static void test_hash_alloc(void) > +{ > + size_t i; > + > + g_assert(qcrypto_init(NULL) == 0); > + > + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { > + uint8_t *result = NULL; > + size_t resultlen = 0; > + int ret; > + size_t j; > + > + ret = qcrypto_hash_bytes(i, > + INPUT_TEXT, > + strlen(INPUT_TEXT), > + &result, > + &resultlen, > + NULL); > + g_assert(ret == 0); > + g_assert(resultlen == expected_lens[i]); > + > + for (j = 0; j < resultlen; j++) { > + g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]); > + g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]); > + } > + g_free(result); > + } > +} > + > +/* Test with caller preallocating */ > +static void test_hash_prealloc(void) > +{ > + size_t i; > + > + g_assert(qcrypto_init(NULL) == 0); > + > + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { > + uint8_t *result; > + size_t resultlen; > + int ret; > + size_t j; > + > + resultlen = expected_lens[i]; > + result = g_new0(uint8_t, resultlen); > + > + ret = qcrypto_hash_bytes(i, > + INPUT_TEXT, > + strlen(INPUT_TEXT), > + &result, > + &resultlen, > + NULL); > + g_assert(ret == 0); > + > + g_assert(resultlen == expected_lens[i]); > + for (j = 0; j < resultlen; j++) { > + g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]); > + g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]); > + } > + g_free(result); > + } > +} > + > + > +/* Test with dynamic allocation */ > +static void test_hash_iov(void) > +{ > + size_t i; > + > + g_assert(qcrypto_init(NULL) == 0); > + > + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { > + struct iovec iov[3] = { > + { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) }, > + { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) }, > + { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) }, > + }; > + uint8_t *result = NULL; > + size_t resultlen = 0; > + int ret; > + size_t j; > + > + ret = qcrypto_hash_bytesv(i, > + iov, 3, > + &result, > + &resultlen, > + NULL); > + g_assert(ret == 0); > + g_assert(resultlen == expected_lens[i]); > + for (j = 0; j < resultlen; j++) { > + g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]); > + g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]); > + } > + g_free(result); > + } > +} > + > + > +/* Test with printable hashing */ > +static void test_hash_digest(void) > +{ > + size_t i; > + > + g_assert(qcrypto_init(NULL) == 0); > + > + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { > + int ret; > + char *digest; > + > + ret = qcrypto_hash_digest(i, > + INPUT_TEXT, > + strlen(INPUT_TEXT), > + &digest, > + NULL); > + g_assert(ret == 0); > + g_assert(g_str_equal(digest, expected_outputs[i])); > + g_free(digest); > + } > +} > + > +/* Test with base64 encoding */ > +static void test_hash_base64(void) > +{ > + size_t i; > + > + g_assert(qcrypto_init(NULL) == 0); > + > + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { > + int ret; > + char *digest; > + > + ret = qcrypto_hash_base64(i, > + INPUT_TEXT, > + strlen(INPUT_TEXT), > + &digest, > + NULL); > + g_assert(ret == 0); > + g_assert(g_str_equal(digest, expected_outputs_b64[i])); > + g_free(digest); > + } > +} > + > +int main(int argc, char **argv) > +{ > + g_test_init(&argc, &argv, NULL); > + g_test_add_func("/crypto/hash/iov", test_hash_iov); > + g_test_add_func("/crypto/hash/alloc", test_hash_alloc); > + g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc); > + g_test_add_func("/crypto/hash/digest", test_hash_digest); > + g_test_add_func("/crypto/hash/base64", test_hash_base64); > + return g_test_run(); > +} > diff --git a/vl.c b/vl.c > index 15bccc4..72313a4 100644 > --- a/vl.c > +++ b/vl.c > @@ -119,6 +119,7 @@ int main(int argc, char **argv) > #include "qapi/opts-visitor.h" > #include "qom/object_interfaces.h" > #include "qapi-event.h" > +#include "crypto/init.h" > > #define DEFAULT_RAM_SIZE 128 > > @@ -2777,6 +2778,7 @@ int main(int argc, char **argv, char **envp) > uint64_t ram_slots = 0; > FILE *vmstate_dump_file = NULL; > Error *main_loop_err = NULL; > + Error *err = NULL; > > qemu_init_cpu_loop(); > qemu_mutex_lock_iothread(); > @@ -2819,6 +2821,12 @@ int main(int argc, char **argv, char **envp) > > runstate_init(); > > + if (qcrypto_init(&err) < 0) { > + fprintf(stderr, "Cannot initialize crypto: %s\n", > + error_get_pretty(err)); > + error_free(err); This free is superflous (before exit) IMO. Regards, -Gonglei > + exit(1); > + } > rtc_clock = QEMU_CLOCK_HOST; > > QLIST_INIT (&vm_change_state_head); >