d6cca8e111
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>
138 lines
3.2 KiB
C
138 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;
|
|
}
|