qemu-devel
[Top][All Lists]
Advanced

[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);
> 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]