Skip to content

luks: automatic tpm unlocking#134577

Closed
cwyc wants to merge 1 commit intoNixOS:masterfrom
cwyc:tpmluks-persistentonly-rebased
Closed

luks: automatic tpm unlocking#134577
cwyc wants to merge 1 commit intoNixOS:masterfrom
cwyc:tpmluks-persistentonly-rebased

Conversation

@cwyc
Copy link
Contributor

@cwyc cwyc commented Aug 18, 2021

Motivation for this change

This is an attempt to implement TPM unlocking for LUKS volumes.

The method is based on this guide: https://threat.tevora.com/secure-boot-tpm-2/

Set it up by generating a keyfile, registering it in a LUKS keyslot, and storing it in the TPM sealed with your selected PCRs:

dd if=/dev/urandom of=secret.bin bs=1 count=32

cryptsetup luksAddKey /dev/my-disk secret.bin #or cryptsetup luksFormat /dev/my-disk --key-file secret.bin

tpm2_pcrread sha256:0,2,3,7 -o pcrs.bin
tpm2_createpolicy --policy-pcr -l sha256:0,2,3,7 --pcr pcrs.bin --policy policy.digest
tpm2_createprimary -g sha256 -G rsa --key-context primary.context
tpm2_create -g sha256 --public obj.pub --private obj.priv --parent-context primary.context --policy policy.digest -i secret.bin
tpm2_load --parent-context primary.context --public obj.pub --private obj.priv --key-context load.context
tpm2_evictcontrol --object-context load.context 
# This will output a handle such as "0x81000000", which points to where our keyfile is saved in the TPM's non-volatile memory.
# Don't forget to delete secret.bin.

Then, specify the handle and PCRs in your system configuration:

{
  boot.initrd.luks.devices.root = {
    device = "/dev/my-disk";
    tpm2KeyFile = {
      authString = "pcr:sha256:0,2,3,7";
      persistentObject = "0x81000000";
    };
  };
}

Once the system is rebuilt, it should unseal the volume without any intervention if the PCR values check out, or fall back to a password prompt.

I also have a version that supports transient keyfiles (stored on a disk but encrypted by the TPM) https://github.com/cwyc/nixpkgs/commits/tpmluks, but it's not working.

It's not a very elegant solution. Ideally, it should use systemd-cryptsetup, which can handle TPM unlocking without directly messing around with tpm commands, as well as replace the existing GPG, FIDO2, and Yubikey code. But it doesn't have a standalone executable.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • 21.11 Release Notes (or backporting 21.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module should do
  • Fits CONTRIBUTING.md.

@github-actions github-actions bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` labels Aug 18, 2021
@cwyc cwyc marked this pull request as draft August 18, 2021 00:29
@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. labels Aug 18, 2021
@cwyc cwyc force-pushed the tpmluks-persistentonly-rebased branch from 447359a to 24a3f6b Compare August 18, 2021 00:50
@Mic92 Mic92 requested review from andir and grahamc August 18, 2021 05:30
@cwyc cwyc force-pushed the tpmluks-persistentonly-rebased branch 2 times, most recently from 65c3cbb to 7aa8757 Compare August 19, 2021 06:50
@cwyc cwyc force-pushed the tpmluks-persistentonly-rebased branch from 7aa8757 to e459262 Compare August 20, 2021 04:16
@flokli flokli requested a review from arianvp August 22, 2021 18:06
@flokli
Copy link
Member

flokli commented Aug 22, 2021

@cwyc reading through http://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html, could we also use systemd-cryptenroll (depends on #131618) for this?

@cwyc
Copy link
Contributor Author

cwyc commented Aug 22, 2021

@Floki I also think systemd-cryptsetup is an ideal solution.
But as I understand it, it's not as simple as copy_bin_and_libs-ing an executable to the initrd, and then calling it from the script generated in luksroot.nix.
Rather, the decryption functionality is embedded in systemd, which automatically reads volume configurations in a /etc/crypttab using systemd-cryptsetup-generator, and carries out what it specifies.
So, to use systemd-cryptsetup we would have to transition all our boot-time functions from a initrd based on a script generated by nixos running on busybox utils, to one managed by systemd, which is out of my scope.

@cwyc cwyc marked this pull request as ready for review August 22, 2021 23:36
@cwyc cwyc marked this pull request as draft August 22, 2021 23:36
@zhaofengli
Copy link
Member

I also think systemd-cryptsetup is an ideal solution.
But as I understand it, it's not as simple as copy_bin_and_libs-ing an executable to the initrd, and then calling it from the script generated in luksroot.nix.
Rather, the decryption functionality is embedded in systemd, which automatically reads volume configurations in a /etc/crypttab using systemd-cryptsetup-generator, and carries out what it specifies.
So, to use systemd-cryptsetup we would have to transition all our boot-time functions from a initrd based on a script generated by nixos running on busybox utils, to one managed by systemd, which is out of my scope.

This is what #120015 is doing. What's proposed here seems reasonable as a stop-gap solution before we switch to systemd for stage-1 (which may be a while).

@flokli
Copy link
Member

flokli commented Aug 24, 2021

I'm a bit hesitant to add this now.

Are we sure we do use the TPM the same way systemd-cryptenroll uses it? So could we switch to /etc/crypttab and all the systemd bits if systemd ended up in initrd?

@cwyc
Copy link
Contributor Author

cwyc commented Aug 29, 2021

@Floki Yeah, it's not going to be a smooth transition from this method to systemd-cryptenroll. Here the user has to specify the handle and pcrs, with systemd I believe it's stored in the LUKS header. You'd have to remove the key and re-register it to convert from one to the other.

Though I've noticed archwiki mentions that systemd-cryptsetup actually does have an executable:

To test that the key works, run the following command while the LUKS volume is closed:
/usr/lib/systemd/systemd-cryptsetup attach mapping_name /dev/sdX - tpm2-device=/path/to/tpm2_device

So theoretically we can use that in the boot script now, and transition to the function built into systemd when we get a systemd initrd.

But I can't find *any* other documentation on how to use this program. Running it with "--help" just gives me This program requires at least two arguments.. So I feel like they really don't want us calling this executable directly, and its behaviour could change in weird ways later. Though I could take a peek in the source code.

@flokli
Copy link
Member

flokli commented Aug 29, 2021

I don't think we should introduce our own TPM LUKS way of doing things, especially considering we want to switch to systemd-in-initrd. If we can use systemd-cryptsetup to do most of this already today (and migrate to using it more natively later), we should.

Also, even without systemd in initrd, we can probably even make use of other (non-boot disks) being encrypted with keys stored in the TPM, similarly to how we already now support systemd-cryptsetup's /etc/crypttab. See https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/systemd.nix#L154-L163, which exercises this feature.

If we're worried about regressions, we can probably even add a VM test for this, considering QEMU does support emulating a TPM2.

@cwyc
Copy link
Contributor Author

cwyc commented Aug 29, 2021

Sounds good. I've already been using TPM with QEMU to develop this patch. Once it's ready I'll open another PR.

@aviallon
Copy link
Contributor

aviallon commented Nov 6, 2023

@cwyc I believe there isn't any support for LUKS encrypted root + TPM yet.
Couldn't this be added back again?

@cwyc
Copy link
Contributor Author

cwyc commented Nov 6, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants