diff mbox

[v2,1/2] crypto: add support for querying parameters for block encryption

Message ID 1465901813-510-2-git-send-email-berrange@redhat.com
State New
Headers show

Commit Message

Daniel P. Berrangé June 14, 2016, 10:56 a.m. UTC
When creating new block encryption volumes, we accept a list of
parameters to control the formatting process. It is useful to
be able to query what those parameters were for existing block
devices. Add a qcrypto_block_get_info() method which returns a
QCryptoBlockInfo instance to report this data.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 crypto/block-luks.c    | 70 ++++++++++++++++++++++++++++++++++++++++++++++
 crypto/block.c         | 17 +++++++++++
 crypto/blockpriv.h     |  4 +++
 include/crypto/block.h | 16 +++++++++++
 qapi/crypto.json       | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 183 insertions(+)

Comments

Max Reitz June 14, 2016, 3:30 p.m. UTC | #1
On 14.06.2016 12:56, Daniel P. Berrange wrote:
> When creating new block encryption volumes, we accept a list of
> parameters to control the formatting process. It is useful to
> be able to query what those parameters were for existing block
> devices. Add a qcrypto_block_get_info() method which returns a
> QCryptoBlockInfo instance to report this data.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  crypto/block-luks.c    | 70 ++++++++++++++++++++++++++++++++++++++++++++++
>  crypto/block.c         | 17 +++++++++++
>  crypto/blockpriv.h     |  4 +++
>  include/crypto/block.h | 16 +++++++++++
>  qapi/crypto.json       | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 183 insertions(+)
> 
> diff --git a/crypto/block-luks.c b/crypto/block-luks.c
> index 63649f1..6a6ef07 100644
> --- a/crypto/block-luks.c
> +++ b/crypto/block-luks.c

[...]

> @@ -1284,6 +1305,54 @@ qcrypto_block_luks_create(QCryptoBlock *block,
>  }
>  
>  
> +static int qcrypto_block_luks_get_info(QCryptoBlock *block,
> +                                       QCryptoBlockInfo *info,
> +                                       Error **errp)
> +{
> +    QCryptoBlockLUKS *luks = block->opaque;
> +    QCryptoBlockInfoLUKSSlot *slot;
> +    QCryptoBlockInfoLUKSSlotList *slots = NULL, *prev = NULL;

You could make prev a double pointer, initializing it to
&info->u.luks.slots... [1]

> +    size_t i;
> +
> +    info->u.luks.cipher_alg = luks->cipher_alg;
> +    info->u.luks.cipher_mode = luks->cipher_mode;
> +    info->u.luks.ivgen_alg = luks->ivgen_alg;
> +    if (info->u.luks.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
> +        info->u.luks.has_ivgen_hash_alg = true;
> +        info->u.luks.ivgen_hash_alg = luks->ivgen_hash_alg;
> +    }
> +    info->u.luks.hash_alg = luks->hash_alg;
> +    info->u.luks.payload_offset = block->payload_offset;
> +    info->u.luks.master_key_iters = luks->header.master_key_iterations;
> +    info->u.luks.uuid = g_strdup((const char *)luks->header.uuid);

Wouldn't g_strndup() with sizeof(luks->header.uuid) be a better choice?

> +
> +    for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
> +        slots = g_new0(QCryptoBlockInfoLUKSSlotList, 1);
> +        if (i == 0) {
> +            info->u.luks.slots = slots;
> +        } else {
> +            prev->next = slots;
> +        }

[1] ...then unconditionally use *prev = slots here...

> +
> +        slots->value = slot = g_new0(QCryptoBlockInfoLUKSSlot, 1);
> +        slot->active = luks->header.key_slots[i].active ==
> +            QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED;
> +        slot->key_offset = luks->header.key_slots[i].key_offset
> +             * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
> +        if (slot->active) {
> +            slot->has_iters = true;
> +            slot->iters = luks->header.key_slots[i].iterations;
> +            slot->has_stripes = true;
> +            slot->stripes = luks->header.key_slots[i].stripes;
> +        }
> +
> +        prev = slots;

[1] ...and prev = &slots->next here.

> +    }
> +
> +    return 0;
> +}
> +
> +
>  static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
>  {
>      g_free(block->opaque);

[...]

> diff --git a/include/crypto/block.h b/include/crypto/block.h
> index a21e11f..6256f64 100644
> --- a/include/crypto/block.h
> +++ b/include/crypto/block.h
> @@ -138,6 +138,22 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
>                                     void *opaque,
>                                     Error **errp);
>  
> +
> +/**
> + * qcrypto_block_get_info:
> + * block: the block encryption object

I think this is missing an @.

Max

> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Get information about the configuration options for the
> + * block encryption object. This includes details such as
> + * the cipher algorithms, modes, and initialization vector
> + * generators.
> + *
> + * Returns: a block encryption info object, or NULL on error
> + */
> +QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
> +                                         Error **errp);
> +
>  /**
>   * @qcrypto_block_decrypt:
>   * @block: the block encryption object
diff mbox

Patch

diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 63649f1..6a6ef07 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -201,6 +201,15 @@  QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSHeader) != 592);
 
 struct QCryptoBlockLUKS {
     QCryptoBlockLUKSHeader header;
+
+    /* Cache parsed versions of what's in header fields,
+     * as we can't rely on QCryptoBlock.cipher being
+     * non-NULL */
+    QCryptoCipherAlgorithm cipher_alg;
+    QCryptoCipherMode cipher_mode;
+    QCryptoIVGenAlgorithm ivgen_alg;
+    QCryptoHashAlgorithm ivgen_hash_alg;
+    QCryptoHashAlgorithm hash_alg;
 };
 
 
@@ -835,6 +844,12 @@  qcrypto_block_luks_open(QCryptoBlock *block,
     block->payload_offset = luks->header.payload_offset *
         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
 
+    luks->cipher_alg = cipheralg;
+    luks->cipher_mode = ciphermode;
+    luks->ivgen_alg = ivalg;
+    luks->ivgen_hash_alg = ivhash;
+    luks->hash_alg = hash;
+
     g_free(masterkey);
     g_free(password);
 
@@ -1250,6 +1265,12 @@  qcrypto_block_luks_create(QCryptoBlock *block,
         goto error;
     }
 
+    luks->cipher_alg = luks_opts.cipher_alg;
+    luks->cipher_mode = luks_opts.cipher_mode;
+    luks->ivgen_alg = luks_opts.ivgen_alg;
+    luks->ivgen_hash_alg = luks_opts.ivgen_hash_alg;
+    luks->hash_alg = luks_opts.hash_alg;
+
     memset(masterkey, 0, luks->header.key_bytes);
     g_free(masterkey);
     memset(slotkey, 0, luks->header.key_bytes);
@@ -1284,6 +1305,54 @@  qcrypto_block_luks_create(QCryptoBlock *block,
 }
 
 
+static int qcrypto_block_luks_get_info(QCryptoBlock *block,
+                                       QCryptoBlockInfo *info,
+                                       Error **errp)
+{
+    QCryptoBlockLUKS *luks = block->opaque;
+    QCryptoBlockInfoLUKSSlot *slot;
+    QCryptoBlockInfoLUKSSlotList *slots = NULL, *prev = NULL;
+    size_t i;
+
+    info->u.luks.cipher_alg = luks->cipher_alg;
+    info->u.luks.cipher_mode = luks->cipher_mode;
+    info->u.luks.ivgen_alg = luks->ivgen_alg;
+    if (info->u.luks.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
+        info->u.luks.has_ivgen_hash_alg = true;
+        info->u.luks.ivgen_hash_alg = luks->ivgen_hash_alg;
+    }
+    info->u.luks.hash_alg = luks->hash_alg;
+    info->u.luks.payload_offset = block->payload_offset;
+    info->u.luks.master_key_iters = luks->header.master_key_iterations;
+    info->u.luks.uuid = g_strdup((const char *)luks->header.uuid);
+
+    for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
+        slots = g_new0(QCryptoBlockInfoLUKSSlotList, 1);
+        if (i == 0) {
+            info->u.luks.slots = slots;
+        } else {
+            prev->next = slots;
+        }
+
+        slots->value = slot = g_new0(QCryptoBlockInfoLUKSSlot, 1);
+        slot->active = luks->header.key_slots[i].active ==
+            QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED;
+        slot->key_offset = luks->header.key_slots[i].key_offset
+             * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
+        if (slot->active) {
+            slot->has_iters = true;
+            slot->iters = luks->header.key_slots[i].iterations;
+            slot->has_stripes = true;
+            slot->stripes = luks->header.key_slots[i].stripes;
+        }
+
+        prev = slots;
+    }
+
+    return 0;
+}
+
+
 static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
 {
     g_free(block->opaque);
@@ -1321,6 +1390,7 @@  qcrypto_block_luks_encrypt(QCryptoBlock *block,
 const QCryptoBlockDriver qcrypto_block_driver_luks = {
     .open = qcrypto_block_luks_open,
     .create = qcrypto_block_luks_create,
+    .get_info = qcrypto_block_luks_get_info,
     .cleanup = qcrypto_block_luks_cleanup,
     .decrypt = qcrypto_block_luks_decrypt,
     .encrypt = qcrypto_block_luks_encrypt,
diff --git a/crypto/block.c b/crypto/block.c
index da60eba..be823ee 100644
--- a/crypto/block.c
+++ b/crypto/block.c
@@ -105,6 +105,23 @@  QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
 }
 
 
+QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
+                                         Error **errp)
+{
+    QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
+
+    info->format = block->format;
+
+    if (block->driver->get_info &&
+        block->driver->get_info(block, info, errp) < 0) {
+        g_free(info);
+        return NULL;
+    }
+
+    return info;
+}
+
+
 int qcrypto_block_decrypt(QCryptoBlock *block,
                           uint64_t startsector,
                           uint8_t *buf,
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
index 6297085..35217cd 100644
--- a/crypto/blockpriv.h
+++ b/crypto/blockpriv.h
@@ -53,6 +53,10 @@  struct QCryptoBlockDriver {
                   void *opaque,
                   Error **errp);
 
+    int (*get_info)(QCryptoBlock *block,
+                    QCryptoBlockInfo *info,
+                    Error **errp);
+
     void (*cleanup)(QCryptoBlock *block);
 
     int (*encrypt)(QCryptoBlock *block,
diff --git a/include/crypto/block.h b/include/crypto/block.h
index a21e11f..6256f64 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -138,6 +138,22 @@  QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
                                    void *opaque,
                                    Error **errp);
 
+
+/**
+ * qcrypto_block_get_info:
+ * block: the block encryption object
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Get information about the configuration options for the
+ * block encryption object. This includes details such as
+ * the cipher algorithms, modes, and initialization vector
+ * generators.
+ *
+ * Returns: a block encryption info object, or NULL on error
+ */
+QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
+                                         Error **errp);
+
 /**
  * @qcrypto_block_decrypt:
  * @block: the block encryption object
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 760d0c0..2c7465a 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -220,3 +220,79 @@ 
   'discriminator': 'format',
   'data': { 'qcow': 'QCryptoBlockOptionsQCow',
             'luks': 'QCryptoBlockCreateOptionsLUKS' } }
+
+
+##
+# QCryptoBlockInfoBase:
+#
+# The common information that applies to all full disk
+# encryption formats
+#
+# @format: the encryption format
+#
+# Since: 2.7
+##
+{ 'struct': 'QCryptoBlockInfoBase',
+  'data': { 'format': 'QCryptoBlockFormat' }}
+
+
+##
+# QCryptoBlockInfoLUKSSlot:
+#
+# Information about the LUKS block encryption key
+# slot options
+#
+# @active: whether the key slot is currently in use
+# @key-offset: offset to the key material in bytes
+# @iters: #optional number of PBKDF2 iterations for key material
+# @stripes: #optional number of stripes for splitting key material
+#
+# Since: 2.7
+##
+{ 'struct': 'QCryptoBlockInfoLUKSSlot',
+  'data': {'active': 'bool',
+           '*iters': 'int',
+           '*stripes': 'int',
+           'key-offset': 'int' } }
+
+
+##
+# QCryptoBlockInfoLUKS:
+#
+# Information about the LUKS block encryption options
+#
+# @cipher-alg: the cipher algorithm for data encryption
+# @cipher-mode: the cipher mode for data encryption
+# @ivgen-alg: the initialization vector generator
+# @ivgen-hash-alg: #optional the initialization vector generator hash
+# @hash-alg: the master key hash algorithm
+# @payload-offset: offset to the payload data in bytes
+# @master-key-iters: number of PBKDF2 iterations for key material
+# @uuid: unique identifier for the volume
+# @slots: information about each key slot
+#
+# Since: 2.7
+##
+{ 'struct': 'QCryptoBlockInfoLUKS',
+  'data': {'cipher-alg': 'QCryptoCipherAlgorithm',
+           'cipher-mode': 'QCryptoCipherMode',
+           'ivgen-alg': 'QCryptoIVGenAlgorithm',
+           '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
+           'hash-alg': 'QCryptoHashAlgorithm',
+           'payload-offset': 'int',
+           'master-key-iters': 'int',
+           'uuid': 'str',
+           'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
+
+
+##
+# QCryptoBlockInfo:
+#
+# Information about the block encryption options
+#
+# Since: 2.7
+##
+{ 'union': 'QCryptoBlockInfo',
+  'base': 'QCryptoBlockInfoBase',
+  'discriminator': 'format',
+  'data': { 'luks': 'QCryptoBlockInfoLUKS' } }