Measured Boot: The TCG Event Log from SRTM to PCR-Bound BitLocker
How Windows turns every byte of firmware, every signed boot manager, and every loaded driver into a single 32-byte hash that decides whether BitLocker unlocks your disk -- and why patching that chain breaks it.
Permalink1. Two PCs That Hash Differently
At 06:00 on a Tuesday in March 2024, a senior administrator at a 500-seat law firm finishes patching her fleet of Dell OptiPlex 7090s overnight. At 08:42 she has answered her 173rd help-desk ticket, all variations on the same theme: Why is my laptop asking for a 48-digit BitLocker recovery key? The answer -- the answer the rest of this article exists to make obvious -- is that a single 32-byte SHA-256 register on every machine in her fleet now holds a different number than it did yesterday, and BitLocker's seal is bound to that number.
The patch she applied to make the fleet safer is the patch that locked it out.
Across town a second firm runs Secured-core PCs that ship with System Guard Secure Launch enabled. Those machines absorb the same overnight UEFI delta without a single recovery prompt. Same vendor patch. Same Microsoft cumulative update. Same hour. Zero tickets. The difference is not the hardware; the difference is which subset of TPM registers BitLocker bound the disk-encryption key to.
A fixed-width append-only register inside a Trusted Platform Module. PCRs do not store; they extend. The TPM rewrites PCR[N] := H(PCR[N] || measurement), where H is a cryptographic hash. PCRs reset to zero only at platform reset. A modern TPM 2.0 has 24 PCRs per hash bank, with banks for SHA-1, SHA-256, SHA-384, SHA-512, and SM3-256.
A boot mode in which every stage of platform initialisation hashes the next stage's code and configuration into one or more PCRs before transferring control. Measured Boot is reporting, not enforcement -- it records what ran, but does not refuse to run anything. Secure Boot is the enforcement counterpart that refuses unsigned code; the two cooperate. Microsoft's Trusted Boot extends the measurement chain into the Windows kernel.
By the end of this article you will be able to name every byte that went into that hash, predict whether any given administrative action will change it, and read the TCG event log on your own machine to confirm. You will see why the BitLocker seal is, in some configurations, a Faraday cage built on top of a fence the verifier never opened. You will learn that the chip Microsoft calls the Trusted Platform Module knows nothing of trust -- only of arithmetic over hashes -- and that the verifier, which knows what good looks like, is always someone other than the chip.
But first, the historical answer: how did a 32-byte register get into the position of deciding whether a PC boots cleanly or asks for a 48-digit key?
2. Origins: Arbaugh 1997 and the Chain-of-Hashes Axiom
The first paper to take the boot problem seriously is also one of the calmest. In 1997, three researchers at the University of Pennsylvania Distributed Systems Laboratory -- William A. Arbaugh, David J. Farber, and Jonathan M. Smith -- presented A Secure and Reliable Bootstrap Architecture at the IEEE Symposium on Security and Privacy in Oakland. They opened with a line that ages disconcertingly well: "we find it surprising, given the great attention paid to operating system security that so little attention has been paid to the underpinnings required for secure operation, e.g., a secure bootstrapping phase for these operating systems."
They built a working prototype. A Pentium-class PC. A modified BIOS. A small PROM expansion card with public-key certificates. And, threaded through everything, an inductive structure they called AEGIS.
An ordered sequence in which each stage of platform initialisation verifies the cryptographic identity of the next stage before it executes. If every link verifies its successor, an external observer who trusts the first link transitively trusts the chain, modulo the cryptographic strength of the verification primitive.
AEGIS divided the boot into six levels (0 through 5). L0 was a small trusted ROM that ran the first POST phase, the signature-verification routines, and recovery code. L1 was the rest of the BIOS code plus CMOS. L2 was option-ROM expansion cards (the era's GPUs, network cards, SCSI controllers). L3 was the operating system boot block(s). L4 was the OS kernel. L5 was user programs and any network hosts the kernel reached. Each level verified the next before handing off; on a failed verification, L0 recovered the broken stage from a known-good network image. (The paper also presents a "four levels of abstraction" framing for one of its figures; the article uses the canonical six-level numbering.)
The smallest, lowest, most immutable code that runs after platform reset. It measures the next stage of firmware and extends that measurement into PCR[0] before transferring control. Modern PCs implement the CRTM in silicon -- Intel's Boot Guard Authenticated Code Module, AMD's Platform Security Processor firmware, or Microsoft's Pluton silicon -- because anything mutable is not actually a root of trust.
The architectural axiom that survived 28 years of evolution is this: there is always a bottom layer you cannot verify yourself. AEGIS does not eliminate that layer; it reduces trust to the smallest possible unverifiable thing. The L0 trusted ROM is the axiom; everything above it is provable from the axiom. Replace "trusted ROM" with "Boot Guard ACM" or "PSP boot ROM" or "Pluton silicon firmware" and the structure does not change.
AEGIS could not, on its own, make the next pivot. It had no hardware-rooted endorsement key. It had no append-only register that could not be lied to. It had no remote-attestation primitive -- the L0 ROM trusted itself, but an external auditor was forced to trust the BIOS's own report of the bootstrap. The trick AEGIS could not pull off is the trick the Trusted Computing Platform Alliance was about to attempt: make the root a chip.
Arbaugh continued the work at the University of Maryland and later took a senior position at the National Security Agency. The bootstrap problem followed him; in 2005 he co-authored an early TPM-on-Linux survey that anticipates several of the PCR allocation conventions that PFP would formalise.The TCPA was founded on October 11, 1999 by Compaq, Hewlett-Packard, IBM, Intel, and Microsoft. Its first specification shipped January 30, 2001. The first hardware-TPM-equipped PC shipped on the IBM ThinkPad T30 in 2002 (with a TPM 1.1-class Infineon SLB chip); the TPM 1.1b revision deployed in volume the year after. In 2003 the TCPA was reorganised as the Trusted Computing Group, with AMD joining as a founding board member.
The thing AEGIS could not do -- turn a chain of in-RAM hash comparisons into a record a remote party can trust -- is what the TPM became.
3. Early Approaches: TPM 1.1b, SHA-1, and the Original PCSI
"The first TPM version that was deployed was 1.1b in 2003" -- Wikipedia, drawing on the TCPA shipment record. A 24-pin chip in a tiny LPC-bus package, soldered to the motherboard of a ThinkPad T30. Twenty-four PCRs. One hash bank: SHA-1, 20 bytes wide. A monotonic counter. An endorsement key, fused at manufacture. A storage root key, generated at first ownership. By 2010, hundreds of millions of business PCs shipped with one. By July 28, 2016, Microsoft's Windows 10 hardware logo programme required TPM 2.0 on every new OEM Windows 10 PC -- desktop, mobile, and server alike.
The mechanic that did all the work is one operation: TPM_Extend. It takes a PCR index and a 20-byte digest. It produces a new PCR value defined as PCR[N] := SHA1(PCR[N] || digest).
The only writable mutation a TPM permits on a PCR. Given the current value P and a new measurement M, the TPM computes H(P || M) and writes the result back into the PCR. There is no set; there is no clear (PCRs reset only at platform reset, and some PCRs not even then). The hash chain is the only trace.
That two-letter primitive -- extend -- is doing more cryptographic work than its size suggests. A PCR is not a set of measurements; it is a sequence. If three boot stages measure three values a, b, c into PCR[0] in that order, the resulting PCR encodes H(H(H(0 || a) || b) || c). Reorder the stages and the final hash differs. Repeat a stage and the final hash differs. Skip a stage -- the move every rootkit dreams of -- and the final hash differs. Under collision-resistance of the underlying hash, producing the same final PCR via a different ordered sequence is computationally infeasible.
The PC Client Specific Implementation (PCSI) specification carved up the 24 PCRs of TPM 1.2 into eight indices that the world still uses today. PCR[0] holds the CRTM, the system firmware code, and the firmware host platform extensions. PCR[1] holds the host platform configuration (CMOS settings that change platform behaviour). PCR[2] holds the option ROM code. PCR[3] holds the option ROM configuration. PCR[4] holds the master boot record code (and on UEFI machines, the boot-loader image). PCR[5] holds the master boot record partition table (and on UEFI machines, the boot configuration). PCR[6] holds host platform manufacturer-specific events. PCR[7] holds host platform manufacturer events -- a category that, post-PFP, became Secure Boot policy.
A group of PCRs that share a hash algorithm. TPM 1.2 had one bank only (SHA-1). TPM 2.0 supports multiple banks simultaneously -- the same PCR index exists once per bank, with one digest per bank. A measurement into PCR[7] writes the same source bytes into every bank but produces algorithm-specific digests.
TPM 1.2 also defined the first remote-attestation primitive in industry hardware: TPM_Quote. The TPM signs a snapshot of selected PCR values plus a verifier-supplied nonce with a private key the chip alone holds (the attestation identity key, signed by a TCG-managed privacy CA). The verifier checks the signature, checks the nonce, checks the AIK certificate chain, and re-derives the expected PCR set from a TCG event log delivered separately. If the re-derivation matches the signed quote, the platform's boot history is authenticated.
It worked. For a while. Then, on February 23, 2017, the SHAttered team -- Marc Stevens (CWI Amsterdam) and Pierre Karpman (Inria) with Elie Bursztein, Ange Albertini, and Yarik Markov (Google Research) -- published the first public SHA-1 collision. Two PDF files with identical SHA-1 hashes. The collision cost about 110 GPU-years of compute. The implication for TPM 1.2 was immediate: a 20-byte SHA-1 PCR can no longer be assumed unique under attacker-controlled input.
The SHA-1 choice in 2003 was state-of-the-art at the time, not negligence. NIST's SHA-256 had been published in 2001 but was not yet broadly trusted; SHA-1 was the IETF-blessed default for X.509 and many TLS deployments. The SHAttered collision required compute that did not exist commercially in 2003. By 2017 it required compute that anyone with a Google Cloud account could buy.If the cryptographic floor is broken and you cannot re-floor in place -- a TPM 1.2 chip cannot grow a SHA-256 bank -- you replace the floor with one that can be moved. That is what TPM 2.0 became.
4. Evolution: TPM 2.0, Hash Agility, and the UEFI PFP
On April 9, 2014, the Trusted Computing Group announced the TPM Library Specification 2.0. ISO ratified the result the following year as ISO/IEC 11889-1:2015, and confirmed the standard as current in a 2021 review. The change set is large -- new algorithm framework, NV index ACLs, sessions, command authorization area, ECC primary keys -- but the line that matters for measurement is the simplest one: PCRs now exist in banks.
A property of a security system that lets operators or vendors replace one hash function with another without changing the system's interfaces. TPM 2.0 implements hash agility for PCRs (multiple banks), HMAC keys (algorithm parameter on the key), and signature primitives (algorithm parameter on the signature). Hash agility is not free: every bank costs storage, every bank costs extend cost, and the verifier must agree with the prover on which bank to use.
A TPM 2.0 chip can run a SHA-1 bank, a SHA-256 bank, and (often) a SHA-384 bank in parallel, plus optional SHA-512 and SM3-256. The same PCR index lives once per bank. A TPM2_PCR_Extend call updates every active bank with bank-specific digests; the source bytes are identical but the output is per-algorithm. TPM2_PCR_Allocate reconfigures the bank set at runtime, gated by platform authorization.
The event log structure had to grow with the chip. The pre-2014 log format -- TCG_PCR_EVENT, single SHA-1 digest -- could not carry per-bank digests. The PC Client PFP defined a new structure, TCG_PCR_EVENT2. From Microsoft's Tbsi_Get_TCG_Log reference, the wire format is:
typedef struct {
TCG_PCRINDEX PCRIndex;
TCG_EVENTTYPE EventType;
TPML_DIGEST_VALUES Digests;
UINT32 EventSize;
UINT8 Event[EventSize];
} TCG_PCR_EVENT2;
typedef struct {
UINT32 Count;
TPMT_HA Digests; // Count copies, one per bank
} TPML_DIGEST_VALUES;
typedef struct {
UINT16 HashAlg;
UINT8 Digest[size_varies_with_algorithm];
} TPMT_HA;
An in-RAM ordered list of TCG_PCR_EVENT2 records, populated by firmware and OS components in the exact order they extend digests into PCRs. The log is unsigned -- only the PCR values are signed when the verifier later requests a quote. A verifier replays the log to re-derive the PCR values and accepts the log if the re-derivation matches the signed quote.
The multi-bank digest container inside TCG_PCR_EVENT2. It holds a Count of TPMT_HA records, each carrying a hash-algorithm identifier (HashAlg, a TPM_ALG_ID) and the corresponding digest. A modern Windows log on a SHA-256-and-SHA-1 dual-bank TPM emits Count = 2 per event with both digests of the same source bytes.
The very first event in a TPM-2.0-format log is, deliberately, a TPM-1.2-format record. From Microsoft Learn verbatim: "The Signature member of the TCG_EfiSpecIdEventStruct structure is set to a null-terminated ASCII string of \"Spec ID Event03\"". That string is the self-describing handshake: a parser that doesn't know about banks reads the legacy event and either understands it (continuing as a 1.2 parser) or recognises the Spec ID handshake (and upgrades to the 2.0 parser). The cost of forward compatibility is precisely one event.
TCG_EfiSpecIDEventStruct with Signature[16] containing the ASCII string and a specVersionMajor/specVersionMinor/specErrata triplet. The "03" denotes the third revision of the format. Earlier "Spec ID Event02" structures exist in pre-1.21 PFP firmware; they encode banks differently and are extremely rare in Windows-era machines.
The bridge between the chip and the firmware is a UEFI protocol. EFI_TCG2_PROTOCOL (UEFI 2.5 and later) exposes three calls that matter: HashLogExtendEvent (the one-shot "hash this blob, log it, extend the PCR" call), GetEventLog (return the in-progress event log to a caller), and GetCapability (which banks are active, which algorithms are supported). After ExitBootServices, the firmware publishes the final log as a UEFI configuration table; the OS reads it from there.
The Microsoft PFP-era PCR allocation is the table every modern Windows administrator should memorise.
| PCR | TCG PFP definition | Microsoft WBCL convention | Linux IMA / shim convention |
|---|---|---|---|
| 0 | SRTM, BIOS, host platform extensions, embedded option ROMs | Firmware version (EV_S_CRTM_VERSION); platform firmware blob | Same |
| 1 | Host platform configuration | BIOS setup data | Same |
| 2 | UEFI driver and application code (option ROMs) | Pluggable option ROM code | Same |
| 3 | UEFI driver and application configuration | Option ROM data | Same |
| 4 | UEFI boot manager and boot attempts | EV_EFI_BOOT_SERVICES_APPLICATION for bootmgfw.efi | Same (shim/grub image) |
| 5 | Boot manager code and boot attempts | Boot partition GPT, EFI variables loaded by boot manager | Same |
| 6 | Host platform manufacturer events | Wake reason, S-state events | Same |
| 7 | Secure Boot policy | SecureBoot/PK/KEK/db/dbx variable digests | Same |
| 8-9 | OS-loader reserved | Unused on Windows | Linux kernel measurement (some distros) |
| 10 | OS-loader reserved | Unused on Windows | IMA file measurements (canonical) |
| 11 | OS-loader reserved | Microsoft WBCL events (BitLocker control PCR) | Unused |
| 12 | OS-loader reserved | Boot environment configuration | Unused |
| 13 | OS-loader reserved | ELAM driver hash and policy | Unused |
| 14 | OS-loader reserved | Boot-loader-authority events | shim MOK certificate enrolment |
| 15 | OS-loader reserved | Reserved | Reserved |
| 16 | Debug | Used during development | Same |
| 17-22 | Dynamic OS (DRTM use only) | Secure Launch, Authenticated Code Module | TrenchBoot, tboot |
| 23 | Application support | Reserved | Reserved |
A small word on the index column: a 24-PCR TPM ranges from PCR[0] to PCR[23]. The PFP allocates PCR[16] as a debug index that platform firmware may extend during development; the value resets to zero at TPM_Init, which is one of two PCRs (the other is PCR[23]) the platform may explicitly reset. Older PCSI-era documentation sometimes refers to PCR[24]; that is a historical artifact of an unsanctioned Infineon extension and is not part of the modern PFP allocation. The allocation itself is normative in the PFP, but it sits inside a wider policy frame: NIST SP 800-155 (BIOS Integrity Measurement Guidelines, December 2011 IPD) defined the federal procurement bar for "BIOS integrity measurement" -- a draft that, despite never finalising, became the de-facto procurement template for the SRTM measurement chain U.S. agencies require their suppliers to ship.
Diagram source
gantt
dateFormat YYYY
title Five generations of measured boot
section Generation 1
AEGIS at UPenn (Arbaugh 1997) :a1, 1997, 1y
section Generation 2
TCPA founded (1999) / TPM 1.1b (2003) :a2, 1999, 11y
TPM 1.2 PCSI defines PCR[0-7] :a3, after a2, 11y
section Generation 3
TPM 2.0 announced (April 9, 2014) :a4, 2014, 12y
ISO/IEC 11889 (2015) / Hash agility :a5, 2015, 11y
section Generation 4
Intel TXT GETSEC[SENTER] (2007) :a6, 2007, 19y
Microsoft Secure Launch (Win10 1809) :a7, 2018, 8y
section Generation 5
Azure Attestation / Intune DHA :a8, 2018, 8y
PFP r2 / ML-DSA in flight :a9, 2025, 1y We now have a self-describing log, a hash-agile PCR set, and a verbatim ABI. Who actually writes the log? And who reads it?
5. The Breakthrough: One Log, Many Consumers
Every trust decision a modern Windows machine makes about its own boot ultimately consults the same record. BitLocker's seal release. Windows Defender System Guard runtime attestation. Windows Hello for Business device-bound key attestation. Microsoft Azure Attestation policy evaluation. Microsoft Intune Device Health Attestation. Conditional Access posture checks. All of them, ultimately, read the TCG event log -- and the PCR snapshot it replays into. One log; every feature.
This is the article's structural insight. It is also the reason this specification has survived three generations of attacks: the cost of designing a new attestation feature on Windows is no longer "design a new measurement plane," it is "decide which PCRs your policy cares about."
One log, many consumers. Every Windows trust decision about boot integrity -- BitLocker unseal, System Guard attestation, Hello for Business key attestation, Azure Attestation, Intune Device Health Attestation, Conditional Access -- ultimately consults the same TCG event log and the PCR snapshot it replays into. The cost of adding a new attestation feature is not a new measurement plane; it is a policy decision about which PCRs matter.
"One log, every feature."
The cooperative writers populate the log in pipeline order, following the Microsoft Tbsi_Get_TCG_Log PCR allocation. Firmware -- the silicon root of trust and everything above it through the UEFI driver execution environment -- writes PCRs 0 through 7. The Microsoft boot manager bootmgfw.efi writes additional events into PCRs 4, 11, and 12. The Windows OS loader winload.efi writes into PCRs 11 and 13. Into PCR 13 specifically, winload.efi writes the ELAM policy hash and the ELAM driver writes its own image digest (§6.5 walks the full PCR[13] cooperative sequence). The Windows kernel emits a EV_SEPARATOR event on every measured PCR once the boot-time measurement phase is complete, freezing the boot-time slice of the log for verifiers.
The unified reader path mirrors the writer fan-in. EFI_TCG2_PROTOCOL exposes the log to firmware drivers and applications. After ExitBootServices, UEFI publishes the final log via the EFI_TCG2_FINAL_EVENTS_TABLE configuration table. Windows reads that table during boot and exposes the merged log -- the firmware portion plus the OS-loader extensions -- to user mode through Tbsi_Get_TCG_Log. Operators read it with the inbox tpmtool.exe or cross-platform tpm2_eventlog; §6.7 walks the full tool set.
Diagram source
flowchart TD
subgraph FW["Firmware (CRTM / PEI / DXE / BDS)"]
F0["PCR[0]: CRTM, firmware blob"]
F1["PCR[1]: BIOS setup"]
F2["PCR[2]: option ROMs"]
F3["PCR[3]: option ROM config"]
F5["PCR[5]: GPT, EFI vars"]
F6["PCR[6]: wake reason"]
F7["PCR[7]: Secure Boot policy"]
end
subgraph BM["bootmgfw.efi"]
B4["PCR[4]: boot mgr image (Authenticode)"]
B11A["PCR[11]: WBCL boot mgr events"]
B12["PCR[12]: boot config"]
end
subgraph WL["winload.efi"]
W11["PCR[11]: kernel, HAL, boot-critical drivers"]
W13A["PCR[13]: ELAM policy hash"]
end
subgraph ELAM["ELAM driver"]
E13["PCR[13]: ELAM driver hash"]
end
subgraph K["Windows kernel"]
SEP["EV_SEPARATOR on every measured PCR (freeze)"]
end
FW --> BM --> WL --> ELAM --> K A single canonical log eliminates per-feature reinvention. Azure Attestation does not have to parse a different log than BitLocker. Hello for Business does not have to extend its own PCRs. The verifier community -- the part that knows what "good" means -- builds policies on top of one shared substrate.
We have named the log abstractly. What does an actual event look like, byte by byte, on the wire?
6. State of the Art: A Line-by-Line Walk Through the SRTM Chain
This is the section the practitioner audience came for. We walk the chain in the exact order events are logged on a modern UEFI Windows 11 24H2 machine. Reference: a Dell OptiPlex 7090 with Boot Guard, TPM 2.0 in SHA-256-only mode, Secure Boot enabled, BitLocker with TPM-only protector bound to the PFP-default UEFI profile.
The first event in the log on that machine is a EV_S_CRTM_VERSION record. PCR index 0. Event type 0x00000008. Two SHA-256 digests (one per active bank if SHA-1 is also enabled). Event size 8. Event data: a little-endian UTF-16 string containing the firmware version, padded to 8 bytes. The CRTM extends its own version into PCR[0] before measuring anything else. This is the foundation event.
6.1 The CRTM and PCR[0]
The very first instruction the CPU fetches after reset is not in DRAM. On a modern x86, it is in an immutable silicon region whose location and contents differ by silicon vendor.
On AMD Zen-class platforms, the Platform Security Processor -- a 32-bit ARM core inside the SOC -- boots first, validates the platform firmware against a key fused into silicon, and only then releases the x86 cores from reset. On Intel platforms with Boot Guard, the Authenticated Code Module is loaded from firmware into the cache-as-RAM region, signed by a key whose hash is fused into Intel chipset OTP fuses, and verified by microcode before x86 main core start. On Microsoft Pluton SKUs, the Pluton silicon firmware runs first; on AMD Ryzen 6000-series and later parts with Pluton enabled, Pluton is implemented as a Microsoft-co-designed firmware mode running on the existing AMD PSP coprocessor, not as a separate chip.
In every case, that silicon-rooted CRTM measures the next stage of firmware before transferring control. From Microsoft's hardware-rooted trust documentation, verbatim: "This technique of measuring the static early boot UEFI components is called the Static Root of Trust for Measurement (SRTM)." The SRTM extends PCR[0] with a chain of three early events: EV_S_CRTM_VERSION (firmware version), EV_S_CRTM_CONTENTS (the immutable CRTM code hash), and EV_POST_CODE (the POST code region hash). Then, if the platform has a separable firmware volume, an EV_EFI_PLATFORM_FIRMWARE_BLOB event covers the rest of the SPI flash region per the TCG PFP event-type registry surfaced in Microsoft's Tbsi_Get_TCG_Log reference. The PFP closes PCR[0] with an EV_SEPARATOR event at the BDS boundary.
Where the firmware-version string differs, the SHA-256 digest of the EV_S_CRTM_VERSION event data differs. Where the EV_S_CRTM_VERSION digest differs, PCR[0] differs. That is the entire mechanism by which an overnight UEFI patch changes PCR[0]. Dell updated the firmware string from "1.16.0" to "1.17.0"; the bytes hashed; the PCR moved; the seal broke.
6.2 PEI/DXE, option ROMs, and PCR[1-3]
After the CRTM hands off, the Pre-EFI Initialisation (PEI) phase runs and the Driver Execution Environment (DXE) phase loads UEFI drivers. PEI does early silicon initialisation -- memory controller, cache topology, basic chipset config -- and DXE does device discovery, including option ROMs for plug-in cards.
Each option ROM that runs is measured into PCR[2]. The option ROM's configuration -- card-specific NVRAM state that survives reboot -- is measured into PCR[3]. The PFP also reserves PCR[1] for the platform configuration: CMOS settings, the SMBIOS table contents, and any BIOS-setup-visible knob that affects platform behaviour per the PCR-allocation mapping surfaced in Microsoft's Tbsi_Get_TCG_Log documentation. Changing your boot order in BIOS setup changes PCR[1]. Disabling a USB controller in firmware changes PCR[1]. Installing a discrete GPU adds an EV_EFI_BOOT_SERVICES_DRIVER event into PCR[2] for the GPU's video BIOS.
6.3 Secure Boot variables and PCR[7]
PCR[7] is the Secure Boot policy PCR. It records the digests of the four variables that define Secure Boot identity -- SecureBoot (the on/off flag), PK (Platform Key), KEK (Key Exchange Key), db (allowed signers), and dbx (revocation list) -- plus any signed program execution events the firmware logs to PCR[7] under EV_EFI_VARIABLE_AUTHORITY.
Each variable contributes one EV_EFI_VARIABLE_DRIVER_CONFIG event whose Event field encodes (VariableName GUID, UnicodeName, VariableDataLength, VariableData) and whose digest is the SHA-256 of that entire structure. The digest is not over the variable data alone; it is over the GUID and name as well. This matters: when the May 2023 Microsoft dbx update shipped under KB5025885 added the BlackLotus-vulnerable boot manager hashes to the revocation list, the variable data length grew, the structure changed, and the resulting EV_EFI_VARIABLE_DRIVER_CONFIG digest differed. Every UEFI Windows machine on Earth that consumed that dbx update saw PCR[7] move.
From the Wack0/bitlocker-attacks index, reproducing TCG EFI Platform Specification §6.4 verbatim: "If the platform provides a firmware debugger mode which may be used prior to the UEFI environment or if the platform provides a debugger for the UEFI environment, then the platform SHALL extend an EV_EFI_ACTION event into PCR[7] before allowing use of the debugger". The intent is clear: a debugged firmware is a different PCR[7] than a production firmware. The verifier can refuse to release a key to a debugged platform.
6.4 Boot manager (bootmgfw.efi) and PCR[4] + PCR[11]
The UEFI Boot Device Selection (BDS) phase locates EFI/Microsoft/Boot/bootmgfw.efi on the EFI System Partition, computes its Authenticode digest, verifies the Authenticode signature against db and dbx, logs an EV_EFI_BOOT_SERVICES_APPLICATION event into PCR[4] with that digest, and transfers control. PCR[4] now binds to the boot manager's image content. A different boot manager binary -- a different version, a different language pack -- produces a different PCR[4].
Microsoft's Portable Executable signature format. The Authenticode digest is computed over the PE image excluding fields the loader rewrites (file offset bytes, the checksum field, the digital-signature pointer). Authenticode is not the same as a SHA-256 over the file -- two byte-identical .exe files can have different SHA-256 but the same Authenticode digest, and vice versa. Boot Guard, Secure Boot, and PCR[4] all hash the Authenticode digest, not the raw file.
Once bootmgfw.efi runs, it extends its own events into PCR[11]. These are Microsoft-specific Windows Boot Configuration Log (WBCL) records, not generic TCG events. They include the BCD store contents, the boot-environment configuration, and Microsoft-private telemetry about the boot manager's policy decisions. PCR[11] is the BitLocker control PCR -- the index that captures Windows-side boot-time configuration.
The Microsoft-specific extension of the TCG event log carrying boot-manager, loader, and ELAM events. WBCL events use the TCG EV_EVENT_TAG event type with Microsoft-private sub-types. They are extended into PCR[11], PCR[12], and PCR[13]. WBCL is exposed by Tbsi_Get_TCG_Log_Ex and is what tpmtool.exe getdeviceinformation actually parses.
6.5 winload.efi and the ELAM handoff
bootmgfw.efi chains to winload.efi, the OS loader. winload measures the Windows kernel image (ntoskrnl.exe), the Hardware Abstraction Layer (hal.dll), the OS configuration data (the boot manager's view of boot-critical drivers), and each boot-critical driver in load order -- each into PCR[11] as a WBCL record. The kernel binary itself is part of that chain; a kernel update changes PCR[11].
The Early Launch Anti-Malware (ELAM) interface gives a vendor anti-malware driver a chance to run before all other drivers and approve or block subsequent driver load attempts. winload measures the ELAM policy file hash into PCR[13]; the ELAM driver, when loaded, extends its own image digest into PCR[13]; the ELAM driver then returns its allow/deny verdict on each subsequent driver, and winload logs those verdicts (also into PCR[13] under WBCL EV_EVENT_TAG).
6.6 Kernel and the final separator
Once the Windows kernel starts, it exposes the TCG event log through the TPM Base Services driver Tbs.sys, which is consumed by Win32 callers through Tbsi_Get_TCG_Log. The kernel emits a EV_SEPARATOR event into every measured PCR -- the "ready-to-boot" marker. After the separator, no further measured-boot events occur for the current boot session. The WBCL is frozen. A verifier reading the log at this point sees the complete boot history.
6.7 Reading the log from user mode
On a Windows 11 24H2 machine, the simplest way to read the log is tpmtool.exe getdeviceinformation from an elevated prompt -- it prints the parsed WBCL plus the current PCR values. For the raw binary log, Get-TpmEndorsementKeyInfo from PowerShell returns the EK chain, and MeasuredBootTool.exe -log <path> from the Windows HLK kit returns the raw binary log file written under C:\Windows\Logs\MeasuredBoot\*.log.
Cross-platform, tpm2_eventlog from the tpm2-tools suite parses any binary log conforming to the PC Client PFP -- including Windows-saved logs, because the WBCL extension is structurally compatible. The man page is precise: "tpm2_eventlog(1) -- Parse a binary TPM2 event log... The format of this log documented in the 'TCG PC Client Platform Firmware Profile Specification'." On Linux, the firmware-published log lives at /sys/kernel/security/tpm0/binary_bios_measurements.
// Simulate three iterative SHA-256 extends into a single PCR.
// Initial PCR is 32 zero bytes. Each extend: PCR := SHA256(PCR || measurement).
async function sha256(buffer) {
const hash = await crypto.subtle.digest('SHA-256', buffer);
return new Uint8Array(hash);
}
function concat(a, b) {
const out = new Uint8Array(a.length + b.length);
out.set(a, 0);
out.set(b, a.length);
return out;
}
function toHex(arr) {
return Array.from(arr).map(b => b.toString(16).padStart(2, '0')).join('');
}
async function extendChain(measurements) {
let pcr = new Uint8Array(32); // 32 zero bytes
for (const m of measurements) {
pcr = await sha256(concat(pcr, m));
}
return toHex(pcr);
}
const a = new TextEncoder().encode('firmware-v1.16');
const b = new TextEncoder().encode('bootmgfw-2024-03');
const c = new TextEncoder().encode('winload-26100.123');
(async () => {
const abc = await extendChain([a, b, c]);
const cba = await extendChain([c, b, a]);
console.log('PCR after a,b,c =', abc);
console.log('PCR after c,b,a =', cba);
console.log('Same value?', abc === cba);
})(); Press Run to execute.
Run that snippet and you will see two completely different 32-byte hex strings. The PCR encodes the order. A verifier comparing your machine's PCR[11] against a known-good baseline is implicitly checking that the kernel, the HAL, and the boot-critical drivers all loaded in the expected sequence -- not just that they all loaded. Reorder the chain, even with identical inputs, and the PCR moves. This is the property that makes the chain-of-hashes axiom load-bearing.
6.8 The PCR allocation cheat sheet
Pin the table from Section 4 to your wall. Most operational questions reduce to "which PCR is affected by this change, and is it in my BitLocker profile?" Three quick rules:
- Code changes go to even PCRs (0, 2, 4). Firmware blob, option ROM, boot manager. A firmware update moves PCR[0]; a discrete GPU swap moves PCR[2]; a boot-manager update moves PCR[4].
- Configuration changes go to odd PCRs (1, 3, 5). BIOS setup, option ROM config, EFI variables seen by the boot manager.
- Policy and identity go to PCR[7]. Secure Boot keys. Any
dbxupdate moves PCR[7]. Disabling Secure Boot moves PCR[7]. Enrolling third-partydbentries moves PCR[7].
PCR[11] is the OS-loader code chain on Windows (kernel, HAL, boot drivers). PCR[13] is the ELAM policy and driver. PCR[14] is, by Microsoft convention, boot-loader-authority events; by Linux shim convention, MOK enrolment. Same index; different ontology. Verifiers must pick a side.
6.9 BitLocker seal-binding
BitLocker's Volume Master Key is wrapped by a TPM-resident sealed blob whose policy is TPM2_PolicyPCR over a chosen PCR profile. The default UEFI profile is the bitmask 0x00000080 | 0x00000800 = 0x880 -- that is PCR[7] (bit 7 = 0x80) plus PCR[11] (bit 11 = 0x800) -- as documented in the BitLocker Group Policy reference, which notes verbatim that "when Secure Boot State (PCR7) support is available, the default platform validation profile secures the encryption key using Secure Boot State (PCR 7) and the BitLocker access control (PCR 11)." The legacy CSM/BIOS profile is 0x00000015 | 0x00000800 = 0x815 -- that is PCR[0], PCR[2], PCR[4], plus PCR[11].
At seal time (when BitLocker enables, or when a user changes the protector configuration), the TPM records the current PCR values into the policy. At every subsequent boot, the boot manager rebuilds the session, calls TPM2_PolicyPCR with the current PCR values, and calls TPM2_Unseal. If the current PCRs match the seal-time digest, the TPM releases the VMK and BitLocker unlocks transparently. If they don't match, the TPM refuses and Windows prompts for the 48-digit recovery key.
From Microsoft's BitLocker countermeasures documentation: "By default, BitLocker provides integrity protection for Secure Boot by utilizing the TPM PCR[7] measurement. An unauthorized EFI firmware, EFI boot application, or bootloader can't run and acquire the BitLocker key". The PCR[7]-default choice is deliberate: PCR[7] is the policy PCR, not the code PCR. Firmware updates don't change a Secure-Boot-policy hash; only key-database updates do.
Diagram source
sequenceDiagram
participant Firmware
participant BootMgr as bootmgfw.efi
participant TPM
participant Winload as winload.efi
Firmware->>TPM: TPM2_PCR_Extend (PCR[0-7])
BootMgr->>TPM: TPM2_PCR_Extend (PCR[4], PCR[11], PCR[12])
BootMgr->>TPM: TPM2_StartAuthSession
BootMgr->>TPM: TPM2_PolicyPCR (selection = current profile)
BootMgr->>TPM: TPM2_Unseal (sealed VMK blob)
alt PCRs match seal-time digest
TPM-->>BootMgr: VMK plaintext
BootMgr->>Winload: hand off, VMK in protected memory
Winload-->>Firmware: continue boot
else PCRs do not match
TPM-->>BootMgr: TPM_RC_POLICY_FAIL
BootMgr-->>BootMgr: prompt for 48-digit recovery key
end The on-disk registry path that records the profile choice is HKLM\SOFTWARE\Policies\Microsoft\FVE\PlatformValidationProfileUEFI. The value is a 24-bit bitmask where bit N selects PCR[N]. A device that sealed under the default 0x880 profile and then has Group Policy changed to 0x815 will not automatically re-seal -- you must explicitly disable and re-enable the TPM protector with manage-bde -protectors to rotate the policy.
A small utility decodes the bitmask:
function decodeProfile(mask) {
const selected = [];
for (let bit = 0; bit < 24; bit++) {
if (mask & (1 << bit)) selected.push(bit);
}
return selected;
}
console.log('Default UEFI profile (0x880):', decodeProfile(0x880));
console.log('Legacy CSM profile (0x815): ', decodeProfile(0x815));
console.log('A more restrictive profile (0x8D5):', decodeProfile(0x8D5));
// Output:
// Default UEFI profile (0x880): [7, 11] (PCR[7]+PCR[11])
// Legacy CSM profile (0x815): [0, 2, 4, 11] (PCR[0]+PCR[2]+PCR[4]+PCR[11])
// A more restrictive profile (0x8D5): [0, 2, 4, 6, 7, 11] Press Run to execute.
Run it. Your machine's profile mask is one of those three (or close enough). If the mask includes PCR[0], every firmware update will trigger a recovery prompt. If it omits PCR[0] but includes PCR[7], only Secure Boot key changes (Microsoft's annual dbx updates, third-party Linux enrolments, BIOS-setup Secure Boot toggles) will. The four canonical recovery-prompt causes follow directly:
| Cause | PCR affected | Mitigation |
|---|---|---|
| UEFI firmware update | PCR[0] | Suspend BitLocker before update; legacy profile only |
Microsoft dbx update or Secure Boot key rotation | PCR[7] | Suspend BitLocker before patch Tuesday |
| Boot-manager binary swap (KB-driven update) | PCR[4], PCR[11] | Suspend BitLocker before cumulative update |
| BIOS-setup change (boot order, virtualization toggle) | PCR[1] | Suspend BitLocker before deliberate change |
Diagram source
flowchart LR
CRTM["CRTM
(Boot Guard ACM / PSP / Pluton)"] -->|"PCR[0] EV_S_CRTM_VERSION"| PEI
PEI["PEI
(silicon init)"] -->|"PCR[0] EV_S_CRTM_CONTENTS"| DXE
DXE["DXE
(driver execution)"] -->|"PCR[2] option ROM
PCR[3] option ROM config"| OPTROM
OPTROM["option ROMs"] -->|"PCR[7] SecureBoot/PK/KEK/db/dbx"| BDS
BDS["BDS
(boot device selection)"] -->|"PCR[4] Authenticode digest"| BM
BM["bootmgfw.efi"] -->|"PCR[11] WBCL boot mgr
PCR[12] boot config"| WL
WL["winload.efi"] -->|"PCR[11] kernel/HAL/drivers
PCR[13] ELAM policy"| ELAM
ELAM["ELAM driver"] -->|"PCR[13] driver hash"| KERN
KERN["Windows kernel"] -->|"EV_SEPARATOR on every measured PCR (freeze)"| DONE["WBCL frozen"] We have walked the chain. What about the chain we cannot trust -- the OEM-vendor-firmware-allowlist explosion that overwhelms remote verifiers?
7. Competing Approaches: DRTM, Late Launch, and Secure Launch
A quote from Microsoft's hardware-root-of-trust documentation frames the problem precisely: "As there are thousands of PC vendors that produce many models with different UEFI BIOS versions, there becomes an incredibly large number of SRTM measurements upon bootup. Two techniques exist to establish trust here -- either maintain a list of known 'bad' SRTM measurements (also known as a blocklist), or a list of known 'good' SRTM measurements (also known as an allowlist)."
The allowlist explodes. Every OEM, every model, every firmware revision, every Secure Boot key generation produces a fresh PCR[0]/PCR[7]/PCR[11] tuple. A central verifier that wants to assert "this fleet booted firmware Microsoft has signed off on" has to maintain a database whose cardinality grows quadratically in (vendors x firmware versions). By 2017 the table size made the verifier policy ungovernable for general-purpose Windows fleets.
The fix is structural: introduce a second measurement plane that does not depend on the OEM. From the same Microsoft document: "System Guard Secure Launch, first introduced in Windows 10 version 1809, aims to alleviate these issues by using a technology known as the Dynamic Root of Trust for Measurement (DRTM)." And: "Secure Launch simplifies management of SRTM measurements because the launch code is now unrelated to a specific hardware configuration."
DRTM is a CPU primitive. On Intel, it is GETSEC[SENTER], introduced with Trusted Execution Technology in 2007. From the Intel SDM mirror, verbatim: "GETSEC[SENTER] / Launch a measured environment. EBX holds the SINIT authenticated code module physical base address. ECX holds the SINIT authenticated code module size (bytes)." On AMD, the equivalent is the SKINIT instruction from the AMD-V (SVM) family, introduced with the first AMD-V silicon in 2005-2006. Microsoft's Secure Launch implementation issues SENTER or SKINIT from a small Secure Kernel Loader (SKL) inside winload.efi.
What SENTER and SKINIT do, at machine level, is roughly identical: they suspend all but one CPU, reset PCRs 17 through 22 in the TPM to a defined value (zero for SHA-256, all-ones for SHA-1 historically; the SHA-256 reset value is UNVERIFIED_FETCH -- the TCG PFP returns HTTP 403 to non-browser agents), load a vendor-signed Authenticated Code Module (Intel) or a self-signed Secure Loader Block (AMD), verify its signature, and atomically transfer control to it with interrupts disabled and the IOMMU active. The ACM/SLB's measurement gets extended into PCR[17]; the Measured Launch Environment (MLE) it loads -- on Windows, the Hyper-V hypervisor and the secure kernel -- gets extended into PCR[18].
The code body that the DRTM primitive (/) measures into PCR[18] after the Authenticated Code Module (Intel) or Secure Loader Block (AMD) has been measured into PCR[17] and verified. On Microsoft Secure Launch, the MLE is the hypervisor plus the secure kernel. On Linux+TrenchBoot, the MLE is the GRUB late-launch component plus the kernel.
The reason SENTER and SKINIT matter, beyond the resetting of PCRs 17-22, is what they don't measure. They do not measure the PEI/DXE firmware. They do not measure option ROMs. They do not measure the entire SRTM trail in PCRs 0-7. A verifier that consumes only PCRs 17-22 sees a uniform digest across every Intel platform (because every Intel platform runs the same Intel-signed ACM) and every Microsoft Secure-Launch-capable system (because every such system runs the same Microsoft-signed SKL). The OEM diversity is absorbed by ignoring the diverse measurements.
The Rutkowska / Wojtczuk attack and the IOMMU precondition
Before SENTER could be trusted, it had to survive a DMA attack class that Joanna Rutkowska and Rafal Wojtczuk demonstrated at Black Hat DC 2009. Their paper's abstract is direct: "We describe a practical attack that is capable of bypassing the TXT's trusted boot process". The mechanism: between the signature check on the SINIT ACM and its execution, a DMA-capable peripheral could overwrite the verified payload. Intel's response was architectural -- route SINIT through IOMMU-protected memory, and refuse to start SENTER if the IOMMU is not on. The fix is enforced at the instruction level: the SDM mirror's GETSEC[SENTER] description lists the chipset and TPM preconditions GETSEC[SENTER] now checks before opening the measured-launch window. Every modern DRTM design rests on the assumption that the IOMMU is active at the late-launch instant.
Microsoft Secure Launch and the Secured-Core PC bar
Microsoft's Secured-core PC programme packages Secure Launch with a set of other hardware requirements: SMM Supervisor, kernel DMA protection, Boot Guard or PSP firmware, Pluton or equivalent silicon root of trust, and Memory Integrity (HVCI) enabled by default. The Microsoft framing: "Microsoft is working closely with OEM partners and silicon vendors to build Secured-core PCs that features deeply integrated hardware, firmware and software to ensure enhanced security for devices, identities and data." The result is a tier-1 SKU set whose attestation evidence is the small OEM-invariant DRTM TCB, not the large SRTM history.
Operationally, the Secured-Core flag enables the configuration block at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios per Microsoft's Secure Launch configuration guide. When the registry flag is set and the silicon supports late launch, winload.efi issues SENTER/SKINIT after measuring the early kernel, and the hypervisor launches inside the MLE.
TrenchBoot: open-source DRTM for Linux
DRTM is not Windows-only. The TrenchBoot project -- with contributors from Apertus Solutions, Oracle, and 3mdeb -- maintains an open-source DRTM stack for Linux and Xen on GRUB. From the TrenchBoot documentation repo: "TrenchBoot is a framework that allows individuals and projects to build security engines to perform launch integrity actions for their systems." The Linux side of the same primitive that Microsoft Secure Launch uses on Windows.
Diagram source
flowchart TD
subgraph SRTM["SRTM chain (PCRs 0-7, 11-14)"]
S1["CRTM"] --> S2["PEI/DXE"] --> S3["option ROMs"] --> S4["BDS"]
S4 --> S5["bootmgfw.efi"] --> S6["winload.efi (early)"]
end
subgraph DRTM["DRTM chain (PCRs 17-22)"]
D1["SKL issues SENTER / SKINIT"] --> D2["CPU resets PCRs 17-22"]
D2 --> D3["ACM/SLB extended into PCR[17]"]
D3 --> D4["MLE (hypervisor + secure kernel) into PCR[18]"]
D4 --> D5["Secure kernel boots; IOMMU active"]
end
S6 --> D1 The comparison below synthesizes the TCG PFP PCR allocation surfaced in Microsoft's Tbsi_Get_TCG_Log reference with the Microsoft hardware-root-of-trust documentation and the BitLocker countermeasures unlock-mode enumeration:
| Property | SRTM (PCR[0-7,11-14]) | DRTM (PCR[17-22]) | TPM-only BitLocker (seal PCR[7,11]) | TPM+PIN |
|---|---|---|---|---|
| Trust-anchor size | OEM CRTM + firmware + option ROMs + drivers (large) | Vendor ACM/SLB + MLE only (small) | Same as SRTM | Same + human PIN secret |
| Hardware required | Any TPM 2.0 platform | Intel TXT-capable or AMD SVM-capable + IOMMU | Same as SRTM | Same |
| Recovery prompts/year | High (firmware + dbx + boot manager) | Low (PCR[17-22] not in default profile) | High on TPM-only profile | Same as seal profile |
| bitpixie-class attack | Vulnerable | Not directly mitigated | Vulnerable | Mitigated (PIN required) |
| Verifier policy size | O(vendors x versions) | O(vendor) | O(profile) | O(profile + PIN policy) |
DRTM solves the OEM diversity problem. It does not solve the problem that the log is unsigned, the measurement is a hash and not a good hash, and the CRTM is an axiom. What can measurement never prove?
8. Theoretical Limits: What Measurement Can Never Prove
Restate the axiom from §2: the first hash in the chain is an axiom; the silicon that computes it is itself unmeasured. CRTM is the Root of Trust for Measurement, not the Root of Trust for Everything. The trust we can claim is that, given the integrity of the silicon and the immutability of the embedded keys, the chain is a faithful record of what ran. The "given" is doing all the work.
Three limits, each architectural and not implementational.
8.1 Trust on first measurement
The CRTM has nothing under it. If you compromise the silicon -- through a faulTPM-class voltage glitch on the SPI bus, through a Pluton supply-chain tamper, through an Intel Boot Guard key extraction -- the rest of the chain is, formally, useless. The verifier asks the chip "what ran?"; the chip computes the answer using cryptographic primitives the chip itself implements; if the chip is malicious, every answer is consistent with whatever boot history the attacker wishes. The TPM's TPM2_Quote signature is bound to the chip's own AIK; if the chip is the attacker, the signature is honest about a lie.
This is not a flaw of TPM 2.0. It is a feature of mathematics. You cannot bootstrap trust from nothing. AEGIS knew this in 1997; the TCG accepted it in 1999; every silicon root of trust still depends on it in 2026. The only mitigations are (a) make the silicon as small and audited and physically resistant as the budget allows (which is why Pluton ships a separate sub-millimetre microcontroller), and (b) bind the chip's identity to a manufacturer-rooted certificate chain that an out-of-band auditor can verify -- which is why Hello for Business enrollment cross-checks the EK certificate against the OEM root before issuing the device-bound key.
8.2 A PCR value is a hash, not a good hash
The TPM has no knowledge of what is good. PCR[0] holding 0xC4F7... is just a number. To the TPM it is no more or less suspicious than 0xA21E.... The TPM's job, during TPM2_PolicyPCR+TPM2_Unseal, is to refuse the key release if the PCRs do not match the seal-time digest -- regardless of whether the seal-time digest was a benign value or a malicious one.
"A PCR value is a hash, not a good hash."
This is why a sealed BitLocker VMK released on a successful TPM2_PolicyPCR match is not a guarantee that the booted code was actually trustworthy. It is a guarantee that the booted code matched the seal-time digest. If at seal time the platform was running an older, signed, but vulnerable bootmgfw.efi, the seal binds to that boot manager's PCR[11]. Years later, when an attacker downgrades to that same older, signed boot manager, PCR[11] reproduces the seal-time digest exactly, and the TPM cheerfully releases the key. This is the mechanism that makes bitpixie work; we will meet it again in Section 9.
The verifier -- BitLocker policy, Azure Attestation policy, Intune DHA, your fleet management tool -- is the only entity that knows what good means. The TPM provides reporting infrastructure; the verifier provides policy infrastructure. Measurement is reporting infrastructure, not policy infrastructure.
Measurement is reporting infrastructure, not policy infrastructure. The TPM knows what was measured; only the verifier knows what is good. Every BitLocker unseal, every Azure Attestation, every Intune DHA verdict is a policy decision made by software outside the TPM, against a number the TPM merely reports.
8.3 The log is unsigned
TPM2_Quote signs only the PCR values plus the verifier's nonce. It does not sign the TCG event log. A malicious firmware can extend an honest digest into the TPM and report a different event in the log it hands the OS. The PCR is correct; the log is a fabrication. Detection comes only from the verifier replaying the log against the quoted PCRs and flagging a mismatch.
In practice this is not a problem on benign firmware, because the firmware has no incentive to lie about its own events. It becomes a problem precisely in the cases where the firmware is the attacker -- BlackLotus-class implants that own the boot manager, faulTPM-class chip compromises that own the TPM. In those cases, a verifier that trusts both the log and the quote without replaying is trusting a forged document.
The mitigation is structural and well-known: verifiers MUST replay. Azure Attestation, Intune DHA, and Microsoft's reference attestation library all replay the log against the quoted PCRs and refuse to issue a token on mismatch. Operators rolling their own attestation pipeline often skip the replay step, especially in early-prototype deployments. Skip the replay and you have an unauthenticated event list dressed up as evidence.
8.4 The cuckoo attestation class (Parno 2008)
There is a class of attack that no amount of replay or PCR profile tightening can stop. Bryan Parno's 2008 HotSec paper names the problem the cuckoo attack and proposes the first formal model for establishing trust in a platform under that threat. The abstract, paraphrased lightly to fit this article's word-list: any naive approach falls victim to a cuckoo attack; the model, in Parno's own phrasing, "reveals the cuckoo attack problem".
An attestation-relay attack in which a verifier challenges a compromised device, the compromised device proxies the challenge to a separate, genuine, attested device elsewhere, the genuine device produces a valid signed quote, the compromised device returns that quote as if it were its own, and the verifier accepts. Without out-of-band identification of this device's endorsement key, the verifier cannot distinguish "the EK that signed the quote" from "an EK in the world that signed a quote." Named by Bryan Parno in 2008 by analogy with the cuckoo bird's brood parasitism.
A TPM-resident asymmetric key whose certificate is signed by the platform's Endorsement Key certificate chain, used to sign TPM2_Quote responses. The verifier checks the AK's certificate chain to the OEM root before trusting the quote. If the EK chain is not pre-bound to this device's serial number (or some other out-of-band identifier), an attacker can relay the challenge to a different TPM and return a valid signature from that TPM's AK.
The cuckoo class is closeable, but only by binding the AK to this device's identity before trust is needed. Microsoft Autopilot and Windows Hello for Business do this transparently during device enrollment: the EK certificate chain is captured at first boot, cross-checked against the OEM root, and the resulting AK is bound to a specific Microsoft Entra ID device object. Ad-hoc attestation deployments that do not capture the EK chain at enrollment are vulnerable.
Bryan Parno is now at Carnegie Mellon and was on sabbatical at Amazon during 2025. The cuckoo paper remains, on its eighteenth birthday, the canonical reference for the class.
Permanent limits accepted. What are people actively trying to fix that we have not solved yet?
9. Open Problems: bitpixie, the dbx-Update UX, and What's Next
The fix is the breakage. The patch that closes the most dangerous BitLocker bypass of the decade is also the patch that drowns help-desks in 48-digit recovery prompts. The structural entanglement of these two facts is the central open problem of measured boot in 2026.
9.1 bitpixie (CVE-2023-21563)
An attacker reaches behind a fully-patched, BitLocker-enabled Windows 11 laptop. They plug in a LAN cable. They plug in a USB keyboard. They press F12 to boot from network. Within five minutes the disk encryption key is on their disk.
That is bitpixie. From the Neodyme write-up: "Thanks to a bug discovered by Rairii in August 2022, attackers can extract your disk encryption key on Windows' default 'Device Encryption' setup. This exploit, dubbed bitpixie, relies on downgrading the Windows Boot Manager. All an attacker needs is the ability to plug in a LAN cable and keyboard to decrypt the disk." The CVE is CVE-2023-21563, described as a "BitLocker Security Feature Bypass Vulnerability" with the MSRC advisory at CVE-2023-21563.
The mechanism is the second aha moment from Section 8 made operational. From SySS's bitpixie technical write-up: "The bitpixie vulnerability in Windows Boot Manager is caused by a flaw in the PXE soft reboot feature, whereby the BitLocker key is not erased from memory. To exploit this vulnerability on up-to-date systems, a downgrade attack can be performed by loading an older, unpatched boot manager."
The chain in detail: (1) The attacker boots the target normally. The boot manager unseals the VMK, hands it to winload.efi, and loads BitLocker into the boot path. (2) Before winload.efi zeroes the VMK from RAM, the attacker triggers a PXE soft reboot (a feature of older boot manager versions) that returns control to the boot manager without a full platform reset. (3) The attacker now PXE-boots a Linux image that scans physical memory for the BitLocker FVE marker -FVE-FS- and extracts the VMK. The platform reset never happened, the RAM never cleared, the TPM never re-quoted -- the VMK is just lying there in untouched physical memory.
The downgrade: the older boot manager whose soft-reboot path leaks the VMK is still signed by the Microsoft 2011 production certificate, which is still in db on every Secure Boot machine until that certificate's natural 2026 expiry. PCR[7] -- the policy PCR -- accepts the downgraded boot manager because the boot manager is still validly signed. PCR[11] still matches the seal-time digest because, at seal time, that exact older boot manager was the one running. The TPM unseals. BitLocker unlocks. The attack proceeds.
This is the third aha moment from the article's structure: a PCR replay attack with a still-trusted older signed binary. The TPM is not malfunctioning. The policy is not misconfigured. The seal is doing exactly what it was sealed to do: release the key if the boot reproduces the boot it was sealed against. The attacker just produced the seal-time boot, in 2024, using a signed-but-vulnerable binary the verifier has not revoked.
Public disclosure landed at the 38th Chaos Communication Congress in December 2024. From the talk abstract verbatim: "since 2022, when Rairii discovered the bitpixie bug (CVE-2023-21563). While this bug is 'fixed' since Nov. 2022 and publically known since 2023, we can still use it today with a downgrade attack to decrypt BitLocker." The full attack chain was demonstrated on stage by Thomas Lambertz of Neodyme. The proof-of-concept code is at github.com/martanne/bitpixie.
The repository handlemartanne is the GitHub username; the discoverer is Rairii (August 2022); the 38C3 presenter is Thomas Lambertz (Neodyme). Press accounts that refer to "martanne" as a person are confusing the GitHub handle with an author identity.
9.2 The KB5025885 / Windows UEFI CA 2023 rotation
Microsoft's structural response is documented in the canonical KB article on Boot Manager revocations. The fix is in three stages. Stage 1: enroll the new Windows UEFI CA 2023 certificate in the Secure Boot db variable. Stage 2: replace existing boot manager binaries with copies signed by the 2023 CA instead of the 2011 CA. Stage 3: revoke the 2011 CA in dbx. The full rollout is gated on the 2026 natural expiry of the original Microsoft production signing certificate.
Every one of those three stages changes PCR[7]. Every one. Stage 1 adds bytes to db; Stage 3 adds bytes to dbx; even Stage 2, which doesn't touch the Secure Boot variables directly, ships a new boot manager binary whose Authenticode digest moves PCR[4]. On TPM-only BitLocker bound to 0x880 = PCR[7] + PCR[11], the recovery prompt fires twice for every customer.
9.3 BlackLotus (CVE-2022-21894 "Baton Drop")
The bitpixie story does not stand alone. On March 1, 2023, ESET researcher Martin Smolár disclosed BlackLotus -- in his own words, "the first publicly known UEFI bootkit bypassing the essential platform security feature -- UEFI Secure Boot -- is now a reality." BlackLotus exploits CVE-2022-21894 ("Baton Drop"), a Secure Boot bypass in a Microsoft-signed boot manager. From the ESET write-up: "Although the vulnerability was fixed in Microsoft's January 2022 update, its exploitation is still possible as the affected, validly signed binaries have still not been added to the UEFI revocation list. BlackLotus takes advantage of this, bringing its own copies of legitimate -- but vulnerable -- binaries to the system in order to exploit the vulnerability."
The structural fix for BlackLotus is identical to the structural fix for bitpixie: revoke the vulnerable signed binaries in dbx. Microsoft shipped the BlackLotus dbx revocations in May 2023; that update is the source of most of the "PCR[7] moved overnight" stories from the second half of 2023. The break-fix-break loop is now a recurring operational reality, not an exception.
"the first publicly known UEFI bootkit bypassing the essential platform security feature -- UEFI Secure Boot -- is now a reality." -- Martin Smolár, ESET Research, March 1, 2023
9.4 The break-fix-break loop
The fix is the breakage. Every dbx update that closes a Secure Boot bypass changes PCR[7]. Every PCR[7] change forces a 48-digit recovery prompt on every TPM-only BitLocker machine on the platform. The patch that closes BlackLotus or bitpixie is the operational pain. The only deployment path that breaks this loop is pre-boot authentication, because TPM+PIN does not depend on PCR[7] alone.
Diagram source
flowchart LR
A["BlackLotus disclosed
(March 2023)"] --> B["Microsoft May 2023 dbx update
revokes vulnerable boot managers"]
B --> C["PCR[7] changes on every
UEFI Windows machine"]
C --> D["TPM-only BitLocker fires
fleet-wide 48-digit prompts"]
D --> E["Operators delay patches
or roll back to gain stability"]
E --> F["Window of vulnerability
re-opens for class"]
F --> A 9.5 Post-quantum agility for the attestation key
Looking ahead, the next structural break is cryptographic: the TPM's signing primitives (RSA-2048, ECC P-256) do not survive Shor's algorithm on a sufficiently large quantum computer. The TCG's PC Client Platform Firmware Profile revision 2 work is targeting post-quantum agility for attestation keys -- ML-DSA (Dilithium) and ML-KEM (Kyber) variants of the signature and key-encapsulation primitives that TPM2_Quote and TPM2_ActivateCredential depend on.
The constraint that limits the rollout is mechanical. The TPM 2.0 command and response buffer is, by default, 4096 bytes. A Dilithium Level 3 (ML-DSA-65) signature is 3,309 bytes per FIPS 204. An RSA-2048 signature is 256 bytes. The buffer survives RSA quotes with vast headroom; it has roughly 800 bytes of headroom for an ML-DSA-65 quote. ML-KEM-768 (NIST Category 3) ciphertexts are 1,088 bytes per FIPS 203, with public keys at 1,184 bytes -- still tight if you also need an ML-DSA-65 signature on the same response. The PFP r2 work is largely about negotiating buffer growth across the TPM-firmware-OS path so the post-quantum primitives fit. As of 2026 this is UNVERIFIED_FETCH from the TCG (the TCG specifications site returns HTTP 403 to non-browser User-Agents), but Microsoft has signalled interim TPM 2.0 deployments with enlarged buffers.
9.6 DRTM coverage gaps
DRTM is a Secured-core feature; not every fleet runs Secured-core hardware. Raw Intel TXT has shipped on vPro platforms since the Q3 2007 introduction of the Intel DQ35J board, but the deployable surface for Microsoft Secure Launch is narrower because Secured-Core also requires HVCI, kernel DMA protection, and an SMM Supervisor. In practice Secure Launch is available on Intel Coffee Lake (Core 8th-generation) and later platforms; on AMD with Zen 2 and later (Ryzen 3000+ desktop; EPYC 7002+ server with SKINIT); and on Qualcomm Snapdragon SD850 and later on the ARM side. Fleets dominated by pre-2018 hardware -- and there are many of them, especially in cost-sensitive deployments -- cannot use Secure Launch as a SRTM allowlist substitute.
For those fleets, the only deployable mitigation against bitpixie remains pre-boot authentication (TPM+PIN). The cuckoo class remains open against ad-hoc attestation pipelines that do not bind AKs to device serials at provisioning. The OEM allowlist combinatorial explosion remains the unsolved problem that pushed Microsoft to DRTM in the first place.
9.7 PFP r2 in flight
The PC Client Platform Firmware Profile is in active revision. PFP r2 is expected to formalise SHA-3 support, change the default banks to SHA-384 and SHA-512 (with SHA-256 retained for legacy compatibility), and codify the PCR[14] semantics that have been a Microsoft-vs-Linux ontology disagreement for the past decade. As of 2026 the revision is UNVERIFIED_FETCH from the TCG canonical URL (same 403 class); the tpm2_eventlog man page tracks the spec by name without a rev number, deliberately so it can absorb r2 without rebuild.
You have read 8,000 words. You have a recovery prompt to clear on Monday morning. What do you do?
10. Practical Guide: A Monday-Morning Checklist
Six actions. Each one tied to a verified Microsoft Learn or TCG source. Run them in order; you will know more about your fleet's measured-boot posture in twenty minutes than most operators learn in a year.
10.1 Inspect your log
Run tpmtool.exe getdeviceinformation from an elevated prompt; §6.7 enumerates the cross-platform and Linux equivalents. For a clean machine-readable dump, save the binary log via MeasuredBootTool.exe -log <path> (Windows HLK), then parse it with tpm2_eventlog for a portable text dump. The event stream conforms to the TCG_PCR_EVENT2 struct documented in the Tbsi_Get_TCG_Log reference.
10.2 Confirm your BitLocker PCR profile
Run manage-bde -status C: from an elevated prompt. Confirm a Numerical Password protector exists -- without one, you cannot recover from a profile mismatch and you are one PCR drift away from data loss. Then inspect HKLM\SOFTWARE\Policies\Microsoft\FVE\PlatformValidationProfileUEFI. On a Secure Boot UEFI machine the value should be 0x880 (PCR[7] + PCR[11]) per the BitLocker countermeasures documentation: "By default, BitLocker provides integrity protection for Secure Boot by utilizing the TPM PCR[7] measurement."
If you see 0x815 (PCR[0,2,4,11]), you are running the legacy CSM profile and every firmware update will trigger a recovery prompt. The fix is to verify Secure Boot is on (Confirm-SecureBootUEFI from PowerShell), then re-seal by disabling and re-enabling the TPM protector.
10.3 Suspend BitLocker before every firmware update
The only safe pattern is this:
The full Suspend-Patch-Resume PowerShell incantation
# Run as administrator.
# Suspend BitLocker for the next 1 reboot. BitLocker auto-resumes after the
# next clean boot completes, regardless of how many additional boots happen.
Suspend-BitLocker -MountPoint "C:" -RebootCount 1
# Now run the OEM firmware updater or the Windows cumulative update that
# touches Secure Boot. The PCRs will move; BitLocker will not see a mismatch
# because the seal check is bypassed for this boot.
# After the patch reboot, BitLocker automatically re-seals to the new PCR
# values. To verify, run:
manage-bde -status C:
# The output should show "Protection On" and the new PCR profile.10.4 Enable Secure Launch on Secured-Core hardware
If your hardware supports DRTM (Intel TXT-capable Coffee Lake or later, AMD Zen 2 or later with SKINIT, ARM SD850 or later), enable Secure Launch. The configuration guide lists the four paths: MDM via Intune, Group Policy, the Windows Security UI, or the registry directly at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios. Once enabled, Secure Launch absorbs OEM firmware diversity into the small DRTM TCB, reducing the verifier's allowlist burden from O(vendors x firmware versions) to O(vendor).
10.5 For high-value devices, switch to TPM+PIN
This is the only deployed mitigation that closes bitpixie pre-attack. From Microsoft's countermeasures documentation, four unlock modes exist: TPM-only, TPM+startup-key, TPM+PIN, TPM+startup-key+PIN. Of those, only the modes that require a human secret survive a downgrade attack -- the attacker can recreate the seal-time PCRs by booting an older signed boot manager, but they cannot recreate the PIN.
Enable it with manage-bde -protectors -add C: -tpmandpin <PIN>. Users will type the PIN at boot. For Secured-Core fleets where the BIOS exposes USB and TPM+PIN before the OS, this is the best practical security/UX trade. For high-value developer or executive endpoints it is non-negotiable.
10.6 Bind your attestation keys to the device at provisioning
The cuckoo class only closes if the verifier knows the specific TPM's endorsement key before trust is needed. Microsoft Autopilot and Hello for Business do this transparently during device enrollment, capturing the EK certificate chain and cross-checking it against the OEM root before issuing the device-bound key. Ad-hoc deployments -- "we joined our domain after first boot" -- usually skip this step and leave the cuckoo path open. If you run an attestation pipeline outside Hello for Business or Azure Attestation, audit your AK provisioning: is the EK chain captured at first boot, and is it bound to a unique device record?
The Monday-morning steps are six items long. The structural questions are not. We close with the questions every reader still has.
11. Frequently Asked Questions
Frequently asked questions about Measured Boot and PCR-bound BitLocker
Why am I being prompted for a 48-digit recovery key after a BIOS update?
Because PCR[0] or PCR[7] changed. BitLocker's seal binds the Volume Master Key to a specific subset of PCR values captured at seal time. A UEFI firmware update changes the EV_S_CRTM_VERSION and EV_EFI_PLATFORM_FIRMWARE_BLOB digests in PCR[0]; a Secure Boot dbx update changes PCR[7]. On boot, the TPM runs TPM2_PolicyPCR against the current PCRs, fails the match, and refuses to release the VMK. BitLocker falls back to the recovery-key protector. The fix is to suspend BitLocker before the patch with Suspend-BitLocker -MountPoint "C:" -RebootCount 1, per Microsoft's BitLocker countermeasures documentation.
What's the difference between Secure Boot and Measured Boot?
Secure Boot is enforcement: it refuses to run code that isn't signed by a trusted certificate in the db variable. Measured Boot is reporting: it records what ran -- signed or not -- into PCRs and the TCG event log. They cooperate but don't substitute. Secure Boot stops a bootkit from running. Measured Boot lets a remote verifier confirm, after the fact, that no bootkit ran. The TPM-based Trusted Boot extension continues the measurement chain into the Windows kernel, drivers, and ELAM.
If Secure Boot is on, do I still need Measured Boot?
Yes. The remote-attestation evidence chain is a measured-boot artifact -- Azure Attestation, Intune Device Health Attestation, Hello for Business device-bound key attestation, BitLocker PCR-bound unseal, and System Guard runtime attestation all consult the TCG event log and PCR snapshot. Secure Boot has no remote-reporting story; it cannot, by itself, prove to a verifier in Azure that this laptop in the field booted the firmware Microsoft signed off on. Measured Boot is what makes that proof possible.
Why does BitLocker bind to PCR[7] instead of PCR[0,2,4,11]?
Because PCR[7] is the policy PCR, not the code PCR. Firmware updates and option-ROM changes move PCR[0] and PCR[2]; Secure-Boot-policy hashes don't change unless the actual PK/KEK/db/dbx variables change. The result: a fleet on the default UEFI profile (0x880 = PCR[7] + PCR[11]) survives Dell and HP and Lenovo firmware updates without recovery prompts, because those vendors' firmware updates move PCR[0] and not PCR[7]. The trade-off is that PCR[7] only moves when Secure Boot's identity moves -- which is exactly when you do want a recovery prompt (a key revocation is a real security event). Microsoft makes the trade-off explicit in the BitLocker countermeasures documentation.
Can attestation prove my OS isn't compromised right now?
No. Attestation proves what booted. It captures the boot-time state of the platform up to a EV_SEPARATOR event the kernel emits early in OS bootstrap. Anything that happens after the separator -- a malicious kernel driver loaded at runtime, a memory-corruption exploit in a Win32 service, a rootkit that bypasses HVCI -- is invisible to PCR-based attestation. The runtime-attestation problem is what Windows Defender System Guard runtime attestation and Microsoft's hypervisor-isolated runtime checks try to address; that is a separate trust system layered on top of measured boot, not part of it.
What is PCR[14] for on Windows?
Microsoft's Windows Boot Configuration Log convention uses PCR[14] for boot-loader-authority events -- WBCL records that capture which authorities the boot manager consulted for code-integrity decisions. The Linux shim convention uses PCR[14] for Machine Owner Key (MOK) enrolment events. Same PCR index; different ontology. A verifier reading PCR[14] must know which OS produced the log it is reading; the value is meaningless without that context. This is one of the corner cases PFP r2 is expected to formalise.
Is bitpixie fixed?
Not on TPM-only BitLocker, not yet. The structural fix is KB5025885 (May 2023) which enrolls the new Windows UEFI CA 2023 certificate and ultimately revokes the 2011 CA in dbx. Full revocation is gated on the 2011 CA's 2026 natural expiry. Until then, an attacker can still downgrade to a 2011-signed boot manager whose PXE-soft-reboot path leaks the VMK. The only pre-attack mitigation that closes the class today is pre-boot authentication: TPM+PIN, or TPM+startup-key, or both. The 38C3 talk demonstrated the attack on fully-patched late-2024 firmware.
Study guide
Key terms
- PCR (Platform Configuration Register)
- Append-only TPM register that extends rather than stores. Modern TPMs have 24 PCRs per hash bank; `PCR[N] := H(PCR[N] || measurement)`.
- CRTM (Core Root of Trust for Measurement)
- The smallest, lowest, immutable code that runs after platform reset. It measures the next firmware stage into PCR[0] and is an axiomatic root, not a verified one.
- SRTM (Static Root of Trust for Measurement)
- The measurement chain rooted at the CRTM, covering PCRs 0-7 and 11-14 across firmware, boot manager, OS loader, ELAM, and kernel.
- DRTM (Dynamic Root of Trust for Measurement)
- Mid-boot CPU primitive (Intel `GETSEC[SENTER]`, AMD `SKINIT`) that resets PCRs 17-22 and atomically launches a vendor-signed Authenticated Code Module plus a Measured Launch Environment.
- TCG Event Log / WBCL
- Ordered list of `TCG_PCR_EVENT2` records (with Microsoft-specific WBCL extensions in PCRs 11/12/13) that the verifier replays to re-derive PCR values from a `TPM2_Quote`.
- TPM2_PolicyPCR / TPM2_Unseal
- TPM 2.0 commands that bind a sealed blob's release to a specific PCR profile. BitLocker uses this pair to release the VMK only when current PCRs match the seal-time digest.
- Authenticode
- Microsoft PE-image digest format used for code signing. PCR[4] hashes the Authenticode digest of `bootmgfw.efi`, not the raw bytes of the file.
- Cuckoo Attack
- An attestation-relay attack (Parno 2008) in which a compromised device proxies a verifier's challenge to a different genuine TPM and returns that TPM's valid signed quote. Closeable only by pre-binding the AK to the device serial.
References
- (1997). A Secure and Reliable Bootstrap Architecture. https://www.cs.umd.edu/~waa/pubs/oakland97.pdf ↩
- (2009). Attacking Intel Trusted Execution Technology. https://invisiblethingslab.com/resources/bh09dc/Attacking%20Intel%20TXT%20-%20paper.pdf ↩
- (2008). Bootstrapping Trust in a "Trusted" Platform. https://www.usenix.org/legacy/event/hotsec08/tech/full_papers/parno/parno.pdf ↩
- (2008). Bootstrapping Trust in a "Trusted" Platform. https://www.usenix.org/conference/hotsec-08/bootstrapping-trust-trusted-platform ↩
- Tbsi_Get_TCG_Log function (tbs.h). https://learn.microsoft.com/en-us/windows/win32/api/tbs/nf-tbs-tbsi_get_tcg_log ↩
- How hardware-based root of trust helps protect Windows. https://learn.microsoft.com/en-us/windows/security/hardware-security/how-hardware-based-root-of-trust-helps-protect-windows ↩
- BitLocker Countermeasures. https://learn.microsoft.com/en-us/windows/security/operating-system-security/data-protection/bitlocker/countermeasures ↩
- System Guard Secure Launch and SMM protection. https://learn.microsoft.com/en-us/windows/security/hardware-security/system-guard-secure-launch-and-smm-protection ↩
- Microsoft Azure Attestation overview. https://learn.microsoft.com/en-us/azure/attestation/overview ↩
- TPM attestation concepts (Azure Attestation). https://learn.microsoft.com/en-us/azure/attestation/tpm-attestation-concepts ↩
- Secure the Windows 10 boot process. https://learn.microsoft.com/en-us/windows/security/operating-system-security/system-security/secure-the-windows-10-boot-process ↩
- Secured-core PCs (OEM highly secure 11). https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-highly-secure-11 ↩
- ISO/IEC 11889-1:2015 -- Trusted platform module library Part 1: Architecture. https://www.iso.org/standard/66510.html ↩
- NIST SP 800-155 (Initial Public Draft): BIOS Integrity Measurement Guidelines. https://csrc.nist.gov/pubs/sp/800/155/ipd ↩
- NIST SP 800-155 IPD (December 2011 draft PDF). https://csrc.nist.gov/files/pubs/sp/800/155/ipd/docs/draft-SP800-155_Dec2011.pdf ↩
- CVE-2023-21563: BitLocker Security Feature Bypass Vulnerability. https://nvd.nist.gov/vuln/detail/CVE-2023-21563 ↩
- CVE-2022-21894: Secure Boot Security Feature Bypass Vulnerability (Baton Drop). https://nvd.nist.gov/vuln/detail/CVE-2022-21894 ↩
- BlackLotus UEFI bootkit: Myth confirmed. https://www.welivesecurity.com/2023/03/01/blacklotus-uefi-bootkit-myth-confirmed/ ↩
- Windows BitLocker: Screwed without a Screwdriver (38C3). https://events.ccc.de/congress/2024/hub/en/event/windows-bitlocker-screwed-without-a-screwdriver/ ↩
- BitLocker: Screwed without a Screwdriver (Neodyme blog). https://neodyme.io/en/blog/bitlocker_screwed_without_a_screwdriver/ ↩
- bitpixie technical write-up (SySS). https://blog.syss.com/posts/bitpixie/ ↩
- UEFI Forum specifications index. https://uefi.org/specifications ↩
- UEFI Specification 2.10. https://uefi.org/specs/UEFI/2.10/index.html ↩
- Trusted Platform Module (Wikipedia). https://en.wikipedia.org/wiki/Trusted_Platform_Module ↩
- Trusted Execution Technology (Wikipedia). https://en.wikipedia.org/wiki/Trusted_Execution_Technology ↩
- Trusted Computing Group (Wikipedia). https://en.wikipedia.org/wiki/Trusted_Computing_Group ↩
- SHA-1 (Wikipedia). https://en.wikipedia.org/wiki/SHA-1 ↩
- Unified Extensible Firmware Interface (Wikipedia). https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface ↩
- x86 virtualization (Wikipedia). https://en.wikipedia.org/wiki/X86_virtualization ↩
- Attacking Intel TXT -- paper and slides (Invisible Things Lab blog). https://theinvisiblethings.blogspot.com/2009/02/attacking-intel-txt-paper-and-slides.html ↩
- Wack0/bitlocker-attacks index (GitHub). https://github.com/Wack0/bitlocker-attacks ↩
- martanne/bitpixie proof-of-concept (GitHub). https://github.com/martanne/bitpixie ↩
- tpm2-software/tpm2-tools. https://github.com/tpm2-software/tpm2-tools ↩
- tpm2_eventlog man page. https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_eventlog.1.md ↩
- TrenchBoot documentation (GitHub). https://github.com/TrenchBoot/documentation ↩
- TrenchBoot project home. https://trenchboot.org/ ↩
- GETSEC[SENTER] (Intel SDM mirror, felixcloutier.com). https://www.felixcloutier.com/x86/senter ↩
- Bryan Parno -- faculty page (CMU). https://www.andrew.cmu.edu/user/bparno/ ↩
- TPM 2.0 Library Specification (TCG). https://trustedcomputinggroup.org/resource/tpm-library-specification/ - UNVERIFIED_FETCH; trustedcomputinggroup.org returns HTTP 403 to non-browser User-Agents. Cited canonically; verbatim struct definitions sourced from ms-tbs-get-tcg-log. ↩
- PC Client Platform Firmware Profile Specification (TCG). https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ - UNVERIFIED_FETCH; same TCG 403 class as tcg-tpm-library. ↩
- How to manage the Windows Boot Manager revocations for Secure Boot changes associated with CVE-2023-24932. https://support.microsoft.com/en-us/topic/how-to-manage-the-windows-boot-manager-revocations-for-secure-boot-changes-associated-with-cve-2023-24932-41a975df-beb2-40c1-99a3-b3ff139f832d ↩
- MSRC advisory for CVE-2023-21563 (bitpixie). https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-21563 ↩
- BitLocker Group Policy settings. https://learn.microsoft.com/en-us/windows/security/operating-system-security/data-protection/bitlocker/bitlocker-group-policy-settings ↩
- manage-bde protectors. https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/manage-bde-protectors ↩