qemu/crypto/init.c
Richard W.M. Jones d6cca8e111 crypto: Remove use of GCRYPT_VERSION macro.
According to the gcrypt documentation it's intended that
gcry_check_version() is called with the minimum version of gcrypt
needed by the program, not the version from the <gcrypt.h> header file
that happened to be installed when qemu was compiled.  Indeed the
gcrypt.h header says that you shouldn't use the GCRYPT_VERSION macro.

This causes the following failure:

  qemu-img: Unable to initialize gcrypt

if a slightly older version of libgcrypt is installed with a newer
qemu, even though the slightly older version works fine.  This can
happen with RPM packaging which uses symbol versioning to determine
automatically which libgcrypt is required by qemu, which caused the
following bug in RHEL 8:

  https://bugzilla.redhat.com/show_bug.cgi?id=1840485

qemu actually requires libgcrypt >= 1.5.0, so we might put the string
"1.5.0" here.  However since 1.5.0 was released in 2011, it hardly
seems we need to check that.  So I replaced GCRYPT_VERSION with NULL.
Perhaps in future if we move to requiring a newer version of gcrypt we
could put a literal string here.

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2020-06-15 11:33:51 +01:00

137 lines
3.2 KiB
C

/*
* 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.1 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 "qemu/osdep.h"
#include "crypto/init.h"
#include "qapi/error.h"
#include "qemu/thread.h"
#ifdef CONFIG_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#endif
#ifdef CONFIG_GCRYPT
#include <gcrypt.h>
#endif
#include "crypto/random.h"
/* #define DEBUG_GNUTLS */
/*
* We need to init gcrypt threading if
*
* - gcrypt < 1.6.0
*
*/
#if (defined(CONFIG_GCRYPT) && \
(GCRYPT_VERSION_NUMBER < 0x010600))
#define QCRYPTO_INIT_GCRYPT_THREADS
#else
#undef QCRYPTO_INIT_GCRYPT_THREADS
#endif
#ifdef DEBUG_GNUTLS
static void qcrypto_gnutls_log(int level, const char *str)
{
fprintf(stderr, "%d: %s", level, str);
}
#endif
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
static int qcrypto_gcrypt_mutex_init(void **priv)
{ \
QemuMutex *lock = NULL;
lock = g_new0(QemuMutex, 1);
qemu_mutex_init(lock);
*priv = lock;
return 0;
}
static int qcrypto_gcrypt_mutex_destroy(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_destroy(lock);
g_free(lock);
return 0;
}
static int qcrypto_gcrypt_mutex_lock(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_lock(lock);
return 0;
}
static int qcrypto_gcrypt_mutex_unlock(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_unlock(lock);
return 0;
}
static struct gcry_thread_cbs qcrypto_gcrypt_thread_impl = {
(GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
NULL,
qcrypto_gcrypt_mutex_init,
qcrypto_gcrypt_mutex_destroy,
qcrypto_gcrypt_mutex_lock,
qcrypto_gcrypt_mutex_unlock,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
#endif /* QCRYPTO_INIT_GCRYPT */
int qcrypto_init(Error **errp)
{
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
gcry_control(GCRYCTL_SET_THREAD_CBS, &qcrypto_gcrypt_thread_impl);
#endif /* QCRYPTO_INIT_GCRYPT_THREADS */
#ifdef CONFIG_GNUTLS
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
#endif
#ifdef CONFIG_GCRYPT
if (!gcry_check_version(NULL)) {
error_setg(errp, "Unable to initialize gcrypt");
return -1;
}
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
#endif
if (qcrypto_random_init(errp) < 0) {
return -1;
}
return 0;
}