[Unlocking LUKS2 volumes with TPM2, FIDO2, PKCS#11 Security Hardware on systemd 
248](http://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html)

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](https://www.freedesktop.org/software/systemd/man/[email protected])
 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](https://www.freedesktop.org/software/systemd/man/systemd-cryptenroll.html).
 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](https://www.freedesktop.org/software/systemd/man/crypttab.html).
 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. ;-))

Reply via email to