@@ -15,6 +15,7 @@ export BG_COLOR_MAIN_MENU="normal"
1515# reset when we reach the main menu so the user can retry from the main menu and
1616# # see errors again.
1717skip_to_menu=" false"
18+ INTEGRITY_GATE_REQUIRED=" n"
1819
1920mount_boot () {
2021 TRACE_FUNC
@@ -115,23 +116,44 @@ verify_global_hashes() {
115116 less /tmp/hash_output_mismatches
116117 # move outdated hash mismatch list
117118 mv /tmp/hash_output_mismatches /tmp/hash_output_mismatch_old
118- TEXT=" Would you like to update your checksums now?"
119+ TEXT=" ${CHANGED_FILES_COUNT} files failed the verification process.\n\nThis could indicate a compromise!\n\nWould you like to investigate discrepancies or update your checksums now?"
119120 else
120- TEXT=" The following files failed the verification process:\n\n${CHANGED_FILES} \n\nThis could indicate a compromise!\n\nWould you like to update your checksums now?"
121+ TEXT=" The following files failed the verification process:\n\n${CHANGED_FILES} \n\nThis could indicate a compromise!\n\nWould you like to investigate discrepancies or update your checksums now?"
121122 fi
122123 fi
123124
124- if (whiptail_error --title ' ERROR: Boot Hash Mismatch' --yesno " $TEXT " 0 80); then
125- if update_checksums; then
126- BG_COLOR_MAIN_MENU=" normal"
127- return 0
128- else
129- whiptail_error --title ' ERROR' \
130- --msgbox " Failed to update checksums / sign default config" 0 80
131- fi
132- fi
133- BG_COLOR_MAIN_MENU=" error"
134- return 1
125+ while true ; do
126+ TRACE_FUNC
127+ whiptail_error --title ' ERROR: Boot Hash Mismatch' \
128+ --menu " $TEXT \n\nChoose an action:" 0 80 8 \
129+ ' i' ' Investigate discrepancies -->' \
130+ ' u' ' Update checksums now' \
131+ ' m' ' Return to main menu' \
132+ 2> /tmp/whiptail || {
133+ BG_COLOR_MAIN_MENU=" error"
134+ return 1
135+ }
136+
137+ option=$( cat /tmp/whiptail)
138+ case " $option " in
139+ i)
140+ investigate_integrity_discrepancies
141+ ;;
142+ u)
143+ if update_checksums; then
144+ BG_COLOR_MAIN_MENU=" normal"
145+ return 0
146+ else
147+ whiptail_error --title ' ERROR' \
148+ --msgbox " Failed to update checksums / sign default config" 0 80
149+ fi
150+ ;;
151+ m | * )
152+ BG_COLOR_MAIN_MENU=" error"
153+ return 1
154+ ;;
155+ esac
156+ done
135157 fi
136158}
137159
@@ -146,6 +168,63 @@ prompt_update_checksums() {
146168 fi
147169}
148170
171+ gate_reseal_with_integrity_report () {
172+ TRACE_FUNC
173+ local token_ok=" y"
174+
175+ if [ " $INTEGRITY_GATE_REQUIRED " != " y" ]; then
176+ DEBUG " Skipping integrity gate: no TOTP/HOTP failure context"
177+ return 0
178+ fi
179+
180+ INTEGRITY_REPORT_HASH_STATE=" UNKNOWN"
181+ report_integrity_measurements
182+ local report_rc=$?
183+ DEBUG " gate_reseal_with_integrity_report: report_integrity_measurements rc=$report_rc "
184+ DEBUG " gate_reseal_with_integrity_report: INTEGRITY_REPORT_HASH_STATE=$INTEGRITY_REPORT_HASH_STATE "
185+ if [ " $INTEGRITY_REPORT_HASH_STATE " != " OK" ]; then
186+ DEBUG " returned from integrity report, now running investigation"
187+ if ! investigate_integrity_discrepancies; then
188+ DEBUG " investigation indicated problem, aborting gate"
189+ return 1
190+ fi
191+
192+ DEBUG " gate_reseal_with_integrity_report: about to verify detached signature"
193+ DEBUG " ls -l /boot/kexec.sig: $( ls -l /boot/kexec.sig 2> /dev/null || echo missing) "
194+ if ! detached_kexec_signature_valid /boot; then
195+ DEBUG " detached_kexec_signature_valid failed"
196+ whiptail_error --title ' ERROR: Signature Verification Failed' \
197+ --msgbox " Cannot proceed with sealing new secrets because /boot/kexec.sig could not be verified with your current keyring.\n\nTreat /boot as untrusted and recover ownership first." 0 80
198+ return 1
199+ fi
200+ else
201+ DEBUG " gate_reseal_with_integrity_report: integrity is OK, skipping investigation and detached signature verification"
202+ fi
203+
204+ if [ -x /bin/hotp_verification ]; then
205+ token_ok=" n"
206+ while [ " $token_ok " != " y" ]; do
207+ enable_usb
208+ if hotp_verification info > /dev/null 2>&1 ; then
209+ token_ok=" y"
210+ break
211+ fi
212+ if ! whiptail_warning --title " USB Security Dongle Required" \
213+ --yes-button " Retry" --no-button " Abort" \
214+ --yesno " Your USB security dongle must be present before sealing new secrets.\n\nInsert the dongle and choose Retry, or Abort." 0 80; then
215+ return 1
216+ fi
217+ done
218+ fi
219+
220+ if ! whiptail_warning --title ' Integrity Gate Passed' \
221+ --yesno " Integrity checks completed.\n\nProceed with TOTP/HOTP reseal action?" 0 80; then
222+ return 1
223+ fi
224+ INTEGRITY_GATE_REQUIRED=" n"
225+ return 0
226+ }
227+
149228generate_totp_hotp () {
150229 TRACE_FUNC
151230 tpm_owner_password=" $1 " # May be empty, will prompt if needed and empty
@@ -216,16 +295,14 @@ update_totp() {
216295 if [ " $CONFIG_TPM " != " y" ]; then
217296 TOTP=" NO TPM"
218297 else
219- TOTP=$( unseal-totp)
298+ TOTP=$( HEADS_NONFATAL_UNSEAL=y unseal-totp)
220299 if [ $? -ne 0 ]; then
300+ INTEGRITY_GATE_REQUIRED=" y"
221301 BG_COLOR_MAIN_MENU=" error"
222302 if [ " $skip_to_menu " = " true" ]; then
223303 return 1 # Already asked to skip to menu from a prior error
224304 fi
225305
226- DEBUG " CONFIG_TPM: $CONFIG_TPM "
227- DEBUG " CONFIG_TPM2_TOOLS: $CONFIG_TPM2_TOOLS "
228- DEBUG " Show PCRs"
229306 DEBUG " $( pcrs) "
230307
231308 whiptail_error --title " ERROR: TOTP Generation Failed!" \
@@ -245,7 +322,7 @@ update_totp() {
245322 option=$( cat /tmp/whiptail)
246323 case " $option " in
247324 g)
248- if (whiptail_warning --title ' Generate new TOTP/HOTP secret' \
325+ if gate_reseal_with_integrity_report && (whiptail_warning --title ' Generate new TOTP/HOTP secret' \
249326 --yesno " This will erase your old secret and replace it with a new one!\n\nDo you want to proceed?" 0 80); then
250327 if generate_totp_hotp && update_totp && BG_COLOR_MAIN_MENU=" normal" ; then
251328 reseal_tpm_disk_decryption_key || prompt_missing_gpg_key_action
@@ -257,14 +334,16 @@ update_totp() {
257334 return 1
258335 ;;
259336 p)
260- if reset_tpm && update_totp && BG_COLOR_MAIN_MENU=" normal" ; then
337+ if gate_reseal_with_integrity_report && reset_tpm && update_totp && BG_COLOR_MAIN_MENU=" normal" ; then
261338 reseal_tpm_disk_decryption_key || prompt_missing_gpg_key_action
262339 fi
263340 ;;
264341 x)
265342 recovery " User requested recovery shell"
266343 ;;
267344 esac
345+ else
346+ INTEGRITY_GATE_REQUIRED=" n"
268347 fi
269348 fi
270349}
@@ -286,7 +365,7 @@ update_hotp() {
286365 return
287366 fi
288367 fi
289- HOTP=$( unseal-hotp)
368+ HOTP=$( HEADS_NONFATAL_UNSEAL=y unseal-hotp)
290369 # Don't output HOTP codes to screen, so as to make replay attacks harder
291370 hotp_verification check " $HOTP "
292371 case " $? " in
@@ -308,9 +387,7 @@ update_hotp() {
308387 fi
309388
310389 if [[ " $HOTP " = " Invalid code" ]]; then
311- # Do not propose to generate a new secret if there is no /boot/kexec_hotp_counter
312- # tpm unseal succeeded: so the sealed secret is correct: we should propose to reset TPM if not already
313- # Here: the OS was most probably reinstalled since TPM can still unseal the secret
390+ INTEGRITY_GATE_REQUIRED=" y"
314391 whiptail_error --title " ERROR: HOTP Validation Failed!" \
315392 --menu " ERROR: $CONFIG_BRAND_NAME couldn't validate the HOTP code.\n\nIf you just reflashed your BIOS, you should generate a new TOTP/HOTP secret.\n\nIf you have not just reflashed your BIOS, THIS COULD INDICATE TAMPERING!\n\nHow would you like to proceed?" 0 80 4 \
316393 ' g' ' Generate new TOTP/HOTP secret' \
@@ -321,9 +398,11 @@ update_hotp() {
321398 option=$( cat /tmp/whiptail)
322399 case " $option " in
323400 g)
324- if (whiptail_warning --title ' Generate new TOTP/HOTP secret' \
401+ if gate_reseal_with_integrity_report && (whiptail_warning --title ' Generate new TOTP/HOTP secret' \
325402 --yesno " This will erase your old secret and replace it with a new one!\n\nDo you want to proceed?" 0 80); then
326- if generate_totp_hotp && BG_COLOR_MAIN_MENU=" normal" ; then
403+ if generate_totp_hotp; then
404+ update_totp || true
405+ BG_COLOR_MAIN_MENU=" normal"
327406 reseal_tpm_disk_decryption_key || prompt_missing_gpg_key_action
328407 fi
329408 fi
@@ -335,6 +414,8 @@ update_hotp() {
335414 recovery " User requested recovery shell"
336415 ;;
337416 esac
417+ else
418+ INTEGRITY_GATE_REQUIRED=" n"
338419 fi
339420}
340421
@@ -449,6 +530,7 @@ show_options_menu() {
449530 --menu " " 0 80 10 \
450531 ' b' ' Boot Options -->' \
451532 ' t' ' TPM/TOTP/HOTP Options -->' \
533+ ' i' ' Investigate integrity discrepancies -->' \
452534 ' h' ' Change system time' \
453535 ' u' ' Update checksums and sign all files in /boot' \
454536 ' c' ' Change configuration settings -->' \
@@ -470,6 +552,9 @@ show_options_menu() {
470552 t)
471553 show_tpm_totp_hotp_options_menu
472554 ;;
555+ i)
556+ investigate_integrity_discrepancies
557+ ;;
473558 h)
474559 change-time.sh
475560 ;;
@@ -545,12 +630,12 @@ show_tpm_totp_hotp_options_menu() {
545630 option=$( cat /tmp/whiptail)
546631 case " $option " in
547632 g)
548- if generate_totp_hotp; then
633+ if gate_reseal_with_integrity_report && generate_totp_hotp; then
549634 reseal_tpm_disk_decryption_key || prompt_missing_gpg_key_action
550635 fi
551636 ;;
552637 r)
553- if reset_tpm; then
638+ if gate_reseal_with_integrity_report && reset_tpm; then
554639 reseal_tpm_disk_decryption_key || prompt_missing_gpg_key_action
555640 fi
556641 ;;
@@ -616,19 +701,24 @@ reset_tpm() {
616701 GPG_KEY_COUNT=$( gpg -k 2> /dev/null | wc -l)
617702 if [ " $GPG_KEY_COUNT " -eq 0 ]; then
618703 prompt_missing_gpg_key_action
619- elif (whiptail --title ' TPM Reset Successfully ' \
620- --yesno " Would you like to update the checksums and sign all of the files in /boot?\n\nYou will need your GPG key to continue and this will modify your disk.\n\nOtherwise the system will reboot immediately. " 0 80) ; then
704+ else
705+ DEBUG " TPM reset successful: updating checksums/signatures without additional confirmation "
621706 if ! update_checksums; then
622707 whiptail_error --title ' ERROR' \
623708 --msgbox " Failed to update checksums / sign default config" 0 80
709+ return 1
624710 fi
625- else
626- warn " TPM reset successful, but user chose not to update+sign /boot checksums. Rebooting"
627- reboot
628711 fi
629712 mount -o ro,remount /boot
630713
631- generate_totp_hotp " $tpm_owner_password "
714+ if ! generate_totp_hotp " $tpm_owner_password " ; then
715+ return 1
716+ fi
717+
718+ if [ -s /boot/kexec_key_devices.txt ] || [ -s /boot/kexec_key_lvm.txt ]; then
719+ DEBUG " TPM reset successful: auto-resealing TPM Disk Unlock Key (DUK)"
720+ reseal_tpm_disk_decryption_key || prompt_missing_gpg_key_action
721+ fi
632722 else
633723 echo " Returning to the main menu"
634724 fi
0 commit comments