All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations
@ 2015-06-18 17:02 Daniel P. Berrange
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 01/10] crypto: introduce new module for computing hash digests Daniel P. Berrange
                   ` (9 more replies)
  0 siblings, 10 replies; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

This small series covers the crypto consolidation patches
I previously posted:

RFC: https://lists.nongnu.org/archive/html/qemu-devel/2015-04/msg02038.html
 v1: https://lists.nongnu.org/archive/html/qemu-devel/2015-05/msg04267.html
 v2: https://lists.nongnu.org/archive/html/qemu-devel/2015-06/msg00601.html

Currently there are a 5 main places in QEMU which use some
form of cryptographic hash or cipher algorithm. These are
the quorum block driver (hash), qcow[2] block driver (cipher),
VNC password auth (cipher), VNC websockets (hash) and some
of the CPU instruction emulation (cipher).

For ciphers the code is using the in-tree implementations
of AES and/or the RFB cripple-DES. While there is nothing
broken about these implementations, it is none the less
desirable to be able to use the GNUTLS provided impls in
cases whre we are already linking to GNUTLS. This will
allow QEMU to use FIPS certified implementations, which
have been well audited, have some protection against
side-channel leakage and are generally actively maintained
by people knowledgable about encryption.

For hash digests the code is already using GNUTLS APIs.

With the TLS work, and possible future improved block device
encryption, there will be more general purpose crypto APIs
needed in QEMU.

It is undesirable to continue to litter the code with
countless #ifdef WITH_GNUTLS conditionals, as it makes
it increasingly hard to understand the code.

The goal of this series is to thus consolidate all the
crypto code into a single logical place in QEMU - the
source in $GIT/crypto and heads in $GIT/include/crypto
The code in this location will provide QEMU internal
APIs for hash digests, ciphers, and later TLS and block
encryption primitives. The implementations will be
backed by GNUTLS, and either libgcrypt or nettle depending
on which of these GNUTLS is linking to. In the case where
GNUTLS is disabled at build time, we'll still keep the
built-in AES & RFB-cripple-DES implementations available
so we have no regression vs today's level of support.

The callers of the crypto code can now be unconditionally
compiled and, if needed, they can check the availability
of algorithms they want at runtime and report clear errors
to the CLI or QMP if not available. This is a minor
difference in behaviour for the quorum block driver which
would previously be disabled at compile time if gnutls
was not available.

A future posting will include the TLS crypto APIs.

I have not attempted to convert the CPU emulation code to
use the new crypto APIs, since that code appears to have
quite specific need for access to the low level internal
stages of the AES algorithm. So I've left it using the
QEMU built-in AES code.

I've added myself in the MAINTAINERS file for the new
directories, since it was't clear if anyone else on the
existing QEMU maintainer list had any interest / knowledge
in maintaining the crypto related pieces.

Changes since v2:

  - Remove _(..) gettext markers from error messages
  - Fix array bounds check in hash module (Richard Henderson)
  - Fix null dereference in freeing of gcrypt cipher impl
    (Gonglei)

Changes since v1:

  - Add explicit algorithm constants for each AES key size,
    instead of inferring it from array length
  - Share code for munging des rfb key bit order
  - Share code for validating key array size vs algorithm
  - Refactor built-in cipher impl to reduce number of big
    switch statements
  - Fix uninitialized 'Error *err' var
  - Add comments in places where error reporting should be
    improved in future


Daniel P. Berrange (10):
  crypto: introduce new module for computing hash digests
  crypto: move built-in AES implementation into crypto/
  crypto: move built-in D3DES implementation into crypto/
  crypto: introduce generic cipher API & built-in implementation
  crypto: add a gcrypt cipher implementation
  crypto: add a nettle cipher implementation
  block: convert quorum blockdrv to use crypto APIs
  ui: convert VNC websockets to use crypto APIs
  block: convert qcow/qcow2 to use generic cipher API
  ui: convert VNC to use generic cipher API

 MAINTAINERS                           |   7 +
 Makefile.objs                         |   1 +
 block/Makefile.objs                   |   2 +-
 block/qcow.c                          | 102 ++++++---
 block/qcow2-cluster.c                 |  46 +++-
 block/qcow2.c                         |  96 ++++----
 block/qcow2.h                         |  13 +-
 block/quorum.c                        |  41 ++--
 configure                             | 162 +++++++++-----
 crypto/Makefile.objs                  |   5 +
 {util => crypto}/aes.c                |   2 +-
 crypto/cipher-builtin.c               | 398 ++++++++++++++++++++++++++++++++++
 crypto/cipher-gcrypt.c                | 195 +++++++++++++++++
 crypto/cipher-nettle.c                | 206 ++++++++++++++++++
 crypto/cipher.c                       |  71 ++++++
 ui/d3des.c => crypto/desrfb.c         |   2 +-
 crypto/hash.c                         | 200 +++++++++++++++++
 crypto/init.c                         | 150 +++++++++++++
 include/{qemu => crypto}/aes.h        |   0
 include/crypto/cipher.h               | 210 ++++++++++++++++++
 ui/d3des.h => include/crypto/desrfb.h |   0
 include/crypto/hash.h                 | 189 ++++++++++++++++
 include/crypto/init.h                 |  29 +++
 target-arm/crypto_helper.c            |   2 +-
 target-i386/fpu_helper.c              |   1 -
 target-i386/ops_sse.h                 |   2 +-
 target-ppc/int_helper.c               |   2 +-
 tests/.gitignore                      |   2 +
 tests/Makefile                        |   4 +
 tests/test-crypto-cipher.c            | 290 +++++++++++++++++++++++++
 tests/test-crypto-hash.c              | 209 ++++++++++++++++++
 ui/Makefile.objs                      |   4 +-
 ui/vnc-ws.c                           |  22 +-
 ui/vnc-ws.h                           |   2 -
 ui/vnc.c                              | 119 +++++-----
 ui/vnc.h                              |   8 -
 util/Makefile.objs                    |   2 +-
 vl.c                                  |   7 +
 38 files changed, 2538 insertions(+), 265 deletions(-)
 create mode 100644 crypto/Makefile.objs
 rename {util => crypto}/aes.c (99%)
 create mode 100644 crypto/cipher-builtin.c
 create mode 100644 crypto/cipher-gcrypt.c
 create mode 100644 crypto/cipher-nettle.c
 create mode 100644 crypto/cipher.c
 rename ui/d3des.c => crypto/desrfb.c (99%)
 create mode 100644 crypto/hash.c
 create mode 100644 crypto/init.c
 rename include/{qemu => crypto}/aes.h (100%)
 create mode 100644 include/crypto/cipher.h
 rename ui/d3des.h => include/crypto/desrfb.h (100%)
 create mode 100644 include/crypto/hash.h
 create mode 100644 include/crypto/init.h
 create mode 100644 tests/test-crypto-cipher.c
 create mode 100644 tests/test-crypto-hash.c

-- 
2.4.2

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 01/10] crypto: introduce new module for computing hash digests
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:11   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 02/10] crypto: move built-in AES implementation into crypto/ Daniel P. Berrange
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

Introduce a new crypto/ directory that will (eventually) contain
all the cryptographic related code. This initially defines a
wrapper for initializing gnutls and for computing hashes with
gnutls. The former ensures that gnutls is guaranteed to be
initialized exactly once in QEMU regardless of CLI args. The
block quorum code currently fails to initialize gnutls so it
only works by luck, if VNC server TLS is not requested. The
hash APIs avoids the need to litter the rest of the code with
preprocessor checks and simplifies callers by allocating the
correct amount of memory for the requested hash.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 MAINTAINERS              |   7 ++
 Makefile.objs            |   1 +
 configure                |  46 +++++++++++
 crypto/Makefile.objs     |   2 +
 crypto/hash.c            | 200 +++++++++++++++++++++++++++++++++++++++++++++
 crypto/init.c            |  60 ++++++++++++++
 include/crypto/hash.h    | 189 ++++++++++++++++++++++++++++++++++++++++++
 include/crypto/init.h    |  29 +++++++
 tests/.gitignore         |   1 +
 tests/Makefile           |   2 +
 tests/test-crypto-hash.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
 vl.c                     |   7 ++
 12 files changed, 753 insertions(+)
 create mode 100644 crypto/Makefile.objs
 create mode 100644 crypto/hash.c
 create mode 100644 crypto/init.c
 create mode 100644 include/crypto/hash.h
 create mode 100644 include/crypto/init.h
 create mode 100644 tests/test-crypto-hash.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0f801e0..2827d08 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1033,6 +1033,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
diff --git a/Makefile.objs b/Makefile.objs
index 4881d2c..f094eff 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -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
diff --git a/configure b/configure
index 222694f..a85917c 100755
--- a/configure
+++ b/configure
@@ -329,6 +329,8 @@ glusterfs_zerofill="no"
 archipelago="no"
 gtk=""
 gtkabi=""
+gnutls=""
+gnutls_hash=""
 vte=""
 tpm="yes"
 libssh2=""
@@ -1113,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"
@@ -1294,6 +1300,8 @@ Advanced options (experts only):
   --disable-gtk            disable gtk UI
   --enable-gtk             enable gtk UI
   --with-gtkabi            select preferred GTK ABI 2.0 or 3.0
+  --disable-gnutls         disable gnutls crypto features
+  --enable-gnutls          enable gnutls crypto features
   --disable-virtfs         disable VirtFS
   --enable-virtfs          enable VirtFS
   --disable-vnc            disable VNC
@@ -2157,6 +2165,36 @@ if test "$gtk" != "no"; then
     fi
 fi
 
+
+##########################################
+# GNUTLS probe
+
+if test "$gnutls" != "no"; then
+    if $pkg_config --exists "gnutls"; then
+        gnutls_cflags=`$pkg_config --cflags gnutls`
+        gnutls_libs=`$pkg_config --libs gnutls`
+        libs_softmmu="$gnutls_libs $libs_softmmu"
+        libs_tools="$gnutls_libs $libs_tools"
+	QEMU_CFLAGS="$QEMU_CFLAGS $gnutls_cflags"
+        gnutls="yes"
+
+	# gnutls_hash_init requires >= 2.9.10
+	if $pkg_config --exists "gnutls >= 2.9.10"; then
+            gnutls_hash="yes"
+	else
+	    gnutls_hash="no"
+	fi
+    elif test "$gnutls" = "yes"; then
+	feature_not_found "gnutls" "Install gnutls devel"
+    else
+        gnutls="no"
+        gnutls_hash="no"
+    fi
+else
+    gnutls_hash="no"
+fi
+
+
 ##########################################
 # VTE probe
 
@@ -4416,6 +4454,8 @@ fi
 echo "pixman            $pixman"
 echo "SDL support       $sdl"
 echo "GTK support       $gtk"
+echo "GNUTLS support    $gnutls"
+echo "GNUTLS hash       $gnutls_hash"
 echo "VTE support       $vte"
 echo "curses support    $curses"
 echo "curl support      $curl"
@@ -4765,6 +4805,12 @@ if test "$gtk" = "yes" ; then
   echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
   echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
 fi
+if test "$gnutls" = "yes" ; then
+  echo "CONFIG_GNUTLS=y" >> $config_host_mak
+fi
+if test "$gnutls_hash" = "yes" ; then
+  echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
+fi
 if test "$vte" = "yes" ; then
   echo "CONFIG_VTE=y" >> $config_host_mak
   echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
new file mode 100644
index 0000000..03cc1b2
--- /dev/null
+++ b/crypto/Makefile.objs
@@ -0,0 +1,2 @@
+util-obj-y += init.o
+util-obj-y += hash.o
diff --git a/crypto/hash.c b/crypto/hash.c
new file mode 100644
index 0000000..81e74de
--- /dev/null
+++ b/crypto/hash.c
@@ -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);
+}
diff --git a/crypto/init.c b/crypto/init.c
new file mode 100644
index 0000000..40f3d6e
--- /dev/null
+++ b/crypto/init.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU Crypto initialization
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "crypto/init.h"
+
+#ifdef CONFIG_GNUTLS
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+/* #define DEBUG_GNUTLS */
+
+#ifdef DEBUG_GNUTLS
+static void qcrypto_gnutls_log(int level, const char *str)
+{
+    fprintf(stderr, "%d: %s", level, str);
+}
+#endif
+
+int qcrypto_init(Error **errp)
+{
+    int ret;
+    ret = gnutls_global_init();
+    if (ret < 0) {
+        error_setg(errp,
+                   "Unable to initialize GNUTLS library: %s",
+                   gnutls_strerror(ret));
+        return -1;
+    }
+#ifdef DEBUG_GNUTLS
+    gnutls_global_set_log_level(10);
+    gnutls_global_set_log_function(qcrypto_gnutls_log);
+#endif
+    return 0;
+}
+
+#else /* ! CONFIG_GNUTLS */
+
+int qcrypto_init(Error **errp G_GNUC_UNUSED)
+{
+    return 0;
+}
+
+#endif /* ! CONFIG_GNUTLS */
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
new file mode 100644
index 0000000..b5acbf6
--- /dev/null
+++ b/include/crypto/hash.h
@@ -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__ */
diff --git a/include/crypto/init.h b/include/crypto/init.h
new file mode 100644
index 0000000..5fc510c
--- /dev/null
+++ b/include/crypto/init.h
@@ -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__ */
diff --git a/tests/.gitignore b/tests/.gitignore
index 0dcb618..12d2373 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -9,6 +9,7 @@ rcutorture
 test-aio
 test-bitops
 test-coroutine
+test-crypto-hash
 test-cutils
 test-hbitmap
 test-int128
diff --git a/tests/Makefile b/tests/Makefile
index 4de40de..b90f632 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -72,6 +72,7 @@ check-unit-y += tests/test-qemu-opts$(EXESUF)
 gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c
 check-unit-y += tests/test-write-threshold$(EXESUF)
 gcov-files-test-write-threshold-y = block/write-threshold.c
+check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -336,6 +337,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) l
 
 tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
 tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
+tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a
 
 libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
 libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
diff --git a/tests/test-crypto-hash.c b/tests/test-crypto-hash.c
new file mode 100644
index 0000000..911437e
--- /dev/null
+++ b/tests/test-crypto-hash.c
@@ -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();
+}
diff --git a/vl.c b/vl.c
index 2201e27..8fad89d 100644
--- a/vl.c
+++ b/vl.c
@@ -119,6 +119,7 @@ int main(int argc, char **argv)
 #include "qapi/opts-visitor.h"
 #include "qom/object_interfaces.h"
 #include "qapi-event.h"
+#include "crypto/init.h"
 
 #define MAX_VIRTIO_CONSOLES 1
 #define MAX_SCLP_CONSOLES 1
@@ -2847,6 +2848,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();
@@ -2890,6 +2892,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);
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 02/10] crypto: move built-in AES implementation into crypto/
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 01/10] crypto: introduce new module for computing hash digests Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:11   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 03/10] crypto: move built-in D3DES " Daniel P. Berrange
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

To prepare for a generic internal cipher API, move the
built-in AES implementation into the crypto/ directory

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 block/qcow.c                   | 2 +-
 block/qcow2.c                  | 1 -
 block/qcow2.h                  | 2 +-
 crypto/Makefile.objs           | 1 +
 {util => crypto}/aes.c         | 2 +-
 include/{qemu => crypto}/aes.h | 0
 target-arm/crypto_helper.c     | 2 +-
 target-i386/fpu_helper.c       | 1 -
 target-i386/ops_sse.h          | 2 +-
 target-ppc/int_helper.c        | 2 +-
 util/Makefile.objs             | 2 +-
 11 files changed, 8 insertions(+), 9 deletions(-)
 rename {util => crypto}/aes.c (99%)
 rename include/{qemu => crypto}/aes.h (100%)

diff --git a/block/qcow.c b/block/qcow.c
index 911e59f..5a7c6cb 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -25,7 +25,7 @@
 #include "block/block_int.h"
 #include "qemu/module.h"
 #include <zlib.h>
-#include "qemu/aes.h"
+#include "crypto/aes.h"
 #include "migration/migration.h"
 
 /**************************************************************/
diff --git a/block/qcow2.c b/block/qcow2.c
index c4f6938..e9e3fa5 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -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"
diff --git a/block/qcow2.h b/block/qcow2.h
index 5936d29..462147c 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -25,7 +25,7 @@
 #ifndef BLOCK_QCOW2_H
 #define BLOCK_QCOW2_H
 
-#include "qemu/aes.h"
+#include "crypto/aes.h"
 #include "block/coroutine.h"
 
 //#define DEBUG_ALLOC
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 03cc1b2..9efc9b4 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -1,2 +1,3 @@
 util-obj-y += init.o
 util-obj-y += hash.o
+util-obj-y += aes.o
diff --git a/util/aes.c b/crypto/aes.c
similarity index 99%
rename from util/aes.c
rename to crypto/aes.c
index 3d7c4be..244a388 100644
--- a/util/aes.c
+++ b/crypto/aes.c
@@ -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;
diff --git a/include/qemu/aes.h b/include/crypto/aes.h
similarity index 100%
rename from include/qemu/aes.h
rename to include/crypto/aes.h
diff --git a/target-arm/crypto_helper.c b/target-arm/crypto_helper.c
index 1fe975d..5d22838 100644
--- a/target-arm/crypto_helper.c
+++ b/target-arm/crypto_helper.c
@@ -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];
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 30d34d5..280adba 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -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"
 
diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h
index 0765073..bee134b 100644
--- a/target-i386/ops_sse.h
+++ b/target-i386/ops_sse.h
@@ -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
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 4c2b71c..0a55d5e 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -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"
 /*****************************************************************************/
diff --git a/util/Makefile.objs b/util/Makefile.objs
index ceaba30..114d657 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -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
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 03/10] crypto: move built-in D3DES implementation into crypto/
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 01/10] crypto: introduce new module for computing hash digests Daniel P. Berrange
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 02/10] crypto: move built-in AES implementation into crypto/ Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:12   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 04/10] crypto: introduce generic cipher API & built-in implementation Daniel P. Berrange
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

To prepare for a generic internal cipher API, move the
built-in D3DES implementation into the crypto/ directory.

This is not in fact a normal D3DES implementation, it is
D3DES with double & triple length modes removed, and the
key bytes in reversed bit order. IOW it is crippled
specifically for the "benefit" of RFB, so call the new
files desrfb.c instead of d3des.c to make it clear that
it isn't a generally useful impl.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 crypto/Makefile.objs                  | 1 +
 ui/d3des.c => crypto/desrfb.c         | 2 +-
 ui/d3des.h => include/crypto/desrfb.h | 0
 ui/Makefile.objs                      | 2 +-
 ui/vnc.c                              | 2 +-
 5 files changed, 4 insertions(+), 3 deletions(-)
 rename ui/d3des.c => crypto/desrfb.c (99%)
 rename ui/d3des.h => include/crypto/desrfb.h (100%)

diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 9efc9b4..9f70294 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -1,3 +1,4 @@
 util-obj-y += init.o
 util-obj-y += hash.o
 util-obj-y += aes.o
+util-obj-y += desrfb.o
diff --git a/ui/d3des.c b/crypto/desrfb.c
similarity index 99%
rename from ui/d3des.c
rename to crypto/desrfb.c
index 5bc99b8..fc20a30 100644
--- a/ui/d3des.c
+++ b/crypto/desrfb.c
@@ -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 *);
diff --git a/ui/d3des.h b/include/crypto/desrfb.h
similarity index 100%
rename from ui/d3des.h
rename to include/crypto/desrfb.h
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 023914c..dd1f8e4 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -1,4 +1,4 @@
-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
diff --git a/ui/vnc.c b/ui/vnc.c
index 69b605c..d86f9c2 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -46,7 +46,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/desrfb.h"
 
 static QTAILQ_HEAD(, VncDisplay) vnc_displays =
     QTAILQ_HEAD_INITIALIZER(vnc_displays);
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 04/10] crypto: introduce generic cipher API & built-in implementation
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
                   ` (2 preceding siblings ...)
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 03/10] crypto: move built-in D3DES " Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:15   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 05/10] crypto: add a gcrypt cipher implementation Daniel P. Berrange
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

Introduce a generic cipher API and an implementation of it that
supports only the built-in AES and DES-RFB algorithms.

The test suite checks the supported algorithms + modes to
validate that every backend implementation is actually correctly
complying with the specs.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 crypto/Makefile.objs       |   1 +
 crypto/cipher-builtin.c    | 398 +++++++++++++++++++++++++++++++++++++++++++++
 crypto/cipher.c            |  50 ++++++
 include/crypto/cipher.h    | 210 ++++++++++++++++++++++++
 tests/.gitignore           |   1 +
 tests/Makefile             |   2 +
 tests/test-crypto-cipher.c | 290 +++++++++++++++++++++++++++++++++
 7 files changed, 952 insertions(+)
 create mode 100644 crypto/cipher-builtin.c
 create mode 100644 crypto/cipher.c
 create mode 100644 include/crypto/cipher.h
 create mode 100644 tests/test-crypto-cipher.c

diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 9f70294..b050138 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -2,3 +2,4 @@ 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
diff --git a/crypto/cipher-builtin.c b/crypto/cipher-builtin.c
new file mode 100644
index 0000000..c625cb4
--- /dev/null
+++ b/crypto/cipher-builtin.c
@@ -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);
+}
diff --git a/crypto/cipher.c b/crypto/cipher.c
new file mode 100644
index 0000000..8b05de8
--- /dev/null
+++ b/crypto/cipher.c
@@ -0,0 +1,50 @@
+/*
+ * 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-internal.h"
+
+#include "crypto/cipher-builtin.c"
+
+
+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,
+};
+
+bool qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
+                                        size_t nkey,
+                                        Error **errp)
+{
+    if (alg < 0 ||
+        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;
+}
diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h
new file mode 100644
index 0000000..b4d714f
--- /dev/null
+++ b/include/crypto/cipher.h
@@ -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__ */
diff --git a/tests/.gitignore b/tests/.gitignore
index 12d2373..e93148e 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -9,6 +9,7 @@ rcutorture
 test-aio
 test-bitops
 test-coroutine
+test-crypto-cipher
 test-crypto-hash
 test-cutils
 test-hbitmap
diff --git a/tests/Makefile b/tests/Makefile
index b90f632..29a2eeb 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -73,6 +73,7 @@ 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
 
@@ -338,6 +339,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) l
 tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
 tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
 tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a
+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
diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c
new file mode 100644
index 0000000..f9b1a03
--- /dev/null
+++ b/tests/test-crypto-cipher.c
@@ -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();
+}
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 05/10] crypto: add a gcrypt cipher implementation
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
                   ` (3 preceding siblings ...)
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 04/10] crypto: introduce generic cipher API & built-in implementation Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 06/10] crypto: add a nettle " Daniel P. Berrange
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

If we are linking to gnutls already and gnutls is built against
gcrypt, then we should use gcrypt as a cipher backend in
preference to our built-in backend.

This will be used when linking against GNUTLS 1.x and many
GNUTLS 2.x versions.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 configure              |  29 ++++++++
 crypto/cipher-gcrypt.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++
 crypto/cipher.c        |  19 +++++
 crypto/init.c          |  90 +++++++++++++++++++++++
 4 files changed, 333 insertions(+)
 create mode 100644 crypto/cipher-gcrypt.c

diff --git a/configure b/configure
index a85917c..28f4172 100755
--- a/configure
+++ b/configure
@@ -2169,6 +2169,7 @@ fi
 ##########################################
 # GNUTLS probe
 
+gnutls_gcrypt=no
 if test "$gnutls" != "no"; then
     if $pkg_config --exists "gnutls"; then
         gnutls_cflags=`$pkg_config --cflags gnutls`
@@ -2184,6 +2185,18 @@ if test "$gnutls" != "no"; then
 	else
 	    gnutls_hash="no"
 	fi
+
+	if $pkg_config --exists 'gnutls >= 3.0'; then
+	    gnutls_gcrypt=no
+	elif $pkg_config --exists 'gnutls >= 2.12'; then
+	    case `$pkg_config --libs --static gnutls` in
+		*gcrypt*) gnutls_gcrypt=yes     ;;
+		*nettle*) gnutls_gcrypt=no      ;;
+		*)        gnutls_gcrypt=yes     ;;
+	    esac
+	else
+	    gnutls_gcrypt=yes
+	fi
     elif test "$gnutls" = "yes"; then
 	feature_not_found "gnutls" "Install gnutls devel"
     else
@@ -2194,6 +2207,18 @@ 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
+
 
 ##########################################
 # VTE probe
@@ -4456,6 +4481,7 @@ echo "SDL support       $sdl"
 echo "GTK support       $gtk"
 echo "GNUTLS support    $gnutls"
 echo "GNUTLS hash       $gnutls_hash"
+echo "GNUTLS gcrypt     $gnutls_gcrypt"
 echo "VTE support       $vte"
 echo "curses support    $curses"
 echo "curl support      $curl"
@@ -4811,6 +4837,9 @@ 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 "$vte" = "yes" ; then
   echo "CONFIG_VTE=y" >> $config_host_mak
   echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c
new file mode 100644
index 0000000..8cfc562
--- /dev/null
+++ b/crypto/cipher-gcrypt.c
@@ -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;
+}
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 8b05de8..02bcda3 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -20,7 +20,11 @@
 
 #include "crypto/cipher-internal.h"
 
+#ifdef CONFIG_GNUTLS_GCRYPT
+#include "crypto/cipher-gcrypt.c"
+#else
 #include "crypto/cipher-builtin.c"
+#endif
 
 
 static size_t alg_key_len[QCRYPTO_CIPHER_ALG_LAST] = {
@@ -48,3 +52,18 @@ bool qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
     }
     return true;
 }
+
+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;
+}
diff --git a/crypto/init.c b/crypto/init.c
index 40f3d6e..7447882 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -19,13 +19,48 @@
  */
 
 #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)
 {
@@ -33,6 +68,49 @@ static void qcrypto_gnutls_log(int level, const char *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;
@@ -47,6 +125,18 @@ int qcrypto_init(Error **errp)
     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;
 }
 
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 06/10] crypto: add a nettle cipher implementation
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
                   ` (4 preceding siblings ...)
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 05/10] crypto: add a gcrypt cipher implementation Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:17   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 07/10] block: convert quorum blockdrv to use crypto APIs Daniel P. Berrange
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

If we are linking to gnutls already and gnutls is built against
nettle, then we should use nettle as a cipher backend in
preference to our built-in backend.

This will be used when linking against some GNUTLS 2.x versions
and all GNUTLS 3.x versions.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 configure              |  35 ++++++++-
 crypto/cipher-nettle.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++
 crypto/cipher.c        |   2 +
 3 files changed, 240 insertions(+), 3 deletions(-)
 create mode 100644 crypto/cipher-nettle.c

diff --git a/configure b/configure
index 28f4172..6749a85 100755
--- a/configure
+++ b/configure
@@ -2170,6 +2170,7 @@ 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`
@@ -2188,14 +2189,25 @@ if test "$gnutls" != "no"; then
 
 	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     ;;
-		*nettle*) gnutls_gcrypt=no      ;;
-		*)        gnutls_gcrypt=yes     ;;
+		*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"
@@ -2220,6 +2232,19 @@ if test "$gnutls_gcrypt" != "no"; then
 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
 
@@ -4482,6 +4507,7 @@ 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"
@@ -4840,6 +4866,9 @@ 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
diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c
new file mode 100644
index 0000000..e5a14bc
--- /dev/null
+++ b/crypto/cipher-nettle.c
@@ -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;
+}
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 02bcda3..6327aa3 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -22,6 +22,8 @@
 
 #ifdef CONFIG_GNUTLS_GCRYPT
 #include "crypto/cipher-gcrypt.c"
+#elif CONFIG_GNUTLS_NETTLE
+#include "crypto/cipher-nettle.c"
 #else
 #include "crypto/cipher-builtin.c"
 #endif
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 07/10] block: convert quorum blockdrv to use crypto APIs
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
                   ` (5 preceding siblings ...)
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 06/10] crypto: add a nettle " Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:17   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 08/10] ui: convert VNC websockets " Daniel P. Berrange
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

Get rid of direct use of gnutls APIs in quorum blockdrv in
favour of using the crypto APIs. This avoids the need to
do conditional compilation of the quorum driver. It can
simply report an error at file open file instead if the
required hash algorithm isn't supported by QEMU.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 block/Makefile.objs |  2 +-
 block/quorum.c      | 41 ++++++++++++++++++++++-------------------
 configure           | 39 ---------------------------------------
 3 files changed, 23 insertions(+), 59 deletions(-)

diff --git a/block/Makefile.objs b/block/Makefile.objs
index c34fd7c..58ef2ef 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -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
diff --git a/block/quorum.c b/block/quorum.c
index 77e55b2..4d58aff 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -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"
@@ -23,6 +21,9 @@
 #include "qapi/qmp/qlist.h"
 #include "qapi/qmp/qstring.h"
 #include "qapi-event.h"
+#include "crypto/hash.h"
+
+#include <glib/gi18n.h>
 
 #define HASH_LENGTH 32
 
@@ -33,7 +34,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;
 
@@ -427,25 +428,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;
-
-    ret = gnutls_hash_init(&dig, GNUTLS_DIG_SHA256);
-
-    if (ret < 0) {
-        return ret;
+    size_t len = sizeof(hash->h);
+    uint8_t *data = hash->h;
+
+    /* 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)
@@ -869,6 +866,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 */
diff --git a/configure b/configure
index 6749a85..7d1daa8 100755
--- a/configure
+++ b/configure
@@ -335,7 +335,6 @@ vte=""
 tpm="yes"
 libssh2=""
 vhdx=""
-quorum=""
 numa=""
 tcmalloc="no"
 
@@ -1141,10 +1140,6 @@ for opt do
   ;;
   --disable-vhdx) vhdx="no"
   ;;
-  --disable-quorum) quorum="no"
-  ;;
-  --enable-quorum) quorum="yes"
-  ;;
   --disable-numa) numa="no"
   ;;
   --enable-numa) numa="yes"
@@ -1422,8 +1417,6 @@ Advanced options (experts only):
   --enable-libssh2         enable ssh block device support
   --disable-vhdx           disable support for the Microsoft VHDX image format
   --enable-vhdx            enable support for the Microsoft VHDX image format
-  --disable-quorum         disable quorum block filter support
-  --enable-quorum          enable quorum block filter support
   --disable-numa           disable libnuma support
   --enable-numa            enable libnuma support
   --disable-tcmalloc       disable tcmalloc support
@@ -2421,33 +2414,6 @@ EOF
 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
   cat > $TMPC <<EOF
@@ -4585,7 +4551,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"
@@ -5058,10 +5023,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
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 08/10] ui: convert VNC websockets to use crypto APIs
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
                   ` (6 preceding siblings ...)
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 07/10] block: convert quorum blockdrv to use crypto APIs Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:18   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 09/10] block: convert qcow/qcow2 to use generic cipher API Daniel P. Berrange
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 10/10] ui: convert VNC " Daniel P. Berrange
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

Remove the direct use of gnutls for hash processing in the
websockets code, in favour of using the crypto APIs. This
allows the websockets code to be built unconditionally
removing countless conditional checks from the VNC code.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 configure        | 19 +---------------
 ui/Makefile.objs |  2 +-
 ui/vnc-ws.c      | 22 +++++++++----------
 ui/vnc-ws.h      |  2 --
 ui/vnc.c         | 67 +++++++++++---------------------------------------------
 ui/vnc.h         |  8 -------
 6 files changed, 25 insertions(+), 95 deletions(-)

diff --git a/configure b/configure
index 7d1daa8..371c676 100755
--- a/configure
+++ b/configure
@@ -246,7 +246,6 @@ vnc_tls=""
 vnc_sasl=""
 vnc_jpeg=""
 vnc_png=""
-vnc_ws=""
 xen=""
 xen_ctrl_version=""
 xen_pci_passthrough=""
@@ -895,10 +894,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"
@@ -2385,7 +2380,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; }
@@ -2396,20 +2391,13 @@ 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
 
@@ -4488,7 +4476,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"
@@ -4691,10 +4678,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
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index dd1f8e4..c62d4d9 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -4,7 +4,7 @@ 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
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index 8c18268..b4cb6bd 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -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;
     }
diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h
index 14d4230..9494225 100644
--- a/ui/vnc-ws.h
+++ b/ui/vnc-ws.h
@@ -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
 
diff --git a/ui/vnc.c b/ui/vnc.c
index d86f9c2..76bf2aa 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -38,6 +38,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
@@ -353,9 +354,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) {
@@ -580,12 +579,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;
@@ -1229,10 +1226,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);
 
@@ -1411,12 +1406,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);
         }
     }
@@ -1427,11 +1419,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);
@@ -1537,7 +1525,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) {
@@ -1547,10 +1534,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)
@@ -1622,11 +1607,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);
@@ -3017,7 +2999,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
@@ -3029,7 +3010,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);
     }
@@ -3038,10 +3018,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);
     }
 
@@ -3097,12 +3074,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);
     }
 
@@ -3117,12 +3091,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",
@@ -3148,9 +3120,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;
@@ -3184,14 +3154,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
@@ -3577,13 +3545,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
@@ -3666,9 +3633,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 {
@@ -3691,7 +3656,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) {
@@ -3702,16 +3666,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);
@@ -3721,9 +3682,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)
diff --git a/ui/vnc.h b/ui/vnc.h
index 3f7c6a9..814d720 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -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;
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 09/10] block: convert qcow/qcow2 to use generic cipher API
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
                   ` (7 preceding siblings ...)
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 08/10] ui: convert VNC websockets " Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:18   ` Gonglei
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 10/10] ui: convert VNC " Daniel P. Berrange
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

Switch the qcow/qcow2 block driver over to use the generic cipher
API, this allows it to use the pluggable AES implementations,
instead of being hardcoded to use QEMU's built-in impl.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 block/qcow.c          | 102 +++++++++++++++++++++++++++++++++++++-------------
 block/qcow2-cluster.c |  46 ++++++++++++++++++-----
 block/qcow2.c         |  95 +++++++++++++++++++++++-----------------------
 block/qcow2.h         |  13 +++----
 4 files changed, 165 insertions(+), 91 deletions(-)

diff --git a/block/qcow.c b/block/qcow.c
index 5a7c6cb..1e5179a 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -25,7 +25,7 @@
 #include "block/block_int.h"
 #include "qemu/module.h"
 #include <zlib.h>
-#include "crypto/aes.h"
+#include "crypto/cipher.h"
 #include "migration/migration.h"
 
 /**************************************************************/
@@ -71,10 +71,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;
@@ -153,6 +151,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;
@@ -259,6 +262,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);
@@ -270,38 +274,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:
@@ -415,15 +448,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;
@@ -463,7 +501,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);
@@ -530,6 +568,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);
@@ -593,10 +632,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;
@@ -617,6 +657,7 @@ done:
     return ret;
 
 fail:
+    error_free(err);
     ret = -EIO;
     goto done;
 }
@@ -665,12 +706,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;
@@ -707,6 +753,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);
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 1a5c97a..b43f186 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -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,
diff --git a/block/qcow2.c b/block/qcow2.c
index e9e3fa5..7e14bcd 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -698,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;
@@ -1031,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);
@@ -1042,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)
-        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;
-#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;
 }
 
@@ -1108,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;
@@ -1158,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);
         }
@@ -1230,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
@@ -1263,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);
             }
@@ -1343,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
@@ -1358,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,
@@ -1465,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);
 
@@ -1481,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;
@@ -1493,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);
 
@@ -1523,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,
@@ -2728,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;
diff --git a/block/qcow2.h b/block/qcow2.h
index 462147c..72e1328 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -25,7 +25,7 @@
 #ifndef BLOCK_QCOW2_H
 #define BLOCK_QCOW2_H
 
-#include "crypto/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);
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v3 10/10] ui: convert VNC to use generic cipher API
  2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
                   ` (8 preceding siblings ...)
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 09/10] block: convert qcow/qcow2 to use generic cipher API Daniel P. Berrange
@ 2015-06-18 17:02 ` Daniel P. Berrange
  2015-06-23  2:26   ` Gonglei
  9 siblings, 1 reply; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-18 17:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Gonglei, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

Switch the VNC server over to use the generic cipher API, this
allows it to use the pluggable DES implementations, instead of
being hardcoded to use QEMU's built-in impl.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 ui/vnc.c | 52 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/ui/vnc.c b/ui/vnc.c
index 76bf2aa..7d6f702 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -47,7 +47,7 @@ static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
 static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
 
 #include "vnc_keysym.h"
-#include "crypto/desrfb.h"
+#include "crypto/cipher.h"
 
 static QTAILQ_HEAD(, VncDisplay) vnc_displays =
     QTAILQ_HEAD_INITIALIZER(vnc_displays);
@@ -2515,9 +2515,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");
@@ -2534,9 +2536,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) {
@@ -3482,12 +3504,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);
-- 
2.4.2

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/10] crypto: introduce new module for computing hash digests
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 01/10] crypto: introduce new module for computing hash digests Daniel P. Berrange
@ 2015-06-23  2:11   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:11 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> Introduce a new crypto/ directory that will (eventually) contain
> all the cryptographic related code. This initially defines a
> wrapper for initializing gnutls and for computing hashes with
> gnutls. The former ensures that gnutls is guaranteed to be
> initialized exactly once in QEMU regardless of CLI args. The
> block quorum code currently fails to initialize gnutls so it
> only works by luck, if VNC server TLS is not requested. The
> hash APIs avoids the need to litter the rest of the code with
> preprocessor checks and simplifies callers by allocating the
> correct amount of memory for the requested hash.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  MAINTAINERS              |   7 ++
>  Makefile.objs            |   1 +
>  configure                |  46 +++++++++++
>  crypto/Makefile.objs     |   2 +
>  crypto/hash.c            | 200 +++++++++++++++++++++++++++++++++++++++++++++
>  crypto/init.c            |  60 ++++++++++++++
>  include/crypto/hash.h    | 189 ++++++++++++++++++++++++++++++++++++++++++
>  include/crypto/init.h    |  29 +++++++
>  tests/.gitignore         |   1 +
>  tests/Makefile           |   2 +
>  tests/test-crypto-hash.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
>  vl.c                     |   7 ++
>  12 files changed, 753 insertions(+)
>  create mode 100644 crypto/Makefile.objs
>  create mode 100644 crypto/hash.c
>  create mode 100644 crypto/init.c
>  create mode 100644 include/crypto/hash.h
>  create mode 100644 include/crypto/init.h
>  create mode 100644 tests/test-crypto-hash.c

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 02/10] crypto: move built-in AES implementation into crypto/
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 02/10] crypto: move built-in AES implementation into crypto/ Daniel P. Berrange
@ 2015-06-23  2:11   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:11 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> To prepare for a generic internal cipher API, move the
> built-in AES implementation into the crypto/ directory
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  block/qcow.c                   | 2 +-
>  block/qcow2.c                  | 1 -
>  block/qcow2.h                  | 2 +-
>  crypto/Makefile.objs           | 1 +
>  {util => crypto}/aes.c         | 2 +-
>  include/{qemu => crypto}/aes.h | 0
>  target-arm/crypto_helper.c     | 2 +-
>  target-i386/fpu_helper.c       | 1 -
>  target-i386/ops_sse.h          | 2 +-
>  target-ppc/int_helper.c        | 2 +-
>  util/Makefile.objs             | 2 +-
>  11 files changed, 8 insertions(+), 9 deletions(-)
>  rename {util => crypto}/aes.c (99%)
>  rename include/{qemu => crypto}/aes.h (100%)

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/10] crypto: move built-in D3DES implementation into crypto/
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 03/10] crypto: move built-in D3DES " Daniel P. Berrange
@ 2015-06-23  2:12   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:12 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> To prepare for a generic internal cipher API, move the
> built-in D3DES implementation into the crypto/ directory.
> 
> This is not in fact a normal D3DES implementation, it is
> D3DES with double & triple length modes removed, and the
> key bytes in reversed bit order. IOW it is crippled
> specifically for the "benefit" of RFB, so call the new
> files desrfb.c instead of d3des.c to make it clear that
> it isn't a generally useful impl.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  crypto/Makefile.objs                  | 1 +
>  ui/d3des.c => crypto/desrfb.c         | 2 +-
>  ui/d3des.h => include/crypto/desrfb.h | 0
>  ui/Makefile.objs                      | 2 +-
>  ui/vnc.c                              | 2 +-
>  5 files changed, 4 insertions(+), 3 deletions(-)
>  rename ui/d3des.c => crypto/desrfb.c (99%)
>  rename ui/d3des.h => include/crypto/desrfb.h (100%)

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/10] crypto: introduce generic cipher API & built-in implementation
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 04/10] crypto: introduce generic cipher API & built-in implementation Daniel P. Berrange
@ 2015-06-23  2:15   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:15 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> Introduce a generic cipher API and an implementation of it that
> supports only the built-in AES and DES-RFB algorithms.
> 
> The test suite checks the supported algorithms + modes to
> validate that every backend implementation is actually correctly
> complying with the specs.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  crypto/Makefile.objs       |   1 +
>  crypto/cipher-builtin.c    | 398 +++++++++++++++++++++++++++++++++++++++++++++
>  crypto/cipher.c            |  50 ++++++
>  include/crypto/cipher.h    | 210 ++++++++++++++++++++++++
>  tests/.gitignore           |   1 +
>  tests/Makefile             |   2 +
>  tests/test-crypto-cipher.c | 290 +++++++++++++++++++++++++++++++++
>  7 files changed, 952 insertions(+)
>  create mode 100644 crypto/cipher-builtin.c
>  create mode 100644 crypto/cipher.c
>  create mode 100644 include/crypto/cipher.h
>  create mode 100644 tests/test-crypto-cipher.c

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/10] crypto: add a nettle cipher implementation
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 06/10] crypto: add a nettle " Daniel P. Berrange
@ 2015-06-23  2:17   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:17 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> If we are linking to gnutls already and gnutls is built against
> nettle, then we should use nettle as a cipher backend in
> preference to our built-in backend.
> 
> This will be used when linking against some GNUTLS 2.x versions
> and all GNUTLS 3.x versions.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  configure              |  35 ++++++++-
>  crypto/cipher-nettle.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++
>  crypto/cipher.c        |   2 +
>  3 files changed, 240 insertions(+), 3 deletions(-)
>  create mode 100644 crypto/cipher-nettle.c

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/10] block: convert quorum blockdrv to use crypto APIs
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 07/10] block: convert quorum blockdrv to use crypto APIs Daniel P. Berrange
@ 2015-06-23  2:17   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:17 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> Get rid of direct use of gnutls APIs in quorum blockdrv in
> favour of using the crypto APIs. This avoids the need to
> do conditional compilation of the quorum driver. It can
> simply report an error at file open file instead if the
> required hash algorithm isn't supported by QEMU.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  block/Makefile.objs |  2 +-
>  block/quorum.c      | 41 ++++++++++++++++++++++-------------------
>  configure           | 39 ---------------------------------------
>  3 files changed, 23 insertions(+), 59 deletions(-)

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/10] ui: convert VNC websockets to use crypto APIs
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 08/10] ui: convert VNC websockets " Daniel P. Berrange
@ 2015-06-23  2:18   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:18 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> Remove the direct use of gnutls for hash processing in the
> websockets code, in favour of using the crypto APIs. This
> allows the websockets code to be built unconditionally
> removing countless conditional checks from the VNC code.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  configure        | 19 +---------------
>  ui/Makefile.objs |  2 +-
>  ui/vnc-ws.c      | 22 +++++++++----------
>  ui/vnc-ws.h      |  2 --
>  ui/vnc.c         | 67 +++++++++++---------------------------------------------
>  ui/vnc.h         |  8 -------
>  6 files changed, 25 insertions(+), 95 deletions(-)

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/10] block: convert qcow/qcow2 to use generic cipher API
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 09/10] block: convert qcow/qcow2 to use generic cipher API Daniel P. Berrange
@ 2015-06-23  2:18   ` Gonglei
  0 siblings, 0 replies; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:18 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
> Switch the qcow/qcow2 block driver over to use the generic cipher
> API, this allows it to use the pluggable AES implementations,
> instead of being hardcoded to use QEMU's built-in impl.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  block/qcow.c          | 102 +++++++++++++++++++++++++++++++++++++-------------
>  block/qcow2-cluster.c |  46 ++++++++++++++++++-----
>  block/qcow2.c         |  95 +++++++++++++++++++++++-----------------------
>  block/qcow2.h         |  13 +++----
>  4 files changed, 165 insertions(+), 91 deletions(-)

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/10] ui: convert VNC to use generic cipher API
  2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 10/10] ui: convert VNC " Daniel P. Berrange
@ 2015-06-23  2:26   ` Gonglei
  2015-06-23  8:48     ` Daniel P. Berrange
  0 siblings, 1 reply; 21+ messages in thread
From: Gonglei @ 2015-06-23  2:26 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Gerd Hoffmann, Richard Henderson

On 2015/6/19 1:02, Daniel P. Berrange wrote:
>      if (!vs->vd->password) {
>          VNC_DEBUG("No password configured on server");
> @@ -2534,9 +2536,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;
> +    }

Do we need change above VNC_DEBUGs to error_report() or something like that?
Anyway, it doesn't influence my R-b:
	Reviewed-by: Gonglei <arei.gonglei@huawei.com>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/10] ui: convert VNC to use generic cipher API
  2015-06-23  2:26   ` Gonglei
@ 2015-06-23  8:48     ` Daniel P. Berrange
  0 siblings, 0 replies; 21+ messages in thread
From: Daniel P. Berrange @ 2015-06-23  8:48 UTC (permalink / raw)
  To: Gonglei
  Cc: Kevin Wolf, qemu-devel, Gerd Hoffmann, Paolo Bonzini, Richard Henderson

On Tue, Jun 23, 2015 at 10:26:50AM +0800, Gonglei wrote:
> On 2015/6/19 1:02, Daniel P. Berrange wrote:
> >      if (!vs->vd->password) {
> >          VNC_DEBUG("No password configured on server");
> > @@ -2534,9 +2536,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;
> > +    }
> 
> Do we need change above VNC_DEBUGs to error_report() or something like that?

In general, yes, the VNC code doesn't really handle error reporting very
well today.

> Anyway, it doesn't influence my R-b:
> 	Reviewed-by: Gonglei <arei.gonglei@huawei.com>

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2015-06-23  8:48 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-18 17:02 [Qemu-devel] [PATCH v3 00/10] Consolidate crypto APIs & implementations Daniel P. Berrange
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 01/10] crypto: introduce new module for computing hash digests Daniel P. Berrange
2015-06-23  2:11   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 02/10] crypto: move built-in AES implementation into crypto/ Daniel P. Berrange
2015-06-23  2:11   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 03/10] crypto: move built-in D3DES " Daniel P. Berrange
2015-06-23  2:12   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 04/10] crypto: introduce generic cipher API & built-in implementation Daniel P. Berrange
2015-06-23  2:15   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 05/10] crypto: add a gcrypt cipher implementation Daniel P. Berrange
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 06/10] crypto: add a nettle " Daniel P. Berrange
2015-06-23  2:17   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 07/10] block: convert quorum blockdrv to use crypto APIs Daniel P. Berrange
2015-06-23  2:17   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 08/10] ui: convert VNC websockets " Daniel P. Berrange
2015-06-23  2:18   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 09/10] block: convert qcow/qcow2 to use generic cipher API Daniel P. Berrange
2015-06-23  2:18   ` Gonglei
2015-06-18 17:02 ` [Qemu-devel] [PATCH v3 10/10] ui: convert VNC " Daniel P. Berrange
2015-06-23  2:26   ` Gonglei
2015-06-23  8:48     ` Daniel P. Berrange

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.