From 3cca3bebb3caa150c382b2ea49bebbf957abfb07 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 27 Nov 2024 11:54:58 -0500 Subject: [PATCH 01/11] qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet board: addition of board containing 'export CONFIG_QUIET_MODE=y' for output comparison between debug, prod and quiet mode Signed-off-by: Thierry Laurion --- ...oot-fbwhiptail-tpm2-hotp-prod_quiet.config | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 boards/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet.config diff --git a/boards/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet.config b/boards/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet.config new file mode 100644 index 000000000..cf8491f58 --- /dev/null +++ b/boards/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet/qemu-coreboot-fbwhiptail-tpm2-hotp-prod_quiet.config @@ -0,0 +1,99 @@ +# Configuration for building a coreboot ROM that works in +# the qemu emulator in graphical mode thanks to FBWhiptail +# This version requires a supported HOTP Security dongle (Nitrokey Pro/Storage or Librem Key) +# +# TPM can be used with a qemu software TPM (TIS, 2.0). +export CONFIG_COREBOOT=y +export CONFIG_COREBOOT_VERSION=24.02.01 +export CONFIG_LINUX_VERSION=6.1.8 + +CONFIG_COREBOOT_CONFIG=config/coreboot-qemu-tpm2-prod.config +CONFIG_LINUX_CONFIG=config/linux-qemu.config + +#Enable only one RESTRICTED/BASIC boot modes below to test them manually (we cannot inject config under QEMU (no internal flashing) +#export CONFIG_RESTRICTED_BOOT=y +#export CONFIG_BASIC=y + +#Enable HAVE_GPG_KEY_BACKUP to test GPG key backup drive (we cannot inject config under QEMU (no internal flashing)) +#export CONFIG_HAVE_GPG_KEY_BACKUP=y + +#Enable DEBUG output +#export CONFIG_DEBUG_OUTPUT=y +#export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y +#Enable TPM2 pcap output under /tmp +#export CONFIG_TPM2_CAPTURE_PCAP=y + +#Enable quiet mode: technical information logged under /tmp/debug.log +export CONFIG_QUIET_MODE=y + +#On-demand hardware support (modules.cpio) +CONFIG_LINUX_USB=y +CONFIG_LINUX_E1000=y +#CONFIG_MOBILE_TETHERING=y +#Runtime on-demand additional hardware support (modules.cpio) +export CONFIG_LINUX_USB_COMPANION_CONTROLLER=y + + + +#Modules packed into tools.cpio +ifeq "$(CONFIG_UROOT)" "y" +CONFIG_BUSYBOX=n +else +#Modules packed into tools.cpio +CONFIG_CRYPTSETUP2=y +CONFIG_FLASHPROG=y +CONFIG_FLASHTOOLS=y +CONFIG_GPG2=y +CONFIG_KEXEC=y +CONFIG_UTIL_LINUX=y +CONFIG_LVM2=y +CONFIG_MBEDTLS=y +CONFIG_PCIUTILS=y +#Runtime tools to write to MSR +CONFIG_MSRTOOLS=y +#Remote attestation support +# TPM2 requirements +CONFIG_TPM2_TSS=y +CONFIG_OPENSSL=y +#Remote Attestation common tools +CONFIG_POPT=y +CONFIG_QRENCODE=y +CONFIG_TPMTOTP=y +#HOTP based remote attestation for supported USB Security dongle +#With/Without TPM support +CONFIG_HOTPKEY=y +#Nitrokey Storage admin tool (deprecated) +#CONFIG_NKSTORECLI=n +#GUI Support +#Console based Whiptail support(Console based, no FB): +#CONFIG_SLANG=y +#CONFIG_NEWT=y +#FBWhiptail based (Graphical): +CONFIG_CAIRO=y +CONFIG_FBWHIPTAIL=y +#Additional tools (tools.cpio): +#SSH server (requires ethernet drivers, eg: CONFIG_LINUX_E1000E) +CONFIG_DROPBEAR=y +endif + +#Runtime configuration +#Automatically boot if HOTP is valid +export CONFIG_AUTO_BOOT_TIMEOUT=5 +#TPM2 requirements +export CONFIG_TPM2_TOOLS=y +export CONFIG_PRIMARY_KEY_TYPE=ecc +#TPM1 requirements +#export CONFIG_TPM=y +export CONFIG_BOOTSCRIPT=/bin/gui-init +#text-based original init: +#export CONFIG_BOOTSCRIPT=/bin/generic-init +export CONFIG_BOOT_REQ_HASH=n +export CONFIG_BOOT_REQ_ROLLBACK=n +export CONFIG_BOOT_RECOVERY_SERIAL="/dev/ttyS0" +export CONFIG_BOOT_KERNEL_ADD="console=ttyS0 console=tty systemd.zram=0" +export CONFIG_BOOT_KERNEL_REMOVE="quiet rhgb splash" +export CONFIG_BOARD_NAME="qemu-coreboot-fbwhiptail-tpm2-hotp" +#export CONFIG_FLASH_OPTIONS="flashprog --progress --programmer internal" +export CONFIG_AUTO_BOOT_TIMEOUT=5 + +BOARD_TARGETS := qemu From 8594f3af51bfad2a1f8761cfc1d1deadfeb2dc9c Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 27 Nov 2024 10:38:37 -0500 Subject: [PATCH 02/11] initrd bin/* sbin/insmod + /etc/ash_functions: TPM extend operations now all passed to LOG (quiet mode doesn't show them and logs them to /tmp/debug.log) Signed-off-by: Thierry Laurion --- initrd/bin/cbfs-init | 6 ++---- initrd/bin/kexec-insert-key | 2 +- initrd/bin/kexec-select-boot | 2 +- initrd/bin/qubes-measure-luks | 2 +- initrd/bin/tpmr | 6 +++--- initrd/etc/ash_functions | 13 +++++++++++-- initrd/sbin/insmod | 6 +++--- 7 files changed, 22 insertions(+), 15 deletions(-) diff --git a/initrd/bin/cbfs-init b/initrd/bin/cbfs-init index c54991f41..d89effe5e 100755 --- a/initrd/bin/cbfs-init +++ b/initrd/bin/cbfs-init @@ -17,12 +17,12 @@ for cbfsname in `echo $cbfsfiles`; do if [ ! -z "$filename" ]; then mkdir -p `dirname $filename` \ || die "$filename: mkdir failed" - echo "Extracting CBFS file $cbfsname into $filename" + LOG "Extracting CBFS file $cbfsname into $filename" cbfs -t 50 $CBFS_ARG -r $cbfsname > "$filename" \ || die "$filename: cbfs file read failed" if [ "$CONFIG_TPM" = "y" ]; then TRACE_FUNC - echo "TPM: Extending PCR[$CONFIG_PCR] with $filename" + LOG "TPM: Extending PCR[$CONFIG_PCR] with filename $filename and then its content" # Measure both the filename and its content. This # ensures that renaming files or pivoting file content # will still affect the resulting PCR measurement. @@ -32,5 +32,3 @@ for cbfsname in `echo $cbfsfiles`; do fi fi done - -# TODO: copy CBFS file named "heads/initrd.tgz" to /tmp, measure and extract diff --git a/initrd/bin/kexec-insert-key b/initrd/bin/kexec-insert-key index 0028e348e..ca5db6a57 100755 --- a/initrd/bin/kexec-insert-key +++ b/initrd/bin/kexec-insert-key @@ -66,7 +66,7 @@ fi # Override PCR 4 so that user can't read the key TRACE_FUNC -echo "TPM: Extending PCR[4] to prevent any future secret unsealing" +LOG "TPM: Extending PCR[4] to prevent any future secret unsealing" tpmr extend -ix 4 -ic generic || die 'Unable to scramble PCR' diff --git a/initrd/bin/kexec-select-boot b/initrd/bin/kexec-select-boot index b3b55c302..bdda8aaf8 100755 --- a/initrd/bin/kexec-select-boot +++ b/initrd/bin/kexec-select-boot @@ -385,7 +385,7 @@ while true; do if [ ! -r "$TMP_KEY_DEVICES" ]; then # Extend PCR4 as soon as possible TRACE_FUNC - DEBUG "TPM: Extending PCR[4] to prevent further secret unsealing" + LOG "TPM: Extending PCR[4] to prevent further secret unsealing" tpmr extend -ix 4 -ic generic || die "Failed to extend TPM PCR[4]" fi diff --git a/initrd/bin/qubes-measure-luks b/initrd/bin/qubes-measure-luks index bef6fb102..cc94c9c81 100755 --- a/initrd/bin/qubes-measure-luks +++ b/initrd/bin/qubes-measure-luks @@ -20,6 +20,6 @@ DEBUG "Removing /tmp/lukshdr-*" rm /tmp/lukshdr-* TRACE_FUNC -echo "TPM: Extending PCR[6] with hash of LUKS headers from /tmp/luksDump.txt" +LOG "TPM: Extending PCR[6] with hash of LUKS headers from /tmp/luksDump.txt" tpmr extend -ix 6 -if /tmp/luksDump.txt || die "Unable to extend PCR" diff --git a/initrd/bin/tpmr b/initrd/bin/tpmr index 78b71ea1f..5adb48253 100755 --- a/initrd/bin/tpmr +++ b/initrd/bin/tpmr @@ -258,7 +258,7 @@ tpm2_extend() { esac done tpm2 pcrextend "$index:sha256=$hash" - tpm2 pcrread "sha256:$index" + LOG $(tpm2 pcrread "sha256:$index" 2>&1) TRACE_FUNC DEBUG "TPM: Extended PCR[$index] with hash $hash" @@ -786,7 +786,7 @@ if [ "$CONFIG_TPM2_TOOLS" != "y" ]; then fi TRACE_FUNC - DEBUG "TPM: Extending PCR[$3] with hash $hash" + LOG "TPM: Extending PCR[$3] with hash $hash" DO_WITH_DEBUG exec tpm "$@" ;; seal) @@ -828,7 +828,7 @@ calcfuturepcr) ;; extend) TRACE_FUNC - DEBUG "TPM: Extending PCR[$2] with $4" + LOG "TPM: Extending PCR[$2] with $4" tpm2_extend "$@" ;; counter_read) diff --git a/initrd/etc/ash_functions b/initrd/etc/ash_functions index bf2e32896..735c8760c 100644 --- a/initrd/etc/ash_functions +++ b/initrd/etc/ash_functions @@ -39,7 +39,16 @@ TRACE() { # Write directly to the debug log (but not kmsg), never appears on console LOG() { - echo "LOG: $*" >>/tmp/debug.log + # if not CONFIG_QUIET_MODE=y, output to console. If not, output to debug.log + if [ "$CONFIG_DEBUG_OUTPUT" = "y" ]; then + DEBUG "$*" + elif [ "$CONFIG_QUIET_MODE" = "y" ]; then + # if in quiet mode, output solely to debug.log + echo "$*" >> /tmp/debug.log + else + # if not in quiet mode, output to console + echo "$*" + fi } fw_version() { @@ -241,7 +250,7 @@ recovery() { DEBUG "Board $CONFIG_BOARD - version $(fw_version)" if [ "$CONFIG_TPM" = "y" ]; then - echo "TPM: Extending PCR[4] to prevent any further secret unsealing" + LOG "TPM: Extending PCR[4] to prevent any further secret unsealing" tpmr extend -ix 4 -ic recovery fi diff --git a/initrd/sbin/insmod b/initrd/sbin/insmod index 359bf68f6..95e2303c6 100755 --- a/initrd/sbin/insmod +++ b/initrd/sbin/insmod @@ -39,19 +39,19 @@ if [ ! -r /sys/class/tpm/tpm0/pcrs -o ! -x /bin/tpm ]; then fi if [ -z "$tpm_missing" ]; then - echo "TPM: Extending PCR[$MODULE_PCR] with $MODULE and parameters '$*' before loading" + LOG "TPM: Extending PCR[$MODULE_PCR] with $MODULE and parameters '$*' before loading" # Extend with the module parameters (even if they are empty) and the # module. Changing the parameters or the module content will result in a # different PCR measurement. if [ -n "$*" ]; then TRACE_FUNC - DEBUG "Extending with module parameters and the module's content" + LOG "Extending with module parameters and the module's content" tpmr extend -ix "$MODULE_PCR" -ic "$*" tpmr extend -ix "$MODULE_PCR" -if "$MODULE" \ || die "$MODULE: tpm extend failed" else TRACE_FUNC - DEBUG "No module parameters, extending only with the module's content" + LOG "No module parameters, extending only with the module's content" tpmr extend -ix "$MODULE_PCR" -if "$MODULE" \ || die "$MODULE: tpm extend failed" fi From e44c3017d3db4a1d4c8198c0996c806ce49d8d08 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 27 Nov 2024 13:17:56 -0500 Subject: [PATCH 03/11] init: suppress /etc/config.user not existing on grep calls Signed-off-by: Thierry Laurion --- initrd/init | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/initrd/init b/initrd/init index 55a894a79..6959424e3 100755 --- a/initrd/init +++ b/initrd/init @@ -125,6 +125,7 @@ if [ "$CONFIG_LINUXBOOT" = "y" ]; then fi # Set GPG_TTY before calling gpg in key-init +#TODO: do better then this; on dual console gpg only interacts with main console (affects Talos-2 and all whiptail variants) export GPG_TTY=/dev/console # Initialize gpnupg with distro/user keys and setup the keyrings @@ -144,10 +145,10 @@ fi # changing the value for the rest of the scripts which source /tmp/config. #Only set CONFIG_TPM and CONFIG_TPM2_TOOLS if they are not already set in /etc/config.user -if ! grep -q 'CONFIG_TPM=' /etc/config.user; then +if ! grep -q 'CONFIG_TPM=' /etc/config.user 2>/dev/null; then echo "export CONFIG_TPM=\"$CONFIG_TPM\"" >> /etc/config.user fi -if ! grep -q 'CONFIG_TPM2_TOOLS=' /etc/config.user; then +if ! grep -q 'CONFIG_TPM2_TOOLS=' /etc/config.user 2> /dev/null; then echo "export CONFIG_TPM2_TOOLS=\"$CONFIG_TPM2_TOOLS\"" >> /etc/config.user fi From a450dba9026dbdbe2cd265d18a53a8ea34bdda45 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 27 Nov 2024 13:27:13 -0500 Subject: [PATCH 04/11] init: inform user that running in quiet mode, tell user that technical information can be seen running 'cat /tmp/debug.log' from Recovery Shell Signed-off-by: Thierry Laurion --- initrd/init | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/initrd/init b/initrd/init index 6959424e3..83ea659cf 100755 --- a/initrd/init +++ b/initrd/init @@ -59,6 +59,11 @@ hwclock -l -s . /etc/ash_functions . /etc/config +# report if we are in quiet mode, tell logs available under /tmp/debug.log +if [ "$CONFIG_QUIET_MODE" = "y" ]; then + echo "Quiet mode enabled. To see technical output, do 'cat /tmp/debug.log' from Recovery Shell!" > /dev/tty0 +fi + # Board config had CONFIG_DEBUG_OUTPUT=y defined. # Note that boards's coreboot config kernel command line "debug" option only will have all kernel messages output on console prior of this point if [ "$CONFIG_DEBUG_OUTPUT" = "y" ]; then From 69bac71954d1b27fcfa9bdfa4b7986726cd467ed Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Tue, 3 Dec 2024 11:22:03 -0500 Subject: [PATCH 05/11] codebase: silence dd output while capturing output in variables when needed Signed-off-by: Thierry Laurion --- initrd/bin/inject_firmware.sh | 2 +- initrd/bin/tpmr | 8 ++++---- initrd/bin/unpack_initramfs.sh | 2 +- initrd/mount-boot | 2 +- targets/qemu.mk | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/initrd/bin/inject_firmware.sh b/initrd/bin/inject_firmware.sh index 0de9e33c1..f9e6556e6 100755 --- a/initrd/bin/inject_firmware.sh +++ b/initrd/bin/inject_firmware.sh @@ -96,7 +96,7 @@ chmod a+x "$INITRD_ROOT/init" # Linux ignores zeros between archive segments, so any extra padding is not # harmful. FW_INITRD="/tmp/inject_firmware_initrd.cpio.gz" -dd if="$ORIG_INITRD" of="$FW_INITRD" bs=512 conv=sync status=none +dd if="$ORIG_INITRD" of="$FW_INITRD" bs=512 conv=sync status=none > /dev/null 2>&1 # Pack up the new contents and append to the initrd. Don't spend time # compressing this. (cd "$INITRD_ROOT"; find . | cpio -o -H newc) >>"$FW_INITRD" diff --git a/initrd/bin/tpmr b/initrd/bin/tpmr index 5adb48253..5d8a59531 100755 --- a/initrd/bin/tpmr +++ b/initrd/bin/tpmr @@ -332,7 +332,7 @@ tpm2_counter_create() { esac done prompt_tpm_owner_password - rand_index="1$(dd if=/dev/urandom bs=1 count=3 | xxd -pc3)" + rand_index="1$(dd if=/dev/urandom bs=1 count=3 2>/dev/null | xxd -pc3)" tpm2 nvdefine -C o -s 8 -a "ownerread|authread|authwrite|nt=1" \ -P "$(tpm2_password_hex "$(cat "/tmp/secret/tpm_owner_password")")" "0x$rand_index" >/dev/console || { @@ -412,7 +412,7 @@ tpm1_destroy() { index="$1" # Index of the sealed file size="$2" # Size of zeroes to overwrite for TPM1 - dd if=/dev/zero bs="$size" count=1 of=/tmp/wipe-totp-zero + dd if=/dev/zero bs="$size" count=1 of=/tmp/wipe-totp-zero > /dev/null 2>&1 tpm nv_writevalue -in "$index" -if /tmp/wipe-totp-zero || die "Unable to wipe sealed secret from TPM NVRAM" } @@ -690,7 +690,7 @@ tpm2_reset() { # The default lockout password is empty, so we must set this, and we # don't need to provide any auth (use the default empty password). tpm2 changeauth -Q -c lockout \ - "hex:$(dd if=/dev/urandom bs=32 count=1 status=none | xxd -p | tr -d ' \n')" + "hex:$(dd if=/dev/urandom bs=32 count=1 status=none 2>/dev/null | xxd -p | tr -d ' \n')" } tpm1_reset() { TRACE_FUNC @@ -729,7 +729,7 @@ tpm2_kexec_finalize() { # being cleared in the OS. # This passphrase is only effective before the next boot. echo "Locking TPM2 platform hierarchy..." - randpass=$(dd if=/dev/urandom bs=4 count=1 status=none | xxd -p) + randpass=$(dd if=/dev/urandom bs=4 count=1 status=none 2>/dev/null | xxd -p) tpm2 changeauth -c platform "$randpass" || warn "Failed to lock platform hierarchy of TPM2" } diff --git a/initrd/bin/unpack_initramfs.sh b/initrd/bin/unpack_initramfs.sh index 772131188..4fff52f60 100755 --- a/initrd/bin/unpack_initramfs.sh +++ b/initrd/bin/unpack_initramfs.sh @@ -61,7 +61,7 @@ unpack_first_segment() { mkdir -p "$dest_dir" # peek the beginning of the file to determine what type of content is next - magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)" + magic="$(dd if="$unpack_archive" bs=6 count=1 status=none 2>/dev/null | xxd -p)" # read this segment of the archive, then write the rest to the next file ( diff --git a/initrd/mount-boot b/initrd/mount-boot index 42e4c9ae5..be02e08d8 100755 --- a/initrd/mount-boot +++ b/initrd/mount-boot @@ -36,7 +36,7 @@ dev_blocks=`cat "$dev_size_file"` # # Extract the signed file from the hard disk image # -if ! dd if="$dev" of="$cmd_sig" bs=512 skip="`expr $dev_blocks - 1`"; then +if ! dd if="$dev" of="$cmd_sig" bs=512 skip="`expr $dev_blocks - 1`" > /dev/null 2>&1; then echo >&2 '!!!!!' echo >&2 '!!!!! Boot block extraction failed' echo >&2 '!!!!! Dropping to recovery shell' diff --git a/targets/qemu.mk b/targets/qemu.mk index d5d7dc018..5520ebcdf 100644 --- a/targets/qemu.mk +++ b/targets/qemu.mk @@ -45,7 +45,7 @@ $(MEMORY_SIZE_FILE): @echo "$(QEMU_MEMORY_SIZE)" >"$(MEMORY_SIZE_FILE)" USB_FD_IMG=$(build)/$(BOARD)/usb_fd.raw $(USB_FD_IMG): - dd if=/dev/zero bs=1M of="$(USB_FD_IMG)" bs=1M count=256 + dd if=/dev/zero bs=1M of="$(USB_FD_IMG)" bs=1M count=256 >/dev/null 2>&1 # Debian obnoxiously does not include /usr/sbin in PATH for non-root, even # though it is meaningful to use mkfs.vfat (etc.) as non-root MKFS_VFAT=mkfs.vfat; \ From c8fe99466b4a65b8ca1b274dd9a0b25595730e75 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Tue, 3 Dec 2024 12:20:21 -0500 Subject: [PATCH 06/11] initrd/bin/tmpr: silence tpm reset console output, LOG instead Signed-off-by: Thierry Laurion --- initrd/bin/tpmr | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/initrd/bin/tpmr b/initrd/bin/tpmr index 5d8a59531..65ecbe534 100755 --- a/initrd/bin/tpmr +++ b/initrd/bin/tpmr @@ -650,15 +650,15 @@ tpm2_reset() { # 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" - tpm2 clear -c platform || warn "Unable to clear TPM on platform hierarchy" - tpm2 changeauth -c owner "$(tpm2_password_hex "$tpm_owner_password")" - tpm2 changeauth -c endorsement "$(tpm2_password_hex "$tpm_owner_password")" + tpm2 clear -c platform > /dev/null 2>&1 || LOG "Unable to clear TPM on platform hierarchy" + tpm2 changeauth -c owner "$(tpm2_password_hex "$tpm_owner_password")" > /dev/null 2>&1 || LOG "Unable to change owner password" + tpm2 changeauth -c endorsement "$(tpm2_password_hex "$tpm_owner_password")" > /dev/null 2>&1 || LOG "Unable to change endorsement password" tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \ - -c "$SECRET_DIR/primary.ctx" -P "$(tpm2_password_hex "$tpm_owner_password")" + -c "$SECRET_DIR/primary.ctx" -P "$(tpm2_password_hex "$tpm_owner_password")" > /dev/null 2>&1 || LOG "Unable to create primary key" tpm2 evictcontrol -C owner -c "$SECRET_DIR/primary.ctx" "$PRIMARY_HANDLE" \ - -P "$(tpm2_password_hex "$tpm_owner_password")" - shred -u "$SECRET_DIR/primary.ctx" - tpm2_startsession + -P "$(tpm2_password_hex "$tpm_owner_password")" > /dev/null 2>&1 || LOG "Unable to evict primary key" + shred -u "$SECRET_DIR/primary.ctx" > /dev/null 2>&1 + tpm2_startsession > /dev/null 2>&1 || LOG "Unable to start session" # Set the dictionary attack parameters. TPM2 defaults vary widely, we # want consistent behavior on any TPM. @@ -681,7 +681,7 @@ tpm2_reset() { --max-tries=10 \ --recovery-time=3600 \ --lockout-recovery-time=0 \ - --auth="session:$ENC_SESSION_FILE" + --auth="session:$ENC_SESSION_FILE" > /dev/null 2>&1 || LOG "Unable to set dictionary lockout parameters" # Set a random DA lockout password, so the DA lockout can't be cleared # with a password. Heads doesn't offer dictionary attach reset, instead @@ -690,7 +690,7 @@ tpm2_reset() { # The default lockout password is empty, so we must set this, and we # don't need to provide any auth (use the default empty password). tpm2 changeauth -Q -c lockout \ - "hex:$(dd if=/dev/urandom bs=32 count=1 status=none 2>/dev/null | xxd -p | tr -d ' \n')" + "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" } tpm1_reset() { TRACE_FUNC @@ -700,17 +700,17 @@ tpm1_reset() { 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 "$tpm_owner_password" + tpm physicalpresence -s > /dev/null 2>&1 || LOG "Unable to assert physical presence" + tpm physicalenable > /dev/null 2>&1 || >LOG "Unable to enable TPM" + tpm physicalsetdeactivated -c > /dev/null 2>&1 || LOG "Unable to deactivate TPM" + tpm forceclear -pwdo "$tpm_owner_password" > /dev/null 2>&1 || LOG "Unable to clear TPM" + tpm physicalenable > /dev/null 2>&1 || LOG "Unable to enable TPM" + tpm takeown -pwdo "$tpm_owner_password" > /dev/null 2>&1 || LOG "Unable to take ownership of TPM" # And now turn it all back on - tpm physicalpresence -s - tpm physicalenable - tpm physicalsetdeactivated -c + tpm physicalpresence -s > /dev/null 2>&1 || LOG "Unable to assert physical presence" + tpm physicalenable > /dev/null 2>&1 || LOG "Unable to enable TPM" + tpm physicalsetdeactivated -c > /dev/null 2>&1 || LOG "Unable to deactivate TPM" } # Perform final cleanup before boot and lock the platform heirarchy. From ae97467de97f5f6c4afd75a74efc076a7dfa6bfd Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Tue, 3 Dec 2024 12:48:32 -0500 Subject: [PATCH 07/11] initrd/etc/ash_functions: add GPG Admin/User PIN output grabbing on confirm_gpg_card presence call, echo for now, warn to input GPG User PIN when asked to unlock GPG card Mitigate misunderstands and show GPG User/Admin PIN counts until proper output exists under hotp_verification info to reduce global confusion Add TODO under initrd/bin/seal-hotpkey to not foget to fix output since now outputting counter of 8 for Admin PIN which makes no sense at all under hotp_verification 1.6 https://github.com/Nitrokey/nitrokey-hotp-verification/issues/38 Signed-off-by: Thierry Laurion --- initrd/bin/seal-hotpkey | 1 + initrd/etc/ash_functions | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/initrd/bin/seal-hotpkey b/initrd/bin/seal-hotpkey index 3f91edcc9..957b94240 100755 --- a/initrd/bin/seal-hotpkey +++ b/initrd/bin/seal-hotpkey @@ -105,6 +105,7 @@ awk_get_admin_counter="$awk_admin_counter_regex"' { print gensub('"$awk_admin_co admin_pin_retries="$(echo "$hotp_token_info" | awk "$awk_get_admin_counter")" admin_pin_retries="${admin_pin_retries:-0}" DEBUG "Admin PIN retry counter is $admin_pin_retries" +#TODO: as per hotp_verification 1.6: this is 8 for nk3 and wrong. FIX # Try using factory default admin PIN for 1 month following OEM reset to ease # initial setup. But don't do it forever to encourage changing the PIN and diff --git a/initrd/etc/ash_functions b/initrd/etc/ash_functions index 735c8760c..c0182002a 100644 --- a/initrd/etc/ash_functions +++ b/initrd/etc/ash_functions @@ -154,7 +154,7 @@ confirm_gpg_card() { # ensure we don't exit without retrying errexit=$(set -o | grep errexit | awk '{print $2}') set +e - gpg --card-status >/dev/null + gpg_output=$(gpg --card-status 2>&1) if [ $? -ne 0 ]; then # prompt for reinsertion and try a second time read -n1 -r -p \ @@ -165,13 +165,26 @@ confirm_gpg_card() { set -e fi # retry card status - gpg --card-status >/dev/null || + gpg_output=$(gpg --card-status 2>&1) || die "gpg card read failed" fi # restore prev errexit state if [ "$errexit" = "on" ]; then set -e fi + + # Extract and display GPG PIN retry counters + # output excerpt: "PIN retry counter : 3 0 3" + pin_retry_counters=$(echo "$gpg_output" | grep 'PIN retry counter' | awk -F': ' '{print $2}') + user_pin_retries=$(echo "$pin_retry_counters" | awk '{print $1}') + admin_pin_retries=$(echo "$pin_retry_counters" | awk '{print $3}') + + echo "" + echo "GPG User PIN retry attempts left before becoming locked: $user_pin_retries" + echo "GPG Admin PIN retry attempts left before becoming locked: $admin_pin_retries" + echo "" + warn "Your GPG User PIN, followed by Enter key will be required for input at: 'Please unlock the card' next prompt" + echo "" } gpg_auth() { From 385c99f2fce6bf30c96f3a5e105b820fafc1f982 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Mon, 9 Dec 2024 13:38:28 -0500 Subject: [PATCH 08/11] SQUASH codebase: silence dd output while capturing output in variables when needed Signed-off-by: Thierry Laurion --- initrd/bin/kexec-insert-key | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/initrd/bin/kexec-insert-key b/initrd/bin/kexec-insert-key index ca5db6a57..68b9bed2c 100755 --- a/initrd/bin/kexec-insert-key +++ b/initrd/bin/kexec-insert-key @@ -92,7 +92,7 @@ echo '+++ Building initrd' # pad the initramfs (dracut doesn't pad the last gz blob) # without this the kernel init/initramfs.c fails to read # the subsequent uncompressed/compressed cpio -dd if="$INITRD" of="$SECRET_CPIO" bs=512 conv=sync || +dd if="$INITRD" of="$SECRET_CPIO" bs=512 conv=sync > /dev/null 2>&1 || die "Failed to copy initrd to /tmp" if [ "$unseal_failed" = "n" ]; then From 38b3db451f2eb9e224be0e5f1d6437744c1e815b Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Mon, 9 Dec 2024 13:40:17 -0500 Subject: [PATCH 09/11] initrd/bin/tmpr: silence unneeded output for tpm related operations Signed-off-by: Thierry Laurion --- initrd/bin/tpmr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/initrd/bin/tpmr b/initrd/bin/tpmr index 65ecbe534..e58f4567b 100755 --- a/initrd/bin/tpmr +++ b/initrd/bin/tpmr @@ -307,7 +307,7 @@ tpm1_counter_create() { # other parameters for TPM1 are passed directly, and TPM2 mimics the # TPM1 interface. prompt_tpm_owner_password - if ! tpm counter_create -pwdo "$(cat "/tmp/secret/tpm_owner_password")" "$@"; then + if ! tpm counter_create -pwdo "$(cat "/tmp/secret/tpm_owner_password")" "$@" >/dev/null 2>&1; then DEBUG "Failed to create counter from tpm1_counter_create. Wiping /tmp/secret/tpm_owner_password" shred -n 10 -z -u /tmp/secret/tpm_owner_password die "Unable to create counter from tpm1_counter_create" @@ -334,7 +334,7 @@ tpm2_counter_create() { prompt_tpm_owner_password rand_index="1$(dd if=/dev/urandom bs=1 count=3 2>/dev/null | xxd -pc3)" tpm2 nvdefine -C o -s 8 -a "ownerread|authread|authwrite|nt=1" \ - -P "$(tpm2_password_hex "$(cat "/tmp/secret/tpm_owner_password")")" "0x$rand_index" >/dev/console || + -P "$(tpm2_password_hex "$(cat "/tmp/secret/tpm_owner_password")")" "0x$rand_index" >/dev/null 2>&1 || { DEBUG "Failed to create counter from tpm2_counter_create. Wiping /tmp/secret/tpm_owner_password" shred -n 10 -z -u /tmp/secret/tpm_owner_password From 4ec37e7bbb99afb0695c1a52a893d88f19f7635c Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Mon, 9 Dec 2024 13:42:58 -0500 Subject: [PATCH 10/11] initrd/bin/kexec-sign-config: safeguard ops between remounting /boot rw/ro Signed-off-by: Thierry Laurion --- initrd/bin/kexec-sign-config | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/initrd/bin/kexec-sign-config b/initrd/bin/kexec-sign-config index c34060d0b..d0d66c69e 100755 --- a/initrd/bin/kexec-sign-config +++ b/initrd/bin/kexec-sign-config @@ -27,6 +27,9 @@ assert_signable confirm_gpg_card +# remount /boot as rw +mount -o remount,rw /boot + # update hashes in /boot before signing if [ "$update" = "y" ]; then ( @@ -81,8 +84,15 @@ for tries in 1 2 3; do ; then # successful - update the validated params check_config $paramsdir + + # remount /boot as ro + mount -o remount,ro /boot + exit 0 fi done +# remount /boot as ro +mount -o remount,ro /boot + die "$paramsdir: Unable to sign kexec hashes" From ef30271618bc9df6c8c8ddfc50e9410381b29ff0 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Mon, 9 Dec 2024 13:44:57 -0500 Subject: [PATCH 11/11] initrd/bin/oem-factory-reset: fix tpmr counter output on screen, output of gpg on screen and safeguard PIN that would be word splitted Signed-off-by: Thierry Laurion --- initrd/bin/oem-factory-reset | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/initrd/bin/oem-factory-reset b/initrd/bin/oem-factory-reset index 8fa69ca99..e29465be7 100755 --- a/initrd/bin/oem-factory-reset +++ b/initrd/bin/oem-factory-reset @@ -577,6 +577,11 @@ generate_OEM_gpg_keys() { echo ${USER_PIN_DEF} # Default user PIN since we just factory reset } | DO_WITH_DEBUG gpg --command-fd=0 --status-fd=2 --pinentry-mode=loopback --card-edit \ >/tmp/gpg_card_edit_output 2>&1 + #This outputs to console \ + # "gpg: checking the trustdb" + # "gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model" + # "gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u" + #TODO: Suppress this output to console (stdout shown in DEBUG mode)? if [ $? -ne 0 ]; then ERROR=$(cat /tmp/gpg_card_edit_output) whiptail_error_die "GPG Key automatic keygen failed!\n\n$ERROR" @@ -636,7 +641,7 @@ generate_checksums() { tpmr counter_create \ -pwdc '' \ -la -3135106223 | - tee /tmp/counter || + tee /tmp/counter >/dev/null 2>&1 || whiptail_error_die "Unable to create TPM counter" TPM_COUNTER=$(cut -d: -f1 /dev/null | DO_WITH_DEBUG --mask-position 4 gpg \ --pinentry-mode loopback \ - --passphrase "${USER_PIN}" \ + --passphrase-file <(echo -n "$USER_PIN") \ --digest-algo SHA256 \ --detach-sign \ -a \