diff options
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | Makefile.objs | 1 | ||||
-rwxr-xr-x | configure | 45 | ||||
-rw-r--r-- | crypto/Makefile.objs | 2 | ||||
-rw-r--r-- | crypto/hash.c | 200 | ||||
-rw-r--r-- | crypto/init.c | 60 | ||||
-rw-r--r-- | include/crypto/hash.h | 189 | ||||
-rw-r--r-- | include/crypto/init.h | 29 | ||||
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile | 2 | ||||
-rw-r--r-- | tests/test-crypto-hash.c | 209 | ||||
-rw-r--r-- | vl.c | 7 |
12 files changed, 752 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 3d48a6bd65..411da3cf57 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1052,6 +1052,13 @@ S: Supported F: qemu-seccomp.c F: include/sysemu/seccomp.h +Cryptography +M: Daniel P. Berrange <berrange@redhat.com> +S: Maintained +F: crypto/ +F: include/crypto/ +F: tests/test-crypto-* + Usermode Emulation ------------------ Overall diff --git a/Makefile.objs b/Makefile.objs index 4881d2c2a6..f094eff15e 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 @@ -330,6 +330,8 @@ glusterfs_zerofill="no" archipelago="no" gtk="" gtkabi="" +gnutls="" +gnutls_hash="" vte="" tpm="yes" libssh2="" @@ -1118,6 +1120,10 @@ for opt do ;; --enable-gtk) gtk="yes" ;; + --disable-gnutls) gnutls="no" + ;; + --enable-gnutls) gnutls="yes" + ;; --enable-rdma) rdma="yes" ;; --disable-rdma) rdma="no" @@ -1328,6 +1334,7 @@ disabled with --disable-FEATURE, default is enabled if available: debug-info debugging information sparse sparse checker + gnutls GNUTLS cryptography support sdl SDL UI --with-sdlabi select preferred SDL ABI 1.2 or 2.0 gtk gtk UI @@ -2115,6 +2122,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 + 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 @@ -4424,6 +4461,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" @@ -4782,6 +4821,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 0000000000..03cc1b232d --- /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 0000000000..81e74de868 --- /dev/null +++ b/crypto/hash.c @@ -0,0 +1,200 @@ +/* + * 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" + +#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 0000000000..40f3d6e778 --- /dev/null +++ b/crypto/init.c @@ -0,0 +1,60 @@ +/* + * 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" + +#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 0000000000..b5acbf638c --- /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 0000000000..5fc510c4f8 --- /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 dc813c2713..18f60f1790 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -10,6 +10,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 eff5e1143d..8c7f1ac677 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -74,6 +74,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 @@ -339,6 +340,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 0000000000..911437e60d --- /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(); +} @@ -121,6 +121,7 @@ int main(int argc, char **argv) #include "qom/object_interfaces.h" #include "qapi-event.h" #include "exec/semihost.h" +#include "crypto/init.h" #define MAX_VIRTIO_CONSOLES 1 #define MAX_SCLP_CONSOLES 1 @@ -2958,6 +2959,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(); @@ -3001,6 +3003,11 @@ 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)); + exit(1); + } rtc_clock = QEMU_CLOCK_HOST; QLIST_INIT (&vm_change_state_head); |