summaryrefslogtreecommitdiffstatshomepage
path: root/docs/tpm-unlock.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/tpm-unlock.md')
-rw-r--r--docs/tpm-unlock.md219
1 files changed, 186 insertions, 33 deletions
diff --git a/docs/tpm-unlock.md b/docs/tpm-unlock.md
index 0cd915b..be02edd 100644
--- a/docs/tpm-unlock.md
+++ b/docs/tpm-unlock.md
@@ -59,56 +59,209 @@ or boot software will produce the same measurements on the next boot. Keep the
disk passphrase available. No unattended hook relaxes protection or replaces
LUKS enrollments.
-## Unused NvPCR Measurements
+## NvPCR Measurements
-This host uses PCR 7 for root unlock. It does not use the default `cryptsetup`,
-`hardware`, `login`, or `verity` NvPCR measurements. Systemd 262 requires a signed
-initrd PCR policy for NvPCR initialization, which this boot setup does not provide.
-This is separate from the NV index that stores the `pcrlock` policy.
+This setup initializes the four systemd NvPCRs. It records hardware identity,
+the logged-in user, and the LUKS root unlock method and keyslot. It also records
+the root volume key in ordinary PCR 15. The verity NvPCR has no event on this
+host because it does not use dm-verity. Root unlock still uses only the existing
+PCR 7 `pcrlock` policy. The NvPCR indices are separate from that policy's index.
-Empty files in `etc/nvpcr/` mask the four vendor definitions. Empty unit files
-mask only `systemd-pcrproduct.service` and `systemd-pcrlogin@.service`. Keep these
-files at zero bytes: adding comments removes the mask. SRK setup and PCR 7
-policy maintenance remain active. No TPM index or LUKS keyslot is deleted.
-The mkinitcpio drop-in includes the masks in each rebuilt initramfs.
+Ukify signs an initrd PCR 11 policy with reference `initrd` and embeds its public
+key in each UKI. The `sbctl` mkinitcpio post hook signs the complete UKI for
+Secure Boot. Keep the PCR private key outside the repo and EFI System Partition
+(ESP). Do not regenerate it during updates.
-Deploy outside aibox, with the recovery passphrase available:
+### First Activation
-```sh
-just apply
-sudo mkinitcpio -P
-sudo sbctl sign-all
-sudo sbctl verify
-```
+Run these steps on Halley2. Keep the LUKS passphrase and pcrlock recovery PIN
+available without unlocking this laptop. Do not reboot until the requested test
+is agreed. Stop if any command fails.
+
+1. Install the declared Arch packages. A full Arch update may rebuild UKIs. If
+ it does, verify Secure Boot signing and automatic unlock on a separate,
+ approved reboot before taking the recovery copy below.
+
+ ```sh
+ sudo pacman -Syu --needed systemd-ukify efibootmgr sbsigntools
+ pacman -Q systemd systemd-ukify mkinitcpio
+ sudo sbctl verify
+ sudo /usr/lib/systemd/systemd-pcrlock --strict=yes --pcr=7 --location=770 predict
+ df -h /boot
+ ```
+
+ `systemd` and `systemd-ukify` must have the same package version. Check that
+ `/boot` can hold one more complete hardened UKI and temporary replacement
+ files. Leave enough free space for normal kernel updates.
+
+2. Save the current boot images and affected `/etc` files in a root-only backup.
+ Do this once, before `just apply`. Do not overwrite this backup on a retry.
+
+ ```sh
+ sudo bash -euo pipefail -c '
+ backup=/var/lib/dotfiles/tpm-nvpcr/backup
+ test ! -e "$backup"
+ install -d -m 0700 "$backup"
+ cp -a /boot/EFI/Linux/arch-linux-hardened*.efi \
+ /boot/EFI/Linux/arch-linux-lts*.efi "$backup/"
+ tar -C / -cpf "$backup/etc.tar" \
+ etc/nvpcr/cryptsetup.nvpcr etc/nvpcr/hardware.nvpcr \
+ etc/nvpcr/login.nvpcr etc/nvpcr/verity.nvpcr \
+ etc/systemd/system/systemd-pcrlogin@.service \
+ etc/systemd/system/systemd-pcrproduct.service \
+ etc/mkinitcpio.conf.d/60-no-nvpcr.conf \
+ etc/mkinitcpio.conf etc/kernel/cmdline \
+ etc/kernel/cmdline-linux-hardened
+ '
+ ```
+
+3. Copy and check a working recovery UKI. Use `--create-only` so this entry does
+ not change the normal EFI boot order. Read its entry number from `efibootmgr -v`.
+
+ ```sh
+ sudo cp -a /boot/EFI/Linux/arch-linux-hardened.efi \
+ /boot/EFI/Linux/arch-linux-hardened-nvpcr-recovery.efi
+ sudo sbverify --cert /var/lib/sbctl/keys/db/db.pem \
+ /boot/EFI/Linux/arch-linux-hardened-nvpcr-recovery.efi
+ sudo efibootmgr --create-only --disk /dev/nvme0n1 --part 1 \
+ --label 'Arch NvPCR Recovery' \
+ --loader '\EFI\Linux\arch-linux-hardened-nvpcr-recovery.efi'
+ sudo efibootmgr -v
+ ```
+
+ On an approved reboot, select this entry once with `efibootmgr --bootnext`
+ or the firmware menu. Confirm automatic unlock. Return to the normal entry.
+ The recovery copy is outside all mkinitcpio presets.
+
+4. Create a dedicated PCR signing key pair if neither file exists. Ukify refuses
+ to replace existing key files. Check permissions and that the keys match.
+
+ ```sh
+ sudo ukify --pcr-private-key=/etc/systemd/tpm2-pcr-private-key.pem \
+ --pcr-public-key=/etc/systemd/tpm2-pcr-public-key.pem genkey
+ sudo stat -c '%U:%G:%a %n' /etc/systemd/tpm2-pcr-private-key.pem
+ sudo openssl pkey -in /etc/systemd/tpm2-pcr-private-key.pem -pubout |
+ sudo cmp - /etc/systemd/tpm2-pcr-public-key.pem
+ ```
+
+ The private file must be `root:root:600`. If either file already exists,
+ verify the pair and do not run `genkey` again. Never copy the private key
+ into the repo, an initramfs, or the ESP.
-Stop if image generation or signing fails. Confirm that the rebuilt UKIs are
-signed before rebooting. No re-enrollment is required. The current boot's failed
-setup status can remain until the next boot; do not restart TPM setup merely
-to clear that status.
+5. Apply the repo files and remove only the prior masks. The deployment checks
+ the key pair, ukify version, and recovery image before it changes `/etc`.
+ Chezmoi does not delete files that were removed from its source directory;
+ `tpm-nvpcr-unmask` checks their exact old contents before removing them.
-After an approved reboot, confirm automatic unlock and inspect:
+ ```sh
+ just apply
+ just tpm-nvpcr-unmask
+ ```
+
+6. Build and sign all four candidate UKIs on the root filesystem. These
+ commands do not replace the active boot images.
+
+ ```sh
+ sudo install -d -m 0700 /var/lib/dotfiles/tpm-nvpcr/stage
+ sudo mkinitcpio -k /boot/vmlinuz-linux-hardened \
+ -U /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-hardened.efi \
+ --cmdline /etc/kernel/cmdline-linux-hardened \
+ --ukiconfig /etc/kernel/uki.conf
+ sudo mkinitcpio -k /boot/vmlinuz-linux-hardened \
+ -U /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-hardened-fallback.efi \
+ --cmdline /etc/kernel/cmdline-linux-hardened \
+ --ukiconfig /etc/kernel/uki.conf -S autodetect
+ sudo mkinitcpio -k /boot/vmlinuz-linux-lts \
+ -U /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-lts.efi \
+ --cmdline /etc/kernel/cmdline --ukiconfig /etc/kernel/uki.conf
+ sudo mkinitcpio -k /boot/vmlinuz-linux-lts \
+ -U /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-lts-fallback.efi \
+ --cmdline /etc/kernel/cmdline --ukiconfig /etc/kernel/uki.conf \
+ -S autodetect
+ just tpm-nvpcr-check \
+ /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-hardened.efi \
+ /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-hardened-fallback.efi \
+ /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-lts.efi \
+ /var/lib/dotfiles/tpm-nvpcr/stage/arch-linux-lts-fallback.efi
+ ```
+
+ The check reads `.pcrpkey`, `.pcrsig`, and `.cmdline` using ukify, then
+ verifies each Secure Boot signature with the enrolled `sbctl` certificate.
+ Stop on any mismatch. The `systemd-pcrextend` socket and early setup units
+ must be present in both initramfs variants.
+
+7. Copy the checked images to the ESP with temporary names, then rename them
+ into place. Do not reboot after a partial copy. Restore from the backup if
+ a copy or verification fails.
+
+ ```sh
+ sudo bash -euo pipefail -c '
+ for name in arch-linux-hardened.efi arch-linux-hardened-fallback.efi \
+ arch-linux-lts.efi arch-linux-lts-fallback.efi; do
+ install -m 0644 "/var/lib/dotfiles/tpm-nvpcr/stage/$name" \
+ "/boot/EFI/Linux/$name.next"
+ done
+ for name in arch-linux-hardened.efi arch-linux-hardened-fallback.efi \
+ arch-linux-lts.efi arch-linux-lts-fallback.efi; do
+ mv -f "/boot/EFI/Linux/$name.next" "/boot/EFI/Linux/$name"
+ done
+ '
+ sudo sbctl verify
+ just tpm-nvpcr-check /boot/EFI/Linux/arch-linux-hardened.efi \
+ /boot/EFI/Linux/arch-linux-hardened-fallback.efi \
+ /boot/EFI/Linux/arch-linux-lts.efi \
+ /boot/EFI/Linux/arch-linux-lts-fallback.efi
+ ```
+
+### Boot Checks
+
+After an approved reboot into a new UKI, confirm automatic unlock and run:
```sh
+just tpm-nvpcr-check
sudo journalctl -b --no-pager \
-u systemd-tpm2-setup-early.service \
- -u systemd-tpm2-setup.service \
+ -u systemd-pcrnvdone.service \
+ -u systemd-pcrproduct.service \
+ -u systemd-pcrlogin@1000.service \
+ -u systemd-cryptsetup@root.service \
-u systemd-pcrlock-make-policy.service
systemctl --failed --no-pager
-systemctl is-enabled systemd-pcrproduct.service systemd-pcrlogin@.service
+systemd-analyze nvpcrs
```
-The two measurement units must report `masked`. SRK setup must have no NvPCR
-initialization failures, and the policy must retain PCR 7 protection.
+The early setup and NvPCR separator must succeed. The `hardware`, `login`, and
+`cryptsetup` records must appear after their events; `verity` can stay at its
+initial value. Check that PCR 7 is still the only disk-unlock policy PCR.
+Boot-test hardened and LTS default and fallback UKIs with explicit approval.
+Then rebuild with `sudo mkinitcpio -P` and repeat a normal boot test. Keep the
+recovery UKI until these checks pass.
+
+### Rollback
+
+If a new image does not boot or automatic unlock fails, select the recovery
+entry and use the disk passphrase if needed. On the running host, restore the
+saved images and exact `/etc` files. Do not remove any TPM indices or keyslots.
+
+```sh
+sudo install -d -m 0700 /var/lib/dotfiles/tpm-nvpcr
+sudo touch /var/lib/dotfiles/tpm-nvpcr/rollback
+sudo bash -euo pipefail -c '
+ cp -a /var/lib/dotfiles/tpm-nvpcr/backup/arch-linux-hardened*.efi \
+ /var/lib/dotfiles/tpm-nvpcr/backup/arch-linux-lts*.efi /boot/EFI/Linux/
+'
+sudo tar -C / -xpf /var/lib/dotfiles/tpm-nvpcr/backup/etc.tar
+sudo rm -f /etc/kernel/uki.conf /etc/initcpio/install/nvpcr
+sudo systemctl daemon-reload
+sudo sbctl verify
+```
-To roll back, remove the four `/etc/nvpcr/*.nvpcr` masks listed above, the two
-empty unit files, and `/etc/mkinitcpio.conf.d/60-no-nvpcr.conf`. Remove the same
-files from the repo to prevent redeployment. Reload systemd, rebuild and sign
-the UKIs, and test at the next approved reboot. This restores the vendor
-behavior, including its errors if signed initrd PCR policies are still absent.
+Revert this task's repo commit before another `just apply`. The rollback marker
+blocks redeployment until then. Keep the key pair and recovery UKI for diagnosis.
Sources: [systemd 262 release notes](https://github.com/systemd/systemd/releases/tag/v262),
-[NvPCR setup](https://github.com/systemd/systemd/blob/v262/src/tpm2-setup/tpm2-setup.c),
-and [empty-file mask handling](https://github.com/systemd/systemd/blob/v262/src/basic/conf-files.c).
+[ukify](https://github.com/systemd/systemd/blob/v262/man/ukify.xml), and
+[systemd TPM measurement guide](https://github.com/systemd/systemd/blob/v262/docs/TPM2_PCR_MEASUREMENTS.md).
## Recovery