heads/initrd/bin/kexec-seal-key
Kyle Rankin 79a09e7424
Ignore PCR5 when sealing key when Librem Key is enabled
When the Librem Key is enabled, the kernel loads USB modules at boot,
this causes PCR5 to change and breaks unsealing the LUKS key (if set).
This change retains the protection of the PCR5 check unless Librem Key
is enabled.
2018-11-07 13:27:52 -08:00

155 lines
4.0 KiB
Bash
Executable File

#!/bin/sh
# This will generate a disk encryption key and seal / ecncrypt
# with the current PCRs and then store it in the TPM NVRAM.
# It will then need to be bundled into initrd that is booted.
set -e -o pipefail
TPM_INDEX=3
TPM_SIZE=312
KEY_FILE="/tmp/secret/secret.key"
TPM_SEALED="/tmp/secret/secret.sealed"
RECOVERY_KEY="/tmp/secret/recovery.key"
. /etc/functions
. /etc/config
paramsdir=$1
if [ -z "$paramsdir" ]; then
die "Usage $0 /boot"
fi
KEY_DEVICES="$paramsdir/kexec_key_devices.txt"
KEY_LVM="$paramsdir/kexec_key_lvm.txt"
if [ ! -r "$KEY_DEVICES" ]; then
die "No devices defined for disk encryption"
fi
if [ -r "$KEY_LVM" ]; then
# Activate the LVM volume group
VOLUME_GROUP=`cat $KEY_LVM`
if [ -z "$VOLUME_GROUP" ]; 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
# Key slot 0 is the manual recovery pass phrase
# that they user entered when they installed Qubes,
# key slot 1 is the one that we've generated.
read -s -p "Enter disk recovery key: " disk_password
echo -n "$disk_password" > "$RECOVERY_KEY"
echo
read -s -p "New disk unlock password for booting: " key_password
echo
read -s -p "Repeat unlock code: " key_password2
echo
if [ "$key_password" != "$key_password2" ]; then
die "Key passwords do not match"
fi
# Generate key file
dd \
if=/dev/urandom \
of="$KEY_FILE" \
bs=1 \
count=128 \
2>/dev/null \
|| die "Unable to generate 128 random bytes"
# Remove all the old keys from slot 1
for dev in `cat "$KEY_DEVICES" | cut -d\ -f1`; do
echo "++++++ $dev: Removing old key slot"
cryptsetup luksKillSlot \
--key-file "$RECOVERY_KEY" \
$dev 1 \
|| warn "$dev: ignoring problem"
echo "++++++ $dev: Adding key"
cryptsetup luksAddKey \
--key-file "$RECOVERY_KEY" \
--key-slot 1 \
$dev "$KEY_FILE" \
|| die "$dev: Unable to add key"
done
# Now that we have setup the new keys, measure the PCRs
# We don't care what ends up in PCR 6; we just want
# to get the /tmp/luksDump.txt file. We use PCR16
# since it should still be zero
cat "$KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \
|| die "Unable to measure the LUKS headers"
luks_pcr=`tpm calcfuturepcr -ix 16 -if /tmp/luksDump.txt`
# Librem Key loads USB modules which changes PCR5.
# In the event Librem Key is enabled, skip verification of PCR5
if [ -x /bin/libremkey_hotp_verification ]; then
pcr_5="X"
else
pcr_5="0000000000000000000000000000000000000000"
fi
# Note that PCR 4 needs to be set with the "normal-boot"
# path value, which we do not have right now since we are
# in a recovery shell.
# used to be -ix 4 f8fa3b6e32e7c6fe04c366e74636e505b28f3b0d \
# now just all zeros in a normal boot
# PCR 5 must be all zero since no kernel modules should have
# been loaded during a normal boot, but might have been
# loaded in the recovery shell.
# Otherwise use the current values of the PCRs, which will be read
# from the TPM as part of the sealing ("X").
tpm sealfile2 \
-if "$KEY_FILE" \
-of "$TPM_SEALED" \
-pwdd "$key_password" \
-hk 40000000 \
-ix 0 X \
-ix 1 X \
-ix 2 X \
-ix 3 X \
-ix 4 0000000000000000000000000000000000000000 \
-ix 5 $pcr_5 \
-ix 6 $luks_pcr \
-ix 7 X \
|| die "Unable to seal secret"
rm -f "$KEY_FILE" \
|| die "Failed to delete key file"
# try it without the owner password first
if ! tpm nv_writevalue \
-in $TPM_INDEX \
-if "$TPM_SEALED" \
; then
# to create an nvram space we need the TPM owner password
# and the TPM physical presence must be asserted.
#
# The permissions are 0 since there is nothing special
# about the sealed file
tpm physicalpresence -s \
|| warn "Warning: Unable to assert physical presence"
read -s -p "TPM Owner password: " tpm_password
echo
tpm nv_definespace \
-in $TPM_INDEX \
-sz $TPM_SIZE \
-pwdo "$tpm_password" \
-per 0 \
|| warn "Warning: Unable to define NVRAM space; trying anyway"
tpm nv_writevalue \
-in $TPM_INDEX \
-if "$TPM_SEALED" \
|| die "Unable to write sealed secret to NVRAM"
fi
rm "$TPM_SEALED" \
|| warn "Failed to delete the sealed secret - continuing"