[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

API definition for LUKS key management

From: Maxim Levitsky
Subject: API definition for LUKS key management
Date: Mon, 11 Nov 2019 17:58:20 +0200


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

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 
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 
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 
it will be put into the new slot. when disabling (erasing a keyslot), all 
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 
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 
# 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 
'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 
     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' 

   * 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 
     which is kind of ugly and might be racy as well.

So what do you think?

Best regards,
        Maxim Levitsky

reply via email to

[Prev in Thread] Current Thread [Next in Thread]