gui-init: Eliminate extra TPM owner password prompts in TPM reset

We just set the TPM owner password, so there's no need to make the user
enter it again.  Eliminates some failure modes if the user mistypes it
or enters the wrong password.

Allow optionally passing in the TPM owner password in tpmr seal,
check_tpm_counter(), seal-totp, and generate_totp_htop().  The user is
still prompted if the password is needed but was not provided, so
existing uses in other contexts continue to work unchanged.

Prompt for the password in reset_tpm() and pass it down to each of the
above.

Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
This commit is contained in:
Jonathon Hall
2023-03-10 15:36:24 -05:00
parent 48421ada1e
commit 698fc83046
4 changed files with 55 additions and 15 deletions

View File

@ -150,9 +150,10 @@ prompt_update_checksums()
generate_totp_htop() generate_totp_htop()
{ {
tpm_password="$1" # May be empty, will prompt if needed and empty
TRACE "Under /bin/gui-init:generate_totp_htop" TRACE "Under /bin/gui-init:generate_totp_htop"
echo "Scan the QR code to add the new TOTP secret" echo "Scan the QR code to add the new TOTP secret"
if /bin/seal-totp "$BOARD_NAME"; then if /bin/seal-totp "$BOARD_NAME" "$tpm_password"; then
if [ -x /bin/hotp_verification ]; then if [ -x /bin/hotp_verification ]; then
echo "Once you have scanned the QR code, hit Enter to configure your HOTP USB Security Dongle (e.g. Librem Key or Nitrokey)" echo "Once you have scanned the QR code, hit Enter to configure your HOTP USB Security Dongle (e.g. Librem Key or Nitrokey)"
read read
@ -509,13 +510,39 @@ prompt_totp_mismatch()
fi fi
} }
prompt_new_owner_password() {
read -s -p "New TPM owner password: " key_password
echo
if [ -z "$key_password" ]; then
echo "Empty owner password is not allowed" >&2
return 1
fi
read -s -p "Repeat owner password: " key_password2
echo
if [ "$key_password" != "$key_password2" ]; then
echo "Key passwords do not match" >&2
return 1
fi
}
reset_tpm() reset_tpm()
{ {
TRACE "Under /bin/gui-init:reset_tpm" TRACE "Under /bin/gui-init:reset_tpm"
if [ "$CONFIG_TPM" = "y" ]; then if [ "$CONFIG_TPM" = "y" ]; then
if (whiptail $BG_COLOR_WARNING --title 'Reset the TPM' \ if (whiptail $BG_COLOR_WARNING --title 'Reset the TPM' \
--yesno "This will clear the TPM and TPM password, replace them with new ones!\n\nDo you want to proceed?" 0 80) then --yesno "This will clear the TPM and TPM password, replace them with new ones!\n\nDo you want to proceed?" 0 80) then
/bin/tpm-reset
if ! prompt_new_owner_password; then
echo "Press Enter to return to the menu..."
read
echo
return 1
fi
tpmr reset "$key_password"
# now that the TPM is reset, remove invalid TPM counter files # now that the TPM is reset, remove invalid TPM counter files
mount_boot mount_boot
@ -524,7 +551,7 @@ reset_tpm()
rm -f /boot/kexec_primhdl_hash.txt rm -f /boot/kexec_primhdl_hash.txt
# create Heads TPM counter before any others # create Heads TPM counter before any others
check_tpm_counter /boot/kexec_rollback.txt \ check_tpm_counter /boot/kexec_rollback.txt "" "$key_password" \
|| die "Unable to find/create tpm counter" || die "Unable to find/create tpm counter"
counter="$TPM_COUNTER" counter="$TPM_COUNTER"
@ -535,7 +562,7 @@ reset_tpm()
|| die "Unable to create rollback file" || die "Unable to create rollback file"
mount -o ro,remount /boot mount -o ro,remount /boot
generate_totp_htop generate_totp_htop "$key_password"
else else
echo "Returning to the main menu" echo "Returning to the main menu"
fi fi

View File

@ -15,6 +15,7 @@ HOST="$1"
if [ -z "$HOST" ]; then if [ -z "$HOST" ]; then
HOST="TPMTOTP" HOST="TPMTOTP"
fi fi
TPM_PASSWORD="$2"
TOTP_SECRET="/tmp/secret/totp.key" TOTP_SECRET="/tmp/secret/totp.key"
TOTP_SEALED="/tmp/secret/totp.sealed" TOTP_SEALED="/tmp/secret/totp.sealed"
@ -41,7 +42,7 @@ DEBUG "Sealing TOTP neglecting PCR5 involvement (Dynamically loaded kernel modul
DEBUG "Sealing TOTP without PCR6 involvement (LUKS header consistency is not firmware integrity attestation related)" DEBUG "Sealing TOTP without PCR6 involvement (LUKS header consistency is not firmware integrity attestation related)"
# pcr 7 is containing measurements of user injected stuff in cbfs # pcr 7 is containing measurements of user injected stuff in cbfs
tpmr pcrread -a 7 "$pcrf" tpmr pcrread -a 7 "$pcrf"
tpmr seal "$TOTP_SECRET" "$TPM_NVRAM_SPACE" 0,1,2,3,4,7 "$pcrf" 312 \ tpmr seal "$TOTP_SECRET" "$TPM_NVRAM_SPACE" 0,1,2,3,4,7 "$pcrf" 312 "" "$TPM_PASSWORD" \
|| die "Unable to write sealed secret to NVRAM" || die "Unable to write sealed secret to NVRAM"
shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null

View File

@ -262,7 +262,9 @@ tpm2_seal() {
pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix) pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix)
pcrf="$4" pcrf="$4"
sealed_size="$5" # Not used for TPM2 sealed_size="$5" # Not used for TPM2
pass="$6" pass="$6" # May be empty to seal with no password
tpm_password="$7" # Owner password - will prompt if needed and not empty
# Owner password is always needed for TPM2.
mkdir -p "$SECRET_DIR" mkdir -p "$SECRET_DIR"
bname="`basename $file`" bname="`basename $file`"
@ -313,13 +315,12 @@ tpm2_seal() {
tpm2 load -Q -C "/tmp/$PRIMARY_HANDLE_FILE" \ tpm2 load -Q -C "/tmp/$PRIMARY_HANDLE_FILE" \
-u "$SECRET_DIR/$bname.priv" -r "$SECRET_DIR/$bname.pub" \ -u "$SECRET_DIR/$bname.priv" -r "$SECRET_DIR/$bname.pub" \
-c "$SECRET_DIR/$bname.seal.ctx" -c "$SECRET_DIR/$bname.seal.ctx"
read -s -p "TPM owner password: " key_password prompt_tpm_password
echo # new line after password prompt
# remove possible data occupying this handle # remove possible data occupying this handle
tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$key_password")" \ tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_password")" \
-c "$handle" 2>/dev/null || true -c "$handle" 2>/dev/null || true
DO_WITH_DEBUG --mask-position 6 \ DO_WITH_DEBUG --mask-position 6 \
tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$key_password")" \ tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_password")" \
-c "$SECRET_DIR/$bname.seal.ctx" "$handle" -c "$SECRET_DIR/$bname.seal.ctx" "$handle"
} }
tpm1_seal() { tpm1_seal() {
@ -329,7 +330,8 @@ tpm1_seal() {
pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix) pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix)
pcrf="$4" pcrf="$4"
sealed_size="$5" sealed_size="$5"
pass="$6" pass="$6" # May be empty to seal with no password
tpm_password="$7" # Owner password - will prompt if needed and not empty
sealed_file="$SECRET_DIR/tpm1_seal_sealed.bin" sealed_file="$SECRET_DIR/tpm1_seal_sealed.bin"
trap "cleanup_shred '$sealed_file'" EXIT trap "cleanup_shred '$sealed_file'" EXIT
@ -368,8 +370,7 @@ tpm1_seal() {
tpm physicalpresence -s \ tpm physicalpresence -s \
|| warn "Warning: Unable to assert physical presence" || warn "Warning: Unable to assert physical presence"
read -s -p "TPM Owner password: " tpm_password prompt_tpm_password
echo
tpm nv_definespace -in "$index" -sz "$sealed_size" \ tpm nv_definespace -in "$index" -sz "$sealed_size" \
-pwdo "$tpm_password" -per 0 \ -pwdo "$tpm_password" -per 0 \

View File

@ -247,19 +247,30 @@ confirm_gpg_card()
fi fi
} }
# Prompt for an owner password if it is not already set in tpm_password. Sets
# tpm_password. Tools should optionally accept a TPM password on the command
# line, since some flows need it multiple times and only one prompt is ideal.
prompt_tpm_password() {
if [ -n "$tpm_password" ]; then
return 0;
fi
read -s -p "TPM Owner password: " tpm_password
echo # new line after password prompt
}
check_tpm_counter() check_tpm_counter()
{ {
TRACE "Under /etc/functions:check_tpm_counter" TRACE "Under /etc/functions:check_tpm_counter"
LABEL=${2:-3135106223} LABEL=${2:-3135106223}
tpm_password="$3"
# if the /boot.hashes file already exists, read the TPM counter ID # if the /boot.hashes file already exists, read the TPM counter ID
# from it. # from it.
if [ -r "$1" ]; then if [ -r "$1" ]; then
TPM_COUNTER=`grep counter- "$1" | cut -d- -f2` TPM_COUNTER=`grep counter- "$1" | cut -d- -f2`
else else
warn "$1 does not exist; creating new TPM counter" warn "$1 does not exist; creating new TPM counter"
read -s -p "TPM Owner password: " tpm_password prompt_tpm_password
echo
tpmr counter_create \ tpmr counter_create \
-pwdo "$tpm_password" \ -pwdo "$tpm_password" \
-pwdc '' \ -pwdc '' \