Skip to content

Commit dc4d1de

Browse files
committed
tpmr: added helper and enhanced reset routines with clearcontrol and error checks
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
1 parent e931ff1 commit dc4d1de

File tree

1 file changed

+94
-29
lines changed

1 file changed

+94
-29
lines changed

initrd/bin/tpmr

Lines changed: 94 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -657,22 +657,69 @@ tpm1_unseal() {
657657
-hk 40000000
658658
}
659659

660+
# cache_owner_password <password>
661+
# Store the TPM owner password in SECRET_DIR for the current boot session.
662+
# The original callers wrote the password to a file directly; the helper
663+
# provides identical behaviour and keeps the code DRY.
664+
cache_owner_password() {
665+
TRACE_FUNC
666+
mkdir -p "$SECRET_DIR"
667+
DEBUG "Caching TPM Owner Password to $SECRET_DIR/tpm_owner_password"
668+
printf '%s' "$1" >"$SECRET_DIR/tpm_owner_password"
669+
}
670+
671+
# Reset a TPM2 device for Heads. (Previous versions in origin/master put the
672+
# comment about caching directly in this function, which is preserved below.)
660673
tpm2_reset() {
661674
TRACE_FUNC
662675
tpm_owner_password="$1"
663-
mkdir -p "$SECRET_DIR"
664676
# output TPM Owner Password to a file to be reused in this boot session until recovery shell/reboot
665-
DEBUG "Caching TPM Owner Password to $SECRET_DIR/tpm_owner_password"
666-
echo -n "$tpm_owner_password" >"$SECRET_DIR/tpm_owner_password"
667-
DO_WITH_DEBUG tpm2 clear -c platform &>/dev/null
668-
DO_WITH_DEBUG tpm2 changeauth -c owner "$(tpm2_password_hex "$tpm_owner_password")" &>/dev/null
669-
DO_WITH_DEBUG tpm2 changeauth -c endorsement "$(tpm2_password_hex "$tpm_owner_password")" &>/dev/null
670-
DO_WITH_DEBUG tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \
671-
-c "$SECRET_DIR/primary.ctx" -P "$(tpm2_password_hex "$tpm_owner_password")" &>/dev/null
672-
DO_WITH_DEBUG tpm2 evictcontrol -C owner -c "$SECRET_DIR/primary.ctx" "$PRIMARY_HANDLE" \
673-
-P "$(tpm2_password_hex "$tpm_owner_password")" &>/dev/null
674-
shred -u "$SECRET_DIR/primary.ctx" &>/dev/null
675-
DO_WITH_DEBUG tpm2_startsession &>/dev/null
677+
# (using cache_owner_password() to avoid duplicating the write logic)
678+
cache_owner_password "$tpm_owner_password"
679+
680+
# 1. Ensure TPM2_Clear is allowed: clear disableClear via platform hierarchy.
681+
# This makes future clears (Owner/Lockout) possible and avoids a 'no clear' stuck state.
682+
if ! DO_WITH_DEBUG tpm2 clearcontrol -C platform c >/dev/null 2>&1; then
683+
LOG "tpm2_reset: unable to clear disableClear via platform hierarchy"
684+
return 1
685+
fi
686+
687+
# 2. Factory-style clear via platform hierarchy.
688+
# This destroys all previous owner/endorsement/lockout auth and user-created objects.
689+
if ! DO_WITH_DEBUG tpm2 clear -c platform >/dev/null 2>&1; then
690+
LOG "tpm2_reset: TPM2_Clear via platform hierarchy failed; TPM not reset"
691+
return 1
692+
fi
693+
694+
# 3. Re-own the TPM for Heads: set new owner and endorsement auth.
695+
if ! DO_WITH_DEBUG tpm2 changeauth -c owner "$(tpm2_password_hex "$tpm_owner_password")" >/dev/null 2>&1; then
696+
LOG "tpm2_reset: unable to set owner auth"
697+
return 1
698+
fi
699+
700+
if ! DO_WITH_DEBUG tpm2 changeauth -c endorsement "$(tpm2_password_hex "$tpm_owner_password")" >/dev/null 2>&1; then
701+
LOG "tpm2_reset: unable to set endorsement auth"
702+
return 1
703+
fi
704+
705+
# 4. Create and persist Heads primary key.
706+
if ! DO_WITH_DEBUG tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \
707+
-c "$SECRET_DIR/primary.ctx" \
708+
-P "$(tpm2_password_hex "$tpm_owner_password")" >/dev/null 2>&1; then
709+
LOG "tpm2_reset: unable to create primary"
710+
return 1
711+
fi
712+
713+
if ! DO_WITH_DEBUG tpm2 evictcontrol -C owner -c "$SECRET_DIR/primary.ctx" "$PRIMARY_HANDLE" \
714+
-P "$(tpm2_password_hex "$tpm_owner_password")" >/dev/null 2>&1; then
715+
LOG "tpm2_reset: unable to persist primary"
716+
shred -u "$SECRET_DIR/primary.ctx" >/dev/null 2>&1
717+
return 1
718+
fi
719+
720+
shred -u "$SECRET_DIR/primary.ctx" >/dev/null 2>&1
721+
722+
DO_WITH_DEBUG tpm2_startsession >/dev/null 2>&1
676723

677724
# Set the dictionary attack parameters. TPM2 defaults vary widely, we
678725
# want consistent behavior on any TPM.
@@ -695,36 +742,54 @@ tpm2_reset() {
695742
--max-tries=10 \
696743
--recovery-time=3600 \
697744
--lockout-recovery-time=0 \
698-
--auth="session:$ENC_SESSION_FILE" >/dev/null 2>&1 || LOG "Unable to set dictionary lockout parameters"
745+
--auth="session:$ENC_SESSION_FILE" >/dev/null 2>&1 \
746+
|| LOG "tpm2_reset: unable to set dictionary lockout parameters"
699747

748+
# 6. Set a random DA lockout password so DA reset requires another TPM reset.
700749
# Set a random DA lockout password, so the DA lockout can't be cleared
701750
# with a password. Heads doesn't offer dictionary attach reset, instead
702751
# the TPM can be reset and new secrets sealed.
703752
#
704753
# The default lockout password is empty, so we must set this, and we
705754
# don't need to provide any auth (use the default empty password).
706755
tpm2 changeauth -Q -c lockout \
707-
"hex:$(dd if=/dev/urandom bs=32 count=1 status=none 2>/dev/null | xxd -p | tr -d ' \n')" >/dev/null 2>&1 || LOG "Unable to set lockout password"
756+
"hex:$(dd if=/dev/urandom bs=32 count=1 status=none 2>/dev/null | xxd -p | tr -d ' \n')" \
757+
>/dev/null 2>&1 || LOG "tpm2_reset: unable to set lockout password"
708758
}
759+
709760
tpm1_reset() {
710761
TRACE_FUNC
711762
tpm_owner_password="$1"
712-
mkdir -p "$SECRET_DIR"
713763
# output tpm_owner_password to a file to be reused in this boot session until recovery shell/reboot
714-
DEBUG "Caching TPM Owner Password to $SECRET_DIR/tpm_owner_password"
715-
echo -n "$tpm_owner_password" >"$SECRET_DIR/tpm_owner_password"
716-
# Make sure the TPM is ready to be reset
717-
DO_WITH_DEBUG tpm physicalpresence -s &>/dev/null
718-
DO_WITH_DEBUG tpm physicalenable &>/dev/null
719-
DO_WITH_DEBUG tpm physicalsetdeactivated -c &>/dev/null
720-
DO_WITH_DEBUG tpm forceclear &>/dev/null
721-
DO_WITH_DEBUG tpm physicalenable &>/dev/null
722-
DO_WITH_DEBUG --mask-position 3 tpm takeown -pwdo "$tpm_owner_password" &>/dev/null
723-
724-
# And now turn it all back on
725-
DO_WITH_DEBUG tpm physicalpresence -s &>/dev/null
726-
DO_WITH_DEBUG tpm physicalenable &>/dev/null
727-
DO_WITH_DEBUG tpm physicalsetdeactivated -c &>/dev/null
764+
# (using cache_owner_password() under the hood)
765+
cache_owner_password "$tpm_owner_password"
766+
767+
# 1. Request physical presence and enable TPM.
768+
DO_WITH_DEBUG tpm physicalpresence -s >/dev/null 2>&1 || LOG "tpm1_reset: unable to set physical presence"
769+
DO_WITH_DEBUG tpm physicalenable >/dev/null 2>&1 || LOG "tpm1_reset: unable to physicalenable"
770+
771+
# Ensure TPM is not deactivated.
772+
DO_WITH_DEBUG tpm physicalsetdeactivated -c >/dev/null 2>&1 || LOG "tpm1_reset: unable to clear deactivated state"
773+
774+
# 2. Force clear: this is the critical full reset for TPM 1.2.
775+
if ! DO_WITH_DEBUG tpm forceclear >/dev/null 2>&1; then
776+
LOG "tpm1_reset: tpm forceclear failed; TPM not reset (firmware policy or state blocking clear)"
777+
return 1
778+
fi
779+
780+
# Re-enable after clear (some platforms require this).
781+
DO_WITH_DEBUG tpm physicalenable >/dev/null 2>&1 || LOG "tpm1_reset: unable to physicalenable after clear"
782+
783+
# 3. Take ownership with the new TPM owner password.
784+
if ! DO_WITH_DEBUG --mask-position 3 tpm takeown -pwdo "$tpm_owner_password" >/dev/null 2>&1; then
785+
LOG "tpm1_reset: tpm takeown failed after forceclear"
786+
return 1
787+
fi
788+
789+
# 4. Leave TPM enabled, present, and not deactivated.
790+
DO_WITH_DEBUG tpm physicalpresence -s >/dev/null 2>&1 || LOG "tpm1_reset: unable to set physical presence (final)"
791+
DO_WITH_DEBUG tpm physicalenable >/dev/null 2>&1 || LOG "tpm1_reset: unable to physicalenable (final)"
792+
DO_WITH_DEBUG tpm physicalsetdeactivated -c >/dev/null 2>&1 || LOG "tpm1_reset: unable to clear deactivated state (final)"
728793
}
729794

730795
# Perform final cleanup before boot and lock the platform heirarchy.

0 commit comments

Comments
 (0)