diff --git a/docs/04_TPM_UNLOCKING.md b/docs/04_TPM_UNLOCKING.md index c72d6c1..daed812 100644 --- a/docs/04_TPM_UNLOCKING.md +++ b/docs/04_TPM_UNLOCKING.md @@ -1,3 +1,178 @@ # TPM Unlocking -WIP +This will explain how to set up TPM (Trusted Platform Module) based automatic unlocking of your encrypted partition(s). +Encryption usually requires that you manually type the password in each time you boot. This can however be pretty +annoying (especially if you use a long password, like I do). This guide aims to fix this problem, without compromising +security. + +Once finished, this will basically store another decryption key(s) to your encrypted partition(s) in the TPM module. +During boot, while in initrd, we will request this decryption key from TPM, which will only do so under certain +conditions, to ensure safety. + +The guide assumes you have already a working NixOS system, that uses LUKS encryption. You will also need to set up +secure-boot, as described in [SECURE_BOOT](./03_SECURE_BOOT.md). This is a requirement, as while it is possible to set +up TPM unlocking without it, doing so is incredibly insecure, and might lead to unauthorized users getting TPM to +release your decryption keys. + +> [!WARNING] +> This solution will be mostly safe, however, it is technically possible to hook up wires to the motherboard, to listen +> to the communication coming from the TPM chip. In that case, the attacker would be able to observe the key as it gets +> released by the chip. They could then take out your SSD/HDD, and mount it on their machine, using these obtained keys +> to decrypt the contents. See: +> +> If you can't afford to be vulnerable to this type of attack, you can still follow through with this, however instead +> of the TPM seamlessly releasing the decryption password, you can require a password to be entered, without which TPM +> won't release the decryption password. +> +> This can be useful if you use a very long encryption passwords, and you want to be able to enter a shorter passphrase, +> or a PIN code instead (TPM has brute-force protection, so the PIN isn't actually that unsafe to use). + +## Check if you actually have the TPM module + +First, you will want to verify that your machine even has the TPM module. To do so, you can use the following command: + +```shell +bootctl status +``` + +You should see `TPM2 Support: yes` in the output. + +## Enable TPM2 support + +First, we will want to enable the TPM support in our configuration: + +```nix +# Points TPM2TOOLS_TCTI and TPM2_PKCS11_TCTI to /dev/tpmrm0 +# and allows you to read and write to /dev/tpmrm0 +security.tpm2.enable = true; + +# Tools we will need to interact with the TPM module +environment.systemPackages = with pkgs; [ tpm2-tss tpm2-tools ]; + +# Use systemd in initrd. Only systemd based initrd systems can request data from the TPM module, +# busybox based ones do not have support for this. +boot.initrd.systemd.enable = true; +``` + +## Choosing PCRs + +PCR stands for Platform Configuration Register, and all TPM v2 modules have a bunch of these registers, which hold +hashes about the system's state. These registers are read-only, and their value is set by the TPM module itself. + +The data held by the TPM module (our LUKS encryption key) can then only be accessed when all of the selected PCR +registers contain the expected values. You can find a list of the PCR registers on [Arch +Wiki](https://wiki.archlinux.org/title/Trusted_Platform_Module#Accessing_PCR_registers). + +You can look at the current values of these registers with this command: + +```bash +systemd-analyze pcrs +``` + +For our purposes, we will choose these: + +- **PCR0:** Hash of the UEFI firmware executable code (may change if you update UEFI) +- **PCR7:** Secure boot state - contains the certificates used to validate each boot application +- **PCR12:** Overridden kernel command line, credentials + +> [!IMPORTANT] +> If you're using a boot loader (rather than booting directly from the Unified Kernel Images - EFI files), it is crucial +> that we choose all 3, including PCR12, as many tutorials only recommend 0 and 7, which would however lead to a +> security hole, where an attacker would be able to remove the drive with the (unencrypted) EFI partition, and modify +> the boot loader config. (With systemd-boot, this would be `loaders/loader.conf`). +> +> From there, the attacker could simply add a kernel argument like `init=/bin/bash`, or just enable editor support, +> allowing them to edit the parameters from the boot menu on the fly (This is actually the default for systemd-boot on +> NixOS, editor support is enabled). This would then bypass systemd as the init system and instead make the kernel run +> bash executable as the PID=1 (init) program. This would mean you would get directly into bash console that is running +> as root, without any need to enter a password. +> +> This wouldn't violate secure boot, as the `.efi` image files were unchanged, and are still signed, so the attacker +> would be able to boot into the system without issues. +> +> However, with PCR12, this is prevented, as it detects that the kernel cmdline arguments which were used, and if they +> don't match the recorded parameters during enrollment, TPM will not release the key. +> +> The nice thing about also selecting PCR12 is that it will actually allow us to securely keep systemd-boot editor +> support, which can be very useful for debugging, as all that will happen if we do edit the kernel command line will be +> that the TPM module will not release the credentials, and the initrd will just ask us to enter the password manually. + +Optionally, you may also consider these: + +- **PCR1:** Hash of the UEFI firmware data (changes when you change your BIOS settings) +- **PCR4:** Boot manager (changes when you change the boot manager) + +## Enroll a new key into TPM + +The following command will enroll a new randomly generated key into the TPM module and add it as a new keyslot of the +specified LUKS2 encrypted device (make sure to use the path to your device, it might not be the same as the one I'm +using): + +```shell +sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7+12 /dev/disk/by-label/NIXCRYPTFS +``` + +> [!NOTE] +> If you already had something in the tpm2 module, you'll want to add `--wipe-slot=tpm2` too. + +> [!NOTE] +> If you're extra paranoid, you can also provide `--tpm2-with-pin=yes`, to prompt for a PIN code on each boot. +> +> I have mentioned why you may want to do this in the beginning. + +You will now be prompted for an existing LUKS password (needed to add a new LUKS keyslot). + +## Reboot + +All that remains now is rebooting. The system should now get unlocked automatically, without prompting for the password. + +If you're using a bootloader, I'd recommend also trying to modify the kernel parameters, to make sure that TPM does not +release the key anymore, and you will be prompted to enter it manually. + +## Remove existing key + +Once you have confirmed that TPM unlocking is working, you can now optionally get rid of your original LUKS key. +Since the passphrase generated by systemd-cryptenroll is guaranteed to have a high encryption, getting rid of your, likely much less secure, chosen key can be a good idea, as it further improves your chances if someone attempts a brute-force decryption of your drive. + +That said, if you wish to proceed with this, I **heavily** recommend first creating an equally secure recovery key, so +that you have a way to decrypt your data from the drive in case your computer breaks. To generate a recovery key, you +can actually also just use `systemd-cryptenroll` (though you can also do it manually with `cryptsetup`): + +```shell +systemd-cryptenroll /dev/disk/by-label/NIXCRYPTFS --recovery-key +``` + +This will give you a randomized key, using characters that are easy to type. You will even be given a QR code that can +be scanned directly to save the password on your phone. + +Before proceeding with removing your own key, let's first make absolutely certain that the recovery key you saved does +in fact work. Without doing this, you may get locked out! + +```shell +cryptsetup luksOpen /dev/disk/by-label/NIXCRYPTFS crypttemp # enter the recovery key +cryptsetup luksClose crypttemp +``` + +If this worked, proceed to: + +```shell +cryptsetup luksRemoveKey /dev/disk/by-label/NIXCRYPTFS # Enter your key to be deleted +``` + +## Removing the key from TPM + +In case you'd ever want to remove the LUKS key from TPM, you can do so simply with: + +```bash +csystemd-cryptenroll --wipe-slot=tpm2 +``` + +This will actually also remove the LUKS key from the `/dev/disk/by-label/NIXCRYPTFS` device. + +## Sources / Attribution + +- +- +- +- +-