mirror of
https://github.com/linuxboot/heads.git
synced 2025-01-18 18:57:04 +00:00
0cef8e1edc
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>
209 lines
5.8 KiB
Bash
Executable File
209 lines
5.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# Shell functions for common operations using fbwhiptail
|
|
. /etc/functions
|
|
|
|
# Pause for the configured timeout before booting automatically. Returns 0 to
|
|
# continue with automatic boot, nonzero if user interrupted.
|
|
pause_automatic_boot()
|
|
{
|
|
if IFS= read -t "$CONFIG_AUTO_BOOT_TIMEOUT" -s -n 1 -r -p \
|
|
$'Automatic boot in '"$CONFIG_AUTO_BOOT_TIMEOUT"$' seconds unless interrupted by keypress...\n'; then
|
|
return 1 # Interrupt automatic boot
|
|
fi
|
|
return 0 # Continue with automatic boot
|
|
}
|
|
|
|
mount_usb()
|
|
{
|
|
TRACE_FUNC
|
|
# Unmount any previous USB device
|
|
if grep -q /media /proc/mounts ; then
|
|
umount /media || die "Unable to unmount /media"
|
|
fi
|
|
# Mount the USB boot device
|
|
mount-usb && USB_FAILED=0 || ( [ $? -eq 5 ] && exit 1 || USB_FAILED=1 )
|
|
if [ $USB_FAILED -ne 0 ]; then
|
|
whiptail_error --title 'USB Drive Missing' \
|
|
--msgbox "Insert your USB drive and press Enter to continue." 0 80
|
|
mount-usb && USB_FAILED=0 || ( [ $? -eq 5 ] && exit 1 || USB_FAILED=1 )
|
|
if [ $USB_FAILED -ne 0 ]; then
|
|
whiptail_error --title 'ERROR: Mounting /media Failed' \
|
|
--msgbox "Unable to mount USB device" 0 80
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# -- Display related functions --
|
|
# Produce a whiptail prompt with 'warning' background, works for fbwhiptail and newt
|
|
whiptail_warning() {
|
|
#TODO: Cannot be called as is under luks_functions with string expension in title: why?
|
|
if [ -x /bin/fbwhiptail ]; then
|
|
whiptail $BG_COLOR_WARNING "$@"
|
|
else
|
|
env NEWT_COLORS="root=,$TEXT_BG_COLOR_WARNING" whiptail "$@"
|
|
fi
|
|
}
|
|
|
|
# Produce a whiptail prompt with 'error' background, works for fbwhiptail and newt
|
|
whiptail_error() {
|
|
#TODO: Cannot be called as is under luks_functions with string expension in title: why?
|
|
if [ -x /bin/fbwhiptail ]; then
|
|
whiptail $BG_COLOR_ERROR "$@"
|
|
else
|
|
env NEWT_COLORS="root=,$TEXT_BG_COLOR_ERROR" whiptail "$@"
|
|
fi
|
|
}
|
|
|
|
# Produce a whiptail prompt of the given type - 'error', 'warning', or 'normal'
|
|
whiptail_type() {
|
|
TRACE_FUNC
|
|
local TYPE="$1"
|
|
shift
|
|
case "$TYPE" in
|
|
error)
|
|
whiptail_error "$@"
|
|
;;
|
|
warning)
|
|
whiptail_warning "$@"
|
|
;;
|
|
normal)
|
|
whiptail "$@"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Create display text for a size in bytes in either MB or GB, unit selected
|
|
# automatically, rounded to nearest
|
|
display_size() {
|
|
local size_bytes unit_divisor unit_symbol
|
|
size_bytes="$1"
|
|
|
|
# If it's less than 1 GB, display MB
|
|
if [ "$((size_bytes))" -lt "$((1024*1024*1024))" ]; then
|
|
unit_divisor=$((1024*1024))
|
|
unit_symbol="MB"
|
|
else
|
|
unit_divisor=$((1024*1024*1024))
|
|
unit_symbol="GB"
|
|
fi
|
|
|
|
# Divide by the unit divisor and round to nearest
|
|
echo "$(( (size_bytes + unit_divisor/2) / unit_divisor )) $unit_symbol"
|
|
}
|
|
|
|
# Create display text for the size of a block device using MB or GB, rounded to
|
|
# nearest
|
|
display_block_device_size() {
|
|
local block_dev disk_size_bytes
|
|
block_dev="$1"
|
|
|
|
# Obtain size of thumb drive to be wiped with fdisk
|
|
if ! disk_size_bytes="$(blockdev --getsize64 "$block_dev")"; then
|
|
exit 1
|
|
fi
|
|
|
|
display_size "$disk_size_bytes"
|
|
}
|
|
|
|
# Display a menu to select a file from a list. Pass the name of a file
|
|
# containing the list.
|
|
# --show-size: Append sizes of files listed. Currently only supports block
|
|
# devices.
|
|
# $1: Name of file listing files that can be chosen (one per line)
|
|
# $2: Optional prompt message
|
|
# $3: Optional prompt title
|
|
#
|
|
# Success: Sets FILE with the selected file
|
|
# User aborted: Exits successfully with FILE empty
|
|
# No entries in list: Displays error and exits unsuccessfully
|
|
file_selector()
|
|
{
|
|
TRACE_FUNC
|
|
|
|
local FILE_LIST MENU_MSG MENU_TITLE CHOICE_ARGS SHOW_SIZE OPTION_SIZE option_index
|
|
|
|
FILE=""
|
|
|
|
if [ "$1" = "--show-size" ]; then
|
|
SHOW_SIZE=y
|
|
shift
|
|
fi
|
|
|
|
FILE_LIST=$1
|
|
MENU_MSG=${2:-"Choose the file"}
|
|
MENU_TITLE=${3:-"Select your File"}
|
|
|
|
CHOICE_ARGS=()
|
|
n=0
|
|
while read option; do
|
|
n="$((++n))"
|
|
|
|
if [ "$SHOW_SIZE" = "y" ] && OPTION_SIZE="$(display_block_device_size "$option")"; then
|
|
option="$option - $OPTION_SIZE"
|
|
fi
|
|
CHOICE_ARGS+=("$n" "$option")
|
|
done < "$FILE_LIST"
|
|
|
|
if [ "${#CHOICE_ARGS[@]}" -eq 0 ]; then
|
|
whiptail_error --title 'ERROR: No Files Found' \
|
|
--msgbox "No Files found matching the pattern. Aborting." 0 80
|
|
exit 1
|
|
fi
|
|
|
|
CHOICE_ARGS+=(a Abort)
|
|
|
|
# create file menu options
|
|
option_index=""
|
|
while [ -z "$option_index" ]; do
|
|
whiptail --title "${MENU_TITLE}" \
|
|
--menu "${MENU_MSG} [1-$n, a to abort]:" 20 120 8 \
|
|
-- "${CHOICE_ARGS[@]}" \
|
|
2>/tmp/whiptail || die "Aborting"
|
|
|
|
option_index=$(cat /tmp/whiptail)
|
|
|
|
if [ "$option_index" != "a" ]; then
|
|
FILE="$(head -n "$option_index" "$FILE_LIST" | tail -1)"
|
|
fi
|
|
done
|
|
}
|
|
|
|
show_system_info()
|
|
{
|
|
TRACE_FUNC
|
|
battery_charge="$(print_battery_charge)"
|
|
battery_health="$(print_battery_health)"
|
|
if [ -n $battery_charge -a -n $battery_health ];then
|
|
battery_status="\nBattery charge: $battery_charge%\nBattery health: $battery_health%\n"
|
|
fi
|
|
|
|
memtotal=$(cat /proc/meminfo | grep 'MemTotal' | tr -s ' ' | cut -f2 -d ' ')
|
|
memtotal=$((${memtotal} / 1024 / 1024 + 1))
|
|
cpustr=$(cat /proc/cpuinfo | grep 'model name' | uniq | sed -r 's/\(R\)//;s/\(TM\)//;s/CPU //;s/model name.*: //')
|
|
kernel=$(uname -s -r)
|
|
|
|
whiptail_type $BG_COLOR_MAIN_MENU --title 'System Info' \
|
|
--msgbox "${BOARD_NAME}\n\nFW_VER: ${FW_VER}\nKernel: ${kernel}\n\nCPU: ${cpustr}\nRAM: ${memtotal} GB\n$battery_status\n$(fdisk -l | grep -e '/dev/sd.:' -e '/dev/nvme.*:' | sed 's/B,.*/B/')" 0 80
|
|
}
|
|
|
|
# Get "Enable" or "Disable" to display in the configuration menu, based on a
|
|
# setting value
|
|
get_config_display_action()
|
|
{
|
|
[ "$1" = "y" ] && echo "Disable" || echo "Enable"
|
|
}
|
|
|
|
# Invert a config value
|
|
invert_config()
|
|
{
|
|
[ "$1" = "y" ] && echo "n" || echo "y"
|
|
}
|
|
|
|
# Get "Enable" or "Disable" for a config that internally is inverted (because it
|
|
# disables a behavior that is on by default).
|
|
get_inverted_config_display_action()
|
|
{
|
|
get_config_display_action "$(invert_config "$1")"
|
|
}
|