File HOWTO.luks-keyfile of Package trustedgrub2

= HowTo: Sealing and unsealing a LUKS keyfile with TrustedGrub2

 Michael Chang, <mchang@suse.com>

This article will provde the procedure for using TPM and the 'measure boot'
result to seal a key file for locking LUKS encrypted disk, the sealed key can
be unsealed later if the measure boot reveals a immutable system state,
otherwise the unsealing fails as the system could have been tampered or at
least in a state that differs with the one you sealing the key previously. It
is then worthwhile to stop and having a look on your system for what has
changed and why, then proceed with reverting the changes or sealing the file
again with the new state if all the changes are asserted to be intended and
safe.

To accomplish this, you need to install two packages:

1. TrustedGrub2, needed to performs measure boot by extending hash of critical
components into TPM's pcr register. It also provides some TPM related commands
in bootloader. [1]

2. tpm-tools, the utilties that implements the full TCG stack under Linux to
operate and manipulate on TPM device. It is part of 'trousers' project. [2]

In SUSE/openSUSE, zypper made it easy for installing packages.

  zypper in trustedgrub2-i386-pc
  zypper in tpm-tools

Once after the package gets installed, you have to install TrustedGrub2
bootloader images on your system by this: 

  grub2-install \
  --directory=/usr/lib/trustedgrub2/i386-pc \
  --target=i386-pc /dev/disk/by-id/ata-WDC_WD3200BEVS-08VAT2_WD-WX30AB992593

And enable the tcsd, daemon that manages Trusted Computing resources that all
requests for TPM should go through.

  systemctl start tcsd
  systemctl enable tcsd

If you have problems starting tcsd,  check your bios support for TPM device by
checking any options to enable it. If all settings are good to go and still
don't work, check your kernel has compiled with tpm devce support and modules
are loaded.

Take ownership, enable and activate the TPM device. I won't go through these
command details so please RTFM. :)

  tpm_takeownership -y -z
  tpm_setenable -e -z

Reboot the system, the TrustedGrub2 should start and in the final booted system
you can read the pcr for measured system component hashes.

  reboot
  cat /sys/class/tpm/tpm0/device/pcrs 

Here is what it looks like on my system.

PCR-00: 86 80 80 CD F1 B8 37 3E 88 82 BF C9 5B FC 77 36 DC 8A 6A FD 
PCR-01: 63 00 78 62 C0 C9 53 C0 1A 04 3C C7 1D 4A 92 72 ED 2F 9C A3 
PCR-02: F0 52 17 DD C9 32 7C 48 FD 5A 78 4B A0 0A E2 9E 58 E6 97 3E 
PCR-03: 3A 3F 78 0F 11 A4 B4 99 69 FC AA 80 CD 6E 39 57 C3 3B 22 75 
PCR-04: 27 EE C1 86 68 21 F0 40 E5 67 92 AA 80 39 49 4A F1 40 5C DD 
PCR-05: BE 7B 73 7B B9 EA 1E DE E0 3C E1 38 3A 83 69 37 18 8F FC 07 
PCR-06: 58 5E 57 9E 48 99 7F EE 8E FD 20 83 0C 6A 84 1E B3 53 C6 28 
PCR-07: 3A 3F 78 0F 11 A4 B4 99 69 FC AA 80 CD 6E 39 57 C3 3B 22 75 
PCR-08: 1D 6D 3C F3 C3 D4 CA 9E A6 29 BC F5 37 F3 C3 45 6A 1A F4 C4 
PCR-09: BD EE 55 59 B2 DE 6A 2D 2D 96 39 AA 28 4C F4 8B E5 DB AD 83 
PCR-10: 0C E0 17 81 CD C7 A6 AD DD 3C 38 8E 7D 73 6E F9 FF 7E A5 47 
PCR-11: B1 A6 F3 26 A7 95 FC DB C1 22 85 62 B9 B3 69 55 06 22 95 65 
PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
PCR-13: 93 84 4B FC 91 EC A0 A0 57 B7 A3 0C 31 61 95 43 60 00 C6 F1 
PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

Roughly, the selected components measured into each PCR numbers could be
(quoted from TrustedGrub2 README):

PCR 0-7 Measured by BIOS
PCR 8 First sector of TrustedGRUB2 kernel (diskboot.img)
PCR 9 TrustedGRUB2 kernel (core.img)
PCR 10 Loader measurements - currently linux-kernel, initrd, ntldr, chainloader, multiboot, module
PCR 11 Contains all commandline arguments from scripts (e.g. grub.cfg) and those entered in the shell
PCR 12 LUKS-header
PCR 13 Parts of GRUB2 that are loaded from disk like GRUB2-modules // TODO: fonts, themes, locales

Now it's time to prepare the LUKS encrypted disk, assuming the disk device is
/dev/sdb.

  cryptsetup luksFormat /dev/sdb
  cryptsetup luksOpen /dev/sdb Luks
  mkfs.ext2 /dev/mapper/Luks 
  mount /dev/mapper/Luks /mnt
  echo 'foo' > /mnt/bar
  umount /mnt
  cryptsetup luksClose Luks 

Now you entered a passphrase, which can be used to get your data back in case
you lost your key-file. Of course you could avoid the passphrase and provide
keyfile directly via --key-file during luksFormat. That's fine, as it seems to
be more secure if using a keyfile generated by random number, but it's annoying
to me providing a file holds passphrase as cleartext for luksOpen everytime at
risk of exposing it on occasions and is what we want to avoid and solve here.

Now you can create the key-file with random contents in it.

  dd if=/dev/urandom of=/root/keyfile bs=16 count=1

Add the keyfile to the LUKS key slot.
  cryptsetup luksAddKey /dev/sdb /root/keyfile 

Check if it works

  cryptsetup luksOpen --key-file=/root/keyfile /dev/sdb Luks
  mount /dev/mapper/Luks /mnt
  cat /mnt/bar
  umount /mnt

If the key-files works, it's time to sealing it by your current system status,
that is represented by system's pcr values that you wouldn't expect to change.

Here I count in all pcr numbers (1-13) that contain measured values.

  tpm_sealdata -z -i /root/keyfile -o /root/keyfile.seal -p1 -p2 -p3 -p4 -p5 -p6 -p7 -p8 -p9 -p10 -p11 -p12 -p13

Now, you can remove /root/keyfile from your system and hide it away in a
secret place with better protection.

From now on you should use keyfile.seal and placing it on a removable usb
stick, with ciphertext even the stick accidentally handed over to people can't
read the passphrase in it, unless they can boot into your system with physical
presence and also can creep into system with root privilege to take control the
TPM WITHOUT the help of any tweaked process or running hacker programs in the
boot process, which turns out to be a very difficult and insane job. ;)

The step to unseal the keyfile and unlock the encrypted disk now looks like:

  ( plug USB stick )
  mount /dev/sdc /media/usb
  tpm_unsealdata -z -i /media/usb/keyfile.seal | cryptsetup luksOpen --key-file - /dev/sdb Luks
  umount /dev/sdc
  ( unplug the USB stick )

Optionally, you can remove your passphrase entered during luksFormat, it
enhances the security as a tradeoff to potential data loss by losing the
initial key-file. 
  
  cryptsetup luksRemoveKey /dev/sdb
  ( type your passphrase to remove )

Finally, it's also possible to perform unsealing the keyfile in bootloader to
unlock the disk. You need to be careful though when sealing the keyfile can
only be up to pcr9 as that's how far bootloader execution reaches at that time.

  tpm_sealdata -z -i /root/keyfile -o /root/keyfile-pre.seal -p1 -p2 -p3 -p4 -p5 -p6 -p7 -p8 -p9

Here is sample config, please note that 'cryptmount -k ... -s'
only provided by TrustedGrub2.

  menuentry 'READ LUKS AUTO' {
  
    insmod ext2
    search --file --set=keydev /keyfile-pre.seal

    if [ -f ${keydev}/keyfile-pre.seal ]; then
      insmod ext2
      insmod cryptodisk
      insmod luks
      insmod gcry_rijndael
      insmod gcry_sha1
      cryptomount -u ac003bec1b6a4759b620822bd255a90f -k ${keydev}/keyfile-pre.seal -s
      search --no-floppy --fs-uuid --set=root --hint='cryptouuid/ac003bec1b6a4759b620822bd255a90f' 23b0a412-f781-4979-b9fd-5c8a8b5ffd45
      cat /bar
    else
      echo "No Key File !!!!"
    fi
  }

[1] https://github.com/Sirrix-AG/TrustedGRUB2
[2] http://trousers.sourceforge.net/
openSUSE Build Service is sponsored by