mirror of
https://github.com/linuxboot/heads.git
synced 2024-12-21 13:57:52 +00:00
8bf5415e79
Trace parameters to seal/unseal and some key tpm2 invocations. Trace invocation of tpmr seal/unseal for disk unlock key. Add DO_WITH_DEBUG() to trace a command and parameters, then execute it. Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
207 lines
6.4 KiB
Bash
Executable File
207 lines
6.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# 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
|
|
. /etc/functions
|
|
|
|
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
|
|
. /tmp/config
|
|
|
|
TRACE "Under kexec-seal-key"
|
|
|
|
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
|
|
|
|
DEBUG "$(pcrs)"
|
|
|
|
# LUKS Key slot 0 is the manual recovery pass phrase
|
|
# that they user entered when they installed OS,
|
|
# 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"
|
|
|
|
if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM2_TOOLS" != "y" ]; then
|
|
luks_pcr=`tpm calcfuturepcr -ix 16 -if /tmp/luksDump.txt`
|
|
# HOTP USB Secrity Dongle loads USB modules which changes PCR5.
|
|
# In the event HOTP USB Security Dongle is enabled, skip verification of PCR5
|
|
# If modules should be loaded during normal boot, skip verification of PCR5
|
|
#
|
|
#TODO: check condition, no libdata.ko
|
|
if [ "$CONFIG_USB_KEYBOARD" = "y" -o -r /lib/modules/libata.ko -o -x /bin/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 "init" mode
|
|
# 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
|
|
|
|
if [ $? -ne 0 ]; then
|
|
die "Unable to seal secret"
|
|
fi
|
|
|
|
shred -n 10 -z -u "$KEY_FILE" 2> /dev/null \
|
|
|| 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
|
|
elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
|
|
pcrf="/tmp/secret/pcrf.bin"
|
|
#TODO: verify logic below against tpm2
|
|
tpm2 pcrread -o "$pcrf" sha256:0,1,2,3
|
|
# pcr 4 is expected to be zero (init mode)
|
|
dd if=/dev/zero bs=32 count=1 >> "$pcrf"
|
|
if [ "$CONFIG_USB_KEYBOARD" = "y" -o -r /lib/modules/libata.ko -o -x /bin/hotp_verification ]; then
|
|
DEBUG "TPM2, with PCR5 involvement (additional kernel modules are loaded per board config)..."
|
|
# Here, we take pcr 5 into consideration if modules are expected to be measured+loaded
|
|
#
|
|
# binary pcr dump can only go via stderr for redirection
|
|
# sadly this busybox has buggy support for "2>>" and "2|"
|
|
# so we need workaround...
|
|
DEBUG "tpm2 pcrread -o /dev/stderr sha256:5 2>&1 >/dev/console | cat >> "$pcrf""
|
|
tpm2 pcrread -o /dev/stderr sha256:5 2>&1 >/dev/console | cat >> "$pcrf"
|
|
else
|
|
DEBUG "TPM2, without PCR5 involvement. Inserting 32 zero bytes under pcrf..."
|
|
#no kernel modules are expected to be measured+loaded
|
|
dd if=/dev/zero bs=32 count=1 >> "$pcrf"
|
|
fi
|
|
# Use pcr 23 to precompute the value for pcr 6
|
|
tpmr extend -ix 23 -if /tmp/luksDump.txt
|
|
tpm2 pcrread -o /dev/stderr sha256:23 2>&1 >/dev/console | cat >> "$pcrf"
|
|
# goal is to validate that what is in pcr 23 is at pcr 6 at unseal
|
|
DEBUG "PCR23 content used to simulate PCR6 content at unseal:"
|
|
DEBUG "$(pcrs)"
|
|
tpm2 pcrreset 23
|
|
# We take into consideration user files in cbfs
|
|
DEBUG "tpm2 pcrread -o /dev/stderr sha256:7 2>&1 >/dev/console | cat >> "$pcrf""
|
|
tpm2 pcrread -o /dev/stderr sha256:7 2>&1 >/dev/console | cat >> "$pcrf"
|
|
DEBUG "tpmr seal $KEY_FILE 0x8100000$TPM_INDEX sha256:0,1,2,3,4,5,6,7 $pcrf <password>"
|
|
tpmr seal "$KEY_FILE" "0x8100000$TPM_INDEX" sha256:0,1,2,3,4,5,6,7 "$pcrf" "$key_password"
|
|
if [ $? -eq 0 ]; then
|
|
# should be okay if this fails
|
|
shred -n 10 -z -u "$pcrf".* 2> /dev/null || true
|
|
fi
|
|
fi
|
|
|
|
shred -n 10 -z -u "$TPM_SEALED" 2> /dev/null \
|
|
|| warn "Failed to delete the sealed secret - continuing"
|
|
|
|
cp /tmp/luksDump.txt "$paramsdir/kexec_lukshdr_hash.txt" \
|
|
|| warn "Failed to have hashes of LUKS header - continuing"
|