heads/initrd/bin/kexec-insert-key

115 lines
4.0 KiB
Plaintext
Raw Normal View History

#!/bin/bash
# Unseal a disk key from TPM and add to a new initramfs
set -e -o pipefail
. /etc/functions
TRACE_FUNC
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
bootdir=$(dirname "$INITRD")
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
echo "!!! Failed to unseal the TPM LUKS disk key"
fi
# Override PCR 4 so that user can't read the key
DEBUG "Extending TPM PCR 4 to prevent further secret unsealing"
tpmr extend -ix 4 -ic generic ||
die 'Unable to scramble PCR'
# Check to continue
if [ "$unseal_failed" = "y" ]; then
confirm_boot="n"
read \
-n 1 \
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold. ''' echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following conditions:\n 1-Every boot if no Disk Unlock Key was added to the TPM\n 2-If the TPM fails (hardware failure)\n 3-If the firmware has been tampered with/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s ''' Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width: ''' This will replace the encrypted container content and its LUKS Disk Recovery Key. The passphrase associated with this key will be asked from the user under the following conditions: 1-Every boot if no Disk Unlock Key was added to the TPM 2-If the TPM fails (hardware failure) 3-If the firmware has been tampered with/modified by the user This process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present. At the next prompt, you may be asked to select which file corresponds to the LUKS device container. Hit Enter to continue. ''' Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
-p "Do you wish to boot and use the LUKS Disk Recovery Key? [Y/n] " \
confirm_boot
echo
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
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
# kexec-save-default might have created crypttab overrides to be injected in initramfs through additional cpio
if [ -r "$bootdir/kexec_initrd_crypttab_overrides.txt" ]; then
echo "+++ $bootdir/kexec_initrd_crypttab_overrides.txt found..."
echo "+++ Preparing initramfs crypttab overrides as defined under $bootdir/kexec_initrd_crypttab_overrides.txt to be injected through cpio at next kexec call..."
# kexec-save-default has found crypttab files under initrd and saved them
cat "$bootdir/kexec_initrd_crypttab_overrides.txt" | while read line; do
crypttab_file=$(echo "$line" | awk -F ':' {'print $1'})
crypttab_entry=$(echo "$line" | awk -F ':' {'print $NF'})
# Replace each initrd crypttab file with modified entry containing /secret.key path
mkdir -p "$INITRD_DIR/$(dirname $crypttab_file)"
echo "$crypttab_entry" | tee -a "$INITRD_DIR/$crypttab_file" >/dev/null
echo "+++ initramfs's $crypttab_file will be overriden with: $crypttab_entry"
done
else
# No crypttab files were found under selected default boot option's initrd file
# Meanwhile, force crypttab to be created from scratch on both possible locations: /etc/crypttab and /cryptroot/crypttab
crypttab_files="etc/crypttab cryptroot/crypttab"
for crypttab_file in $crypttab_files; do
mkdir -p "$INITRD_DIR/$(dirname $crypttab_file)"
# overwrite crypttab to mirror behavior of seal-key
echo "+++ The following $crypttab_file overrides will be passed through concatenated secret/initrd.cpio at kexec call:"
for uuid in $(cat "$TMP_KEY_DEVICES" | cut -d\ -f2); do
# NOTE: discard operation (TRIM) is activated by default if no crypptab found in initrd
echo "luks-$uuid UUID=$uuid /secret.key luks,discard" | tee -a "$INITRD_DIR/$crypttab_file"
done
done
fi
(
cd "$INITRD_DIR"
find . -type f | cpio -H newc -o
) >>"$SECRET_CPIO"
fi