Skip to content

Commit 75e766a

Browse files
committed
HOTP + /boot verif: add debug and prompt if HOTP counter is not found but TPMTOTP can unseal (OS reinstalled?) + die asks for input now.
Signed-off-by: Thierry Laurion <[email protected]>
1 parent 4797981 commit 75e766a

File tree

8 files changed

+76
-29
lines changed

8 files changed

+76
-29
lines changed

initrd/bin/gui-init

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,6 @@ update_totp() {
183183
TOTP="NO TPM"
184184
else
185185
TOTP=$(unseal-totp)
186-
# On platforms using CONFIG_BOOT_EXTRA_TTYS multiple processes may try to
187-
# access TPM at the same time, failing with EBUSY. The order of execution
188-
# is unpredictable, so the error may appear on main console, secondary one,
189-
# or neither of them if the calls are sufficiently staggered. Try up to
190-
# three times (including previous one) with small delays in case of error,
191-
# instead of immediately scaring users with "you've been pwned" message.
192-
while [ $? -ne 0 ] && [ $tries -lt 2 ]; do
193-
sleep 0.5
194-
((tries++))
195-
TOTP=$(unseal-totp)
196-
done
197186
if [ $? -ne 0 ]; then
198187
BG_COLOR_MAIN_MENU="error"
199188
if [ "$skip_to_menu" = "true" ]; then
@@ -280,7 +269,9 @@ update_hotp() {
280269
HOTP='N/A'
281270
fi
282271

283-
if [[ "$CONFIG_TPM" = n && "$HOTP" = "Invalid code" ]]; then
272+
if [[ "$HOTP" = "Invalid code" ]]; then
273+
#TOTP unseal succeeded if unseal-totp called first: TPMTOTP secret is correct. Only propose to reseal TPMTOTP though reverse HOTP
274+
# The OS was most probably reinstalled while TPM can still unseal TPMTOTP secret
284275
whiptail_error --title "ERROR: HOTP Validation Failed!" \
285276
--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 \
286277
'g' ' Generate new TOTP/HOTP secret' \
@@ -553,7 +544,9 @@ reset_tpm() {
553544
mount -o rw,remount /boot
554545
#TODO: this is really problematic, we should really remove the primary handle hash
555546

556-
INFO "Removing rollback and primary handle hash under /boot"
547+
INFO "Removing rollback and primary handle hashes under /boot"
548+
549+
DEBUG "Removing /boot/kexec_rollback.txt and /boot/kexec_primhdl_hash.txt"
557550
rm -f /boot/kexec_rollback.txt
558551
rm -f /boot/kexec_primhdl_hash.txt
559552

@@ -562,12 +555,16 @@ reset_tpm() {
562555
die "Unable to find/create tpm counter"
563556
counter="$TPM_COUNTER"
564557

558+
DEBUG "TPM_COUNTER: $counter"
559+
TRACE_FUNC
560+
565561
increment_tpm_counter $counter >/dev/null 2>&1 ||
566562
die "Unable to increment tpm counter"
567563

568564
sha256sum /tmp/counter-$counter >/boot/kexec_rollback.txt ||
569565
die "Unable to create rollback file"
570566

567+
TRACE_FUNC
571568
# As a countermeasure for existing primary handle hash, we will now force sign /boot without it
572569
if (whiptail --title 'TPM Reset Successfully' \
573570
--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
@@ -606,10 +603,12 @@ attempt_default_boot() {
606603
fi
607604
DEFAULT_FILE=$(find /boot/kexec_default.*.txt 2>/dev/null | head -1)
608605
if [ -r "$DEFAULT_FILE" ]; then
606+
TRACE_FUNC
609607
kexec-select-boot -b /boot -c "grub.cfg" -g ||
610608
recovery "Failed default boot"
611609
elif (whiptail_warning --title 'No Default Boot Option Configured' \
612610
--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
611+
TRACE_FUNC
613612
kexec-select-boot -m -b /boot -c "grub.cfg" -g
614613
fi
615614
}

initrd/bin/kexec-save-key

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ kexec-seal-key $paramsdir ||
7777
if [ "$skip_sign" != "y" ]; then
7878
extparam=
7979
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
80+
DEBUG "kexec-save-key: CONFIG_IGNORE_ROLLBACK is not set, will sign with -r"
8081
extparam=-r
8182
fi
8283
# sign and auto-roll config counter

initrd/bin/kexec-select-boot

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,14 @@ verify_rollback_counter() {
120120
TPM_COUNTER=$(grep counter $TMP_ROLLBACK_FILE | cut -d- -f2)
121121

122122
if [ -z "$TPM_COUNTER" ]; then
123-
die "$TMP_ROLLBACK_FILE: TPM counter not found?"
123+
die "$TMP_ROLLBACK_FILE: TPM counter not found. Please reset TPM through the Heads menu: Options -> TPM/TOTP/HOTP Options -> Reset the TPM"
124124
fi
125125

126126
read_tpm_counter $TPM_COUNTER >/dev/null 2>&1 ||
127-
die "Failed to read TPM counter"
127+
die "Failed to read TPM counter. Please reset TPM through the Heads menu: Options -> TPM/TOTP/HOTP Options -> Reset the TPM"
128128

129129
sha256sum -c $TMP_ROLLBACK_FILE >/dev/null 2>&1 ||
130-
die "Invalid TPM counter state. TPM Reset required"
130+
die "Invalid TPM counter state. Please reset TPM through the Heads menu: Options -> TPM/TOTP/HOTP Options -> Reset the TPM"
131131

132132
valid_rollback="y"
133133
}

initrd/bin/kexec-sign-config

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,31 @@ fi
2727
paramsdir="${paramsdir%%/}"
2828

2929
assert_signable
30+
TRACE_FUNC
3031

3132
confirm_gpg_card
33+
TRACE_FUNC
3234

3335
# remount /boot as rw
3436
mount -o remount,rw /boot
3537

38+
DEBUG "Signing kexec parameters in $paramsdir, rollback=$rollback, update=$update, counter=$counter"
39+
3640
# update hashes in /boot before signing
3741
if [ "$update" = "y" ]; then
3842
(
43+
TRACE_FUNC
44+
DEBUG "update=y: Updating kexec hashes in /boot"
3945
cd /boot
4046
find ./ -type f ! -path './kexec*' -print0 | xargs -0 sha256sum >/boot/kexec_hashes.txt
4147
if [ -e /boot/kexec_default_hashes.txt ]; then
48+
DEBUG "/boot/kexec_default_hashes.txt exists, updating /boot/kexec_default_hashes.txt"
4249
DEFAULT_FILES=$(cat /boot/kexec_default_hashes.txt | cut -f3 -d ' ')
4350
echo $DEFAULT_FILES | xargs sha256sum >/boot/kexec_default_hashes.txt
4451
fi
4552

53+
TRACE_FUNC
54+
4655
#also save the file & directory structure to detect added files
4756
print_tree >/boot/kexec_tree.txt
4857
)
@@ -56,7 +65,13 @@ fi
5665
if [ "$rollback" = "y" ]; then
5766
rollback_file="$paramsdir/kexec_rollback.txt"
5867

68+
DEBUG "rollback=y, counter=$counter, paramsdir=$paramsdir"
69+
TRACE_FUNC
70+
5971
if [ -n "$counter" ]; then
72+
DEBUG "rollback=y: counter=$counter, will read tpm counter next"
73+
TRACE_FUNC
74+
6075
# use existing counter
6176
read_tpm_counter $counter >/dev/null 2>&1 ||
6277
die "$paramsdir: Unable to read tpm counter '$counter'"

initrd/bin/tpmr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ tpm1_reset() {
719719
DO_WITH_DEBUG tpm physicalsetdeactivated -c &>/dev/null
720720
DO_WITH_DEBUG tpm forceclear &>/dev/null
721721
DO_WITH_DEBUG tpm physicalenable &>/dev/null
722-
DO_WITH_DEBUG tpm takeown -pwdo "$tpm_owner_password" &>/dev/null
722+
DO_WITH_DEBUG --mask-position 3 tpm takeown -pwdo "$tpm_owner_password" &>/dev/null
723723

724724
# And now turn it all back on
725725
DO_WITH_DEBUG tpm physicalpresence -s &>/dev/null

initrd/bin/unseal-hotp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ mount_boot_or_die
2929
#counter_value=$(read_tpm_counter $counter | cut -f2 -d ' ' | awk 'gsub("^000e","")')
3030
#
3131

32-
counter_value=$(cat $HOTP_COUNTER)
32+
#if HOTP_COUNTER is not present, bail out
33+
if [ ! -f $HOTP_COUNTER ]; then
34+
die "HOTP counter file not found. If you just reinstalled an OS, you need to reseal the HOTP secret"
35+
fi
36+
37+
# Read the counter from the file
38+
counter_value=$(cat $HOTP_COUNTER 2>/dev/null)
3339

3440
if [ "$counter_value" == "" ]; then
3541
die "Unable to read HOTP counter"

initrd/bin/unseal-totp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ TOTP_SECRET="/tmp/secret/totp.key"
88
TRACE_FUNC
99

1010
if [ "$CONFIG_TPM" = "y" ]; then
11-
tpmr unseal 4d47 0,1,2,3,4,7 312 "$TOTP_SECRET" ||
12-
die "Unable to unseal TOTP secret from TPM"
11+
DO_WITH_DEBUG --mask-position 5 \
12+
tpmr unseal 4d47 0,1,2,3,4,7 312 "$TOTP_SECRET" ||
13+
die "Unable to unseal TOTP secret from TPM"
1314
fi
1415

15-
if ! totp -q <"$TOTP_SECRET"; then
16+
if ! DO_WITH_DEBUG --mask-position 2 totp -q <"$TOTP_SECRET"; then
1617
shred -n 10 -z -u "$TOTP_SECRET" 2>/dev/null
1718
die 'Unable to compute TOTP hash?'
1819
fi

initrd/etc/functions

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ die() {
88
else
99
echo -e "!!! ERROR: $* !!!" >&2
1010
fi
11-
sleep 2
11+
12+
# ask user to press any key prior to exit
13+
read -n 1 -s -r -p $'Press any key to continue...\n\n'
14+
1215
exit 1
1316
}
1417

@@ -778,7 +781,7 @@ prompt_new_owner_password() {
778781
# Cache the password externally to be reused by who needs it
779782
DEBUG "Caching TPM Owner Password to /tmp/secret/tpm_owner_password"
780783
mkdir -p /tmp/secret || die "Unable to create /tmp/secret"
781-
echo -n "$tpm_owner_password" >/tmp/secret/tpm_owner_password || die "Unable to cache TPM password under /tmp/secret"
784+
echo -n "$tpm_owner_password" >/tmp/secret/tpm_owner_password || die "Unable to cache TPM password under /tmp/secret/tpm_owner_password"
782785
}
783786

784787
check_tpm_counter() {
@@ -817,12 +820,17 @@ increment_tpm_counter() {
817820
TRACE_FUNC
818821
tpmr counter_increment -ix "$1" -pwdc '' |
819822
tee /tmp/counter-$1 >/dev/null 2>&1 ||
820-
die "TPM counter increment failed for rollback prevention. Please reset the TPM"
823+
die "TPM counter increment failed for rollback prevention. Please reset the TPM. Press Enter to continue"
824+
#TODO: why the die here needs to say to Press Enter to continue? Should be part of die call?
821825
}
822826

823827
# Check detached signature on kexec boot params
824828
check_config() {
825829
TRACE_FUNC
830+
831+
DEBUG "paramdir: $1"
832+
DEBUG "force: $2"
833+
826834
if [ ! -d /tmp/kexec ]; then
827835
mkdir /tmp/kexec ||
828836
die 'Failed to make kexec tmp dir'
@@ -832,17 +840,27 @@ check_config() {
832840
fi
833841

834842
if [ ! -r $1/kexec.sig -a "$CONFIG_BASIC" != "y" ]; then
843+
DEBUG "No $1/kexec.sig found"
835844
return
836845
fi
837846

838847
if [ $(find $1/kexec*.txt | wc -l) -eq 0 ]; then
848+
DEBUG "No $1/kexec*.txt found"
839849
return
840850
fi
841851

842852
if [ "$2" != "force" ]; then
853+
DEBUG "checking unforced signature on $1/kexec*.txt against $1/kexec.sig"
854+
#TODO: what does unforced signature mean if its actually forced?
855+
856+
#die if we have no detached digest under $1/kexec.sig
857+
if [ ! -r "$1/kexec.sig" ]; then
858+
die "No detached digest signature found under $1/kexec.sig. Please do 'Options-> Update checksums and sign all files in /boot'"
859+
fi
860+
843861
# Note that kexec.sig detached signature is solely verifying kexec*.txt files here!
844862
if ! sha256sum $(find $1/kexec*.txt) | gpgv $1/kexec.sig -; then
845-
die 'Invalid signature on kexec boot params'
863+
die "Invalid digest signature under $1/kexec.sig. Please do 'Options-> Update checksums and sign all files in /boot'"
846864
fi
847865
fi
848866

@@ -913,6 +931,7 @@ update_checksums() {
913931
extparam=
914932
if [ "$CONFIG_TPM" = "y" ]; then
915933
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
934+
DEBUG "add -r to kexec-sign-config since CONFIG_IGNORE_ROLLBACK is not set"
916935
extparam=-r
917936
fi
918937
fi
@@ -1024,20 +1043,26 @@ verify_checksums() {
10241043
set +e -o pipefail
10251044
local ret=0
10261045
cd "$boot_dir" || ret=1
1027-
sha256sum -c "$TMP_HASH_FILE" >/tmp/hash_output || ret=1
1046+
TRACE_FUNC
1047+
sha256sum -c "$TMP_HASH_FILE" >/tmp/hash_output 2>/dev/null || ret=1
10281048

10291049
# also make sure that the file & directory structure didn't change
10301050
# (sha256sum won't detect added files)
10311051
print_tree >/tmp/tree_output || ret=1
1032-
if ! cmp -s "$TMP_TREE_FILE" /tmp/tree_output &>/dev/null; then
1052+
#if ! cmp -s "$TMP_TREE_FILE" /tmp/tree_output 2>/dev/null; then
1053+
if ! cmp -s "$TMP_TREE_FILE" /tmp/tree_output; then
1054+
TRACE_FUNC
10331055
ret=1
10341056
[[ "$gui" != "y" ]] && exit "$ret"
10351057
# produce a diff that can safely be presented to the user
10361058
# this is relatively hard as file names may e.g. contain backslashes etc.,
10371059
# which are interpreted by whiptail, less, ...
1038-
escape_zero "(new) " <"$TMP_TREE_FILE" >"${TMP_TREE_FILE}.user"
1060+
[ -f "$TMP_TREE_FILE" ] && escape_zero "(new) " <"$TMP_TREE_FILE" >"${TMP_TREE_FILE}.user"
10391061
escape_zero "(new) " </tmp/tree_output >/tmp/tree_output.user
1040-
diff "${TMP_TREE_FILE}.user" /tmp/tree_output.user | grep -E '^\+\(new\).*$' | sed -r 's/^\+\(new\)/(new)/g' >>/tmp/hash_output
1062+
TRACE_FUNC
1063+
diff "${TMP_TREE_FILE}.user" /tmp/tree_output.user 2>/dev/null |
1064+
grep -E '^\+(new).*$' | sed -r 's/^\+(new)/(new)/g' >/tmp/tree_output
1065+
TRACE_FUNC
10411066
rm -f "${TMP_TREE_FILE}.user"
10421067
rm -f /tmp/tree_output.user
10431068
fi

0 commit comments

Comments
 (0)