TPM Disk Unlock Key sealing/renewal cleanup (Triggered automatically when resealing TOTP)

Changes:
- As per master: when TOTP cannot unseal TOTP, user is prompted to either reset or regenerate TOTP
- Now, when either is done and a previous TPM Disk Unlock Key was setuped, the user is guided into:
  - Regenerating checksums and signing them
  - Regenerating TPM disk Unlock Key and resealing TPM disk Unlock Key with passphrase into TPM
  - LUKS header being modified, user is asked to resign kexec.sig one last time prior of being able to default boot
- When no previous Disk Unlock Key was setuped, the user is guided into:
  - The above, plus
    - Detection of LUKS containers,suggesting only relevant partitions

- Addition of TRACE and DEBUG statements to troubleshoot actual vs expected behavior while coding
  - Were missing under TPM Disk Unlock Key setup codepaths

- Fixes for #645 : We now check if only one slots exists and we do not use it if its slot1.
  - Also shows in DEBUG traces now

Unrelated staged changes
- ash_functions: warn and die now contains proper spacing and eye attaction
- all warn and die calls modified if containing warnings and too much punctuation
- unify usage of term TPM Disk Unlock Key and Disk Recovery Key
This commit is contained in:
Thierry Laurion 2023-08-22 14:34:29 -04:00
parent 45a4f9d0f3
commit 4910c1188f
No known key found for this signature in database
GPG Key ID: E7B4A71658E36A93
14 changed files with 255 additions and 94 deletions

2
FAQ.md
View File

@ -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. 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 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) would need to have the entire machine (or a backdoor in the TPM)

View File

@ -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 \ flashrom --programmer="ast1100:spibus=2,cpu=reset" -c "S25FL128P......0" -w /tmp/kgpe-d16-openbmc.rom \
|| die "$ROM: Flash failed" || die "$ROM: Flash failed"
warn "Reboot and hopefully it works..." warn "Reboot and hopefully it works"
exit 0 exit 0

View File

@ -173,7 +173,8 @@ generate_totp_hotp()
# clear screen # clear screen
printf "\033c" printf "\033c"
else 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"
fi fi
} }
@ -229,6 +230,7 @@ update_totp()
if (whiptail $BG_COLOR_WARNING --title 'Generate new TOTP/HOTP secret' \ 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 --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="" generate_totp_hotp && update_totp && BG_COLOR_MAIN_MENU=""
reseal_tpm_disk_decryption_key
fi fi
;; ;;
i ) i )
@ -237,6 +239,7 @@ update_totp()
;; ;;
p ) p )
reset_tpm && update_totp && BG_COLOR_MAIN_MENU="" reset_tpm && update_totp && BG_COLOR_MAIN_MENU=""
reseal_tpm_disk_decryption_key
;; ;;
x ) x )
recovery "User requested recovery shell" recovery "User requested recovery shell"
@ -298,6 +301,7 @@ update_hotp()
if (whiptail $BG_COLOR_WARNING --title 'Generate new TOTP/HOTP secret' \ 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 --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="" generate_totp_hotp && BG_COLOR_MAIN_MENU=""
reseal_tpm_disk_decryption_key
fi fi
;; ;;
i ) i )
@ -523,9 +527,11 @@ show_tpm_totp_hotp_options_menu()
case "$option" in case "$option" in
g ) g )
generate_totp_hotp generate_totp_hotp
reseal_tpm_disk_decryption_key
;; ;;
r ) r )
reset_tpm reset_tpm
reseal_tpm_disk_decryption_key
;; ;;
t ) t )
prompt_totp_mismatch prompt_totp_mismatch
@ -571,8 +577,10 @@ reset_tpm()
# now that the TPM is reset, remove invalid TPM counter files # now that the TPM is reset, remove invalid TPM counter files
mount_boot mount_boot
mount -o rw,remount /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_rollback.txt
rm -f /boot/kexec_primhdl_hash.txt rm -f /boot/kexec_primhdl_hash.txt
#TODO: When primhdl_hash is gone but not recreated and signed: fail at TPM Disk Unlock Key for TPM2....
# create Heads TPM counter before any others # create Heads TPM counter before any others
check_tpm_counter /boot/kexec_rollback.txt "" "$key_password" \ check_tpm_counter /boot/kexec_rollback.txt "" "$key_password" \

View File

@ -158,7 +158,9 @@ if [ "$CONFIG_DEBUG_OUTPUT" = "y" ];then
#Repeat kexec command that will be executed since in debug #Repeat kexec command that will be executed since in debug
DEBUG "kexeccmd= $kexeccmd" 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 if [ "${debug_boot_confirm^^}" = N ]; then
# abort # abort
die "Boot aborted" die "Boot aborted"

View File

@ -8,10 +8,10 @@ TRACE "Under /bin/kexec-save-default"
while getopts "b:d:p:i:" arg; do while getopts "b:d:p:i:" arg; do
case $arg in case $arg in
b) bootdir="$OPTARG" ;; b) bootdir="$OPTARG" ;;
d) paramsdev="$OPTARG" ;; d) paramsdev="$OPTARG" ;;
p) paramsdir="$OPTARG" ;; p) paramsdir="$OPTARG" ;;
i) index="$OPTARG" ;; i) index="$OPTARG" ;;
esac esac
done done
@ -35,21 +35,53 @@ TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"
ENTRY_FILE="$paramsdir/kexec_default.$index.txt" ENTRY_FILE="$paramsdir/kexec_default.$index.txt"
HASH_FILE="$paramsdir/kexec_default_hashes.txt" HASH_FILE="$paramsdir/kexec_default_hashes.txt"
PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt" PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt"
KEY_DEVICES="$paramsdir/kexec_key_devices.txt"
KEY_LVM="$paramsdir/kexec_key_lvm.txt"
lvm_suggest=$(lvm vgscan | awk -F '"' {'print $1'} | tail -n +2)
num_lvm=$(echo "$lvm_suggest" | wc -l)
if [ "$num_lvm" -eq 1 ] && [ -n "$lvm_suggest" ]; then
lvm_volume_group="$lvm_suggest"
elif [ -z "$lvm_suggest" ]; then
num_lvm=0
fi
DEBUG "LVM num_lvm: $num_lvm, lvm_suggest: $lvm_suggest"
# get all LUKS container devices
devices_suggest=$(blkid | cut -d ':' -f 1 | while read device; do
cryptsetup isLuks "$device"
if [ $(echo $?) == 0 ]; then echo "$device"; fi
done | sort)
num_devices=$(echo "$devices_suggest" | wc -l)
if [ "$num_devices" -eq 1 ] && [ -s "$devices_suggest" ]; then
key_devices=$devices_suggest
else
devices_suggest=$(echo $devices_suggest)
fi
DEBUG "LUKS num_devices: $num_devices, devices_suggest: $devices_suggest"
if [ "$num_lvm" -eq 0 ] && [ "$num_devices" -eq 0 ]; then
#No encrypted partition found.
no_encrypted_partition=1
fi
if [ ! -r "$TMP_MENU_FILE" ]; then if [ ! -r "$TMP_MENU_FILE" ]; then
die "No menu options available, please run kexec-select-boot" die "No menu options available, please run kexec-select-boot"
fi fi
entry=`head -n $index $TMP_MENU_FILE | tail -1` entry=$(head -n $index $TMP_MENU_FILE | tail -1)
if [ -z "$entry" ]; then if [ -z "$entry" ]; then
die "Invalid menu index $index" die "Invalid menu index $index"
fi fi
KEY_DEVICES="$paramsdir/kexec_key_devices.txt"
KEY_LVM="$paramsdir/kexec_key_lvm.txt"
save_key="n" save_key="n"
if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ "$CONFIG_BASIC" != y ]; then if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ "$CONFIG_BASIC" != y ]; then
DEBUG "TPM is enabled and TPM_NO_LUKS_DISK_UNLOCK is not set"
DEBUG "Checking if a a TPM Disk Unlock Key was previously setuped from $KEY_DEVICES"
if [ ! -r "$KEY_DEVICES" ]; then if [ ! -r "$KEY_DEVICES" ]; then
DEBUG "No previous TPM Disk Unlock Key was setuped for LUKS devices, confirming to add a disk encryption to the TPM"
read \ read \
-n 1 \ -n 1 \
-p "Do you wish to add a disk encryption to the TPM [y/N]: " \ -p "Do you wish to add a disk encryption to the TPM [y/N]: " \
@ -58,11 +90,11 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
if [ "$add_key_confirm" = "y" \ if [ "$add_key_confirm" = "y" \
-o "$add_key_confirm" = "Y" ]; then -o "$add_key_confirm" = "Y" ]; then
lvm_suggest="e.g. qubes_dom0 or blank" DEBUG "User confirmed to add a disk encryption to the TPM"
devices_suggest="e.g. /dev/sda2 or blank"
save_key="y" save_key="y"
fi fi
else else
DEBUG "Previous TPM Disk Unlock Key was setuped for LUKS devices"
read \ read \
-n 1 \ -n 1 \
-p "Do you want to reseal a disk key to the TPM [y/N]: " \ -p "Do you want to reseal a disk key to the TPM [y/N]: " \
@ -73,36 +105,85 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
-o "$change_key_confirm" = "Y" ]; then -o "$change_key_confirm" = "Y" ]; then
old_lvm_volume_group="" old_lvm_volume_group=""
if [ -r "$KEY_LVM" ]; then if [ -r "$KEY_LVM" ]; then
old_lvm_volume_group=`cat $KEY_LVM` || true old_lvm_volume_group=$(cat $KEY_LVM) || true
old_key_devices=`cat $KEY_DEVICES \ old_key_devices=$(cat $KEY_DEVICES |
| cut -d\ -f1 \ cut -d\ -f1 |
| grep -v "$old_lvm_volume_group" \ grep -v "$old_lvm_volume_group" |
| xargs` || true xargs) || true
else else
old_key_devices=`cat $KEY_DEVICES \ old_key_devices=$(cat $KEY_DEVICES |
| cut -d\ -f1 | xargs` || true cut -d\ -f1 | xargs) || true
fi fi
lvm_suggest="was '$old_lvm_volume_group'" lvm_suggest="$old_lvm_volume_group"
devices_suggest="was '$old_key_devices'" devices_suggest="$old_key_devices"
save_key="y" save_key="y"
fi fi
fi fi
if [ "$save_key" = "y" ]; then if [ "$save_key" = "y" ]; then
echo "+++ LVM volume groups (lvm vgscan): " if [ -n "$old_key_devices" ] || [ -n "$old_lvm_volume_group" ]; then
lvm vgscan || true DEBUG "Previous TPM Disk Unlock Key was setuped for LUKS devices $old_key_devices $old_lvm_volume_group"
read \
-n 1 \
-p "Do you want to reuse configured Encrypted LVM groups/Block devices? (Y/n):" \
reuse_past_devices
echo
if [ "$reuse_past_devices" = "y" ] || [ "$reuse_past_devices" = "Y" ] || [ -z "$reuse_past_devices" ]; then
if [ -z "$key_devices" ] && [ -n "$old_key_devices" ]; then
key_devices="$old_key_devices"
fi
if [ -z "$lvm_volume_group" ] && [ -n "$old_lvm_volume_group" ]; then
lvm_volume_group="$old_lvm_volume_group"
fi
fi
else
DEBUG "No previous TPM Disk Unlock Key was setuped for LUKS devices, setting up new ones"
if [ "$num_lvm" -gt 1 ]; then
DEBUG "Multiple LVM groups found"
//untested
selected_lvmdev_not_existing=1
while [ $selected_lvmdev_not_existing -ne 0 ]; do
{
read \
-p "Encrypted LVM group? choose between: '$lvm_suggest': " \
lvm_volume_group
read \ result=$(echo "$lvm_suggest" | grep -q "$lvm_volume_group") || selected_lvmdev_not_existing=1
-p "LVM group containing Encrypted LVs (retype to keep)? ($lvm_suggest): " \ if [ $? == 0 ]; then
lvm_volume_group selected_lvmdev_not_existing=0
fi
}
done
elif [ "$num_lvm" -eq 1 ] && [ -s $lvm_suggest ]; then
echo "Single Encrypted LVM group found at $lvm_suggest."
lvm_volume_group=$lvm_suggest
else
echo "No encrypted LVM Group found."
fi
echo "+++ Block devices (blkid): " if [ "$num_devices" -gt 1 ]; then
blkid || true DEBUG "Multiple LUKS devices found"
selected_luksdev_not_existing=1
while [ $selected_luksdev_not_existing -ne 0 ]; do
{
read \
-p "Encrypted devices? (choose between: '$devices_suggest'): " \
key_devices
read \ result=$(echo "$devices_suggest" | grep -q "$key_devices") || selected_luksdev_not_existing=1
-p "Encrypted devices (retype to keep)? ($devices_suggest): " \ if [ $? == 0 ]; then
key_devices selected_luksdev_not_existing=0
fi
}
done
elif [ "$num_devices" -eq 1 ]; then
echo "Single Encrypted Disk found at $devices_suggest."
key_devices=$devices_suggest
else
echo "No encrypted devices found."
fi
fi
save_key_params="-s -p $paramsdev" save_key_params="-s -p $paramsdev"
if [ -n "$lvm_volume_group" ]; then if [ -n "$lvm_volume_group" ]; then
@ -110,9 +191,8 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
else else
save_key_params="$save_key_params $key_devices" save_key_params="$save_key_params $key_devices"
fi fi
echo "Running kexec-save-key with params: $save_key_params" kexec-save-key $save_key_params ||
kexec-save-key $save_key_params \ die "Failed to save the disk key"
|| die "Failed to save the disk key"
fi fi
fi fi
@ -120,19 +200,20 @@ fi
mount -o rw,remount $paramsdev mount -o rw,remount $paramsdev
if [ ! -d $paramsdir ]; then if [ ! -d $paramsdir ]; then
mkdir -p $paramsdir \ mkdir -p $paramsdir ||
|| die "Failed to create params directory" die "Failed to create params directory"
fi fi
if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
sha256sum /tmp/primary.handle > "$PRIMHASH_FILE" \ sha256sum /tmp/primary.handle >"$PRIMHASH_FILE" ||
|| die "ERROR: Failed to Hash TPM2 primary key handle!" die "ERROR: Failed to Hash TPM2 primary key handle!"
fi fi
rm $paramsdir/kexec_default.*.txt 2>/dev/null || true rm $paramsdir/kexec_default.*.txt 2>/dev/null || true
echo "$entry" > $ENTRY_FILE echo "$entry" >$ENTRY_FILE
( cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f| \ (
xargs sha256sum > $HASH_FILE \ cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f |
xargs sha256sum >$HASH_FILE
) || die "Failed to create hashes of boot files" ) || die "Failed to create hashes of boot files"
if [ ! -r $ENTRY_FILE -o ! -r $HASH_FILE ]; then if [ ! -r $ENTRY_FILE -o ! -r $HASH_FILE ]; then
die "Failed to write default config" die "Failed to write default config"
@ -144,19 +225,19 @@ if [ "$save_key" = "y" ]; then
cd /tmp/initrd_extract cd /tmp/initrd_extract
# Get initrd filename selected to be default initrd that OS could be using to configure LUKS on boot by deploying crypttab files # Get initrd filename selected to be default initrd that OS could be using to configure LUKS on boot by deploying crypttab files
current_default_initrd=$(cat /boot/kexec_default_hashes.txt | grep initr | awk -F " " {'print $NF'} | sed 's/\.\//\/boot\//g') current_default_initrd=$(cat /boot/kexec_default_hashes.txt | grep initr | awk -F " " {'print $NF'} | sed 's/\.\//\/boot\//g')
# Get crypttab files paths from initrd # Get crypttab files paths from initrd
echo "+++ Checking current selected default boot's $current_default_initrd for existing crypttab files..." echo "+++ Checking current selected default boot's $current_default_initrd for existing crypttab files..."
# First either decompress or use the original if it's not compressed # First either decompress or use the original if it's not compressed
initrd_decompressed="/tmp/initrd_extract/initrd_decompressed.cpio" initrd_decompressed="/tmp/initrd_extract/initrd_decompressed.cpio"
zcat < "$current_default_initrd" > "$initrd_decompressed" 2> /dev/null || initrd_decompressed="$current_default_initrd" zcat <"$current_default_initrd" >"$initrd_decompressed" 2>/dev/null || initrd_decompressed="$current_default_initrd"
crypttab_files=$(cpio --list --quiet < "$initrd_decompressed" | grep crypttab 2> /dev/null) || true crypttab_files=$(cpio --list --quiet <"$initrd_decompressed" | grep crypttab 2>/dev/null) || true
if [ ! -z "$crypttab_files" ]; then if [ ! -z "$crypttab_files" ]; then
echo "+++ Extracting current selected default boot's $current_default_initrd for found crypttab files analysis..." echo "+++ Extracting current selected default boot's $current_default_initrd for found crypttab files analysis..."
cpio -id --quiet < $initrd_decompressed $crypttab_files 2> /dev/null cpio -id --quiet $crypttab_files <$initrd_decompressed 2>/dev/null
rm -f $bootdir/kexec_initrd_crypttab_overrides.txt || true rm -f $bootdir/kexec_initrd_crypttab_overrides.txt || true
#Parsing each crypttab file found #Parsing each crypttab file found
echo "$crypttab_files" | while read filepath; do echo "$crypttab_files" | while read filepath; do
# Keep only non-commented lines # Keep only non-commented lines
@ -165,7 +246,7 @@ if [ "$save_key" = "y" ]; then
modified_filepath_entries=$(echo "$current_filepath_entries" | sed 's/none/\/secret.key/g') modified_filepath_entries=$(echo "$current_filepath_entries" | sed 's/none/\/secret.key/g')
echo "$modified_filepath_entries" | while read single_modified_filepath_entry; do echo "$modified_filepath_entries" | while read single_modified_filepath_entry; do
# Append each found filepath:entry into additional kexec_ file that will be part of detached signed digest # Append each found filepath:entry into additional kexec_ file that will be part of detached signed digest
echo "$filepath:$single_modified_filepath_entry" >> $bootdir/kexec_initrd_crypttab_overrides.txt echo "$filepath:$single_modified_filepath_entry" >>$bootdir/kexec_initrd_crypttab_overrides.txt
done done
done done
@ -189,14 +270,14 @@ fi
# sign and auto-roll config counter # sign and auto-roll config counter
extparam= extparam=
if [ "$CONFIG_TPM" = "y" ];then if [ "$CONFIG_TPM" = "y" ]; then
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
extparam=-r extparam=-r
fi fi
fi fi
if [ "$CONFIG_BASIC" != "y" ]; then if [ "$CONFIG_BASIC" != "y" ]; then
kexec-sign-config -p $paramsdir $extparam \ kexec-sign-config -p $paramsdir $extparam ||
|| die "Failed to sign default config" die "Failed to sign default config"
fi fi
# switch back to ro mode # switch back to ro mode
mount -o ro,remount $paramsdev mount -o ro,remount $paramsdev

View File

@ -1,5 +1,9 @@
#!/bin/bash #!/bin/bash
# Generate a TPM key used to unlock LUKS disks # Generate a TPM key used to unlock LUKS disks
. /etc/functions
TRACE "kexec-save-key: start"
set -e -o pipefail set -e -o pipefail
. /etc/functions . /etc/functions
@ -13,20 +17,28 @@ while getopts "sp:d:l:" arg; do
l) lvm_volume_group="$OPTARG" ;; l) lvm_volume_group="$OPTARG" ;;
esac esac
done done
DEBUG "kexec-save-key prior of parsing: paramsdir: $paramsdir, paramsdev: $paramsdev, lvm_volume_group: $lvm_volume_group"
shift `expr $OPTIND - 1` shift `expr $OPTIND - 1`
key_devices="$@" key_devices="$@"
DEBUG "kexec-save-key: key_devices: $key_devices"
if [ -z "$paramsdir" ]; then if [ -z "$paramsdir" ]; then
die "Usage: $0 [-s] -p /boot [-l qubes_dom0] [/dev/sda2 /dev/sda5 ...] " die "Usage: $0 [-s] -p /boot [-l qubes_dom0] [/dev/sda2 /dev/sda5 ...] "
fi fi
if [ -z "$paramsdev" ]; then if [ -z "$paramsdev" ]; then
paramsdev="$paramsdir" paramsdev="$paramsdir"
DEBUG "kexec-save-key: paramsdev modified to : $paramsdev"
fi fi
paramsdev="${paramsdev%%/}" paramsdev="${paramsdev%%/}"
paramsdir="${paramsdir%%/}" paramsdir="${paramsdir%%/}"
DEBUG "kexec-save-key prior of last override: paramsdir: $paramsdir, paramsdev: $paramsdev, lvm_volume_group: $lvm_volume_group"
if [ -n "$lvm_volume_group" ]; then if [ -n "$lvm_volume_group" ]; then
lvm vgchange -a y $lvm_volume_group \ lvm vgchange -a y $lvm_volume_group \
|| die "Failed to activate the LVM group" || die "Failed to activate the LVM group"
@ -45,14 +57,17 @@ mount -o rw,remount $paramsdev
rm -f $paramsdir/kexec_key_lvm.txt || true rm -f $paramsdir/kexec_key_lvm.txt || true
if [ -n "$lvm_volume_group" ]; then if [ -n "$lvm_volume_group" ]; then
DEBUG "kexec-save-key saving under $paramsdir/kexec_key_lvm.txt : lvm_volume_group: $lvm_volume_group"
echo "$lvm_volume_group" > $paramsdir/kexec_key_lvm.txt \ echo "$lvm_volume_group" > $paramsdir/kexec_key_lvm.txt \
|| die "Failed to write lvm group to key config " || die "Failed to write lvm group to key config "
fi fi
rm -f $paramsdir/kexec_key_devices.txt || true rm -f $paramsdir/kexec_key_devices.txt || true
for dev in $key_devices; do for dev in $key_devices; do
DEBUG "gettinmg uuid for $dev"
uuid=`cryptsetup luksUUID "$dev" 2>/dev/null` \ uuid=`cryptsetup luksUUID "$dev" 2>/dev/null` \
|| die "Failed to get UUID for device $dev" || die "Failed to get UUID for device $dev"
DEBUG "saving under $paramsdir/kexec_key_devices.txt : dev: $dev, uuid: $uuid"
echo "$dev $uuid" >> $paramsdir/kexec_key_devices.txt \ echo "$dev $uuid" >> $paramsdir/kexec_key_devices.txt \
|| die "Failed to add $dev:$uuid to key devices config" || die "Failed to add $dev:$uuid to key devices config"
done done
@ -71,4 +86,4 @@ if [ "$skip_sign" != "y" ]; then
fi fi
# switch back to ro mode # switch back to ro mode
mount -o ro,remount $paramsdev mount -o ro,remount $paramsdev

View File

@ -26,16 +26,20 @@ KEY_LVM="$paramsdir/kexec_key_lvm.txt"
if [ ! -r "$KEY_DEVICES" ]; then if [ ! -r "$KEY_DEVICES" ]; then
die "No devices defined for disk encryption" die "No devices defined for disk encryption"
else
DEBUG "Devices defined for disk encryption: $(cat "$KEY_DEVICES" | cut -d\ -f1)"
fi fi
if [ -r "$KEY_LVM" ]; then if [ -r "$KEY_LVM" ]; then
# Activate the LVM volume group # Activate the LVM volume group
VOLUME_GROUP=`cat $KEY_LVM` VOLUME_GROUP=$(cat $KEY_LVM)
if [ -z "$VOLUME_GROUP" ]; then if [ -z "$VOLUME_GROUP" ]; then
die "No LVM volume group defined for activation" die "No LVM volume group defined for activation"
fi fi
lvm vgchange -a y $VOLUME_GROUP \ lvm vgchange -a y $VOLUME_GROUP ||
|| die "$VOLUME_GROUP: unable to activate volume group" die "$VOLUME_GROUP: unable to activate volume group"
else
DEBUG "No LVM volume group defined for activation"
fi fi
DEBUG "$(pcrs)" DEBUG "$(pcrs)"
@ -43,50 +47,69 @@ DEBUG "$(pcrs)"
# LUKS Key slot 0 is the manual recovery pass phrase # LUKS Key slot 0 is the manual recovery pass phrase
# that they user entered when they installed OS, # that they user entered when they installed OS,
# key slot 1 is the one that we've generated. # key slot 1 is the one that we've generated.
read -s -p "Enter disk recovery key: " disk_password read -s -p "Enter disk recovery key/passphrase: " disk_password
echo -n "$disk_password" > "$RECOVERY_KEY" echo -n "$disk_password" >"$RECOVERY_KEY"
echo echo
read -s -p "New disk unlock password for booting: " key_password read -s -p "New TPM Disk Unlock Key passphrase for booting: " key_password
echo echo
read -s -p "Repeat unlock code: " key_password2 read -s -p "Repeat TPM Disk Unlock key passphrase: " key_password2
echo echo
if [ "$key_password" != "$key_password2" ]; then if [ "$key_password" != "$key_password2" ]; then
die "Key passwords do not match" die "Key passphrases do not match"
fi fi
# Generate key file # Generate key file
echo "++++++ Generating new randomized 128 bytes key file that will be unsealed by TPM Disk Unlock Key passphrase"
dd \ dd \
if=/dev/urandom \ if=/dev/urandom \
of="$KEY_FILE" \ of="$KEY_FILE" \
bs=1 \ bs=1 \
count=128 \ count=128 \
2>/dev/null \ 2>/dev/null ||
|| die "Unable to generate 128 random bytes" die "Unable to generate 128 random bytes"
# Count the number of slots used on each device
for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do
DEBUG "Checking number of slots used on $dev"
#check if the device is a LUKS device with luks[1,2]
slots_used=$(cryptsetup luksDump $dev | grep -c 'luks[0-9]*' || die "Unable to get number of slots used on $dev")
DEBUG "Number of slots used on $dev: $slots_used"
# If slot1 is the only one used, warn and die with proper messages
if [ $slots_used -eq 1 ]; then
# Check if slot 1 is the only one existing
if cryptsetup luksDump $dev | grep -q "Slot 1: ENABLED"; then
warn "Slot 1 is the only one existing on $dev. Heads cannot use it to store TPM sealed LUKS Disk Unlock Key"
die "Slot 1 should not be the only one existing on $dev. Fix your custom setup"
fi
else
DEBUG "Slot 1 is not the only one existing on $dev. It is safe to use it to store TPM sealed LUKS Disk Unlock Key"
fi
done
# Remove all the old keys from slot 1 # Remove all the old keys from slot 1
for dev in `cat "$KEY_DEVICES" | cut -d\ -f1`; do for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do
echo "++++++ $dev: Removing old key slot" echo "++++++ $dev: Removing old key slot 1"
cryptsetup luksKillSlot \ cryptsetup luksKillSlot \
--key-file "$RECOVERY_KEY" \ --key-file "$RECOVERY_KEY" \
$dev 1 \ $dev 1 ||
|| warn "$dev: ignoring problem" warn "$dev: removal of key in slot 1 failed: might not exist. Continuing"
echo "++++++ $dev: Adding key" echo "++++++ $dev: Adding key to slot 1"
cryptsetup luksAddKey \ cryptsetup luksAddKey \
--key-file "$RECOVERY_KEY" \ --key-file "$RECOVERY_KEY" \
--key-slot 1 \ --key-slot 1 \
$dev "$KEY_FILE" \ $dev "$KEY_FILE" ||
|| die "$dev: Unable to add key" die "$dev: Unable to add key to slot 1"
done done
# Now that we have setup the new keys, measure the PCRs # Now that we have setup the new keys, measure the PCRs
# We don't care what ends up in PCR 6; we just want # We don't care what ends up in PCR 6; we just want
# to get the /tmp/luksDump.txt file. We use PCR16 # to get the /tmp/luksDump.txt file. We use PCR16
# since it should still be zero # since it should still be zero
cat "$KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \ cat "$KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks ||
|| die "Unable to measure the LUKS headers" die "Unable to measure the LUKS headers"
pcrf="/tmp/secret/pcrf.bin" pcrf="/tmp/secret/pcrf.bin"
tpmr pcrread 0 "$pcrf" tpmr pcrread 0 "$pcrf"
@ -94,19 +117,19 @@ tpmr pcrread -a 1 "$pcrf"
tpmr pcrread -a 2 "$pcrf" tpmr pcrread -a 2 "$pcrf"
tpmr pcrread -a 3 "$pcrf" tpmr pcrread -a 3 "$pcrf"
# Note that PCR 4 needs to be set with the "normal-boot" path value, read it from event log. # Note that PCR 4 needs to be set with the "normal-boot" path value, read it from event log.
tpmr calcfuturepcr 4 >> "$pcrf" tpmr calcfuturepcr 4 >>"$pcrf"
if [ "$CONFIG_USB_KEYBOARD" = "y" -o -r /lib/modules/libata.ko -o -x /bin/hotp_verification ]; then if [ "$CONFIG_USB_KEYBOARD" = "y" -o -r /lib/modules/libata.ko -o -x /bin/hotp_verification ]; then
DEBUG "Sealing TPM disk unlock key with PCR5 involvement (additional kernel modules are loaded per board config)..." DEBUG "Sealing TPM Disk Unlock key 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 # Here, we take pcr 5 into consideration if modules are expected to be measured+loaded
tpmr pcrread -a 5 "$pcrf" tpmr pcrread -a 5 "$pcrf"
else else
DEBUG "Sealing TPM disk unlock key with PCR5=0 (NO additional kernel modules are loaded per board config)..." DEBUG "Sealing TPM Disk Unlock Key with PCR5=0 (NO additional kernel modules are loaded per board config)..."
#no kernel modules are expected to be measured+loaded #no kernel modules are expected to be measured+loaded
tpmr calcfuturepcr 5 >> "$pcrf" tpmr calcfuturepcr 5 >>"$pcrf"
fi fi
# Precompute the value for pcr 6 # Precompute the value for pcr 6
DEBUG "Precomputing TPM future value for PCR6 sealing/unsealing of TPM disk unlock key..." DEBUG "Precomputing TPM future value for PCR6 sealing/unsealing of TPM Disk Unlock Key..."
tpmr calcfuturepcr 6 "/tmp/luksDump.txt" >> "$pcrf" tpmr calcfuturepcr 6 "/tmp/luksDump.txt" >>"$pcrf"
# We take into consideration user files in cbfs # We take into consideration user files in cbfs
tpmr pcrread -a 7 "$pcrf" tpmr pcrread -a 7 "$pcrf"
@ -115,9 +138,12 @@ DO_WITH_DEBUG --mask-position 7 \
"$TPM_SIZE" "$key_password" "$TPM_SIZE" "$key_password"
# should be okay if this fails # should be okay if this fails
shred -n 10 -z -u "$pcrf".* 2> /dev/null || true shred -n 10 -z -u "$pcrf" 2>/dev/null ||
shred -n 10 -z -u "$KEY_FILE" 2> /dev/null \ warn "Failed to delete pcrf file - continuing"
|| warn "Failed to delete key file - continuing" shred -n 10 -z -u "$KEY_FILE" 2>/dev/null ||
warn "Failed to delete key file - continuing"
cp /tmp/luksDump.txt "$paramsdir/kexec_lukshdr_hash.txt" \ mount -o rw,remount $paramsdir || die "Failed to remount $paramsdir in RW - continuing"
|| warn "Failed to have hashes of LUKS header - continuing" cp -f /tmp/luksDump.txt "$paramsdir/kexec_lukshdr_hash.txt" ||
die "Failed to copy LUKS header hashes to /boot - continuing"
mount -o ro,remount $paramsdir || die "Failed to remount $paramsdir in RO - continuing"

View File

@ -57,7 +57,7 @@ if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
|| { || {
echo "FATAL: Hash of TPM2 primary key handle mismatch!"; echo "FATAL: Hash of TPM2 primary key handle mismatch!";
echo "If you have not intentionally regenerated TPM2 primary key,"; echo "If you have not intentionally regenerated TPM2 primary key,";
warn "your system may have been compromised!"; warn "your system may have been compromised";
} }
else else
echo "WARNING: Hash of TPM2 primary key handle does not exist!" echo "WARNING: Hash of TPM2 primary key handle does not exist!"
@ -252,7 +252,7 @@ default_select() {
whiptail $BG_COLOR_ERROR --title 'ERROR: Boot Entry Has Changed' \ whiptail $BG_COLOR_ERROR --title 'ERROR: Boot Entry Has Changed' \
--msgbox "The list of boot entries has changed\n\nPlease set a new default" 0 80 --msgbox "The list of boot entries has changed\n\nPlease set a new default" 0 80
fi fi
warn "!!! Boot entry has changed - please set a new default" warn "Boot entry has changed - please set a new default"
return return
fi fi
parse_option parse_option

View File

@ -26,7 +26,7 @@ DEBUG "Show PCRs"
DEBUG "$(pcrs)" DEBUG "$(pcrs)"
for tries in 1 2 3; do for tries in 1 2 3; do
read -s -p "Enter unlock password (blank to abort): " tpm_password read -s -p "Enter LUKS Disk Unlock Key passphrase (blank to abort): " tpm_password
echo echo
if [ -z "$tpm_password" ]; then if [ -z "$tpm_password" ]; then
die "Aborting unseal disk encryption key" die "Aborting unseal disk encryption key"

View File

@ -9,7 +9,7 @@ HOTP_KEY="/boot/kexec_hotp_key"
mount_boot() mount_boot()
{ {
TRACE "Under /bin/seal-htopkey:mount_boot" TRACE "Under /bin/seal-hotpkey:mount_boot"
# Mount local disk if it is not already mounted # Mount local disk if it is not already mounted
if ! grep -q /boot /proc/mounts ; then if ! grep -q /boot /proc/mounts ; then
mount -o ro /boot \ mount -o ro /boot \

View File

@ -495,13 +495,13 @@ tpm1_seal() {
# 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
tpm physicalpresence -s \ tpm physicalpresence -s \
|| warn "Warning: Unable to assert physical presence" || warn "Unable to assert physical presence"
prompt_tpm_password prompt_tpm_password
tpm nv_definespace -in "$index" -sz "$sealed_size" \ tpm nv_definespace -in "$index" -sz "$sealed_size" \
-pwdo "$tpm_password" -per 0 \ -pwdo "$tpm_password" -per 0 \
|| warn "Warning: Unable to define NVRAM space; trying anyway" || warn "Unable to define NVRAM space; trying anyway"
tpm nv_writevalue -in "$index" -if "$sealed_file" \ tpm nv_writevalue -in "$index" -if "$sealed_file" \
@ -595,7 +595,7 @@ tpm2_reset() {
TRACE "Under /bin/tpmr:tpm2_reset" TRACE "Under /bin/tpmr:tpm2_reset"
key_password="$1" key_password="$1"
mkdir -p "$SECRET_DIR" mkdir -p "$SECRET_DIR"
tpm2 clear -c platform || warn "Unable to clear TPM on platform hierarchy!" tpm2 clear -c platform || warn "Unable to clear TPM on platform hierarchy"
tpm2 changeauth -c owner "$(tpm2_password_hex "$key_password")" tpm2 changeauth -c owner "$(tpm2_password_hex "$key_password")"
tpm2 changeauth -c endorsement "$(tpm2_password_hex "$key_password")" tpm2 changeauth -c endorsement "$(tpm2_password_hex "$key_password")"
tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \ tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \
@ -673,7 +673,7 @@ tpm2_kexec_finalize() {
echo "Locking TPM2 platform hierarchy..." echo "Locking TPM2 platform hierarchy..."
randpass=$(dd if=/dev/urandom bs=4 count=1 status=none | xxd -p) randpass=$(dd if=/dev/urandom bs=4 count=1 status=none | xxd -p)
tpm2 changeauth -c platform "$randpass" \ tpm2 changeauth -c platform "$randpass" \
|| warn "Failed to lock platform hierarchy of TPM2!" || warn "Failed to lock platform hierarchy of TPM2"
} }
tpm2_shutdown() { tpm2_shutdown() {

View File

@ -4,13 +4,13 @@
# busybox ash on legacy-flash boards, and with bash on all other boards. # busybox ash on legacy-flash boards, and with bash on all other boards.
die() { die() {
echo >&2 "$*"; echo >&2 " !!! ERROR: $* !!!";
sleep 2; sleep 2;
exit 1; exit 1;
} }
warn() { warn() {
echo >&2 "$*"; echo >&2 " *** WARNING: $* ***";
sleep 1; sleep 1;
} }

View File

@ -81,6 +81,36 @@ confirm_totp()
echo echo
} }
reseal_tpm_disk_decryption_key()
{
TRACE "Under /etc/functions:reseal_tpm_disk_decryption_key"
#Can be called only on resealing, not on tpm reset:
#otherise primary handle and rollback would change.
if ! grep -q /boot /proc/mounts ; then
mount -o ro /boot \
|| recovery "Unable to mount /boot"
fi
if [ -s /boot/kexec_key_devices.txt ] || [ -s /boot/kexec_key_lvm.txt ]; then
warn "A TPM disk decryption key previoulsy sealed is now invalid since firmware measurements cannot be unsealed"
warn "Renewing LUKS Disk Unlock Key to be unsealed by TPM Disk Unlock Key passphrase"
while ! kexec-seal-key /boot; do
warn "Recovery disk encryption key passphrase invalid. Try again!"
done
warn "LUKS header hash changed under of /boot/kexec_luks_hdr_hash.txt"
warn "Updating checksums and signing all files under /boot/kexec.sig"
while ! update_checksums; do
warn "Checksums were not signed. Bad GPG PIN provided?"
warn "Please update checksums and provide a valid GPG PIN"
done
warn "Rebooting in 3 seconds to enable booting default boot option"
sleep 3
reboot
else
DEBUG "No TPM disk decryption key to reseal"
fi
}
# Enable USB storage (if not already enabled), and wait for storage devices to # Enable USB storage (if not already enabled), and wait for storage devices to
# be detected. If USB storage was already enabled, no wait occurs, this would # be detected. If USB storage was already enabled, no wait occurs, this would
# have happened already when USB storage was enabled. # have happened already when USB storage was enabled.

View File

@ -246,7 +246,6 @@ select_luks_container()
mount -o remount,ro /boot mount -o remount,ro /boot
fi fi
else else
warn "No encrypted device found." warn "No encrypted device found."
return 1 return 1
fi fi