@@ -105,21 +105,29 @@ is_hash() {
105105# initial_state - a hash value setting the initial state
106106# files/hashes... - any number of files or hashes, state is extended once for each item
107107extend_pcr_state () {
108+ TRACE " Under /bin/tpmr:extend_pcr_state"
108109 local alg=" $1 "
109110 local state=" $2 "
111+ DEBUG " Initial PCR state: $state "
110112 local next extend
111113 shift 2
114+ local argument=1
112115
113116 while [ " $# " -gt 0 ]; do
117+ DEBUG " Extending PCR state with argument #$argument : $1 "
114118 next=" $1 "
115119 shift
116120 if is_hash " $alg " " $next " ; then
117121 extend=" $next "
122+ DEBUG " Extending PCR state with passed argument #$argument hash: $extend "
118123 else
119124 extend=" $( " ${alg} sum" < " $next " | cut -d' ' -f1) "
125+ DEBUG " Extending PCR state with argument #$argument file: $extend "
120126 fi
121127 state=" $( echo " $state$extend " | hex2bin | " ${alg} sum" | cut -d' ' -f1) "
128+ argument=$(( argument + 1 ))
122129 done
130+ DEBUG " Extended final PCR state: $state "
123131 echo " $state "
124132}
125133
@@ -213,8 +221,10 @@ replay_pcr() {
213221 shift 2
214222 replayed_pcr=$( extend_pcr_state $alg $( printf " %.${alg_digits} d" 0) \
215223 $( echo " $log " | awk -v alg=$alg -v pcr=$pcr -f <( echo $AWK_PROG ) ) $@ )
216- echo $replayed_pcr | hex2bin
217224 DEBUG " Replayed cbmem -L clean boot state of PCR=$pcr ALG=$alg : $replayed_pcr "
225+
226+ # Output in binary form
227+ echo $replayed_pcr | hex2bin
218228 # To manually introspect current PCR values:
219229 # PCR-2:
220230 # tpmr calcfuturepcr 2 | xxd -p
@@ -228,11 +238,33 @@ replay_pcr() {
228238 # (6: LUKS header, 7: user related cbfs files loaded from cbfs-init)
229239}
230240
231- # usage: calc_pcr <alg> <pcr_num> [ <input_file>|<input_hash> ... ]
232- # Calculate PCR value to compare with CBMEM event log.
233- # First argument is PCR number, followed by optional
234- # hashes and/or files.
235- # Resulting PCR value is returned in binary form.
241+
242+ # Read the FMAP from cbmem and pad it to the next multiple of 512 bytes to match cbfsutil/measured boot FMAP
243+ read_and_pad_FMAP_from_cbmem () {
244+ # Create the directory for temporary files
245+ mkdir -p /tmp/secret/
246+ # Fetch the address of the FMAP in memory and write the raw FMAP data to a file
247+ cbmem --rawdump $( cbmem -l | grep FMAP | awk -F " " {' print $3' }) > /tmp/secret/fmap.raw
248+ # Fetch the size of the FMAP from the raw data (4 bytes at offset 8) and store it as a hexadecimal string
249+ fmap_size_hex=$( hexdump -v -e ' /1 "%02x"' -s 8 -n 4 /tmp/secret/fmap.raw)
250+ # Rearrange the bytes in the size to little-endian format
251+ fmap_size_le=${fmap_size_hex: 6: 2}${fmap_size_hex: 4: 2}${fmap_size_hex: 2: 2}${fmap_size_hex: 0: 2}
252+ # Convert the size from hexadecimal to decimal
253+ fmap_size=$(( 16 #$fmap_size_le ))
254+ # Calculate the next multiple of 512 that is greater than or equal to the size of the FMAP
255+ next_multiple=$(( ($fmap_size + 511 ) / 512 * 512 ))
256+ # Calculate the number of bytes needed to fill the fmap.raw file to the next multiple of 512
257+ # fill_size=$(( $next_multiple - $fmap_size ))
258+ fill_size=$(( $next_multiple - $(stat - c% s / tmp/ secret/ fmap.raw)) )
259+ # Create a file named fill.ff filled with 'ff' of the required size
260+ dd if=/dev/zero bs=1 count=$fill_size 2> /dev/null | tr ' \0' ' \377' > /tmp/secret/fill.ff
261+ # Append the fill.ff file to the fmap.raw file, resulting in a file named fmap_filled.raw
262+ cat /tmp/secret/fmap.raw /tmp/secret/fill.ff > /tmp/secret/fmap_filled.raw
263+ # Caller is expected to use hash format that matches the algorithm used for the PCR
264+ sha1sum /tmp/secret/fmap_filled.raw | awk -F " " {' print $1' }
265+ # Removal of the tempory files in tmpfs is left to when going to recovery shell or rebooting
266+ }
267+
236268calc_pcr () {
237269 TRACE " Under /bin/tpmr:calc_pcr"
238270 if [ -z " $2 " ]; then
@@ -252,8 +284,9 @@ calc_pcr() {
252284 if [ " $alg " = " sha256" ]; then alg_digits=64; fi
253285 shift 2
254286 replayed_pcr=$( extend_pcr_state $alg $( printf " %.${alg_digits} d" 0) $@ )
255- echo $replayed_pcr | hex2bin
256287 DEBUG " Replayed cbmem -L clean boot state of PCR=$pcr ALG=$alg : $replayed_pcr "
288+ echo $replayed_pcr
289+
257290 # To manually introspect calculated to PCR values:
258291 # TODO: fix the following examples with WORKING examples
259292 # PCR-2:
@@ -271,6 +304,41 @@ calc_pcr() {
271304 # (6: LUKS header, 7: user related cbfs files loaded from cbfs-init)
272305}
273306
307+
308+ # Function: recalculate_firmware_pcr_from_cbfs
309+ # Description: This function recalculates the firmware PCR (Platform Configuration Register) values from the files measured by coreboot.
310+ # It simulates the measurement process by passing the hashes of the files to the `calc_pcr` function.
311+ # The function uses various `cbfs` commands to read the contents of specific files and calculates their SHA1 hashes.
312+ # The calculated hashes are then passed to `calc_pcr` along with other necessary parameters.
313+ # The function also outputs the PCR values for TPM PCR2 and the TPM event log reported by `cbmem -L`.
314+ #
315+ # Parameters:
316+ # - $1: checksum algorithm (sha1 or sha256)
317+ #
318+ # Usage: recalculate_firmware_pcr_from_cbfs <checksum algo> <file_hash/file_name>
319+ # Examples:
320+ # recalculate_firmware_pcr_from_cbfs sha1 "3E0A13C35B0244B012BE5287A3B52352CC576BAE"
321+ # recalculate_firmware_pcr_from_cbfs sha256 "3E0A13C35B0244B012BE5287A3B52352CC576BAE"
322+ #
323+ # TODO: redo alternative function with files instead of hashes
324+ recalculate_firmware_pcr_from_cbfs ()
325+ {
326+ TRACE " Under /bin/tpmr:recalculate_firmware_pcr_from_cbfs"
327+ # We pass hashes of the files that are measured by coreboot, simulating the measurement process
328+ # As of now, Heads uses coreboot custom TPM Event log format, which measures everything in PCR-2
329+ DO_WITH_DEBUG calc_pcr " $1 " 2 \
330+ $( read_and_pad_FMAP_from_cbmem) \
331+ $( cbfs --read bootblock | sha1sum | awk -F " " {' print $1' }) \
332+ $( cbfs --read fallback/romstage | sha1sum | awk -F " " {' print $1' }) \
333+ $( cbfs --read fallback/postcar | sha1sum | awk -F " " {' print $1' }) \
334+ $( cbfs --read fallback/ramstage | sha1sum | awk -F " " {' print $1' }) \
335+ $( cbfs --read bootsplash.jpg | sha1sum | awk -F " " {' print $1' }) \
336+ $( cbfs --read fallback/payload | sha1sum | awk -F " " {' print $1' })
337+
338+ DEBUG " Actual TPM $( pcrs | grep PCR-02) "
339+ DEBUG " TPM event log reported by cbmem -L: $( cbmem -L) "
340+ }
341+
274342tpm2_extend () {
275343 TRACE " Under /bin/tpmr:tpm2_extend"
276344 while true ; do
@@ -530,7 +598,7 @@ tpm1_seal() {
530598 pcrl=" $3 " # 0,1,2,3,4,5,6,7 (does not include algorithm prefix)
531599 pcrf=" $4 "
532600 sealed_size=" $5 "
533- pass=" $6 " # May be empty to seal with no password
601+ pass=" $6 " # May be empty to seal with no password
534602 tpm_owner_password=" $7 " # Owner password - will prompt if needed and not empty
535603
536604 sealed_file=" $SECRET_DIR /tpm1_seal_sealed.bin"
@@ -540,7 +608,6 @@ tpm1_seal() {
540608
541609 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 " ) "
542610
543-
544611 # If a password was given, add it to the policy arguments
545612 if [ " $pass " ]; then
546613 POLICY_ARGS+=(-pwdd " $pass " )
@@ -798,6 +865,10 @@ if [ "$CONFIG_TPM2_TOOLS" != "y" ]; then
798865 shift
799866 calc_pcr " sha1" " $@ "
800867 ;;
868+ recalculate_firmware_pcr_from_cbfs)
869+ shift
870+ recalculate_firmware_pcr_from_cbfs " sha1"
871+ ;;
801872 counter_create)
802873 shift
803874 tpm1_counter_create " $@ "
@@ -846,6 +917,9 @@ calcfuturepcr)
846917calc_pcr)
847918 calc_pcr " sha256" " $@ "
848919 ;;
920+ recalculate_firmware_pcr_from_cbfs)
921+ recalculate_firmware_pcr_from_cbfs " sha256"
922+ ;;
849923extend)
850924 tpm2_extend " $@ "
851925 ;;
0 commit comments