crypto: qcrypto_random_bytes() now works on windows w/o any other crypto libs

If no crypto library is included in the build, QEMU uses
qcrypto_random_bytes() to generate random data. That function tried to open
/dev/urandom or /dev/random and if opening both files failed it errored out.

Those files obviously do not exist on windows, so there the code uses
CryptGenRandom().

Furthermore there was some refactoring and a new function
qcrypto_random_init() was introduced. If a proper crypto library (gnutls or
libgcrypt) is included in the build, this function does nothing. If neither
is included it initializes the (platform specific) handles that are used by
qcrypto_random_bytes().
Either:
* a handle to /dev/urandom | /dev/random on unix like systems
* a handle to a cryptographic service provider on windows

Signed-off-by: Geert Martin Ijewski <gm.ijewski@web.de>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Geert Martin Ijewski 2017-04-26 00:15:01 +02:00 committed by Daniel P. Berrange
parent e4a3507e86
commit a37278169d
5 changed files with 57 additions and 8 deletions

View File

@ -32,6 +32,8 @@
#include <gcrypt.h>
#endif
#include "crypto/random.h"
/* #define DEBUG_GNUTLS */
/*
@ -146,5 +148,9 @@ int qcrypto_init(Error **errp)
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
#endif
if (qcrypto_random_init(errp) < 0) {
return -1;
}
return 0;
}

View File

@ -31,3 +31,5 @@ int qcrypto_random_bytes(uint8_t *buf,
gcry_randomize(buf, buflen, GCRY_STRONG_RANDOM);
return 0;
}
int qcrypto_random_init(Error **errp G_GNUC_UNUSED) { return 0; }

View File

@ -41,3 +41,6 @@ int qcrypto_random_bytes(uint8_t *buf,
return 0;
}
int qcrypto_random_init(Error **errp G_GNUC_UNUSED) { return 0; }

View File

@ -22,14 +22,16 @@
#include "crypto/random.h"
int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
size_t buflen G_GNUC_UNUSED,
Error **errp)
{
int fd;
int ret = -1;
int got;
#ifdef _WIN32
#include <Wincrypt.h>
static HCRYPTPROV hCryptProv;
#else
static int fd; /* a file handle to either /dev/urandom or /dev/random */
#endif
int qcrypto_random_init(Error **errp)
{
#ifndef _WIN32
/* TBD perhaps also add support for BSD getentropy / Linux
* getrandom syscalls directly */
fd = open("/dev/urandom", O_RDONLY);
@ -41,6 +43,25 @@ int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
error_setg(errp, "No /dev/urandom or /dev/random found");
return -1;
}
#else
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) {
error_setg_win32(errp, GetLastError(),
"Unable to create cryptographic provider");
return -1;
}
#endif
return 0;
}
int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
size_t buflen G_GNUC_UNUSED,
Error **errp)
{
#ifndef _WIN32
int ret = -1;
int got;
while (buflen > 0) {
got = read(fd, buf, buflen);
@ -59,6 +80,14 @@ int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
ret = 0;
cleanup:
close(fd);
return ret;
#else
if (!CryptGenRandom(hCryptProv, buflen, buf)) {
error_setg_win32(errp, GetLastError(),
"Unable to read random bytes");
return -1;
}
return 0;
#endif
}

View File

@ -40,5 +40,14 @@ int qcrypto_random_bytes(uint8_t *buf,
size_t buflen,
Error **errp);
/**
* qcrypto_random_init:
* @errp: pointer to a NULL-initialized error object
*
* Initializes the handles used by qcrypto_random_bytes
*
* Returns 0 on success, -1 on error
*/
int qcrypto_random_init(Error **errp);
#endif /* QCRYPTO_RANDOM_H */