@@ -354,7 +354,7 @@ tpm2_counter_inc() {
354354 rm -f " $tmp_err_file "
355355 shred -n 10 -z -u /tmp/secret/tpm_owner_passphrase 2> /dev/null || true
356356 DEBUG " tpm2_counter_inc attempt $attempt failed. Stderr: $tmp_err_content "
357- if ! echo " $tmp_err_content " | grep -qiE ' authorization|auth|bad|permission|0x98e|0x149' ; then
357+ if ! echo " $tmp_err_content " | grep -qiE ' authorization|auth|bad|permission|defend| 0x98e|0x149' ; then
358358 DIE " Can't increment TPM counter for $index , access denied."
359359 fi
360360 WARN " Authentication failed, retrying..."
@@ -370,16 +370,26 @@ tpm2_counter_inc() {
370370# Caching: prompt_tpm_owner_password reuses cached passphrase if available.
371371# On auth failure the cache is shredded; next prompt will ask the user.
372372#
373+ # Error stream selection:
374+ # TPM1 (tpmtotp): errors go to stdout via printf() — capture stdout+stderr
375+ # TPM2 (tpm2-tools): errors go to stderr via LOG_ERR() — capture stderr only
376+ #
377+ # Auth detection grep patterns:
378+ # English words — TPM1 (TPM_GetErrMsg returns "Authentication failed...")
379+ # — TPM2 (tpm2-tools LOG_ERR returns "TPM2_RC_AUTH_FAIL...")
380+ # defend — TPM1 "Defend lock running" (TPM_DEFEND_LOCK_RUNNING)
381+ # 0x98e, 0x149 — TPM2 raw hex codes (TPM2_RC_AUTH_FAIL, TPM2_RC_NV_AUTHORIZATION)
382+ #
373383# Usage: _tpm_auth_retry <label> <error_stream> <tpm_type> <pw_flag> <cmd...>
374384# <label>: short name for debug (e.g. "counter_create")
375- # <error_stream>: "stdout" (TPM1) or "stderr" (TPM2)
385+ # <error_stream>: "stdout" (TPM1: tpmtotp printf ) or "stderr" (TPM2: tpm2-tools LOG_ERR )
376386# <tpm_type>: "tpm1" or "tpm2"
377387# <pw_flag>: passphrase flag for TPM1 (-pwdo or -pwdc), ignored for TPM2
378388# <cmd...>: the tpm command and its non-auth arguments
379389#
380390# Exit codes:
381391# 0: success
382- # 1: non-auth error (e.g., "out of resources" 0x15) — caller should check
392+ # 1: non-auth error (e.g., TPM1 "out of resources" 0x15) — caller should check
383393_tpm_auth_retry () {
384394 local label=" $1 " error_stream=" $2 " tpm_type=" $3 " pw_flag=" $4 "
385395 shift 4
@@ -417,7 +427,7 @@ _tpm_auth_retry() {
417427 DEBUG " _tpm_auth_retry $label attempt $attempt failed: $out_content "
418428 rm -f " $tmp_file "
419429 shred -n 10 -z -u /tmp/secret/tpm_owner_passphrase 2> /dev/null || true
420- if echo " $out_content " | grep -qiE ' authorization|auth|bad|permission' ; then
430+ if echo " $out_content " | grep -qiE ' authorization|auth|bad|permission|defend|0x98e|0x149 ' ; then
421431 WARN " $label failed (bad passphrase?). Retrying..."
422432 else
423433 # Non-auth error (e.g., out of resources 0x15)
@@ -641,7 +651,7 @@ tpm2_seal() {
641651 rm -f " $tmp_err_file "
642652 DEBUG " Failed attempt $attempt to write sealed secret to NVRAM from tpm2_seal. Stderr: $tmp_err_content "
643653 shred -n 10 -z -u /tmp/secret/tpm_owner_passphrase 2> /dev/null || true
644- if echo " $tmp_err_content " | grep -qiE ' authorization|auth|bad|permission' ; then
654+ if echo " $tmp_err_content " | grep -qiE ' authorization|auth|bad|permission|defend|0x98e|0x149 ' ; then
645655 if [ " $attempt " -ge 3 ]; then
646656 DIE " Unable to write sealed secret to TPM NVRAM after 3 attempts. Reset the TPM and try again."
647657 fi
@@ -759,7 +769,7 @@ tpm1_seal() {
759769 rm -f " $tmp_def_out "
760770 DEBUG " tpm1_seal nv_definespace failed (attempt $attempt ): $def_out_content "
761771 # If auth failure, retry after re-prompt; otherwise bail out.
762- if echo " $def_out_content " | grep -qiE ' authorization|auth|bad|permission' ; then
772+ if echo " $def_out_content " | grep -qiE ' authorization|auth|bad|permission|defend ' ; then
763773 shred -n 10 -z -u /tmp/secret/tpm_owner_passphrase 2> /dev/null || true
764774 WARN " nv_definespace failed (bad passphrase?). Retrying..."
765775 continue
@@ -788,7 +798,7 @@ tpm1_seal() {
788798 fi
789799 DEBUG " tpm1_seal nv_writevalue(post-define) output: $tmp_out_content "
790800 shred -n 10 -z -u /tmp/secret/tpm_owner_passphrase 2> /dev/null || true
791- if echo " $tmp_out_content " | grep -qiE ' authorization|auth|bad|permission' ; then
801+ if echo " $tmp_out_content " | grep -qiE ' authorization|auth|bad|permission|defend ' ; then
792802 if [ " $attempt " -ge 3 ]; then
793803 DIE " Unable to write sealed secret to TPM NVRAM after 3 attempts"
794804 fi
@@ -1075,9 +1085,34 @@ tpm1_reset() {
10751085 DO_WITH_DEBUG tpm physicalenable > /dev/null 2>&1 || LOG " tpm1_reset: unable to physicalenable after clear"
10761086
10771087 # 3. Take ownership with the new TPM owner passphrase.
1078- if ! DO_WITH_DEBUG --mask-position 3 tpm takeown -pwdo " $tpm_owner_passphrase " > /dev/null 2>&1 ; then
1079- LOG " tpm1_reset: tpm takeown failed after forceclear"
1080- return 1
1088+ # TPM_DEFEND_LOCK_RUNNING is a standard TPM 1.2 error raised after
1089+ # too many failed authorization attempts (see tpm_error.h). The TPM
1090+ # enters a time-out period and refuses all authorization operations —
1091+ # including takeown, even after a successful forceclear (forceclear
1092+ # clears the owner but not the dictionary attack counter on some
1093+ # implementations).
1094+ # TPM_ResetLockValue requires owner auth, which does not exist after
1095+ # forceclear, so we cannot call it. Cycle physical presence
1096+ # (physicaldisable + physicalenable) to reset the TPM state machine
1097+ # on chips that honour software presence. If the lock persists,
1098+ # only a full AC power cycle (not just reboot) will clear it.
1099+ local takeown_rc takeown_out
1100+ takeown_out=" $( DO_WITH_DEBUG --mask-position 3 tpm takeown -pwdo " $tpm_owner_passphrase " 2>&1 ) " && takeown_rc=0 || takeown_rc=$?
1101+ if [ $takeown_rc -ne 0 ]; then
1102+ if echo " $takeown_out " | grep -qi " defend lock" ; then
1103+ LOG " tpm1_reset: defend lock detected after forceclear — cycling physical presence to clear"
1104+ DO_WITH_DEBUG tpm physicaldisable > /dev/null 2>&1 || true
1105+ DO_WITH_DEBUG tpm physicalenable > /dev/null 2>&1 || true
1106+ DO_WITH_DEBUG tpm physicalpresence -s > /dev/null 2>&1 || true
1107+ DO_WITH_DEBUG tpm physicalsetdeactivated -c > /dev/null 2>&1 || true
1108+ if ! DO_WITH_DEBUG --mask-position 3 tpm takeown -pwdo " $tpm_owner_passphrase " > /dev/null 2>&1 ; then
1109+ LOG " tpm1_reset: tpm takeown still failed after defend lock recovery"
1110+ return 1
1111+ fi
1112+ else
1113+ LOG " tpm1_reset: tpm takeown failed after forceclear"
1114+ return 1
1115+ fi
10811116 fi
10821117
10831118 # 4. Leave TPM enabled, present, and not deactivated.
0 commit comments