Codebase up to TPM DUK: ident, add DEBUG+TRACE_FUNC, TRACE_FUNC now gives call hierarchy, fix HOTP resealing only on OS reinstall, clarify TPM increment workflow

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
This commit is contained in:
Thierry Laurion 2025-02-07 13:18:17 -05:00
parent 2ab7d5884b
commit 1f6a975940
No known key found for this signature in database
GPG Key ID: 9A53E1BB3FF00461
16 changed files with 212 additions and 123 deletions

View File

@ -5,9 +5,9 @@ find /boot/kexec*.txt | gpg --verify /boot/kexec.sig -
#remove invalid kexec_* signed files
mount /dev/sda1 /boot && mount -o remount,rw /boot && rm /boot/kexec* && mount -o remount,ro /boot
#Generate keys on OpenPGP smartcard:
mount-usb && gpg --home=/.gnupg/ --card-edit
mount-usb --mode rw && gpg --home=/.gnupg/ --card-edit
#Copy generated public key, private_subkey, trustdb and artifacts to external media for backup:
mount -o remount,rw /media && mkdir -p /media/gpg_keys; gpg --export-secret-keys --armor email@address.com > /media/gpg_keys/private.key && gpg --export --armor email@address.com > /media/gpg_keys/public.key && gpg --export-ownertrust > /media/gpg_keys/otrust.txt && cp -r ./.gnupg/* /media/gpg_keys/ 2> /dev/null
mkdir -p /media/gpg_keys; gpg --export-secret-keys --armor email@address.com > /media/gpg_keys/private.key && gpg --export --armor email@address.com > /media/gpg_keys/public.key && gpg --export-ownertrust > /media/gpg_keys/otrust.txt && cp -r ./.gnupg/* /media/gpg_keys/ 2> /dev/null
#Insert public key and trustdb export into reproducible rom:
cbfs -o /media/coreboot.rom -a "heads/initrd/.gnupg/keys/public.key" -f /media/gpg_keys/public.key && cbfs -o /media/coreboot.rom -a "heads/initrd/.gnupg/keys/otrust.txt" -f /media/gpg_keys/otrust.txt
#Flush changes to external media:

View File

@ -48,14 +48,14 @@ while true; do
if [ "$totp_confirm" = "m" ]; then
# Try to select a kernel from the menu
mount_boot
kexec-select-boot -m -b /boot -c "grub.cfg"
DO_WITH_DEBUG kexec-select-boot -m -b /boot -c "grub.cfg"
continue
fi
if [ "$totp_confirm" = "y" -o -n "$totp_confirm" ]; then
# Try to boot the default
mount_boot
kexec-select-boot -b /boot -c "grub.cfg" \
DO_WITH_DEBUG kexec-select-boot -b /boot -c "grub.cfg" \
|| recovery "Failed default boot"
fi

View File

@ -183,17 +183,6 @@ update_totp() {
TOTP="NO TPM"
else
TOTP=$(unseal-totp)
# On platforms using CONFIG_BOOT_EXTRA_TTYS multiple processes may try to
# access TPM at the same time, failing with EBUSY. The order of execution
# is unpredictable, so the error may appear on main console, secondary one,
# or neither of them if the calls are sufficiently staggered. Try up to
# three times (including previous one) with small delays in case of error,
# instead of immediately scaring users with "you've been pwned" message.
while [ $? -ne 0 ] && [ $tries -lt 2 ]; do
sleep 0.5
((tries++))
TOTP=$(unseal-totp)
done
if [ $? -ne 0 ]; then
BG_COLOR_MAIN_MENU="error"
if [ "$skip_to_menu" = "true" ]; then
@ -280,7 +269,10 @@ update_hotp() {
HOTP='N/A'
fi
if [[ "$CONFIG_TPM" = n && "$HOTP" = "Invalid code" ]]; then
if [[ "$HOTP" = "Invalid code" ]]; then
#Do not propose to generate a new secret if there is no /boot/kexec_hotp_counter
# tpm unseal succeeded: so the sealed secret is correct: we should propose to reset TPM if not already
# Here: the OS was most probably reinstalled since TPM can still unseal the secret
whiptail_error --title "ERROR: HOTP Validation Failed!" \
--menu "ERROR: $CONFIG_BRAND_NAME couldn't validate the HOTP code.\n\nIf you just reflashed your BIOS, you should generate a new TOTP/HOTP secret.\n\nIf you have not just reflashed your BIOS, THIS COULD INDICATE TAMPERING!\n\nHow would you like to proceed?" 0 80 4 \
'g' ' Generate new TOTP/HOTP secret' \
@ -553,21 +545,30 @@ reset_tpm() {
mount -o rw,remount /boot
#TODO: this is really problematic, we should really remove the primary handle hash
INFO "Removing rollback and primary handle hash under /boot"
INFO "Removing rollback and primary handle hashes under /boot"
DEBUG "Removing /boot/kexec_rollback.txt and /boot/kexec_primhdl_hash.txt"
rm -f /boot/kexec_rollback.txt
rm -f /boot/kexec_primhdl_hash.txt
# create Heads TPM counter before any others
check_tpm_counter /boot/kexec_rollback.txt "" "$tpm_owner_password" ||
die "Unable to find/create tpm counter"
counter="$TPM_COUNTER"
increment_tpm_counter $counter >/dev/null 2>&1 ||
TRACE_FUNC
TPM_COUNTER=$(cut -d: -f1 </tmp/counter)
DEBUG "TPM_COUNTER: $TPM_COUNTER"
#TODO was counter supposed to be empty and that was ok?!?!?!
DO_WITH_DEBUG increment_tpm_counter $TPM_COUNTER>/dev/null 2>&1 ||
die "Unable to increment tpm counter"
sha256sum /tmp/counter-$counter >/boot/kexec_rollback.txt ||
#TODO: should this be here?
DO_WITH_DEBUG sha256sum /tmp/counter-$TPM_COUNTER >/boot/kexec_rollback.txt ||
die "Unable to create rollback file"
TRACE_FUNC
# As a countermeasure for existing primary handle hash, we will now force sign /boot without it
if (whiptail --title 'TPM Reset Successfully' \
--yesno "Would you like to update the checksums and sign all of the files in /boot?\n\nYou will need your GPG key to continue and this will modify your disk.\n\nOtherwise the system will reboot immediately." 0 80); then
@ -593,7 +594,7 @@ select_os_boot_option() {
TRACE_FUNC
mount_boot
if verify_global_hashes; then
kexec-select-boot -m -b /boot -c "grub.cfg" -g
DO_WITH_DEBUG kexec-select-boot -m -b /boot -c "grub.cfg" -g
fi
}
@ -606,11 +607,13 @@ attempt_default_boot() {
fi
DEFAULT_FILE=$(find /boot/kexec_default.*.txt 2>/dev/null | head -1)
if [ -r "$DEFAULT_FILE" ]; then
kexec-select-boot -b /boot -c "grub.cfg" -g ||
TRACE_FUNC
DO_WITH_DEBUG kexec-select-boot -b /boot -c "grub.cfg" -g ||
recovery "Failed default boot"
elif (whiptail_warning --title 'No Default Boot Option Configured' \
--yesno "There is no default boot option configured yet.\nWould you like to load a menu of boot options?\nOtherwise you will return to the main menu." 0 80); then
kexec-select-boot -m -b /boot -c "grub.cfg" -g
TRACE_FUNC
DO_WITH_DEBUG kexec-select-boot -m -b /boot -c "grub.cfg" -g
fi
}

View File

@ -159,7 +159,7 @@ select_os_boot_option()
{
TRACE_FUNC
mount_boot
kexec-select-boot -m -b /boot -c "grub.cfg" -g -i
DO_WITH_DEBUG kexec-select-boot -m -b /boot -c "grub.cfg" -g -i
}
attempt_default_boot()
@ -174,11 +174,11 @@ attempt_default_boot()
if [ "$CONFIG_BASIC_NO_AUTOMATIC_DEFAULT" != "y" ]; then
basic-autoboot.sh
elif [ -r "$DEFAULT_FILE" ]; then
kexec-select-boot -b /boot -c "grub.cfg" -g -i -s \
DO_WITH_DEBUG kexec-select-boot -b /boot -c "grub.cfg" -g -i -s \
|| recovery "Failed default boot"
elif (whiptail_warning --title 'No Default Boot Option Configured' \
--yesno "There is no default boot option configured yet.\nWould you like to load a menu of boot options?\nOtherwise you will return to the main menu." 0 80) then
kexec-select-boot -m -b /boot -c "grub.cfg" -g -i
DO_WITH_DEBUG kexec-select-boot -m -b /boot -c "grub.cfg" -g -i
fi
}

View File

@ -8,10 +8,10 @@ TRACE_FUNC
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
@ -354,7 +354,7 @@ if [ "$CONFIG_TPM" = "y" ]; then
fi
fi
if [ "$CONFIG_BASIC" != "y" ]; then
kexec-sign-config -p $paramsdir $extparam ||
DO_WITH_DEBUG kexec-sign-config -p $paramsdir $extparam ||
die "Failed to sign default config"
fi
# switch back to ro mode

View File

@ -77,10 +77,11 @@ kexec-seal-key $paramsdir ||
if [ "$skip_sign" != "y" ]; then
extparam=
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
DEBUG "kexec-save-key: CONFIG_IGNORE_ROLLBACK is not set, will sign with -r"
extparam=-r
fi
# sign and auto-roll config counter
kexec-sign-config -p $paramsdir $extparam ||
DO_WITH_DEBUG kexec-sign-config -p $paramsdir $extparam ||
die "Failed to sign updated config"
fi

View File

@ -20,25 +20,25 @@ force_boot="n"
skip_confirm="n"
while getopts "b:d:p:a:r:c:uimgfs" arg; do
case $arg in
b) bootdir="$OPTARG" ;;
d) paramsdev="$OPTARG" ;;
p) paramsdir="$OPTARG" ;;
a) add="$OPTARG" ;;
r) remove="$OPTARG" ;;
c) config="$OPTARG" ;;
u) unique="y" ;;
m) force_menu="y" ;;
i)
valid_hash="y"
valid_rollback="y"
;;
g) gui_menu="y" ;;
f)
force_boot="y"
valid_hash="y"
valid_rollback="y"
;;
s) skip_confirm="y" ;;
b) bootdir="$OPTARG" ;;
d) paramsdev="$OPTARG" ;;
p) paramsdir="$OPTARG" ;;
a) add="$OPTARG" ;;
r) remove="$OPTARG" ;;
c) config="$OPTARG" ;;
u) unique="y" ;;
m) force_menu="y" ;;
i)
valid_hash="y"
valid_rollback="y"
;;
g) gui_menu="y" ;;
f)
force_boot="y"
valid_hash="y"
valid_rollback="y"
;;
s) skip_confirm="y" ;;
esac
done
@ -120,14 +120,14 @@ verify_rollback_counter() {
TPM_COUNTER=$(grep counter $TMP_ROLLBACK_FILE | cut -d- -f2)
if [ -z "$TPM_COUNTER" ]; then
die "$TMP_ROLLBACK_FILE: TPM counter not found?"
die "$TMP_ROLLBACK_FILE: TPM counter not found. Please reset TPM through the Heads menu: Options -> TPM/TOTP/HOTP Options -> Reset the TPM"
fi
read_tpm_counter $TPM_COUNTER >/dev/null 2>&1 ||
die "Failed to read TPM counter"
die "Failed to read TPM counter. Please reset TPM through the Heads menu: Options -> TPM/TOTP/HOTP Options -> Reset the TPM"
sha256sum -c $TMP_ROLLBACK_FILE >/dev/null 2>&1 ||
die "Invalid TPM counter state. TPM Reset required"
die "Invalid TPM counter state. Please reset TPM through the Heads menu: Options -> TPM/TOTP/HOTP Options -> Reset the TPM"
valid_rollback="y"
}
@ -361,9 +361,9 @@ do_boot() {
while true; do
if [ "$force_boot" = "y" -o "$CONFIG_BASIC" = "y" ]; then
check_config $paramsdir force
DO_WITH_DEBUG check_config $paramsdir force
else
check_config $paramsdir
DO_WITH_DEBUG check_config $paramsdir
fi
TMP_DEFAULT_FILE=$(find /tmp/kexec/kexec_default.*.txt 2>/dev/null | head -1) || true
TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"

View File

@ -27,24 +27,32 @@ fi
paramsdir="${paramsdir%%/}"
assert_signable
TRACE_FUNC
confirm_gpg_card
TRACE_FUNC
# remount /boot as rw
mount -o remount,rw /boot
DEBUG "Signing kexec parameters in $paramsdir, rollback=$rollback, update=$update, counter=$counter"
# update hashes in /boot before signing
if [ "$update" = "y" ]; then
(
TRACE_FUNC
DEBUG "update=y: Updating kexec hashes in /boot"
cd /boot
find ./ -type f ! -path './kexec*' -print0 | xargs -0 sha256sum >/boot/kexec_hashes.txt
if [ -e /boot/kexec_default_hashes.txt ]; then
DEBUG "/boot/kexec_default_hashes.txt exists, updating /boot/kexec_default_hashes.txt"
DEFAULT_FILES=$(cat /boot/kexec_default_hashes.txt | cut -f3 -d ' ')
echo $DEFAULT_FILES | xargs sha256sum >/boot/kexec_default_hashes.txt
fi
#also save the file & directory structure to detect added files
print_tree >/boot/kexec_tree.txt
TRACE_FUNC
)
[ $? -eq 0 ] || die "$paramsdir: Failed to update hashes."
@ -56,31 +64,65 @@ fi
if [ "$rollback" = "y" ]; then
rollback_file="$paramsdir/kexec_rollback.txt"
DEBUG "rollback=y, counter=$counter, paramsdir=$paramsdir, rollback_file=$rollback_file"
TRACE_FUNC
if [ -n "$counter" ]; then
# use existing counter
read_tpm_counter $counter >/dev/null 2>&1 ||
DEBUG "rollback=y: provided counter=$counter, will read tpm counter next"
TRACE_FUNC
# use existing tpm counter
DO_WITH_DEBUG read_tpm_counter "$counter" >/dev/null 2>&1 ||
die "$paramsdir: Unable to read tpm counter '$counter'"
else
# increment counter
check_tpm_counter $rollback_file >/dev/null 2>&1 ||
die "$paramsdir: Unable to find/create tpm counter"
counter="$TPM_COUNTER"
DEBUG "rollback=y: counter was not provided: checking for existing TPM counter from TPM rollback_file=$rollback_file"
TRACE_FUNC
increment_tpm_counter $counter >/dev/null 2>&1 ||
die "$paramsdir: Unable to increment tpm counter"
if [ -e "$rollback_file" ]; then
# Extract TPM_COUNTER from rollback file
TPM_COUNTER=$(grep -o 'counter-[0-9a-f]*' "$rollback_file" | cut -d- -f2)
DEBUG "rollback=y: Found TPM counter $TPM_COUNTER in rollback file $rollback_file"
else
DEBUG "Rollback file $rollback_file does not exist. Creating new TPM counter."
DO_WITH_DEBUG check_tpm_counter $rollback_file ||
die "$paramsdir: Unable to find/create tpm counter"
TRACE_FUNC
TPM_COUNTER=$(cut -d: -f1 </tmp/counter)
DEBUG "rollback=y: Created new TPM counter $TPM_COUNTER"
fi
fi
sha256sum /tmp/counter-$counter >$rollback_file ||
TRACE_FUNC
# Increment the TPM counter
DEBUG "rollback=y: Incrementing counter $TPM_COUNTER."
DO_WITH_DEBUG increment_tpm_counter $TPM_COUNTER >/dev/null 2>&1 ||
die "$paramsdir: Unable to increment tpm counter"
# Ensure the incremented counter file exists
incremented_counter_file="/tmp/counter-$TPM_COUNTER"
if [ ! -e "$incremented_counter_file" ]; then
DEBUG "TPM counter file '$incremented_counter_file' not found. Attempting to read it again."
DO_WITH_DEBUG read_tpm_counter "$TPM_COUNTER" >/dev/null 2>&1 ||
die "$paramsdir: TPM counter file '$incremented_counter_file' not found after incrementing."
fi
DEBUG "TPM counter file '$incremented_counter_file' found."
# Create the rollback file
sha256sum "$incremented_counter_file" >$rollback_file ||
die "$paramsdir: Unable to create rollback file"
fi
TRACE_FUNC
param_files=$(find $paramsdir/kexec*.txt)
if [ -z "$param_files" ]; then
die "$paramsdir: No kexec parameter files to sign"
fi
for tries in 1 2 3; do
if sha256sum $param_files | gpg \
if DO_WITH_DEBUG sha256sum $param_files | gpg \
--detach-sign \
-a \
>$paramsdir/kexec.sig \

View File

@ -10,19 +10,19 @@ TRACE_FUNC
# Good system clock is required for GPG to work properly.
# if system year is less then 2024, prompt user to set correct time
if [ "$(date +%Y)" -lt 2024 ]; then
if whiptail_warning --title "System Time Incorrect" \
--yesno "The system time is incorrect. Please set the correct time." \
0 80 --yes-button Continue --no-button Skip --clear; then
change-time.sh
fi
if whiptail_warning --title "System Time Incorrect" \
--yesno "The system time is incorrect. Please set the correct time." \
0 80 --yes-button Continue --no-button Skip --clear; then
change-time.sh
fi
fi
# Import user's keys if they exist
if [ -d /.gnupg/keys ]; then
# This is legacy location for user's keys. cbfs-init takes for granted that keyring and trustdb are in /.gnupg
# oem-factory-reset generates keyring and trustdb which cbfs-init dumps to /.gnupg
# TODO: Remove individual key imports. This is still valid for distro keys only below.
gpg --import /.gnupg/keys/*.key /.gnupg/keys/*.asc 2>/dev/null || warn "Importing user's keys failed"
# This is legacy location for user's keys. cbfs-init takes for granted that keyring and trustdb are in /.gnupg
# oem-factory-reset generates keyring and trustdb which cbfs-init dumps to /.gnupg
# TODO: Remove individual key imports. This is still valid for distro keys only below.
gpg --import /.gnupg/keys/*.key /.gnupg/keys/*.asc 2>/dev/null || warn "Importing user's keys failed"
fi
# Import trusted distro keys allowed for ISO signing

View File

@ -731,14 +731,20 @@ generate_checksums() {
whiptail_error_die "Unable to create TPM counter"
TPM_COUNTER=$(cut -d: -f1 </tmp/counter)
# increment TPM counter
increment_tpm_counter $TPM_COUNTER >/dev/null 2>&1 ||
whiptail_error_die "Unable to increment tpm counter"
if [ -s /tmp/counter-$TPM_COUNTER ]; then
# create rollback file
sha256sum /tmp/counter-$TPM_COUNTER >/boot/kexec_rollback.txt 2>/dev/null ||
whiptail_error_die "Unable to create rollback file"
else
# increment TPM counter
increment_tpm_counter $TPM_COUNTER >/dev/null 2>&1 ||
whiptail_error_die "Unable to increment tpm counter"
# create rollback file
sha256sum /tmp/counter-$TPM_COUNTER >/boot/kexec_rollback.txt 2>/dev/null ||
whiptail_error_die "Unable to create rollback file"
fi
fi
# If HOTP is enabled from board config, create HOTP counter
if [ -x /bin/hotp_verification]; then
## needs to exist for initial call to unseal-hotp
echo "0" >/boot/kexec_hotp_counter
fi

View File

@ -5,7 +5,7 @@ TRACE_FUNC
if [ "$CONFIG_DEBUG_OUTPUT" = "y" ]; then
#Generalize user prompt to continue reboot or go to recovery shell
read -r -n 1 -s -p "Press any key to continue reboot or 'r' to go to recovery shell: " REPLY
read -r -n 1 -s -p "Press Enter to continue reboot or 'r' to go to recovery shell: " REPLY
echo
if [ "$REPLY" = "r" ] || [ "$REPLY" = "R" ]; then
recovery "Reboot call bypassed to go into recovery shell to debug"

View File

@ -589,7 +589,7 @@ tpm2_unseal() {
# can't do anything without a primary handle.
if [ ! -f "$PRIMARY_HANDLE_FILE" ]; then
DEBUG "tpm2_unseal: No primary handle, cannot attempt to unseal"
warn "No TPM primary handle. You must reset TPM to seal secret to TPM NVRAM"
warn "No TPM primary handle. You must reset the TPM to seal secret to TPM NVRAM"
exit 1
fi
@ -639,7 +639,7 @@ tpm1_unseal() {
rm -f "$sealed_file"
tpm nv_readvalue \
DO_WITH_DEBUG tpm nv_readvalue \
-in "$index" \
-sz "$sealed_size" \
-of "$sealed_file" ||
@ -719,7 +719,7 @@ tpm1_reset() {
DO_WITH_DEBUG tpm physicalsetdeactivated -c &>/dev/null
DO_WITH_DEBUG tpm forceclear &>/dev/null
DO_WITH_DEBUG tpm physicalenable &>/dev/null
DO_WITH_DEBUG tpm takeown -pwdo "$tpm_owner_password" &>/dev/null
DO_WITH_DEBUG --mask-position 3 tpm takeown -pwdo "$tpm_owner_password" &>/dev/null
# And now turn it all back on
DO_WITH_DEBUG tpm physicalpresence -s &>/dev/null

View File

@ -7,12 +7,12 @@ HOTP_SECRET="/tmp/secret/hotp.key"
HOTP_COUNTER="/boot/kexec_hotp_counter"
mount_boot_or_die() {
TRACE_FUNC
# Mount local disk if it is not already mounted
if ! grep -q /boot /proc/mounts; then
mount -o ro /boot ||
die "Unable to mount /boot"
fi
TRACE_FUNC
# Mount local disk if it is not already mounted
if ! grep -q /boot /proc/mounts; then
mount -o ro /boot ||
die "Unable to mount /boot"
fi
}
TRACE_FUNC
@ -29,27 +29,33 @@ mount_boot_or_die
#counter_value=$(read_tpm_counter $counter | cut -f2 -d ' ' | awk 'gsub("^000e","")')
#
counter_value=$(cat $HOTP_COUNTER)
#if HOTP_COUNTER is not present, bail out
if [ ! -f $HOTP_COUNTER ]; then
die "HOTP counter file not found. If you just reinstalled an OS, you need to reseal the HOTP secret"
fi
# Read the counter from the file
counter_value=$(cat $HOTP_COUNTER 2>/dev/null)
if [ "$counter_value" == "" ]; then
die "Unable to read HOTP counter"
die "Unable to read HOTP counter"
fi
#counter_value=$(printf "%d" 0x${counter_value})
if [ "$CONFIG_TPM" = "y" ]; then
DEBUG "Unsealing HOTP secret reuses TOTP sealed secret..."
tpmr unseal 4d47 0,1,2,3,4,7 312 "$HOTP_SECRET" || die "Unable to unseal HOTP secret"
DEBUG "Unsealing HOTP secret reuses TOTP sealed secret..."
tpmr unseal 4d47 0,1,2,3,4,7 312 "$HOTP_SECRET" || die "Unable to unseal HOTP secret"
else
# without a TPM, generate a secret based on the SHA-256 of the ROM
secret_from_rom_hash >"$HOTP_SECRET" || die "Reading ROM failed"
# without a TPM, generate a secret based on the SHA-256 of the ROM
secret_from_rom_hash >"$HOTP_SECRET" || die "Reading ROM failed"
fi
# Truncate the secret if it is longer than the maximum HOTP secret
truncate_max_bytes 20 "$HOTP_SECRET"
if ! hotp $counter_value <"$HOTP_SECRET"; then
shred -n 10 -z -u "$HOTP_SECRET" 2>/dev/null
die 'Unable to compute HOTP hash?'
shred -n 10 -z -u "$HOTP_SECRET" 2>/dev/null
die 'Unable to compute HOTP hash?'
fi
shred -n 10 -z -u "$HOTP_SECRET" 2>/dev/null
@ -65,7 +71,7 @@ mount -o remount,rw /boot
DEBUG "Incrementing HOTP counter under $HOTP_COUNTER"
counter_value=$(expr $counter_value + 1)
echo $counter_value >$HOTP_COUNTER ||
die "Unable to create hotp counter file"
die "Unable to create hotp counter file"
mount -o remount,ro /boot
exit 0

View File

@ -8,11 +8,12 @@ TOTP_SECRET="/tmp/secret/totp.key"
TRACE_FUNC
if [ "$CONFIG_TPM" = "y" ]; then
tpmr unseal 4d47 0,1,2,3,4,7 312 "$TOTP_SECRET" ||
die "Unable to unseal TOTP secret from TPM"
DO_WITH_DEBUG --mask-position 5 \
tpmr unseal 4d47 0,1,2,3,4,7 312 "$TOTP_SECRET" ||
die "Unable to unseal TOTP secret from TPM"
fi
if ! totp -q <"$TOTP_SECRET"; then
if ! DO_WITH_DEBUG totp -q <"$TOTP_SECRET"; then
shred -n 10 -z -u "$TOTP_SECRET" 2>/dev/null
die 'Unable to compute TOTP hash?'
fi

View File

@ -8,7 +8,10 @@ die() {
else
echo -e "!!! ERROR: $* !!!" >&2
fi
sleep 2
# ask user to press any key prior to exit
read -n 1 -s -r -p $'Press Enter to continue...\n\n'
exit 1
}
@ -194,7 +197,7 @@ confirm_gpg_card() {
echo "GPG User PIN retry attempts left before becoming locked: $user_pin_retries"
echo "GPG Admin PIN retry attempts left before becoming locked: $admin_pin_retries"
echo ""
warn "Your GPG User PIN, followed by Enter key will be required for input at: 'Please unlock the card' next prompt"
warn "Your GPG User PIN, followed by Enter will be required for input at: 'Please unlock the card' next prompt"
echo ""
}
@ -512,14 +515,33 @@ DO_WITH_DEBUG() {
return "$exit_status"
}
# Trace the current script and function.
# TRACE_FUNC outputs the function call stack in a readable format.
# It helps debug the execution path leading to the current function.
#
# The format of the output is:
# main(/path/to/script:line) -> function1(/path/to/file:line) -> function2(/path/to/file:line)
#
# Usage:
# Call TRACE_FUNC within any function to print the call hierarchy.
TRACE_FUNC() {
# Index [1] for BASH_SOURCE and FUNCNAME give us the caller location.
# FUNCNAME is 'main' if called from a script outside any function.
# BASH_LINENO is offset by 1, it provides the line that the
# corresponding FUNCNAME was _called from_, so BASH_LINENO[0] is the
# location of the caller.
TRACE "${BASH_SOURCE[1]}(${BASH_LINENO[0]}): ${FUNCNAME[1]}"
local i stack_trace=""
# Traverse the call stack from the earliest caller to the direct caller of TRACE_FUNC
for ((i = ${#FUNCNAME[@]} - 1; i > 1; i--)); do
stack_trace+="${FUNCNAME[i]}(${BASH_SOURCE[i]}:${BASH_LINENO[i - 1]}) -> "
done
# Append the direct caller (without extra " -> " at the end)
stack_trace+="${FUNCNAME[1]}(${BASH_SOURCE[1]}:${BASH_LINENO[0]})"
# Print the final trace output
TRACE "${stack_trace}"
}
# Show the entire current call stack in debug output - useful if a catastrophic
@ -750,7 +772,7 @@ prompt_new_owner_password() {
# Cache the password externally to be reused by who needs it
DEBUG "Caching TPM Owner Password to /tmp/secret/tpm_owner_password"
mkdir -p /tmp/secret || die "Unable to create /tmp/secret"
echo -n "$tpm_owner_password" >/tmp/secret/tpm_owner_password || die "Unable to cache TPM password under /tmp/secret"
echo -n "$tpm_owner_password" >/tmp/secret/tpm_owner_password || die "Unable to cache TPM password under /tmp/secret/tpm_owner_password"
}
check_tpm_counter() {
@ -780,16 +802,21 @@ check_tpm_counter() {
# Read the TPM counter value from the TPM.
read_tpm_counter() {
TRACE_FUNC
tpmr counter_read -ix "$1" | tee "/tmp/counter-$1" >/dev/null 2>&1 ||
die "Counter read failed"
if [ ! -e /tmp/counter-"$1" ]; then
DEBUG "Counter file /tmp/counter-$1 not found. Attempting to read from TPM."
DO_WITH_DEBUG tpmr counter_read -ix "$1" | tee /tmp/counter-"$1" >/dev/null 2>&1 ||
die "Counter read failed for index $1"
fi
DEBUG "Counter file /tmp/counter-$1 read successfully."
}
# Increment the TPM counter value in the TPM.
increment_tpm_counter() {
TRACE_FUNC
tpmr counter_increment -ix "$1" -pwdc '' |
tee /tmp/counter-$1 >/dev/null 2>&1 ||
die "TPM counter increment failed for rollback prevention. Please reset the TPM"
DO_WITH_DEBUG tpmr counter_increment -ix "$1" -pwdc '' |
tee /tmp/counter-"$1" >/dev/null 2>&1 ||
die "TPM counter increment failed for rollback prevention. Please reset the TPM."
DEBUG "TPM counter incremented successfully for index $1"
}
# Check detached signature on kexec boot params
@ -804,14 +831,17 @@ check_config() {
fi
if [ ! -r $1/kexec.sig -a "$CONFIG_BASIC" != "y" ]; then
DEBUG "No $1/kexec.sig found"
return
fi
if [ $(find $1/kexec*.txt | wc -l) -eq 0 ]; then
DEBUG "No $1/kexec*.txt found"
return
fi
if [ "$2" != "force" ]; then
DEBUG "second param: $2 != force"
# Note that kexec.sig detached signature is solely verifying kexec*.txt files here!
if ! sha256sum $(find $1/kexec*.txt) | gpgv $1/kexec.sig -; then
die 'Invalid signature on kexec boot params'
@ -885,10 +915,11 @@ update_checksums() {
extparam=
if [ "$CONFIG_TPM" = "y" ]; then
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
DEBUG "add -r to kexec-sign-config since CONFIG_IGNORE_ROLLBACK is not set"
extparam=-r
fi
fi
if ! kexec-sign-config -p /boot -u $extparam; then
if ! DO_WITH_DEBUG kexec-sign-config -p /boot -u $extparam; then
rv=1
else
rv=0
@ -996,12 +1027,12 @@ 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 2>/dev/null || 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
if ! cmp -s "$TMP_TREE_FILE" /tmp/tree_output 2>/dev/null; then
ret=1
[[ "$gui" != "y" ]] && exit "$ret"
# produce a diff that can safely be presented to the user
@ -1190,7 +1221,6 @@ scan_boot_options() {
fi
}
# truncate a file to a size only if it is longer (busybox truncate lacks '<' and
# always sets the file size)
truncate_max_bytes() {
@ -1220,13 +1250,13 @@ fromhex_plain() {
print_battery_charge() {
local battery
battery="$1"
echo "$((100*$(cat "${battery}/charge_now")/$(cat "${battery}/charge_full")))"
echo "$((100 * $(cat "${battery}/charge_now") / $(cat "${battery}/charge_full")))"
}
print_battery_health() {
local battery
battery="$1"
echo "$((100*$(cat "${battery}/charge_full")/$(cat "${battery}/charge_full_design")))"
echo "$((100 * $(cat "${battery}/charge_full") / $(cat "${battery}/charge_full_design")))"
}
print_battery_name() {

View File

@ -33,9 +33,9 @@ if lsmod | sed 's/_/-/g' | grep -q "^$module_name\\b"; then
fi
if [ ! -r /sys/class/tpm/tpm0/pcrs -o ! -x /bin/tpm ]; then
if [ ! -c /dev/tpmrm0 -o ! -x /bin/tpm2 ]; then
tpm_missing=1
fi
if [ ! -c /dev/tpmrm0 -o ! -x /bin/tpm2 ]; then
tpm_missing=1
fi
fi
if [ -z "$tpm_missing" ]; then