qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* API definition for LUKS key management
@ 2019-11-11 15:58 Maxim Levitsky
  2019-11-11 18:34 ` Daniel P. Berrangé
  2019-11-12 10:02 ` Daniel P. Berrangé
  0 siblings, 2 replies; 13+ messages in thread
From: Maxim Levitsky @ 2019-11-11 15:58 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Daniel P. Berrangé,
	qemu-block, Markus Armbruster, Max Reitz, John Ferlan, John Snow

Hi!

I would like to discuss the API for LUKS key management.

First of all very brief overview of LUKS v1 format:

Each sector of the image is encrypted with same master key, which
is not stored directly on the disk.

Instead in the LUKS header we have 8 slots. Each slot optionally stores
an encrypted version of the master key, encrypted by the user password.
Knowing the password, you can retrieve the master key from the keyslot.
Slot can be marked as active or inactive, inactive slots are not considered
when opening the image.

In addition to that LUKS header has a hash of the master key, so that
you can check if the password 'opens' a keyslot by decrypting it
with given the password, and then checking if 
the hash of the decrypted master key candidate obtained matches the stored hash.

That basically means that you can have up to 8 different passwords that will
open a luks volume and you can change them as you wish without re-encrypting
everything.

Now for raw luks volumes you have cryptsetup which allows to manage these
keyslots, but we also have so called encrypted qcow2 format which
basically has the luks header, together with keyslots embedded, plus each
cluster is encrypted with the master key as in raw luks.
Cryptsetup doesn't support this, thus I implemented this in qemu block layer.

Link to bugzilla here: https://bugzilla.redhat.com/show_bug.cgi?id=1662412


Relevant to the API,
first of all qemu has the notion of amend (qemu-img amend), which allows
currently to change format specific extensions of qcow2.

Since luks, especially luks inside qcow2 is a format on its own, it fits to 
use that interface to change the 'format' options, in this case,
the encryption key slots.


There are the following requirements (they are 100% hardcoded, we might discuss
to drop some of these):


1. ability to add a new password to a free keyslot 
(best is to let api to pick a free keyslot)
Also user should not need to know all the passwords in existing keyslots.


2. ability to erase a keyslot, usually by giving the password that should be erased, and erasing all
the keyslots that match the password, or by giving a keyslot index.
This will usually be done after adding a new password.


3. Allow to do so online, that is while qemu is running, but also support offline management.
Note that online management is even useful for raw luks volumes, since its not safe
to run cryptsetup on them while qemu is using the images.


I implemented those requirements using the following interface.
(I have sent the patches already)

I will try to explain the interface with bunch of examples:


# adds a new password, defined by qemu secret 'sec0' to first unused slot
# give user a error if all keyslots are occupied
qemu-img amend --secret ... -o key-secret=sec1 image.luks


# erases all keyslots that can be opened by password that is contained in a qemu secret 'sec0'
# active=off means that the given password/keyslot won't be active after the operation
qemu-img amend --secret ... -o key-secret=sec0,active=off image.luks


# erase the slot 5 (this is more low level command, less expected to be used)
qemu-img amend --secret ... -o slot=5,active=off image.luks

# add new secret to slot 5 (will fail if the slot is already marked as active)
qemu-img amend --secret ... -o slot=5,key-secret=sec1 image.luks


This is basically it.

The full option syntax is as following:

active=on/off (optional, default to on) - toggles if we enabling a keyslot or are erasing it.

slot=number (optional, advanced option) - specifies which exactly slot to erase or which
slot to put the new key on

key-secret = id of the secret object - specifies the secret. when slot is enabled,
it will be put into the new slot. when disabling (erasing a keyslot), all keyslots
matching that secret will be erased. 
Specifying both key-secret and slot index is treated as error I think


As as very advanced option, --force is added to qemu-img to allow to do unsafe operation,
which in this case is removing last keyslot which will render the encrypted image useless.


In addition to that, QMP interface was added for online version of the above.
It is very similiar, but since we don't have blockdev-amend,
I added one and it has the following interface:



##
# @x-blockdev-amend:
#
# Starts a job to amend format specific options of an existing open block device.
# The job is automatically finalized, but a manual job-dismiss is required.
#
# @job-id:          Identifier for the newly created job.
#
# @node-name:       Name of the block node to work on
#
# @options:         Options (same as for image creation)
#
# @force:           Allow unsafe operations, format specific
#                   For luks that allows erase of the last active keyslot
#                   (permanent loss of data),
#                   and replacement of an active keyslot
#                   (possible loss of data if IO error happens)
#
# Since: 4.2
##
{ 'command': 'x-blockdev-amend',
  'data': { 'job-id': 'str',
            'node-name': 'str',
            'options': 'BlockdevCreateOptions',
            '*force': 'bool' } }



It takes the same BlockdevCreateOptions as blockdev-create (this is open to debate if to leave this as is)


BlockdevCreateOptionsLUKS (its parent QCryptoBlockCreateOptionsLUKS technically is extended in this way):


--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -190,6 +190,21 @@
 #                  Currently defaults to 'sha256'
 # @hash-alg: the master key hash algorithm
 #            Currently defaults to 'sha256'
+#
+# @active: Should the new secret be added (true) or erased (false)
+#          (amend only, since 4.2)
+#
+# @slot: The slot in which to put/erase the secret
+#        if not given, will select first free slot for secret addtion
+#        and erase all keyslots that match the given @key-secret for erase.
+#        except the last one
+#        (optional, since 4.2)
+#
+# @unlock-secret: The secret to use to unlock the image
+#        If not given, will use the secret that was used
+#        when opening the image.
+#        (optional, for amend only, since 4.2)
+#
 # @iter-time: number of milliseconds to spend in
 #             PBKDF passphrase processing. Currently defaults
 #             to 2000. (since 2.8)
@@ -201,7 +216,12 @@
             '*cipher-mode': 'QCryptoCipherMode',
             '*ivgen-alg': 'QCryptoIVGenAlgorithm',
             '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
+
             '*hash-alg': 'QCryptoHashAlgorithm',
+            '*active' : 'bool',
+            '*slot': 'int',
+            '*unlock-secret': 'str',
+
             '*iter-time': 'int'}}


Here note that key-secret is already present in the in api, and I am adding the 'slot','active' and 'unlock-secret'

'slot' can be also used for new created image to specify where to place the the secret.
'active' not allowed to be false for blockdev-create of an image and can be true/false for 'blockdev-amend'

'unlock-secret' (might be removed later) covers an corner case that is specific for online key management.
The case is that if the keyslot used to open the image in first place is removed, it can be used to specify
the password to retrieve the master key from one of existing keyslots, since the driver doesn't officially
keep the master key all the time (it can be in theory only loaded in hardware crypto device)

That is why for adding a new keyslot, the secret that was used to open the image is tried first, and if it
doesn't open a keyslot, the 'unlock-secret' can be used instead. This can be thought of as the 'current password'
that is need to update the password on many web forums.


One of the concerns that was raised during the review was that amend interface for luks that I propose is
different from the amend inteface used currently for qcow2.

qcow2 amend interface specifies all the format options, thus overwrites the existing options.
Thus it seems natural to make the luks amend interface work the same way, that it receive an array
of 8 slots, and for each slot specify if it is active, and if true what password to put in it.
This does allow to add and erase the keyslots, but it doesn't allow:

   * add a password without knowing all other passwords that exist in existing keyslots
     this can be mitigated by specifying which keyslots to modify for example by omitting the
     keyslots that shouldn't be touched from the array (passing null placeholder instead)
     but then it already doesn't follow the 'specify all the options each time' principle.

   * erase all keyslots matching a password - this is really hard to do using this approach,
     unless we give user some kind of api to try each keyslot with given password,
     which is kind of ugly and might be racy as well.


So what do you think?

Best regards,
	Maxim Levitsky







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

end of thread, other threads:[~2019-11-26 14:25 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-11 15:58 API definition for LUKS key management Maxim Levitsky
2019-11-11 18:34 ` Daniel P. Berrangé
2019-11-12  9:12   ` Kevin Wolf
2019-11-12 10:47     ` Max Reitz
2019-11-12 11:02     ` Daniel P. Berrangé
2019-11-14 10:54       ` Maxim Levitsky
2019-11-14 10:58     ` Maxim Levitsky
2019-11-14 10:37   ` Maxim Levitsky
2019-11-12 10:02 ` Daniel P. Berrangé
2019-11-22 14:22   ` API definition for LUKS key management [V2] Maxim Levitsky
2019-11-25 18:45     ` Max Reitz
2019-11-26  9:28       ` Maxim Levitsky
2019-11-26 14:24       ` Kevin Wolf

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).