[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 01/10] crypto: introduce new module for computin
From: |
Gonglei |
Subject: |
Re: [Qemu-devel] [PATCH 01/10] crypto: introduce new module for computing hash digests |
Date: |
Thu, 28 May 2015 21:28:20 +0800 |
User-agent: |
Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 |
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 <address@hidden>
> ---
> 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 <address@hidden>
> +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
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "crypto/hash.h"
> +
> +#include <glib/gi18n.h>
> +
> +#ifdef CONFIG_GNUTLS_HASH
> +#include <gnutls/gnutls.h>
> +#include <gnutls/crypto.h>
> +
> +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
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "crypto/init.h"
> +
> +#include <glib/gi18n.h>
> +
> +#ifdef CONFIG_GNUTLS
> +#include <gnutls/gnutls.h>
> +#include <gnutls/crypto.h>
> +
> +/* #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
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#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
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#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
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include <glib.h>
> +
> +#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);
>