2023-02-08 21:01:48 +00:00
|
|
|
#!/bin/bash
|
2017-07-04 23:49:14 +00:00
|
|
|
# Save these options to be the persistent default
|
2017-07-12 04:17:45 +00:00
|
|
|
set -e -o pipefail
|
2018-12-06 23:24:28 +00:00
|
|
|
. /tmp/config
|
2017-07-04 23:49:14 +00:00
|
|
|
. /etc/functions
|
|
|
|
|
2024-02-01 19:30:31 +00:00
|
|
|
TRACE_FUNC
|
2023-02-18 17:58:43 +00:00
|
|
|
|
2017-07-22 20:32:10 +00:00
|
|
|
while getopts "b:d:p:i:" arg; do
|
2017-07-04 23:49:14 +00:00
|
|
|
case $arg in
|
2023-08-22 18:34:29 +00:00
|
|
|
b) bootdir="$OPTARG" ;;
|
|
|
|
d) paramsdev="$OPTARG" ;;
|
|
|
|
p) paramsdir="$OPTARG" ;;
|
|
|
|
i) index="$OPTARG" ;;
|
2017-07-04 23:49:14 +00:00
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
2017-07-08 20:59:37 +00:00
|
|
|
if [ -z "$bootdir" -o -z "$index" ]; then
|
2017-07-17 16:43:14 +00:00
|
|
|
die "Usage: $0 -b /boot -i menu_option "
|
2017-07-04 23:49:14 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -z "$paramsdev" ]; then
|
|
|
|
paramsdev="$bootdir"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -z "$paramsdir" ]; then
|
|
|
|
paramsdir="$bootdir"
|
|
|
|
fi
|
|
|
|
|
2017-07-22 18:25:39 +00:00
|
|
|
bootdir="${bootdir%%/}"
|
|
|
|
paramsdev="${paramsdev%%/}"
|
|
|
|
paramsdir="${paramsdir%%/}"
|
|
|
|
|
2017-07-08 20:59:37 +00:00
|
|
|
TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"
|
2017-07-04 23:49:14 +00:00
|
|
|
ENTRY_FILE="$paramsdir/kexec_default.$index.txt"
|
|
|
|
HASH_FILE="$paramsdir/kexec_default_hashes.txt"
|
2022-08-25 18:43:31 +00:00
|
|
|
PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt"
|
2023-08-22 18:34:29 +00:00
|
|
|
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
|
2023-09-01 19:18:36 +00:00
|
|
|
# $lvm_suggest is a multiline string, we need to convert it to a space separated string
|
2023-09-02 15:49:57 +00:00
|
|
|
lvm_suggest=$(echo $lvm_suggest | tr '\n' ' ')
|
2023-08-22 18:34:29 +00:00
|
|
|
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
|
2023-08-31 16:07:39 +00:00
|
|
|
if cryptsetup isLuks "$device"; then echo "$device"; fi
|
2023-08-22 18:34:29 +00:00
|
|
|
done | sort)
|
|
|
|
num_devices=$(echo "$devices_suggest" | wc -l)
|
|
|
|
|
|
|
|
if [ "$num_devices" -eq 1 ] && [ -s "$devices_suggest" ]; then
|
|
|
|
key_devices=$devices_suggest
|
2023-09-01 19:18:36 +00:00
|
|
|
elif [ -z "$devices_suggest" ]; then
|
|
|
|
num_devices=0
|
2023-08-22 18:34:29 +00:00
|
|
|
fi
|
2023-09-01 19:18:36 +00:00
|
|
|
# $devices_suggest is a multiline string, we need to convert it to a space separated string
|
2023-09-02 15:49:57 +00:00
|
|
|
devices_suggest=$(echo $devices_suggest | tr '\n' ' ')
|
2023-08-22 18:34:29 +00:00
|
|
|
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
|
2017-07-04 23:49:14 +00:00
|
|
|
|
2023-09-01 19:18:36 +00:00
|
|
|
#Reusable function when user wants to define new TPM DUK for lvms/disks
|
|
|
|
prompt_for_existing_encrypted_lvms_or_disks() {
|
2024-02-01 19:30:31 +00:00
|
|
|
TRACE_FUNC
|
2023-09-01 19:18:36 +00:00
|
|
|
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"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-07-08 20:59:37 +00:00
|
|
|
if [ ! -r "$TMP_MENU_FILE" ]; then
|
|
|
|
die "No menu options available, please run kexec-select-boot"
|
|
|
|
fi
|
|
|
|
|
2023-08-22 18:34:29 +00:00
|
|
|
entry=$(head -n $index $TMP_MENU_FILE | tail -1)
|
2017-07-08 20:59:37 +00:00
|
|
|
if [ -z "$entry" ]; then
|
|
|
|
die "Invalid menu index $index"
|
|
|
|
fi
|
|
|
|
|
2017-07-29 17:24:34 +00:00
|
|
|
save_key="n"
|
2023-09-01 19:18:36 +00:00
|
|
|
|
2023-06-30 18:37:38 +00:00
|
|
|
if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ "$CONFIG_BASIC" != y ]; then
|
2023-08-22 18:34:29 +00:00
|
|
|
DEBUG "TPM is enabled and TPM_NO_LUKS_DISK_UNLOCK is not set"
|
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following 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/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
|
|
|
DEBUG "Checking if a a LUKS TPM Disk Unlock Key was previously set up from $KEY_DEVICES"
|
2023-09-01 19:18:36 +00:00
|
|
|
#check if $KEY_DEVICES file exists and is not empty
|
|
|
|
if [ -r "$KEY_DEVICES" ] && [ -s "$KEY_DEVICES" ]; then
|
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following 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/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
|
|
|
DEBUG "LUKS TPM Disk Unlock Key was previously set up from $KEY_DEVICES"
|
2017-12-05 08:29:07 +00:00
|
|
|
read \
|
|
|
|
-n 1 \
|
2024-03-27 14:04:10 +00:00
|
|
|
-p "Do you want to reseal a Disk Unlock Key in the TPM [y/N]: " \
|
2017-12-05 08:29:07 +00:00
|
|
|
change_key_confirm
|
|
|
|
echo
|
|
|
|
|
|
|
|
if [ "$change_key_confirm" = "y" \
|
|
|
|
-o "$change_key_confirm" = "Y" ]; then
|
|
|
|
old_lvm_volume_group=""
|
|
|
|
if [ -r "$KEY_LVM" ]; then
|
2023-08-22 18:34:29 +00:00
|
|
|
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
|
2017-12-05 08:29:07 +00:00
|
|
|
else
|
2023-08-22 18:34:29 +00:00
|
|
|
old_key_devices=$(cat $KEY_DEVICES |
|
|
|
|
cut -d\ -f1 | xargs) || true
|
2017-12-05 08:29:07 +00:00
|
|
|
fi
|
|
|
|
|
2023-08-22 18:34:29 +00:00
|
|
|
lvm_suggest="$old_lvm_volume_group"
|
|
|
|
devices_suggest="$old_key_devices"
|
2017-12-05 08:29:07 +00:00
|
|
|
save_key="y"
|
2017-07-22 20:32:10 +00:00
|
|
|
fi
|
2023-09-01 19:18:36 +00:00
|
|
|
else
|
cryptsetup2 toolstack version bump and script fixes to support multi-LUKS containers (BTRFS QubesOS 4.2)
cryptsetup2 2.6.1 is a new release that supports reencryption of Q4.2 release LUKS2 volumes created at installation.
This is a critical feature for the Qubes OS 4.2 release for added data at rest protection
Cryptsetup 2.6.x internal changes:
- Argon2 used externally and internally: requires a lot of RAM and CPU to derivate passphrase to key validated in key slots.
- This is used to rate limit efficiently bruteforcing of LUKS key slots, requiring each offline brute force attempt to consume ~15-30 seconds per attempt
- OF course, strong passphrases are still recommended, but bruteforcing LUKSv2 containers with Argon2 would require immense time, ram and CPU even to bruteforce low entropy passphrase/PINs.
- passphrase change doesn't permit LUKS key slot specification anymore: key slot rotates (new one consusumed per op: then old one wiped internally. EG: LUKS key slot 1 created, then 0 deleted)
- reencryption doesn't permit old call arguments. No more direct-io; inadmissively slow through AIO (async) calls, need workarounds for good enough perfs (arguments + newer kernel with cloudfare fixes in tree)
cryptsetup 2.6.1 requires:
- lvm2 2.03.23, which is also included in this PR.
- requires libaio, which is also included in this PR (could be hacked out but deep dependency at first sight: left in)
- requires util-linux 2.39
- patches for reproducible builds are included for above 3 packages.
luks-functions was updated to support the new cryptsetup2 version calls/changes
- reencryption happen in direct-io, offline mode and without locking, requiring linux 5.10.9+ to bypass linux queues
- from tests, this is best for performance and reliability in single-user mode
- LUKS container ops now validate Disk Recovery Key (DRK) passphrase prior and DRK key slot prior of going forward if needed, failing early.
- Heads don't expect DRK to be in static key slot anymore, and finds the DRK key slot dynamically.
- If reencrytipn/passphrase change: make sure all LUKS containers on same block device can be unlocked with same DRK
- Reencryption: requires to know which key slot to reencrypt.
- Find LUKS key slot that unlocks with DRK passphrase unlock prior of reencrypt call
- Passphrase change: no slot can be passed, but key slot of DRK rotates.
kexec-seal-key
- TPM LUKS Disk Unlock Key key slots have changed to be set in max slots per LUKS version (LUKSv1:7 /LUKSv2: 31)
- If key slot != default LUKS version's keyslot outside of DRK key slot: prompt the user before wiping that key slot, otherwise wipe automatically
- This takes for granted that the DRK key slot alone is needed on the system and Heads controls the LUKS key slots.
- If user has something else going on, ie: Using USB Security dongle + TPM DUK, then the user will need to say no when wiping keys.
- It was suggested to leave LUKS key slots outside of DRK alone, but then: what to do when all key slots would be used?
- Alternative implementation could be to only prompt users to wipe keyslots other then DRK when key slots are all used (LUKSv1: 0-7, LUKSv2: 0-31)
- But then cleanup would need to happen prior of operations (LUKS passphrase change, TPM DUK setup) and could be problematic.
- LUKS containers now checked to be same LUKS version prior of permitting to set TPM DUK and will refuse to go forward of different versions.
TODO:
- async (AIO) calls are not used. direct-io is used instead. libaio could be hacked out
- this could be subject to future work
Notes:
- time to deprecated legacy boards the do not enough space for the new space requirements
- x230-legacy, x230-legacy-flash, x230-hotp-legacy
- t430-legacy, t430-legacy-flash, t430-hotp-legacy already deprecated
Unrelated:
- typos fixes found along the way
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-08-16 19:20:11 +00:00
|
|
|
DEBUG "No previous LUKS TPM Disk Unlock Key was set up, confirming to add a Disk Unlock Key (DUK) to the TPM"
|
2023-09-01 19:18:36 +00:00
|
|
|
read \
|
|
|
|
-n 1 \
|
cryptsetup2 toolstack version bump and script fixes to support multi-LUKS containers (BTRFS QubesOS 4.2)
cryptsetup2 2.6.1 is a new release that supports reencryption of Q4.2 release LUKS2 volumes created at installation.
This is a critical feature for the Qubes OS 4.2 release for added data at rest protection
Cryptsetup 2.6.x internal changes:
- Argon2 used externally and internally: requires a lot of RAM and CPU to derivate passphrase to key validated in key slots.
- This is used to rate limit efficiently bruteforcing of LUKS key slots, requiring each offline brute force attempt to consume ~15-30 seconds per attempt
- OF course, strong passphrases are still recommended, but bruteforcing LUKSv2 containers with Argon2 would require immense time, ram and CPU even to bruteforce low entropy passphrase/PINs.
- passphrase change doesn't permit LUKS key slot specification anymore: key slot rotates (new one consusumed per op: then old one wiped internally. EG: LUKS key slot 1 created, then 0 deleted)
- reencryption doesn't permit old call arguments. No more direct-io; inadmissively slow through AIO (async) calls, need workarounds for good enough perfs (arguments + newer kernel with cloudfare fixes in tree)
cryptsetup 2.6.1 requires:
- lvm2 2.03.23, which is also included in this PR.
- requires libaio, which is also included in this PR (could be hacked out but deep dependency at first sight: left in)
- requires util-linux 2.39
- patches for reproducible builds are included for above 3 packages.
luks-functions was updated to support the new cryptsetup2 version calls/changes
- reencryption happen in direct-io, offline mode and without locking, requiring linux 5.10.9+ to bypass linux queues
- from tests, this is best for performance and reliability in single-user mode
- LUKS container ops now validate Disk Recovery Key (DRK) passphrase prior and DRK key slot prior of going forward if needed, failing early.
- Heads don't expect DRK to be in static key slot anymore, and finds the DRK key slot dynamically.
- If reencrytipn/passphrase change: make sure all LUKS containers on same block device can be unlocked with same DRK
- Reencryption: requires to know which key slot to reencrypt.
- Find LUKS key slot that unlocks with DRK passphrase unlock prior of reencrypt call
- Passphrase change: no slot can be passed, but key slot of DRK rotates.
kexec-seal-key
- TPM LUKS Disk Unlock Key key slots have changed to be set in max slots per LUKS version (LUKSv1:7 /LUKSv2: 31)
- If key slot != default LUKS version's keyslot outside of DRK key slot: prompt the user before wiping that key slot, otherwise wipe automatically
- This takes for granted that the DRK key slot alone is needed on the system and Heads controls the LUKS key slots.
- If user has something else going on, ie: Using USB Security dongle + TPM DUK, then the user will need to say no when wiping keys.
- It was suggested to leave LUKS key slots outside of DRK alone, but then: what to do when all key slots would be used?
- Alternative implementation could be to only prompt users to wipe keyslots other then DRK when key slots are all used (LUKSv1: 0-7, LUKSv2: 0-31)
- But then cleanup would need to happen prior of operations (LUKS passphrase change, TPM DUK setup) and could be problematic.
- LUKS containers now checked to be same LUKS version prior of permitting to set TPM DUK and will refuse to go forward of different versions.
TODO:
- async (AIO) calls are not used. direct-io is used instead. libaio could be hacked out
- this could be subject to future work
Notes:
- time to deprecated legacy boards the do not enough space for the new space requirements
- x230-legacy, x230-legacy-flash, x230-hotp-legacy
- t430-legacy, t430-legacy-flash, t430-hotp-legacy already deprecated
Unrelated:
- typos fixes found along the way
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-08-16 19:20:11 +00:00
|
|
|
-p "Do you wish to add a disk encryption key to the TPM [y/N]: " \
|
2023-09-01 19:18:36 +00:00
|
|
|
add_key_confirm
|
cryptsetup2 toolstack version bump and script fixes to support multi-LUKS containers (BTRFS QubesOS 4.2)
cryptsetup2 2.6.1 is a new release that supports reencryption of Q4.2 release LUKS2 volumes created at installation.
This is a critical feature for the Qubes OS 4.2 release for added data at rest protection
Cryptsetup 2.6.x internal changes:
- Argon2 used externally and internally: requires a lot of RAM and CPU to derivate passphrase to key validated in key slots.
- This is used to rate limit efficiently bruteforcing of LUKS key slots, requiring each offline brute force attempt to consume ~15-30 seconds per attempt
- OF course, strong passphrases are still recommended, but bruteforcing LUKSv2 containers with Argon2 would require immense time, ram and CPU even to bruteforce low entropy passphrase/PINs.
- passphrase change doesn't permit LUKS key slot specification anymore: key slot rotates (new one consusumed per op: then old one wiped internally. EG: LUKS key slot 1 created, then 0 deleted)
- reencryption doesn't permit old call arguments. No more direct-io; inadmissively slow through AIO (async) calls, need workarounds for good enough perfs (arguments + newer kernel with cloudfare fixes in tree)
cryptsetup 2.6.1 requires:
- lvm2 2.03.23, which is also included in this PR.
- requires libaio, which is also included in this PR (could be hacked out but deep dependency at first sight: left in)
- requires util-linux 2.39
- patches for reproducible builds are included for above 3 packages.
luks-functions was updated to support the new cryptsetup2 version calls/changes
- reencryption happen in direct-io, offline mode and without locking, requiring linux 5.10.9+ to bypass linux queues
- from tests, this is best for performance and reliability in single-user mode
- LUKS container ops now validate Disk Recovery Key (DRK) passphrase prior and DRK key slot prior of going forward if needed, failing early.
- Heads don't expect DRK to be in static key slot anymore, and finds the DRK key slot dynamically.
- If reencrytipn/passphrase change: make sure all LUKS containers on same block device can be unlocked with same DRK
- Reencryption: requires to know which key slot to reencrypt.
- Find LUKS key slot that unlocks with DRK passphrase unlock prior of reencrypt call
- Passphrase change: no slot can be passed, but key slot of DRK rotates.
kexec-seal-key
- TPM LUKS Disk Unlock Key key slots have changed to be set in max slots per LUKS version (LUKSv1:7 /LUKSv2: 31)
- If key slot != default LUKS version's keyslot outside of DRK key slot: prompt the user before wiping that key slot, otherwise wipe automatically
- This takes for granted that the DRK key slot alone is needed on the system and Heads controls the LUKS key slots.
- If user has something else going on, ie: Using USB Security dongle + TPM DUK, then the user will need to say no when wiping keys.
- It was suggested to leave LUKS key slots outside of DRK alone, but then: what to do when all key slots would be used?
- Alternative implementation could be to only prompt users to wipe keyslots other then DRK when key slots are all used (LUKSv1: 0-7, LUKSv2: 0-31)
- But then cleanup would need to happen prior of operations (LUKS passphrase change, TPM DUK setup) and could be problematic.
- LUKS containers now checked to be same LUKS version prior of permitting to set TPM DUK and will refuse to go forward of different versions.
TODO:
- async (AIO) calls are not used. direct-io is used instead. libaio could be hacked out
- this could be subject to future work
Notes:
- time to deprecated legacy boards the do not enough space for the new space requirements
- x230-legacy, x230-legacy-flash, x230-hotp-legacy
- t430-legacy, t430-legacy-flash, t430-hotp-legacy already deprecated
Unrelated:
- typos fixes found along the way
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-08-16 19:20:11 +00:00
|
|
|
#TODO: still not convinced: disk encryption key? decryption key? everywhere TPM Disk Unlock Key. Confusing even more?
|
2023-09-01 19:18:36 +00:00
|
|
|
echo
|
|
|
|
|
|
|
|
if [ "$add_key_confirm" = "y" \
|
|
|
|
-o "$add_key_confirm" = "Y" ]; then
|
cryptsetup2 toolstack version bump and script fixes to support multi-LUKS containers (BTRFS QubesOS 4.2)
cryptsetup2 2.6.1 is a new release that supports reencryption of Q4.2 release LUKS2 volumes created at installation.
This is a critical feature for the Qubes OS 4.2 release for added data at rest protection
Cryptsetup 2.6.x internal changes:
- Argon2 used externally and internally: requires a lot of RAM and CPU to derivate passphrase to key validated in key slots.
- This is used to rate limit efficiently bruteforcing of LUKS key slots, requiring each offline brute force attempt to consume ~15-30 seconds per attempt
- OF course, strong passphrases are still recommended, but bruteforcing LUKSv2 containers with Argon2 would require immense time, ram and CPU even to bruteforce low entropy passphrase/PINs.
- passphrase change doesn't permit LUKS key slot specification anymore: key slot rotates (new one consusumed per op: then old one wiped internally. EG: LUKS key slot 1 created, then 0 deleted)
- reencryption doesn't permit old call arguments. No more direct-io; inadmissively slow through AIO (async) calls, need workarounds for good enough perfs (arguments + newer kernel with cloudfare fixes in tree)
cryptsetup 2.6.1 requires:
- lvm2 2.03.23, which is also included in this PR.
- requires libaio, which is also included in this PR (could be hacked out but deep dependency at first sight: left in)
- requires util-linux 2.39
- patches for reproducible builds are included for above 3 packages.
luks-functions was updated to support the new cryptsetup2 version calls/changes
- reencryption happen in direct-io, offline mode and without locking, requiring linux 5.10.9+ to bypass linux queues
- from tests, this is best for performance and reliability in single-user mode
- LUKS container ops now validate Disk Recovery Key (DRK) passphrase prior and DRK key slot prior of going forward if needed, failing early.
- Heads don't expect DRK to be in static key slot anymore, and finds the DRK key slot dynamically.
- If reencrytipn/passphrase change: make sure all LUKS containers on same block device can be unlocked with same DRK
- Reencryption: requires to know which key slot to reencrypt.
- Find LUKS key slot that unlocks with DRK passphrase unlock prior of reencrypt call
- Passphrase change: no slot can be passed, but key slot of DRK rotates.
kexec-seal-key
- TPM LUKS Disk Unlock Key key slots have changed to be set in max slots per LUKS version (LUKSv1:7 /LUKSv2: 31)
- If key slot != default LUKS version's keyslot outside of DRK key slot: prompt the user before wiping that key slot, otherwise wipe automatically
- This takes for granted that the DRK key slot alone is needed on the system and Heads controls the LUKS key slots.
- If user has something else going on, ie: Using USB Security dongle + TPM DUK, then the user will need to say no when wiping keys.
- It was suggested to leave LUKS key slots outside of DRK alone, but then: what to do when all key slots would be used?
- Alternative implementation could be to only prompt users to wipe keyslots other then DRK when key slots are all used (LUKSv1: 0-7, LUKSv2: 0-31)
- But then cleanup would need to happen prior of operations (LUKS passphrase change, TPM DUK setup) and could be problematic.
- LUKS containers now checked to be same LUKS version prior of permitting to set TPM DUK and will refuse to go forward of different versions.
TODO:
- async (AIO) calls are not used. direct-io is used instead. libaio could be hacked out
- this could be subject to future work
Notes:
- time to deprecated legacy boards the do not enough space for the new space requirements
- x230-legacy, x230-legacy-flash, x230-hotp-legacy
- t430-legacy, t430-legacy-flash, t430-hotp-legacy already deprecated
Unrelated:
- typos fixes found along the way
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-08-16 19:20:11 +00:00
|
|
|
DEBUG "User confirmed desire to add a Disk Unlock Key (DUK) to the TPM"
|
2023-09-01 19:18:36 +00:00
|
|
|
save_key="y"
|
|
|
|
fi
|
2017-07-29 17:24:34 +00:00
|
|
|
fi
|
|
|
|
|
2017-12-05 08:29:07 +00:00
|
|
|
if [ "$save_key" = "y" ]; then
|
2023-08-22 18:34:29 +00:00
|
|
|
if [ -n "$old_key_devices" ] || [ -n "$old_lvm_volume_group" ]; then
|
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following 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/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
|
|
|
DEBUG "Previous LUKS TPM Disk Unlock Key was set up for $old_key_devices $old_lvm_volume_group"
|
2023-08-22 18:34:29 +00:00
|
|
|
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
|
2023-09-01 19:18:36 +00:00
|
|
|
#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
|
2023-08-22 18:34:29 +00:00
|
|
|
fi
|
|
|
|
else
|
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following 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/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
|
|
|
DEBUG "No previous LUKS TPM Disk Unlock Key was set up, setting up"
|
2023-09-01 19:18:36 +00:00
|
|
|
prompt_for_existing_encrypted_lvms_or_disks
|
2023-08-22 18:34:29 +00:00
|
|
|
fi
|
2017-07-29 17:24:34 +00:00
|
|
|
|
2017-12-05 08:29:07 +00:00
|
|
|
save_key_params="-s -p $paramsdev"
|
|
|
|
if [ -n "$lvm_volume_group" ]; then
|
|
|
|
save_key_params="$save_key_params -l $lvm_volume_group $key_devices"
|
|
|
|
else
|
|
|
|
save_key_params="$save_key_params $key_devices"
|
|
|
|
fi
|
2023-08-22 18:34:29 +00:00
|
|
|
kexec-save-key $save_key_params ||
|
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following 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/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
|
|
|
die "Failed to save the LUKS TPM Disk Unlock Key"
|
2017-07-22 20:32:10 +00:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2017-07-04 23:49:14 +00:00
|
|
|
# try to switch to rw mode
|
|
|
|
mount -o rw,remount $paramsdev
|
|
|
|
|
|
|
|
if [ ! -d $paramsdir ]; then
|
2023-08-22 18:34:29 +00:00
|
|
|
mkdir -p $paramsdir ||
|
|
|
|
die "Failed to create params directory"
|
2017-07-04 23:49:14 +00:00
|
|
|
fi
|
2022-08-25 18:43:31 +00:00
|
|
|
|
|
|
|
if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
|
2023-11-02 18:17:38 +00:00
|
|
|
sha256sum /tmp/secret/primary.handle >"$PRIMHASH_FILE" ||
|
2023-08-22 18:34:29 +00:00
|
|
|
die "ERROR: Failed to Hash TPM2 primary key handle!"
|
2023-11-02 18:17:38 +00:00
|
|
|
DEBUG "TPM2 primary key handle hash saved to $PRIMHASH_FILE"
|
2022-08-25 18:43:31 +00:00
|
|
|
fi
|
|
|
|
|
2020-08-26 11:21:57 +00:00
|
|
|
rm $paramsdir/kexec_default.*.txt 2>/dev/null || true
|
2023-08-22 18:34:29 +00:00
|
|
|
echo "$entry" >$ENTRY_FILE
|
|
|
|
(
|
|
|
|
cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f |
|
|
|
|
xargs sha256sum >$HASH_FILE
|
2023-01-13 19:53:11 +00:00
|
|
|
) || die "Failed to create hashes of boot files"
|
2017-07-04 23:49:14 +00:00
|
|
|
if [ ! -r $ENTRY_FILE -o ! -r $HASH_FILE ]; then
|
|
|
|
die "Failed to write default config"
|
|
|
|
fi
|
|
|
|
|
2023-01-16 20:15:21 +00:00
|
|
|
if [ "$save_key" = "y" ]; then
|
|
|
|
# logic to parse OS initrd to extract crypttab, its filepaths and its OS defined options
|
2023-09-02 08:21:08 +00:00
|
|
|
initrd_decompressed="/tmp/initrd_extract"
|
|
|
|
mkdir -p "$initrd_decompressed"
|
2023-01-16 20:15:21 +00:00
|
|
|
# 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')
|
2023-08-22 18:34:29 +00:00
|
|
|
|
2023-09-01 20:28:53 +00:00
|
|
|
echo "+++ Extracting current selected default boot's $current_default_initrd to find crypttab files..."
|
2023-09-02 08:21:08 +00:00
|
|
|
unpack_initramfs.sh "$current_default_initrd" "$initrd_decompressed"
|
2023-09-01 20:28:53 +00:00
|
|
|
crypttab_files=$(find "$initrd_decompressed" | grep crypttab 2>/dev/null) || true
|
2023-08-22 18:34:29 +00:00
|
|
|
|
2023-01-16 20:15:21 +00:00
|
|
|
if [ ! -z "$crypttab_files" ]; then
|
2023-09-01 20:28:53 +00:00
|
|
|
DEBUG "Found crypttab files in $current_default_initrd"
|
2023-01-16 20:15:21 +00:00
|
|
|
rm -f $bootdir/kexec_initrd_crypttab_overrides.txt || true
|
2023-08-22 18:34:29 +00:00
|
|
|
|
2023-01-16 20:15:21 +00:00
|
|
|
#Parsing each crypttab file found
|
2023-09-02 08:21:08 +00:00
|
|
|
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
|
2023-01-16 20:15:21 +00:00
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
#insert current default boot's initrd crypttab locations into tracking file to be overwritten into initramfs at kexec-inject-key
|
2023-03-09 18:28:04 +00:00
|
|
|
echo "+++ The following OS crypttab file:entry were modified from default boot's initrd:"
|
2023-01-16 20:15:21 +00:00
|
|
|
cat $bootdir/kexec_initrd_crypttab_overrides.txt
|
2023-03-09 18:28:04 +00:00
|
|
|
echo "+++ Heads added /secret.key in those entries and saved them under $bootdir/kexec_initrd_crypttab_overrides.txt"
|
|
|
|
echo "+++ Those overrides will be part of detached signed digests and used to prepare cpio injected at kexec of selected default boot entry."
|
2023-01-16 20:15:21 +00:00
|
|
|
else
|
2023-03-14 14:42:21 +00:00
|
|
|
echo "+++ No crypttab file found in extracted initrd. A generic crypttab will be generated"
|
|
|
|
if [ -e "$bootdir/kexec_initrd_crypttab_overrides.txt" ]; then
|
|
|
|
echo "+++ Removing $bootdir/kexec_initrd_crypttab_overrides.txt"
|
|
|
|
rm -f "$bootdir/kexec_initrd_crypttab_overrides.txt"
|
|
|
|
fi
|
2023-01-16 20:15:21 +00:00
|
|
|
fi
|
2023-03-14 14:42:21 +00:00
|
|
|
|
2023-01-16 20:15:21 +00:00
|
|
|
# Cleanup
|
2023-03-14 14:42:21 +00:00
|
|
|
cd /
|
2023-01-16 20:15:21 +00:00
|
|
|
rm -rf /tmp/initrd_extract || true
|
|
|
|
fi
|
|
|
|
|
2017-07-08 20:59:37 +00:00
|
|
|
# sign and auto-roll config counter
|
2017-12-05 08:29:07 +00:00
|
|
|
extparam=
|
2023-08-22 18:34:29 +00:00
|
|
|
if [ "$CONFIG_TPM" = "y" ]; then
|
2022-08-25 18:43:31 +00:00
|
|
|
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
|
|
|
|
extparam=-r
|
|
|
|
fi
|
2017-12-05 08:29:07 +00:00
|
|
|
fi
|
2023-06-21 18:36:28 +00:00
|
|
|
if [ "$CONFIG_BASIC" != "y" ]; then
|
2023-08-22 18:34:29 +00:00
|
|
|
kexec-sign-config -p $paramsdir $extparam ||
|
|
|
|
die "Failed to sign default config"
|
2022-03-15 17:05:04 +00:00
|
|
|
fi
|
2017-07-04 23:49:14 +00:00
|
|
|
# switch back to ro mode
|
|
|
|
mount -o ro,remount $paramsdev
|