crypto: introduce new module for computing hash digests
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 <berrange@redhat.com> Message-Id: <1435770638-25715-2-git-send-email-berrange@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
6b3f7f639e
commit
ddbb0d0966
@ -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
|
||||
|
@ -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
|
||||
|
45
configure
vendored
45
configure
vendored
@ -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
|
||||
|
2
crypto/Makefile.objs
Normal file
2
crypto/Makefile.objs
Normal file
@ -0,0 +1,2 @@
|
||||
util-obj-y += init.o
|
||||
util-obj-y += hash.o
|
200
crypto/hash.c
Normal file
200
crypto/hash.c
Normal file
@ -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);
|
||||
}
|
60
crypto/init.c
Normal file
60
crypto/init.c
Normal file
@ -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 */
|
189
include/crypto/hash.h
Normal file
189
include/crypto/hash.h
Normal file
@ -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__ */
|
29
include/crypto/init.h
Normal file
29
include/crypto/init.h
Normal file
@ -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__ */
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -10,6 +10,7 @@ rcutorture
|
||||
test-aio
|
||||
test-bitops
|
||||
test-coroutine
|
||||
test-crypto-hash
|
||||
test-cutils
|
||||
test-hbitmap
|
||||
test-int128
|
||||
|
@ -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
|
||||
|
209
tests/test-crypto-hash.c
Normal file
209
tests/test-crypto-hash.c
Normal file
@ -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();
|
||||
}
|
7
vl.c
7
vl.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user