From 27c457f04b566891bd8468d929e1dafd04585ba6 Mon Sep 17 00:00:00 2001 From: Thierry Laurion <insurgo@riseup.net> Date: Tue, 24 Oct 2023 11:19:49 -0400 Subject: [PATCH] TPM2 DUK and TOTP/HOTP reseal fix, refactoring and ifferenciating tpm_password into tpm_owner_password and reusing correctly i TODO: fix all TODO in PR prior of review + squash Signed-off-by: Thierry Laurion <insurgo@riseup.net> --- .../qemu-coreboot-whiptail-tpm1.config | 5 ++- initrd/bin/gui-init | 12 ++--- initrd/bin/kexec-seal-key | 4 +- initrd/bin/oem-factory-reset | 8 ++-- initrd/bin/seal-totp | 2 +- initrd/bin/tpm-reset | 2 +- initrd/bin/tpmr | 35 ++++++++------- initrd/etc/functions | 44 +++++++++---------- 8 files changed, 58 insertions(+), 54 deletions(-) diff --git a/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config b/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config index bc485944..0b05dfaa 100644 --- a/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config +++ b/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config @@ -11,11 +11,12 @@ export CONFIG_LINUX_VERSION=5.10.5 #export CONFIG_BASIC=y #Enable HAVE_GPG_KEY_BACKUP to test GPG key backup drive (we cannot inject config under QEMU (no internal flashing)) +#TODO: comment following line prior of pushing final version export CONFIG_HAVE_GPG_KEY_BACKUP=y #Enable DEBUG output -#export CONFIG_DEBUG_OUTPUT=y -#export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y +export CONFIG_DEBUG_OUTPUT=y +export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y CONFIG_COREBOOT_CONFIG=config/coreboot-qemu-tpm1.config CONFIG_LINUX_CONFIG=config/linux-qemu.config diff --git a/initrd/bin/gui-init b/initrd/bin/gui-init index a9bfc417..1434f570 100755 --- a/initrd/bin/gui-init +++ b/initrd/bin/gui-init @@ -151,12 +151,12 @@ prompt_update_checksums() generate_totp_hotp() { - tpm_password="$1" # May be empty, will prompt if needed and empty - TRACE "Under /bin/gui-init:generate_totp_hotp" + TRACE "Under /bin/gui-init:generate_totp_hotp" + tpm_owner_password="$1" # May be empty, will prompt if needed and empty if [ "$CONFIG_TPM" != "y" ] && [ -x /bin/hotp_verification ]; then echo "Generating new HOTP secret" /bin/seal-hotpkey - elif echo -e "Generating new TOTP secret...\n\n" && /bin/seal-totp "$BOARD_NAME" "$tpm_password"; then + 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 [ "$CONFIG_TOTP_SKIP_QRCODE" != y ]; then @@ -567,7 +567,7 @@ reset_tpm() return 1 fi - tpmr reset "$key_password" + tpmr reset "$tpm_owner_password" # now that the TPM is reset, remove invalid TPM counter files mount_boot @@ -577,7 +577,7 @@ reset_tpm() rm -f /boot/kexec_primhdl_hash.txt # create Heads TPM counter before any others - check_tpm_counter /boot/kexec_rollback.txt "" "$key_password" \ + check_tpm_counter /boot/kexec_rollback.txt "" "$tpm_owner_password" \ || die "Unable to find/create tpm counter" counter="$TPM_COUNTER" @@ -588,7 +588,7 @@ reset_tpm() || die "Unable to create rollback file" mount -o ro,remount /boot - generate_totp_hotp "$key_password" + generate_totp_hotp "$tpm_owner_password" else echo "Returning to the main menu" fi diff --git a/initrd/bin/kexec-seal-key b/initrd/bin/kexec-seal-key index 4e0cb321..70985d1c 100755 --- a/initrd/bin/kexec-seal-key +++ b/initrd/bin/kexec-seal-key @@ -136,13 +136,13 @@ tpmr calcfuturepcr 6 "/tmp/luksDump.txt" >>"$pcrf" tpmr pcrread -a 7 "$pcrf" DEBUG "TODO: REMOVE THIS: key_password=$key_password here" -DEBUG "TODO: REMOVE THIS: content of /tmp/secret/tpm_password: $(cat /tmp/secret/tpm_password) here" +DEBUG "TODO: REMOVE THIS: content of /tmp/secret/tpm_owner_password: $(cat /tmp/secret/tpm_owner_password) here" DO_WITH_DEBUG --mask-position 7 \ tpmr seal "$KEY_FILE" "$TPM_INDEX" 0,1,2,3,4,5,6,7 "$pcrf" \ "$TPM_SIZE" "$key_password" || { - shred -n 10 -z -u /tmp/secret/tpm_password 2>/dev/null + shred -n 10 -z -u /tmp/secret/tpm_owner_password 2>/dev/null : die "Unable to write TPM Disk Unlock Key to NVRAM" } diff --git a/initrd/bin/oem-factory-reset b/initrd/bin/oem-factory-reset index b9e7ce4b..1f44cc46 100755 --- a/initrd/bin/oem-factory-reset +++ b/initrd/bin/oem-factory-reset @@ -1114,16 +1114,16 @@ else fi if [ "$CONFIG_TPM" = "y" ]; then - tpm_password_changed=" + tpm_owner_password_changed=" TPM Owner Password: $TPM_PASS\n" else - tpm_password_changed="" + tpm_owner_password_changed="" fi ## Show to user current provisioned secrets prior of rebooting whiptail --msgbox " $luks_passphrase_changed - $tpm_password_changed + $tpm_owner_password_changed GPG Admin PIN: $ADMIN_PIN\n GPG User PIN: $USER_PIN\n\n" \ $HEIGHT $WIDTH --title "Provisioned secrets" @@ -1139,6 +1139,6 @@ whiptail --msgbox " # Clean LUKS secrets luks_secrets_cleanup unset luks_passphrase_changed -unset tpm_password_changed +unset tpm_owner_password_changed reboot diff --git a/initrd/bin/seal-totp b/initrd/bin/seal-totp index d3953ce4..9df8e85a 100755 --- a/initrd/bin/seal-totp +++ b/initrd/bin/seal-totp @@ -50,7 +50,7 @@ tpmr pcrread -a 7 "$pcrf" #Make sure we clear the TPM Owner Password from memory in case it failed to be used to seal TOTP tpmr seal "$TOTP_SECRET" "$TPM_NVRAM_SPACE" 0,1,2,3,4,7 "$pcrf" 312 "" "$TPM_PASSWORD" || { - shred -n 10 -z -u /tmp/secret/tpm_password 2>/dev/null + shred -n 10 -z -u /tmp/secret/tpm_owner_password 2>/dev/null : die "Unable to write sealed secret to NVRAM" } diff --git a/initrd/bin/tpm-reset b/initrd/bin/tpm-reset index f8b0c6a8..5049bea0 100755 --- a/initrd/bin/tpm-reset +++ b/initrd/bin/tpm-reset @@ -7,4 +7,4 @@ echo '*****' prompt_new_owner_password -tpmr reset "$key_password" +tpmr reset "$tpm_owner_password" diff --git a/initrd/bin/tpmr b/initrd/bin/tpmr index ddcf5e88..e64ec2bf 100755 --- a/initrd/bin/tpmr +++ b/initrd/bin/tpmr @@ -393,6 +393,7 @@ tpm2_seal() { tpm_password="$7" # Owner password - will prompt if needed and not empty # TPM Owner Password is always needed for TPM2. + DEBUG "TODO REMOVE THIS. tpm2_seal: pass=$pass tpm_password=$tpm_password" mkdir -p "$SECRET_DIR" bname="`basename $file`" @@ -442,12 +443,12 @@ tpm2_seal() { tpm2 load -Q -C "/tmp/$PRIMARY_HANDLE_FILE" \ -u "$SECRET_DIR/$bname.priv" -r "$SECRET_DIR/$bname.pub" \ -c "$SECRET_DIR/$bname.seal.ctx" - prompt_tpm_password + prompt_tpm_owner_password # remove possible data occupying this handle - tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_password")" \ + tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_owner_password")" \ -c "$handle" 2>/dev/null || true DO_WITH_DEBUG --mask-position 6 \ - tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_password")" \ + tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_owner_password")" \ -c "$SECRET_DIR/$bname.seal.ctx" "$handle" } tpm1_seal() { @@ -497,7 +498,7 @@ tpm1_seal() { tpm physicalpresence -s \ || warn "Unable to assert physical presence" - prompt_tpm_password + prompt_tpm_owner_password tpm nv_definespace -in "$index" -sz "$sealed_size" \ -pwdo "$tpm_password" -per 0 \ @@ -554,6 +555,8 @@ tpm2_unseal() { UNSEAL_PASS_SUFFIX="+$(tpm2_password_hex "$pass")" fi + DEBUG "TODO REMOVE THIS. tpm2_unseal: pass=$pass UNSEAL_PASS_SUFFIX=$UNSEAL_PASS_SUFFIX" + tpm2 unseal -Q -c "$handle" -p "session:$POLICY_SESSION$UNSEAL_PASS_SUFFIX" \ -S "/tmp/$ENC_SESSION_FILE" > "$file" } @@ -594,18 +597,18 @@ tpm1_unseal() { tpm2_reset() { TRACE "Under /bin/tpmr:tpm2_reset" - key_password="$1" + tpm_owner_password="$1" mkdir -p "$SECRET_DIR" # output TPM Owner Password key_password to a file to be reused in this boot session until recovery shell/reboot - DEBUG "Caching TPM Owner Password to $SECRET_DIR/tpm_password" - echo "$key_password" > "$SECRET_DIR/tpm_password" + DEBUG "Caching TPM Owner Password to $SECRET_DIR/tpm_owner_password" + echo -n "$tpm_owner_password" > "$SECRET_DIR/tpm_owner_password" tpm2 clear -c platform || warn "Unable to clear TPM on platform hierarchy" - tpm2 changeauth -c owner "$(tpm2_password_hex "$key_password")" - tpm2 changeauth -c endorsement "$(tpm2_password_hex "$key_password")" + tpm2 changeauth -c owner "$(tpm2_password_hex "$tpm_owner_password")" + tpm2 changeauth -c endorsement "$(tpm2_password_hex "$tpm_owner_password")" tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \ - -c "$SECRET_DIR/primary.ctx" -P "$(tpm2_password_hex "$key_password")" + -c "$SECRET_DIR/primary.ctx" -P "$(tpm2_password_hex "$tpm_owner_password")" tpm2 evictcontrol -C owner -c "$SECRET_DIR/primary.ctx" "$PRIMARY_HANDLE" \ - -P "$(tpm2_password_hex "$key_password")" + -P "$(tpm2_password_hex "$tpm_owner_password")" shred -u "$SECRET_DIR/primary.ctx" tpm2_startsession @@ -643,18 +646,18 @@ tpm2_reset() { } tpm1_reset() { TRACE "Under /bin/tpmr:tpm1_reset" - key_password="$1" + tpm_owner_password="$1" mkdir -p "$SECRET_DIR" - # output key_password to a file to be reused in this boot session until recovery shell/reboot - DEBUG "Caching TPM Owner Password to $SECRET_DIR/tpm_password" - echo "$key_password" > "$SECRET_DIR/tpm_password" + # output tpm_owner_password to a file to be reused in this boot session until recovery shell/reboot + DEBUG "Caching TPM Owner Password to $SECRET_DIR/tpm_owner_password" + echo -n "$tpm_owner_password" > "$SECRET_DIR/tpm_owner_password" # Make sure the TPM is ready to be reset tpm physicalpresence -s tpm physicalenable tpm physicalsetdeactivated -c tpm forceclear tpm physicalenable - tpm takeown -pwdo "$key_password" + tpm takeown -pwdo "$tpm_owner_password" # And now turn it all back on tpm physicalpresence -s diff --git a/initrd/etc/functions b/initrd/etc/functions index 1227c66c..5bea478d 100755 --- a/initrd/etc/functions +++ b/initrd/etc/functions @@ -192,28 +192,28 @@ list_usb_storage() { # 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() { - TRACE "Under /etc/functions:prompt_tpm_password" +prompt_tpm_owner_password() { + TRACE "Under /etc/functions:prompt_tpm_owner_password" #Caller might already have cached the password in tpm_password. If not, prompt for it and cache it externally - if [ -n "$tpm_password" ]; then - DEBUG "tpm_password variable already set by caller. Reusing" - DEBUG "TODO REMOVE THIS! tpm_password is $tpm_password here." + if [ -n "$tpm_owner_password" ]; then + DEBUG "tpm_owner_password variable already set by caller. Reusing" + DEBUG "TODO REMOVE THIS! tpm_owner_password is $tpm_owner_password here." return 0 - elif [ -s /tmp/secret/tpm_password ]; then - DEBUG "/tmp/secret/tpm_password already cached in file. Reusing" - tpm_password=$(cat /tmp/secret/tpm_password) - DEBUG "TODO REMOVE THIS! tpm_password is $tpm_password here." + elif [ -s /tmp/secret/tpm_owner_password ]; then + DEBUG "/tmp/secret/tpm_owner_password already cached in file. Reusing" + tpm_owner_password=$(cat /tmp/secret/tpm_owner_password) + DEBUG "TODO REMOVE THIS! tpm_owner_password is $tpm_owner_password here." return 0 fi - read -s -p "TPM Owner Password: " tpm_password + read -s -p "TPM Owner Password: " tpm_owner_password #TODO: This function is called for both owner and TPM sealing calls. We should probably have a different prompt for each echo # new line after password prompt # Cache the password externally to be reused by who needs it - DEBUG "Caching TPM Owner Password to /tmp/secret/tpm_password" + DEBUG "Caching TPM Owner Password to /tmp/secret/tpm_owner_password" mkdir -p /tmp/secret || die "Unable to create /tmp/secret" - echo "$key_password" >/tmp/secret/tpm_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 owner_password under /tmp/secret/tpm_owner_password" } # Prompt for a new owner password when resetting the TPM. Returned in @@ -221,26 +221,26 @@ prompt_tpm_password() { # the script will loop until this is met. prompt_new_owner_password() { TRACE "Under /etc/functions:prompt_new_owner_password" - local key_password2 - key_password=1 - key_password2=2 - while [ "$key_password" != "$key_password2" ] || [ "${#key_password}" -gt 32 ] || [ -z "$key_password" ]; do - read -s -p "New TPM Owner Password (2 words suggested, 1-32 characters max): " key_password + local tpm_owner_password2 + tpm_owner_password=1 + tpm_owner_password2=2 + while [ "$tpm_owner_password" != "$tpm_owner_password2" ] || [ "${#tpm_owner_password}" -gt 32 ] || [ -z "$tpm_owner_password" ]; do + read -s -p "New TPM Owner Password (2 words suggested, 1-32 characters max): " tpm_owner_password echo - read -s -p "Repeat chosen TPM Owner Password: " key_password2 + read -s -p "Repeat chosen TPM Owner Password: " tpm_owner_password2 echo - if [ "$key_password" != "$key_password2" ]; then + if [ "$tpm_owner_password" != "$tpm_owner_password2" ]; then echo "Passphrases entered do not match. Try again!" echo fi done # Cache the password externally to be reused by who needs it - DEBUG "Caching TPM Owner Password to /tmp/secret/tpm_password" + DEBUG "Caching TPM Owner Password to /tmp/secret/tpm_owner_password" mkdir -p /tmp/secret || die "Unable to create /tmp/secret" - echo "$key_password" >/tmp/secret/tpm_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" } check_tpm_counter() { @@ -253,7 +253,7 @@ check_tpm_counter() { TPM_COUNTER=$(grep counter- "$1" | cut -d- -f2) else warn "$1 does not exist; creating new TPM counter" - prompt_tpm_password + prompt_tpm_owner_password tpmr counter_create \ -pwdo "$tpm_password" \ -pwdc '' \