Skip to content

Commit

Permalink
Merge pull request #1595 from tlaurion/fix_tpm_duk_retry
Browse files Browse the repository at this point in the history
Fix TPM DUK retry loop (bogus), uniformize related vocabulary
  • Loading branch information
tlaurion authored Jan 22, 2024
2 parents f877739 + 4f2b1b6 commit bd9125f
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 63 deletions.
2 changes: 1 addition & 1 deletion FAQ.md
Original file line number Diff line number Diff line change
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 (TPM Disk Unlock Key) or user passphrase?
Disk key in TPM (LUKS 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
3 changes: 2 additions & 1 deletion initrd/bin/kexec-insert-key
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ mkdir -p "$INITRD_DIR/etc"
unseal_failed="n"
if ! kexec-unseal-key "$INITRD_DIR/secret.key"; then
unseal_failed="y"
echo
echo "!!! Failed to unseal the TPM LUKS disk key"
fi

Expand All @@ -58,7 +59,7 @@ if [ "$unseal_failed" = "y" ]; then
confirm_boot="n"
read \
-n 1 \
-p "Do you wish to boot and use the disk recovery key? [Y/n] " \
-p "Do you wish to boot and use the LUKS Disk Recovery Key? [Y/n] " \
confirm_boot

if [ "$confirm_boot" != 'y' \
Expand Down
12 changes: 6 additions & 6 deletions initrd/bin/kexec-save-default
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,10 @@ save_key="n"

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 set up from $KEY_DEVICES"
DEBUG "Checking if a a LUKS TPM Disk Unlock Key was previously set up from $KEY_DEVICES"
#check if $KEY_DEVICES file exists and is not empty
if [ -r "$KEY_DEVICES" ] && [ -s "$KEY_DEVICES" ]; then
DEBUG "TPM Disk Unlock Key was previously set up from $KEY_DEVICES"
DEBUG "LUKS TPM Disk Unlock Key was previously set up from $KEY_DEVICES"
read \
-n 1 \
-p "Do you want to reseal a disk key to the TPM [y/N]: " \
Expand All @@ -218,7 +218,7 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
save_key="y"
fi
else
DEBUG "No previous TPM Disk Unlock Key was set up for LUKS devices, confirming to add a Disk Encryption Key to the TPM"
DEBUG "No previous LUKS TPM Disk Unlock Key was set up, confirming to add a Disk Encryption Key to the TPM"
read \
-n 1 \
-p "Do you wish to add a disk encryption to the TPM [y/N]: " \
Expand All @@ -234,7 +234,7 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [

if [ "$save_key" = "y" ]; then
if [ -n "$old_key_devices" ] || [ -n "$old_lvm_volume_group" ]; then
DEBUG "Previous TPM Disk Unlock Key was set up for LUKS devices $old_key_devices $old_lvm_volume_group"
DEBUG "Previous LUKS TPM Disk Unlock Key was set up for $old_key_devices $old_lvm_volume_group"
read \
-n 1 \
-p "Do you want to reuse configured Encrypted LVM groups/Block devices? (Y/n):" \
Expand All @@ -252,7 +252,7 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
prompt_for_existing_encrypted_lvms_or_disks
fi
else
DEBUG "No previous TPM Disk Unlock Key was set up for LUKS devices, setting up new one"
DEBUG "No previous LUKS TPM Disk Unlock Key was set up, setting up"
prompt_for_existing_encrypted_lvms_or_disks
fi

Expand All @@ -263,7 +263,7 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
save_key_params="$save_key_params $key_devices"
fi
kexec-save-key $save_key_params ||
die "Failed to save the TPM Disk Unlock Key"
die "Failed to save the LUKS TPM Disk Unlock Key"
fi
fi

Expand Down
2 changes: 1 addition & 1 deletion initrd/bin/kexec-save-key
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ for dev in $key_devices; do
done

kexec-seal-key $paramsdir ||
die "Failed to save and generate TPM Disk Unlock Key"
die "Failed to save and generate LUKS TPM Disk Unlock Key"

if [ "$skip_sign" != "y" ]; then
extparam=
Expand Down
53 changes: 36 additions & 17 deletions initrd/bin/kexec-seal-key
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,21 @@ 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/passphrase: " disk_password
read -s -p "Enter LUKS Disk Recovery Key/passphrase: " disk_password
echo -n "$disk_password" >"$RECOVERY_KEY"
echo

read -s -p "New TPM Disk Unlock Key passphrase for booting: " key_password
read -s -p "New LUKS TPM Disk Unlock Key passphrase for booting: " key_password
echo
read -s -p "Repeat TPM Disk Unlock Key passphrase for booting: " key_password2
read -s -p "Repeat LUKS TPM Disk Unlock Key passphrase for booting: " key_password2
echo

if [ "$key_password" != "$key_password2" ]; then
die "Key passphrases do not match"
fi

# Generate key file
echo "++++++ Generating new randomized 128 bytes key file that will be sealed/unsealed by TPM Disk Unlock Key passphrase"
echo "++++++ Generating new randomized 128 bytes key file that will be sealed/unsealed by LUKS TPM Disk Unlock Key passphrase"
dd \
if=/dev/urandom \
of="$KEY_FILE" \
Expand All @@ -74,36 +74,55 @@ dd \
for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do
DEBUG "Checking number of slots used on $dev LUKS header"
#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")
# Get the number of key slots used on the LUKS header.
# LUKS1 Format is :
# Slot 0: ENABLED
# Slot 1: ENABLED
# Slot 2: DISABLED
# Slot 3: DISABLED
#...
# Slot 7: DISABLED
# Luks2 only reports on enabled slots.
# luks2 Format is :
# 0: luks2
# 1: luks2
# Meaning that the number of slots used is the number of lines returned by a grep on the LUKS2 above format.
# We need to count the number of ENABLED slots for both LUKS1 and LUKS2
# create regex pattern for both LUKS1 and LUKS2
regex="Slot [0-9]*: ENABLED"
regex+="\|"
regex+="[0-9]*: luks2"
slots_used=$(cryptsetup luksDump "$dev" | grep -c "$regex" || die "Unable to get number of slots used on $dev")

DEBUG "Number of slots used on $dev LUKS header: $slots_used"
# If slot1 is the only one used, warn and die with proper messages
if [ $slots_used -eq 1 ]; then
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
if [ "$(cryptsetup luksDump "$dev" | grep -c "Slot 1: ENABLED")" -eq 1 ] || [ "$(cryptsetup luksDump "$dev" | grep -c "1: luks2")" -eq 1 ]; then
warn "Slot 1 is the only one existing on $dev LUKS header. Heads cannot use it to store TPM sealed LUKS Disk Unlock Key"
warn "Slot 1 should not be the only slot existing on $dev LUKS header. Slot 0 should be used to store Disk Recovery Key/passphrase"
warn "Slot 1 should not be the only slot existing on $dev LUKS header. Slot 0 should be used to store LUKS Disk Recovery Key/passphrase"
die "You can safely fix this before continuing through Heads recovery shell: cryptsetup luksAddKey $dev"
fi
else
DEBUG "Slot 1 is not the only existing slot on $dev LUKS header."
DEBUG "$dev LUKS header's slot 1 will store LUKS Disk Unlock Key that TPM will seal/unseal with TPM Disk Unlock Key passphrase"
DEBUG "$dev LUKS header's slot 1 will store LUKS Disk Unlock Key that TPM will seal/unseal with LUKS TPM Disk Unlock Key passphrase"
fi
done

# Remove all the old keys from slot 1
for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do
echo "++++++ $dev: Removing old key slot 1"
echo "++++++ $dev: Removing old LUKS TPM Disk Unlock Key in LUKS slot 1"
cryptsetup luksKillSlot \
--key-file "$RECOVERY_KEY" \
$dev 1 ||
warn "$dev: removal of key in slot 1 failed: might not exist. Continuing"
warn "$dev: removal of LUKS TPM Disk Unlock Key in LUKS slot 1 failed: might not exist. Continuing"

echo "++++++ $dev: Adding key to slot 1"
echo "++++++ $dev: Adding LUKS TPM Disk Unlock Key to LUKS slot 1"
cryptsetup luksAddKey \
--key-file "$RECOVERY_KEY" \
--key-slot 1 \
$dev "$KEY_FILE" ||
die "$dev: Unable to add key to slot 1"
die "$dev: Unable to add LUKS TPM Disk Unlock Key to LUKS slot 1"
done

# Now that we have setup the new keys, measure the PCRs
Expand All @@ -121,23 +140,23 @@ tpmr pcrread -a 3 "$pcrf"
# Note that PCR 4 needs to be set with the "normal-boot" path value, read it from event log.
tpmr calcfuturepcr 4 >>"$pcrf"
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 LUKS 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
tpmr pcrread -a 5 "$pcrf"
else
DEBUG "Sealing TPM Disk Unlock Key with PCR5=0 (NO additional kernel modules are loaded per board config)..."
DEBUG "Sealing LUKS 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
tpmr calcfuturepcr 5 >>"$pcrf"
fi
# 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 LUKS TPM Disk Unlock Key..."
tpmr calcfuturepcr 6 "/tmp/luksDump.txt" >>"$pcrf"
# We take into consideration user files in cbfs
tpmr pcrread -a 7 "$pcrf"

DO_WITH_DEBUG --mask-position 7 \
tpmr seal "$KEY_FILE" "$TPM_INDEX" 0,1,2,3,4,5,6,7 "$pcrf" \
"$TPM_SIZE" "$key_password" || die "Unable to write TPM Disk Unlock Key to NVRAM"
"$TPM_SIZE" "$key_password" || die "Unable to write LUKS TPM Disk Unlock Key to NVRAM"

# should be okay if this fails
shred -n 10 -z -u "$pcrf" 2>/dev/null ||
Expand Down
10 changes: 4 additions & 6 deletions initrd/bin/kexec-unseal-key
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,19 @@ DEBUG "Show PCRs"
DEBUG "$(pcrs)"

for tries in 1 2 3; do
read -s -p "Enter LUKS Disk Unlock Key passphrase (blank to abort): " tpm_password
read -s -p "Enter LUKS TPM Disk Unlock Key passphrase (blank to abort): " tpm_password
echo
if [ -z "$tpm_password" ]; then
die "Aborting unseal disk encryption key"
fi

DO_WITH_DEBUG --mask-position 6 \
if DO_WITH_DEBUG --mask-position 6 \
tpmr unseal "$TPM_INDEX" "0,1,2,3,4,5,6,7" "$TPM_SIZE" \
"$key_file" "$tpm_password"

if [ "$?" -eq 0 ]; then
"$key_file" "$tpm_password"; then
exit 0
fi

pcrs
DEBUG $(pcrs)
warn "Unable to unseal disk encryption key"
done

Expand Down
12 changes: 6 additions & 6 deletions initrd/bin/oem-factory-reset
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ generate_checksums() {
mount -o remount,rw /boot || whiptail_error_die "Unable to mount /boot"
fi

#Check if previous TPM Disk unlock Key was set
#Check if previous LUKS TPM Disk Unlock Key was set
if [ -e /boot/kexec_key_devices.txt ]; then
TPM_DISK_ENCRYPTION_KEY_SET=1
fi
Expand Down Expand Up @@ -657,7 +657,7 @@ generate_checksums() {
fi
fi

# set default boot option only if no TPM Disk Unlock Key previously set
# set default boot option only if no LUKS TPM Disk Unlock Key previously set
if [ -z "$TPM_DISK_ENCRYPTION_KEY_SET" ]; then
set_default_boot_option
fi
Expand Down Expand Up @@ -903,7 +903,7 @@ if [ "$use_defaults" == "n" -o "$use_defaults" == "N" ]; then
echo -e "\n"
fi

echo -e -n "Would you like to re-encrypt LUKS encrypted container and generate new Disk Recovery key?\n (Highly recommended if you didn't install the operating system yourself: this would prevent any LUKS backed up header to be restored to access encrypted data) [y/N]: "
echo -e -n "Would you like to re-encrypt LUKS encrypted container and generate new LUKS Disk Recovery Key?\n (Highly recommended if you didn't install the operating system yourself: this would prevent any LUKS backed up header to be restored to access encrypted data) [y/N]: "
read -n 1 prompt_output
echo
if [ "$prompt_output" == "y" \
Expand Down Expand Up @@ -1022,13 +1022,13 @@ if [ "$use_defaults" == "n" -o "$use_defaults" == "N" ]; then
if [ -n "$luks_new_Disk_Recovery_Key_passphrase_desired" -a -z "$luks_new_Disk_Recovery_Key_passphrase" ]; then
# We catch here if changing LUKS Disk Recovery Key passphrase was desired
# but yet undone. This is if not being covered by the single password
echo -e "\nEnter desired replacement for current Disk Recovery Key passphrase (At least 8 characters long):"
echo -e "\nEnter desired replacement for current LUKS Disk Recovery Key passphrase (At least 8 characters long):"
while [[ ${#luks_new_Disk_Recovery_Key_passphrase} -lt 8 ]]; do
{
read -r luks_new_Disk_Recovery_Key_passphrase
}
done
#We test that current Disk Recovery Key passphrase is known prior of going further
#We test that current LUKS Disk Recovery Key passphrase is known prior of going further
test_luks_current_disk_recovery_key_passphrase
echo -e "\n"
fi
Expand Down Expand Up @@ -1147,7 +1147,7 @@ if [[ "$SKIP_BOOT" == "n" ]]; then
fi

if [ -n "$luks_new_Disk_Recovery_Key_desired" -a -n "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then
#Reencryption of disk, disk recovery key and Disk Recovery Key passphrase change is requested
#Reencryption of disk, LUKS Disk Recovery Key and LUKS Disk Recovery Key passphrase change is requested
luks_change_passphrase
luks_reencrypt
elif [ -n "$luks_new_Disk_Recovery_Key_desired" -a -z "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then
Expand Down
10 changes: 5 additions & 5 deletions initrd/etc/functions
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ confirm_totp() {

reseal_tpm_disk_decryption_key() {
TRACE "Under /etc/functions:reseal_tpm_disk_decryption_key"
#For robustness, exit early if TPM Disk Unlock Key is prohibited in board configs
#For robustness, exit early if LUKS TPM Disk Unlock Key is prohibited in board configs
if [ "$CONFIG_TPM_DISK_UNLOCK_KEY" == "n" ]; then
DEBUG "TPM Disk Unlock Key is prohibited in board configs"
DEBUG "LUKS TPM Disk Unlock Key is prohibited in board configs"
return
else
DEBUG "TPM Disk Unlock Key is allowed in board configs. Continuing"
DEBUG "LUKS TPM Disk Unlock Key is allowed in board configs. Continuing"
fi

if ! grep -q /boot /proc/mounts; then
Expand All @@ -96,8 +96,8 @@ reseal_tpm_disk_decryption_key() {
fi

if [ -s /boot/kexec_key_devices.txt ] || [ -s /boot/kexec_key_lvm.txt ]; then
warn "TPM sealed Disk Unlock Key secret needs to be resealed alongside TOTP/HOTP secret"
echo "Resealing TPM LUKS Disk Unlock Key to be unsealed by TPM Disk Unlock Key passphrase"
warn "LUKS TPM sealed Disk Unlock Key secret needs to be resealed alongside TOTP/HOTP secret"
echo "Resealing LUKS TPM Disk Unlock Key to be unsealed by LUKS TPM Disk Unlock Key passphrase"
while ! kexec-seal-key /boot; do
warn "Recovery Disk Encryption key passphrase/TPM Owner Password may be invalid. Please try again"
done
Expand Down
Loading

0 comments on commit bd9125f

Please sign in to comment.