heads/initrd/bin/kexec-insert-key
Francis Lam 7cec25542d
Allow boot without unseal of TPM LUKS key
Closes issue 

Also changed to procedure to show LVM volume groups and block
device ids to aid in choosing the right combination during the
TPM LUKS key sealing process.
2017-09-02 14:13:29 -04:00

82 lines
2.3 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 /etc/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
mkdir -p "$INITRD_DIR/etc"
# 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"
if [ "$unseal_failed" = "n" ]; then
# overwrite /etc/crypttab to mirror the behavior for in seal-key
for uuid in `cat "$TMP_KEY_DEVICES" | cut -d\ -f2`; do
echo "luks-$uuid UUID=$uuid /secret.key" >> "$INITRD_DIR/etc/crypttab"
done
( cd "$INITRD_DIR" ; find . -type f | cpio -H newc -o ) >> "$SECRET_CPIO"
fi