SEDutil Future with Secure Boot - a Potential Option is Available Now
ChubbyAnt opened this issue · 11 comments
Windows 11 requires secure boot. Thus, for those who use SEDutil for preboot OPAL unlocking, we need a path for a secure boot compatible PBA.
Relax and Recover (https://github.com/rear/rear) is a backup and restoration utility that wraps in SEDutil in a rescue image and PBA. With great difficulty I have been able to get the rescue image working with secure boot and SEDutil, but I have not yet successfully managed to get the slimmer rear PBA working correctly. After trying many iterations to make rear work correctly, I ultimately succeeded in getting the rescue image to work with NVME and SATA SEDs by building rear in Debian 10.
It looks like a reasonable path forward to develop a Secure Boot enabled PBA for SEDutil is to use rear rescue image as a base with stripped out unnecessary rear packages.
The great news is that today rear is a working secure boot option for SEDutil PBA unlocking.
See also Drive-Trust-Alliance#366
Am I correct in assuming this is based on a Debian-signed kernel (+ shim + grub) and custom userspace?
Rear uses a secure boot shim (shim64x.efi) to grub to signed kernel to custom userspace. But, the way they have it configured is unfriendly to all the UEFIs I tired so it requires a lot of cleanup to work universally.
If you'd just like to have a generic rescue system to set up your SED and a PBA on recent hardware, using Debian 10 as a base system for ReaR does not seem ideal. ReaR uses the kernel and all utilities from the base system. If the base system is too old, this may cause problems, in particular on recent hardware.
ReaR's TCG Opal 2 support was build and tested on Ubuntu 20.04 LTS (focal). So you'd probably get better results when you
- Use Ubuntu 20.04 LTS Desktop as the base system,
- Install the latest ReaR version tested with Opal 2 support directly from GitHub (https://github.com/OliverO2/rear),
- Follow the instructions in https://github.com/rear/rear/blob/master/doc/user-guide/13-tcg-opal-support.adoc.
I am running Secure Boot with my own keys, sbupdate-generated signed cmdline+kernel+initramfs image that loads from EFI system partition (either directly by firmware or via systemd-boot), and within the initramfs I have a hook that runs sedutil to unlock my drives before root is mounted (password input over ssh). No reboot is needed after unlocking like with PBAs.
As an extra, I use LockingRange 1 instead of the global locking range so that
- The EFI system partition can be read normally without all that ShadowMBR hackery (only root partition and swap in LR1)
- My UEFI firmware doesn't try to unlock the drive (pausing forever on a password prompt)
The firmware prompt (on a new Asus Intel motherboard) is particularly annoying because I could not disable it in setup, and because it cannot actually unlock the drive (tried plain text, sha-1 and sha-512 hashing on the Admin1 password but unlocking always fails).
ChubbyAnt, do you have a guide on how you got PBA/SecureBoot working with ReAR? I would really like to get this all working with Opal compliant SSD and NVMe. It would be even better if the drive password could be stored in TPM. Thanks!
I am running Secure Boot with my own keys, sbupdate-generated signed cmdline+kernel+initramfs image that loads from EFI system partition (either directly by firmware or via systemd-boot), and within the initramfs I have a hook that runs sedutil to unlock my drives before root is mounted (password input over ssh). No reboot is needed after unlocking like with PBAs.
As an extra, I use LockingRange 1 instead of the global locking range so that
* The EFI system partition can be read normally without all that ShadowMBR hackery (only root partition and swap in LR1) * My UEFI firmware doesn't try to unlock the drive (pausing forever on a password prompt)
@Tronic could you elaborate a bit more on your locking configuration? Specifically, I don't understand how locking ranges work, and I can't find any clear documentation about them. Also, how did you implement that initramfs hook you mentioned?
@napaalm I guess I should've documented the process because now it is a bit hard to remember.
You need something like this for initial setup (after you've setup your drive for SED Opal otherwise but NOT enabled locking range 0, shadow MBR or any of that stuff):
sedutil --setupLockingRange 1 262144 1953259520 password /dev/nvme0
The 1 is the number of the locking range. 0 is the global range, others are free for this use and we need only one.
The middle value is 128 MiB for the starting position of locking. This allows for GPT (1 MiB) and a 127 MiB UEFI system partition at the beginning of the disk (ending at sector 262143 inclusive, as shown by the gdisk tool).
The largest value is the length of the locking range. This is a bit trickier. First of all, it is not the ending sector (which gdisk would show), and secondly it may have to be rounded (e.g. to 1 MiB or even larger boundary) for the drive to accept it. You need to calculate this based on the size of your disk, leaving some unprotected area at the end (minimum 1 MiB for the secondary GPT). The create your main partition(s) so that it doesn't pass the locked range (possibly leaving a bit of unpartitioned space at the end).
Gdisk showing end sectors inclusive makes then one smaller than you'd use in arithmetic, so remember to add/subtract one manually. Also notice that gdisk uses one too large value if you specify the ending position as 128M (yeah, really bad design). You should be able to use +127M though.
In your initramfs you need to unlock with
sedutil --setLockingRange 1 RW Admin1 password /dev/nvme0
Depending on which sedutil fork you use, it may or may not take the Admin1 argument. Try to find out which form works. You can also experiment with this right after setting up your range (use LK instead of RW to lock it to see that it actually prevents access to that region, with no partitions mounted of course).
How exactly you setup your initramfs is another question. I use systemd on initramfs too (most distros don't by default), and systemd-ask-password to get the password input in a simple shell script that I have there. Possibly your script needs to assemble md0 or do something of the like afterwards or possibly systemd will immediately continue normal boot once the devices become available or if already unlocked (automatically killing your script as well). Mine also has sshd (part of the systemd initramfs stuff, that also enables networking at such early stage) that allows unlocking over network rather than only by console, using the same script still. Obviously the sedutil tool also needs to be on the initramfs, and your distro might provide sedutil-sleep or similar package for that, but simply adding the binary should also work.
Once you are fairly confident that all of that works, enable locking by default on cold boots:
sedutil --enableLockingRange 1 password /dev/nvme0
Had you already configured LR0, be sure to also --disableLockingRange 0
, and should you wish to get rid of partial locking, just disable LR1.
@Tronic, thank you very much for your thorough explanation! I've been looking for a viable solution for some time and your setup is perfect for my use case.
There's just one detail I miss about locking ranges: my high-level understanding of SEDs (coming from the arch wiki) is that the actual data encryption key used by the disk firmware is encrypted with the passphrase I provide, so that it doesn't have to re-encrypt the entire disk after a passphrase change.
As long as you're dealing with locking and unlocking the whole disk, I understand why it's convenient while still being cryptographically secure. But if I tell the disk to lock a specific range, assuming the whole disk is encrypted with the same key, that doesn't mean that a copy of it needs to be kept in plain text in the firmware to make the parts not included in the range always readable? In effect, this would render the whole encryption useless to an attacker who has physical access to the machine and the technical ability to extract the key from the firmware.
I guess my understanding is incomplete, so how is this actually implemented? Does the disk generate a new encryption key for each locking range? If so, I guess all data in that range is lost when I enable it because it's encrypted with a new key, right?
@napaalm When you setupLockingRange, the drive re-keys that part, and in effect destroys all the data that you had there. The drive returns scrambled data with no error, so it is better to not have any partitions on the disk when doing setup (especially it should not be a RAID member!)
The same for initial SED setup, it is always a destructive operation (at least with Samsung drives) despite sedutil tutorials claiming something else.
Speaking of keys and passwords, be aware that each sedutil fork uses different hashing, so passwords are not compatible between different versions of the software. I almost prefer not having sedutil hash at all (-n), and optionally adding your own hashing (I suggest Argon2id with RAM and parallelism set to match your actual hardware, such that even short passwords can be secure).