Skip to content

Commit

Permalink
bin/tpmr .ash_history: add needed functions to be able to call tpmr r…
Browse files Browse the repository at this point in the history
…ecalculate_firmware_pcr_from_cbfs

.ash_history: add tpmr recalculate_firmware_pcr_from_cbfs but remove unneeded deprecated ways of doing things

Signed-off-by: Thierry Laurion <[email protected]>
  • Loading branch information
tlaurion committed Jan 3, 2024
1 parent 5574fb4 commit 51231f3
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 30 deletions.
31 changes: 10 additions & 21 deletions initrd/.ash_history
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
#mount /boot in read-only by default
mount /boot
#verify detached signature of /boot content
find /boot/kexec*.txt | gpg --verify /boot/kexec.sig -
#remove invalid kexec_* signed files
mount /dev/sda1 /boot && mount -o remount,rw /boot && rm /boot/kexec* && mount -o remount,ro /boot
#Generate keys from GPG smartcard:
mount-usb && gpg --home=/.gnupg/ --card-edit
#Copy generated public key, private_subkey, trustdb and artifacts to external media for backup:
mount -o remount,rw /media && mkdir -p /media/gpg_keys; gpg --export-secret-keys --armor [email protected] > /media/gpg_keys/private.key && gpg --export --armor [email protected] > /media/gpg_keys/public.key && gpg --export-ownertrust > /media/gpg_keys/otrust.txt && cp -r ./.gnupg/* /media/gpg_keys/ 2> /dev/null
#Insert public key and trustdb export into reproducible rom:
cbfs -o /media/coreboot.rom -a "heads/initrd/.gnupg/keys/public.key" -f /media/gpg_keys/public.key && cbfs -o /media/coreboot.rom -a "heads/initrd/.gnupg/keys/otrust.txt" -f /media/gpg_keys/otrust.txt
#Flush changes to external media:
mount -o,remount ro /media
#Flash modified reproducible rom with inserted public key and trustdb export from precedent step. Flushes actual rom's keys (-c: clean):
flash.sh -c /media/coreboot.rom
#Attest integrity of firmware as it is
seal-totp
#Verify Intel ME state:
cbmem --console | grep '^ME'
cbmem --console | less
mount /boot #mount /boot in read-only by default
find /boot/kexec*.txt | gpg --verify /boot/kexec.sig - #verify detached signature of /boot content
media-scan /dev/sdXZ #scan Y partition of X device for detached signed ISOs to boot from
mount-usb --mode rw #mount usb in read-write mode
mount-usb --mode ro #mount usb in read-only mode
flash.sh -c /media/coreboot.rom #flash coreboot.rom WITHOUT preserving user settings
flash.sh /media/coreboot.rom -p #flash coreboot.rom WITH preserving user settings
cbmem --console | grep '^ME' #view ME console
cbmem --console | less #view coreboot console
tpmr recalculate_firmware_pcr_from_cbfs #Replay coreboot TPM event log from CBFS
# Reboot/power off (important for devices with no keyboard to escape recovery shell)
reboot # Press Enter with this command to reboot
poweroff # Press Enter with this command to power off
92 changes: 83 additions & 9 deletions initrd/bin/tpmr
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,29 @@ is_hash() {
# initial_state - a hash value setting the initial state
# files/hashes... - any number of files or hashes, state is extended once for each item
extend_pcr_state() {
TRACE "Under /bin/tpmr:extend_pcr_state"
local alg="$1"
local state="$2"
DEBUG "Initial PCR state: $state"
local next extend
shift 2
local argument=1

while [ "$#" -gt 0 ]; do
DEBUG "Extending PCR state with argument #$argument: $1"
next="$1"
shift
if is_hash "$alg" "$next"; then
extend="$next"
DEBUG "Extending PCR state with passed argument #$argument hash: $extend"
else
extend="$("${alg}sum" <"$next" | cut -d' ' -f1)"
DEBUG "Extending PCR state with argument #$argument file: $extend"
fi
state="$(echo "$state$extend" | hex2bin | "${alg}sum" | cut -d' ' -f1)"
argument=$((argument + 1))
done
DEBUG "Extended final PCR state: $state"
echo "$state"
}

Expand Down Expand Up @@ -213,8 +221,10 @@ replay_pcr() {
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 $replayed_pcr | hex2bin
DEBUG "Replayed cbmem -L clean boot state of PCR=$pcr ALG=$alg : $replayed_pcr"

# Output in binary form
echo $replayed_pcr | hex2bin
# To manually introspect current PCR values:
# PCR-2:
# tpmr calcfuturepcr 2 | xxd -p
Expand All @@ -228,11 +238,33 @@ replay_pcr() {
# (6: LUKS header, 7: user related cbfs files loaded from cbfs-init)
}

# usage: calc_pcr <alg> <pcr_num> [ <input_file>|<input_hash> ... ]
# Calculate PCR value to compare with CBMEM event log.
# First argument is PCR number, followed by optional
# hashes and/or files.
# Resulting PCR value is returned in binary form.

# Read the FMAP from cbmem and pad it to the next multiple of 512 bytes to match cbfsutil/measured boot FMAP
read_and_pad_FMAP_from_cbmem() {
# Create the directory for temporary files
mkdir -p /tmp/secret/
# Fetch the address of the FMAP in memory and write the raw FMAP data to a file
cbmem --rawdump $(cbmem -l | grep FMAP | awk -F " " {'print $3'}) >/tmp/secret/fmap.raw
# Fetch the size of the FMAP from the raw data (4 bytes at offset 8) and store it as a hexadecimal string
fmap_size_hex=$(hexdump -v -e '/1 "%02x"' -s 8 -n 4 /tmp/secret/fmap.raw)
# Rearrange the bytes in the size to little-endian format
fmap_size_le=${fmap_size_hex:6:2}${fmap_size_hex:4:2}${fmap_size_hex:2:2}${fmap_size_hex:0:2}
# Convert the size from hexadecimal to decimal
fmap_size=$((16#$fmap_size_le))
# Calculate the next multiple of 512 that is greater than or equal to the size of the FMAP
next_multiple=$((($fmap_size + 511) / 512 * 512))
# Calculate the number of bytes needed to fill the fmap.raw file to the next multiple of 512
#fill_size=$(( $next_multiple - $fmap_size ))
fill_size=$(($next_multiple - $(stat -c%s /tmp/secret/fmap.raw)))
# Create a file named fill.ff filled with 'ff' of the required size
dd if=/dev/zero bs=1 count=$fill_size 2>/dev/null | tr '\0' '\377' >/tmp/secret/fill.ff
# Append the fill.ff file to the fmap.raw file, resulting in a file named fmap_filled.raw
cat /tmp/secret/fmap.raw /tmp/secret/fill.ff >/tmp/secret/fmap_filled.raw
# Caller is expected to use hash format that matches the algorithm used for the PCR
sha1sum /tmp/secret/fmap_filled.raw | awk -F " " {'print $1'}
# Removal of the tempory files in tmpfs is left to when going to recovery shell or rebooting
}

calc_pcr() {
TRACE "Under /bin/tpmr:calc_pcr"
if [ -z "$2" ]; then
Expand All @@ -252,8 +284,9 @@ calc_pcr() {
if [ "$alg" = "sha256" ]; then alg_digits=64; fi
shift 2
replayed_pcr=$(extend_pcr_state $alg $(printf "%.${alg_digits}d" 0) $@)
echo $replayed_pcr | hex2bin
DEBUG "Replayed cbmem -L clean boot state of PCR=$pcr ALG=$alg : $replayed_pcr"
echo $replayed_pcr

# To manually introspect calculated to PCR values:
# TODO: fix the following examples with WORKING examples
# PCR-2:
Expand All @@ -271,6 +304,41 @@ calc_pcr() {
# (6: LUKS header, 7: user related cbfs files loaded from cbfs-init)
}


# Function: recalculate_firmware_pcr_from_cbfs
# Description: This function recalculates the firmware PCR (Platform Configuration Register) values from the files measured by coreboot.
# It simulates the measurement process by passing the hashes of the files to the `calc_pcr` function.
# The function uses various `cbfs` commands to read the contents of specific files and calculates their SHA1 hashes.
# The calculated hashes are then passed to `calc_pcr` along with other necessary parameters.
# The function also outputs the PCR values for TPM PCR2 and the TPM event log reported by `cbmem -L`.
#
# Parameters:
# - $1: checksum algorithm (sha1 or sha256)
#
# Usage: recalculate_firmware_pcr_from_cbfs <checksum algo> <file_hash/file_name>
# Examples:
# recalculate_firmware_pcr_from_cbfs sha1 "3E0A13C35B0244B012BE5287A3B52352CC576BAE"
# recalculate_firmware_pcr_from_cbfs sha256 "3E0A13C35B0244B012BE5287A3B52352CC576BAE"
#
# TODO: redo alternative function with files instead of hashes
recalculate_firmware_pcr_from_cbfs()
{
TRACE "Under /bin/tpmr:recalculate_firmware_pcr_from_cbfs"
# We pass hashes of the files that are measured by coreboot, simulating the measurement process
# As of now, Heads uses coreboot custom TPM Event log format, which measures everything in PCR-2
DO_WITH_DEBUG calc_pcr "$1" 2 \
$(read_and_pad_FMAP_from_cbmem) \
$(cbfs --read bootblock | sha1sum | awk -F " " {'print $1'}) \
$(cbfs --read fallback/romstage | sha1sum | awk -F " " {'print $1'}) \
$(cbfs --read fallback/postcar | sha1sum | awk -F " " {'print $1'}) \
$(cbfs --read fallback/ramstage | sha1sum | awk -F " " {'print $1'}) \
$(cbfs --read bootsplash.jpg | sha1sum | awk -F " " {'print $1'}) \
$(cbfs --read fallback/payload | sha1sum | awk -F " " {'print $1'})

DEBUG "Actual TPM $(pcrs | grep PCR-02)"
DEBUG "TPM event log reported by cbmem -L: $(cbmem -L)"
}

tpm2_extend() {
TRACE "Under /bin/tpmr:tpm2_extend"
while true; do
Expand Down Expand Up @@ -530,7 +598,7 @@ 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
pass="$6" # May be empty to seal with no password
tpm_owner_password="$7" # Owner password - will prompt if needed and not empty

sealed_file="$SECRET_DIR/tpm1_seal_sealed.bin"
Expand All @@ -540,7 +608,6 @@ tpm1_seal() {

DEBUG "tpm1_seal arguments: file=$file index=$index pcrl=$pcrl pcrf=$pcrf sealed_size=$sealed_size pass=$(mask_param "$pass") tpm_password=$(mask_param "$tpm_password")"


# If a password was given, add it to the policy arguments
if [ "$pass" ]; then
POLICY_ARGS+=(-pwdd "$pass")
Expand Down Expand Up @@ -798,6 +865,10 @@ if [ "$CONFIG_TPM2_TOOLS" != "y" ]; then
shift
calc_pcr "sha1" "$@"
;;
recalculate_firmware_pcr_from_cbfs)
shift
recalculate_firmware_pcr_from_cbfs "sha1"
;;
counter_create)
shift
tpm1_counter_create "$@"
Expand Down Expand Up @@ -846,6 +917,9 @@ calcfuturepcr)
calc_pcr)
calc_pcr "sha256" "$@"
;;
recalculate_firmware_pcr_from_cbfs)
recalculate_firmware_pcr_from_cbfs "sha256"
;;
extend)
tpm2_extend "$@"
;;
Expand Down

0 comments on commit 51231f3

Please sign in to comment.