qubes init script and improved TPM disk encryption with LUKS headers (issue #123 and #6)

This commit is contained in:
Trammell Hudson 2017-04-01 23:02:00 -04:00
parent d06ba0a851
commit f99944abe5
Failed to extract signature
7 changed files with 162 additions and 19 deletions

View File

@ -1,5 +1,6 @@
# Configuration for a x230 running Qubes OS # Configuration for a x230 running Qubes OS
BOARD=x230 BOARD=x230
CONFIG_CRYPTSETUP=y CONFIG_CRYPTSETUP=y
CONFIG_FLASHROM=y CONFIG_FLASHROM=y
CONFIG_GPG=y CONFIG_GPG=y
@ -15,3 +16,9 @@ CONFIG_XEN=y
CONFIG_LINUX_USB=y CONFIG_LINUX_USB=y
CONFIG_LINUX_E1000E=y CONFIG_LINUX_E1000E=y
CONFIG_BOOTSCRIPT=/bin/qubes-init
# Disks encrypted by the TPM LUKS key
CONFIG_QUBES_BOOT_DEV="/dev/sda1"
CONFIG_QUBES_DEVS="/dev/sda2 /dev/sda3 /dev/sda5"

18
initrd/bin/mount-usb Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
# Mount a USB device
die() { echo >&2 "!!!!! $@"; exit 1; }
if ! lsmod | grep -q ehci_hcd; then
insmod /lib/modules/ehci-hcd.ko \
|| die "ehci_hcd: module load failed"
fi
if ! lsmod | grep -q ehci_pci; then
insmod /lib/modules/ehci-pci.ko \
|| die "ehci_pci: module load failed"
fi
if [ ! -d /media ]; then
mkdir /media
fi
mount -o ro $1 /media

65
initrd/bin/qubes-init Executable file
View File

@ -0,0 +1,65 @@
#!/bin/sh
# Boot a Qubes installation that has already been setup.
# This depends on the PCR 4 being "normal-boot":
# f8fa3b6e32e7c6fe04c366e74636e505b28f3b0d
# which is only set if the top level /init script has started
# without user intervention or dropping into a recovery shell.
recovery() {
echo >&2 "!!!!! $@"
rm -f /tmp/secret.key
tpm extend -ix 4 -if recovery
echo >&2 "!!!!! Starting recovery shell"
exec /bin/ash
}
. /config
# TODO: Allow /boot to be encrypted?
# This would require a different TPM key or a user
# passphrase to decrypt it.
mount -o ro "$CONFIG_QUBES_BOOT_DEV" /boot \
|| recovery '$CONFIG_BOOT_DEV: Unable to mount /boot'
# TODO: Allow these to be specified on the /boot device
XEN=/boot/xen-4.6.3.heads
INITRD=/boot/initramfs-4.4.31-11.pvops.qubes.x86_64.img
KERNEL=/boot/vmlinuz-4.4.31-11.pvops.qubes.x86_64
echo "+++ Checking $XEN"
gpgv "${XEN}.asc" "${XEN}" \
|| recovery 'Xen signature failed'
echo "+++ Checking $INITRD"
gpgv "${INITRD}.asc" "${INITRD}" \
|| recovery 'Initrd signature failed'
echo "+++ Checking $KERNEL"
gpgv "${KERNEL}.asc" "${KERNEL}" \
|| recovery 'Kernel signature failed'
# Measure the LUKS headers before we unseal the disk key
/bin/qubes-measure-luks $CONFIG_QUBES_DEVS \
|| recovery "LUKS measure failed"
# Attempt to unseal the disk key from the TPM
# should we give this some number of tries?
unseal-key \
|| recovery 'Unseal disk key failed. Starting recovery shell'
# command line arguments are in the hash, so they are "correct".
kexec \
-l \
--module "${KERNEL} root=LABEL=root rhgb" \
--module "${INITRD}" \
--command-line "no-real-mode reboot=no console=vga dom0_mem=min:1024M dom0_mem=max:4096M" \
"${XEN}" \
|| recovery "kexec load failed"
# Last step is to override PCR 6 so that user can't read the key
tpm extend -ix 4 -ic qubes \
|| recovery 'Unable to scramble PCR'
echo "+++ Starting Qubes..."
exec kexec -e

14
initrd/bin/qubes-measure-luks Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
# Measure all of the luks disk encryption headers into
# a PCR so that we can detect disk swap attacks.
die() { echo >&2 "$@"; exit 1; }
# Measure the luks headers into PCR 6
for dev in "$@"; do
cryptsetup luksDump $dev \
|| die "$dev: Unable to measure"
done > /tmp/luksDump.txt
tpm extend -ix 6 -if /tmp/luksDump.txt \
|| die "Unable to extend PCR"

View File

@ -7,15 +7,36 @@ TPM_INDEX=3
TPM_SIZE=312 TPM_SIZE=312
KEY_FILE=/tmp/secret.key KEY_FILE=/tmp/secret.key
die() { echo >&2 "$@"; exit 1; } . /config
die() {
echo >&2 "$@";
rm -f /tmp/secret.key /tmp/recovery.key /tmp/sealed
exit 1;
}
warn() { echo >&2 "$@"; } warn() { echo >&2 "$@"; }
read -s -p "New key password: " key_password # 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" > /tmp/recovery.key
echo
for dev in $CONFIG_QUBES_DEVS; do
echo "++++++ $dev: Removing old key slot"
cryptsetup luksKillSlot \
--key-file /tmp/recovery.key \
$dev 1 \
|| warn "$dev: ignoring problem"
done
read -s -p "New disk decryption password for booting: " key_password
echo echo
read -s -p "Repeat password: " key_password2 read -s -p "Repeat password: " key_password2
echo echo
if [ "$key_password" -ne "$key_password2" ]; then if [ "$key_password" != "$key_password2" ]; then
die "Key passwords do not match" die "Key passwords do not match"
fi fi
@ -27,11 +48,28 @@ dd \
2>/dev/null \ 2>/dev/null \
|| die "Unable to generate 128 random bytes" || die "Unable to generate 128 random bytes"
for dev in $CONFIG_QUBES_DEVS; do
echo "+++++ $dev: Adding key"
cryptsetup luksAddKey \
--key-file /tmp/recovery.key \
--key-slot 1 \
$dev "$KEY_FILE" \
|| die "$dev: Unable to add key"
done
# Use the current values of the PCRs, which will be read # Now that we have setup the new keys, measure the PCRs
/bin/qubes-measure-luks $CONFIG_QUBES_DEVS \
|| die "Unable to measure the LUKS headers"
# 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.
# 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"). # from the TPM as part of the sealing ("X").
# should this read the storage root key? tpm sealfile2 \
sealfile2 \
-if "$KEY_FILE" \ -if "$KEY_FILE" \
-of /tmp/sealed \ -of /tmp/sealed \
-pwdd "$key_password" \ -pwdd "$key_password" \
@ -40,10 +78,12 @@ sealfile2 \
-ix 1 X \ -ix 1 X \
-ix 2 X \ -ix 2 X \
-ix 3 X \ -ix 3 X \
-ix 4 X \ -ix 4 f8fa3b6e32e7c6fe04c366e74636e505b28f3b0d \
-ix 5 0000000000000000000000000000000000000000 \
-ix 6 X \
|| die "Unable to seal secret" || die "Unable to seal secret"
rm "$KEY_FILE" rm -f "$KEY_FILE"
# to create an nvram space we need the TPM owner password # to create an nvram space we need the TPM owner password
@ -51,24 +91,23 @@ rm "$KEY_FILE"
# #
# The permissions are 0 since there is nothing special # The permissions are 0 since there is nothing special
# about the sealed file # about the sealed file
physicalpresence -s \ tpm physicalpresence -s \
|| warn "Warning: Unable to assert physical presence" || warn "Warning: Unable to assert physical presence"
read -s -p "TPM Owner password: " tpm_password read -s -p "TPM Owner password: " tpm_password
echo echo
nv_definespace \ tpm nv_definespace \
-in $TPM_INDEX \ -in $TPM_INDEX \
-sz $TPM_SIZE \ -sz $TPM_SIZE \
-pwdo "$tpm_password" \ -pwdo "$tpm_password" \
-per 0 \ -per 0 \
|| die "Warning: Unable to define NVRAM space; trying anyway" || warn "Warning: Unable to define NVRAM space; trying anyway"
nv_writevalue \ tpm nv_writevalue \
-in $TPM_INDEX \ -in $TPM_INDEX \
-if /tmp/sealed \ -if /tmp/sealed \
|| die "Unable to write sealed secret to NVRAM" || die "Unable to write sealed secret to NVRAM"
rm /tmp/sealed rm /tmp/sealed

View File

@ -13,22 +13,22 @@ if [ -z "$key_file" ]; then
key_file=/tmp/secret.key key_file=/tmp/secret.key
fi fi
read -s -p "Encryption password: " tpm_password read -s -p "Disk encryption password: " tpm_password
echo echo
nv_readvalue \ tpm nv_readvalue \
-in "$TPM_INDEX" \ -in "$TPM_INDEX" \
-sz "$TPM_SIZE" \ -sz "$TPM_SIZE" \
-of /tmp/sealed \ -of /tmp/sealed \
|| die "Unable to read key from TPM NVRAM" || die "Unable to read key from TPM NVRAM"
unsealfile \ tpm unsealfile \
-if /tmp/sealed \ -if /tmp/sealed \
-of "$key_file" \ -of "$key_file" \
-pwdd "$tpm_password" \ -pwdd "$tpm_password" \
-hk 40000000 \ -hk 40000000 \
|| die "Unable to unseal disk encryption key" || die "Unable to unseal disk encryption key"
rm /tmp/sealed rm -f /tmp/sealed
exit 0

View File

@ -1,6 +1,6 @@
#!/bin/ash #!/bin/ash
# First thing it is vital to mount the /dev and other system directories # First thing it is vital to mount the /dev and other system directories
mkdir /proc /sys /dev /tmp /boot 2>&- 1>&- mkdir /proc /sys /dev /tmp /boot /media 2>&- 1>&-
mount -t devtmpfs none /dev mount -t devtmpfs none /dev
mount -t proc none /proc mount -t proc none /proc
mount -t sysfs none /sys mount -t sysfs none /sys