mirror of
https://github.com/linuxboot/heads.git
synced 2024-12-19 21:17:55 +00:00
Merge pull request #1482 from tlaurion/ease_tpm_disk_unlock_key_resealing_after_totp_mismatch-warn_and_die_changes
Ease TPM Disk Unlock Key sealing/resealing after TOTP mismatch (firmware upgrade) + warn and die changes
This commit is contained in:
commit
8272d33e7c
2
FAQ.md
2
FAQ.md
@ -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)
|
||||
|
@ -13,6 +13,7 @@ CONFIG_LINUX_CONFIG=config/linux-x230-flash.config
|
||||
#Add bare minimal tools for flashing boards
|
||||
CONFIG_BASH=n
|
||||
CONFIG_FLASHROM=y
|
||||
CONFIG_ZSTD=n
|
||||
#CONFIG_GPG=y
|
||||
#CONFIG_FLASHTOOLS=y
|
||||
CONFIG_PCIUTILS=y
|
||||
|
@ -20,8 +20,6 @@ CONFIG_PCIUTILS=y
|
||||
CONFIG_POPT=y
|
||||
CONFIG_QRENCODE=y
|
||||
CONFIG_TPMTOTP=y
|
||||
# zstd-decompress - for blob jail, needed to extract /init from zstd cpio archive
|
||||
CONFIG_ZSTD=y
|
||||
|
||||
CONFIG_CAIRO=y
|
||||
CONFIG_FBWHIPTAIL=y
|
||||
|
@ -13,6 +13,7 @@ CONFIG_LINUX_CONFIG=config/linux-x230-flash.config
|
||||
#Add bare minimal tools for flashing boards
|
||||
CONFIG_BASH=n
|
||||
CONFIG_FLASHROM=y
|
||||
CONFIG_ZSTD=n
|
||||
#CONFIG_GPG=y
|
||||
#CONFIG_FLASHTOOLS=y
|
||||
CONFIG_PCIUTILS=y
|
||||
@ -21,6 +22,7 @@ CONFIG_PCIUTILS=y
|
||||
#CONFIG_TPMTOTP=y
|
||||
#CONFIG_DROPBEAR=y
|
||||
|
||||
|
||||
#Additional hardware support
|
||||
CONFIG_LINUX_USB=y
|
||||
#CONFIG_LINUX_E1000E=y
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
fi
|
||||
}
|
||||
|
||||
@ -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 )
|
||||
@ -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"
|
||||
@ -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 )
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
@ -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
|
||||
@ -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..."
|
||||
@ -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
|
||||
# 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
|
||||
|
@ -8,10 +8,10 @@ TRACE "Under /bin/kexec-save-default"
|
||||
|
||||
while getopts "b:d:p:i:" arg; do
|
||||
case $arg in
|
||||
b) bootdir="$OPTARG" ;;
|
||||
d) paramsdev="$OPTARG" ;;
|
||||
p) paramsdir="$OPTARG" ;;
|
||||
i) index="$OPTARG" ;;
|
||||
b) bootdir="$OPTARG" ;;
|
||||
d) paramsdev="$OPTARG" ;;
|
||||
p) paramsdir="$OPTARG" ;;
|
||||
i) index="$OPTARG" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@ -35,34 +35,164 @@ TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"
|
||||
ENTRY_FILE="$paramsdir/kexec_default.$index.txt"
|
||||
HASH_FILE="$paramsdir/kexec_default_hashes.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
|
||||
# $lvm_suggest is a multiline string, we need to convert it to a space separated string
|
||||
lvm_suggest=$(echo $lvm_suggest | tr '\n' ' ')
|
||||
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
|
||||
if cryptsetup isLuks "$device"; 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
|
||||
elif [ -z "$devices_suggest" ]; then
|
||||
num_devices=0
|
||||
fi
|
||||
# $devices_suggest is a multiline string, we need to convert it to a space separated string
|
||||
devices_suggest=$(echo $devices_suggest | tr '\n' ' ')
|
||||
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
|
||||
|
||||
#Reusable function when user wants to define new TPM DUK for lvms/disks
|
||||
prompt_for_existing_encrypted_lvms_or_disks() {
|
||||
TRACE "Under kexec-save-default:prompt_for_existing_encrypted_lvms_or_disks"
|
||||
DEBUG "num_lvm: $num_lvm, lvm_suggest: $lvm_suggest, num_devices: $num_devices, devices_suggest: $devices_suggest"
|
||||
|
||||
# Create an associative array to store the suggested LVMs and their paths
|
||||
declare -A lvms_array
|
||||
# Loop through the suggested LVMs and add them to the array
|
||||
for lvm in $lvm_suggest; do
|
||||
lvms_array[$lvm]=$lvm
|
||||
done
|
||||
|
||||
# Get the number of suggested LVMs
|
||||
num_lvms=${#lvms_array[@]}
|
||||
|
||||
if [ "$num_lvms" -gt 1 ]; then
|
||||
DEBUG "Multiple LVMs found: $lvm_suggest"
|
||||
selected_lvms_not_existing=1
|
||||
# Create an array to store the selected LVMs
|
||||
declare -a key_lvms_array
|
||||
|
||||
while [ $selected_lvms_not_existing -ne 0 ]; do
|
||||
{
|
||||
# Read the user input and store it in a variable
|
||||
read \
|
||||
-p "Encrypted LVMs? (choose between/all: $lvm_suggest): " \
|
||||
key_lvms
|
||||
|
||||
# Split the user input by spaces and add each element to the array
|
||||
IFS=' ' read -r -a key_lvms_array <<<"$key_lvms"
|
||||
|
||||
# Loop through the array and check if each element is in the lvms_array
|
||||
valid=1
|
||||
for lvm in "${key_lvms_array[@]}"; do
|
||||
if [[ ! ${lvms_array[$lvm]+_} ]]; then
|
||||
# If not found, set the flag to indicate invalid input
|
||||
valid=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If valid, set the flag to indicate valid input
|
||||
if [[ $valid -eq 1 ]]; then
|
||||
selected_lvms_not_existing=0
|
||||
fi
|
||||
}
|
||||
done
|
||||
elif [ "$num_lvms" -eq 1 ]; then
|
||||
echo "Single Encrypted LVM found at $lvm_suggest."
|
||||
key_lvms=$lvm_suggest
|
||||
else
|
||||
echo "No encrypted LVMs found."
|
||||
fi
|
||||
|
||||
# Create an associative array to store the suggested devices and their paths
|
||||
declare -A devices_array
|
||||
# Loop through the suggested devices and add them to the array
|
||||
for device in $devices_suggest; do
|
||||
devices_array[$device]=$device
|
||||
done
|
||||
|
||||
# Get the number of suggested devices
|
||||
num_devices=${#devices_array[@]}
|
||||
|
||||
if [ "$num_devices" -gt 1 ]; then
|
||||
DEBUG "Multiple LUKS devices found: $devices_suggest"
|
||||
selected_luksdevs_not_existing=1
|
||||
# Create an array to store the selected devices
|
||||
declare -a key_devices_array
|
||||
|
||||
while [ $selected_luksdevs_not_existing -ne 0 ]; do
|
||||
{
|
||||
# Read the user input and store it in a variable
|
||||
read \
|
||||
-p "Encrypted devices? (choose between/all: $devices_suggest): " \
|
||||
key_devices
|
||||
|
||||
# Split the user input by spaces and add each element to the array
|
||||
IFS=' ' read -r -a key_devices_array <<<"$key_devices"
|
||||
|
||||
# Loop through the array and check if each element is in the devices_array
|
||||
valid=1
|
||||
for device in "${key_devices_array[@]}"; do
|
||||
if [[ ! ${devices_array[$device]+_} ]]; then
|
||||
# If not found, set the flag to indicate invalid input
|
||||
valid=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If valid, set the flag to indicate valid input
|
||||
if [[ $valid -eq 1 ]]; then
|
||||
selected_luksdevs_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
|
||||
|
||||
DEBUG "Multiple LUKS devices selected: $key_devices"
|
||||
|
||||
}
|
||||
|
||||
if [ ! -r "$TMP_MENU_FILE" ]; then
|
||||
die "No menu options available, please run kexec-select-boot"
|
||||
fi
|
||||
|
||||
entry=`head -n $index $TMP_MENU_FILE | tail -1`
|
||||
entry=$(head -n $index $TMP_MENU_FILE | tail -1)
|
||||
if [ -z "$entry" ]; then
|
||||
die "Invalid menu index $index"
|
||||
fi
|
||||
|
||||
KEY_DEVICES="$paramsdir/kexec_key_devices.txt"
|
||||
KEY_LVM="$paramsdir/kexec_key_lvm.txt"
|
||||
save_key="n"
|
||||
if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ "$CONFIG_BASIC" != y ]; then
|
||||
if [ ! -r "$KEY_DEVICES" ]; then
|
||||
read \
|
||||
-n 1 \
|
||||
-p "Do you wish to add a disk encryption to the TPM [y/N]: " \
|
||||
add_key_confirm
|
||||
echo
|
||||
|
||||
if [ "$add_key_confirm" = "y" \
|
||||
-o "$add_key_confirm" = "Y" ]; then
|
||||
lvm_suggest="e.g. qubes_dom0 or blank"
|
||||
devices_suggest="e.g. /dev/sda2 or blank"
|
||||
save_key="y"
|
||||
fi
|
||||
else
|
||||
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"
|
||||
#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"
|
||||
read \
|
||||
-n 1 \
|
||||
-p "Do you want to reseal a disk key to the TPM [y/N]: " \
|
||||
@ -73,36 +203,58 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
|
||||
-o "$change_key_confirm" = "Y" ]; then
|
||||
old_lvm_volume_group=""
|
||||
if [ -r "$KEY_LVM" ]; then
|
||||
old_lvm_volume_group=`cat $KEY_LVM` || true
|
||||
old_key_devices=`cat $KEY_DEVICES \
|
||||
| cut -d\ -f1 \
|
||||
| grep -v "$old_lvm_volume_group" \
|
||||
| xargs` || true
|
||||
old_lvm_volume_group=$(cat $KEY_LVM) || true
|
||||
old_key_devices=$(cat $KEY_DEVICES |
|
||||
cut -d\ -f1 |
|
||||
grep -v "$old_lvm_volume_group" |
|
||||
xargs) || true
|
||||
else
|
||||
old_key_devices=`cat $KEY_DEVICES \
|
||||
| cut -d\ -f1 | xargs` || true
|
||||
old_key_devices=$(cat $KEY_DEVICES |
|
||||
cut -d\ -f1 | xargs) || true
|
||||
fi
|
||||
|
||||
lvm_suggest="was '$old_lvm_volume_group'"
|
||||
devices_suggest="was '$old_key_devices'"
|
||||
lvm_suggest="$old_lvm_volume_group"
|
||||
devices_suggest="$old_key_devices"
|
||||
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"
|
||||
read \
|
||||
-n 1 \
|
||||
-p "Do you wish to add a disk encryption to the TPM [y/N]: " \
|
||||
add_key_confirm
|
||||
echo
|
||||
|
||||
if [ "$add_key_confirm" = "y" \
|
||||
-o "$add_key_confirm" = "Y" ]; then
|
||||
DEBUG "User confirmed desire to add a Disk Encryption Key to the TPM"
|
||||
save_key="y"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$save_key" = "y" ]; then
|
||||
echo "+++ LVM volume groups (lvm vgscan): "
|
||||
lvm vgscan || true
|
||||
|
||||
read \
|
||||
-p "LVM group containing Encrypted LVs (retype to keep)? ($lvm_suggest): " \
|
||||
lvm_volume_group
|
||||
|
||||
echo "+++ Block devices (blkid): "
|
||||
blkid || true
|
||||
|
||||
read \
|
||||
-p "Encrypted devices (retype to keep)? ($devices_suggest): " \
|
||||
key_devices
|
||||
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"
|
||||
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
|
||||
#User doesn't want to reuse past devices, so we need to prompt him from devices_suggest and lvm_suggest
|
||||
else
|
||||
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"
|
||||
prompt_for_existing_encrypted_lvms_or_disks
|
||||
fi
|
||||
|
||||
save_key_params="-s -p $paramsdev"
|
||||
if [ -n "$lvm_volume_group" ]; then
|
||||
@ -110,9 +262,8 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [
|
||||
else
|
||||
save_key_params="$save_key_params $key_devices"
|
||||
fi
|
||||
echo "Running kexec-save-key with params: $save_key_params"
|
||||
kexec-save-key $save_key_params \
|
||||
|| die "Failed to save the disk key"
|
||||
kexec-save-key $save_key_params ||
|
||||
die "Failed to save the TPM Disk Unlock Key"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -120,19 +271,20 @@ fi
|
||||
mount -o rw,remount $paramsdev
|
||||
|
||||
if [ ! -d $paramsdir ]; then
|
||||
mkdir -p $paramsdir \
|
||||
|| die "Failed to create params directory"
|
||||
mkdir -p $paramsdir ||
|
||||
die "Failed to create params directory"
|
||||
fi
|
||||
|
||||
if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
|
||||
sha256sum /tmp/primary.handle > "$PRIMHASH_FILE" \
|
||||
|| die "ERROR: Failed to Hash TPM2 primary key handle!"
|
||||
sha256sum /tmp/primary.handle >"$PRIMHASH_FILE" ||
|
||||
die "ERROR: Failed to Hash TPM2 primary key handle!"
|
||||
fi
|
||||
|
||||
rm $paramsdir/kexec_default.*.txt 2>/dev/null || true
|
||||
echo "$entry" > $ENTRY_FILE
|
||||
( cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f| \
|
||||
xargs sha256sum > $HASH_FILE \
|
||||
echo "$entry" >$ENTRY_FILE
|
||||
(
|
||||
cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f |
|
||||
xargs sha256sum >$HASH_FILE
|
||||
) || die "Failed to create hashes of boot files"
|
||||
if [ ! -r $ENTRY_FILE -o ! -r $HASH_FILE ]; then
|
||||
die "Failed to write default config"
|
||||
@ -140,32 +292,32 @@ fi
|
||||
|
||||
if [ "$save_key" = "y" ]; then
|
||||
# logic to parse OS initrd to extract crypttab, its filepaths and its OS defined options
|
||||
mkdir -p /tmp/initrd_extract
|
||||
cd /tmp/initrd_extract
|
||||
initrd_decompressed="/tmp/initrd_extract"
|
||||
mkdir -p "$initrd_decompressed"
|
||||
# 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')
|
||||
|
||||
# Get crypttab files paths from initrd
|
||||
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
|
||||
initrd_decompressed="/tmp/initrd_extract/initrd_decompressed.cpio"
|
||||
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
|
||||
|
||||
|
||||
echo "+++ Extracting current selected default boot's $current_default_initrd to find crypttab files..."
|
||||
unpack_initramfs.sh "$current_default_initrd" "$initrd_decompressed"
|
||||
crypttab_files=$(find "$initrd_decompressed" | grep crypttab 2>/dev/null) || true
|
||||
|
||||
if [ ! -z "$crypttab_files" ]; then
|
||||
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
|
||||
DEBUG "Found crypttab files in $current_default_initrd"
|
||||
rm -f $bootdir/kexec_initrd_crypttab_overrides.txt || true
|
||||
|
||||
|
||||
#Parsing each crypttab file found
|
||||
echo "$crypttab_files" | while read filepath; do
|
||||
# Keep only non-commented lines
|
||||
current_filepath_entries=$(cat "$filepath" | grep -v "^#")
|
||||
# Modify each retained crypttab line to contain to be injected /secret.key at next default boots
|
||||
modified_filepath_entries=$(echo "$current_filepath_entries" | sed 's/none/\/secret.key/g')
|
||||
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
|
||||
echo "$filepath:$single_modified_filepath_entry" >> $bootdir/kexec_initrd_crypttab_overrides.txt
|
||||
echo "$crypttab_files" | while read crypttab_file; do
|
||||
# Change crypttab file path to be relative to initrd for string manipulation
|
||||
final_initrd_filepath=${crypttab_file#/tmp/initrd_extract}
|
||||
DEBUG "Final initramfs crypttab path:$final_initrd_filepath"
|
||||
# Keep only non-commented lines for crypttab entries
|
||||
current_crypttab_entries=$(cat "$crypttab_file" | grep -v "^#")
|
||||
DEBUG "Found initrd crypttab entries $final_initrd_filepath:$current_crypttab_entries"
|
||||
# Modify each retained crypttab line for /secret.key under intramfs to be considered as a keyfile
|
||||
modified_crypttab_entries=$(echo "$current_crypttab_entries" | sed 's/none/\/secret.key/g')
|
||||
DEBUG "Modified crypttab entries $final_initrd_filepath:$modified_crypttab_entries"
|
||||
echo "$modified_crypttab_entries" | while read modified_crypttab_entry; do
|
||||
echo "$final_initrd_filepath:$modified_crypttab_entry" >>$bootdir/kexec_initrd_crypttab_overrides.txt
|
||||
done
|
||||
done
|
||||
|
||||
@ -189,14 +341,14 @@ fi
|
||||
|
||||
# sign and auto-roll config counter
|
||||
extparam=
|
||||
if [ "$CONFIG_TPM" = "y" ];then
|
||||
if [ "$CONFIG_TPM" = "y" ]; then
|
||||
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
|
||||
extparam=-r
|
||||
fi
|
||||
fi
|
||||
if [ "$CONFIG_BASIC" != "y" ]; then
|
||||
kexec-sign-config -p $paramsdir $extparam \
|
||||
|| die "Failed to sign default config"
|
||||
kexec-sign-config -p $paramsdir $extparam ||
|
||||
die "Failed to sign default config"
|
||||
fi
|
||||
# switch back to ro mode
|
||||
mount -o ro,remount $paramsdev
|
||||
|
@ -1,5 +1,9 @@
|
||||
#!/bin/bash
|
||||
# Generate a TPM key used to unlock LUKS disks
|
||||
|
||||
. /etc/functions
|
||||
|
||||
TRACE "kexec-save-key: start"
|
||||
set -e -o pipefail
|
||||
. /etc/functions
|
||||
|
||||
@ -7,30 +11,38 @@ lvm_volume_group=""
|
||||
skip_sign="n"
|
||||
while getopts "sp:d:l:" arg; do
|
||||
case $arg in
|
||||
s) skip_sign="y" ;;
|
||||
p) paramsdir="$OPTARG" ;;
|
||||
d) paramsdev="$OPTARG" ;;
|
||||
l) lvm_volume_group="$OPTARG" ;;
|
||||
s) skip_sign="y" ;;
|
||||
p) paramsdir="$OPTARG" ;;
|
||||
d) paramsdev="$OPTARG" ;;
|
||||
l) lvm_volume_group="$OPTARG" ;;
|
||||
esac
|
||||
done
|
||||
shift `expr $OPTIND - 1`
|
||||
|
||||
DEBUG "kexec-save-key prior of parsing: paramsdir: $paramsdir, paramsdev: $paramsdev, lvm_volume_group: $lvm_volume_group"
|
||||
|
||||
shift $(expr $OPTIND - 1)
|
||||
key_devices="$@"
|
||||
|
||||
DEBUG "kexec-save-key: key_devices: $key_devices"
|
||||
|
||||
if [ -z "$paramsdir" ]; then
|
||||
die "Usage: $0 [-s] -p /boot [-l qubes_dom0] [/dev/sda2 /dev/sda5 ...] "
|
||||
fi
|
||||
|
||||
if [ -z "$paramsdev" ]; then
|
||||
paramsdev="$paramsdir"
|
||||
DEBUG "kexec-save-key: paramsdev modified to : $paramsdev"
|
||||
fi
|
||||
|
||||
paramsdev="${paramsdev%%/}"
|
||||
paramsdir="${paramsdir%%/}"
|
||||
|
||||
if [ -n "$lvm_volume_group" ]; then
|
||||
lvm vgchange -a y $lvm_volume_group \
|
||||
|| die "Failed to activate the LVM group"
|
||||
DEBUG "kexec-save-key prior of last override: paramsdir: $paramsdir, paramsdev: $paramsdev, lvm_volume_group: $lvm_volume_group"
|
||||
|
||||
if [ -n "$lvm_volume_group" ]; then
|
||||
lvm vgchange -a y $lvm_volume_group ||
|
||||
die "Failed to activate the LVM group"
|
||||
#TODO: why reuse key_devices for lvm devices?
|
||||
for dev in /dev/$lvm_volume_group/*; do
|
||||
key_devices="$key_devices $dev"
|
||||
done
|
||||
@ -45,20 +57,23 @@ mount -o rw,remount $paramsdev
|
||||
|
||||
rm -f $paramsdir/kexec_key_lvm.txt || true
|
||||
if [ -n "$lvm_volume_group" ]; then
|
||||
echo "$lvm_volume_group" > $paramsdir/kexec_key_lvm.txt \
|
||||
|| die "Failed to write lvm group to key config "
|
||||
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 ||
|
||||
die "Failed to write lvm group to key config "
|
||||
fi
|
||||
|
||||
rm -f $paramsdir/kexec_key_devices.txt || true
|
||||
for dev in $key_devices; do
|
||||
uuid=`cryptsetup luksUUID "$dev" 2>/dev/null` \
|
||||
|| die "Failed to get UUID for device $dev"
|
||||
echo "$dev $uuid" >> $paramsdir/kexec_key_devices.txt \
|
||||
|| die "Failed to add $dev:$uuid to key devices config"
|
||||
DEBUG "Getting UUID for $dev"
|
||||
uuid=$(cryptsetup luksUUID "$dev" 2>/dev/null) ||
|
||||
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 ||
|
||||
die "Failed to add $dev:$uuid to key devices config"
|
||||
done
|
||||
|
||||
kexec-seal-key $paramsdir \
|
||||
|| die "Failed to save and generate key in TPM"
|
||||
kexec-seal-key $paramsdir ||
|
||||
die "Failed to save and generate TPM Disk Unlock Key"
|
||||
|
||||
if [ "$skip_sign" != "y" ]; then
|
||||
extparam=
|
||||
@ -66,8 +81,8 @@ if [ "$skip_sign" != "y" ]; then
|
||||
extparam=-r
|
||||
fi
|
||||
# sign and auto-roll config counter
|
||||
kexec-sign-config -p $paramsdir $extparam \
|
||||
|| die "Failed to sign updated config"
|
||||
kexec-sign-config -p $paramsdir $extparam ||
|
||||
die "Failed to sign updated config"
|
||||
fi
|
||||
|
||||
# switch back to ro mode
|
||||
|
@ -26,16 +26,20 @@ KEY_LVM="$paramsdir/kexec_key_lvm.txt"
|
||||
|
||||
if [ ! -r "$KEY_DEVICES" ]; then
|
||||
die "No devices defined for disk encryption"
|
||||
else
|
||||
DEBUG "Devices defined for disk encryption: $(cat "$KEY_DEVICES" | cut -d\ -f1 | tr '\n' ' ')"
|
||||
fi
|
||||
|
||||
if [ -r "$KEY_LVM" ]; then
|
||||
# Activate the LVM volume group
|
||||
VOLUME_GROUP=`cat $KEY_LVM`
|
||||
VOLUME_GROUP=$(cat $KEY_LVM)
|
||||
if [ -z "$VOLUME_GROUP" ]; 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"
|
||||
else
|
||||
DEBUG "No LVM volume group defined for activation"
|
||||
fi
|
||||
|
||||
DEBUG "$(pcrs)"
|
||||
@ -43,50 +47,70 @@ 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: " disk_password
|
||||
echo -n "$disk_password" > "$RECOVERY_KEY"
|
||||
read -s -p "Enter Disk Recovery Key/passphrase: " disk_password
|
||||
echo -n "$disk_password" >"$RECOVERY_KEY"
|
||||
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
|
||||
read -s -p "Repeat unlock code: " key_password2
|
||||
read -s -p "Repeat TPM Disk Unlock Key passphrase for booting: " key_password2
|
||||
echo
|
||||
|
||||
if [ "$key_password" != "$key_password2" ]; then
|
||||
die "Key passwords do not match"
|
||||
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"
|
||||
dd \
|
||||
if=/dev/urandom \
|
||||
of="$KEY_FILE" \
|
||||
bs=1 \
|
||||
count=128 \
|
||||
2>/dev/null \
|
||||
|| die "Unable to generate 128 random bytes"
|
||||
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"
|
||||
#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 slot existing on $dev. Fix your custom setup"
|
||||
fi
|
||||
else
|
||||
DEBUG "Slot 1 is not the only existing slot on $dev"
|
||||
DEBUG "$dev Slot 1 will be used to store LUKS Disk Unlock Key that TPM will seal/unseal with 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"
|
||||
for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do
|
||||
echo "++++++ $dev: Removing old key slot 1"
|
||||
cryptsetup luksKillSlot \
|
||||
--key-file "$RECOVERY_KEY" \
|
||||
$dev 1 \
|
||||
|| warn "$dev: ignoring problem"
|
||||
$dev 1 ||
|
||||
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 \
|
||||
--key-file "$RECOVERY_KEY" \
|
||||
--key-slot 1 \
|
||||
$dev "$KEY_FILE" \
|
||||
|| die "$dev: Unable to add key"
|
||||
$dev "$KEY_FILE" ||
|
||||
die "$dev: Unable to add key to slot 1"
|
||||
done
|
||||
|
||||
# Now that we have setup the new keys, measure the PCRs
|
||||
# We don't care what ends up in PCR 6; we just want
|
||||
# to get the /tmp/luksDump.txt file. We use PCR16
|
||||
# since it should still be zero
|
||||
cat "$KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \
|
||||
|| die "Unable to measure the LUKS headers"
|
||||
cat "$KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks ||
|
||||
die "Unable to measure the LUKS headers"
|
||||
|
||||
pcrf="/tmp/secret/pcrf.bin"
|
||||
tpmr pcrread 0 "$pcrf"
|
||||
@ -94,19 +118,19 @@ tpmr pcrread -a 1 "$pcrf"
|
||||
tpmr pcrread -a 2 "$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.
|
||||
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
|
||||
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
|
||||
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 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"
|
||||
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..."
|
||||
tpmr calcfuturepcr 6 "/tmp/luksDump.txt" >> "$pcrf"
|
||||
DEBUG "Precomputing TPM future value for PCR6 sealing/unsealing of TPM Disk Unlock Key..."
|
||||
tpmr calcfuturepcr 6 "/tmp/luksDump.txt" >>"$pcrf"
|
||||
# We take into consideration user files in cbfs
|
||||
tpmr pcrread -a 7 "$pcrf"
|
||||
|
||||
@ -115,9 +139,12 @@ DO_WITH_DEBUG --mask-position 7 \
|
||||
"$TPM_SIZE" "$key_password"
|
||||
|
||||
# should be okay if this fails
|
||||
shred -n 10 -z -u "$pcrf".* 2> /dev/null || true
|
||||
shred -n 10 -z -u "$KEY_FILE" 2> /dev/null \
|
||||
|| warn "Failed to delete key file - continuing"
|
||||
shred -n 10 -z -u "$pcrf" 2>/dev/null ||
|
||||
warn "Failed to delete pcrf 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" \
|
||||
|| warn "Failed to have hashes of LUKS header - continuing"
|
||||
mount -o rw,remount $paramsdir || die "Failed to remount $paramsdir in RW - 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"
|
||||
|
@ -56,12 +56,12 @@ if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
|
||||
sha256sum -c "$PRIMHASH_FILE" \
|
||||
|| {
|
||||
echo "FATAL: Hash of TPM2 primary key handle mismatch!";
|
||||
echo "If you have not intentionally regenerated TPM2 primary key,";
|
||||
warn "your system may have been compromised!";
|
||||
warn "If you have not intentionally regenerated TPM2 primary key,";
|
||||
warn "your system may have been compromised";
|
||||
}
|
||||
else
|
||||
echo "WARNING: Hash of TPM2 primary key handle does not exist!"
|
||||
echo "Please rebuild the boot hash tree."
|
||||
warn "Hash of TPM2 primary key handle does not exist"
|
||||
warn "Please rebuild the boot hash tree"
|
||||
default_failed="y"
|
||||
fi
|
||||
fi
|
||||
@ -252,7 +252,7 @@ default_select() {
|
||||
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
|
||||
fi
|
||||
warn "!!! Boot entry has changed - please set a new default"
|
||||
warn "Boot entry has changed - please set a new default"
|
||||
return
|
||||
fi
|
||||
parse_option
|
||||
|
@ -26,7 +26,7 @@ DEBUG "Show PCRs"
|
||||
DEBUG "$(pcrs)"
|
||||
|
||||
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
|
||||
if [ -z "$tpm_password" ]; then
|
||||
die "Aborting unseal disk encryption key"
|
||||
|
@ -1,21 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Measure all of the luks disk encryption headers into
|
||||
# Measure all of the LUKS Disk Encryption headers into
|
||||
# a PCR so that we can detect disk swap attacks.
|
||||
. /etc/functions
|
||||
|
||||
TRACE "Under /bin/qubes-measure-luks"
|
||||
DEBUG "Arguments passed to qubes-measure-luks: $@"
|
||||
|
||||
die() { echo >&2 "$@"; exit 1; }
|
||||
|
||||
# Measure the luks headers into PCR 6
|
||||
# Measure the LUKS headers into PCR 6
|
||||
for dev in "$@"; do
|
||||
DEBUG "Storing LUKS header for $dev into /tmp/lukshdr-$(echo "$dev" | sed 's/\//_/g')"
|
||||
cryptsetup luksHeaderBackup $dev \
|
||||
--header-backup-file /tmp/lukshdr-$(echo "$dev" | sed 's/\//_/g') \
|
||||
|| die "$dev: Unable to read luks header"
|
||||
--header-backup-file /tmp/lukshdr-$(echo "$dev" | sed 's/\//_/g') ||
|
||||
die "$dev: Unable to read LUKS header"
|
||||
done
|
||||
|
||||
sha256sum /tmp/lukshdr-* > /tmp/luksDump.txt || die "Unable to hash luks headers"
|
||||
DEBUG "Hashing luks headers into /tmp/luksDump.txt"
|
||||
sha256sum /tmp/lukshdr-* >/tmp/luksDump.txt || die "Unable to hash luks headers"
|
||||
DEBUG "Removing /tmp/lukshdr-*"
|
||||
rm /tmp/lukshdr-*
|
||||
|
||||
tpmr extend -ix 6 -if /tmp/luksDump.txt \
|
||||
|| die "Unable to extend PCR"
|
||||
DEBUG "Extending PCR 6 with /tmp/luksDump.txt"
|
||||
tpmr extend -ix 6 -if /tmp/luksDump.txt ||
|
||||
die "Unable to extend PCR"
|
||||
|
@ -9,7 +9,7 @@ HOTP_KEY="/boot/kexec_hotp_key"
|
||||
|
||||
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
|
||||
if ! grep -q /boot /proc/mounts ; then
|
||||
mount -o ro /boot \
|
||||
|
@ -495,13 +495,13 @@ tpm1_seal() {
|
||||
# The permissions are 0 since there is nothing special
|
||||
# about the sealed file
|
||||
tpm physicalpresence -s \
|
||||
|| warn "Warning: Unable to assert physical presence"
|
||||
|| warn "Unable to assert physical presence"
|
||||
|
||||
prompt_tpm_password
|
||||
|
||||
tpm nv_definespace -in "$index" -sz "$sealed_size" \
|
||||
-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" \
|
||||
@ -595,7 +595,7 @@ tpm2_reset() {
|
||||
TRACE "Under /bin/tpmr:tpm2_reset"
|
||||
key_password="$1"
|
||||
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 endorsement "$(tpm2_password_hex "$key_password")"
|
||||
tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \
|
||||
@ -673,7 +673,7 @@ tpm2_kexec_finalize() {
|
||||
echo "Locking TPM2 platform hierarchy..."
|
||||
randpass=$(dd if=/dev/urandom bs=4 count=1 status=none | xxd -p)
|
||||
tpm2 changeauth -c platform "$randpass" \
|
||||
|| warn "Failed to lock platform hierarchy of TPM2!"
|
||||
|| warn "Failed to lock platform hierarchy of TPM2"
|
||||
}
|
||||
|
||||
tpm2_shutdown() {
|
||||
|
@ -3,6 +3,7 @@ set -e -o pipefail
|
||||
|
||||
. /etc/functions
|
||||
|
||||
TRACE "Under unpack_initramfs.sh"
|
||||
# Unpack a Linux initramfs archive.
|
||||
#
|
||||
# In general, the initramfs archive is one or more cpio archives, optionally
|
||||
@ -30,6 +31,7 @@ CPIO_ARGS=("$@")
|
||||
|
||||
# Consume zero bytes, the first nonzero byte read (if any) is repeated on stdout
|
||||
consume_zeros() {
|
||||
TRACE "Under unpack_initramfs.sh:consume_zeros"
|
||||
next_byte='00'
|
||||
while [ "$next_byte" = "00" ]; do
|
||||
# if we reach EOF, next_byte becomes empty (dd does not fail)
|
||||
@ -42,11 +44,13 @@ consume_zeros() {
|
||||
}
|
||||
|
||||
unpack_cpio() {
|
||||
TRACE "Under unpack_initramfs.sh:unpack_cpio"
|
||||
(cd "$dest_dir"; cpio -i "${CPIO_ARGS[@]}" 2>/dev/null)
|
||||
}
|
||||
|
||||
# unpack the first segment of an archive, then write the rest to another file
|
||||
unpack_first_segment() {
|
||||
TRACE "Under unpack_initramfs.sh:unpack_first_segment"
|
||||
unpack_archive="$1"
|
||||
dest_dir="$2"
|
||||
rest_archive="$3"
|
||||
@ -62,18 +66,21 @@ unpack_first_segment() {
|
||||
# lib/decompress.c (gzip)
|
||||
case "$magic" in
|
||||
00*)
|
||||
DEBUG "archive segment $magic: uncompressed cpio"
|
||||
# Skip zero bytes and copy the first nonzero byte
|
||||
consume_zeros
|
||||
# Copy the remaining data
|
||||
cat
|
||||
;;
|
||||
303730373031*|303730373032*) # plain cpio
|
||||
DEBUG "archive segment $magic: plain cpio"
|
||||
# Unpack the plain cpio, this stops reading after the trailer
|
||||
unpack_cpio
|
||||
# Copy the remaining data
|
||||
cat
|
||||
;;
|
||||
1f8b*|1f9e*) # gzip
|
||||
DEBUG "archive segment $magic: gzip"
|
||||
# gunzip won't stop when reaching the end of the gzipped member,
|
||||
# so we can't read another segment after this. We can't
|
||||
# reasonably determine the member length either, this requires
|
||||
@ -81,6 +88,7 @@ unpack_first_segment() {
|
||||
gunzip | unpack_cpio
|
||||
;;
|
||||
28b5*) # zstd
|
||||
DEBUG "archive segment $magic: zstd"
|
||||
# Like gunzip, this will not stop when reaching the end of the
|
||||
# frame, and determining the frame length requires walking all
|
||||
# of its blocks.
|
||||
|
@ -4,13 +4,13 @@
|
||||
# busybox ash on legacy-flash boards, and with bash on all other boards.
|
||||
|
||||
die() {
|
||||
echo >&2 "$*";
|
||||
echo >&2 " !!! ERROR: $* !!!";
|
||||
sleep 2;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo >&2 "$*";
|
||||
echo >&2 " *** WARNING: $* ***";
|
||||
sleep 1;
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,7 @@ pcrs() {
|
||||
fi
|
||||
}
|
||||
|
||||
confirm_totp()
|
||||
{
|
||||
confirm_totp() {
|
||||
TRACE "Under /etc/functions:confirm_totp"
|
||||
prompt="$1"
|
||||
last_half=X
|
||||
@ -51,15 +50,15 @@ confirm_totp()
|
||||
while true; do
|
||||
|
||||
# update the TOTP code every thirty seconds
|
||||
date=`date "+%Y-%m-%d %H:%M:%S"`
|
||||
seconds=`date "+%s"`
|
||||
half=`expr \( $seconds % 60 \) / 30`
|
||||
date=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
seconds=$(date "+%s")
|
||||
half=$(expr \( $seconds % 60 \) / 30)
|
||||
if [ "$CONFIG_TPM" != "y" ]; then
|
||||
TOTP="NO TPM"
|
||||
elif [ "$half" != "$last_half" ]; then
|
||||
last_half=$half;
|
||||
TOTP=`unseal-totp` \
|
||||
|| recovery "TOTP code generation failed"
|
||||
last_half=$half
|
||||
TOTP=$(unseal-totp) ||
|
||||
recovery "TOTP code generation failed"
|
||||
fi
|
||||
|
||||
echo -n "$date $TOTP: "
|
||||
@ -70,8 +69,8 @@ confirm_totp()
|
||||
-n 1 \
|
||||
-s \
|
||||
-p "$prompt" \
|
||||
totp_confirm \
|
||||
&& break
|
||||
totp_confirm &&
|
||||
break
|
||||
|
||||
# nothing typed, redraw the line
|
||||
echo -ne '\r'
|
||||
@ -81,26 +80,59 @@ confirm_totp()
|
||||
echo
|
||||
}
|
||||
|
||||
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
|
||||
if [ "$CONFIG_TPM_DISK_UNLOCK_KEY" == "n" ]; then
|
||||
DEBUG "TPM Disk Unlock Key is prohibited in board configs"
|
||||
return
|
||||
else
|
||||
DEBUG "TPM Disk Unlock Key is allowed in board configs. Continuing"
|
||||
fi
|
||||
|
||||
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 Unlock Key previously sealed is now invalid since firmware measurements could not unseal TOTP"
|
||||
echo "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 /boot/kexec_luks_hdr_hash.txt"
|
||||
echo "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
|
||||
# be detected. If USB storage was already enabled, no wait occurs, this would
|
||||
# have happened already when USB storage was enabled.
|
||||
enable_usb_storage()
|
||||
{
|
||||
enable_usb_storage() {
|
||||
if ! lsmod | grep -q usb_storage; then
|
||||
timeout=0
|
||||
echo "Scanning for USB storage devices..."
|
||||
insmod /lib/modules/usb-storage.ko >/dev/null 2>&1 \
|
||||
|| die "usb_storage: module load failed"
|
||||
while [[ $(list_usb_storage | wc -l) -eq 0 ]]; do
|
||||
insmod /lib/modules/usb-storage.ko >/dev/null 2>&1 ||
|
||||
die "usb_storage: module load failed"
|
||||
while [[ $(list_usb_storage | wc -l) -eq 0 ]]; do
|
||||
[[ $timeout -ge 8 ]] && break
|
||||
sleep 1
|
||||
timeout=$(($timeout+1))
|
||||
timeout=$(($timeout + 1))
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
list_usb_storage()
|
||||
{
|
||||
list_usb_storage() {
|
||||
TRACE "Under /etc/functions:list_usb_storage"
|
||||
# List all USB storage devices, including partitions unless we received argument stating we want drives only
|
||||
# The output is a list of device names, one per line.
|
||||
@ -157,8 +189,7 @@ list_usb_storage()
|
||||
done
|
||||
}
|
||||
|
||||
confirm_gpg_card()
|
||||
{
|
||||
confirm_gpg_card() {
|
||||
TRACE "Under /etc/functions:confirm_gpg_card"
|
||||
read \
|
||||
-n 1 \
|
||||
@ -169,7 +200,7 @@ confirm_gpg_card()
|
||||
if [ "$card_confirm" != "y" \
|
||||
-a "$card_confirm" != "Y" \
|
||||
-a -n "$card_confirm" ] \
|
||||
; then
|
||||
; then
|
||||
die "gpg card not confirmed"
|
||||
fi
|
||||
|
||||
@ -180,23 +211,23 @@ confirm_gpg_card()
|
||||
# ensure we don't exit without retrying
|
||||
errexit=$(set -o | grep errexit | awk '{print $2}')
|
||||
set +e
|
||||
gpg --card-status > /dev/null
|
||||
gpg --card-status >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
# prompt for reinsertion and try a second time
|
||||
read -n1 -r -p \
|
||||
"Can't access GPG key; remove and reinsert, then press Enter to retry. " \
|
||||
ignored
|
||||
# restore prev errexit state
|
||||
if [ "$errexit" = "on" ]; then
|
||||
set -e
|
||||
fi
|
||||
# retry card status
|
||||
gpg --card-status > /dev/null \
|
||||
|| die "gpg card read failed"
|
||||
# prompt for reinsertion and try a second time
|
||||
read -n1 -r -p \
|
||||
"Can't access GPG key; remove and reinsert, then press Enter to retry. " \
|
||||
ignored
|
||||
# restore prev errexit state
|
||||
if [ "$errexit" = "on" ]; then
|
||||
set -e
|
||||
fi
|
||||
# retry card status
|
||||
gpg --card-status >/dev/null ||
|
||||
die "gpg card read failed"
|
||||
fi
|
||||
# restore prev errexit state
|
||||
if [ "$errexit" = "on" ]; then
|
||||
set -e
|
||||
set -e
|
||||
fi
|
||||
}
|
||||
|
||||
@ -205,7 +236,7 @@ confirm_gpg_card()
|
||||
# line, since some flows need it multiple times and only one prompt is ideal.
|
||||
prompt_tpm_password() {
|
||||
if [ -n "$tpm_password" ]; then
|
||||
return 0;
|
||||
return 0
|
||||
fi
|
||||
|
||||
read -s -p "TPM Owner password: " tpm_password
|
||||
@ -233,25 +264,24 @@ prompt_new_owner_password() {
|
||||
done
|
||||
}
|
||||
|
||||
check_tpm_counter()
|
||||
{
|
||||
TRACE "Under /etc/functions:check_tpm_counter"
|
||||
LABEL=${2:-3135106223}
|
||||
tpm_password="$3"
|
||||
check_tpm_counter() {
|
||||
TRACE "Under /etc/functions:check_tpm_counter"
|
||||
LABEL=${2:-3135106223}
|
||||
tpm_password="$3"
|
||||
# if the /boot.hashes file already exists, read the TPM counter ID
|
||||
# from it.
|
||||
if [ -r "$1" ]; then
|
||||
TPM_COUNTER=`grep counter- "$1" | cut -d- -f2`
|
||||
TPM_COUNTER=$(grep counter- "$1" | cut -d- -f2)
|
||||
else
|
||||
warn "$1 does not exist; creating new TPM counter"
|
||||
prompt_tpm_password
|
||||
tpmr counter_create \
|
||||
-pwdo "$tpm_password" \
|
||||
-pwdc '' \
|
||||
-la $LABEL \
|
||||
| tee /tmp/counter \
|
||||
|| die "Unable to create TPM counter"
|
||||
TPM_COUNTER=`cut -d: -f1 < /tmp/counter`
|
||||
-la $LABEL |
|
||||
tee /tmp/counter ||
|
||||
die "Unable to create TPM counter"
|
||||
TPM_COUNTER=$(cut -d: -f1 </tmp/counter)
|
||||
fi
|
||||
|
||||
if [ -z "$TPM_COUNTER" ]; then
|
||||
@ -259,48 +289,46 @@ check_tpm_counter()
|
||||
fi
|
||||
}
|
||||
|
||||
read_tpm_counter()
|
||||
{
|
||||
read_tpm_counter() {
|
||||
TRACE "Under /etc/functions:read_tpm_counter"
|
||||
tpmr counter_read -ix "$1" | tee "/tmp/counter-$1" \
|
||||
|| die "Counter read failed"
|
||||
tpmr counter_read -ix "$1" | tee "/tmp/counter-$1" ||
|
||||
die "Counter read failed"
|
||||
}
|
||||
|
||||
increment_tpm_counter()
|
||||
{
|
||||
increment_tpm_counter() {
|
||||
TRACE "Under /etc/functions:increment_tpm_counter"
|
||||
tpmr counter_increment -ix "$1" -pwdc '' \
|
||||
| tee /tmp/counter-$1 \
|
||||
|| die "Counter increment failed"
|
||||
tpmr counter_increment -ix "$1" -pwdc '' |
|
||||
tee /tmp/counter-$1 ||
|
||||
die "Counter increment failed"
|
||||
}
|
||||
|
||||
check_config() {
|
||||
TRACE "Under /etc/functions:check_config"
|
||||
if [ ! -d /tmp/kexec ]; then
|
||||
mkdir /tmp/kexec \
|
||||
|| die 'Failed to make kexec tmp dir'
|
||||
mkdir /tmp/kexec ||
|
||||
die 'Failed to make kexec tmp dir'
|
||||
else
|
||||
rm -rf /tmp/kexec/* \
|
||||
|| die 'Failed to empty kexec tmp dir'
|
||||
rm -rf /tmp/kexec/* ||
|
||||
die 'Failed to empty kexec tmp dir'
|
||||
fi
|
||||
|
||||
if [ ! -r $1/kexec.sig -a "$CONFIG_BASIC" != "y" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ `find $1/kexec*.txt | wc -l` -eq 0 ]; then
|
||||
if [ $(find $1/kexec*.txt | wc -l) -eq 0 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$2" != "force" ]; then
|
||||
if ! sha256sum `find $1/kexec*.txt` | gpgv $1/kexec.sig - ; then
|
||||
if ! sha256sum $(find $1/kexec*.txt) | gpgv $1/kexec.sig -; then
|
||||
die 'Invalid signature on kexec boot params'
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "+++ Found verified kexec boot params"
|
||||
cp $1/kexec*.txt /tmp/kexec \
|
||||
|| die "Failed to copy kexec boot params to tmp"
|
||||
cp $1/kexec*.txt /tmp/kexec ||
|
||||
die "Failed to copy kexec boot params to tmp"
|
||||
}
|
||||
|
||||
# Replace a file in a ROM (add it if the file does not exist)
|
||||
@ -308,8 +336,8 @@ replace_rom_file() {
|
||||
ROM="$1"
|
||||
ROM_FILE="$2"
|
||||
NEW_FILE="$3"
|
||||
|
||||
if (cbfs.sh -o "$ROM" -l | grep -q "$ROM_FILE") then
|
||||
|
||||
if (cbfs.sh -o "$ROM" -l | grep -q "$ROM_FILE"); then
|
||||
cbfs.sh -o "$ROM" -d "$ROM_FILE"
|
||||
fi
|
||||
cbfs.sh -o "$ROM" -a "$ROM_FILE" -f "$NEW_FILE"
|
||||
@ -322,13 +350,13 @@ replace_config() {
|
||||
NEW_SETTING=$3
|
||||
|
||||
touch $CONFIG_FILE
|
||||
# first pull out the existing option from the global config and place in a tmp file
|
||||
awk "gsub(\"^export ${CONFIG_OPTION}=.*\",\"export ${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config > ${CONFIG_FILE}.tmp
|
||||
awk "gsub(\"^${CONFIG_OPTION}=.*\",\"${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config >> ${CONFIG_FILE}.tmp
|
||||
# first pull out the existing option from the global config and place in a tmp file
|
||||
awk "gsub(\"^export ${CONFIG_OPTION}=.*\",\"export ${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config >${CONFIG_FILE}.tmp
|
||||
awk "gsub(\"^${CONFIG_OPTION}=.*\",\"${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config >>${CONFIG_FILE}.tmp
|
||||
|
||||
# then copy any remaining settings from the existing config file, minus the option you changed
|
||||
grep -v "^export ${CONFIG_OPTION}=" ${CONFIG_FILE} | grep -v "^${CONFIG_OPTION}=" >> ${CONFIG_FILE}.tmp || true
|
||||
sort ${CONFIG_FILE}.tmp | uniq > ${CONFIG_FILE}
|
||||
# then copy any remaining settings from the existing config file, minus the option you changed
|
||||
grep -v "^export ${CONFIG_OPTION}=" ${CONFIG_FILE} | grep -v "^${CONFIG_OPTION}=" >>${CONFIG_FILE}.tmp || true
|
||||
sort ${CONFIG_FILE}.tmp | uniq >${CONFIG_FILE}
|
||||
rm -f ${CONFIG_FILE}.tmp
|
||||
}
|
||||
|
||||
@ -338,7 +366,7 @@ set_config() {
|
||||
CONFIG_FILE="$1"
|
||||
CONFIG_OPTION="$2"
|
||||
NEW_SETTING="$3"
|
||||
|
||||
|
||||
if grep -q "$CONFIG_OPTION" "$CONFIG_FILE"; then
|
||||
replace_config "$CONFIG_FILE" "$CONFIG_OPTION" "$NEW_SETTING"
|
||||
else
|
||||
@ -359,12 +387,11 @@ set_user_config() {
|
||||
|
||||
# Load a config value to a variable, defaulting to empty. Does not fail if the
|
||||
# config is not set (since it would expand to empty by default).
|
||||
load_config_value()
|
||||
{
|
||||
local config_name="$1"
|
||||
if grep -q "$config_name=" /tmp/config; then
|
||||
grep "$config_name=" /tmp/config | tail -n1 | cut -f2 -d '=' | tr -d '"'
|
||||
fi
|
||||
load_config_value() {
|
||||
local config_name="$1"
|
||||
if grep -q "$config_name=" /tmp/config; then
|
||||
grep "$config_name=" /tmp/config | tail -n1 | cut -f2 -d '=' | tr -d '"'
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate a secret for TPM-less HOTP by reading the ROM. Output is the
|
||||
@ -383,13 +410,12 @@ secret_from_rom_hash() {
|
||||
sha256sum "${ROM_IMAGE}" | cut -f1 -d ' ' | fromhex_plain
|
||||
}
|
||||
|
||||
update_checksums()
|
||||
{
|
||||
update_checksums() {
|
||||
TRACE "Under /etc/functions:update_checksums"
|
||||
# ensure /boot mounted
|
||||
if ! grep -q /boot /proc/mounts ; then
|
||||
mount -o ro /boot \
|
||||
|| recovery "Unable to mount /boot"
|
||||
if ! grep -q /boot /proc/mounts; then
|
||||
mount -o ro /boot ||
|
||||
recovery "Unable to mount /boot"
|
||||
fi
|
||||
|
||||
# remount RW
|
||||
@ -397,12 +423,12 @@ update_checksums()
|
||||
|
||||
# sign and auto-roll config counter
|
||||
extparam=
|
||||
if [ "$CONFIG_TPM" = "y" ];then
|
||||
if [ "$CONFIG_TPM" = "y" ]; then
|
||||
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
|
||||
extparam=-r
|
||||
fi
|
||||
fi
|
||||
if ! kexec-sign-config -p /boot -u $extparam ; then
|
||||
if ! kexec-sign-config -p /boot -u $extparam; then
|
||||
rv=1
|
||||
else
|
||||
rv=0
|
||||
@ -436,15 +462,15 @@ escape_zero() {
|
||||
|
||||
echo -e -n "$prefix"
|
||||
xxd -p -c1 | tr -d '\n' |
|
||||
{
|
||||
while IFS= read -r -n2 -d '' ; do
|
||||
if [ -n "$todo" ] ; then
|
||||
#REPLY == " " is EOF
|
||||
[[ "$REPLY" == " " ]] && echo '' || echo -e -n "$todo"
|
||||
todo=""
|
||||
fi
|
||||
{
|
||||
while IFS= read -r -n2 -d ''; do
|
||||
if [ -n "$todo" ]; then
|
||||
#REPLY == " " is EOF
|
||||
[[ "$REPLY" == " " ]] && echo '' || echo -e -n "$todo"
|
||||
todo=""
|
||||
fi
|
||||
|
||||
case "$REPLY" in
|
||||
case "$REPLY" in
|
||||
00)
|
||||
todo="\n$prefix"
|
||||
;;
|
||||
@ -467,16 +493,16 @@ escape_zero() {
|
||||
echo -n "$echar$echar"
|
||||
;;
|
||||
#interpreted characters:
|
||||
2[0-9a-f]|3[0-9a-f]|4[0-9a-f]|5[0-9abd-f]|6[0-9a-f]|7[0-9a-e])
|
||||
2[0-9a-f] | 3[0-9a-f] | 4[0-9a-f] | 5[0-9abd-f] | 6[0-9a-f] | 7[0-9a-e])
|
||||
echo -e -n '\x'"$REPLY"
|
||||
;;
|
||||
# All others are escaped
|
||||
*)
|
||||
echo -n "${echar}x$REPLY"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
esac
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
# Currently heads doesn't support signing file names with certain characters
|
||||
@ -485,14 +511,14 @@ escape_zero() {
|
||||
assert_signable() {
|
||||
TRACE "Under /etc/functions:assert_signable"
|
||||
# ensure /boot mounted
|
||||
if ! grep -q /boot /proc/mounts ; then
|
||||
if ! grep -q /boot /proc/mounts; then
|
||||
mount -o ro /boot || die "Unable to mount /boot"
|
||||
fi
|
||||
|
||||
find /boot -print0 > /tmp/signable.ref
|
||||
find /boot -print0 >/tmp/signable.ref
|
||||
local del='\001-\037\134\177-\377'
|
||||
LC_ALL=C tr -d "$del" < /tmp/signable.ref > /tmp/signable.del || die "Failed to execute tr."
|
||||
if ! cmp -s "/tmp/signable.ref" "/tmp/signable.del" &> /dev/null ; then
|
||||
LC_ALL=C tr -d "$del" </tmp/signable.ref >/tmp/signable.del || die "Failed to execute tr."
|
||||
if ! cmp -s "/tmp/signable.ref" "/tmp/signable.del" &>/dev/null; then
|
||||
local user_out="/tmp/hash_output_mismatches"
|
||||
local add="Please investigate!"
|
||||
[ -f "$user_out" ] && add="Please investigate the following relative paths to /boot (where # are sanitized invalid characters):"$'\n'"$(cat "$user_out")"
|
||||
@ -501,8 +527,7 @@ assert_signable() {
|
||||
rm -f /tmp/signable.*
|
||||
}
|
||||
|
||||
verify_checksums()
|
||||
{
|
||||
verify_checksums() {
|
||||
TRACE "Under /etc/functions:verify_checksums"
|
||||
local boot_dir="$1"
|
||||
local gui="${2:-y}"
|
||||
@ -511,20 +536,20 @@ verify_checksums()
|
||||
set +e -o pipefail
|
||||
local ret=0
|
||||
cd "$boot_dir" || ret=1
|
||||
sha256sum -c "$TMP_HASH_FILE" > /tmp/hash_output || ret=1
|
||||
sha256sum -c "$TMP_HASH_FILE" >/tmp/hash_output || ret=1
|
||||
|
||||
# also make sure that the file & directory structure didn't change
|
||||
# (sha256sum won't detect added files)
|
||||
print_tree > /tmp/tree_output || ret=1
|
||||
if ! cmp -s "$TMP_TREE_FILE" /tmp/tree_output &> /dev/null ; then
|
||||
print_tree >/tmp/tree_output || ret=1
|
||||
if ! cmp -s "$TMP_TREE_FILE" /tmp/tree_output &>/dev/null; then
|
||||
ret=1
|
||||
[[ "$gui" != "y" ]] && exit "$ret"
|
||||
# produce a diff that can safely be presented to the user
|
||||
# this is relatively hard as file names may e.g. contain backslashes etc.,
|
||||
# which are interpreted by whiptail, less, ...
|
||||
escape_zero "(new) " < "$TMP_TREE_FILE" > "${TMP_TREE_FILE}.user"
|
||||
escape_zero "(new) " < /tmp/tree_output > /tmp/tree_output.user
|
||||
diff "${TMP_TREE_FILE}.user" /tmp/tree_output.user | grep -E '^\+\(new\).*$' | sed -r 's/^\+\(new\)/(new)/g' >> /tmp/hash_output
|
||||
escape_zero "(new) " <"$TMP_TREE_FILE" >"${TMP_TREE_FILE}.user"
|
||||
escape_zero "(new) " </tmp/tree_output >/tmp/tree_output.user
|
||||
diff "${TMP_TREE_FILE}.user" /tmp/tree_output.user | grep -E '^\+\(new\).*$' | sed -r 's/^\+\(new\)/(new)/g' >>/tmp/hash_output
|
||||
rm -f "${TMP_TREE_FILE}.user"
|
||||
rm -f /tmp/tree_output.user
|
||||
fi
|
||||
@ -535,8 +560,7 @@ verify_checksums()
|
||||
|
||||
# detect and set /boot device
|
||||
# mount /boot if successful
|
||||
detect_boot_device()
|
||||
{
|
||||
detect_boot_device() {
|
||||
TRACE "Under /etc/functions:detect_boot_device"
|
||||
# unmount /boot to be safe
|
||||
cd / && umount /boot 2>/dev/null
|
||||
@ -552,22 +576,22 @@ detect_boot_device()
|
||||
fi
|
||||
|
||||
# generate list of possible boot devices
|
||||
fdisk -l | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" > /tmp/disklist
|
||||
fdisk -l | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" >/tmp/disklist
|
||||
|
||||
# filter out extraneous options
|
||||
> /tmp/boot_device_list
|
||||
for i in `cat /tmp/disklist`; do
|
||||
>/tmp/boot_device_list
|
||||
for i in $(cat /tmp/disklist); do
|
||||
# remove block device from list if numeric partitions exist, since not bootable
|
||||
DEV_NUM_PARTITIONS=$((`ls -1 $i* | wc -l`-1))
|
||||
DEV_NUM_PARTITIONS=$(($(ls -1 $i* | wc -l) - 1))
|
||||
if [ ${DEV_NUM_PARTITIONS} -eq 0 ]; then
|
||||
echo $i >> /tmp/boot_device_list
|
||||
echo $i >>/tmp/boot_device_list
|
||||
else
|
||||
ls $i* | tail -${DEV_NUM_PARTITIONS} >> /tmp/boot_device_list
|
||||
ls $i* | tail -${DEV_NUM_PARTITIONS} >>/tmp/boot_device_list
|
||||
fi
|
||||
done
|
||||
|
||||
# iterate thru possible options and check for grub dir
|
||||
for i in `cat /tmp/boot_device_list`; do
|
||||
for i in $(cat /tmp/boot_device_list); do
|
||||
umount /boot 2>/dev/null
|
||||
if mount -o ro $i /boot >/dev/null 2>&1; then
|
||||
if ls -d /boot/grub* >/dev/null 2>&1; then
|
||||
@ -583,30 +607,28 @@ detect_boot_device()
|
||||
return 1
|
||||
}
|
||||
|
||||
scan_boot_options()
|
||||
{
|
||||
scan_boot_options() {
|
||||
local bootdir config option_file
|
||||
bootdir="$1"
|
||||
config="$2"
|
||||
option_file="$3"
|
||||
|
||||
if [ -r $option_file ]; then rm $option_file; fi
|
||||
for i in `find $bootdir -name "$config"`; do
|
||||
DO_WITH_DEBUG kexec-parse-boot "$bootdir" "$i" >> $option_file
|
||||
for i in $(find $bootdir -name "$config"); do
|
||||
DO_WITH_DEBUG kexec-parse-boot "$bootdir" "$i" >>$option_file
|
||||
done
|
||||
# FC29/30+ may use BLS format grub config files
|
||||
# https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault
|
||||
# only parse these if $option_file is still empty
|
||||
if [ ! -s $option_file ] && [ -d "$bootdir/loader/entries" ]; then
|
||||
for i in `find $bootdir -name "$config"`; do
|
||||
kexec-parse-bls "$bootdir" "$i" "$bootdir/loader/entries" >> $option_file
|
||||
for i in $(find $bootdir -name "$config"); do
|
||||
kexec-parse-bls "$bootdir" "$i" "$bootdir/loader/entries" >>$option_file
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
calc()
|
||||
{
|
||||
awk "BEGIN { print "$*" }";
|
||||
calc() {
|
||||
awk "BEGIN { print "$*" }"
|
||||
}
|
||||
|
||||
# truncate a file to a size only if it is longer (busybox truncate lacks '<' and
|
||||
@ -635,24 +657,21 @@ fromhex_plain() {
|
||||
fold -w 60 | xxd -p -r
|
||||
}
|
||||
|
||||
print_battery_health()
|
||||
{
|
||||
print_battery_health() {
|
||||
if [ -d /sys/class/power_supply/BAT* ]; then
|
||||
battery_health=$(calc $(cat /sys/class/power_supply/BAT*/charge_full)/$(cat /sys/class/power_supply/BAT*/charge_full_design)*100 | awk -F "." {'print $1'})
|
||||
battery_health=$(calc $(cat /sys/class/power_supply/BAT*/charge_full)/$(cat /sys/class/power_supply/BAT*/charge_full_design)*100 | awk -F "." {'print $1'})
|
||||
echo "$battery_health"
|
||||
fi
|
||||
}
|
||||
|
||||
print_battery_charge()
|
||||
{
|
||||
print_battery_charge() {
|
||||
if [ -d /sys/class/power_supply/BAT* ]; then
|
||||
battery_charge=$(calc $(cat /sys/class/power_supply/BAT*/charge_now)/$(cat /sys/class/power_supply/BAT*/charge_full)*100 | awk -F "." {'print $1'})
|
||||
echo "$battery_charge"
|
||||
fi
|
||||
battery_charge=$(calc $(cat /sys/class/power_supply/BAT*/charge_now)/$(cat /sys/class/power_supply/BAT*/charge_full)*100 | awk -F "." {'print $1'})
|
||||
echo "$battery_charge"
|
||||
fi
|
||||
}
|
||||
|
||||
generate_random_mac_address()
|
||||
{
|
||||
generate_random_mac_address() {
|
||||
#Borrowed from https://stackoverflow.com/questions/42660218/bash-generate-random-mac-address-unicast
|
||||
hexdump -n 6 -ve '1/1 "%.2x "' /dev/urandom | awk -v a="2,6,a,e" -v r="$RANDOM" 'BEGIN{srand(r);}NR==1{split(a,b,",");r=int(rand()*4+1);printf "%s%s:%s:%s:%s:%s:%s\n",substr($1,0,1),b[r],$2,$3,$4,$5,$6}'
|
||||
}
|
||||
@ -683,9 +702,9 @@ run_at_exit_handlers() {
|
||||
# Silence trace if there are no handlers, this is common and occurs a lot
|
||||
[ "$cmd_pos" -gt 0 ] && DEBUG "Running at_exit handlers"
|
||||
while [ "$cmd_pos" -gt 0 ]; do
|
||||
cmd_pos="$((cmd_pos-1))"
|
||||
cmd_pos="$((cmd_pos - 1))"
|
||||
cmd_len="${AT_EXIT_HANDLERS[$cmd_pos]}"
|
||||
cmd_pos="$((cmd_pos-cmd_len))"
|
||||
cmd_pos="$((cmd_pos - cmd_len))"
|
||||
"${AT_EXIT_HANDLERS[@]:$cmd_pos:$cmd_len}"
|
||||
done
|
||||
}
|
||||
|
@ -246,7 +246,6 @@ select_luks_container()
|
||||
mount -o remount,ro /boot
|
||||
fi
|
||||
else
|
||||
|
||||
warn "No encrypted device found."
|
||||
return 1
|
||||
fi
|
||||
@ -302,7 +301,7 @@ while : ; do
|
||||
if [ -z "$luks_current_Disk_Recovery_Key_passphrase" ]; then
|
||||
#if no external provisioning provides current Disk Recovery Key passphrase
|
||||
whiptail --title 'Reencrypt LUKS disk encrypted container ?' \
|
||||
--msgbox "This will replace the encrypted container content and its Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user in the\nfollowing conditions:\n 1-Every boot if no Disk unlock key was added to the TPM\n 2-If the TPM fails (Hardware failure)\n 3-If the firmware has been tampered with/upgraded/modified by the user\n\nThis process requires you to type the current Disk Recovery Key passphrase\nand will delete TPM Disk unlock key slot if setuped by setting a default boot\n LUKS header (slot 1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to\nthe LUKS device container.\n\nHit Enter to continue." 0 80
|
||||
--msgbox "This will replace the encrypted container content and its Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user in the\nfollowing conditions:\n 1-Every boot if no Disk unlock key was added to the TPM\n 2-If the TPM fails (Hardware failure)\n 3-If the firmware has been tampered with/upgraded/modified by the user\n\nThis process requires you to type the current Disk Recovery Key passphrase\nand will delete TPM Disk unlock key slot if set up by setting a default boot\n LUKS header (slot 1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to\nthe LUKS device container.\n\nHit Enter to continue." 0 80
|
||||
echo -e "\nEnter current Disk Recovery Key passphrase (Provisioned at OS installation or by OEM):"
|
||||
read -r luks_current_Disk_Recovery_Key_passphrase
|
||||
echo -n "$luks_current_Disk_Recovery_Key_passphrase" > /tmp/luks_current_Disk_Recovery_Key_passphrase
|
||||
|
@ -4,10 +4,9 @@
|
||||
# The default PCR to be extended is 5, but can be
|
||||
# overridden with the MODULE_PCR environment variable
|
||||
|
||||
die() {
|
||||
echo >&2 "$@"
|
||||
exit 1
|
||||
}
|
||||
. /etc/functions
|
||||
|
||||
TRACE "Under insmod.sh"
|
||||
|
||||
MODULE="$1"; shift
|
||||
|
||||
@ -31,18 +30,22 @@ if [ ! -r /sys/class/tpm/tpm0/pcrs -o ! -x /bin/tpm ]; then
|
||||
fi
|
||||
|
||||
if [ -z "$tpm_missing" ]; then
|
||||
DEBUG "Extending PCR $MODULE_PCR with $MODULE"
|
||||
tpmr extend -ix "$MODULE_PCR" -if "$MODULE" \
|
||||
|| die "$MODULE: tpm extend failed"
|
||||
fi
|
||||
|
||||
if [ ! -z "$*" -a -z "$tpm_missing" ]; then
|
||||
DEBUG "Extending PCR $MODULE_PCR with $*"
|
||||
TMPFILE=/tmp/insmod.$$
|
||||
echo "$@" > $TMPFILE
|
||||
DEBUG "Extending PCR $MODULE_PCR with $TMPFILE"
|
||||
tpmr extend -ix "$MODULE_PCR" -if $TMPFILE \
|
||||
|| die "$MODULE: tpm extend on arguments failed"
|
||||
fi
|
||||
|
||||
# Since we have replaced the real insmod, we must invoke
|
||||
# the busybox insmod via the original executable
|
||||
DEBUG "Loading $MODULE with busybox insmod"
|
||||
busybox insmod "$MODULE" "$@" \
|
||||
|| die "$MODULE: insmod failed"
|
||||
|
@ -1,3 +1,6 @@
|
||||
# ZSTD is always included, unless explicitly turned off
|
||||
# Needed by initrd/bin/unpack_initramfs.sh under TPM Disk Unlock Key setup
|
||||
CONFIG_ZSTD ?= y
|
||||
modules-$(CONFIG_ZSTD) += zstd
|
||||
|
||||
zstd_version := 1.5.5
|
||||
|
Loading…
Reference in New Issue
Block a user