This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| cert.pem | |
| cert.der | |
| key.pem |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Generate key/cert for MOK | |
| openssl req -new -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days $((365*30)) -subj '/CN=custom-sb-cert/' | |
| # DER format can be enrolled in UEFI if not using shim; for convenience, this is copied alongside the signed kernel image when running ./update-image | |
| openssl x509 -outform der -in cert.pem -out cert.der | |
| # If using shim, import of MOK to UEFI (will prompt for one-time password, requires reboot to UEFI to complete enrolment) | |
| mokutil --import cert.der |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # target directory within ESP | |
| TPMBOOT_EFI_OUT=/boot/efi/EFI/debian0 | |
| # NOTE: panic=0 is important for disabling the root shell in case of failure | |
| TPMBOOT_CMDLINE='root=/dev/mapper/debian--vg-root ro panic=0' | |
| # options to pass to `seal` and `unseal`; should contain a list of PCRs to use | |
| TPMBOOT_TPM2_INITRAMFS_TOOL_OPTS='-p 0,2,7' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| PREREQ="" | |
| prereqs() { | |
| echo "$PREREQ" | |
| } | |
| case $1 in | |
| prereqs) | |
| prereqs | |
| exit 0 | |
| ;; | |
| esac | |
| . /usr/share/initramfs-tools/hook-functions | |
| set -e | |
| copy_exec /usr/lib/x86_64-linux-gnu/libtss2-tcti-device.so.0 | |
| copy_exec /usr/bin/tpm2-initramfs-tool | |
| copy_exec /usr/bin/jq | |
| copy_exec "$(dirname "$(realpath "$0")")"/config | |
| copy_exec "$(dirname "$(realpath "$0")")"/tpm2-unseal | |
| # using header checksums to authenticate devices, since otherwise some other device could be used (with a different password) to impersonate a root/resume device such that the tpm key is still unlockable | |
| trusted_devices_luks2="$( | |
| for x in $(cut -f 1 -d ' ' /etc/crypttab); do | |
| # NOTE: only supporting luks2 since the relevant header size needs to be assumed (4096 bytes for luks2) | |
| (cryptsetup status "$x" | grep -q LUKS2) && cryptsetup status "$x" | |
| done | sed 's/^ *device: *//; t; d' | |
| )" | |
| for device in $trusted_devices_luks2; do | |
| # NOTE: authenticating based on the volume key digest, which generally shouldn't change (unless the device is reencrypted) | |
| cryptsetup luksDump --dump-json-metadata "$device" | jq -c '.digests | .[] |= (.keyslots = [])' | sha256sum | cut -f 1 -d ' ' | |
| done >"${DESTDIR}"/trusted-devices | |
| # disable autoactivation of LVM volumes, since otherwise an untrusted (even unencrpted) "root" or "resume" volume might be used | |
| echo 'global { event_activation = 0 }' >>"${DESTDIR}"/etc/lvm/lvm.conf | |
| cat >"${DESTDIR}"/scripts/local-block/trusted-devices-check << 'EOF' | |
| #!/bin/sh | |
| PREREQ="cryptroot" | |
| prereqs() { | |
| echo "$PREREQ" | |
| } | |
| case $1 in | |
| prereqs) | |
| prereqs | |
| exit 0 | |
| ;; | |
| esac | |
| for crypttab in /etc/crypttab /cryptroot/crypttab; do | |
| [ -e "$crypttab" ] || continue | |
| for name in $(cut -f 1 -d ' ' "$crypttab"); do | |
| [ -e /dev/mapper/"$name" ] || continue | |
| device="$(cryptsetup status "$name" | sed 's/^ *device: *//; t; d')" | |
| if cryptsetup luksDump --dump-json-metadata "$device" | jq -c '.digests | .[] |= (.keyslots = [])' | sha256sum | grep -q -f /trusted-devices; then | |
| lvm vgchange -a ay --devices /dev/mapper/"$name" | |
| else | |
| echo "$0: closing unknown crypt device: $name" >&2 | |
| cryptsetup close "$name" | |
| fi | |
| done | |
| done | |
| EOF | |
| chmod +x "${DESTDIR}"/scripts/local-block/trusted-devices-check | |
| # NOTE: this is annoyingly getting overridden because the script doesn't exist in one of the expected places ({/etc,/usr/share}/initramfs-tools/scripts) | |
| # NOTE: there's an extra hack in `tpm2-unseal` to add it back in at runtime | |
| (cache_run_scripts "${DESTDIR}"/scripts/local-block) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| dir="$(dirname "$(realpath "$0")")" | |
| . "$dir"/config | |
| check_script=/scripts/local-block/trusted-devices-check | |
| order_script="$(dirname "$check_script")"/ORDER | |
| if [ -e "$order_script" ] && ! grep -q "^$check_script" "$order_script"; then | |
| echo "$check_script" '$@' >>"$order_script" | |
| fi | |
| [ "$CRYPTTAB_TRIED" = "" ] && CRYPTTAB_TRIED=0 | |
| [ "$CRYPTTAB_TRIED" -gt 0 ] && exec /lib/cryptsetup/askpass Password: | |
| exec tpm2-initramfs-tool unseal $TPMBOOT_TPM2_INITRAMFS_TOOL_OPTS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -e | |
| dir="$(dirname "$(realpath "$0")")" | |
| . "$dir"/config | |
| # NOTE: debian's version of shimx64 has "grubx64.efi" hardcoded; reusing the name to avoid needing to build/sign a custom version | |
| image_out="$TPMBOOT_EFI_OUT"/grubx64.efi | |
| cert_out="$TPMBOOT_EFI_OUT"/grubx64.der | |
| vmlinuz="$(ls -tr /boot/vmlinuz-* | tail -1)" | |
| # check that selected kernel image is not from the future; reduce the chance of offline attacks against the (presumably unencrypted) /boot partition | |
| find "$vmlinuz" -mtime -0 -exec false {} + | |
| initrd="$(sed 's/\<vmlinuz\>/initrd.img/' <<< "$vmlinuz")" | |
| gen_vmlinuz() { | |
| # replace the UTF-16 "SecureBoot" string with something else in the kernel, so Linux doesn't detect the secureboot state and doesn't enable lockdown mode | |
| # NOTE: this works because the secureboot state is checked at an early stage in kernel startup, so the code is not compressed | |
| sed s/"$(sed 's/./\\x00&/g' <<< SecureBoot)"/"$(sed 's/./\\x00&/g' <<< ZecurePoot)"/ <"$vmlinuz" | |
| } | |
| for x in shimx64.efi fbx64.efi mmx64.efi; do cp /usr/lib/shim/"$x".signed "$TPMBOOT_EFI_OUT"/"$x"; done | |
| tmp="$(mktemp)" | |
| trap "rm -f $tmp" EXIT | |
| objcopy \ | |
| --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \ | |
| --add-section .cmdline=<(echo "$TPMBOOT_CMDLINE") --change-section-vma .cmdline=0x30000 \ | |
| --add-section .splash=/dev/null --change-section-vma .splash=0x40000 \ | |
| --add-section .linux=<(gen_vmlinuz) --change-section-vma .linux=0x2000000 \ | |
| --add-section .initrd="$initrd" --change-section-vma .initrd=0x3000000 \ | |
| /usr/lib/systemd/boot/efi/linuxx64.efi.stub "$tmp" | |
| sbsign --key "$dir"/key.pem --cert "$dir"/cert.pem "$tmp" --output "$image_out" | |
| cp "$dir"/cert.der "$cert_out" | |
| echo Success |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -e | |
| dir="$(dirname "$(realpath "$0")")" | |
| . "$dir"/config | |
| # small sanity check that we're currently booted in the secure system | |
| if ! grep -q 'panic=0' /proc/cmdline; then | |
| echo "Not booted securely. You probably don't want to create a key in this state." | |
| exit 1 | |
| fi | |
| # NOTE: this key slot is assumed to be unused for other purposes, since it gets wiped without a prompt | |
| key_slot=23 | |
| new_key="$(tpm2-initramfs-tool seal $TPMBOOT_TPM2_INITRAMFS_TOOL_OPTS)" | |
| for x in $(grep tpm2-unseal /etc/crypttab | cut -f2 -d' '); do | |
| # no point in trying to make this atomic, since at this point the old key has already been forgotten by the TPM | |
| cryptsetup luksKillSlot --batch-mode "$x" "$key_slot" || true | |
| cryptsetup luksAddKey --new-key-slot "$key_slot" "$x" <(echo -n "$new_key") | |
| done | |
| echo Success |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment