Linux Boot Security

What a TPM Actually Does, and How Linux Uses It to Protect Disk Unlock

How TPM 2.0, LUKS2, PCRs and measured boot work together to unlock encrypted Linux systems without storing the unlock secret on disk.

#tpm#tpm2#measured-boot#linux#luks#pcr

1. The security hardware already in your machine

A TPM, or Trusted Platform Module, is a small cryptographic security device built into essentially every modern PC.

Microsoft made TPM 2.0 mandatory for supported Windows 11 systems, which effectively made it part of the standard hardware platform.

The TPM is useful because it provides a small area of cryptographic state that is separate from the operating system.

Linux can ask it to create and use keys, protect small secrets, record measurements of the boot process, and make use of a protected object conditional on the machine being in an expected state.

The TPM doesn’t decide whether Linux is trustworthy and it does not encrypt the filesystem.

Instead, it provides a hardware-backed answer to a more useful question:

Should this machine be allowed to obtain this secret in its current state?

That makes it useful for disk encryption.


2. Why use a TPM for disk unlock?

Full-disk encryption creates an obvious problem for unattended systems.

If the root filesystem is encrypted, something has to provide the credential required to unlock it during boot.

On a laptop this is normally a person:

That is often unacceptable for appliances, servers and other devices deployed into secure or controlled environments.

Those systems may need to reboot automatically after a power failure, kernel update or watchdog reset and there may be nobody present who should know the disk passphrase, or who should be able to gain access to the underlying OS at all.

Simply putting the unlock credential in a file on the disk does not solve the problem. Someone who removes or copies the storage can copy the credential along with it.

The TPM gives us another option:

The device can then unlock itself without a person entering a secret, while the credential remains tied to the machine, and measurements of how it booted.

Two useful security properties of this:

The TPM provides a controlled way for the machine to obtain the credential required to use it.


3. Where LUKS fits

On Linux, the common solution for full-disk encryption is LUKS — Linux Unified Key Setup, normally using LUKS2.

LUKS sits above the kernel’s dm-crypt encryption layer and handles the problem of key management.

The important detail is that the passphrase you type is not normally the key directly encrypting every sector of the disk.

LUKS generates a high-entropy volume key which is used by dm-crypt to encrypt and decrypt the block device.

The LUKS header then provides one or more ways of recovering that volume key.

Those are represented by keyslots.

For example:

Each keyslot is simply another authorised route to the same underlying volume key.

Adding a second passphrase therefore does not re-encrypt the filesystem. It creates another way to recover the existing volume key.

For the purposes of understanding TPM sealing, we can simplify the model and imagine that we have added a strong random passphrase to a LUKS keyslot:

If the TPM releases that secret during boot, cryptsetup can use it to unlock the keyslot and recover the volume key.

The TPM never encrypts or decrypts the filesystem itself.

Its job ends once it has released the small piece of key material required by LUKS.

In modern LUKS2 implementations, TPM integration is normally a little cleaner than literally treating the TPM output as a passphrase. LUKS2 supports tokens stored as metadata in the LUKS2 header. Tools such as systemd-cryptenroll can create a TPM-backed token associated with a keyslot, allowing cryptsetup to invoke the TPM integration automatically during boot.

Conceptually, however, the result is the same:


4. What the TPM is protecting

The TPM does not hold a large amount of secret storage.

Instead, it contains cryptographic root secrets that never leave the TPM, from which it can create protected key hierarchies.

Objects created underneath those keys can be returned to Linux as encrypted, integrity-protected blobs and stored perfectly safely on an ordinary disk.

Conceptually:

An attacker is free to copy that blob.

To actually use it though, the blob has to be loaded back through the TPM key hierarchy that created it.

This is an important distinction: the protected TPM object does not need to remain physically stored inside the TPM.

The TPM only needs to retain the cryptographic root from which that object’s protection ultimately derives.

This design lets a TPM with very little internal storage protect many objects stored elsewhere.

And for disk unlock, it means the LUKS header can contain the TPM-related data needed for automatic unlock without that data itself being the plaintext disk-unlock secret.


5. Every TPM is cryptographically unique

Each TPM has its own internal cryptographic root secrets.

Those secrets are generated inside the TPM and are not exportable.

As a result, two otherwise identical machines do not have interchangeable TPM key hierarchies.

Imagine two units built from the same image:

UNIT A                           UNIT B

same Linux image                same Linux image
same LUKS header                cloned LUKS header
same firmware settings          same firmware settings

TPM root A                      TPM root B
    │                               │
    ▼                               ▼
different key hierarchy         different key hierarchy

If a TPM-protected object was created on Unit A, copying the entire disk to Unit B also copies that object’s protected blob.

But Unit B does not possess Unit A’s TPM root secrets.

It therefore cannot reconstruct the cryptographic hierarchy required to use that object.

This is the first important property of TPM-backed disk unlock:

The protected credential is tied to the TPM that created it.

So even before PCR measurements enter the picture, simply cloning the disk onto another machine does not reproduce the complete unlock environment.

This is why TPM enrollment normally has a per-device step.

A common OS image can be cloned across a fleet, but the TPM-backed credential has to be associated with each individual device’s TPM.

Clearing the TPM or replacing the motherboard has the same consequence: the original TPM relationship may be gone, which is why any production design also needs a separate recovery path.


6. Hardware identity is only half of the problem

Binding a credential to one TPM answers one question:

Is this the TPM that the credential was created for?

For an unattended encrypted device, that is useful, but it is not enough.

Suppose somebody steals the entire machine rather than just its SSD.

The original TPM is still present.

If the TPM releases the disk credential whenever it is asked, an attacker who can alter the boot environment may still be able to persuade the genuine machine to unlock its own disk.

What we would prefer is something closer to:

That second condition requires the TPM to know something about how the machine reached its current state.

This is where Platform Configuration Registers, or PCRs, become important.

Rather than just binding a secret to a physical TPM, PCRs let us make use of that secret dependent on measurements taken during the boot process.

The next question, then, is not how the TPM stores the credential.

It is:

How can the TPM retain a trustworthy record of what happened before Linux started?


7. TPM objects, hierarchies, and why the TPM is passive

A discrete TPM is a small microcontroller with dedicated cryptographic functionality, protected internal state and a narrow command interface. Software never reads a private key out of it directly, It asks the TPM to perform an operation such as sign or unseal, using an object the TPM holds:

host                         TPM

data ───────────────────────►│
                             │ sign using private key

signature ◄──────────────────│

TPM objects live beneath hierarchies (platform, storage, endorsement, and a null hierarchy for ephemeral objects), each rooted in a secret seed that never leaves the TPM. From that seed the TPM derives primary objects reproducibly, given the same seed and template — and from those, child objects such as sealed secrets.

The useful trick is that a child object doesn’t have to stay inside the TPM. The TPM can hand back a public portion (not secret) and a private portion: a blob encrypted and integrity-protected so it can only be reloaded beneath the parent that created it:

public blob
private blob


TPM2_Load(parent)


usable TPM object

That blob can sit on an ordinary disk. An attacker can copy it freely; without the originating TPM’s hierarchy, it cannot be turned back into the underlying secret. This is what lets a sealed object live on the very disk it protects.

It’s also worth being explicit that the TPM is passive. It doesn’t inspect boot images, veto kernels, or watch memory for malware. It mostly just responds to commands, saying in effect:

Given my current state and the policy attached to this object, I will or will not perform this operation.


8. PCRs and measured boot

The key hierarchy tells us whether an object belongs to this TPM. It says nothing about what the machine actually booted. That’s the job of Platform Configuration Registers, or PCRs.

A PCR isn’t normally assigned an arbitrary value. Instead, software extends a measurement into it:

PCR_new = H(PCR_old || measurement)

Each new measurement therefore incorporates everything that came before it. Order matters, earlier measurements can’t simply be removed, and changing any measured component changes the resulting PCR value.

The TPM itself generally doesn’t measure boot components. Firmware and later stages of the boot chain measure the next component before transferring control to it:

Because the measurement happens before control transfers, the measured component cannot subsequently rewrite the PCR to erase evidence of what was loaded.

Different PCRs are conventionally used for different parts of platform state — firmware, boot applications, configuration and Secure Boot state among them — but the number itself is less important than understanding who extends it, with what data, and when.

A PCR contains only the resulting hash chain. It doesn’t tell us which components produced it.

That detail is recorded separately in the TCG event log, alongside the measurements:

TCG event log                       TPM PCR

event A + digest A ───────────────► extend
event B + digest B ───────────────► extend
event C + digest C ───────────────► extend


                                  final PCR value

The event log can be replayed from the PCR’s initial state and the calculated result compared with the actual value held by the TPM.

The event log describes what was measured; the PCR is the cryptographic commitment to that sequence.

This is Measured Boot, and it is distinct from Secure Boot.

Secure Boot enforces: firmware verifies that a boot component is signed by an authorised key before allowing it to execute.

Measured Boot records: components are measured into PCRs so that the resulting boot state can later be used as an input to policy.

Together they give us three useful questions:

Secure Boot:
"Is this component authorised to execute?"

Measured Boot:
"What actually executed?"

TPM policy:
"Given what executed, should this secret be released?"

For disk encryption, the last question is the important one.


9. From measured state to LUKS unlock

TPM objects can carry an authorisation policy which has to be satisfied before the TPM will allow the protected operation.

These policies are evaluated through TPM policy sessions. A PCR requirement can be introduced with operations such as TPM2_PolicyPCR.

Conceptually:

start policy session


evaluate selected PCR state


construct policy digest

       ├── expected policy not reached ──► refuse


policy satisfied


allow protected operation

The important detail is that the sealed object’s authPolicy is a digest representing the required policy. At use time, the caller has to construct a policy session which arrives at that expected state.

For disk unlock, suppose the sealed object’s sensitive data is some secret K.

If the current policy succeeds:

load sealed object


start policy session


PolicyPCR


policy satisfied


TPM2_Unseal


       K

If the measured state is wrong, TPM2_Unseal is not authorised.

This gives the sealed secret two distinct protections:

correct TPM
     +
acceptable measured state


TPM2_Unseal

The first comes from the TPM-specific hierarchy described earlier. The second comes from policy.

How this maps onto LUKS2

Modern LUKS2 can integrate this directly through its token mechanism.

systemd-cryptenroll can enrol a TPM-backed unlock method against a LUKS2 volume. The LUKS header then contains a normal keyslot plus a systemd-tpm2 token containing the TPM-related metadata needed to obtain the material for that keyslot.

Conceptually:

During early boot the path is roughly:

So when we say that “the TPM unlocks the disk”, what actually happens is:

  1. cryptsetup finds the TPM-backed token in the LUKS2 header.
  2. The TPM object and policy information are loaded.
  3. A TPM policy session evaluates the required state.
  4. TPM2_Unseal returns the protected material if that policy succeeds.
  5. cryptsetup uses it to unlock the associated LUKS keyslot.
  6. LUKS recovers the volume key and dm-crypt activates the device.

Higher-level tooling hides most of the TPM software stack underneath this. Modern userspace normally reaches the TPM through /dev/tpmrm0, with tpm2-tss providing the underlying TPM APIs.

For an encrypted root filesystem these components must be available in the initramfs, because the TPM-backed unlock has to happen before the real root filesystem can be mounted.

The important boundary is still simple:

The TPM authorises release of a small secret. LUKS and dm-crypt perform the actual disk-unlock and encryption work.


10. Why exact PCR binding becomes a problem

At this point it is tempting to bind the sealed object against as many PCRs as possible.

More measured state sounds like stronger security.

But every PCR included in a direct policy also represents another condition which has to reproduce the expected value before the TPM will release the secret.

If a selected PCR depends on firmware, a firmware update may change it.

If it includes boot configuration, changing that configuration may change it.

And if the kernel or initramfs contributes to it, an ordinary OS update can change it.

Suppose a machine is enrolled while the relevant PCR state is:

PCR = A58D9F...

The policy succeeds and the machine unlocks normally.

Now install a legitimate kernel update.

The new kernel produces a different measurement and the next boot produces:

PCR = 73C10B...

The TPM has no concept of:

"this difference came from an approved update"

It only knows that the measured state is different.

From its perspective:

attacker modifies measured component


        PCR value changes

and:

administrator updates measured component


        PCR value changes

are cryptographically the same event.

If the policy authorised only the original value, both are rejected.

The TPM is doing exactly what it was asked to do. The problem is that the policy has defined:

trusted

as:

exactly the measured state that existed when this object was enrolled.

Those are not equivalent.

This becomes especially painful on unattended systems.

On a laptop, a failed TPM unlock may mean entering the recovery passphrase and re-enrolling the TPM.

Across a fleet, a kernel update now has to account for old and new boot states, rollout failures and rollback. A perfectly valid software update can otherwise leave a remote machine unable to unlock itself after reboot.

PCR selection should therefore start with:

What security property are we trying to enforce, and which measurements are actually required to establish it?

rather than:

How many PCRs can we bind to?

The real problem is allowing the measured state to change when the change is authorised, without also accepting arbitrary changes.

That is the problem the next article will solve.


11. What TPM-backed disk unlock does not protect

TPM sealing establishes a useful boundary during boot, but it is not a general runtime security mechanism.

Once LUKS has been unlocked, the volume key required by dm-crypt necessarily exists in kernel-controlled memory.

A kernel compromised after that point already has access to the mounted filesystem. The TPM cannot make data which has already been legitimately decrypted inaccessible to the running kernel.

The useful boundary is therefore roughly:

powered off


measured boot


TPM policy succeeds


disk unlocked


running system

TPM sealing controls access to the secret during that transition. It does not make a compromised running system trustworthy.

There is also a related issue if the unseal policy remains valid after boot: privileged software may be able to request the protected secret from the TPM again. Designs which care about this can deliberately invalidate part of the unseal policy once the early-boot secret has been consumed.

Physical attacks remain relevant as well. Depending on the platform, sensitive TPM traffic may cross an accessible hardware interface. TPM 2.0 supports authenticated sessions and parameter encryption to protect sensitive command data, but the software integration has to make appropriate use of those mechanisms.

As always, the value of the TPM depends on the threat model around it.


12. Why Linux is starting to care

None of the TPM primitives described here are particularly new.

What has changed is the plumbing around them.

Linux has mature TPM support, and LUKS2, cryptsetup and systemd now make TPM-backed disk unlock something that can be integrated into the normal boot and storage stack rather than assembled entirely from low-level TPM commands and custom scripts.

systemd-cryptenroll in particular makes the relationship between the LUKS keyslot, TPM-protected credential and LUKS2 token much easier to manage.

That makes unattended encrypted Linux systems considerably more practical.

It also exposes the remaining problem more clearly.

What we want is:

correct TPM
     +
authorised boot state


unlock LUKS

But secure systems have to change.

Kernels receive security updates.

initramfs images are rebuilt.

Boot components evolve.

Measured Boot should detect those differences — otherwise measuring them would accomplish very little.

The challenge is therefore not to keep the measurements permanently unchanged.

It is to allow new authorised measured states without turning every legitimate kernel update into a TPM re-enrollment and recovery operation.

That is where the next article begins.

The TPM gives us the machinery to bind a secret to machine state. The harder problem is defining trust in a way that can safely evolve with the machine.


← All writing