[libvirt PATCH v2 09/12] tools: support generating SEV secret injection tables
Dov Murik
dovmurik at linux.ibm.com
Wed Oct 26 12:34:00 UTC 2022
On 26/10/2022 12:59, Daniel P. Berrangé wrote:
> On Tue, Oct 25, 2022 at 07:38:43PM -0400, Cole Robinson wrote:
>> On 10/19/22 6:17 AM, Daniel P. Berrangé wrote:
>>> It is possible to build OVMF for SEV with an embedded Grub that can
>>> fetch LUKS disk secrets. This adds support for injecting secrets in
>>> the required format.
>>>
>>> Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
>>> ---
>>
>>> diff --git a/tools/virt-qemu-sev-validate b/tools/virt-qemu-sev-validate
>>> index 5ce5763d5b..2d15edb933 100755
>>> --- a/tools/virt-qemu-sev-validate
>>> +++ b/tools/virt-qemu-sev-validate
>>> @@ -36,16 +36,19 @@
>>>
>>> import abc
>>> import argparse
>>> -from base64 import b64decode
>>> +from base64 import b64decode, b64encode
>>> from hashlib import sha256
>>> import hmac
>>> import logging
>>> +import os
>>> import re
>>> import socket
>>> from struct import pack
>>> import sys
>>> import traceback
>>> from uuid import UUID
>>> +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
>>> +
>>>
>>> from lxml import etree
>>> import libvirt
>>> @@ -573,7 +576,26 @@ class KernelTable(GUIDTable):
>>> return entries
>>>
>>>
>>> -class ConfidentialVM(object):
>>> +class SecretsTable(GUIDTable):
>>> +
>>> + TABLE_GUID = UUID('{1e74f542-71dd-4d66-963e-ef4287ff173b}').bytes_le
>>> + DISK_PW_GUID = UUID('{736869e5-84f0-4973-92ec-06879ce3da0b}').bytes_le
>>> +
>>> + def __init__(self):
>>> + super().__init__(guid=self.TABLE_GUID,
>>> + lenlen=4)
>>> + self.disk_password = None
>>> +
>>> + def load_disk_password(self, path):
>>> + with open(path, 'rb') as fh:
>>> + self.disk_password = fh.read()
>>> +
>>> + def entries(self):
>>> + return self.build_entry(self.DISK_PW_GUID,
>>> + self.disk_password + bytes([0]), 4)
>>> +
>>
>> This bytes([0]) NUL byte ends up in the efi_secret /sys path. Dropping
>> it doesn't seem to impact injecting the secret at all
>
> The specs/sev-guest-firmware.rst files does not specify anything in
> particular about the injected secret format. The rules for the format
> will vary according to the GUID used for the entry. In this case what
> I've called the DISK_PW_GUID is the same as the GUID used in James
> Bottomley's grub patch:
>
> https://lists.gnu.org/archive/html/grub-devel/2020-12/msg00260.html
>
> In particular note
>
> + /*
> + * the passphrase must be a zero terminated string because the
> + * password routines call grub_strlen () to find its size
> + */
>
> As written, the code just passes around a pointer to the data in the
> secret table, so it can't simply add a NUL terminator itself.
>
> See also James' python demo script for injection which adds a NUL:
>
> https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg03691.html
>
>> FWIW once that's dropped, getting automatic luks unlock is really simple
>> with /etc/crypttab + kernel 5.19
>>
>> sed -i -e "s| none |
>> /sys/kernel/security/secrets/coco/736869e5-84f0-4973-92ec-06879ce3da0b
>> |g" /etc/crypttab
>> dracut --force --add-drivers efi_secret
>> shutdown -r now
I'm not an initrd expert, but maybe there's a way to run an early script
(before cryptsetup) that will peel that terminating NUL:
head -c -1 /sys/kernel/security/secrets/coco/736869e5-84f0-4973-92ec-06879ce3da0b > /tmp/luks_key
and then use /tmp/luks_key in /etc/crypttab.
Of course /tmp/luks_key isn't a secure place, so need to find the correct location for this.
>
> Now one option here is to invent a different GUID and call it the
> "CRYTPTAB_PW_GUID", and have the host side injection tools not use
> a NUL terminator for this option.
and then modify the Grub patch (option 1 below) to read from the
new GUID, copy the value, and add the NUL byte.
>
> What I don't like about this is that in both cases we're just passing
> in the same data - a passphrase for unlocking a LUKS keyslot.
>
> IMHO, we should have a "LUKS_PASSPHARSE_GUID" secret entry which can
> be consumed by any software that wants to unlock LUKS, not have
> software specific GUIDs.
>
> The crypttab keyfiles can contain arbitrary bytes, so we can't just
> drop the trailing NUL as that might be relevant key material.
>
Note that grub and cryptsetup are not identical -- I think that (currently) the
grub patches do not support binary passphrases (that may include NUL bytes),
whereas cryptsetup keyfile can be have binary content. But I'm not following
grub-devel closely.
> Reading cryttab(5) I see that /etc/crypttab supports an option
> called 'keyfile-size', which could be used to truncate the file.
> That's not at all user friendly for us, as the user pw data can be
> arbitrary length and when building the disk image template we
> don't know how many bytes are sensitive.IOW, we can't predict
> what keyfile-size to use.
>
> So it seems we have a few options
>
> 1. modify grub patches to remove the requirement for NUL
> termination
> 2. modify systemd to add a 'keyfile-nul-terminated' option
> to instruct it to stip a trailing NUL from key-file.
> 3. modify systemd to add a 'efi-secret=UUID' option and
> ignore key-file field entirely
Debian's crypttab supports keyscript=/path/to/script which should output
the passphrase to stdout. This is very generic and can allow us to:
1. check a few GUIDs (fallback)
2. drop terminating NUL
3. for SNP-style late attestation: fetch attestation report, contact the KBS,
and retrieve the key (see AMD's example [1])
[1] https://github.com/AMDESE/sev-guest/tree/main/attestation/cryptsetup-initramfs
But there's no keyscript option in systemd...
>
> Incidentally I think we should document well known secret GUIDs
> in specs/sev-guest-firmware.rst.
The only others I know are used in confidential-containers
attestation agent (offline_sev_kbc [2] and online_sev_kbc [3]).
[2] https://github.com/confidential-containers/attestation-agent/blob/6e4a249dfbf6fae4a0ec636ae2fac8c0aa368467/src/kbc_modules/offline_sev_kbc/mod.rs#L17
[3] https://github.com/confidential-containers/attestation-agent/blob/6e4a249dfbf6fae4a0ec636ae2fac8c0aa368467/src/kbc_modules/online_sev_kbc/mod.rs#L28
-Dov
More information about the libvir-list
mailing list