heads/initrd/bin/kexec-insert-key
HardenedVault 8a60930c6b
Make the path to crypttab within initramfs overridable
Not all distro put crypttab under /etc/ within initramfs, but finding it at
runtime needs unpacking, which may be hard to do, so it is made overridable
with a file at /boot/kexec_initrd_crypttab_path.txt, whose content could be
obtained with $ cpio -t < ${uncompressed_initrd} | grep crypttab .

The "target" field of the record within the crypttab stored in the root
file system for the luks container which is going to be unlocked via
kexec-insert-key should be modified into the same "luks-$uuid" format,
otherwise the boot sequence will get stuck when OS is trying to unlock them
again, in order to map them according to "target" fields written in the
crypttab stored in the root fs.
2023-01-27 12:56:32 -05:00

102 lines
3.2 KiB
Bash
Executable File

#!/bin/sh
# Unseal a disk key from TPM and add to a new initramfs
set -e -o pipefail
. /etc/functions
TMP_KEY_DEVICES="/tmp/kexec/kexec_key_devices.txt"
TMP_KEY_LVM="/tmp/kexec/kexec_key_lvm.txt"
INITRD="$1"
if [ -z "$INITRD" ]; then
die "Usage: $0 /boot/initramfs... "
fi
if [ ! -r "$TMP_KEY_DEVICES" ]; then
die "No devices defined for disk encryption"
fi
if [ -r "$TMP_KEY_LVM" ]; then
# Activate the LVM volume group
VOLUME_GROUP=`cat $TMP_KEY_LVM`
if [ -z "$TMP_KEY_LVM" ]; then
die "No LVM volume group defined for activation"
fi
lvm vgchange -a y $VOLUME_GROUP \
|| die "$VOLUME_GROUP: unable to activate volume group"
fi
# Measure the LUKS headers before we unseal the disk key
cat "$TMP_KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \
|| die "LUKS measure failed"
# Unpack the initrd and fixup the crypttab
# this is a hack to split it into two parts since
# we know that the first 0x3400 bytes are the microcode
INITRD_DIR=/tmp/secret/initrd
SECRET_CPIO=/tmp/secret/initrd.cpio
# Not all distro put crypttab under /etc/ within initramfs, but finding it at
# runtime needs unpacking, which may be hard to do, so it is made overridable
# with a file at /boot/kexec_initrd_crypttab_path.txt, whose content could be
# obtained with $ cpio -t < ${uncompressed_initrd} | grep crypttab .
bootdir=$(dirname "$INITRD")
if [ -r $bootdir/kexec_initrd_crypttab_path.txt ]; then
crypttab_path=$(cat $bootdir/kexec_initrd_crypttab_path.txt)
else
crypttab_path=etc/crypttab
fi
mkdir -p "$INITRD_DIR/$(dirname $crypttab_path)"
# Attempt to unseal the disk key from the TPM
# should we give this some number of tries?
unseal_failed="n"
if ! kexec-unseal-key "$INITRD_DIR/secret.key" ; then
unseal_failed="y"
echo "!!! Failed to unseal the TPM LUKS disk key"
fi
# Override PCR 4 so that user can't read the key
tpm extend -ix 4 -ic generic \
|| die 'Unable to scramble PCR'
# Check to continue
if [ "$unseal_failed" = "y" ]; then
confirm_boot="n"
read \
-n 1 \
-p "Do you wish to boot and use the disk recovery key? [Y/n] " \
confirm_boot
if [ "$confirm_boot" != 'y' \
-a "$confirm_boot" != 'Y' \
-a -n "$confirm_boot" ] \
; then
die "!!! Aborting boot due to failure to unseal TPM disk key"
fi
fi
echo '+++ Building initrd'
# pad the initramfs (dracut doesn't pad the last gz blob)
# without this the kernel init/initramfs.c fails to read
# the subsequent uncompressed/compressed cpio
dd if="$INITRD" of="$SECRET_CPIO" bs=512 conv=sync \
|| die "Failed to copy initrd to /tmp"
# The "target" field of the record within the crypttab stored in the root
# file system for the luks container which is going to be unlocked via
# kexec-insert-key should be modified into the same "luks-$uuid" format,
# otherwise the boot sequence will get stuck when OS is trying to unlock them
# again, in order to map them according to "target" fields written in the
# crypttab stored in the root fs.
if [ "$unseal_failed" = "n" ]; then
# overwrite crypttab to mirror the behavior for in seal-key
for uuid in `cat "$TMP_KEY_DEVICES" | cut -d\ -f2`; do
# In Debian, the "luks" option at last should not be omitted
echo "luks-$uuid UUID=$uuid /secret.key luks" >> "$INITRD_DIR/$crypttab_path"
done
( cd "$INITRD_DIR" ; find . -type f | cpio -H newc -o ) >> "$SECRET_CPIO"
fi