Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ease TPM Disk Unlock Key sealing/resealing after TOTP mismatch (firmware upgrade) + warn and die changes #1482

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion FAQ.md
Expand Up @@ -110,7 +110,7 @@ to deceive you and steal your login password? Maybe! It wouldn't get
your disk password, which is perhaps an improvement.


Disk key in TPM or user passphrase?
Disk key in TPM (TPM Disk Unlock Key) or user passphrase?
---
Depends on your threat model. With the disk key in the TPM an attacker
would need to have the entire machine (or a backdoor in the TPM)
Expand Down
2 changes: 1 addition & 1 deletion initrd/bin/flashrom-kgpe-d16-openbmc.sh
Expand Up @@ -14,5 +14,5 @@ sha256sum /tmp/kgpe-d16-openbmc.rom
flashrom --programmer="ast1100:spibus=2,cpu=reset" -c "S25FL128P......0" -w /tmp/kgpe-d16-openbmc.rom \
|| die "$ROM: Flash failed"

warn "Reboot and hopefully it works..."
warn "Reboot and hopefully it works"
exit 0
9 changes: 8 additions & 1 deletion initrd/bin/gui-init
Expand Up @@ -173,7 +173,8 @@ generate_totp_hotp()
# clear screen
printf "\033c"
else
warn "Unsealing TOTP/HOTP secret from previous sealed measurements failed. Try "Generate new HOTP/TOTP secret" option if you updated firmware content."
warn "Unsealing TOTP/HOTP secret from previous sealed measurements failed"
warn "Try "Generate new HOTP/TOTP secret" option if you updated firmware content"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The internal quotes need to be escaped to appear in the output (or change the outer quotes to single quotes)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this addressed in the review commit (8809588)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my bad missed it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JonathonHall-Purism should be fixed now

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in 47eba7d 👍

fi
}

Expand Down Expand Up @@ -229,6 +230,7 @@ update_totp()
if (whiptail $BG_COLOR_WARNING --title 'Generate new TOTP/HOTP secret' \
--yesno "This will erase your old secret and replace it with a new one!\n\nDo you want to proceed?" 0 80) then
generate_totp_hotp && update_totp && BG_COLOR_MAIN_MENU=""
reseal_tpm_disk_decryption_key
fi
;;
i )
Expand All @@ -237,6 +239,7 @@ update_totp()
;;
p )
reset_tpm && update_totp && BG_COLOR_MAIN_MENU=""
reseal_tpm_disk_decryption_key
;;
x )
recovery "User requested recovery shell"
Expand Down Expand Up @@ -298,6 +301,7 @@ update_hotp()
if (whiptail $BG_COLOR_WARNING --title 'Generate new TOTP/HOTP secret' \
--yesno "This will erase your old secret and replace it with a new one!\n\nDo you want to proceed?" 0 80) then
generate_totp_hotp && BG_COLOR_MAIN_MENU=""
reseal_tpm_disk_decryption_key
fi
;;
i )
Expand Down Expand Up @@ -523,9 +527,11 @@ show_tpm_totp_hotp_options_menu()
case "$option" in
g )
generate_totp_hotp
reseal_tpm_disk_decryption_key
;;
r )
reset_tpm
reseal_tpm_disk_decryption_key
;;
t )
prompt_totp_mismatch
Expand Down Expand Up @@ -571,6 +577,7 @@ reset_tpm()
# now that the TPM is reset, remove invalid TPM counter files
mount_boot
mount -o rw,remount /boot
warn "Removing rollback and primary handle hash under /boot"
rm -f /boot/kexec_rollback.txt
rm -f /boot/kexec_primhdl_hash.txt

Expand Down
4 changes: 3 additions & 1 deletion initrd/bin/kexec-boot
Expand Up @@ -158,7 +158,9 @@ if [ "$CONFIG_DEBUG_OUTPUT" = "y" ];then
#Repeat kexec command that will be executed since in debug
DEBUG "kexeccmd= $kexeccmd"

read -n 1 -p "[DEBUG] Continue booting? [Y/n]: " debug_boot_confirm
#Ask user if they want to continue booting without echoing back the input (-s)
read -s -n 1 -p "[DEBUG] Continue booting? [Y/n]: " debug_boot_confirm
echo
if [ "${debug_boot_confirm^^}" = N ]; then
# abort
die "Boot aborted"
Expand Down
51 changes: 29 additions & 22 deletions initrd/bin/kexec-insert-key
Expand Up @@ -20,17 +20,17 @@ fi

if [ -r "$TMP_KEY_LVM" ]; then
# Activate the LVM volume group
VOLUME_GROUP=`cat $TMP_KEY_LVM`
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"
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"
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
Expand All @@ -43,14 +43,14 @@ 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
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
tpmr extend -ix 4 -ic generic \
|| die 'Unable to scramble PCR'
tpmr extend -ix 4 -ic generic ||
die 'Unable to scramble PCR'

# Check to continue
if [ "$unseal_failed" = "y" ]; then
Expand All @@ -63,21 +63,21 @@ if [ "$unseal_failed" = "y" ]; then
if [ "$confirm_boot" != 'y' \
-a "$confirm_boot" != 'Y' \
-a -n "$confirm_boot" ] \
; then
; then
die "!!! Aborting boot due to failure to unseal TPM disk key"
fi
fi

echo
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"
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
# 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..."
Expand All @@ -87,19 +87,26 @@ if [ "$unseal_failed" = "n" ]; then
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 "$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
crypttab_file="etc/crypttab"
mkdir -p "$INITRD_DIR/$(dirname $crypttab_file)"
# overwrite crypttab to mirror behavior of seal-key
echo "+++ The following /etc/crypttab lines will be passed through cpio into kexec call for default boot option:"
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"
# TODO: cpio -t is unfit here :( it just extracts early cpio header and not the whole file. Replace with something else
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the 'something else' you want is initrd/bin/unpack_initramfs.sh 😉

That's designed to unpack concatenated initrds like Linux does, it works for the early microcode initrd followed by the real initrd, details in the documentation comment at the top of the file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm. ZSTD would now be a new requirement. Will switch that as being default for all boards and see if things break for legacy boards and if it does, bye bye legacy boards #1421


~ # unpack_initramfs.sh /boot/initrd.img-6.1.0-11-amd64 /tmp/test
DEBUG: Unpacking /boot/initrd.img-6.1.0-11-amd64 to /tmp/test
DEBUG: archive segment 303730373031: 54560 bytes
DEBUG: archive segment 000000000000: 224 bytes
DEBUG: archive segment 28b52ffd8460: 53378107 bytes
~ # find /tmp/test | grep crypttab
/tmp/test/cryptroot/crypttab

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JonathonHall-Purism Applied change at 03d8f93. Will now use that in code thanks for the tip!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in 47eba7d 👍

# 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"
(
cd "$INITRD_DIR"
find . -type f | cpio -H newc -o
) >>"$SECRET_CPIO"
fi