TL;DR: It's now easy to unlock your LUKS2 volume with a FIDO2
security token (e.g. YubiKey or Nitrokey FIDO2). And TPM2 unlocking is
easy now too.
Blogging is a lot of work, and a lot less fun than hacking. I mostly
focus on the latter because of that, but from time to time I guess
stuff is just too interesting to not be blogged about. Hence here,
finally, another blog story about exciting new features in systemd.
With the upcoming systemd v248 the systemd-cryptsetup
component of systemd (which is responsible for assembling encrypted
volumes during boot) gained direct support for unlocking encrypted
storage with three types of security hardware:
Unlocking with FIDO2 security tokens (well, at least with those which implement the
hmac-secret
extension, most do). i.e. your YubiKeys (series 5 and above), or Nitrokey FIDO2 and such.Unlocking with TPM2 security chips (pretty ubiquitous on non-budget PCs/laptops/…)
Unlocking with PKCS#11 security tokens, i.e. your smartcards and older YubiKeys (the ones that implement PIV). (Strictly speaking this was supported on older systemd already, but was a lot more "manual".)
For completeness' sake, let's keep in mind that the component also
allows unlocking with these more traditional mechanisms:
Unlocking interactively with a user-entered passphrase (i.e. the way most people probably already deploy it, supported since about forever)
Unlocking via key file on disk (optionally on removable media plugged in at boot), supported since forever.
Unlocking via a key acquired through trivial
AF_UNIX
/SOCK_STREAM
socket IPC. (Also new in v248)Unlocking via recovery keys. These are pretty much the same thing as a regular passphrase (and in fact can be entered wherever a passphrase is requested) — the main difference being that they are always generated by the computer, and thus have guaranteed high entropy, typically higher than user-chosen passphrases. They are generated in a way they are easy to type, in many cases even if the local key map is misconfigured. (Also new in v248)
In this blog story, let's focus on the first three items, i.e. those
that talk to specific types of hardware for implementing unlocking.
To make working with security tokens and TPM2 easy, a new, small tool
was added to the systemd tool set: systemd-cryptenroll. It's
only purpose is to make it easy to enroll your security token/chip of
choice into an encrypted volume. It works with any LUKS2 volume, and
embeds a tiny bit of meta-information into the LUKS2 header with
parameters necessary for the unlock operation.
Unlocking with FIDO2
So, let's see how this fits together in the FIDO2 case. Most likely
this is what you want to use if you have one of these fancy FIDO2 tokens
(which need to implement the hmac-secret
extension, as
mentioned). Let's say you already have your LUKS2 volume set up, and
previously unlocked it with a simple passphrase. Plug in your token,
and run:
# systemd-cryptenroll --fido2-device=auto /dev/sda5
(Replace /dev/sda5
with the underlying block device of your volume).
This will enroll the key as an additional way to unlock the volume,
and embeds all necessary information for it in the LUKS2 volume
header. Before we can unlock the volume with this at boot, we need to
allow FIDO2 unlocking via /etc/crypttab
. For
that, find the right entry for your volume in that file, and edit it
like so:
myvolume /dev/sda5 - fido2-device=auto
Replace myvolume
and /dev/sda5
with the right volume name, and
underlying device of course. Key here is the fido2-device=auto
option you need to add to the fourth column in the file. It tells systemd-cryptsetup
to use the FIDO2 metadata now embedded in the
LUKS2 header, wait for the FIDO2 token to be plugged in at boot
(utilizing systemd-udevd
, …) and unlock the volume with it.
And that's it already. Easy-peasy, no?
Note that all of this doesn't modify the FIDO2 token itself in any
way. Moreover you can enroll the same token in as many volumes as you
like. Since all enrollment information is stored in the LUKS2 header
(and not on the token) there are no bounds on any of this. (OK, well,
admittedly, there's a cap on LUKS2 key slots per volume, i.e. you
can't enroll more than a bunch of keys per volume.)
Unlocking with PKCS#11
Let's now have a closer look how the same works with a PKCS#11
compatible security token or smartcard. For this to work, you need a
device that can store an RSA key pair. I figure most security
tokens/smartcards that implement PIV qualify. How you actually get the
keys onto the device might differ though. Here's how you do this for
any YubiKey that implements the PIV feature:
# ykman piv reset # ykman piv generate-key -a RSA2048 9d pubkey.pem # ykman piv generate-certificate --subject "Knobelei" 9d pubkey.pem # rm pubkey.pem
(This chain of commands erases what was stored in PIV feature of your
token before, be careful!)
For tokens/smartcards from other vendors a different series of
commands might work. Once you have a key pair on it, you can enroll it
with a LUKS2 volume like so:
# systemd-cryptenroll --pkcs11-token-uri=auto /dev/sda5
Just like the same command's invocation in the FIDO2 case this enrolls
the security token as an additional way to unlock the volume, any
passphrases you already have enrolled remain enrolled.
For the PKCS#11 case you need to edit your /etc/crypttab
entry like this:
myvolume /dev/sda5 - pkcs11-uri=auto
If you have a security token that implements both PKCS#11 PIV and
FIDO2 I'd probably enroll it as FIDO2 device, given it's the more
contemporary, future-proof standard. Moreover, it requires no special
preparation in order to get an RSA key onto the device: FIDO2 keys
typically just work.
Unlocking with TPM2
Most modern (non-budget) PC hardware (and other kind of hardware too)
nowadays comes with a TPM2 security chip. In many ways a TPM2 chip is
a smartcard that is soldered onto the mainboard of your system. Unlike
your usual USB-connected security tokens you thus cannot remove them
from your PC, which means they address quite a different security
scenario: they aren't immediately comparable to a physical key you can
take with you that unlocks some door, but they are a key you leave at
the door, but that refuses to be turned by anyone but you.
Even though this sounds a lot weaker than the FIDO2/PKCS#11 model TPM2
still bring benefits for securing your systems: because the
cryptographic key material stored in TPM2 devices cannot be extracted
(at least that's the theory), if you bind your hard disk encryption to
it, it means attackers cannot just copy your disk and analyze it
offline — they always need access to the TPM2 chip too to have a
chance to acquire the necessary cryptographic keys. Thus, they can
still steal your whole PC and analyze it, but they cannot just copy
the disk without you noticing and analyze the copy.
Moreover, you can bind the ability to unlock the harddisk to specific
software versions: for example you could say that only your trusted
Fedora Linux can unlock the device, but not any arbitrary OS some
hacker might boot from a USB stick they plugged in. Thus, if you trust
your OS vendor, you can entrust storage unlocking to the vendor's OS
together with your TPM2 device, and thus can be reasonably sure
intruders cannot decrypt your data unless they both hack your OS
vendor and steal/break your TPM2 chip.
Here's how you enroll your LUKS2 volume with your TPM2 chip:
# systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/sda5
This looks almost as straightforward as the two earlier sytemd-cryptenroll
command lines — if it wasn't for the --tpm2-pcrs=
part. With that option you can specify to which TPM2
PCRs you want to bind the enrollment. TPM2 PCRs are a set of
(typically 24) hash values that every TPM2 equipped system at boot
calculates from all the software that is invoked during the boot
sequence, in a secure, unfakable way (this is called
"measurement"). If you bind unlocking to a specific value of a
specific PCR you thus require the system has to follow the same
sequence of software at boot to re-acquire the disk encryption
key. Sounds complex? Well, that's because it is.
For now, let's see how we have to modify your /etc/crypttab
to
unlock via TPM2:
myvolume /dev/sda5 - tpm2-device=auto
This part is easy again: the tpm2-device=
option is what tells systemd-cryptsetup
to use the TPM2 metadata from the LUKS2 header
and to wait for the TPM2 device to show up.
Bonus: Recovery Key Enrollment
FIDO2, PKCS#11 and TPM2 security tokens and chips pair well with
recovery keys: since you don't need to type in your password everyday
anymore it makes sense to get rid of it, and instead enroll a
high-entropy recovery key you then print out or scan off screen and
store a safe, physical location. i.e. forget about good ol'
passphrase-based unlocking, go for FIDO2 plus recovery key instead!
Here's how you do it:
# systemd-cryptenroll --recovery-key /dev/sda5
This will generate a key, enroll it in the LUKS2 volume, show it to
you on screen and generate a QR code you may scan off screen if you
like. The key has highest entropy, and can be entered wherever you can
enter a passphrase. Because of that you don't have to modify /etc/crypttab
to make the recovery key work.
Future
There's still plenty room for further improvement in all of this. In
particular for the TPM2 case: what the text above doesn't really
mention is that binding your encrypted volume unlocking to specific
software versions (i.e. kernel + initrd + OS versions) actually sucks
hard: if you naively update your system to newer versions you might
lose access to your TPM2 enrolled keys (which isn't terrible, after
all you did enroll a recovery key — right? — which you then can use
to regain access). To solve this some more integration with
distributions would be necessary: whenever they upgrade the system
they'd have to make sure to enroll the TPM2 again — with the PCR
hashes matching the new version. And whenever they remove an old
version of the system they need to remove the old TPM2
enrollment. Alternatively TPM2 also knows a concept of signed PCR
hash values. In this mode the distro could just ship a set of PCR
signatures which would unlock the TPM2 keys. (But quite frankly I
don't really see the point: whether you drop in a signature file on
each system update, or enroll a new set of PCR hashes in the LUKS2
header doesn't make much of a difference). Either way, to make TPM2
enrollment smooth some more integration work with your distribution's
system update mechanisms need to happen. And yes, because of this OS
updating complexity the example above — where I referenced your trusty
Fedora Linux — doesn't actually work IRL (yet? hopefully…). Nothing
updates the enrollment automatically after you initially enrolled it,
hence after the first kernel/initrd update you have to manually
re-enroll things again, and again, and again … after every update.
The TPM2 could also be used for other kinds of key policies, we might
look into adding later too. For example, Windows uses TPM2 stuff to
allow short (4 digits or so) "PINs" for unlocking the harddisk,
i.e. kind of a low-entropy password you type in. The reason this is
reasonably safe is that in this case the PIN is passed to the TPM2
which enforces that not more than some limited amount of unlock
attempts may be made within some time frame, and that after too many
attempts the PIN is invalidated altogether. Thus making dictionary
attacks harder (which would normally be easier given the short length
of the PINs).
Postscript
(BTW: Yubico sent me two YubiKeys for testing and Nitrokey a Nitrokey
FIDO2, thank you! — That's why you see all those references to
YubiKey/Nitrokey devices in the text above: it's the hardware I had to
test this with. That said, I also tested the FIDO2 stuff with a
SoloKey I bought, where it also worked fine. And yes, you!, other
vendors!, who might be reading this, please send me your security
tokens for free, too, and I might test things with them as
well. No promises though. And I am not going to give them back, if you
do, sorry. ;-))