-
-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WiP: introspection - replicate TPM PCRs measurements directly from measured content (TCPA/TPM Event log) #1568
base: master
Are you sure you want to change the base?
Conversation
TRACE "Under /bin/tpmr:calc_pcr" | ||
if [ -z "$2" ]; then | ||
echo >&2 "No PCR number passed" | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will return a successful status to the caller. Should this be return 1
or even exit 1
?
fi | ||
if [ "$2" -ge 8 ]; then | ||
echo >&2 "Illegal PCR number ($2)" | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
# SHA-1 hashes are 40 chars | ||
if [ "$alg" = "sha1" ]; then alg_digits=40; fi | ||
# SHA-256 hashes are 64 chars | ||
if [ "$alg" = "sha256" ]; then alg_digits=64; fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# SHA-1 hashes are 40 chars | |
if [ "$alg" = "sha1" ]; then alg_digits=40; fi | |
# SHA-256 hashes are 64 chars | |
if [ "$alg" = "sha256" ]; then alg_digits=64; fi | |
case $alg in | |
(sha1) | |
# SHA-1 hashes are 40 chars | |
alg_digits=40;; | |
(sha256) | |
# SHA-256 hashes are 64 chars | |
alg_digits=64;; | |
(*) | |
# Invalid | |
printf 'Invalid hash algorithm %s\n' "$alg" >&2 | |
exit 1;; | |
esac |
initrd/bin/tpmr
Outdated
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
echo $replayed_pcr | hex2bin | |
printf %s\\n "$replayed_pcr" | hex2bin |
Edit: finally working PoC: Execution of PoC:
Content of PoC
|
8701d14
to
51231f3
Compare
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):
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
|
initrd/bin/tpmr
Outdated
# 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cbmem --rawdump $(cbmem -l | grep FMAP | awk -F " " {'print $3'}) >/tmp/secret/fmap.raw | |
arg=$(cbmem -l | grep FMAP | awk -F " " {'print $3'}) | |
cbmem --rawdump "$arg" >/tmp/secret/fmap.raw |
Hopefully shellcheck catches this.
initrd/bin/tpmr
Outdated
$(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'}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Command substitutions should not be used in command arguments, as failure of the command is ignored. Instead, they should be assigned to a temporary variable.
With 5bd19f4 on qemu-coreboot-whiptail-tpm2 (with DEBUG/TRACE activated per board config):
|
5bd19f4
to
ad79a93
Compare
…nks @githubisnonfree!) - Addition of ifdtool from coreboot project to extract gbe - As of now, its implemented in a hacky way: - ifdtool dir is copied over ifdtool_cross at coreboot's module configure step - then initrd packing step checks for CONFIG_NVMUTIL and builds and pack ifdtool_cross/ifdtool - As a result, what is build under build/coreboot/$BOARD is coreboot's real, where build/coreboot/ content follows Makefile rules - CONFIG_NVMUTIL in board config adds both ifdtool_cross/ifdtool and nvmutil into initrd - Added CONFIG_NVMUTIL to all hotp-maximized boards (to test for size changes) Manually tested (working!): - backup rom from: `flashrom -p internal -r /tmp/backup.rom` - go to that dir: `cd /tmp` - extract gbe from ifdtool on backup.rom: `ifdtool -x backup.rom` - source shell functions: `. /etc/functions` - show current PHY mac address: `nvm showmac flashregion_3_gbe.bin` - generate mac address from sourced shell functions: `newmac=$(generate_random_mac_address)` - show new mac: `echo $newmac` - change mac from nvmtool on extracted gbe: `nvm flashregion_3_gbe.bin setmac $newmac` - insert modified gbe into backup.rom.new with ifdtool: `ifdtool -i gbe:flashregion_3_gbe.bin backup.rom` - flash back modified gbe only through flashrom: `flashrom -p internal --ifd -i gbe -w backup.rom.new` Signed-off-by: Thierry Laurion <[email protected]>
…fstool/ifdtool to get same cbmem -L/TPM eventlog/introspection of PRC content equivalence Signed-off-by: Thierry Laurion <[email protected]>
…uring files/strings to arrive to same cbmem -L (TCPA/Event log content from real measured stuff) Traces: When looking at TCPA log/TPM Event log: ~ # 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] We see that PCR2 is extended from reset state (40*0) with: FMAP (only one not under cbfs), bootblock, fallback/romstage, fallback/postcar, fallback/ramstage, bootsplash.jpg, fallback/payload cbmem permits to extract FMAP from cbmem: ~ # cbmem --rawdump $(cbmem -l | grep FMAP | awk -F " " {'print $3'}) | xxd 00000000: 5f5f 464d 4150 5f5f 0101 0000 60ff 0000 __FMAP__....`... 00000010: 0000 0000 a000 464c 4153 4800 0000 0000 ......FLASH..... 00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000030: 0000 0000 0000 0300 0000 0800 0000 9800 ................ 00000040: 4249 4f53 0000 0000 0000 0000 0000 0000 BIOS............ 00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000060: 0000 0000 0800 0002 0000 464d 4150 0000 ..........FMAP.. 00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000080: 0000 0000 0000 0000 0000 0000 0002 0800 ................ 00000090: 00fe 9700 434f 5245 424f 4f54 0000 0000 ....COREBOOT.... 000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000b0: 0000 0000 0000 ...... ~ # xxd -r cbmem.txt | sha1sum 6ecd73787c001bbc1215bd8787361e1a63b580cb - This sha1sum doesn't match reported TCPA/Event log for FMAP entry: 6ecd73787c001bbc1215bd8787361e1a63b580cb != 5622416ea417186aa1ac32b32c527ac09009fb5e FMAP extracted from cbfsutil externally from ROM image is padded with ff up to 512 bytes (this is dynamic and cannot be hardcoded magic): user@heads-tests-deb12:~/heads$ sudo cbfstool ~/heads/build/x86/qemu-coreboot-whiptail-tpm1/heads-qemu-coreboot-whiptail-tpm1-v0.2.0-1955-gfff99df-dirty.rom read -r FMAP -f xxx.bin user@heads-tests-deb12:~/heads$ xxd xxx.bin > hex.txt user@heads-tests-deb12:~/heads$ cat hex.txt 00000000: 5f5f 464d 4150 5f5f 0101 0000 60ff 0000 __FMAP__....`... 00000010: 0000 0000 a000 464c 4153 4800 0000 0000 ......FLASH..... 00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000030: 0000 0000 0000 0300 0000 0800 0000 9800 ................ 00000040: 4249 4f53 0000 0000 0000 0000 0000 0000 BIOS............ 00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000060: 0000 0000 0800 0002 0000 464d 4150 0000 ..........FMAP.. 00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000080: 0000 0000 0000 0000 0000 0000 0002 0800 ................ 00000090: 00fe 9700 434f 5245 424f 4f54 0000 0000 ....COREBOOT.... 000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000b0: 0000 0000 0000 ffff ffff ffff ffff ffff ................ 000000c0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000000d0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000000e0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000000f0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000100: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000110: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000120: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000130: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000140: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000150: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000160: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000170: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000180: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000190: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000001a0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000001b0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000001c0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000001d0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000001e0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000001f0: ffff ffff ffff ffff ffff ffff ffff ffff ................ user@heads-tests-deb12:~/heads$ xxd -r hex.txt | sha1sum 5622416ea417186aa1ac32b32c527ac09009fb5e - This matches FMAP region measured in TCPA/TPM event log for FMAP trace above: 6ecd73787c001bbc1215bd8787361e1a63b580cb = 6ecd73787c001bbc1215bd8787361e1a63b580cb It seems that coreboot measured boot code does the same as cbfstool (padding prior of measuring) instead of taking only the raw output we could replicate with cbfs.... Signed-off-by: Thierry Laurion <[email protected]>
…fsutil/nvmutil for this task. cbmem+cbfs is enough Signed-off-by: Thierry Laurion <[email protected]>
…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]>
Signed-off-by: Thierry Laurion <[email protected]>
…r comparison Buggy as of now, will reverify next week ~ # tpmr verify_coreboot_measured_boot_tpm_event_log_vs_content_measured #Valida te coreboot TPM event log against cbmem FMAP+cbfs content [ 293.267413] TRACE: Under /bin/tpmr [ 293.390454] TRACE: Under /bin/tpmr [ 293.441752] TRACE: Under /bin/tpmr:replay_pcr [ 293.551759] TRACE: Under /bin/tpmr:extend_pcr_state [ 293.574966] DEBUG: Initial PCR state: 0000000000000000000000000000000000000000000000000000000000000000 [ 293.639890] DEBUG: Extending PCR state with passed argument #1 hash: 02778dad5303b911adc8828cf5101a251a9b2a5a2b711a44159fb89a5a0b5198 [ 293.761500] DEBUG: Extending PCR state with passed argument #2 hash: 5444dba991b48df882ed1e2b85f0c90f947f6c7f8ed3dd6c91dc70dd661b66cb [ 293.899682] DEBUG: Extending PCR state with passed argument #3 hash: 13d3cacde02deff3d5e1ae2b52e5647c67046fb359b58d3899365a87a7161090 [ 294.028814] DEBUG: Extending PCR state with passed argument #4 hash: cea785e25dfdc94b8296a0a2bcc75d2f44f93543d0eb4236a0efa5add87fc97a [ 294.137824] DEBUG: Extending PCR state with passed argument #5 hash: bb2ff5833f90c09916fb972f49963653cf207cc65033276d458e00ce31d4b3d7 [ 294.259655] DEBUG: Extending PCR state with passed argument #6 hash: bc172d6c3551a44fbd6beef7ebbb2d4fa1452c46fcfdeebef1c519f13d668f1b [ 294.400277] DEBUG: Extending PCR state with passed argument linuxboot#7 hash: bf037ed20105da5af9affb40353a4bccc9c8e69f2b03b81260573821ccbfa6d8 [ 294.514983] DEBUG: Extended final PCR state: ab50d5acd93870448844392a2582099650614e0c75f3b6c3f3a5f7a811ab3bca [ 294.561181] DEBUG: Replayed cbmem -L clean boot state of PCR=2 ALG=sha256 : ab50d5acd93870448844392a2582099650614e0c75f3b6c3f3a5f7a811ab3bca [ 294.699187] TRACE: Under /bin/tpmr [ 294.765450] TRACE: Under /bin/tpmr:recalculate_firmware_pcr_from_cbfs [ 294.812153] TRACE: Under /bin/tpmr:read_and_pad_FMAP_from_cbmem [ 295.853558] TRACE: Under /bin/tpmr:calc_pcr [ 295.909978] TRACE: Under /bin/tpmr:extend_pcr_state [ 295.955343] DEBUG: Initial PCR state: 0000000000000000000000000000000000000000000000000000000000000000 [ 296.036572] DEBUG: Extending PCR state with passed argument #1 hash: 02778dad5303b911adc8828cf5101a251a9b2a5a2b711a44159fb89a5a0b5198 [ 296.196037] DEBUG: Extending PCR state with passed argument #2 hash: 5444dba991b48df882ed1e2b85f0c90f947f6c7f8ed3dd6c91dc70dd661b66cb [ 296.364665] DEBUG: Extending PCR state with passed argument #3 hash: 13d3cacde02deff3d5e1ae2b52e5647c67046fb359b58d3899365a87a7161090 [ 296.528953] DEBUG: Extending PCR state with passed argument #4 hash: cea785e25dfdc94b8296a0a2bcc75d2f44f93543d0eb4236a0efa5add87fc97a [ 296.683826] DEBUG: Extending PCR state with passed argument #5 hash: bb2ff5833f90c09916fb972f49963653cf207cc65033276d458e00ce31d4b3d7 [ 296.843403] DEBUG: Extending PCR state with passed argument #6 hash: bc172d6c3551a44fbd6beef7ebbb2d4fa1452c46fcfdeebef1c519f13d668f1b [ 297.011405] DEBUG: Extending PCR state with passed argument linuxboot#7 hash: bf037ed20105da5af9affb40353a4bccc9c8e69f2b03b81260573821ccbfa6d8 [ 297.142107] DEBUG: Extended final PCR state: ab50d5acd93870448844392a2582099650614e0c75f3b6c3f3a5f7a811ab3bca [ 297.200198] DEBUG: Replayed cbmem -L clean boot state of PCR=2 ALG=sha256 : ab50d5acd93870448844392a2582099650614e0c75f3b6c3f3a5f7a811ab3bca [ 297.375755] DEBUG: Original TPM PCR2 value: 2 : 0xAB50D5ACD93870448844392A2582099650614E0C75F3B6C3F3A5F7A811AB3BCA [ 297.438635] DEBUG: TPM event log reported by cbmem -L: coreboot TPM log: [ 297.472275] [ 297.514744] PCR-2 02778dad5303b911adc8828cf5101a251a9b2a5a2b711a44159fb89a5a0b5198 SHA256 [FMAP: FMAP] [ 297.559260] PCR-2 5444dba991b48df882ed1e2b85f0c90f947f6c7f8ed3dd6c91dc70dd661b66cb SHA256 [CBFS: bootblock] [ 297.594767] PCR-2 13d3cacde02deff3d5e1ae2b52e5647c67046fb359b58d3899365a87a7161090 SHA256 [CBFS: fallback/romstage] [ 297.632653] PCR-2 cea785e25dfdc94b8296a0a2bcc75d2f44f93543d0eb4236a0efa5add87fc97a SHA256 [CBFS: fallback/postcar] [ 297.688218] PCR-2 bb2ff5833f90c09916fb972f49963653cf207cc65033276d458e00ce31d4b3d7 SHA256 [CBFS: fallback/ramstage] [ 297.723743] PCR-2 bc172d6c3551a44fbd6beef7ebbb2d4fa1452c46fcfdeebef1c519f13d668f1b SHA256 [CBFS: bootsplash.jpg] [ 297.760327] PCR-2 bf037ed20105da5af9affb40353a4bccc9c8e69f2b03b81260573821ccbfa6d8 SHA256 [CBFS: fallback/payload] [ 297.823487] DEBUG: Calculated TPM PCR2 value from files: ab50d5acd93870448844392a2582099650614e0c75f3b6c3f3a5f7a811ab3bca [ 297.872171] DEBUG: Measured boot from TPM event log: ab50d5acd93870448844392a2582099650614e0c75f3b6c3f3a5f7a811ab [ 297.905953] 3bca [ 297.955757] DEBUG: Measured boot from content measured by coreboot: ab50d5acd93870448844392a2582099650614e0c75f3b6c3f3a5f7a811ab3bca Failed: TPM event log does not match content measured by coreboot [ 298.008151] !!! ERROR: TPM event log does not match content measured by coreboot !!! the 3cba on second line is weird. Close but not good enough Signed-off-by: Thierry Laurion <[email protected]>
ad79a93
to
bf7677c
Compare
Interesting helpers at TrenchBoot/qubes-antievilmaid#11 |
@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. Also note and follow: https://forum.qubes-os.org/t/flashkeeper-the-solution-to-spi-flash-firmware-tampering/28028/5
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. 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:
Bounty tag added (I won't pay, who would?) |
@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. |
Prerequisite was merged #1824 |
This is prerequisite for #1827 (comment) Reasoning: Practical needs here outside of a firmware upgrade:
On firmware upgrade:
In lack of doing so, Heads UX stays complicated. |
Documented in commits as of now, particularly 8701d14. 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+ linuxboot/heads-wiki#107 (comment)) on what is attempted to be done to address current RFC comments:
At term
Let's go back to the basics.
Coreboot measured boot does its thing, leading to TPM PCRs being extended by:
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:
when sealing/resealing TOTP/HOTP:
When sealing/resealing TPM DUK:
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.