Bugfixes and Daniel Berrange's crypto library.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQEcBAABCAAGBQJVnQWdAAoJEL/70l94x66D6OgIAKJlzQfmy5w7Q9WD4vCMhD76
 JrpLSsn7Gx/Bws0Nu9nLQlqun5z4hiUxyG2kP/WqD9+tV3cpSMSyrG6ImVdqKnQ5
 +Z8WJZuREkQv0aqDUjQVST+eIDZuh2LWJXAjhgsCXUHY77eWb/7WmKT79xJOa+5C
 5xB1qxudqX5IsTvpiKKPbmUGYkAcvRX1dUSaFwRIMO0UyKn59B9WfM9a5slIbLW7
 XfI8+wEJshTVLuQkkTfdidWQc5M5DwlmO7ESUNR/BRPCPFeyjcDqgQY5pBM5XVo9
 C+S0R3zIt3Ew0fhCtLRyjlIT0bGfwjbU5HRiHcyldBKhNUZZjSUoOWJnYRHXUDY=
 =H8wA
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging

Bugfixes and Daniel Berrange's crypto library.

# gpg: Signature made Wed Jul  8 12:12:29 2015 BST using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream:
  ossaudio: fix memory leak
  ui: convert VNC to use generic cipher API
  block: convert qcow/qcow2 to use generic cipher API
  ui: convert VNC websockets to use crypto APIs
  block: convert quorum blockdrv to use crypto APIs
  crypto: add a nettle cipher implementation
  crypto: add a gcrypt cipher implementation
  crypto: introduce generic cipher API & built-in implementation
  crypto: move built-in D3DES implementation into crypto/
  crypto: move built-in AES implementation into crypto/
  crypto: introduce new module for computing hash digests
  vl: move rom_load_all after machine init done

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-07-08 20:46:35 +01:00
commit acf7b7fdf3
41 changed files with 2545 additions and 278 deletions

View File

@ -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

View File

@ -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

View File

@ -853,6 +853,7 @@ static void *oss_audio_init (void)
if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
access(conf->devpath_out, R_OK | W_OK) < 0) {
g_free(conf);
return NULL;
}
return conf;

View File

@ -3,7 +3,7 @@ block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-c
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-$(CONFIG_QUORUM) += quorum.o
block-obj-y += quorum.o
block-obj-y += parallels.o blkdebug.o blkverify.o
block-obj-y += block-backend.o snapshot.o qapi.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o

View File

@ -26,7 +26,7 @@
#include "qemu/module.h"
#include <zlib.h>
#include "qapi/qmp/qerror.h"
#include "qemu/aes.h"
#include "crypto/cipher.h"
#include "migration/migration.h"
/**************************************************************/
@ -72,10 +72,8 @@ typedef struct BDRVQcowState {
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
QCryptoCipher *cipher; /* NULL if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
CoMutex lock;
Error *migration_blocker;
} BDRVQcowState;
@ -154,6 +152,11 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
ret = -EINVAL;
goto fail;
}
if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
error_setg(errp, "AES cipher not available");
ret = -EINVAL;
goto fail;
}
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header) {
bs->encrypted = 1;
@ -260,6 +263,7 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
BDRVQcowState *s = bs->opaque;
uint8_t keybuf[16];
int len, i;
Error *err;
memset(keybuf, 0, 16);
len = strlen(key);
@ -271,38 +275,67 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
keybuf[i] = key[i];
}
assert(bs->encrypted);
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
return -1;
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
qcrypto_cipher_free(s->cipher);
s->cipher = qcrypto_cipher_new(
QCRYPTO_CIPHER_ALG_AES_128,
QCRYPTO_CIPHER_MODE_CBC,
keybuf, G_N_ELEMENTS(keybuf),
&err);
if (!s->cipher) {
/* XXX would be nice if errors in this method could
* be properly propagate to the caller. Would need
* the bdrv_set_key() API signature to be fixed. */
error_free(err);
return -1;
}
return 0;
}
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc, Error **errp)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
int ret;
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
if (qcrypto_cipher_setiv(s->cipher,
ivec.b, G_N_ELEMENTS(ivec.b),
errp) < 0) {
return -1;
}
if (enc) {
ret = qcrypto_cipher_encrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
} else {
ret = qcrypto_cipher_decrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
}
if (ret < 0) {
return -1;
}
sector_num++;
in_buf += 512;
out_buf += 512;
}
return 0;
}
/* 'allocate' is:
@ -416,15 +449,20 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
if (bs->encrypted &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
assert(s->crypt_method);
assert(s->cipher);
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0x00, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1, 1,
&s->aes_encrypt_key);
Error *err = NULL;
if (encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1,
true, &err) < 0) {
error_free(err);
errno = EIO;
return -1;
}
if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
s->cluster_data, 512) != 512)
return -1;
@ -464,7 +502,7 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
if (!cluster_offset) {
return 0;
}
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypt_method) {
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->cipher) {
return BDRV_BLOCK_DATA;
}
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
@ -531,6 +569,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector hd_qiov;
uint8_t *buf;
void *orig_buf;
Error *err = NULL;
if (qiov->niov > 1) {
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
@ -594,10 +633,11 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
break;
}
if (bs->encrypted) {
assert(s->crypt_method);
encrypt_sectors(s, sector_num, buf, buf,
n, 0,
&s->aes_decrypt_key);
assert(s->cipher);
if (encrypt_sectors(s, sector_num, buf, buf,
n, false, &err) < 0) {
goto fail;
}
}
}
ret = 0;
@ -618,6 +658,7 @@ done:
return ret;
fail:
error_free(err);
ret = -EIO;
goto done;
}
@ -666,12 +707,17 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
break;
}
if (bs->encrypted) {
assert(s->crypt_method);
Error *err = NULL;
assert(s->cipher);
if (!cluster_data) {
cluster_data = g_malloc0(s->cluster_size);
}
encrypt_sectors(s, sector_num, cluster_data, buf,
n, 1, &s->aes_encrypt_key);
if (encrypt_sectors(s, sector_num, cluster_data, buf,
n, true, &err) < 0) {
error_free(err);
ret = -EIO;
break;
}
src_buf = cluster_data;
} else {
src_buf = buf;
@ -708,6 +754,8 @@ static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
qcrypto_cipher_free(s->cipher);
s->cipher = NULL;
g_free(s->l1_table);
qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);

View File

@ -339,26 +339,47 @@ static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_tab
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
int qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc,
Error **errp)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
int ret;
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
if (qcrypto_cipher_setiv(s->cipher,
ivec.b, G_N_ELEMENTS(ivec.b),
errp) < 0) {
return -1;
}
if (enc) {
ret = qcrypto_cipher_encrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
} else {
ret = qcrypto_cipher_decrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
}
if (ret < 0) {
return -1;
}
sector_num++;
in_buf += 512;
out_buf += 512;
}
return 0;
}
static int coroutine_fn copy_sectors(BlockDriverState *bs,
@ -401,10 +422,15 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
}
if (bs->encrypted) {
assert(s->crypt_method);
qcow2_encrypt_sectors(s, start_sect + n_start,
iov.iov_base, iov.iov_base, n, 1,
&s->aes_encrypt_key);
Error *err = NULL;
assert(s->cipher);
if (qcow2_encrypt_sectors(s, start_sect + n_start,
iov.iov_base, iov.iov_base, n,
true, &err) < 0) {
ret = -EIO;
error_free(err);
goto out;
}
}
ret = qcow2_pre_write_overlap_check(bs, 0,

View File

@ -25,7 +25,6 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include <zlib.h>
#include "qemu/aes.h"
#include "block/qcow2.h"
#include "qemu/error-report.h"
#include "qapi/qmp/qerror.h"
@ -699,6 +698,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
ret = -EINVAL;
goto fail;
}
if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
error_setg(errp, "AES cipher not available");
ret = -EINVAL;
goto fail;
}
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header) {
bs->encrypted = 1;
@ -1032,6 +1036,7 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
BDRVQcowState *s = bs->opaque;
uint8_t keybuf[16];
int len, i;
Error *err = NULL;
memset(keybuf, 0, 16);
len = strlen(key);
@ -1043,30 +1048,21 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
keybuf[i] = key[i];
}
assert(bs->encrypted);
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
qcrypto_cipher_free(s->cipher);
s->cipher = qcrypto_cipher_new(
QCRYPTO_CIPHER_ALG_AES_128,
QCRYPTO_CIPHER_MODE_CBC,
keybuf, G_N_ELEMENTS(keybuf),
&err);
if (!s->cipher) {
/* XXX would be nice if errors in this method could
* be properly propagate to the caller. Would need
* the bdrv_set_key() API signature to be fixed. */
error_free(err);
return -1;
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
return -1;
#if 0
/* test */
{
uint8_t in[16];
uint8_t out[16];
uint8_t tmp[16];
for(i=0;i<16;i++)
in[i] = i;
AES_encrypt(in, tmp, &s->aes_encrypt_key);
AES_decrypt(tmp, out, &s->aes_decrypt_key);
for(i = 0; i < 16; i++)
printf(" %02x", tmp[i]);
printf("\n");
for(i = 0; i < 16; i++)
printf(" %02x", out[i]);
printf("\n");
}
#endif
return 0;
}
@ -1109,7 +1105,7 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
}
if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED &&
!s->crypt_method) {
!s->cipher) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
status |= BDRV_BLOCK_OFFSET_VALID | cluster_offset;
@ -1159,7 +1155,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
/* prepare next request */
cur_nr_sectors = remaining_sectors;
if (s->crypt_method) {
if (s->cipher) {
cur_nr_sectors = MIN(cur_nr_sectors,
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
}
@ -1231,7 +1227,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
}
if (bs->encrypted) {
assert(s->crypt_method);
assert(s->cipher);
/*
* For encrypted images, read everything into a temporary
@ -1264,9 +1260,15 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
goto fail;
}
if (bs->encrypted) {
assert(s->crypt_method);
qcow2_encrypt_sectors(s, sector_num, cluster_data,
cluster_data, cur_nr_sectors, 0, &s->aes_decrypt_key);
assert(s->cipher);
Error *err = NULL;
if (qcow2_encrypt_sectors(s, sector_num, cluster_data,
cluster_data, cur_nr_sectors, false,
&err) < 0) {
error_free(err);
ret = -EIO;
goto fail;
}
qemu_iovec_from_buf(qiov, bytes_done,
cluster_data, 512 * cur_nr_sectors);
}
@ -1344,7 +1346,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
cur_nr_sectors * 512);
if (bs->encrypted) {
assert(s->crypt_method);
Error *err = NULL;
assert(s->cipher);
if (!cluster_data) {
cluster_data = qemu_try_blockalign(bs->file,
QCOW_MAX_CRYPT_CLUSTERS
@ -1359,8 +1362,13 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
qcow2_encrypt_sectors(s, sector_num, cluster_data,
cluster_data, cur_nr_sectors, 1, &s->aes_encrypt_key);
if (qcow2_encrypt_sectors(s, sector_num, cluster_data,
cluster_data, cur_nr_sectors,
true, &err) < 0) {
error_free(err);
ret = -EIO;
goto fail;
}
qemu_iovec_reset(&hd_qiov);
qemu_iovec_add(&hd_qiov, cluster_data,
@ -1466,6 +1474,9 @@ static void qcow2_close(BlockDriverState *bs)
qcow2_cache_destroy(bs, s->l2_table_cache);
qcow2_cache_destroy(bs, s->refcount_block_cache);
qcrypto_cipher_free(s->cipher);
s->cipher = NULL;
g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
@ -1482,9 +1493,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
{
BDRVQcowState *s = bs->opaque;
int flags = s->flags;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
uint32_t crypt_method = 0;
QCryptoCipher *cipher = NULL;
QDict *options;
Error *local_err = NULL;
int ret;
@ -1494,12 +1503,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
* that means we don't have to worry about reopening them here.
*/
if (bs->encrypted) {
assert(s->crypt_method);
crypt_method = s->crypt_method;
memcpy(&aes_encrypt_key, &s->aes_encrypt_key, sizeof(aes_encrypt_key));
memcpy(&aes_decrypt_key, &s->aes_decrypt_key, sizeof(aes_decrypt_key));
}
cipher = s->cipher;
s->cipher = NULL;
qcow2_close(bs);
@ -1524,11 +1529,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
return;
}
if (bs->encrypted) {
s->crypt_method = crypt_method;
memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
memcpy(&s->aes_decrypt_key, &aes_decrypt_key, sizeof(aes_decrypt_key));
}
s->cipher = cipher;
}
static size_t header_ext_add(char *buf, uint32_t magic, const void *s,
@ -2729,8 +2730,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
} else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) {
encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT,
s->crypt_method);
if (encrypt != !!s->crypt_method) {
!!s->cipher);
if (encrypt != !!s->cipher) {
fprintf(stderr, "Changing the encryption flag is not "
"supported.\n");
return -ENOTSUP;

View File

@ -25,7 +25,7 @@
#ifndef BLOCK_QCOW2_H
#define BLOCK_QCOW2_H
#include "qemu/aes.h"
#include "crypto/cipher.h"
#include "block/coroutine.h"
//#define DEBUG_ALLOC
@ -253,10 +253,8 @@ typedef struct BDRVQcowState {
CoMutex lock;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
QCryptoCipher *cipher; /* current cipher, NULL if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
uint64_t snapshots_offset;
int snapshots_size;
unsigned int nb_snapshots;
@ -536,10 +534,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
void qcow2_l2_cache_reset(BlockDriverState *bs);
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key);
int qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc, Error **errp);
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *cluster_offset);

View File

@ -13,8 +13,6 @@
* See the COPYING file in the top-level directory.
*/
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include "block/block_int.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
@ -24,6 +22,7 @@
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qstring.h"
#include "qapi-event.h"
#include "crypto/hash.h"
#define HASH_LENGTH 32
@ -34,7 +33,7 @@
/* This union holds a vote hash value */
typedef union QuorumVoteValue {
char h[HASH_LENGTH]; /* SHA-256 hash */
uint8_t h[HASH_LENGTH]; /* SHA-256 hash */
int64_t l; /* simpler 64 bits hash */
} QuorumVoteValue;
@ -428,25 +427,21 @@ static void quorum_free_vote_list(QuorumVotes *votes)
static int quorum_compute_hash(QuorumAIOCB *acb, int i, QuorumVoteValue *hash)
{
int j, ret;
gnutls_hash_hd_t dig;
QEMUIOVector *qiov = &acb->qcrs[i].qiov;
size_t len = sizeof(hash->h);
uint8_t *data = hash->h;
ret = gnutls_hash_init(&dig, GNUTLS_DIG_SHA256);
if (ret < 0) {
return ret;
/* XXX - would be nice if we could pass in the Error **
* and propagate that back, but this quorum code is
* restricted to just errno values currently */
if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256,
qiov->iov, qiov->niov,
&data, &len,
NULL) < 0) {
return -EINVAL;
}
for (j = 0; j < qiov->niov; j++) {
ret = gnutls_hash(dig, qiov->iov[j].iov_base, qiov->iov[j].iov_len);
if (ret < 0) {
break;
}
}
gnutls_hash_deinit(dig, (void *) hash);
return ret;
return 0;
}
static QuorumVoteVersion *quorum_get_vote_winner(QuorumVotes *votes)
@ -870,6 +865,12 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
int i;
int ret = 0;
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) {
error_setg(errp,
"SHA256 hash support is required for quorum device");
return -EINVAL;
}
qdict_flatten(options);
/* count how many different children are present */

160
configure vendored
View File

@ -246,7 +246,6 @@ vnc_tls=""
vnc_sasl=""
vnc_jpeg=""
vnc_png=""
vnc_ws=""
xen=""
xen_ctrl_version=""
xen_pci_passthrough=""
@ -331,11 +330,12 @@ glusterfs_zerofill="no"
archipelago="no"
gtk=""
gtkabi=""
gnutls=""
gnutls_hash=""
vte=""
tpm="yes"
libssh2=""
vhdx=""
quorum=""
numa=""
tcmalloc="no"
@ -896,10 +896,6 @@ for opt do
;;
--enable-vnc-png) vnc_png="yes"
;;
--disable-vnc-ws) vnc_ws="no"
;;
--enable-vnc-ws) vnc_ws="yes"
;;
--disable-slirp) slirp="no"
;;
--disable-uuid) uuid="no"
@ -1119,6 +1115,10 @@ for opt do
;;
--enable-gtk) gtk="yes"
;;
--disable-gnutls) gnutls="no"
;;
--enable-gnutls) gnutls="yes"
;;
--enable-rdma) rdma="yes"
;;
--disable-rdma) rdma="no"
@ -1141,10 +1141,6 @@ for opt do
;;
--disable-vhdx) vhdx="no"
;;
--disable-quorum) quorum="no"
;;
--enable-quorum) quorum="yes"
;;
--disable-numa) numa="no"
;;
--enable-numa) numa="yes"
@ -1329,6 +1325,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
@ -1376,7 +1373,6 @@ disabled with --disable-FEATURE, default is enabled if available:
tpm TPM support
libssh2 ssh block device support
vhdx support for the Microsoft VHDX image format
quorum quorum block filter support
numa libnuma support
tcmalloc tcmalloc support
@ -2116,6 +2112,86 @@ if test "$gtk" != "no"; then
fi
fi
##########################################
# GNUTLS probe
gnutls_gcrypt=no
gnutls_nettle=no
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
if $pkg_config --exists 'gnutls >= 3.0'; then
gnutls_gcrypt=no
gnutls_nettle=yes
elif $pkg_config --exists 'gnutls >= 2.12'; then
case `$pkg_config --libs --static gnutls` in
*gcrypt*)
gnutls_gcrypt=yes
gnutls_nettle=no
;;
*nettle*)
gnutls_gcrypt=no
gnutls_nettle=yes
;;
*)
gnutls_gcrypt=yes
gnutls_nettle=no
;;
esac
else
gnutls_gcrypt=yes
gnutls_nettle=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
if test "$gnutls_gcrypt" != "no"; then
if has "libgcrypt-config"; then
gcrypt_cflags=`libgcrypt-config --cflags`
gcrypt_libs=`libgcrypt-config --libs`
libs_softmmu="$gcrypt_libs $libs_softmmu"
libs_tools="$gcrypt_libs $libs_tools"
QEMU_CFLAGS="$QEMU_CFLAGS $gcrypt_cflags"
else
feature_not_found "gcrypt" "Install gcrypt devel"
fi
fi
if test "$gnutls_nettle" != "no"; then
if $pkg_config --exists "nettle"; then
nettle_cflags=`$pkg_config --cflags nettle`
nettle_libs=`$pkg_config --libs nettle`
libs_softmmu="$nettle_libs $libs_softmmu"
libs_tools="$nettle_libs $libs_tools"
QEMU_CFLAGS="$QEMU_CFLAGS $nettle_cflags"
else
feature_not_found "nettle" "Install nettle devel"
fi
fi
##########################################
# VTE probe
@ -2263,7 +2339,7 @@ fi
##########################################
# VNC TLS/WS detection
if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$vnc_ws" != "no" \) ; then
if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then
cat > $TMPC <<EOF
#include <gnutls/gnutls.h>
int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
@ -2274,50 +2350,16 @@ EOF
if test "$vnc_tls" != "no" ; then
vnc_tls=yes
fi
if test "$vnc_ws" != "no" ; then
vnc_ws=yes
fi
libs_softmmu="$vnc_tls_libs $libs_softmmu"
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags"
else
if test "$vnc_tls" = "yes" ; then
feature_not_found "vnc-tls" "Install gnutls devel"
fi
if test "$vnc_ws" = "yes" ; then
feature_not_found "vnc-ws" "Install gnutls devel"
fi
vnc_tls=no
vnc_ws=no
fi
fi
##########################################
# Quorum probe (check for gnutls)
if test "$quorum" != "no" ; then
cat > $TMPC <<EOF
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
int main(void) {char data[4096], digest[32];
gnutls_hash_fast(GNUTLS_DIG_SHA256, data, 4096, digest);
return 0;
}
EOF
quorum_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
quorum_tls_libs=`$pkg_config --libs gnutls 2> /dev/null`
if compile_prog "$quorum_tls_cflags" "$quorum_tls_libs" ; then
qcow_tls=yes
libs_softmmu="$quorum_tls_libs $libs_softmmu"
libs_tools="$quorum_tls_libs $libs_softmmu"
QEMU_CFLAGS="$QEMU_CFLAGS $quorum_tls_cflags"
quorum="yes"
else
if test "$quorum" = "yes"; then
feature_not_found "gnutls" "gnutls > 2.10.0 required to compile Quorum"
fi
quorum="no"
fi
fi
##########################################
# VNC SASL detection
if test "$vnc" = "yes" -a "$vnc_sasl" != "no" ; then
@ -4445,6 +4487,10 @@ fi
echo "pixman $pixman"
echo "SDL support $sdl"
echo "GTK support $gtk"
echo "GNUTLS support $gnutls"
echo "GNUTLS hash $gnutls_hash"
echo "GNUTLS gcrypt $gnutls_gcrypt"
echo "GNUTLS nettle $gnutls_nettle"
echo "VTE support $vte"
echo "curses support $curses"
echo "curl support $curl"
@ -4459,7 +4505,6 @@ if test "$vnc" = "yes" ; then
echo "VNC SASL support $vnc_sasl"
echo "VNC JPEG support $vnc_jpeg"
echo "VNC PNG support $vnc_png"
echo "VNC WS support $vnc_ws"
fi
if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
@ -4523,7 +4568,6 @@ echo "libssh2 support $libssh2"
echo "TPM passthrough $tpm_passthrough"
echo "QOM debugging $qom_cast_debug"
echo "vhdx $vhdx"
echo "Quorum $quorum"
echo "lzo support $lzo"
echo "snappy support $snappy"
echo "bzip2 support $bzip2"
@ -4676,10 +4720,6 @@ fi
if test "$vnc_png" = "yes" ; then
echo "CONFIG_VNC_PNG=y" >> $config_host_mak
fi
if test "$vnc_ws" = "yes" ; then
echo "CONFIG_VNC_WS=y" >> $config_host_mak
echo "VNC_WS_CFLAGS=$vnc_ws_cflags" >> $config_host_mak
fi
if test "$fnmatch" = "yes" ; then
echo "CONFIG_FNMATCH=y" >> $config_host_mak
fi
@ -4807,6 +4847,18 @@ 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 "$gnutls_gcrypt" = "yes" ; then
echo "CONFIG_GNUTLS_GCRYPT=y" >> $config_host_mak
fi
if test "$gnutls_nettle" = "yes" ; then
echo "CONFIG_GNUTLS_NETTLE=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
@ -4996,10 +5048,6 @@ if test "$libssh2" = "yes" ; then
echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
fi
if test "$quorum" = "yes" ; then
echo "CONFIG_QUORUM=y" >> $config_host_mak
fi
if test "$vhdx" = "yes" ; then
echo "CONFIG_VHDX=y" >> $config_host_mak
fi

5
crypto/Makefile.objs Normal file
View File

@ -0,0 +1,5 @@
util-obj-y += init.o
util-obj-y += hash.o
util-obj-y += aes.o
util-obj-y += desrfb.o
util-obj-y += cipher.o

View File

@ -28,7 +28,7 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "qemu-common.h"
#include "qemu/aes.h"
#include "crypto/aes.h"
typedef uint32_t u32;
typedef uint8_t u8;

398
crypto/cipher-builtin.c Normal file
View File

@ -0,0 +1,398 @@
/*
* QEMU Crypto cipher built-in 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/aes.h"
#include "crypto/desrfb.h"
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
struct QCryptoCipherBuiltinAES {
AES_KEY encrypt_key;
AES_KEY decrypt_key;
uint8_t *iv;
size_t niv;
};
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
struct QCryptoCipherBuiltinDESRFB {
uint8_t *key;
size_t nkey;
};
typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin;
struct QCryptoCipherBuiltin {
union {
QCryptoCipherBuiltinAES aes;
QCryptoCipherBuiltinDESRFB desrfb;
} state;
void (*free)(QCryptoCipher *cipher);
int (*setiv)(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp);
int (*encrypt)(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp);
int (*decrypt)(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp);
};
static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
g_free(ctxt->state.aes.iv);
g_free(ctxt);
cipher->opaque = NULL;
}
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
const uint8_t *inptr = in;
uint8_t *outptr = out;
while (len) {
if (len > AES_BLOCK_SIZE) {
AES_encrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
inptr += AES_BLOCK_SIZE;
outptr += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else {
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
memcpy(tmp1, inptr, len);
/* Fill with 0 to avoid valgrind uninitialized reads */
memset(tmp1 + len, 0, sizeof(tmp1) - len);
AES_encrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
memcpy(outptr, tmp2, len);
len = 0;
}
}
} else {
AES_cbc_encrypt(in, out, len,
&ctxt->state.aes.encrypt_key,
ctxt->state.aes.iv, 1);
}
return 0;
}
static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
const uint8_t *inptr = in;
uint8_t *outptr = out;
while (len) {
if (len > AES_BLOCK_SIZE) {
AES_decrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
inptr += AES_BLOCK_SIZE;
outptr += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else {
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
memcpy(tmp1, inptr, len);
/* Fill with 0 to avoid valgrind uninitialized reads */
memset(tmp1 + len, 0, sizeof(tmp1) - len);
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
memcpy(outptr, tmp2, len);
len = 0;
}
}
} else {
AES_cbc_encrypt(in, out, len,
&ctxt->state.aes.encrypt_key,
ctxt->state.aes.iv, 1);
}
return 0;
}
static int qcrypto_cipher_setiv_aes(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
if (niv != 16) {
error_setg(errp, "IV must be 16 bytes not %zu", niv);
return -1;
}
g_free(ctxt->state.aes.iv);
ctxt->state.aes.iv = g_new0(uint8_t, niv);
memcpy(ctxt->state.aes.iv, iv, niv);
ctxt->state.aes.niv = niv;
return 0;
}
static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoCipherBuiltin *ctxt;
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
return -1;
}
ctxt = g_new0(QCryptoCipherBuiltin, 1);
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.encrypt_key) != 0) {
error_setg(errp, "Failed to set encryption key");
goto error;
}
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.decrypt_key) != 0) {
error_setg(errp, "Failed to set decryption key");
goto error;
}
ctxt->free = qcrypto_cipher_free_aes;
ctxt->setiv = qcrypto_cipher_setiv_aes;
ctxt->encrypt = qcrypto_cipher_encrypt_aes;
ctxt->decrypt = qcrypto_cipher_decrypt_aes;
cipher->opaque = ctxt;
return 0;
error:
g_free(ctxt);
return -1;
}
static void qcrypto_cipher_free_des_rfb(QCryptoCipher *cipher)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
g_free(ctxt->state.desrfb.key);
g_free(ctxt);
cipher->opaque = NULL;
}
static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
size_t i;
if (len % 8) {
error_setg(errp, "Buffer size must be multiple of 8 not %zu",
len);
return -1;
}
deskey(ctxt->state.desrfb.key, EN0);
for (i = 0; i < len; i += 8) {
des((void *)in + i, out + i);
}
return 0;
}
static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
size_t i;
if (len % 8) {
error_setg(errp, "Buffer size must be multiple of 8 not %zu",
len);
return -1;
}
deskey(ctxt->state.desrfb.key, DE1);
for (i = 0; i < len; i += 8) {
des((void *)in + i, out + i);
}
return 0;
}
static int qcrypto_cipher_setiv_des_rfb(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
error_setg(errp, "Setting IV is not supported");
return -1;
}
static int qcrypto_cipher_init_des_rfb(QCryptoCipher *cipher,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoCipherBuiltin *ctxt;
if (cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
return -1;
}
ctxt = g_new0(QCryptoCipherBuiltin, 1);
ctxt->state.desrfb.key = g_new0(uint8_t, nkey);
memcpy(ctxt->state.desrfb.key, key, nkey);
ctxt->state.desrfb.nkey = nkey;
ctxt->free = qcrypto_cipher_free_des_rfb;
ctxt->setiv = qcrypto_cipher_setiv_des_rfb;
ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb;
ctxt->decrypt = qcrypto_cipher_decrypt_des_rfb;
cipher->opaque = ctxt;
return 0;
}
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
{
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256:
return true;
default:
return false;
}
}
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoCipher *cipher;
cipher = g_new0(QCryptoCipher, 1);
cipher->alg = alg;
cipher->mode = mode;
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
goto error;
}
switch (cipher->alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
if (qcrypto_cipher_init_des_rfb(cipher, key, nkey, errp) < 0) {
goto error;
}
break;
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256:
if (qcrypto_cipher_init_aes(cipher, key, nkey, errp) < 0) {
goto error;
}
break;
default:
error_setg(errp,
"Unsupported cipher algorithm %d", cipher->alg);
goto error;
}
return cipher;
error:
g_free(cipher);
return NULL;
}
void qcrypto_cipher_free(QCryptoCipher *cipher)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
if (!cipher) {
return;
}
ctxt->free(cipher);
g_free(cipher);
}
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
return ctxt->encrypt(cipher, in, out, len, errp);
}
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
return ctxt->decrypt(cipher, in, out, len, errp);
}
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
return ctxt->setiv(cipher, iv, niv, errp);
}

195
crypto/cipher-gcrypt.c Normal file
View File

@ -0,0 +1,195 @@
/*
* QEMU Crypto cipher libgcrypt 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 <gcrypt.h>
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
{
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256:
return true;
default:
return false;
}
}
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoCipher *cipher;
gcry_cipher_hd_t handle;
gcry_error_t err;
int gcryalg, gcrymode;
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
gcrymode = GCRY_CIPHER_MODE_ECB;
break;
case QCRYPTO_CIPHER_MODE_CBC:
gcrymode = GCRY_CIPHER_MODE_CBC;
break;
default:
error_setg(errp, "Unsupported cipher mode %d", mode);
return NULL;
}
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
return NULL;
}
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
gcryalg = GCRY_CIPHER_DES;
break;
case QCRYPTO_CIPHER_ALG_AES_128:
gcryalg = GCRY_CIPHER_AES128;
break;
case QCRYPTO_CIPHER_ALG_AES_192:
gcryalg = GCRY_CIPHER_AES192;
break;
case QCRYPTO_CIPHER_ALG_AES_256:
gcryalg = GCRY_CIPHER_AES256;
break;
default:
error_setg(errp, "Unsupported cipher algorithm %d", alg);
return NULL;
}
cipher = g_new0(QCryptoCipher, 1);
cipher->alg = alg;
cipher->mode = mode;
err = gcry_cipher_open(&handle, gcryalg, gcrymode, 0);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gcry_strerror(err));
goto error;
}
if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
/* We're using standard DES cipher from gcrypt, so we need
* to munge the key so that the results are the same as the
* bizarre RFB variant of DES :-)
*/
uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
err = gcry_cipher_setkey(handle, rfbkey, nkey);
g_free(rfbkey);
} else {
err = gcry_cipher_setkey(handle, key, nkey);
}
if (err != 0) {
error_setg(errp, "Cannot set key: %s",
gcry_strerror(err));
goto error;
}
cipher->opaque = handle;
return cipher;
error:
gcry_cipher_close(handle);
g_free(cipher);
return NULL;
}
void qcrypto_cipher_free(QCryptoCipher *cipher)
{
gcry_cipher_hd_t handle;
if (!cipher) {
return;
}
handle = cipher->opaque;
gcry_cipher_close(handle);
g_free(cipher);
}
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
gcry_cipher_hd_t handle = cipher->opaque;
gcry_error_t err;
err = gcry_cipher_encrypt(handle,
out, len,
in, len);
if (err != 0) {
error_setg(errp, "Cannot encrypt data: %s",
gcry_strerror(err));
return -1;
}
return 0;
}
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
gcry_cipher_hd_t handle = cipher->opaque;
gcry_error_t err;
err = gcry_cipher_decrypt(handle,
out, len,
in, len);
if (err != 0) {
error_setg(errp, "Cannot decrypt data: %s",
gcry_strerror(err));
return -1;
}
return 0;
}
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
gcry_cipher_hd_t handle = cipher->opaque;
gcry_error_t err;
gcry_cipher_reset(handle);
err = gcry_cipher_setiv(handle, iv, niv);
if (err != 0) {
error_setg(errp, "Cannot set IV: %s",
gcry_strerror(err));
return -1;
}
return 0;
}

206
crypto/cipher-nettle.c Normal file
View File

@ -0,0 +1,206 @@
/*
* QEMU Crypto cipher nettle 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 <nettle/nettle-types.h>
#include <nettle/aes.h>
#include <nettle/des.h>
#include <nettle/cbc.h>
typedef struct QCryptoCipherNettle QCryptoCipherNettle;
struct QCryptoCipherNettle {
void *ctx_encrypt;
void *ctx_decrypt;
nettle_crypt_func *alg_encrypt;
nettle_crypt_func *alg_decrypt;
uint8_t *iv;
size_t niv;
};
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
{
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256:
return true;
default:
return false;
}
}
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoCipher *cipher;
QCryptoCipherNettle *ctx;
uint8_t *rfbkey;
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
break;
default:
error_setg(errp, "Unsupported cipher mode %d", mode);
return NULL;
}
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
return NULL;
}
cipher = g_new0(QCryptoCipher, 1);
cipher->alg = alg;
cipher->mode = mode;
ctx = g_new0(QCryptoCipherNettle, 1);
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
ctx->ctx_encrypt = g_new0(struct des_ctx, 1);
ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
des_set_key(ctx->ctx_encrypt, rfbkey);
g_free(rfbkey);
ctx->alg_encrypt = (nettle_crypt_func *)des_encrypt;
ctx->alg_decrypt = (nettle_crypt_func *)des_decrypt;
ctx->niv = DES_BLOCK_SIZE;
break;
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256:
ctx->ctx_encrypt = g_new0(struct aes_ctx, 1);
ctx->ctx_decrypt = g_new0(struct aes_ctx, 1);
aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key);
aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key);
ctx->alg_encrypt = (nettle_crypt_func *)aes_encrypt;
ctx->alg_decrypt = (nettle_crypt_func *)aes_decrypt;
ctx->niv = AES_BLOCK_SIZE;
break;
default:
error_setg(errp, "Unsupported cipher algorithm %d", alg);
goto error;
}
ctx->iv = g_new0(uint8_t, ctx->niv);
cipher->opaque = ctx;
return cipher;
error:
g_free(cipher);
g_free(ctx);
return NULL;
}
void qcrypto_cipher_free(QCryptoCipher *cipher)
{
QCryptoCipherNettle *ctx;
if (!cipher) {
return;
}
ctx = cipher->opaque;
g_free(ctx->iv);
g_free(ctx->ctx_encrypt);
g_free(ctx->ctx_decrypt);
g_free(ctx);
g_free(cipher);
}
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherNettle *ctx = cipher->opaque;
switch (cipher->mode) {
case QCRYPTO_CIPHER_MODE_ECB:
ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
break;
case QCRYPTO_CIPHER_MODE_CBC:
cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
ctx->niv, ctx->iv,
len, out, in);
break;
default:
error_setg(errp, "Unsupported cipher algorithm %d",
cipher->alg);
return -1;
}
return 0;
}
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherNettle *ctx = cipher->opaque;
switch (cipher->mode) {
case QCRYPTO_CIPHER_MODE_ECB:
ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
len, out, in);
break;
case QCRYPTO_CIPHER_MODE_CBC:
cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
ctx->alg_decrypt, ctx->niv, ctx->iv,
len, out, in);
break;
default:
error_setg(errp, "Unsupported cipher algorithm %d",
cipher->alg);
return -1;
}
return 0;
}
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
QCryptoCipherNettle *ctx = cipher->opaque;
if (niv != ctx->niv) {
error_setg(errp, "Expected IV size %zu not %zu",
ctx->niv, niv);
return -1;
}
memcpy(ctx->iv, iv, niv);
return 0;
}

74
crypto/cipher.c Normal file
View File

@ -0,0 +1,74 @@
/*
* QEMU Crypto cipher 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/cipher.h"
static size_t alg_key_len[QCRYPTO_CIPHER_ALG_LAST] = {
[QCRYPTO_CIPHER_ALG_AES_128] = 16,
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
};
static bool
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
size_t nkey,
Error **errp)
{
if ((unsigned)alg >= QCRYPTO_CIPHER_ALG_LAST) {
error_setg(errp, "Cipher algorithm %d out of range",
alg);
return false;
}
if (alg_key_len[alg] != nkey) {
error_setg(errp, "Cipher key length %zu should be %zu",
alg_key_len[alg], nkey);
return false;
}
return true;
}
#if defined(CONFIG_GNUTLS_GCRYPT) || defined(CONFIG_GNUTLS_NETTLE)
static uint8_t *
qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
size_t nkey)
{
uint8_t *ret = g_new0(uint8_t, nkey);
size_t i;
for (i = 0; i < nkey; i++) {
uint8_t r = key[i];
r = (r & 0xf0) >> 4 | (r & 0x0f) << 4;
r = (r & 0xcc) >> 2 | (r & 0x33) << 2;
r = (r & 0xaa) >> 1 | (r & 0x55) << 1;
ret[i] = r;
}
return ret;
}
#endif /* CONFIG_GNUTLS_GCRYPT || CONFIG_GNUTLS_NETTLE */
#ifdef CONFIG_GNUTLS_GCRYPT
#include "crypto/cipher-gcrypt.c"
#elif defined CONFIG_GNUTLS_NETTLE
#include "crypto/cipher-nettle.c"
#else
#include "crypto/cipher-builtin.c"
#endif

View File

@ -26,7 +26,7 @@
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
*/
#include "d3des.h"
#include "crypto/desrfb.h"
static void scrunch(unsigned char *, unsigned long *);
static void unscrun(unsigned long *, unsigned char *);

200
crypto/hash.c Normal file
View 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);
}

150
crypto/init.c Normal file
View File

@ -0,0 +1,150 @@
/*
* 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"
#include "qemu/thread.h"
#ifdef CONFIG_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#ifdef CONFIG_GNUTLS_GCRYPT
#include <gcrypt.h>
#endif
/* #define DEBUG_GNUTLS */
/*
* If GNUTLS is built against GCrypt then
*
* - When GNUTLS >= 2.12, we must not initialize gcrypt threading
* because GNUTLS will do that itself
* - When GNUTLS < 2.12 we must always initialize gcrypt threading
*
* But....
*
* When gcrypt >= 1.6.0 we must not initialize gcrypt threading
* because gcrypt will do that itself.
*
* So we need to init gcrypt threading if
*
* - gcrypt < 1.6.0
* AND
* - gnutls < 2.12
*
*/
#if (defined(CONFIG_GNUTLS_GCRYPT) && \
(!defined(GNUTLS_VERSION_NUMBER) || \
(GNUTLS_VERSION_NUMBER < 0x020c00)) && \
(!defined(GCRYPT_VERSION_NUMBER) || \
(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)
{
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
#ifdef CONFIG_GNUTLS_GCRYPT
if (!gcry_check_version(GCRYPT_VERSION)) {
error_setg(errp, "Unable to initialize gcrypt");
return -1;
}
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
gcry_control(GCRYCTL_SET_THREAD_CBS, &qcrypto_gcrypt_thread_impl);
#endif /* QCRYPTO_INIT_GCRYPT_THREADS */
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
#endif
return 0;
}
#else /* ! CONFIG_GNUTLS */
int qcrypto_init(Error **errp G_GNUC_UNUSED)
{
return 0;
}
#endif /* ! CONFIG_GNUTLS */

View File

@ -933,7 +933,7 @@ static void rom_reset(void *unused)
}
}
int rom_load_all(void)
int rom_check_and_register_reset(void)
{
hwaddr addr = 0;
MemoryRegionSection section;
@ -957,12 +957,8 @@ int rom_load_all(void)
memory_region_unref(section.mr);
}
qemu_register_reset(rom_reset, NULL);
return 0;
}
void rom_load_done(void)
{
roms_loaded = 1;
return 0;
}
void rom_set_fw(FWCfgState *f)

210
include/crypto/cipher.h Normal file
View File

@ -0,0 +1,210 @@
/*
* QEMU Crypto cipher 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_CIPHER_H__
#define QCRYPTO_CIPHER_H__
#include "qemu-common.h"
#include "qapi/error.h"
typedef struct QCryptoCipher QCryptoCipher;
typedef enum {
QCRYPTO_CIPHER_ALG_AES_128,
QCRYPTO_CIPHER_ALG_AES_192,
QCRYPTO_CIPHER_ALG_AES_256,
QCRYPTO_CIPHER_ALG_DES_RFB, /* A stupid variant on DES for VNC */
QCRYPTO_CIPHER_ALG_LAST
} QCryptoCipherAlgorithm;
typedef enum {
QCRYPTO_CIPHER_MODE_ECB,
QCRYPTO_CIPHER_MODE_CBC,
QCRYPTO_CIPHER_MODE_LAST
} QCryptoCipherMode;
/**
* QCryptoCipher:
*
* The QCryptoCipher object provides a way to perform encryption
* and decryption of data, with a standard API, regardless of the
* algorithm used. It further isolates the calling code from the
* details of the specific underlying implementation, whether
* built-in, libgcrypt or nettle.
*
* Each QCryptoCipher object is capable of performing both
* encryption and decryption, and can operate in a number
* or modes including ECB, CBC.
*
* <example>
* <title>Encrypting data with AES-128 in CBC mode</title>
* <programlisting>
* QCryptoCipher *cipher;
* uint8_t key = ....;
* size_t keylen = 16;
* uint8_t iv = ....;
*
* if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
* error_report(errp, "Feature <blah> requires AES cipher support");
* return -1;
* }
*
* cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
* QCRYPTO_CIPHER_MODE_CBC,
* key, keylen,
* errp);
* if (!cipher) {
* return -1;
* }
*
* if (qcrypto_cipher_set_iv(cipher, iv, keylen, errp) < 0) {
* return -1;
* }
*
* if (qcrypto_cipher_encrypt(cipher, rawdata, encdata, datalen, errp) < 0) {
* return -1;
* }
*
* qcrypto_cipher_free(cipher);
* </programlisting>
* </example>
*
*/
struct QCryptoCipher {
QCryptoCipherAlgorithm alg;
QCryptoCipherMode mode;
void *opaque;
};
/**
* qcrypto_cipher_supports:
* @alg: the cipher algorithm
*
* Determine if @alg cipher algorithm is supported by the
* current configured build
*
* Returns: true if the algorithm is supported, false otherwise
*/
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg);
/**
* qcrypto_cipher_new:
* @alg: the cipher algorithm
* @mode: the cipher usage mode
* @key: the private key bytes
* @nkey: the length of @key
* @errp: pointer to an uninitialized error object
*
* Creates a new cipher object for encrypting/decrypting
* data with the algorithm @alg in the usage mode @mode.
*
* The @key parameter provides the bytes representing
* the encryption/decryption key to use. The @nkey parameter
* specifies the length of @key in bytes. Each algorithm has
* one or more valid key lengths, and it is an error to provide
* a key of the incorrect length.
*
* The returned cipher object must be released with
* qcrypto_cipher_free() when no longer required
*
* Returns: a new cipher object, or NULL on error
*/
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp);
/**
* qcrypto_cipher_free:
* @cipher: the cipher object
*
* Release the memory associated with @cipher that
* was previously allocated by qcrypto_cipher_new()
*/
void qcrypto_cipher_free(QCryptoCipher *cipher);
/**
* qcrypto_cipher_encrypt:
* @cipher: the cipher object
* @in: buffer holding the plain text input data
* @out: buffer to fill with the cipher text output data
* @len: the length of @in and @out buffers
* @errp: pointer to an uninitialized error object
*
* Encrypts the plain text stored in @in, filling
* @out with the resulting ciphered text. Both the
* @in and @out buffers must have the same size,
* given by @len.
*
* Returns: 0 on success, or -1 on error
*/
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp);
/**
* qcrypto_cipher_decrypt:
* @cipher: the cipher object
* @in: buffer holding the cipher text input data
* @out: buffer to fill with the plain text output data
* @len: the length of @in and @out buffers
* @errp: pointer to an uninitialized error object
*
* Decrypts the cipher text stored in @in, filling
* @out with the resulting plain text. Both the
* @in and @out buffers must have the same size,
* given by @len.
*
* Returns: 0 on success, or -1 on error
*/
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp);
/**
* qcrypto_cipher_setiv:
* @cipher: the cipher object
* @iv: the initialization vector bytes
* @niv: the length of @iv
* @errpr: pointer to an uninitialized error object
*
* If the @cipher object is setup to use a mode that requires
* initialization vectors, this sets the initialization vector
* bytes. The @iv data should have the same length as the
* cipher key used when originally constructing the cipher
* object. It is an error to set an initialization vector
* if the cipher mode does not require one.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp);
#endif /* QCRYPTO_CIPHER_H__ */

189
include/crypto/hash.h Normal file
View 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
View 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__ */

View File

@ -75,8 +75,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
void *callback_opaque);
int rom_add_elf_program(const char *name, void *data, size_t datasize,
size_t romsize, hwaddr addr);
int rom_load_all(void);
void rom_load_done(void);
int rom_check_and_register_reset(void);
void rom_set_fw(FWCfgState *f);
int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
void *rom_ptr(hwaddr addr);

View File

@ -14,7 +14,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/aes.h"
#include "crypto/aes.h"
union CRYPTO_STATE {
uint8_t bytes[16];

View File

@ -20,7 +20,6 @@
#include <math.h>
#include "cpu.h"
#include "exec/helper-proto.h"
#include "qemu/aes.h"
#include "qemu/host-utils.h"
#include "exec/cpu_ldst.h"

View File

@ -18,7 +18,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/aes.h"
#include "crypto/aes.h"
#if SHIFT == 0
#define Reg MMXReg

View File

@ -19,7 +19,7 @@
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "qemu/aes.h"
#include "crypto/aes.h"
#include "helper_regs.h"
/*****************************************************************************/

2
tests/.gitignore vendored
View File

@ -10,6 +10,8 @@ rcutorture
test-aio
test-bitops
test-coroutine
test-crypto-cipher
test-crypto-hash
test-cutils
test-hbitmap
test-int128

View File

@ -74,6 +74,8 @@ 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-unit-y += tests/test-crypto-cipher$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@ -343,6 +345,8 @@ 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
tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.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

290
tests/test-crypto-cipher.c Normal file
View File

@ -0,0 +1,290 @@
/*
* QEMU Crypto cipher 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/cipher.h"
typedef struct QCryptoCipherTestData QCryptoCipherTestData;
struct QCryptoCipherTestData {
const char *path;
QCryptoCipherAlgorithm alg;
QCryptoCipherMode mode;
const char *key;
const char *plaintext;
const char *ciphertext;
const char *iv;
};
/* AES test data comes from appendix F of:
*
* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
*/
static QCryptoCipherTestData test_data[] = {
{
/* NIST F.1.1 ECB-AES128.Encrypt */
.path = "/crypto/cipher/aes-ecb-128",
.alg = QCRYPTO_CIPHER_ALG_AES_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710",
.ciphertext =
"3ad77bb40d7a3660a89ecaf32466ef97"
"f5d3d58503b9699de785895a96fdbaaf"
"43b1cd7f598ece23881b00e3ed030688"
"7b0c785e27e8ad3f8223207104725dd4"
},
{
/* NIST F.1.3 ECB-AES192.Encrypt */
.path = "/crypto/cipher/aes-ecb-192",
.alg = QCRYPTO_CIPHER_ALG_AES_192,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710",
.ciphertext =
"bd334f1d6e45f25ff712a214571fa5cc"
"974104846d0ad3ad7734ecb3ecee4eef"
"ef7afd2270e2e60adce0ba2face6444e"
"9a4b41ba738d6c72fb16691603c18e0e"
},
{
/* NIST F.1.5 ECB-AES256.Encrypt */
.path = "/crypto/cipher/aes-ecb-256",
.alg = QCRYPTO_CIPHER_ALG_AES_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key =
"603deb1015ca71be2b73aef0857d7781"
"1f352c073b6108d72d9810a30914dff4",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710",
.ciphertext =
"f3eed1bdb5d2a03c064b5a7e3db181f8"
"591ccb10d410ed26dc5ba74a31362870"
"b6ed21b99ca6f4f9f153e7b1beafed1d"
"23304b7a39f9f3ff067d8d8f9e24ecc7",
},
{
/* NIST F.2.1 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-128",
.alg = QCRYPTO_CIPHER_ALG_AES_128,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.iv = "000102030405060708090a0b0c0d0e0f",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710",
.ciphertext =
"7649abac8119b246cee98e9b12e9197d"
"5086cb9b507219ee95db113a917678b2"
"73bed6b8e3c1743b7116e69e22229516"
"3ff1caa1681fac09120eca307586e1a7",
},
{
/* NIST F.2.3 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-192",
.alg = QCRYPTO_CIPHER_ALG_AES_192,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.iv = "000102030405060708090a0b0c0d0e0f",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710",
.ciphertext =
"4f021db243bc633d7178183a9fa071e8"
"b4d9ada9ad7dedf4e5e738763f69145a"
"571b242012fb7ae07fa9baac3df102e0"
"08b0e27988598881d920a9e64f5615cd",
},
{
/* NIST F.2.5 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-256",
.alg = QCRYPTO_CIPHER_ALG_AES_256,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key =
"603deb1015ca71be2b73aef0857d7781"
"1f352c073b6108d72d9810a30914dff4",
.iv = "000102030405060708090a0b0c0d0e0f",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710",
.ciphertext =
"f58c4c04d6e5f1ba779eabfb5f7bfbd6"
"9cfc4e967edb808d679f777bc6702c7d"
"39f23369a9d9bacfa530e26304231461"
"b2eb05e2c39be9fcda6c19078c6a9d1b",
},
{
.path = "/crypto/cipher/des-rfb-ecb-56",
.alg = QCRYPTO_CIPHER_ALG_DES_RFB,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "0123456789abcdef",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710",
.ciphertext =
"8f346aaf64eaf24040720d80648c52e7"
"aefc616be53ab1a3d301e69d91e01838"
"ffd29f1bb5596ad94ea2d8e6196b7f09"
"30d8ed0bf2773af36dd82a6280c20926",
},
};
static inline int unhex(char c)
{
if (c >= 'a' && c <= 'f') {
return 10 + (c - 'a');
}
if (c >= 'A' && c <= 'F') {
return 10 + (c - 'A');
}
return c - '0';
}
static inline char hex(int i)
{
if (i < 10) {
return '0' + i;
}
return 'a' + (i - 10);
}
static size_t unhex_string(const char *hexstr,
uint8_t **data)
{
size_t len;
size_t i;
if (!hexstr) {
*data = NULL;
return 0;
}
len = strlen(hexstr);
*data = g_new0(uint8_t, len / 2);
for (i = 0; i < len; i += 2) {
(*data)[i/2] = (unhex(hexstr[i]) << 4) | unhex(hexstr[i+1]);
}
return len / 2;
}
static char *hex_string(const uint8_t *bytes,
size_t len)
{
char *hexstr = g_new0(char, len * 2 + 1);
size_t i;
for (i = 0; i < len; i++) {
hexstr[i*2] = hex((bytes[i] >> 4) & 0xf);
hexstr[i*2+1] = hex(bytes[i] & 0xf);
}
hexstr[len*2] = '\0';
return hexstr;
}
static void test_cipher(const void *opaque)
{
const QCryptoCipherTestData *data = opaque;
QCryptoCipher *cipher;
Error *err = NULL;
uint8_t *key, *iv, *ciphertext, *plaintext, *outtext;
size_t nkey, niv, nciphertext, nplaintext;
char *outtexthex;
g_test_message("foo");
nkey = unhex_string(data->key, &key);
niv = unhex_string(data->iv, &iv);
nciphertext = unhex_string(data->ciphertext, &ciphertext);
nplaintext = unhex_string(data->plaintext, &plaintext);
g_assert(nciphertext == nplaintext);
outtext = g_new0(uint8_t, nciphertext);
cipher = qcrypto_cipher_new(
data->alg, data->mode,
key, nkey,
&err);
g_assert(cipher != NULL);
g_assert(err == NULL);
if (iv) {
g_assert(qcrypto_cipher_setiv(cipher,
iv, niv,
&err) == 0);
g_assert(err == NULL);
}
g_assert(qcrypto_cipher_encrypt(cipher,
plaintext,
outtext,
nplaintext,
&err) == 0);
g_assert(err == NULL);
outtexthex = hex_string(outtext, nciphertext);
g_assert_cmpstr(outtexthex, ==, data->ciphertext);
g_free(outtext);
g_free(outtexthex);
g_free(key);
g_free(iv);
g_free(ciphertext);
g_free(plaintext);
qcrypto_cipher_free(cipher);
}
int main(int argc, char **argv)
{
size_t i;
g_test_init(&argc, &argv, NULL);
g_assert(qcrypto_init(NULL) == 0);
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher);
}
return g_test_run();
}

209
tests/test-crypto-hash.c Normal file
View 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();
}

View File

@ -1,10 +1,10 @@
vnc-obj-y += vnc.o d3des.o
vnc-obj-y += vnc.o
vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
vnc-obj-y += vnc-enc-tight.o vnc-palette.o
vnc-obj-y += vnc-enc-zrle.o
vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o
vnc-obj-y += vnc-ws.o
vnc-obj-y += vnc-jobs.o
common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o

View File

@ -20,6 +20,7 @@
#include "vnc.h"
#include "qemu/main-loop.h"
#include "crypto/hash.h"
#ifdef CONFIG_VNC_TLS
#include "qemu/sockets.h"
@ -203,24 +204,21 @@ static char *vncws_extract_handshake_entry(const char *handshake,
static void vncws_send_handshake_response(VncState *vs, const char* key)
{
char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1];
unsigned char hash[SHA1_DIGEST_LEN];
size_t hash_size = sizeof(hash);
char *accept = NULL, *response = NULL;
gnutls_datum_t in;
int ret;
Error *err = NULL;
g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1);
g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1);
/* hash and encode it */
in.data = (void *)combined_key;
in.size = WS_CLIENT_KEY_LEN + WS_GUID_LEN;
ret = gnutls_fingerprint(GNUTLS_DIG_SHA1, &in, hash, &hash_size);
if (ret == GNUTLS_E_SUCCESS && hash_size <= SHA1_DIGEST_LEN) {
accept = g_base64_encode(hash, hash_size);
}
if (accept == NULL) {
VNC_DEBUG("Hashing Websocket combined key failed\n");
if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA1,
combined_key,
WS_CLIENT_KEY_LEN + WS_GUID_LEN,
&accept,
&err) < 0) {
VNC_DEBUG("Hashing Websocket combined key failed %s\n",
error_get_pretty(err));
error_free(err);
vnc_client_error(vs);
return;
}

View File

@ -21,8 +21,6 @@
#ifndef __QEMU_UI_VNC_WS_H
#define __QEMU_UI_VNC_WS_H
#include <gnutls/gnutls.h>
#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3)
#define SHA1_DIGEST_LEN 20

119
ui/vnc.c
View File

@ -40,6 +40,7 @@
#include "qemu/osdep.h"
#include "ui/input.h"
#include "qapi-event.h"
#include "crypto/hash.h"
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
#define VNC_REFRESH_INTERVAL_INC 50
@ -48,7 +49,7 @@ static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
#include "vnc_keysym.h"
#include "d3des.h"
#include "crypto/cipher.h"
static QTAILQ_HEAD(, VncDisplay) vnc_displays =
QTAILQ_HEAD_INITIALIZER(vnc_displays);
@ -355,9 +356,7 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client)
info->base->host = g_strdup(host);
info->base->service = g_strdup(serv);
info->base->family = inet_netfamily(sa.ss_family);
#ifdef CONFIG_VNC_WS
info->base->websocket = client->websocket;
#endif
#ifdef CONFIG_VNC_TLS
if (client->tls.session && client->tls.dname) {
@ -582,12 +581,10 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
info->server = qmp_query_server_entry(vd->lsock, false,
info->server);
}
#ifdef CONFIG_VNC_WS
if (vd->lwebsock != -1) {
info->server = qmp_query_server_entry(vd->lwebsock, true,
info->server);
}
#endif
item = g_new0(VncInfo2List, 1);
item->value = info;
@ -1231,10 +1228,8 @@ void vnc_disconnect_finish(VncState *vs)
buffer_free(&vs->input);
buffer_free(&vs->output);
#ifdef CONFIG_VNC_WS
buffer_free(&vs->ws_input);
buffer_free(&vs->ws_output);
#endif /* CONFIG_VNC_WS */
qapi_free_VncClientInfo(vs->info);
@ -1413,12 +1408,9 @@ static void vnc_client_write_locked(void *opaque)
} else
#endif /* CONFIG_VNC_SASL */
{
#ifdef CONFIG_VNC_WS
if (vs->encode_ws) {
vnc_client_write_ws(vs);
} else
#endif /* CONFIG_VNC_WS */
{
} else {
vnc_client_write_plain(vs);
}
}
@ -1429,11 +1421,7 @@ void vnc_client_write(void *opaque)
VncState *vs = opaque;
vnc_lock_output(vs);
if (vs->output.offset
#ifdef CONFIG_VNC_WS
|| vs->ws_output.offset
#endif
) {
if (vs->output.offset || vs->ws_output.offset) {
vnc_client_write_locked(opaque);
} else if (vs->csock != -1) {
qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs);
@ -1539,7 +1527,6 @@ void vnc_client_read(void *opaque)
ret = vnc_client_read_sasl(vs);
else
#endif /* CONFIG_VNC_SASL */
#ifdef CONFIG_VNC_WS
if (vs->encode_ws) {
ret = vnc_client_read_ws(vs);
if (ret == -1) {
@ -1549,10 +1536,8 @@ void vnc_client_read(void *opaque)
vnc_client_error(vs);
return;
}
} else
#endif /* CONFIG_VNC_WS */
{
ret = vnc_client_read_plain(vs);
} else {
ret = vnc_client_read_plain(vs);
}
if (!ret) {
if (vs->csock == -1)
@ -1624,11 +1609,8 @@ void vnc_write_u8(VncState *vs, uint8_t value)
void vnc_flush(VncState *vs)
{
vnc_lock_output(vs);
if (vs->csock != -1 && (vs->output.offset
#ifdef CONFIG_VNC_WS
|| vs->ws_output.offset
#endif
)) {
if (vs->csock != -1 && (vs->output.offset ||
vs->ws_output.offset)) {
vnc_client_write_locked(vs);
}
vnc_unlock_output(vs);
@ -2535,9 +2517,11 @@ static void make_challenge(VncState *vs)
static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
{
unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
int i, j, pwlen;
size_t i, pwlen;
unsigned char key[8];
time_t now = time(NULL);
QCryptoCipher *cipher;
Error *err = NULL;
if (!vs->vd->password) {
VNC_DEBUG("No password configured on server");
@ -2554,9 +2538,29 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
pwlen = strlen(vs->vd->password);
for (i=0; i<sizeof(key); i++)
key[i] = i<pwlen ? vs->vd->password[i] : 0;
deskey(key, EN0);
for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
des(response+j, response+j);
cipher = qcrypto_cipher_new(
QCRYPTO_CIPHER_ALG_DES_RFB,
QCRYPTO_CIPHER_MODE_ECB,
key, G_N_ELEMENTS(key),
&err);
if (!cipher) {
VNC_DEBUG("Cannot initialize cipher %s",
error_get_pretty(err));
error_free(err);
goto reject;
}
if (qcrypto_cipher_decrypt(cipher,
vs->challenge,
response,
VNC_AUTH_CHALLENGE_SIZE,
&err) < 0) {
VNC_DEBUG("Cannot encrypt challenge %s",
error_get_pretty(err));
error_free(err);
goto reject;
}
/* Compare expected vs actual challenge response */
if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
@ -3019,7 +3023,6 @@ static void vnc_connect(VncDisplay *vd, int csock,
VNC_DEBUG("New client on socket %d\n", csock);
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
qemu_set_nonblock(vs->csock);
#ifdef CONFIG_VNC_WS
if (websocket) {
vs->websocket = 1;
#ifdef CONFIG_VNC_TLS
@ -3031,7 +3034,6 @@ static void vnc_connect(VncDisplay *vd, int csock,
qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs);
}
} else
#endif /* CONFIG_VNC_WS */
{
qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs);
}
@ -3040,10 +3042,7 @@ static void vnc_connect(VncDisplay *vd, int csock,
vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
#ifdef CONFIG_VNC_WS
if (!vs->websocket)
#endif
{
if (!vs->websocket) {
vnc_init_state(vs);
}
@ -3099,12 +3098,9 @@ static void vnc_listen_read(void *opaque, bool websocket)
/* Catch-up */
graphic_hw_update(vs->dcl.con);
#ifdef CONFIG_VNC_WS
if (websocket) {
csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen);
} else
#endif /* CONFIG_VNC_WS */
{
} else {
csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
}
@ -3119,12 +3115,10 @@ static void vnc_listen_regular_read(void *opaque)
vnc_listen_read(opaque, false);
}
#ifdef CONFIG_VNC_WS
static void vnc_listen_websocket_read(void *opaque)
{
vnc_listen_read(opaque, true);
}
#endif /* CONFIG_VNC_WS */
static const DisplayChangeListenerOps dcl_ops = {
.dpy_name = "vnc",
@ -3150,9 +3144,7 @@ void vnc_display_init(const char *id)
QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
vs->lsock = -1;
#ifdef CONFIG_VNC_WS
vs->lwebsock = -1;
#endif
QTAILQ_INIT(&vs->clients);
vs->expires = TIME_MAX;
@ -3186,14 +3178,12 @@ static void vnc_display_close(VncDisplay *vs)
close(vs->lsock);
vs->lsock = -1;
}
#ifdef CONFIG_VNC_WS
vs->ws_enabled = false;
if (vs->lwebsock != -1) {
qemu_set_fd_handler(vs->lwebsock, NULL, NULL, NULL);
close(vs->lwebsock);
vs->lwebsock = -1;
}
#endif /* CONFIG_VNC_WS */
vs->auth = VNC_AUTH_INVALID;
vs->subauth = VNC_AUTH_INVALID;
#ifdef CONFIG_VNC_TLS
@ -3516,12 +3506,20 @@ void vnc_display_open(const char *id, Error **errp)
}
password = qemu_opt_get_bool(opts, "password", false);
if (password && fips_get_state()) {
error_setg(errp,
"VNC password auth disabled due to FIPS mode, "
"consider using the VeNCrypt or SASL authentication "
"methods as an alternative");
goto fail;
if (password) {
if (fips_get_state()) {
error_setg(errp,
"VNC password auth disabled due to FIPS mode, "
"consider using the VeNCrypt or SASL authentication "
"methods as an alternative");
goto fail;
}
if (!qcrypto_cipher_supports(
QCRYPTO_CIPHER_ALG_DES_RFB)) {
error_setg(errp,
"Cipher backend does not support DES RFB algorithm");
goto fail;
}
}
reverse = qemu_opt_get_bool(opts, "reverse", false);
@ -3579,13 +3577,12 @@ void vnc_display_open(const char *id, Error **errp)
websocket = qemu_opt_get(opts, "websocket");
if (websocket) {
#ifdef CONFIG_VNC_WS
vs->ws_enabled = true;
qemu_opt_set(wsopts, "port", websocket, &error_abort);
#else /* ! CONFIG_VNC_WS */
error_setg(errp, "Websockets protocol requires gnutls support");
goto fail;
#endif /* ! CONFIG_VNC_WS */
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
error_setg(errp, "SHA1 hash support is required for websockets");
goto fail;
}
}
#ifdef CONFIG_VNC_JPEG
@ -3668,9 +3665,7 @@ void vnc_display_open(const char *id, Error **errp)
/* connect to viewer */
int csock;
vs->lsock = -1;
#ifdef CONFIG_VNC_WS
vs->lwebsock = -1;
#endif
if (strncmp(vnc, "unix:", 5) == 0) {
csock = unix_connect(vnc+5, errp);
} else {
@ -3693,7 +3688,6 @@ void vnc_display_open(const char *id, Error **errp)
if (vs->lsock < 0) {
goto fail;
}
#ifdef CONFIG_VNC_WS
if (vs->ws_enabled) {
vs->lwebsock = inet_listen_opts(wsopts, 0, errp);
if (vs->lwebsock < 0) {
@ -3704,16 +3698,13 @@ void vnc_display_open(const char *id, Error **errp)
goto fail;
}
}
#endif /* CONFIG_VNC_WS */
}
vs->enabled = true;
qemu_set_fd_handler(vs->lsock, vnc_listen_regular_read, NULL, vs);
#ifdef CONFIG_VNC_WS
if (vs->ws_enabled) {
qemu_set_fd_handler(vs->lwebsock, vnc_listen_websocket_read,
NULL, vs);
}
#endif /* CONFIG_VNC_WS */
}
qemu_opts_del(sopts);
qemu_opts_del(wsopts);
@ -3723,9 +3714,7 @@ fail:
qemu_opts_del(sopts);
qemu_opts_del(wsopts);
vs->enabled = false;
#ifdef CONFIG_VNC_WS
vs->ws_enabled = false;
#endif /* CONFIG_VNC_WS */
}
void vnc_display_add_client(const char *id, int csock, bool skipauth)

View File

@ -108,9 +108,7 @@ typedef struct VncDisplay VncDisplay;
#ifdef CONFIG_VNC_SASL
#include "vnc-auth-sasl.h"
#endif
#ifdef CONFIG_VNC_WS
#include "vnc-ws.h"
#endif
struct VncRectStat
{
@ -156,10 +154,8 @@ struct VncDisplay
int connections_limit;
VncSharePolicy share_policy;
int lsock;
#ifdef CONFIG_VNC_WS
int lwebsock;
bool ws_enabled;
#endif
DisplaySurface *ds;
DisplayChangeListener dcl;
kbd_layout_t *kbd_layout;
@ -294,21 +290,17 @@ struct VncState
#ifdef CONFIG_VNC_SASL
VncStateSASL sasl;
#endif
#ifdef CONFIG_VNC_WS
bool encode_ws;
bool websocket;
#endif /* CONFIG_VNC_WS */
VncClientInfo *info;
Buffer output;
Buffer input;
#ifdef CONFIG_VNC_WS
Buffer ws_input;
Buffer ws_output;
size_t ws_payload_remain;
WsMask ws_payload_mask;
#endif
/* current output mode information */
VncWritePixels *write_pixels;
PixelFormat client_pf;

View File

@ -9,7 +9,7 @@ util-obj-y += acl.o
util-obj-y += error.o qemu-error.o
util-obj-$(CONFIG_POSIX) += compatfd.o
util-obj-y += id.o
util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o
util-obj-y += iov.o qemu-config.o qemu-sockets.o uri.o notify.o
util-obj-y += qemu-option.o qemu-progress.o
util-obj-y += hexdump.o
util-obj-y += crc32c.o

18
vl.c
View File

@ -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
@ -2976,6 +2977,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();
@ -3019,6 +3021,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);
@ -4597,18 +4604,15 @@ int main(int argc, char **argv, char **envp)
qdev_machine_creation_done();
if (rom_load_all() != 0) {
fprintf(stderr, "rom loading failed\n");
exit(1);
}
/* TODO: once all bus devices are qdevified, this should be done
* when bus is created by qdev.c */
qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
qemu_run_machine_init_done_notifiers();
/* Done notifiers can load ROMs */
rom_load_done();
if (rom_check_and_register_reset() != 0) {
fprintf(stderr, "rom check and register reset failed\n");
exit(1);
}
qemu_system_reset(VMRESET_SILENT);
if (loadvm) {