heads icon indicating copy to clipboard operation
heads copied to clipboard

WiP: introspection - replicate TPM PCRs measurements directly from measured content (TCPA/TPM Event log)

Open tlaurion opened this issue 1 year ago • 9 comments

Documented in commits as of now, particularly https://github.com/linuxboot/heads/commit/8701d1410e586ca03f18d75a4d0b28e31ecd7ec3. Will progress after reviewing coreboot codebase and maybe even open issues since there is already discrepencies for FMAP extraction/measurements as of now. See commit for details.

This is to give practical context (vs theoritical content as comment+ https://github.com/linuxboot/heads-wiki/issues/107#issuecomment-1868544310) on what is attempted to be done to address current RFC comments:

  • @marmarek comment https://github.com/linuxboot/heads-wiki/issues/107#issuecomment-1869871653
  • @krystian-hebel comment https://github.com/linuxboot/heads-wiki/issues/107#issuecomment-1872561696
  • @DemiMarie tagging you because I think this will interest you.

At term

  • tpmr helper script will have functional tpmr calc_pcr, useable externall through introspect functions to be able to replicate measured content outside of coreboot measured boot code:
    • Take cbmem accessible memory to extract FMAP and properly measure it the same way coreboot measures it in measured boot code
    • Use cbfs to access mapped CBFS filesystem to validate (instrospect) sealed TOTP/HOTP/TPM DUK parts, by being able to validate files integrity
  • Finaly attain #523. If we can validate current state, we will be able to eventually seal content of future calculated PCRs content from those introspection helpers, applied to ROM to be flashed instead of validating runtime accessible content.

Let's go back to the basics.

Coreboot measured boot does its thing, leading to TPM PCRs being extended by:

~ # cbmem -L
coreboot TPM log:

 PCR-2 5622416ea417186aa1ac32b32c527ac09009fb5e SHA1 [FMAP: FMAP]
 PCR-2 8bbaeca78eb7e169df69d3687258318b58c8671e SHA1 [CBFS: bootblock]
 PCR-2 73ccefadc0a1be8184be89800e69186a260ebe40 SHA1 [CBFS: fallback/romstage]
 PCR-2 d697f8c98ef6f1b4aca397821e176bb48a227212 SHA1 [CBFS: fallback/postcar]
 PCR-2 b88302e3a46fb7fb11b92730d05c41b5f1f11bcf SHA1 [CBFS: fallback/ramstage]
 PCR-2 b688d567b0dfe1e1c6e4584289619a525b85cbd6 SHA1 [CBFS: bootsplash.jpg]
 PCR-2 9130eeb4cfe031edeabc56e6b84812d49a5a6bda SHA1 [CBFS: fallback/payload]

Current code is coreboot+heads extend operations of PCRs, leading to sealing/unsealing of secrets.

NOTE: THIS IS NON-HOTP UNDER QEMU (qemu-coreboot-whiptail-tpm1 board) which has DEBUG/TRACE activated in board config by default

On boot in debug mode, one can see:

[    6.367615] DEBUG: Debug output enabled from board CONFIG_DEBUG_OUTPUT=y option (/etc/config)
[    6.397918] TRACE: Under init
[    6.568554] TRACE: Under /bin/tpmr
[    6.713454] TRACE: Under /bin/cbfs-init
[    6.871008] DEBUG: Extending TPM PCR 7 with /.gnupg/pubring.kbx
[    6.993091] TRACE: Under /bin/tpmr
[    7.068339] DEBUG: Direct translation from tpmr to tpm1 call
[    7.117974] DEBUG: exec tpm extend -ix 7 -if /tmp/cbfs.106
[    7.308879] DEBUG: Extending TPM PCR 7 with /.gnupg/trustdb.gpg
[    7.425651] TRACE: Under /bin/tpmr
[    7.508279] DEBUG: Direct translation from tpmr to tpm1 call
[    7.557995] DEBUG: exec tpm extend -ix 7 -if /tmp/cbfs.106

when sealing/resealing TOTP/HOTP:

[   20.436488]  !!! ERROR: Unable to unseal TOTP secret !!!
[   22.492932] DEBUG: CONFIG_TPM: y
[   22.543257] DEBUG: CONFIG_TPM2_TOOLS:
[   22.608812] DEBUG: Show PCRs
[   22.803776] DEBUG: PCR-00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   22.840741] PCR-01: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   22.881815] PCR-02: 29 5B FA C8 71 8E DC 56 38 FF 41 AC 24 42 1B 05 71 15 E9 9A
[   22.918112] PCR-03: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   22.954170] PCR-04: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   22.992496] PCR-05: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   23.026032] PCR-06: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   23.059503] PCR-07: B8 85 CF DE 4E B8 CA 55 B4 05 2D 02 C2 F4 74 D4 21 00 3C 4C
[   36.867188] TRACE: Under /bin/gui-init:generate_totp_hotp
[   36.967579] TRACE: Under /bin/seal-totp
[   37.052311] DEBUG: Sealing TOTP with actual state of PCR0-3
[   37.171910] TRACE: Under /bin/tpmr
[   37.253669] TRACE: Under /bin/tpmr:tpm1_pcrread
[   37.305168] DEBUG: tpm pcrread -ix 0
[   37.443424] TRACE: Under /bin/tpmr
[   37.517793] TRACE: Under /bin/tpmr:tpm1_pcrread
[   37.566605] DEBUG: tpm pcrread -ix 1
[   37.693229] TRACE: Under /bin/tpmr
[   37.753872] TRACE: Under /bin/tpmr:tpm1_pcrread
[   37.810666] DEBUG: tpm pcrread -ix 2
[   37.952421] TRACE: Under /bin/tpmr
[   38.028588] TRACE: Under /bin/tpmr:tpm1_pcrread
[   38.077889] DEBUG: tpm pcrread -ix 3
[   38.168742] DEBUG: Sealing TOTP with boot state of PCR4 (Going to recovery shell extends PCR4)
[   38.269630] TRACE: Under /bin/tpmr
[   38.351576] TRACE: Under /bin/tpmr:replay_pcr
[   38.504755] DEBUG: Replayed cbmem -L clean boot state of PCR=4 ALG=sha1 : 0000000000000000000000000000000000000000
[   38.570688] DEBUG: Sealing TOTP neglecting PCR5 involvement (Dynamically loaded kernel modules are not firmware integrity attestation related)
[   38.618129] DEBUG: Sealing TOTP without PCR6 involvement (LUKS header consistency is not firmware integrity attestation related)
[   38.752815] TRACE: Under /bin/tpmr
[   38.829422] TRACE: Under /bin/tpmr:tpm1_pcrread
[   38.880416] DEBUG: tpm pcrread -ix 7
[   39.025969] TRACE: Under /bin/tpmr
[   39.091944] TRACE: Under /bin/tpmr:tpm1_seal
[   39.171009] DEBUG: tpm1_seal arguments: file=/tmp/secret/totp.key index=4d47 pcrl=0,1,2,3,4,7 pcrf=/tmp/secret/pcrf.bin sealed_size=312 pass=<empty> tpm_password=<empty>
[   39.467437] DEBUG: Running at_exit handlers
[   39.518427] TRACE: Under /bin/tpmr:cleanup_shred
[   40.948091] TRACE: Under /bin/gui-init:update_totp
[   41.071700] TRACE: Under /bin/unseal-totp
[   41.160445] TRACE: Under /bin/tpmr
[   41.233640] TRACE: Under /bin/tpmr:tpm1_unseal
[   41.339872] DEBUG: Running at_exit handlers
[   41.366528] TRACE: Under /bin/tpmr:cleanup_shred

When sealing/resealing TPM DUK:

[   41.445377] TRACE: Under /etc/functions:reseal_tpm_disk_decryption_key
[   41.475321] DEBUG: TPM Disk Unlock Key is allowed in board configs. Continuing
[   41.540213]  *** WARNING: TPM sealed Disk Unlock Key secret needs to be resealed alongside TOTP/HOTP secret ***
[   42.688732] TRACE: Under kexec-seal-key
[   42.759000] DEBUG: Devices defined for disk encryption: /dev/vda4
[   42.805561] DEBUG: No LVM volume group defined for activation
[   42.985001] DEBUG: PCR-00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   43.008100] PCR-01: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   43.036384] PCR-02: 29 5B FA C8 71 8E DC 56 38 FF 41 AC 24 42 1B 05 71 15 E9 9A
[   43.072981] PCR-03: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   43.100711] PCR-04: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   43.129680] PCR-05: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   43.158979] PCR-06: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   43.196712] PCR-07: B8 85 CF DE 4E B8 CA 55 B4 05 2D 02 C2 F4 74 D4 21 00 3C 4C
[  143.067899] DEBUG: Checking number of slots used on /dev/vda4 LUKS header
[  143.251583] DEBUG: Number of slots used on /dev/vda4 LUKS header: 2
[  143.288628] DEBUG: Slot 1 is not the only existing slot on /dev/vda4 LUKS header.
[  143.318917] DEBUG: /dev/vda4 LUKS header's slot 1 will store LUKS Disk Unlock Key that TPM will seal/unseal with TPM Disk Unlock Key passphrase
[  172.592929] TRACE: Under /bin/qubes-measure-luks
[  172.632252] DEBUG: Arguments passed to qubes-measure-luks: /dev/vda4
[  172.692086] DEBUG: Storing LUKS header for /dev/vda4 into /tmp/lukshdr-_dev_vda4
[  173.341529] DEBUG: Hashing LUKS headers into /tmp/luksDump.txt
[  174.149694] DEBUG: Removing /tmp/lukshdr-*
[  174.245129] DEBUG: Extending TPM PCR 6 with hash of LUKS headers from /tmp/luksDump.txt
[  174.353329] TRACE: Under /bin/tpmr
[  174.426883] DEBUG: Direct translation from tpmr to tpm1 call
[  174.473913] DEBUG: exec tpm extend -ix 6 -if /tmp/luksDump.txt
[  174.616760] TRACE: Under /bin/tpmr
[  174.678668] TRACE: Under /bin/tpmr:tpm1_pcrread
[  174.747086] DEBUG: tpm pcrread -ix 0
[  174.905885] TRACE: Under /bin/tpmr
[  174.967405] TRACE: Under /bin/tpmr:tpm1_pcrread
[  175.030457] DEBUG: tpm pcrread -ix 1
[  175.177769] TRACE: Under /bin/tpmr
[  175.259749] TRACE: Under /bin/tpmr:tpm1_pcrread
[  175.310981] DEBUG: tpm pcrread -ix 2
[  175.481466] TRACE: Under /bin/tpmr
[  175.561849] TRACE: Under /bin/tpmr:tpm1_pcrread
[  175.614064] DEBUG: tpm pcrread -ix 3
[  175.792765] TRACE: Under /bin/tpmr
[  175.882876] TRACE: Under /bin/tpmr:replay_pcr
[  176.040742] DEBUG: Replayed cbmem -L clean boot state of PCR=4 ALG=sha1 : 0000000000000000000000000000000000000000
[  176.103851] DEBUG: Sealing TPM Disk Unlock Key with PCR5=0 (NO additional kernel modules are loaded per board config)...
[  176.211233] TRACE: Under /bin/tpmr
[  176.292151] TRACE: Under /bin/tpmr:replay_pcr
[  176.440122] DEBUG: Replayed cbmem -L clean boot state of PCR=5 ALG=sha1 : 0000000000000000000000000000000000000000
[  176.523055] DEBUG: Precomputing TPM future value for PCR6 sealing/unsealing of TPM Disk Unlock Key...
[  176.659425] TRACE: Under /bin/tpmr
[  176.744122] TRACE: Under /bin/tpmr:replay_pcr
[  177.031080] DEBUG: Replayed cbmem -L clean boot state of PCR=6 ALG=sha1 : 01520898d3570c05f0d568c703ced659a86d07d0
[  177.154090] TRACE: Under /bin/tpmr
[  177.241526] TRACE: Under /bin/tpmr:tpm1_pcrread
[  177.299186] DEBUG: tpm pcrread -ix 7
[  177.413648] DEBUG: tpmr seal /tmp/secret/secret.key 3 0,1,2,3,4,5,6,7 /tmp/secret/pcrf.bin 312 <hidden>
[  177.556579] TRACE: Under /bin/tpmr
[  177.629027] TRACE: Under /bin/tpmr:tpm1_seal
[  177.708219] DEBUG: tpm1_seal arguments: file=/tmp/secret/secret.key index=3 pcrl=0,1,2,3,4,5,6,7 pcrf=/tmp/secret/pcrf.bin sealed_size=312 pass=<hidden> tpm_password=<empty>
[  178.059784] DEBUG: Running at_exit handlers
[  178.098162] TRACE: Under /bin/tpmr:cleanup_shred
[  178.205557] EXT4-fs (vda3): re-mounted. Opts: (null)
[  178.383950] EXT4-fs (vda3): re-mounted. Opts: (null)
[  178.457170]  *** WARNING: LUKS header hash changed under /boot/kexec_luks_hdr_hash.txt ***
[  179.534337] TRACE: Under /etc/functions:update_checksums
[  179.598859] EXT4-fs (vda3): re-mounted. Opts: (null)
[  179.697408] TRACE: Under /bin/kexec-sign-config
[  179.758587] TRACE: Under /etc/functions:assert_signable
[  179.945770] TRACE: Under /etc/ash_functions:confirm_gpg_card
[  190.293216] TRACE: Under /etc/ash_functions:enable_usb
[...]

On master, logic present trusts TCPA/TPM event log to be the "replay" base.

Current PR will try to add introspection required bases so that TCPA/TPM event log alone is not trusted, but validated. As explained in RFC under heeads-wiki, Heads packs other tools, including cbfs to read/write from/to cbfs (osresearch/flashtools built cbfs binary) and packs cbmem (coreboot) as of now which if used, would require more then FMAP+bootblock+++ compromise of coreboot base to be able to bypass Heads introspection.

I will point discussion to this so that we can now understand where we want to go instead of requestionning the base and goals of this attempt or focus more directly on what is missing, what we have and where we want to go for next steps.

tlaurion avatar Dec 31 '23 19:12 tlaurion

Edit: finally working PoC:

Execution of PoC:

sha1sum of cbmem filled up to next 512 boundary with ff:
5622416ea417186aa1ac32b32c527ac09009fb5e
TPM Event log for FMAP:
5622416ea417186aa1ac32b32c527ac09009fb5e

Content of PoC

# 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

# Calculate and print the sha1sum of the filled FMAP
echo "sha1sum of cbmem filled up to next 512 boundary with ff:"
sha1sum /tmp/secret/fmap_filled.raw | awk -F " " {'print $1'}

# Remove the /tmp/secret/ directory and all its contents
rm -rf /tmp/secret/

echo "TPM Event log for FMAP:"
cbmem -L | grep FMAP | awk -F " " {'print $2'}

tlaurion avatar Jan 03 '24 01:01 tlaurion

With 5574fb4 we can use cbmem to extract FMAP and pad it up to next 512 byte boundary with ff, and then use cbfs to extract all measured boot coreboot stages.

PoC output looks like this from recovery shell on qemu-coreboot-whiptail-tpm1 (debug+trace activated):

~ # tpmr recalculate_firmware_pcr_from_cbfs #Replay coreboot TPM event log from 
CBFS
[   92.166420] TRACE: Under /bin/tpmr
[   92.231076] TRACE: Under /bin/tpmr:recalculate_firmware_pcr_from_cbfs
[   93.048080] DEBUG: calc_pcr sha1 2 5622416ea417186aa1ac32b32c527ac09009fb5e 4f2447281786fe209dbe350a07f31c579f7059c7 1f39b9bdf52c678785c885aaee2a9e6a6ee81381 5e70311bbbff493a813682a12174d3482acfb7ec f527597d31308054375f13329ee1f12d29a3f279 b688d567b0dfe1e1c6e4584289619a525b85cbd6 69d82307aafc1f9eefeac373aa21cdf2123d5c41
[   93.083696] TRACE: Under /bin/tpmr:calc_pcr
[   93.131434] TRACE: Under /bin/tpmr:extend_pcr_state
[   93.162074] DEBUG: Initial PCR state: 0000000000000000000000000000000000000000
[   93.197414] DEBUG: Extending PCR state with argument #1: 5622416ea417186aa1ac32b32c527ac09009fb5e
[   93.264496] DEBUG: Extending PCR state with passed argument #1 hash: 5622416ea417186aa1ac32b32c527ac09009fb5e
[   93.368362] DEBUG: Extending PCR state with argument #2: 4f2447281786fe209dbe350a07f31c579f7059c7
[   93.447132] DEBUG: Extending PCR state with passed argument #2 hash: 4f2447281786fe209dbe350a07f31c579f7059c7
[   93.537201] DEBUG: Extending PCR state with argument #3: 1f39b9bdf52c678785c885aaee2a9e6a6ee81381
[   93.604202] DEBUG: Extending PCR state with passed argument #3 hash: 1f39b9bdf52c678785c885aaee2a9e6a6ee81381
[   93.688703] DEBUG: Extending PCR state with argument #4: 5e70311bbbff493a813682a12174d3482acfb7ec
[   93.752334] DEBUG: Extending PCR state with passed argument #4 hash: 5e70311bbbff493a813682a12174d3482acfb7ec
[   93.846594] DEBUG: Extending PCR state with argument #5: f527597d31308054375f13329ee1f12d29a3f279
[   93.918457] DEBUG: Extending PCR state with passed argument #5 hash: f527597d31308054375f13329ee1f12d29a3f279
[   94.026392] DEBUG: Extending PCR state with argument #6: b688d567b0dfe1e1c6e4584289619a525b85cbd6
[   94.099127] DEBUG: Extending PCR state with passed argument #6 hash: b688d567b0dfe1e1c6e4584289619a525b85cbd6
[   94.204186] DEBUG: Extending PCR state with argument #7: 69d82307aafc1f9eefeac373aa21cdf2123d5c41
[   94.283342] DEBUG: Extending PCR state with passed argument #7 hash: 69d82307aafc1f9eefeac373aa21cdf2123d5c41
[   94.388297] DEBUG: Extended final PCR state: 9eab5af574049405f221292585b01c85cc53872a
[   94.443378] DEBUG: Replayed cbmem -L clean boot state of PCR=2 ALG=sha1 : 9eab5af574049405f221292585b01c85cc53872a
9eab5af574049405f221292585b01c85cc53872a
[   94.640554] DEBUG: Actual TPM PCR-02: 9E AB 5A F5 74 04 94 05 F2 21 29 25 85 B0 1C 85 CC 53 87 2A
[   94.708640] DEBUG: TPM event log reported by cbmem -L: coreboot TPM log:
[   94.748215] 
[   94.819908] PCR-2 5622416ea417186aa1ac32b32c527ac09009fb5e SHA1 [FMAP: FMAP]
[   94.861644] PCR-2 4f2447281786fe209dbe350a07f31c579f7059c7 SHA1 [CBFS: bootblock]
[   94.885169] PCR-2 1f39b9bdf52c678785c885aaee2a9e6a6ee81381 SHA1 [CBFS: fallback/romstage]
[   94.961600] PCR-2 5e70311bbbff493a813682a12174d3482acfb7ec SHA1 [CBFS: fallback/postcar]
[   94.994400] PCR-2 f527597d31308054375f13329ee1f12d29a3f279 SHA1 [CBFS: fallback/ramstage]
[   95.044307] PCR-2 b688d567b0dfe1e1c6e4584289619a525b85cbd6 SHA1 [CBFS: bootsplash.jpg]
[   95.082265] PCR-2 69d82307aafc1f9eefeac373aa21cdf2123d5c41 SHA1 [CBFS: fallback/payload]

It looks like we could add helpers in Makefile to manipulate, post rom assembly per coreboot, an additional forward sealing file containing the expected PCR value for PCR2 for next steps.

Here, the question is what we would want to do with that

  • Validate sealed PCR2 values of firmware prior of calling totp unseal?
  • Flash new firmware and then do the forward resealing of TPM DUK?

tlaurion avatar Jan 03 '24 07:01 tlaurion

With 5bd19f4 on qemu-coreboot-whiptail-tpm2 (with DEBUG/TRACE activated per board config):

~ # tpmr recalculate_firmware_pcr_from_cbfs #Replay coreboot TPM event log from 
CBFS
[   30.736989] TRACE: Under /bin/tpmr
[   30.800904] TRACE: Under /bin/tpmr:recalculate_firmware_pcr_from_cbfs
[   31.497773] DEBUG: calc_pcr sha256 2 02778dad5303b911adc8828cf5101a251a9b2a5a2b711a44159fb89a5a0b5198 f42df98aeda999e2d9e5e5208668a78e1b7bdda5d02600cf4947591f35c67121 3e371b3ffe51f7ee1d483026ca004f0e0d4432de8103c4c1de31011a94fb1612 1b4f09549008ae961072514b397f2e391aa4d9e6c48a673e87c8a12c17be113a 284e7103b372e7ab1ccf3077ba49a754c06d976f33ad74da1bdb7467fa319c19 bc172d6c3551a44fbd6beef7ebbb2d4fa1452c46fcfdeebef1c519f13d668f1b 829573af425b78fa1bb7cb9cfcb61f520d5063f3c3ba2f93d806dedb3af79ac5
[   31.535528] TRACE: Under /bin/tpmr:calc_pcr
[   31.584183] TRACE: Under /bin/tpmr:extend_pcr_state
[   31.622667] DEBUG: Initial PCR state: 0000000000000000000000000000000000000000000000000000000000000000
[   31.693083] DEBUG: Extending PCR state with passed argument #1 hash: 02778dad5303b911adc8828cf5101a251a9b2a5a2b711a44159fb89a5a0b5198
[   31.806253] DEBUG: Extending PCR state with passed argument #2 hash: f42df98aeda999e2d9e5e5208668a78e1b7bdda5d02600cf4947591f35c67121
[   31.911070] DEBUG: Extending PCR state with passed argument #3 hash: 3e371b3ffe51f7ee1d483026ca004f0e0d4432de8103c4c1de31011a94fb1612
[   32.017774] DEBUG: Extending PCR state with passed argument #4 hash: 1b4f09549008ae961072514b397f2e391aa4d9e6c48a673e87c8a12c17be113a
[   32.151362] DEBUG: Extending PCR state with passed argument #5 hash: 284e7103b372e7ab1ccf3077ba49a754c06d976f33ad74da1bdb7467fa319c19
[   32.281688] DEBUG: Extending PCR state with passed argument #6 hash: bc172d6c3551a44fbd6beef7ebbb2d4fa1452c46fcfdeebef1c519f13d668f1b
[   32.416306] DEBUG: Extending PCR state with passed argument #7 hash: 829573af425b78fa1bb7cb9cfcb61f520d5063f3c3ba2f93d806dedb3af79ac5
[   32.522296] DEBUG: Extended final PCR state: ed1bbd19fceca6f7028e4eb97e6854e6ec24bc084e501b049cec0d19e0de82cd
[   32.580794] DEBUG: Replayed cbmem -L clean boot state of PCR=2 ALG=sha256 : ed1bbd19fceca6f7028e4eb97e6854e6ec24bc084e501b049cec0d19e0de82cd
ed1bbd19fceca6f7028e4eb97e6854e6ec24bc084e501b049cec0d19e0de82cd
[   32.754666] DEBUG: Actual TPM     2 : 0xED1BBD19FCECA6F7028E4EB97E6854E6EC24BC084E501B049CEC0D19E0DE82CD
[   32.846124] DEBUG: TPM event log reported by cbmem -L: coreboot TPM log:
[   32.902556] 
[   32.950721] PCR-2 02778dad5303b911adc8828cf5101a251a9b2a5a2b711a44159fb89a5a0b5198 SHA256 [FMAP: FMAP]
[   32.976485] PCR-2 f42df98aeda999e2d9e5e5208668a78e1b7bdda5d02600cf4947591f35c67121 SHA256 [CBFS: bootblock]
[   33.048439] PCR-2 3e371b3ffe51f7ee1d483026ca004f0e0d4432de8103c4c1de31011a94fb1612 SHA256 [CBFS: fallback/romstage]
[   33.093232] PCR-2 1b4f09549008ae961072514b397f2e391aa4d9e6c48a673e87c8a12c17be113a SHA256 [CBFS: fallback/postcar]
[   33.140986] PCR-2 284e7103b372e7ab1ccf3077ba49a754c06d976f33ad74da1bdb7467fa319c19 SHA256 [CBFS: fallback/ramstage]
[   33.178227] PCR-2 bc172d6c3551a44fbd6beef7ebbb2d4fa1452c46fcfdeebef1c519f13d668f1b SHA256 [CBFS: bootsplash.jpg]
[   33.240108] PCR-2 829573af425b78fa1bb7cb9cfcb61f520d5063f3c3ba2f93d806dedb3af79ac5 SHA256 [CBFS: fallback/payload]

tlaurion avatar Jan 03 '24 18:01 tlaurion

Interesting helpers at https://github.com/TrenchBoot/qubes-antievilmaid/pull/11

tlaurion avatar Apr 16 '24 14:04 tlaurion

@DemiMarie thanks for the early code review, but the reason I poked you here was to get your input on how trivial it is today to tamper bootblock and measured boot together, with end PCR bank values sealed/unsealed for secret release. How quotes would make it better, not really to get code review on PoC code material.

This PR lay down the technical details for anyone to tamper coreboot measured boot scheme (either tamper with coreboot bootblock + phases to report their prior known hardcoded hashes instead of passing content to be hashed that extend PCR today), alongside with also hacking Heads to hardcode LUKS header hash, CBFS generated+injected pubring + trustdb+config overrides (PCR7), kernel module hashes (PCR5) to permit, while passing real TPM DUK passphrase of the end user (rate limited), to unseal LUKS key to final OS through additional cpio passed to kexec call to final OS, so end users type Disk Encryption Key (TPM DUK) related secret in a known safe space.

In other words: how to attack this and pass from "bootblock based root of trust theoretically flawed and unfit" to a successful attack showing measured boot + Heads(sealing/unsealing both firmware remote attestation TPMTOTP and runtime attestation prior of TPM DUK unsealing with TPM DUK passphrase) not good enough AND leading to TPM DUK being released into cpio passed to kexec call with user provided TPM DUK nvram region, authenticated with both replayed (tampered) measurements and proper nvram passphrase, leading to save that passphrase somewhere or saving TPM released DUK key somewhere to capture, and how all of this would not leave an attacked to implant a keyboard sniffer instead and where any of what is discussed here would change anything anyway, and is the simplest attack an attacker would do to simply implant and come back next days to steal the computer altogether, not having to do any of the complex stuff we are talking about here.


For reference, see https://forum.qubes-os.org/t/discussion-on-purism/2627/158 which points back here. I have left enough e-ink everywhere and nobody actually used this PR code to prove theoretical attack becoming practical, and where safeguarding bootblock behind WP/externally enforced tamper evidence would be a solution to all of this.


Also note and follow: https://forum.qubes-os.org/t/flashkeeper-the-solution-to-spi-flash-firmware-tampering/28028/5

“FlashKeeper: where SpiSpy meets Stateless Laptop jaded dreams: A retrofit plan first” will take place at 09-20, 15:10 in Social Hub Main Room.

Which will be presented/design decisions challenged at QubesOS mini-summit 2024 where I will present and have a chance to discuss all of this in details, maybe even around a beer later on at night. @DemiMarie : looking forward to this. -> https://www.qubes-os.org/news/2024/08/11/qubes-os-summit-2024-tickets-now-available/


MEANWHILE TECHNICAL PEOPLE, I remind you that you can play with qemu-whiptail-tpm1/tpm2 board configs directly today: which enforces a sniffable (pcap) virtual TPM, a virtual OpenGPG card, everything needed basically test all of this without needing any physical hardware to render an evil maid PoC based on this PR PoC and follow the white rabiit in this hole, equipped only with docker ce alone to build reproducible Heads images right now and provide practical PoC of an evil maid attack.

Follow:

  • https://github.com/linuxboot/heads/blob/master/targets/qemu.md#swtpm-on-nix-docker-image
  • ie
    • docker run -e DISPLAY=$DISPLAY --network host --rm -ti -v $(pwd):$(pwd) -w $(pwd) tlaurion/heads-dev-env:latest -- make BOARD=qemu-coreboot-whiptail-tpm2
    • docker run -e DISPLAY=$DISPLAY --network host --rm -ti -v $(pwd):$(pwd) -w $(pwd) tlaurion/heads-dev-env:latest -- make BOARD=qemu-coreboot-whiptail-tpm2 run
    • Do OEM Factory Resetf wizard, follow notes in referred link above on how to extract public key from emulated SUB Thumb drive (losetup, mount, cp under heads dir), then point to it in next command
    • docker run -e DISPLAY=$DISPLAY --network host --rm -ti -v $(pwd):$(pwd) -w $(pwd) tlaurion/heads-dev-env:latest -- make BOARD=qemu-coreboot-whiptail-tpm2 PUBKEY_ASC=<path_to_key.asc> inject_gpg
    • docker run -e DISPLAY=$DISPLAY --network host --rm -ti -v $(pwd):$(pwd) -w $(pwd) tlaurion/heads-dev-env:latest -- make BOARD=qemu-coreboot-whiptail-tpm2 PUBKEY_ASC=<path_to_key.asc> run
    • You will of course need to follow ISO OS install notes in above referred docs (just point to iso in heads local dir) to fully test TPM DUK etc on a working simulated setup following https://osresearch.net/InstallingOS/#generic-os-installation
  • other usage notes in that direct link, above. This will provide OP similar TRACE+DEBUG output traces on dual consoles, permitting you to hack this efficiently. So please do it.

Bounty tag added (I won't pay, who would?) IF you prove this flawed practically, the whole coreboot ecosystem, Heads and all coreboot enforced, reasonably secure platforms would benefit of that vuln, you would have a CVE in your name and shake the future of trustworthy computing forever for the better. So please do it if you think bootblock enforced RoT is not enough.

tlaurion avatar Aug 12 '24 14:08 tlaurion

@tlaurion Bootblock-based root of trust is already known to be broken unless either Intel Boot Guard/AMD Platform Secure Boot is in use or the bootblock cannot be tampered with. Chromebooks ensure this by putting it in a SPI chip with the write protect pin always enabled in hardware.

DemiMarie avatar Aug 15 '24 20:08 DemiMarie