-
-
Notifications
You must be signed in to change notification settings - Fork 196
HOTP asked to be resealed even if TOTP good (Picks up on a reinstalled OS even if firmware measurements haven't changed) #1935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
1f6a975
f9def6b
b5cb7ae
c4b7fef
0d3b3b6
68da322
03c5d39
6d90480
08c8862
4ef7473
d9730be
9c7ef3f
d10a424
19d400a
67a7fd9
5dcad9e
1928995
faf32fb
b95ffcc
c43af60
f475296
21adb0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -150,16 +150,21 @@ generate_totp_hotp() { | |
TRACE_FUNC | ||
tpm_owner_password="$1" # May be empty, will prompt if needed and empty | ||
if [ "$CONFIG_TPM" != "y" ] && [ -x /bin/hotp_verification ]; then | ||
# If we don't have a TPM, but we have a HOTP USB Security dongle | ||
TRACE_FUNC | ||
echo "Generating new HOTP secret" | ||
/bin/seal-hotpkey | ||
/bin/seal-hotpkey || | ||
die "Failed to generate HOTP secret" | ||
elif echo -e "Generating new TOTP secret...\n\n" && /bin/seal-totp "$BOARD_NAME" "$tpm_owner_password"; then | ||
echo | ||
if [ -x /bin/hotp_verification ]; then | ||
# If we have a TPM and a HOTP USB Security dongle | ||
if [ "$CONFIG_TOTP_SKIP_QRCODE" != y ]; then | ||
echo "Once you have scanned the QR code, hit Enter to configure your HOTP USB Security dongle (e.g. Librem Key or Nitrokey)" | ||
read | ||
fi | ||
/bin/seal-hotpkey | ||
TRACE_FUNC | ||
/bin/seal-hotpkey || die "Failed to generate HOTP secret" | ||
else | ||
if [ "$CONFIG_TOTP_SKIP_QRCODE" != y ]; then | ||
echo "Once you have scanned the QR code, hit Enter to continue" | ||
|
@@ -183,17 +188,6 @@ update_totp() { | |
TOTP="NO TPM" | ||
else | ||
TOTP=$(unseal-totp) | ||
# On platforms using CONFIG_BOOT_EXTRA_TTYS multiple processes may try to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No more 3 attempts on boot to unseal TPMTOTP: if multiple consoles (Eg Talos-2 with display console + BMC, at worst we could intruduce small delay if race condition still happening, while die asks user to press Enter now, guiding to reseal TPMTOTP or reset TPM if unable to access TPM NVRAM. |
||
# 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 +274,10 @@ update_hotp() { | |
HOTP='N/A' | ||
fi | ||
|
||
if [[ "$CONFIG_TPM" = n && "$HOTP" = "Invalid code" ]]; then | ||
if [[ "$HOTP" = "Invalid code" ]]; then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check only verified if HOTP was invalid if no TPM was in use. So now, if there is no /boot/kexec_hotp_counter and TPMTOTP can unseal, user is promoted to reseal HOTP alone (OS reinstall use case without firmware upgrade) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But what is we have kexec_rollback.txt? All of this doesn't make any sense: user should reset TPM here of more logic needs to be refactored. |
||
#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 +550,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 | ||
|
@@ -576,7 +582,8 @@ reset_tpm() { | |
--msgbox "Failed to update checksums / sign default config" 0 80 | ||
fi | ||
else | ||
die "TPM reset successful, but user chose not to update checksums" | ||
warn "TPM reset successful, but user chose not to update+sign /boot checksums. Rebooting" | ||
reboot | ||
fi | ||
mount -o ro,remount /boot | ||
|
||
|
@@ -593,7 +600,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 +613,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 | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DEBUG was exposing TPM owner passphrase on log + debug.log |
||
|
||
# And now turn it all back on | ||
DO_WITH_DEBUG tpm physicalpresence -s &>/dev/null | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @marmarek the issue was that previously, if TOTPM previously sealed/unsealed (measured boot from coreboot+heads), Heads was not looking to see if HOTP counter under /boot/kexec_hotp_counter was still present. |
||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Welcome to the Recovery Shell! | ||
|
||
- /tmp/debug.log: contains corresponding log level (Quiet/Info/Debug) debug traces | ||
- Read them locally through: 'less /tmp/debug/log' | ||
- If you faced a bug: | ||
- Preformat/connect a ext3/ext4/fat32/exfat USB thumb drive, and then: | ||
- 'mount-usb --mode rw' # Mounts a connected USB drive in Read+Write mode | ||
- 'cp /tmp/debug.log /media' # copy the log to mounted Read+Write partition under /media | ||
- 'umount /media' # Makes sure buffered write operations are done and "ejects" the USB drive | ||
- Share the debug.log with the developers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bash history now promotes mount-usb --mode rw. nitpick