This wiki was updated to MediaWiki 1.37. If you notice any issues, please report them to admin[at]opensuse.org

SDB:LUKS2, TPM2 and FIDO2

Jump to: navigation, search

Tested on openSUSE

Recommended articles

Icon-manual.png

Related articles

Icon-help.png

Warning: This document describes some Proof of Concepts. The final implementation is subject to change.

Situation

This article describes how to perform:

  • Disk encryption using Linux Unified Key Setup version 2 (LUKS2).
  • Disk decryption using Trusted Platform Module version 2.0 (TPM2) or Fast Identity Online version 2.0 (FIDO2).
Warning: FIDO2 tokens need to implement the hmac-secret extension.

Procedure

Current tooling:

  • yast2 4.4.47
  • cryptsetup 2.4.1
  • grub 2.0.6
  • systemd v249
  • dracut 055+suse.179.g3cf989c2

With these package versions we can apply the following scenarios:

Full-Disk Encryption

This method can be used with Secure Boot enabled and, in fact, it should be encouraged.

The current supported method to install an openSUSE system will Full-Disk Encryption is to encrypt the entire root volume, including /boot. Swap and /boot/efi remain unencrypted.

There is no way to boot a system with Full-Disk Encryption enabled without entering the password to the encrypted volume in GRUB2. GRUB2 doesn't support unsealing the key from the TPM. Even if it did, there is no way to retrieve the key safely. TPM objects are sealed by providing appropriate input to a preconfigured set of Platform Configuration Registers (PCRs). These registered are populated by providing data inputs associated with each one and a hash is generated based on the contents. PCRs 0-7 are computed by the system firmware. Higher PCRs may be used by the boot loader, operating system, and applications. The full specification can be found in the PC Client Specific Platform Firmware Profile Specification.

We'll only focus on a subset of these for this document.

The firmware populates PCR 4 after measuring the bootloader. PCR 7 measures whether the Secure Boot state has changed between enabled and disabled.

GRUB2 using the tpm module will provide the TPM with measurements when reading the kernel and initrd to PCR 8. It will provide measurements to PCR 9 when reading its own configuration, any additional commands executed, and the kernel command line.

Although Secure Boot will ensure that the kernel carries a valid signature and is trusted to execute on the host, the initrd is not signed. We require PCR 8 be populated to ensure it has not been tampered with. In order to avoid an attacker simply booting the system with init=/bin/bash to allow the initrd to unlock the volume and provide otherwise unauthenticated administrator access to the system, we require that PCR 9 be a known value.

GRUB2 needs to be able to read the kernel, initrd, and its own configuration to provide these measurements. It cannot read them without unlocking the encrypted volume. Thus the user must always provide the passphrase during the bootloader process.

Enabling TPM support in GRUB2 isn't wasted effort, though. In configuring the bootloader to perform the appropriate measurements, we gain the ability to be certain that the initrd is a known component and allow the operating system to mount the encrypted volume without providing the passphrase again.

In order to unlock the root volume, we should consider PCRs 4,7,8, and 9. Without measuring the kernel command line, an attacker could simply boot the system with init=/bin/bash and allow the initrd to unlock the volume automatically.

To enable tpm support in GRUB2, add the following to /etc/grub.d/00_header above the check for whether BTRFS snapshots are enabled before running update-bootloader --refresh to regenerate the GRUB2 configuration.

cat <<EOF
# The tpm module won't measure anything if it's not loaded.
# If it's not built into the grub binary, we'll need to load it
# before anything else is executed.
insmod tpm
EOF

Then add the ability to use the TPM to unlock the volume to the initrd, where $DEVICE should be substituted with the path to the partition containing the encrypted volume:

  1. Install the TPM2 tools.
    # zypper install tpm2.0-tools
  2. Find the entry for the LUKS2 volume in /etc/crypttab (it may appear referenced by its UUID) and add the tpm2-device= option.
    cr_root  $DEVICE  none  x-initrd.attach,tpm2-device=auto
  3. Regenerate the initrd.
    # dracut -f

At the next reboot and any reboot in which any of the measured components have changed, you will be required to enter the password for the volume. After a successful reboot, enroll the TPM.

# systemd-cryptenroll --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=4+7+8+9 $DEVICE
Warning: The TPM must be re-enrolled after any change that modifies the kernel, initrd, boot loader, or its configuration. Ensure that a regular passphrase is always configured and known to avoid losing access to your system.

Unencrypted boot partition

This scenario derives from the current approach to Full Disk Encrytion (FDE) with LUKS1: kernel and initrd worldwide readable.

The key is not stored in the initrd; the unlock is done via systemd-cryptsetup.

This is the most flexible approach, in terms of FIDO2, TPM2 and different algorithms. Here grub would not be involved in the decryption process itself.

Encryption using LUKS2

EFI disk layout example:

lsblk /dev/sda
NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda           253:0    0   32G  0 disk  
├─sda1        253:1    0  512M  0 part  /boot/efi    (EFI)
├─sda2        253:2    0    2G  0 part  /boot        (btrfs)
└─sda3        253:3    0 29,5G  0 part  
  └─cr-auto-1 254:0    0 29,5G  0 crypt /            (btrfs)

Steps:

  1. Boot using the installation media.
  2. Select the Installation option and press E to edit the entry.
  3. Add YAST_LUKS2_AVAILABLE=1 to the kernel command line (the one starting with "linux") and press Ctrl+X to continue.
  4. Within the Expert Partitioner, select "Start with Existing Partitions" to create the disk layout.
  5. For the root mount point (/) select "Encrypt Device" with the "Regular LUKS2" method.

Decryption using TPM2

Steps:

  1. Install the TPM2 tools.
    # zypper install tpm2.0-tools
  2. Enroll the LUKS2 volume with TPM device.
    # systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/sda3
    Warning: Using only PCR 7 does not protect against changes to the /boot partition, e.g. an attacker can boot a modified initrd and access the decrypted data! To include those in measurement as well, use PCRs 2, 4, 8 and 9. You will have to re-enroll after every kernel and bootloader update as well as initrd rebuilds.
  3. Find the entry for the LUKS2 volume in /etc/crypttab (it may appear referenced by its UUID) and add the tpm2-device= option.
    cr-auto-1  /dev/sda3  none  x-initrd.attach,tpm2-device=auto
  4. Regenerate the initrd.
    # dracut -f

Notes:

  • The enrollment using PCR 7 should not be used on non-EFI systems. See man systemd-cryptenroll for a more detailed explanation of PCR definitions.
  • The problem with changed PCR value still exists, but if the TPM validation fails, the user can unlock the system using a custom password or recovery key and enroll the TPM again with the new PCR value.

Decryption using FIDO2

Steps:

  1. Plug in the FIDO2 token.
  2. Install the libfido2 library.
    # zypper install libfido2-1
  3. Enroll the LUKS2 volume with the FIDO2 device.
    # systemd-cryptenroll --fido2-device=auto /dev/sda3
  4. Find the entry for the LUKS2 volume in /etc/crypttab (it may appear referenced by its UUID) and add the fido2-device= option.
    cr-auto-1  /dev/sda3  none  x-initrd.attach,fido2-device=auto
  5. Regenerate the initrd.
    # dracut -f

Notes:

  • Missing plymouth implementation: the system is silently waiting for FIDO2 input.
  • If the FIDO2 key is not available and the LUKS2 volume also has a passphrase or recovery key enrolled, the system will need to boot using another initrd without the libfido2 library loaded.

Encrypted boot partition

Warning: This setup is limited to EFI systems.
Warning: With the current state of grub2, we will cannot skip entering the decryption passphrase in the bootloader.

This is the most secure, but also most complex approach.

Encryption using LUKS2

EFI disk layout example:

lsblk /dev/sda
NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda           253:0    0   32G  0 disk  
├─sda1        253:1    0  512M  0 part  /boot/efi    (EFI)
├─sda2        253:2    0  128M  0 part  /boot/grub2  (ext2)
└─sda3        253:3    0 31,4G  0 part
  └─cr-auto-1 254:0    0 31,4G  0 crypt /            (btrfs)
Warning: Make sure that Secure Boot is disabled, otherwise you will not be able to load specific modules in grub.

Steps:

  1. Boot using the installation media.
  2. Select the Installation option and press E to edit the entry.
  3. Add YAST_LUKS2_AVAILABLE=1 to the kernel command line (the one starting with "linux") and press Ctrl+X to continue.
  4. Within the Expert Partitioner, select "Start with Existing Partitions" to create the disk layout.
  5. For the root mount point (/) select "Encrypt Device" with the "Regular LUKS2" method and "PBKDF2" (grub 2.0.6 only supports pbkdf2 key derivation).
  6. Boot into a Live ISO (grub2-install does not load modules properly yet, therefore we have to boot back into the live image to fix the bootloader).
  7. Mount all required partitions.
    # cryptsetup luksOpen /dev/sda3 luks-part
    # mount /dev/mapper/luks-part /mnt
    # mount /dev/sda1 /mnt/boot/efi
    # mount /dev/sda2 /mnt/boot/grub2
    # for i in /dev /dev/pts /proc /sys /run; do mount -B $i /mnt$i; done
  8. Change root to the mounted system.
    # chroot /mnt
  9. Install grub2-x86_64-efi.
    # zypper install grub2-x86_64-efi
  10. Install needed LUKS2 modules into grub.
    # grub2-install --target=x86_64-efi --modules="luks2 part_gpt cryptodisk gcry_rijndael pbkdf2 gcry_sha512 btrfs gcry_sha256 gcry_sha1 ext2 luks"
  11. Create the script luks2.sh with the following content:
    #!/bin/bash
    [ $# -lt 1 ] && exit 1
    CONFIG=$(mktemp /tmp/grub-config.XXXXX)
    cat >"$CONFIG" <<EOF
    cryptomount -u "$1"
    set prefix=(hd0,gpt2)
    set root=crypto0
    insmod normal
    normal
    EOF
    grub2-mkimage \
        -p '(hd0,gpt2)' \
        -O x86_64-efi \
        -c "$CONFIG" \
        -o /tmp/image \
        luks2 part_gpt cryptodisk gcry_rijndael pbkdf2 gcry_sha512 btrfs gcry_sha256 gcry_sha1 ext2 luks
    rm "$CONFIG"
  12. Run luks2.sh, passing the UUID of the encrypted root partition without any hyphens '-'. E.g.:
    # ./luks2.sh 4f68bce3e8cd4db196e7fbcaf984b709
  13. Copy new grub image to EFI partition.
    # cp /tmp/image /boot/efi/EFI/opensuse/grubx64.efi
  14. Generate a new grub config file.
    # grub2-mkconfig -o /boot/grub2/grub.cfg

Notes:

  1. grub2 needs to be improved in regards to LUKS2 detection (upstream patches in review).
  2. grub2 can only handle pbkdf2, argon2 will not come any time soon (the patch to allow allocating large chunks of memory dynamically is in review).
  3. grub2-install does not automatically load all required crypto modules yet, so they must be manually specified.

Decryption using TPM2

Notes:

  • grub2 needs support for verifying the TPM value.
  • Possibility to get locked out from the system in case the PCR value changes (e.g. during a firmware upgrade and the new value has not been deployed), also know as PCR fragility (or PCR brittleness).
  • Locked out of btrfs-snapshots in case the PCR-value changed.

Decryption using FIDO2

Notes:

  • The firmware would have to provide the correct USB drivers for the FIDO2 device to access tokens there, otherwise we need to include all required FIDO2 libraries and device port to our grub, which would result in a larger grub image.

See also

External links