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

Improve TPM DUK resealing UX #1678

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 69 additions & 55 deletions initrd/bin/kexec-seal-key
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
# This will generate a disk encryption key and seal / ecncrypt
# This will generate a disk encryption key and seal / encrypt
# 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
Expand Down Expand Up @@ -46,10 +46,12 @@ 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 LUKS Disk Recovery Key/passphrase: " disk_password
echo -n "$disk_password" >"$RECOVERY_KEY"
echo
# key slot 1 is the one that we've generated. TODO: this description needs to be updated in accordance with the new design from PR 1541
read_LUKS_DRK_passphrase_from_user() {
read -s -p "Enter LUKS Disk Recovery Key/passphrase: " disk_password
echo -n "$disk_password" >"$RECOVERY_KEY"
echo
}

read -s -p "New LUKS TPM Disk Unlock Key passphrase for booting: " key_password
echo
Expand All @@ -70,59 +72,71 @@ dd \
2>/dev/null ||
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 LUKS header"
#check if the device is a LUKS device with luks[1,2]
# 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
# Check if slot 1 is the only one existing
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 LUKS Disk Recovery Key/passphrase"
die "You can safely fix this before continuing through Heads recovery shell: cryptsetup luksAddKey $dev"
for tries in 1 2 3; do
read_LUKS_DRK_passphrase_from_user
DEBUG "Testing $RECOVERY_KEY keyfile created from provided passphrase against $dev"
if ! cryptsetup luksOpen --test-passphrase --key-file "$RECOVERY_KEY" $dev; then
if [ $tries == 3 ]; then
die "Failed to unlock $dev with provided passphrase 3 times. Exiting..."
fi
warn "$dev: Unable to unlock LUKS device with provided passphrase. Try again (CAPS LOCK on?)."
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 LUKS TPM Disk Unlock Key passphrase"
fi
done
done

# Remove all the old keys from slot 1
for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do
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 LUKS TPM Disk Unlock Key in LUKS slot 1 failed: might not exist. Continuing"

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 LUKS TPM Disk Unlock Key to LUKS slot 1"
# We will use the following regex to find the slots that are enabled
regex="Slot ([0-9]+): ENABLED|\b([0-9]+): luks2"

# good_slot will be the slot number where the passphrase was tested against as valid. We will keep that slot
good_slot=-1

# test each possible existing key slot of dev against keyfile $RECOVERY_KEY
for slot in $(cryptsetup luksDump "$dev" | grep -E "$regex" | sed -r 's/Slot ([0-9]+): ENABLED|\b([0-9]+): luks2/\1\2/'); do
if [ "$good_slot" -eq "-1" ]; then
if cryptsetup luksOpen --test-passphrase --key-file "$RECOVERY_KEY" $dev $slot; then
good_slot="$slot"
break;
fi
fi
done

# if we found a good slot, we wipe all the other slots on current $dev
for slot in $(cryptsetup luksDump "$dev" | grep -E "$regex" | sed -r 's/Slot ([0-9]+): ENABLED|\b([0-9]+): luks2/\1\2/'); do
if [ "$slot" -ne "$good_slot" ]; then
#set wipe_desired to no by default
wipe_desired="no"

if [ "$slot" -ne "1" ] && [ "$slot" -ne "8" ]; then
# Heads expects key-slot 1 or 8 to be used for TPM DUK setup. Ask user to confirm with big fat warning
read -p "WARNING: LUKS key-slot $slot is not typically used for TPM Disk Unlock Key setup. Are you sure you want to wipe it? [y/N] " -n 1 -r
# If user does not confirm, skip this slot
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
wipe_desired="yes"
fi
else
# If slot is 1 or 8, we wipe it without asking since not DRK's good keyslot
wipe_desired="yes"
fi

if [ "$wipe_desired" == "yes" ]; then
echo "++++++ $dev: Wiping LUKS key-slot $slot"
cryptsetup luksKillSlot \
--key-file "$RECOVERY_KEY" \
$dev $slot ||
warn "$dev: removal of LUKS slot $slot failed: Continuing"
fi
fi
done

# We then add the new key to the luks key slot 8
for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do
echo "++++++ $dev: Adding LUKS TPM Disk Unlock Key to LUKS key-slot 8"
cryptsetup luksAddKey \
--key-file "$RECOVERY_KEY" \
--new-key-slot 8 \
$dev "$KEY_FILE" > /dev/null 2>&1||
die "$dev: Unable to add LUKS TPM Disk Unlock Key to LUKS key-slot #8"
done
done

# Now that we have setup the new keys, measure the PCRs
Expand Down