qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, Josh Durgin <jdurgin@redhat.com>,
	Ronnie Sahlberg <ronniesahlberg@gmail.com>,
	qemu-block@nongnu.org, Markus Armbruster <armbru@redhat.com>,
	Stefan Hajnoczi <stefanha@redhat.com>,
	Paolo Bonzini <pbonzini@redhat.com>
Subject: [Qemu-devel] [PATCH 07/17] qcow2: add a 'keyid' parameter to qcow2 options
Date: Mon, 19 Oct 2015 16:09:39 +0100	[thread overview]
Message-ID: <1445267389-21846-8-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1445267389-21846-1-git-send-email-berrange@redhat.com>

Add a 'keyid' parameter that refers to the ID of a
QCryptoSecret instance that provides the encryption key.

$QEMU \
    -object secret,id=sec0,filename=/home/berrange/encrypted.pw \
    -drive file=/home/berrange/encrypted.qcow2,keyid=sec0

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 block/qcow2.c        | 80 +++++++++++++++++++++++++++++++++++++---------------
 block/qcow2.h        |  1 +
 qapi/block-core.json |  8 ++++--
 3 files changed, 64 insertions(+), 25 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index bacc4f2..3b108b0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -34,6 +34,7 @@
 #include "qapi-event.h"
 #include "trace.h"
 #include "qemu/option_int.h"
+#include "crypto/secret.h"
 
 /*
   Differences with QCOW:
@@ -472,6 +473,11 @@ static QemuOptsList qcow2_runtime_opts = {
             .type = QEMU_OPT_NUMBER,
             .help = "Clean unused cache entries after this time (in seconds)",
         },
+        {
+            .name = QCOW2_OPT_KEY_ID,
+            .type = QEMU_OPT_STRING,
+            .help = "ID of the secret that provides the encryption key",
+        },
         { /* end of list */ }
     },
 };
@@ -589,6 +595,31 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
     }
 }
 
+static QCryptoCipher *qcow2_get_cipher_from_key(const char *key,
+                                                Error **errp)
+{
+    uint8_t keybuf[16];
+    int len, i;
+
+    memset(keybuf, 0, 16);
+    len = strlen(key);
+    if (len > 16) {
+        len = 16;
+    }
+    /* XXX: we could compress the chars to 7 bits to increase
+       entropy */
+    for (i = 0; i < len; i++) {
+        keybuf[i] = key[i];
+    }
+
+    return qcrypto_cipher_new(
+        QCRYPTO_CIPHER_ALG_AES_128,
+        QCRYPTO_CIPHER_MODE_CBC,
+        keybuf, G_N_ELEMENTS(keybuf),
+        errp);
+}
+
+
 typedef struct Qcow2ReopenState {
     Qcow2Cache *l2_table_cache;
     Qcow2Cache *refcount_block_cache;
@@ -596,6 +627,7 @@ typedef struct Qcow2ReopenState {
     int overlap_check;
     bool discard_passthrough[QCOW2_DISCARD_MAX];
     uint64_t cache_clean_interval;
+    QCryptoCipher *cipher;
 } Qcow2ReopenState;
 
 static int qcow2_update_options_prepare(BlockDriverState *bs,
@@ -611,6 +643,8 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
     int i;
     Error *local_err = NULL;
     int ret;
+    const char *keyid;
+    char *key;
 
     opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort);
     qemu_opts_absorb_qdict(opts, options, &local_err);
@@ -754,6 +788,24 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
     r->discard_passthrough[QCOW2_DISCARD_OTHER] =
         qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
 
+    keyid = qemu_opt_get(opts, QCOW2_OPT_KEY_ID);
+    if (keyid) {
+        key = qcrypto_secret_lookup_as_utf8(keyid,
+                                            errp);
+        if (!key) {
+            ret = -ENOENT;
+            goto fail;
+        }
+
+        r->cipher = qcow2_get_cipher_from_key(key,
+                                              errp);
+        g_free(key);
+        if (!r->cipher) {
+            ret = -ENOSYS;
+            goto fail;
+        }
+    }
+
     ret = 0;
 fail:
     qemu_opts_del(opts);
@@ -788,6 +840,9 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
         s->cache_clean_interval = r->cache_clean_interval;
         cache_clean_timer_init(bs, bdrv_get_aio_context(bs));
     }
+
+    qcrypto_cipher_free(s->cipher);
+    s->cipher = r->cipher;
 }
 
 static void qcow2_update_options_abort(BlockDriverState *bs,
@@ -799,6 +854,7 @@ static void qcow2_update_options_abort(BlockDriverState *bs,
     if (r->refcount_block_cache) {
         qcow2_cache_destroy(bs, r->refcount_block_cache);
     }
+    qcrypto_cipher_free(r->cipher);
 }
 
 static int qcow2_update_options(BlockDriverState *bs, QDict *options,
@@ -1202,33 +1258,11 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
 static int qcow2_set_key(BlockDriverState *bs, const char *key)
 {
     BDRVQcow2State *s = bs->opaque;
-    uint8_t keybuf[16];
-    int len, i;
-    Error *err = NULL;
 
-    memset(keybuf, 0, 16);
-    len = strlen(key);
-    if (len > 16)
-        len = 16;
-    /* XXX: we could compress the chars to 7 bits to increase
-       entropy */
-    for(i = 0;i < len;i++) {
-        keybuf[i] = key[i];
-    }
     assert(bs->encrypted);
-
     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);
-
+    s->cipher = qcow2_get_cipher_from_key(key, NULL);
     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;
diff --git a/block/qcow2.h b/block/qcow2.h
index 3512263..7e2f046 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -97,6 +97,7 @@
 #define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
 #define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"
 #define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval"
+#define QCOW2_OPT_KEY_ID "keyid"
 
 typedef struct QCowHeader {
     uint32_t magic;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 513fe93..9f0ec68 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1567,7 +1567,7 @@
 # Driver specific block device options for qcow.
 #
 # @keyid:                 #optional ID of the "secret" object providing the
-#                         AES decryption key.
+#                         AES decryption key (since 2.5)
 #
 # Since: 2.5
 ##
@@ -1611,6 +1611,9 @@
 #                         caches. The interval is in seconds. The default value
 #                         is 0 and it disables this feature (since 2.5)
 #
+# @keyid:                 #optional ID of the "secret" object providing the
+#                         AES decryption key.
+#
 # Since: 1.7
 ##
 { 'struct': 'BlockdevOptionsQcow2',
@@ -1623,7 +1626,8 @@
             '*cache-size': 'int',
             '*l2-cache-size': 'int',
             '*refcount-cache-size': 'int',
-            '*cache-clean-interval': 'int' } }
+            '*cache-clean-interval': 'int',
+            '*keyid': 'str' } }
 
 
 ##
-- 
2.4.3

  parent reply	other threads:[~2015-10-19 15:10 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-19 15:09 [Qemu-devel] [PATCH 00/17] Framework for securely passing secrets to QEMU Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 01/17] crypto: add QCryptoSecret object class for password/key handling Daniel P. Berrange
2015-10-19 15:18   ` Paolo Bonzini
2015-10-19 15:24     ` Daniel P. Berrange
2015-10-19 15:40       ` Paolo Bonzini
2015-10-19 15:46         ` Daniel P. Berrange
2015-10-19 16:12           ` Paolo Bonzini
2015-10-19 16:24             ` Daniel P. Berrange
2015-10-19 16:28               ` Paolo Bonzini
2015-10-19 16:30                 ` Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 02/17] crypto: add support for loading encrypted x509 keys Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 03/17] rbd: add support for getting password from QCryptoSecret object Daniel P. Berrange
2015-10-19 22:57   ` Josh Durgin
2015-10-20  8:35     ` Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 04/17] curl: add support for HTTP authentication parameters Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 05/17] iscsi: add support for getting CHAP password via QCryptoSecret API Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 06/17] qcow: add a 'keyid' parameter to qcow options Daniel P. Berrange
2015-10-28 13:56   ` Eric Blake
2015-10-19 15:09 ` Daniel P. Berrange [this message]
2015-10-19 23:29   ` [Qemu-devel] [PATCH 07/17] qcow2: add a 'keyid' parameter to qcow2 options Eric Blake
2015-10-28 13:58     ` Eric Blake
2015-10-19 15:09 ` [Qemu-devel] [PATCH 08/17] qom: add user_creatable_add & user_creatable_del methods Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 09/17] qemu-img: add support for --object command line arg Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 10/17] qemu-nbd: " Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 11/17] qemu-io: " Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 12/17] qemu-io: allow specifying image as a set of options args Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 13/17] qemu-nbd: " Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 14/17] qemu-img: " Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 15/17] block: rip out all traces of password prompting Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 16/17] block: remove all encryption handling APIs Daniel P. Berrange
2015-10-19 15:09 ` [Qemu-devel] [PATCH 17/17] block: remove support for writing to qcow/qcow2 encrypted images Daniel P. Berrange
2015-10-19 16:05 ` [Qemu-devel] [PATCH 00/17] Framework for securely passing secrets to QEMU Alex Bennée
2015-10-19 16:14   ` Daniel P. Berrange
2015-10-19 17:13 ` Dr. David Alan Gilbert
2015-10-19 17:46   ` Daniel P. Berrange
2015-10-23 15:31 ` Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1445267389-21846-8-git-send-email-berrange@redhat.com \
    --to=berrange@redhat.com \
    --cc=armbru@redhat.com \
    --cc=jdurgin@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=ronniesahlberg@gmail.com \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).