← Back to Logs

How Secure Boot And The TPM Actually Work

Try the interactive lab for this articleTake the quiz (6 questions · ~5 min)

Take a laptop in a Lisbon coworking space, reboot it, and watch nothing happen. The machine goes dark for a few seconds, the vendor logo appears, and then Windows or Linux starts loading. No prompts, no warnings, no visible security theatre. And yet, if you had swapped the SSD for one carrying a tampered bootloader, if you had flashed the firmware with a modified EFI module, if you had plugged in a rogue PCIe expansion card with its own option ROM, the machine would have refused to run, or it would have booted but silently locked its disk encryption key inside a hardware chip that refused to release it until the tampering was undone.

That invisible refusal is the job of two closely related systems that ship on essentially every modern PC, server, and high-end Android tablet: UEFI Secure Boot and the Trusted Platform Module. They do different jobs, they sit at different points in the chain, and they solve different problems, but they are almost always discussed together because neither is useful in isolation. Secure Boot is a gatekeeper: it refuses to run code that is not signed by a key in its trust database. The TPM is a witness: it records every piece of code that runs, extending a running hash of the boot state into a set of dedicated registers, and it lets you tie the release of secrets (like a disk encryption key) to a particular measured state.

The combination is what makes "the machine will only decrypt the drive if nothing on the boot path has been tampered with" a reasonable guarantee rather than wishful thinking. Secure Boot prevents the attacker from running their modified code in the first place. The TPM ensures that even if they manage to boot modified code somehow, the secrets that would make that code useful are not released.

This article walks through the whole chain, from the moment the power button is pressed to the point where the operating system's disk encryption is unlocked. The goal is to build a concrete picture of what every component does, what attacks it stops, what attacks it does not stop, and why both halves of the system exist. By the end it should be clear why a laptop with Secure Boot and TPM sealing configured correctly is genuinely hard to attack offline, even for someone with physical access and an hour alone with the hardware, and also clear what the real failure modes are when something in the chain goes wrong.

What Secure Boot Actually Checks

Start with the gatekeeper. UEFI Secure Boot is a feature of the firmware spec (UEFI 2.3.1 and later) that requires every EFI executable the firmware loads to be signed by a key present in one of the firmware's trust databases. If the signature does not verify, the firmware refuses to load the executable. If no signature is present at all, the firmware refuses to load it. The check is done inside the firmware's boot manager, before any operating system code runs, and before any expansion card firmware runs.

There are four key databases involved, and their relationship is worth laying out clearly:

  • PK (Platform Key): a single X.509 certificate that controls everything else. Whoever holds the private key of PK can modify the other databases. On most consumer laptops the PK is owned by the vendor (Dell, HP, Lenovo, Acer, Asus), so only the vendor can push updates that change the trust database. PK has to be replaced as a whole; you cannot add a second PK.

  • KEK (Key Exchange Key): a database of certificates that can modify the "db" and "dbx" databases below. In practice there are usually two KEK entries: one from the vendor, and one from Microsoft. The Microsoft entry is what lets Microsoft push Secure Boot updates through Windows Update, including revocations of compromised bootloaders.

  • db (allowed signatures database): a list of certificates, SHA-256 hashes, or raw signatures that Secure Boot will accept when validating an EFI binary. Any binary signed by a certificate in db, or whose hash is present in db, is allowed to run. Consumer hardware typically ships with two certificates in db: the "Microsoft Windows Production CA" (which signs the Windows bootloader) and the "Microsoft Corporation UEFI CA" (which signs third-party EFI binaries, most famously including shim, the small EFI binary used to bootstrap Linux distributions into Secure Boot).

  • dbx (forbidden signatures database): the revocation list. If a binary is signed by a key or matches a hash in dbx, it is rejected, even if it would otherwise match an entry in db. dbx grows over time as vulnerabilities are found and compromised bootloaders are revoked. A modern laptop from 2025 has dozens of entries in dbx covering things like old grub2 versions with known vulnerabilities, the original BlackLotus bootkit, and early versions of shim with parsing bugs.

When the firmware needs to load an EFI binary (say, \EFI\Microsoft\Boot\bootmgfw.efi on a Windows disk, or \EFI\ubuntu\shimx64.efi on Ubuntu), it:

  1. Reads the binary from the EFI system partition.
  2. Finds the Authenticode signature block inside the PE/COFF header.
  3. Walks the certificate chain back to a root certificate.
  4. Checks whether that root, any intermediate certificate, or the leaf certificate is present in db.
  5. Checks whether the binary's hash, any certificate in the chain, or the signature itself is present in dbx.
  6. Only runs the binary if db matches and dbx does not.

The check is performed by the firmware using its own crypto library, not anything loaded from disk. That matters because the firmware is in a position of trust: it has to assume the attacker may have already written to the disk, to the boot partition, or to any non-firmware storage. The firmware itself lives in SPI flash, and Secure Boot assumes that SPI flash has not been tampered with. Protecting the SPI flash from tampering is the job of a separate mechanism called BIOS Guard or Intel Boot Guard (on Intel platforms), or PSP and HVCI (on AMD), which we will come back to.

Where The Chain Starts: Boot Guard And The Hardware Root

Secure Boot protects the boot path from the firmware onward. But what protects the firmware itself? If an attacker can reflash the SPI chip with modified firmware, they can install their own PK, their own db entries, and Secure Boot becomes a closed loop where the attacker has rewritten the rules.

This is where Intel Boot Guard (and the equivalent AMD Platform Secure Boot) comes in. Boot Guard is a hardware feature of modern Intel CPUs that validates the firmware image before the CPU executes any instructions from SPI flash. The Management Engine (ME) inside the chipset reads a small manifest from the SPI at reset, verifies its signature against a public key hash fused into the CPU at manufacture time, and then either allows the CPU to fetch its first instruction normally, or prevents boot entirely.

The key hash in the fuses is programmed by the OEM (the laptop vendor) at manufacture time and is permanent. It cannot be changed, updated, or extended after the fact, because "fuses" means a one-time programmable region where a memory cell is physically blown to a permanent state. Once the OEM sets their key in the fuses and ships the laptop, that laptop will only boot firmware signed by that key, forever.

This is the hardware root of trust. Everything above it is cryptographically anchored to those fuses. The ME verifies the firmware, the firmware verifies Secure Boot's databases (which are stored in a variable region that the firmware itself protects), Secure Boot verifies the bootloader, the bootloader verifies the kernel, and so on. Break any link in the chain and the attacker has to defeat everything above it as well.

The fuses are also the reason why "disabling Secure Boot" on a typical laptop does not disable Boot Guard. Secure Boot is a policy decision expressed through UEFI variables that the firmware itself enforces. Turning it off in the BIOS setup just flips a variable and changes the firmware's behaviour. Boot Guard is a hardware behaviour that runs before the firmware is even allowed to execute, and most OEMs configure it to Verified Boot (the strong mode), which enforces the firmware signature check regardless of what the UEFI settings say. Some OEMs use Measured Boot only (which records the firmware hash into the TPM without blocking unsigned firmware), but on consumer laptops Verified Boot is now the norm.

There have been notable breaks. In 2020 a leak of Intel's internal documentation and source exposed some details of how Boot Guard works, and a few specific OEMs were found to have misconfigured their fuses (either leaving them unsigned, which disables the check, or using keys that were subsequently leaked). In 2023 the MSI key leak, where the signing keys for dozens of MSI motherboards were exposed by a ransomware attack on MSI, meant that anyone could sign modified firmware that would pass Boot Guard on those boards. These are real failures, but they are failures of key management at specific vendors, not of the architecture.

Measured Boot: The TPM As A Witness

Now switch from the gatekeeper to the witness. Measured Boot is the parallel story to Secure Boot. Where Secure Boot says "refuse to run if not signed", Measured Boot says "whatever happens, record a hash of what ran into the TPM so we can ask later". The two mechanisms are independent. You can run Measured Boot without Secure Boot (Linux distributions sometimes do this for flexibility), and you can run Secure Boot without Measured Boot (though almost no one does).

The TPM (Trusted Platform Module) is a small chip, either a discrete component on the motherboard or a firmware TPM emulated inside the CPU (Intel PTT, AMD fTPM), that provides three things: a set of Platform Configuration Registers (PCRs), a set of key storage and crypto operations, and a sealed storage mechanism that ties secrets to PCR values.

A PCR is not a normal register. You cannot write to it. You can only extend it. The extend operation takes the current value of the PCR (say, 32 bytes for a SHA-256 PCR) and a new hash, concatenates them, SHA-256s the result, and stores the result back. The mathematical definition is:

PCR[i] := SHA256(PCR[i] || new_hash)

This is a one-way operation. Once you have extended a PCR with some value, there is no way to "un-extend" it. You cannot set it back to a previous state without rebooting the TPM. And because SHA-256 is collision-resistant, there is no way to get a particular final PCR value unless you extend it with the exact sequence of hashes in the exact order, assuming you do not have preimage attacks on SHA-256.

At boot, the firmware extends a sequence of PCRs with hashes of everything that happens:

  • PCR 0: the BIOS/firmware itself (excluding the Boot Guard manifest).
  • PCR 1: host platform configuration, including firmware variables and BIOS settings that affect boot behaviour.
  • PCR 2: option ROMs from PCIe cards (graphics, NICs, RAID controllers).
  • PCR 3: option ROM configuration.
  • PCR 4: the master boot record or, more commonly now, the bootloader EFI binary (bootmgfw.efi, shimx64.efi, grubx64.efi).
  • PCR 5: the partition table and GPT entries.
  • PCR 6: resume events from S3 state (suspend).
  • PCR 7: Secure Boot policy, which includes the contents of PK, KEK, db, and dbx. This PCR is the most useful for BitLocker and LUKS sealing, because it captures the entire Secure Boot state in one value.
  • PCR 8 to 15: free for use by the operating system, the bootloader, or the kernel.
  • PCR 9: Linux distributions often use this for initrd hashes.
  • PCR 11: unified kernel image (UKI) hash in systemd-boot setups.
  • PCR 14: the shim's MokList (the Linux-specific trust database layered on top of UEFI db).

The exact meaning of each PCR is defined by the TCG (Trusted Computing Group) PC Client Platform Firmware Profile specification, and operating systems follow it so that PCR values are portable across vendors. A Windows 11 machine's PCR 7 means the same thing as an Ubuntu 24.04 machine's PCR 7: "the hash chain of every Secure Boot variable the firmware observed at boot".

The important property is that PCRs are only reset on a cold boot (and on some systems, after the TPM is physically tampered with and detects it). A running system cannot reset its own PCRs. Once the kernel has booted, the PCRs contain a cumulative hash of everything that ran before it, and that hash is frozen until the next reboot.

Sealing: Releasing A Secret Only If The PCRs Match

The third thing the TPM does is the payoff for all of the PCR bookkeeping. The TPM can seal a secret to a specific set of PCR values. Sealing means the TPM takes a blob of plaintext (typically an AES key or similar), encrypts it with an internal key that never leaves the chip, and stores the ciphertext along with a policy that says "you can only unseal this if PCRs X, Y, and Z currently have these exact values".

When the operating system later asks the TPM to unseal the blob, the TPM:

  1. Decrypts the ciphertext internally with its storage key.
  2. Reads the current PCR values.
  3. Compares them to the policy.
  4. If they match, returns the plaintext.
  5. If they do not match, returns an error and wipes the decryption buffer.

The critical thing is that the decision to release or not release happens inside the TPM, with the secret never leaving the chip unless the policy is satisfied. There is no "ask nicely" path. There is no debug interface that lets you read sealed blobs unconditionally. There is no memory dump that contains the plaintext, because the plaintext is only briefly present in the TPM's internal SRAM while the unseal is running, and the TPM is typically a separate chip on the motherboard (or a firmware container inside the ME) that you cannot probe without destroying it.

This is what BitLocker and LUKS use to implement "the disk automatically decrypts at boot if nothing has changed, and refuses to decrypt if anything has". BitLocker seals its Volume Master Key (VMK) to PCRs 0, 2, 4, 7, and 11 on most systems (the exact set depends on the BitLocker configuration). When Windows boots:

  1. The bootloader asks the TPM to unseal the VMK.
  2. The TPM checks the current PCR state.
  3. If everything matches (same firmware, same option ROMs, same bootloader, same Secure Boot policy, same boot configuration), the TPM releases the VMK.
  4. Windows uses the VMK to decrypt the Full Volume Encryption Key (FVEK) and mounts the OS drive.

If any PCR does not match, the TPM refuses to release the VMK. BitLocker then falls back to asking for the recovery key, a 48-digit number that the user must type in manually. This is the visible failure mode: swap the drive to a different laptop, or reflash the firmware, or boot from a different device, or change the boot order in some systems, and BitLocker demands the recovery key. It is inconvenient, and occasionally it is a real problem, but it is doing exactly what it was designed to do. The point is that the key cannot be extracted without either (a) the TPM being happy with the current PCRs, or (b) the 48-digit recovery key, which is normally held by the user or stored in their Microsoft or Azure AD account.

LUKS on Linux supports the same model through systemd-cryptenroll or the older clevis framework. You enrol a LUKS slot against a TPM 2.0 policy binding it to specific PCRs (PCR 7 for Secure Boot state, PCR 14 for Linux MOK, PCR 11 for the unified kernel image), and the initrd asks the TPM to unseal the passphrase at boot. If the seal fails, the user has to type the original passphrase.

How The Attacks Work

The interesting question is always "what attack does this actually stop?". For Secure Boot plus TPM sealing, the answer is "attacks where the adversary has offline access to the disk or the firmware, but cannot extract a secret from the TPM". Let us walk through the attacks concretely.

Attack 1: swap the disk, read it. Dimitris steals Katerina's laptop on a train from Lisbon to Porto. He pulls the SSD, plugs it into a USB enclosure, and tries to read it from his own machine. With BitLocker or LUKS enabled and sealed to the TPM, the disk is encrypted, and the decryption key is inside Katerina's TPM, which is still in Katerina's laptop. Dimitris has nothing. He would have to break the AES encryption directly, which is not feasible.

Attack 2: keep the disk in the laptop, boot from USB. Dimitris plugs in a Live Linux USB to the stolen laptop and boots it. Secure Boot either refuses to load the USB (because the live USB's bootloader is not in db) or accepts it if the live distro ships a signed shim. Either way, the Linux boot changes the PCR state, because the hash of the bootloader, kernel, and initrd is different from what Katerina's laptop normally boots. PCRs 4, 9, 11, 14 all change. When Dimitris tries to mount the sealed LUKS volume from the live environment, the TPM refuses to unseal, because the policy was bound to Katerina's expected PCR state. Dimitris still has nothing.

Attack 3: reflash the firmware with a modified version. Dimitris downloads Katerina's laptop's firmware, patches it to accept an attacker-controlled bootloader, and tries to reflash. If Boot Guard is enforced (which it is on almost all modern laptops), the modified firmware fails the hardware signature check and the CPU refuses to execute it. If Boot Guard is bypassed (for example, through a vulnerability in the ME, which happens occasionally), the modified firmware runs, but its hash is different from the original, so PCR 0 contains a different value after boot. The TPM refuses to unseal. Dimitris has the machine running his firmware, but the disk is still encrypted.

Attack 4: cold boot the machine with a rogue PCIe card. This was the classic pre-TPM-sealing attack. Plug in a Thunderbolt device that does DMA over PCIe and dump the contents of physical memory while Windows is running. Modern laptops ship with IOMMU protection (Intel VT-d or AMD-Vi) that restricts DMA access from PCIe devices to specific memory regions, and Windows 10/11 and modern Linux kernels use the IOMMU to prevent external DMA from reading arbitrary memory. If the IOMMU is not configured (older firmware, or vendor-specific quirks), the attack still works and the Secure Boot and TPM story has nothing to say about it, because at that point the attacker is reading memory from a running authorised OS.

Attack 5: LogoFAIL and similar image parsing vulnerabilities. In 2023 the LogoFAIL vulnerability class was disclosed: a series of bugs in the image parsing code that firmware uses to render vendor splash screens at boot. The firmware on many laptops parsed BMP or PNG files from a non-signed region of the firmware volume (because boot splashes were considered cosmetic), and a carefully crafted image could exploit a heap overflow in the parser to run arbitrary code in the firmware context before Secure Boot started enforcing its policy. This bypassed Secure Boot for the attacker's custom code, but the resulting execution still had to deal with the TPM. The attacker's code running in the firmware could not unseal the BitLocker VMK because the PCR state it would measure as it booted would not match the stored policy. So LogoFAIL was a Secure Boot bypass, not a TPM seal bypass, which is an important distinction.

Attack 6: evil maid with a long time window. Dimitris is Katerina's colleague and has unsupervised access to her laptop overnight. He boots it into recovery mode, installs a keylogger into the operating system, reboots. This is where Secure Boot and TPM sealing have limits. If the OS is already unlocked (which requires Katerina to type her PIN or password), then Dimitris's modifications happen inside an authorised running system, and the TPM is already happy. The defence against this attack is operating system integrity (SELinux, AppArmor, Windows integrity levels), not Secure Boot or the TPM.

But there is a version of evil maid that Secure Boot and sealing do stop. Dimitris cannot install a bootkit that runs before the OS starts, because the bootkit would be unsigned code that Secure Boot refuses. And he cannot replace the firmware or the bootloader and still get the TPM to release the VMK, because the PCR state would be different. The set of things he can do offline, with the disk encrypted and sealed, is dramatically smaller than it was in the pre-TPM era.

PCR Policy Design: The Hard Part

Sealing to the wrong PCRs is a common and painful mistake. If you seal to too few PCRs, you lose security guarantees because small changes in the boot environment do not invalidate the seal. If you seal to too many, you turn every firmware update into a BitLocker recovery key prompt, because the firmware hash in PCR 0 changes on every update.

The TCG recommends sealing BitLocker to PCR 7 as the primary strategy, because PCR 7 captures the Secure Boot policy as a whole. PCR 7 only changes if the UEFI variables that define Secure Boot change (PK, KEK, db, dbx, and the Secure Boot enable flag). A firmware update that does not touch those variables leaves PCR 7 unchanged, so BitLocker does not prompt. But if someone tampers with Secure Boot, or disables it, PCR 7 changes and BitLocker refuses to unseal. This has turned out to be a reasonable tradeoff in practice, and it is why Windows 11 seals primarily to PCR 7 by default on modern hardware.

The trickier case is Linux. LUKS setups often want to seal to PCR 11, which captures the unified kernel image hash. This is stronger than PCR 7 (because it pins the exact kernel and initrd that must boot), but it means every kernel update breaks the seal and the user has to re-enrol. systemd-cryptenroll supports automated re-enrolment on successful boot: after the user has typed their passphrase once, the new kernel's PCR 11 is known, and the initrd re-seals the passphrase to the new PCR value. It works, but the first boot after an update is slow and visible.

There is also the problem of the "firmware update attack". When a vendor ships a legitimate firmware update, the user applies it, and the new firmware has a different PCR 0 value. BitLocker prompts for recovery. The user retrieves their recovery key from their Microsoft account, types it, and boots. Fine. But an attacker who gained the ability to flash firmware could, in principle, use this to trick the user into typing their recovery key into a modified environment, and capture it. This has been demonstrated in research settings but requires a very specific social-engineering setup. In practice it is not a common attack path.

TPM 2.0 Versus TPM 1.2: Why The Upgrade Matters

Everything above assumes TPM 2.0. Earlier TPM 1.2 devices shipped on PCs from around 2006 and were not much fun to work with. They supported only SHA-1, had a very small set of algorithms, used a hierarchy model where the Endorsement Key and Storage Root Key were fixed at manufacturing, and had almost no flexibility for policy expression.

TPM 2.0, standardised in 2014 and mandatory on Windows 11 hardware from 2021 onward, fixes most of the problems. It supports multiple hash algorithms in parallel (SHA-1, SHA-256, SHA-384, SHA-512), it has a richer policy language that lets you express things like "unseal if PCR 7 matches AND PCR 14 is in this set AND the current time is before this date", it supports multiple independent hierarchies (Platform, Storage, Endorsement, Null), and it is architected to make post-quantum upgrades easier.

The shift from SHA-1 to SHA-256 for PCR values is particularly important. SHA-1 has known collisions in the general sense since SHAttered in 2017, and although a second-preimage attack on SHA-1 is much harder than a collision attack, building boot-time security on SHA-1 in 2026 would be a poor choice. TPM 2.0 maintains a separate PCR bank per supported hash algorithm, and modern operating systems use the SHA-256 bank by default.

There are two flavours of TPM 2.0 in practice: discrete TPMs (dTPM) and firmware TPMs (fTPM). A discrete TPM is a separate chip, typically from Infineon, STMicroelectronics, or Nuvoton, connected to the CPU over LPC or SPI. It has its own SRAM, its own flash, and a well-defined physical boundary. A firmware TPM runs inside the CPU's secure environment (Intel PTT, AMD fTPM) and shares hardware with the rest of the secure world. Firmware TPMs are cheaper and simpler for OEMs (one less component), but they inherit the security of the enclosing secure environment, which has been broken in a few embarrassing ways over the years.

The most memorable fTPM failure was the AMD fTPM stutter in 2022. Under certain conditions, fTPM operations on Zen 2/Zen 3 systems would block for hundreds of milliseconds at a time, which turned into visible system stutters every few minutes. The root cause was contention in the SMU (System Management Unit) that hosts the fTPM, and AMD eventually fixed it with firmware updates. Not a security failure as such, but a good illustration of the difference between a dedicated chip and a shared one. More concerning was the 2023 fTPM state leak on some older Ryzen parts: a vulnerability in the ASP (AMD Secure Processor) allowed extraction of TPM state under specific conditions, which would compromise any secret sealed to it. The fix required a firmware update, and in the meantime BitLocker seals on affected machines were effectively broken against a capable attacker.

Remote Attestation: Proving Your PCRs To Someone Else

Everything so far has been about local decisions: does this machine boot, does it unseal its own keys. But the TPM can also prove its PCR state to a third party, which opens up remote attestation. This is how a corporate laptop can tell a VPN concentrator "I really am running an approved firmware and bootloader and kernel", and the concentrator can decide whether to let it onto the network.

Remote attestation works by asking the TPM to produce a quote: a structure containing the current PCR values, a nonce provided by the verifier (to prevent replay), and a signature made with an attestation key that the TPM derives from its Endorsement Key. The verifier checks the signature (which proves the quote came from a genuine TPM), compares the PCR values to a known-good set, and makes a decision.

The Endorsement Key itself is certified by the TPM manufacturer at production time, with a certificate stored in the TPM's NVRAM. Intel and AMD run certificate services that sign Endorsement Keys for their firmware TPMs, and Infineon, STMicro, and Nuvoton do the same for their discrete TPMs. The certificate chain lets a verifier trust that the key really is from a genuine TPM and not from a simulator running in software.

Corporate tooling like Windows Device Health Attestation, Azure AD conditional access, and various MDM platforms use this mechanism to enforce "only attested devices can access corporate resources". It is not widely used outside corporate IT because the verifier-side infrastructure is complex and the policy decisions are non-trivial, but it is one of the interesting consequences of having a TPM in every machine.

The Limits And The Failure Modes

Secure Boot and the TPM are not a perfect defence, and it is worth being explicit about where they stop helping.

They do not protect against a compromised running kernel. Once the kernel has booted, authenticated itself to the TPM, and unsealed its keys, a root-level compromise of the kernel has full access to everything the kernel can see. The TPM can be asked to do more operations (the kernel has credentials), but any secret that is already in kernel memory is accessible to any kernel-mode code.

They do not protect against weak user credentials. If BitLocker is enabled with a simple PIN, the TPM's anti-hammering limits the number of PIN guesses per unit time (typically to a few per minute, scaling up on repeated failures), but a determined attacker with enough time and a predictable PIN can still succeed. The TPM is not a substitute for a strong credential.

They do not protect against vulnerabilities in the signed boot chain. If a signed bootloader has a memory corruption bug, an attacker can exploit that bug and run arbitrary code inside a Secure Boot-approved process. The PCR values still record the hash of the unmodified bootloader, so the TPM seal is still happy. This is the BlackLotus attack surface: a known-good bootloader with a known bug that lets an attacker load unsigned modules. Revocations in dbx are the response, but there is a latency between the bug being discovered and the revocation being deployed.

They do not protect against an attacker who can extract the TPM's internal storage key. This is extremely hard on a physical discrete TPM (you would need to decap the chip and probe the flash), but it has been demonstrated. For firmware TPMs, it is potentially easier, because the firmware TPM's state is stored in regular platform flash, and vulnerabilities in the enclosing secure environment can expose it.

And they do not protect against social engineering. If the user is willing to type their BitLocker recovery key into a phishing page, or their LUKS passphrase into a modified initrd, no amount of hardware security helps. The TPM is a strong answer to offline attacks against the boot chain. Online attacks against the user are still a completely separate problem.

Shim And MOK: How Linux Gets Into The Secure Boot World

Linux distributions have a harder time with Secure Boot than Windows does, because db ships with only a handful of certificates, and getting a new one added to every laptop's firmware is impractical. The solution is shim, a small EFI binary maintained by Red Hat and signed by Microsoft under the "Microsoft Corporation UEFI CA" certificate that is present in db on almost all consumer hardware. Shim is the only Linux-related binary the firmware will load directly.

Shim is deliberately minimal. It does two things. First, it loads the next stage (usually grubx64.efi or systemd-boot) and verifies its signature against an embedded vendor certificate that identifies the distribution (Fedora, Ubuntu, SUSE, Debian each have their own). Second, it maintains the Machine Owner Key (MOK) database, a UEFI variable protected by a boot-time password that lets a local user enrol their own signing keys for local modules like DKMS-compiled Nvidia drivers or custom-built kernels.

When you install the Nvidia proprietary driver on a Secure Boot Ubuntu system, the installer builds the kernel module, signs it with a local ephemeral key, and asks you to enrol the key's public half into MOK. On next reboot shim shows a blue MokManager menu that asks for the password you typed during install, you approve the new key, and from then on the kernel will load any module signed by that key. The key is stored in a UEFI variable that only shim can write (because shim is the only thing the firmware loaded with the right credentials), and the list is measured into PCR 14 so that tampering with it invalidates TPM seals.

The design is elegant because it preserves the end-user's freedom to run their own code (the whole point of Linux) without opening a backdoor in db that everyone else would immediately abuse. Distributions that want to run a signed kernel get signed by shim's vendor cert; users who want to run their own modules enrol through MOK; and the firmware's db stays small and stable.

Shim has had its share of bugs. The most famous was the shim 15.3 URL parsing vulnerability disclosed in early 2024, where a crafted HTTP response during HTTP boot could overflow a buffer in the boot-time HTTP client. That bug, once disclosed, caused a wave of dbx updates pushing hashes of vulnerable shim builds into the revocation database, and every distribution had to rebuild shim, get it re-signed by Microsoft, and ship it as a security update. Users who did not update ended up with shim binaries that would eventually match a dbx entry and refuse to load. It is the usual cycle of "signed does not mean safe forever", and dbx is the mechanism that keeps the cycle working.

Hands-On: Sealing A Secret With tpm2-tools

To see how sealing actually looks from userspace, tpm2-tools on Linux exposes every primitive the TPM supports. A minimal flow to seal a secret to PCR 7 and unseal it later looks like this:

# Read the current PCR 7 value and save it as a policy
tpm2_startauthsession --session session.ctx
tpm2_policypcr --session session.ctx --pcr-list sha256:7 \
    --policy policy.digest
tpm2_flushcontext session.ctx
 
# Create a sealed object under the owner hierarchy
tpm2_createprimary --hierarchy o --key-context primary.ctx
tpm2_create --parent-context primary.ctx \
    --sealing-input secret.txt \
    --policy policy.digest \
    --public sealed.pub --private sealed.priv
 
# Load the sealed object and unseal it
tpm2_load --parent-context primary.ctx \
    --public sealed.pub --private sealed.priv \
    --key-context sealed.ctx
 
tpm2_startauthsession --policy-session --session session.ctx
tpm2_policypcr --session session.ctx --pcr-list sha256:7
tpm2_unseal --object-context sealed.ctx --auth session:session.ctx

The tpm2_policypcr step is the one that matters. It tells the TPM "the policy you must satisfy to unseal this is that PCR 7 currently matches this digest". If you run the unseal on the same machine in the same boot, PCR 7 has not changed, and the TPM returns the plaintext. If you reboot after changing Secure Boot settings, PCR 7 changes, the policy no longer matches, and the unseal fails with TPM2_RC_POLICY_FAIL.

You can layer more policy operations: require PCR 7 AND PCR 11, OR fall back to a second policy that requires a user-supplied authorisation value, AND require that the current time is before a specific absolute time (using tpm2_policycountertimer). The TPM's policy language is expressive enough that systemd-cryptenroll can build quite sophisticated seal policies that survive kernel updates without user intervention, by building a policy that says "PCR 11 matches any of these known-good values" and updating the allowed set each time a successful unseal happens after a verified boot.

The Event Log: Proving What Was Measured

One practical problem with raw PCR values is that they are cumulative hashes and not self-describing. If PCR 4 contains a particular 32-byte value, you cannot look at that value and tell which bootloader was measured. The value is SHA-256(SHA-256(SHA-256(...) || hash_of_boot_manager) || hash_of_bootloader), and without knowing the intermediate hashes you cannot reverse it.

The TCG solves this with the event log, a separate structured record that the firmware builds in memory during boot and then hands over to the operating system. Each entry in the event log contains the PCR index it extended, the digest value, the event type (EV_POST_CODE, EV_EFI_BOOT_SERVICES_APPLICATION, EV_IPL, and so on), and a human-readable event data field. The log is not itself trusted, because it lives in ordinary RAM and the operating system can read and write it, but it is cryptographically bound to the PCRs: if you replay the event log from zero, extending each entry in order, you should arrive at the same PCR values the TPM reports.

This replay is the basis of integrity verification. On Linux, tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements parses the event log and prints every event that contributed to the PCRs, along with the digest. tpm2_pcrread reads the current PCR values from the TPM. You replay the event log in your head (or with a verification tool like sbctl or tpm2_checkquote) and confirm that each event's digest, extended in order, produces the reported PCR values. If they match, the event log is authentic. If they do not, something has tampered with either the log or the TPM reports.

Remote attestation uses the event log this way. The verifier asks for both a TPM quote (signed PCR values) and the event log, replays the log against the quoted PCRs to confirm consistency, then inspects each log entry to make a decision: was the measured bootloader a known-good one, was the measured kernel on the allowed list, did any unexpected option ROM show up. The event log is what turns an opaque hash into a human-debuggable trace.

Physical Attacks On The TPM Itself

The boundary between the CPU and a discrete TPM chip is a low-speed serial bus, typically LPC on older platforms and SPI on newer ones. Those buses carry the plaintext of everything the CPU sends to and from the TPM: PCR extends, unseal commands, and the raw secret being released on unseal. Someone with physical access and an oscilloscope can, in principle, listen on the bus and capture the secret as it leaves the TPM.

This is the Dolos Group attack, published in 2021, which targeted Lenovo ThinkPad laptops with BitLocker sealed to a discrete TPM. The researchers soldered probes to the LPC bus between the TPM and the PCH, booted the machine through the normal Secure Boot path, captured the LPC traffic during the BitLocker unseal, and extracted the VMK from the captured bytes. Total time from physical access to unlocked drive: about thirty minutes.

The attack is not a break of the TPM's cryptography. The TPM is doing exactly what it was asked to do: unseal a secret for the authorised host and transmit it back. The problem is that the transmission is in the clear over a physically accessible bus. TPM 2.0 defines an encrypted-session mechanism that lets the CPU and the TPM negotiate a session key and encrypt all traffic between them, which defeats bus sniffing. But Windows did not enable encrypted sessions by default until Windows 11 24H2, and many older BitLocker deployments are still vulnerable on machines with discrete TPMs.

Firmware TPMs are immune to this specific attack because there is no physical bus to sniff; the TPM lives inside the CPU package and the traffic between the host and the TPM never leaves silicon. The tradeoff, as mentioned earlier, is that fTPMs inherit the security of the enclosing secure environment, which has had its own problems.

The practical response to the Dolos attack on affected systems is either (a) use a fTPM if available, (b) enable TPM 2.0 encrypted sessions (newer Windows does this), or (c) add a BitLocker PIN so that the VMK is not released based on PCR state alone but also requires a user secret that is entered through a trusted path.

A Concrete Boot Trace

Walking through all of this in the abstract makes it easier to lose track of the timeline. Here is what happens on a modern Windows 11 laptop, in order:

  1. Power button pressed. The PSU brings rails up. The PCH asserts reset.
  2. The Intel ME starts running. It reads the Boot Guard manifest from SPI flash, verifies its signature against the key hash in the CPU fuses, and either allows the CPU to begin fetching or halts the boot.
  3. The CPU begins fetching at the reset vector, in the SEC phase of UEFI. SEC initialises cache-as-RAM, validates the firmware volume, and hands off to PEI.
  4. PEI trains DRAM and hands off to DXE. Along the way, the TPM's PCR 0 is extended with the firmware's hash. PCR 1 is extended with platform configuration data.
  5. DXE loads drivers and runs option ROMs on PCIe cards. Each option ROM is hashed and extended into PCR 2 and PCR 3. Secure Boot policy decides whether to allow each option ROM based on its signature.
  6. The boot manager selects an EFI application to run. It reads the PK, KEK, db, and dbx variables, extends their hashes into PCR 7, and verifies the selected EFI binary's signature against db.
  7. If the signature check passes, the firmware extends PCR 4 with the binary's hash and transfers control. On Windows this binary is bootmgfw.efi.
  8. The Windows boot manager loads winload.efi, verifies its signature, extends PCR 4 again with the new hash, and runs it.
  9. winload.efi asks the TPM to unseal the BitLocker VMK. The TPM checks PCRs 0, 2, 4, 7, 11 against the sealed policy. They match (nothing has changed since last boot). The TPM releases the VMK.
  10. Windows uses the VMK to decrypt the FVEK and mounts the system drive.
  11. The NT kernel boots, drivers load, and the user sees the login screen.

Every step extends one or more PCRs. Every step passes or fails based on signatures or policies. Every step is logged in the event log for later inspection. If any step fails, the machine either halts or boots into a recovery environment. The entire sequence takes a few seconds, and most of it is invisible.

Why The Chain Has To Be This Long

It is tempting to ask why all of this complexity is needed. Why not have a single "is the system trustworthy" bit? The answer is that trust is not a single bit. It is a chain of decisions, each of which can fail independently, and each of which has to be made by code that itself must be trusted.

Boot Guard trusts only the fuses. The firmware trusts only what Boot Guard says is intact. Secure Boot trusts only what the firmware says is signed. The bootloader trusts only what Secure Boot says is allowed. The kernel trusts only what the bootloader handed it. And the TPM records each of these steps so that, after the fact, the system can prove what happened.

If you cut out any link in the chain, the remaining links collapse. You cannot have Secure Boot without trusted firmware, because an attacker can reflash the firmware to disable Secure Boot. You cannot have a trusted firmware without a hardware root, because an attacker can replace the SPI chip. You cannot have TPM sealing without a measurement of the code that ran, because otherwise the seal has nothing to bind to. You cannot trust the measurements without a root of trust for measurement, which Boot Guard provides by measuring the first code that runs.

The length of the chain is not accidental. It reflects the fact that modern PCs are layered machines with many points of entry, and securing them requires protecting every layer against attackers who can reach each layer independently. A hardware root of trust anchors the chain. Secure Boot gatekeeps the chain. The TPM records the chain. Sealing binds secrets to the recording. Each mechanism does one job, and the combination provides a guarantee that no single mechanism could provide alone.

When it all works, the user sees nothing. The laptop boots, the desktop appears, the disk unlocks, and nothing visibly reminds them that behind the vendor logo a hundred cryptographic checks just happened, each of which had to pass before the machine would reveal its secrets. When it does not work, they see a recovery key prompt, or a red error screen, or a laptop that refuses to boot at all. Those are the visible symptoms of the chain protecting itself. They are not bugs to be worked around. They are the system doing exactly what it was built to do.