@@ -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.)
660673tpm2_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+
709760tpm1_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