diff --git a/initrd/bin/seal-totp b/initrd/bin/seal-totp index 9df8e85a..69ee70d0 100755 --- a/initrd/bin/seal-totp +++ b/initrd/bin/seal-totp @@ -52,7 +52,7 @@ tpmr seal "$TOTP_SECRET" "$TPM_NVRAM_SPACE" 0,1,2,3,4,7 "$pcrf" 312 "" "$TPM_PAS { shred -n 10 -z -u /tmp/secret/tpm_owner_password 2>/dev/null : - die "Unable to write sealed secret to NVRAM" + die "Unable to write sealed secret to NVRAM from seal-totp" } #Make sure we clear TPM TOTP sealed if we succeed to seal TOTP shred -n 10 -z -u "$TOTP_SEALED" 2>/dev/null diff --git a/initrd/bin/tpmr b/initrd/bin/tpmr index 52b183f0..425e08be 100755 --- a/initrd/bin/tpmr +++ b/initrd/bin/tpmr @@ -115,7 +115,7 @@ extend_pcr_state() { shift if is_hash "$alg" "$next"; then extend="$next" - else + else extend="$("${alg}sum" <"$next" | cut -d' ' -f1)" fi state="$(echo "$state$extend" | hex2bin | "${alg}sum" | cut -d' ' -f1)" @@ -127,7 +127,7 @@ extend_pcr_state() { # different arguments for grep. Those formats are shown below as heredocs to # keep all the data, including whitespaces: # 1) TPM2 log, which can hold multiple hash algorithms at once: -: << 'EOF' +: <<'EOF' TPM2 log: Specification: 2.00 Platform class: PC Client @@ -140,7 +140,7 @@ TPM2 log entry 1: Event data: FMAP: FMAP EOF # 2) TPM1.2 log (aka TCPA), digest is always SHA1: -: << 'EOF' +: <<'EOF' TCPA log: Specification: 1.21 Platform class: PC Client @@ -152,7 +152,7 @@ TCPA log entry 1: EOF # 3) coreboot-specific format: # 3.5) older versions printed 'coreboot TCPA log', even though it isn't TCPA -: << 'EOF' +: <<'EOF' coreboot TPM log: PCR-2 27c4f1fa214480c8626397a15981ef3a9323717f SHA1 [FMAP: FMAP] @@ -194,25 +194,25 @@ $0 ~ pcr { # is returned in binary form. replay_pcr() { TRACE "Under /bin/tpmr:replay_pcr" - if [ -z "$2" ] ; then - >&2 echo "No PCR number passed" + if [ -z "$2" ]; then + echo >&2 "No PCR number passed" return fi - if [ "$2" -ge 8 ] ; then - >&2 echo "Illegal PCR number ($2)" + if [ "$2" -ge 8 ]; then + echo >&2 "Illegal PCR number ($2)" return fi - local log=`cbmem -L` + local log=$(cbmem -L) local alg="$1" local pcr="$2" local alg_digits=0 # SHA-1 hashes are 40 chars - if [ "$alg" = "sha1" ] ; then alg_digits=40; fi + if [ "$alg" = "sha1" ]; then alg_digits=40; fi # SHA-256 hashes are 64 chars - if [ "$alg" = "sha256" ] ; then alg_digits=64; fi + if [ "$alg" = "sha256" ]; then alg_digits=64; fi shift 2 replayed_pcr=$(extend_pcr_state $alg $(printf "%.${alg_digits}d" 0) \ - $(echo "$log" | awk -v alg=$alg -v pcr=$pcr -f <(echo $AWK_PROG)) $@) + $(echo "$log" | awk -v alg=$alg -v pcr=$pcr -f <(echo $AWK_PROG)) $@) echo $replayed_pcr | hex2bin DEBUG "Replayed cbmem -L clean boot state of PCR=$pcr ALG=$alg : $replayed_pcr" # To manually introspect current PCR values: @@ -232,17 +232,21 @@ tpm2_extend() { TRACE "Under /bin/tpmr:tpm2_extend" while true; do case "$1" in - -ix) - index="$2" - shift 2;; - -ic) - hash="$(echo -n "$2"|sha256sum|cut -d' ' -f1)" - shift 2;; - -if) - hash="$(sha256sum "$2"|cut -d' ' -f1)" - shift 2;; - *) - break;; + -ix) + index="$2" + shift 2 + ;; + -ic) + hash="$(echo -n "$2" | sha256sum | cut -d' ' -f1)" + shift 2 + ;; + -if) + hash="$(sha256sum "$2" | cut -d' ' -f1)" + shift 2 + ;; + *) + break + ;; esac done tpm2 pcrextend "$index:sha256=$hash" @@ -253,57 +257,67 @@ tpm2_counter_read() { TRACE "Under /bin/tpmr:tpm2_counter_read" while true; do case "$1" in - -ix) - index="$2" - shift 2;; - *) - break;; + -ix) + index="$2" + shift 2 + ;; + *) + break + ;; esac done - echo "$index: `tpm2 nvread 0x$index | xxd -pc8`" + echo "$index: $(tpm2 nvread 0x$index | xxd -pc8)" } tpm2_counter_inc() { TRACE "Under /bin/tpmr:tpm2_counter_inc" while true; do case "$1" in - -ix) - index="$2" - shift 2;; - -pwdc) - pwd="$2" - shift 2;; - *) - break;; + -ix) + index="$2" + shift 2 + ;; + -pwdc) + pwd="$2" + shift 2 + ;; + *) + break + ;; esac done - tpm2 nvincrement "0x$index" > /dev/console - echo "$index: `tpm2 nvread 0x$index | xxd -pc8`" + tpm2 nvincrement "0x$index" >/dev/console + echo "$index: $(tpm2 nvread 0x$index | xxd -pc8)" } tpm2_counter_cre() { TRACE "Under /bin/tpmr:tpm2_counter_cre" while true; do case "$1" in - -pwdo) - pwdo="$2" - shift 2;; - -pwdof) - pwdo="file:$2" - shift 2;; - -pwdc) - pwd="$2" - shift 2;; - -la) - label="$2" - shift 2;; - *) - break;; + -pwdo) + pwdo="$2" + shift 2 + ;; + -pwdof) + pwdo="file:$2" + shift 2 + ;; + -pwdc) + pwd="$2" + shift 2 + ;; + -la) + label="$2" + shift 2 + ;; + *) + break + ;; esac done - rand_index="1`dd if=/dev/urandom bs=1 count=3 | xxd -pc3`" + rand_index="1$(dd if=/dev/urandom bs=1 count=3 | xxd -pc3)" tpm2 nvdefine -C o -s 8 -a "ownerread|authread|authwrite|nt=1" \ - -P "$(tpm2_password_hex "$pwdo")" "0x$rand_index" > /dev/console + -P "$(tpm2_password_hex "$pwdo")" "0x$rand_index" >/dev/console echo "$rand_index: (valid after an increment)" } @@ -311,16 +325,16 @@ tpm2_startsession() { TRACE "Under /bin/tpmr:tpm2_startsession" mkdir -p "$SECRET_DIR" tpm2 flushcontext -Q \ - --transient-object \ - || die "tpm2_flushcontext: unable to flush transient handles" + --transient-object || + die "tpm2_flushcontext: unable to flush transient handles" tpm2 flushcontext -Q \ - --loaded-session \ - || die "tpm2_flushcontext: unable to flush sessions" + --loaded-session || + die "tpm2_flushcontext: unable to flush sessions" tpm2 flushcontext -Q \ - --saved-session \ - || die "tpm2_flushcontext: unable to flush saved session" + --saved-session || + die "tpm2_flushcontext: unable to flush saved session" tpm2 readpublic -Q -c "$PRIMARY_HANDLE" -t "$PRIMARY_HANDLE_FILE" tpm2 startauthsession -Q -c "$PRIMARY_HANDLE_FILE" --hmac-session -S "$ENC_SESSION_FILE" tpm2 startauthsession -Q -c "$PRIMARY_HANDLE_FILE" --hmac-session -S "$DEC_SESSION_FILE" @@ -354,27 +368,27 @@ cleanup_shred() { # tpm2_destroy: Destroy a sealed file in the TPM. The mechanism differs by # TPM version - TPM2 evicts the file object, so it no longer exists. tpm2_destroy() { - index="$1" # Index of the sealed file - size="$2" # Size of zeroes to overwrite for TPM1 (unused in TPM2) + index="$1" # Index of the sealed file + size="$2" # Size of zeroes to overwrite for TPM1 (unused in TPM2) # Pad with up to 6 zeros, i.e. '0x81000001', '0x81001234', etc. handle="$(printf "0x81%6s" "$index" | tr ' ' 0)" # remove possible data occupying this handle - tpm2 evictcontrol -Q -C p -c "$handle" 2>/dev/null \ - || die "Unable to evict secret" + tpm2 evictcontrol -Q -C p -c "$handle" 2>/dev/null || + die "Unable to evict secret" } # tpm1_destroy: Destroy a sealed file in the TPM. The mechanism differs by # TPM version - TPM1 overwrites the file with zeroes, since this can be done # without authorization. (Deletion requires authorization.) tpm1_destroy() { - index="$1" # Index of the sealed file - size="$2" # Size of zeroes to overwrite for TPM1 + 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 - tpm nv_writevalue -in "$index" -if /tmp/wipe-totp-zero \ - || die "Unable to wipe sealed secret" + tpm nv_writevalue -in "$index" -if /tmp/wipe-totp-zero || + die "Unable to wipe sealed secret" } # tpm2_seal: Seal a file against PCR values and, optionally, a password. @@ -388,13 +402,13 @@ tpm2_seal() { index="$2" pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix) pcrf="$4" - sealed_size="$5" # Not used for TPM2 - pass="$6" # May be empty to seal with no password - tpm_password="$7" # Owner password - will prompt if needed and not empty + sealed_size="$5" # Not used for TPM2 + pass="$6" # May be empty to seal with no password + tpm_password="$7" # Owner password - will prompt if needed and not empty # TPM Owner Password is always needed for TPM2. mkdir -p "$SECRET_DIR" - bname="`basename $file`" + bname="$(basename $file)" # Pad with up to 6 zeros, i.e. '0x81000001', '0x81001234', etc. handle="$(printf "0x81%6s" "$index" | tr ' ' 0)" @@ -448,7 +462,8 @@ tpm2_seal() { -c "$handle" 2>/dev/null || true DO_WITH_DEBUG --mask-position 6 \ tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_owner_password")" \ - -c "$SECRET_DIR/$bname.seal.ctx" "$handle" + -c "$SECRET_DIR/$bname.seal.ctx" "$handle" || + die "Unable to write sealed secret to NVRAM from tpm2_seal" } tpm1_seal() { TRACE "Under /bin/tpmr:tpm1_seal" @@ -457,8 +472,8 @@ tpm1_seal() { pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix) pcrf="$4" sealed_size="$5" - pass="$6" # May be empty to seal with no password - tpm_password="$7" # Owner password - will prompt if needed and not empty + pass="$6" # May be empty to seal with no password + tpm_password="$7" # Owner password - will prompt if needed and not empty sealed_file="$SECRET_DIR/tpm1_seal_sealed.bin" at_exit cleanup_shred "$sealed_file" @@ -477,8 +492,8 @@ tpm1_seal() { # Read each PCR_SIZE block from the file and pass as hex POLICY_ARGS+=(-ix "$pcr" "$(dd if="$pcrf" skip="$pcr_file_index" bs="$PCR_SIZE" count=1 status=none | xxd -p | tr -d ' ')" - ) - pcr_file_index=$((pcr_file_index+1)) + ) + pcr_file_index=$((pcr_file_index + 1)) done tpm sealfile2 \ @@ -494,18 +509,17 @@ tpm1_seal() { # # The permissions are 0 since there is nothing special # about the sealed file - tpm physicalpresence -s \ - || warn "Unable to assert physical presence" + tpm physicalpresence -s || + warn "Unable to assert physical presence" prompt_tpm_owner_password tpm nv_definespace -in "$index" -sz "$sealed_size" \ - -pwdo "$tpm_password" -per 0 \ - || warn "Unable to define NVRAM space; trying anyway" + -pwdo "$tpm_password" -per 0 || + warn "Unable to define NVRAM space; trying anyway" - - tpm nv_writevalue -in "$index" -if "$sealed_file" \ - || die "Unable to write sealed secret to NVRAM" + tpm nv_writevalue -in "$index" -if "$sealed_file" || + die "Unable to write sealed secret to NVRAM from tpm1_seal" fi } @@ -555,7 +569,7 @@ tpm2_unseal() { fi tpm2 unseal -Q -c "$handle" -p "session:$POLICY_SESSION$UNSEAL_PASS_SUFFIX" \ - -S "$ENC_SESSION_FILE" > "$file" + -S "$ENC_SESSION_FILE" >"$file" } tpm1_unseal() { TRACE "Under /bin/tpmr:tpm1_unseal" @@ -577,8 +591,8 @@ tpm1_unseal() { tpm nv_readvalue \ -in "$index" \ -sz "$sealed_size" \ - -of "$sealed_file" \ - || die "Unable to read sealed file from TPM NVRAM" + -of "$sealed_file" || + die "Unable to read sealed file from TPM NVRAM" PASS_ARGS=() if [ "$pass" ]; then @@ -598,7 +612,7 @@ tpm2_reset() { mkdir -p "$SECRET_DIR" # 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" + 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")" @@ -647,7 +661,7 @@ tpm1_reset() { mkdir -p "$SECRET_DIR" # 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" + echo -n "$tpm_owner_password" >"$SECRET_DIR/tpm_owner_password" # Make sure the TPM is ready to be reset tpm physicalpresence -s tpm physicalenable @@ -667,20 +681,20 @@ tpm2_kexec_finalize() { TRACE "Under /bin/tpmr:tpm2_kexec_finalize" # Flush sessions and transient objects - tpm2 flushcontext -Q --transient-object \ - || warn "tpm2_flushcontext: unable to flush transient handles" - tpm2 flushcontext -Q --loaded-session \ - || warn "tpm2_flushcontext: unable to flush sessions" - tpm2 flushcontext -Q --saved-session \ - || warn "tpm2_flushcontext: unable to flush saved session" + tpm2 flushcontext -Q --transient-object || + warn "tpm2_flushcontext: unable to flush transient handles" + tpm2 flushcontext -Q --loaded-session || + warn "tpm2_flushcontext: unable to flush sessions" + tpm2 flushcontext -Q --saved-session || + warn "tpm2_flushcontext: unable to flush saved session" # Add a random passphrase to platform hierarchy to prevent TPM2 from # 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) - tpm2 changeauth -c platform "$randpass" \ - || warn "Failed to lock platform hierarchy of TPM2" + tpm2 changeauth -c platform "$randpass" || + warn "Failed to lock platform hierarchy of TPM2" } tpm2_shutdown() { @@ -700,72 +714,97 @@ fi # TPM1 - most commands forward directly to tpm, but some are still wrapped for # consistency with tpm2. if [ "$CONFIG_TPM2_TOOLS" != "y" ]; then - PCR_SIZE=20 # TPM1 PCRs are always SHA-1 + PCR_SIZE=20 # TPM1 PCRs are always SHA-1 subcmd="$1" # Don't shift yet, for most commands we will just forward to tpm. case "$subcmd" in - pcrread) - shift; tpm1_pcrread "$@";; - pcrsize) - echo "$PCR_SIZE";; - calcfuturepcr) - shift; replay_pcr "sha1" "$@";; - destroy) - shift; tpm1_destroy "$@";; - seal) - shift; tpm1_seal "$@";; - startsession) - ;; # Nothing on TPM1. - unseal) - shift; tpm1_unseal "$@";; - reset) - shift; tpm1_reset "$@";; - kexec_finalize) - ;; # Nothing on TPM1. - shutdown) - ;; # Nothing on TPM1. - *) - DEBUG "Direct translation from tpmr to tpm1 call" - DO_WITH_DEBUG exec tpm "$@" - ;; + pcrread) + shift + tpm1_pcrread "$@" + ;; + pcrsize) + echo "$PCR_SIZE" + ;; + calcfuturepcr) + shift + replay_pcr "sha1" "$@" + ;; + destroy) + shift + tpm1_destroy "$@" + ;; + seal) + shift + tpm1_seal "$@" + ;; + startsession) ;; # Nothing on TPM1. + unseal) + shift + tpm1_unseal "$@" + ;; + reset) + shift + tpm1_reset "$@" + ;; + kexec_finalize) ;; # Nothing on TPM1. + shutdown) ;; # Nothing on TPM1. + *) + DEBUG "Direct translation from tpmr to tpm1 call" + DO_WITH_DEBUG exec tpm "$@" + ;; esac exit 0 fi # TPM2 - all commands implemented as wrappers around tpm2 -PCR_SIZE=32 # We use the SHA-256 PCRs +PCR_SIZE=32 # We use the SHA-256 PCRs subcmd="$1" shift 1 case "$subcmd" in - pcrread) - tpm2_pcrread "$@";; - pcrsize) - echo "$PCR_SIZE";; - calcfuturepcr) - replay_pcr "sha256" "$@";; - extend) - tpm2_extend "$@";; - counter_read) - tpm2_counter_read "$@";; - counter_increment) - tpm2_counter_inc "$@";; - counter_create) - tpm2_counter_cre "$@";; - destroy) - tpm2_destroy "$@";; - seal) - tpm2_seal "$@";; - startsession) - tpm2_startsession "$@";; - unseal) - tpm2_unseal "$@";; - reset) - tpm2_reset "$@";; - kexec_finalize) - tpm2_kexec_finalize "$@";; - shutdown) - tpm2_shutdown "$@";; - *) - echo "Command $subcmd not wrapped!" - exit 1 +pcrread) + tpm2_pcrread "$@" + ;; +pcrsize) + echo "$PCR_SIZE" + ;; +calcfuturepcr) + replay_pcr "sha256" "$@" + ;; +extend) + tpm2_extend "$@" + ;; +counter_read) + tpm2_counter_read "$@" + ;; +counter_increment) + tpm2_counter_inc "$@" + ;; +counter_create) + tpm2_counter_cre "$@" + ;; +destroy) + tpm2_destroy "$@" + ;; +seal) + tpm2_seal "$@" + ;; +startsession) + tpm2_startsession "$@" + ;; +unseal) + tpm2_unseal "$@" + ;; +reset) + tpm2_reset "$@" + ;; +kexec_finalize) + tpm2_kexec_finalize "$@" + ;; +shutdown) + tpm2_shutdown "$@" + ;; +*) + echo "Command $subcmd not wrapped!" + exit 1 + ;; esac