Decorative Cryptography
All encryption is end-to-end, if youâre not picky about the ends. config TCG_TPM2_HMAC bool "Use HMAC and encrypted transactions on the TPM bus" default n select CRYPTO_ECDH select CR...
All encryption is end-to-end, if youâre not picky about the ends.
config TCG_TPM2_HMAC
bool "Use HMAC and encrypted transactions on the TPM bus"
default n
select CRYPTO_ECDH
select CRYPTO_LIB_AESCFB
select CRYPTO_LIB_SHA256
select CRYPTO_LIB_UTILS
help
Setting this causes us to deploy a scheme which uses request
and response HMACs in addition to encryption for
communicating with the TPM to prevent or detect bus snooping
and interposer attacks (see tpm-security.rst). Saying Y
here adds some encryption overhead to all kernel to TPM
transactions.
Last year, I came agross a Linux kernel feature called TCG_TPM2_HMAC. It
claims to detect or prevent active and passive interposer attackers. Thatâs one
of my sleeper agent activation phrases, so I dug in.
TCG_TPM2_HMAC lives primarily in
drivers/char/tpm/sessions.c
and is discussed at further length in
Documentation/security/tpm/tpm-security.rst.
It all sounds really great. We should care about interposer adversaries. Itâs
great to use the TPM features that were invented to help us with these problems.
Letâs draw a little picture of whatâs being attempted here.
In this threat model, there is an adversary who can access the untrusted bus
on which all the TPM traffic is sent during the boot. This can be done using
hardware hacking or by hijacking another
device that controls the TPM bus (e.g., a BMC).
TCG_TPM2_HMAC is a kernel feature, and the kernel boots after the platform
firmware and the boot loader, so it canât do anything about interposer
adversaries tampering with firmware and boot loader measurements. Letâs assume
for now that the firmware and boot loader are just implicitly trusted to have
booted âcorrectâ code and successfully made honest measurements of all the boot
stages up to and including the kernel. We also implicitly trust the TPM to
behave correctly, here. Or if you have a newer TPM, donât!
Someone familiar with
the STRIDE model can easily
observe the following threats just on the big red wire in our picture above:
Attack
Example
Spoofing
Attacker pretends to be the TPM or the CPU to the other device
Tampering
Attacker drops or modifies measurements sent to the TPM
Repudiation
Not obviously applicable in this case
Information Disclosure
Attacker obtains unsealed secrets (e.g., disk encryption keys)
Denial of Service
Attacker drops measurements sent to the TPM
Escalation of Privilege
Not obviously applicable in this case
The attacker may or may not necessarily get anything out of manipulating the TPM
traffic itself (unless they are some kind of degenerate that
just likes to talk to TPMs for fun). But folks who are familiar with TPM-based
measured boot and attestation should be able to immediately see the value to the
attacker of âmodifying measurementsâ or âobtaining unsealed secretsâ.
Letâs take a second to distinguish the two types of attackers here:
Passive Interposers aka snoopers can only read from the bus but not modify
the data.
Active Interposers can read and write to the bus.
The very best thing a passive interposer can do here is Information
Disclosure: read data from the bus. Since measurements should typically not
be secret, the (legitimate) measurements sent to the TPM are not very
interesting. Unsealed secrets (that were sealed to the measurements in the TPM)
might very much be! Thatâs why
security/keys/trusted-keys/trusted_tpm2.c
uses an encrypt session
using the helper
tpm_buf_append_hmac_session
which is unfortunately a little bit entangled with the TCG_TPM2_HMAC feature
(but thatâs how software development goes). All that really needs to be done
here for this case is to use an encrypt session key established using the EK
as discussed widely by many others but also myself.
The remainder of this blog post discusses the active interposer case.
An active interposer generally wants to do one of two things in this scenario:
(Tampering, Denial of Service) Tamper with TPM measurements made by
the kernel, to falsely attest or unseal as the âintendedâ code or state, from
âunintendedâ code or state.
(Spoofing, Information Disclosure) Interpose the TPM connection and
defeat the encrypt session solution for unsealing secrets.
The TCG_TPM2_HMAC feature will
establish an auth session
salted (key-encapsulated) to the EK every time the kernel
extends a PCR
or
gets randomness.
You might say to yourself, âself, thatâs a lot of overhead (asymmetric crypto
in the TPM) for common, fast operations (PCR extensions, randomness generation)â
and
youâd be right.
Wow, this feature is expensive! Good thing itâs solving a real problem, right?
Every time a session is needed (e.g., every time the kernel needs to extend a
PCR), the TCG_TPM2_HMAC feature key-encapsulates a new session key with
something called the âNull Primary Keyâ which is a P256 ECDH key derived from
the Null hierarchy (which means it changes on every boot). It uses this session
key to protect the TPM command by encrypting the inputs and outputs and
adding an HMAC to detect tampering. Great.
One problem: how does the kernel know what the Null Primary Key should be? Read
this thread
to not find out.
The kernel takes the Null Primary Key at face value and stashes the Name (hash)
of it at /sys/class/tpm/tpm0/null_name and trusts that userspace will
attest the key later using the EK.
This inverts the chain of trust for measured boot: the kernel is responsible for
measuring userspace, so that âbadâ or âmaliciousâ or âunintendedâ userspace
cannot impersonate âgoodâ or âwell-behavedâ or âintendedâ userspace.
This means that all the active-interposer attacker has to do to defeat
TCG_TPM2_HMAC is:
Replace or hijack the userspace component responsible for checking the
Null Primary Key. Call this âComponent Xâ.
Interpose HMAC session establishment by creating a fake Null Primary Key
themselves (e.g., in software) and pretend to be the TPM responding to
requests.
Intercept TPM2_PCR_Extend commands, replacing the measurements as desired
(e.g., replace âhash of malicious Component Xâ with âhash of good Component
Xâ).
Malicious component X ignores the âwrongâ Null Primary Key name at
/sys/class/tpm/tpm0/null_name.
You can solve this problem by threat model gerrymandering: simply declare that
the active interposer adversary is not able to tamper with userspace, which is
stored on physical media less than 12 inches away from the TPM in most cases.
Note that full disk encryption using the TPM cannot save you here, because
if the booting system can fetch the key, so can the physical adversary. If you
still think you have a tamper-proof userspace at this point, ask yourself why
you need the kernel to measure it anymore.
Adding remote attestation also does not help here, because while a remote system
can spot-attest a âNull Primary Keyâ, it has no way of knowing which key the
kernel used when making its measurements.
TPM2_TCG_HMAC was disabled by default again
in August 2025
starting with version 6.18.
What lessons can we learn from all this?
Applied cryptography cannot solve a security problem. It can only convert
a security problem into a key-management problem.
Corollary: If you arenât actually solving the key-management problem, your
cryptography is strictly decorative. This is not only not helpful, it is
actively harmful, because it gives users a false sense of security, leading
them to skip other precautions they would have otherwise taken.
Chains of trust are directional. Do not invert them.
Corollary:
You know what the chain of trust is? It's the chain I go get and beat you
with 'til ya understand who's trustin' who here.
Unexplainable security features are just marketing materials.
Corollary: While attestation protocols can be quite byzantine, they should
always boil down to 1 or more of âX checks Y against Zâ and it should always
be possible to explain why X, Y, and Z are each trusted. The explanations
may lead to more X, Y, Z tuples, and this is fine, but donât give up if your
questions arenât being answered.
Corollary 2: When someone comes along with detailed questions about something
youâre responsible for, donât take it personally. Instead, build trust by
engaging in a good-faith discussion. Youâll either be right, and your answers
appreciated, or youâll learn about a gap in your system you can improve.
Active physical interposer adversaries are a very real part of legitimate threat
models. You need an integrated root-of-trust in your CPU in order to solve
these. Check out Caliptra,
which provides
TCG DICE
APIs from within the SoC itself as an integrated root-of-trust. This can be
used on its own, or in conjunction with a discrete TPM.
Opinions expressed here are my own and do not represent the official positions
of any employer(s) of mine, past or present