The Certificate You Just Issued Might Be a Lie
Every IoT PKI I've reviewed has the same load-bearing assumption: "the entity presenting this CSR is the device I think it is." The assumption gets encoded as an enrollment token, an API key, a bootstrap certificate — some shared secret that lets a caller prove "I am authorized to request a certificate."
None of that proves anything about the device. Not the firmware it's running. Not whether the key came from the TPM you specified in the bill of materials. Not whether the private key sat on disk in plaintext for three months before somebody re-used it on a lab bench.
Trusted Platform Module (TPM) 2.0 remote attestation closes that gap. Instead of trusting the certificate because someone with credentials asked for it, the CA trusts the certificate because a specific silicon chip proved — cryptographically — that it deserves it.
This post is a plain-language walk-through of why TPM attestation belongs in modern IoT PKI, what "attestation" actually means at the TCG-spec level, and how a production issuance gate looks in practice.
The three questions attestation answers
Every real customer conversation about device identity reduces to three questions:
- Is the device in a good state? Meaning: is it running the firmware, bootloader, and kernel you approved, or has something been altered along the boot chain?
- Is this the TPM we think it is? Meaning: is the Attestation Key that signed the quote genuinely from a manufacturer-certified TPM, or did an attacker generate a soft-AK on a laptop?
- Is the certificate key really in this TPM? Meaning: was the CSR public key generated inside this specific chip, or did the attacker attach a real TPM's attestation to their own key material?
Skip any one of these and the attack surface returns. Skip #1 and stolen credentials can request certificates from any machine. Skip #2 and a self-generated AK makes the quote meaningless. Skip #3 and an attacker gets a valid attestation from a real TPM, then substitutes their own key in the CSR.
TPM 2.0 answers each with a specific TCG-standard mechanism:
| Question | Proof mechanism |
|---|---|
| Device state | TPM2_Quote over PCRs, signed by the Attestation Key (AK) |
| TPM identity | Credential Activation (TPM2_MakeCredential / TPM2_ActivateCredential) against the manufacturer-issued Endorsement Key (EK) certificate |
| Key residency | TPM2_Certify of the CSR signing key by the AK, plus a byte-for-byte match against the CSR public key |
Every mechanism has been in the TCG TPM 2.0 Library Specification for years. The engineering work is in wiring them into a CA gate that actually refuses to sign when any single check fails.
What a PCR actually is (in one paragraph)
Platform Configuration Registers are hash accumulators inside the TPM. They start at zero and can only be extended: PCR_new = SHA256(PCR_old || measurement). UEFI extends PCR0 with the firmware code hash, then PCR1 with firmware config, PCR2 with option-ROM code, PCR7 with the Secure Boot signature database, and so on. By the time the OS boots, the PCRs hold a cryptographic summary of the entire boot chain. Nothing that ran can un-extend them. If a compromised firmware injects a rootkit before extending PCR0, the resulting digest is different from the golden value and any downstream check catches the divergence.
For most fleets, gating on PCRs 0, 1, 2, 3, 4, and 7 gives you firmware plus Secure Boot integrity without pinning to specific kernel versions. Add PCR 8/9 if you want to lock the bootloader/kernel image; add PCR 10 if IMA (Linux Integrity Measurement Architecture) is enabled.
The Endorsement Key: TPM's factory identity
Every TPM 2.0 chip ships with an Endorsement Key. The private half never leaves the chip. The public half is packaged into an X.509 certificate signed by the TPM manufacturer — Intel PTT, Infineon SLB, ST ST33, Nuvoton NPCT, AMD fTPM, IBM, or Microsoft Virtual TPM. That certificate chains back to a manufacturer root that vendors publish (under their own licenses; you download them once at install time).
The EK is what turns "this is a TPM" from a claim into a chain-verifiable fact. If you don't populate a manufacturer trust bundle, you lose the "is this the TPM we think it is?" proof — quote, certify, and PCR-policy checks still run, but any Go-based TPM simulator on a laptop could satisfy them.
The Attestation Key: what actually signs quotes
The EK cannot sign arbitrary data (by design — its scope is limited to key exchange during Credential Activation). So the TPM generates a second key, the Attestation Key, whose only job is to sign attestation structures. The AK is bound to the EK through the Credential Activation protocol: the CA sends a credential blob wrapped to the EK, the TPM decrypts it and recovers a secret, and returning that secret proves "I am a TPM that holds both this exact EK and this exact AK."
Once the AK is enrolled, every subsequent attestation quotes PCRs with the AK, and the verifier trusts the quote because the AK's provenance was cryptographically established once.
Per-issuance flow in six steps
The full attest-and-provision sequence, matching the TigerTrust implementation:
1. Agent asks backend for a fresh challenge nonce
POST /api/iot/devices/:id/attestation/challenge
-> { nonce (hex), expiresAt, purpose }
2. Agent produces the evidence bundle inside the TPM
- pcrValues = tpm2.PCRRead(SHA256, [0,1,2,3,4,7])
- quote, sig = ak.Quote(pcrSel, nonce)
- cert, sig = tpm2.Certify(signingKey.Handle, ak.Handle, nonce)
- boundArea = signingKey.PublicArea().Encode()
- csr = x509.CreateCertificateRequest(subject, signingKeySigner)
3. Agent POSTs everything to backend
POST /api/iot/devices/:id/attest-and-provision
{ caId, templateId, csr,
evidence: { akPub, ekCert, quote, quoteSig, pcrValues,
certifyInfo, certifySig, boundPubPem,
boundPublicArea, nonce, ... } }
4. Backend consumes the nonce (rejects reused/expired)
Backend resolves attestation_policy for device.deviceType
Backend forwards to PKI Core:
POST /api/v1/certificates/sign-attested
5. Verifier runs every check
- AK signature on TPMS_ATTEST (RSA-PKCS1v15, RSA-PSS, ECDSA)
- ExtraData == nonce (freshness)
- PCRDigest == sha256(concat(pcrValues)) (PCR binding)
- Expected PCR values match policy (state check)
- TPM2_Certify sig valid (key binding, part 1)
- CertifyInfo.Name == boundPublicArea.Name() (key binding, part 2)
- boundPublicArea.RSA/ECC == boundPubPem (key binding, part 3)
- EK cert chains to manufacturer trust store (identity)
- EK manufacturer in policy allow list
6. On any failure -> 403 attestation_failed
On success -> CA signs the CSR, cert returned
Result recorded in device_attestations either way
Every failure is stamped into an audit table, so an operator can reconstruct exactly which policy was in effect and which check failed months later.
What a policy looks like
An attestation policy is the rulebook the verifier consults on every issuance. It's stored per device type and evaluated when the request arrives:
{ "name": "prod-edge-gateway", "deviceType": "edge-gateway", "expectedPcrs": { "SHA256": { "0": "ab34c1a2b5...", "7": "9d1543e6..." } }, "requiredPcrs": [0, 1, 2, 3, 4, 7], "allowedEkManufacturers": ["Intel", "Infineon"], "requireBoundCsrKey": true, "requireSecureBoot": true, "maxAttestationAgeSeconds": 300, "enabled": true }
Field-by-field:
expectedPcrs: hex-encoded golden digests. Missing entries mean "we don't care." Present entries must match exactly, or the verifier returnspcr_mismatch:<n>.requiredPcrs: PCR indices the agent must include in its quote. Protects against agents cherry-picking only the PCRs they know are green.allowedEkManufacturers: TPM vendors extracted from the EK certificate issuer. Empty array means any manufacturer allowed (as long as chain-verify passes).requireBoundCsrKey: when true, the verifier enforces the fullTPM2_Certifykey-binding check. Turn off only for legacy devices predating TPM-bound keys.requireSecureBoot: when true, PCR7 must be non-zero (meaning Secure Boot actually ran).maxAttestationAgeSeconds: nonce lifetime ceiling. A background reaper enforces this globally.
Golden PCR values come from a known-good reference device:
$ tpm2_pcrread sha256 sha256: 0 : 0xAB34C1A2B5... 1 : 0xC44D... 2 : 0x91E7... 3 : 0x0000000000000000000000000000000000000000000000000000000000000000 4 : 0x77B2... 7 : 0x9D1543E6...
Copy the hex (without 0x) into the policy's expectedPcrs.SHA256 object.
The attacks attestation actually blocks
It's worth being specific about what attestation buys you versus what it doesn't.
Stolen credentials. An attacker with your enrollment API key still cannot forge a fresh TPM2_Quote with the right PCR digest signed by an AK that Credential-Activated against a manufacturer EK. Credentials alone no longer buy certificates.
Software key exfiltration. Private keys are generated inside the TPM (TPM2_Create with non-migratable attributes) and cannot leave the chip. Malware that pivots onto the device cannot copy the key to a laptop for reuse.
Firmware tampering. A modified bootloader or kernel changes PCRs. The quote still signs cleanly, but the PCR values disagree with the golden set and the verifier returns pcr_mismatch. The device stops receiving certificates until you either revert the firmware or approve the new PCR baseline.
Device cloning. Byte-for-byte imaging the flash of a real device onto a bench-top clone doesn't clone the TPM's internal state. The cloned device has a different EK; enrollment fails.
CSR-swap. An attacker who intercepts a valid attestation bundle cannot substitute their own key into the CSR — the verifier compares the CSR public key to boundPubPem and to the RSA/ECC fields inside boundPublicArea and requires the AK-signed Certify to reference that exact public area.
Nonce replay. Nonces are single-use, expire in 300 seconds, and are consumed atomically. Replaying an old bundle fails with nonce_already_used or nonce_expired.
Not blocked:
Physical extraction of TPM contents. TPMs are hardened but not tamper-proof at the silicon level. Assume a nation-state adversary with physical access to a device can eventually extract the EK. Attestation is a defense against remote and software-borne attackers, not physical adversaries.
Firmware rootkit that pre-dates the measurement chain. Measurement starts from PCR0, so a compromised BIOS/UEFI could produce a "valid" quote as long as it lied consistently. Mitigation: require known-good PCR0/1/2/3 digests — meaning a specific firmware version signed by a specific vendor.
Rollout plan for a real fleet
Bringing TPM attestation online across a fleet you already ship is a five-step process:
1. Populate the manufacturer trust bundle. Pull EK roots from the vendors you actually ship (Intel PTT, Infineon SLB, ST ST33, Nuvoton NPCT, AMD fTPM, IBM, Microsoft). Drop them into your CA's ek_trust_bundle_dir as .pem, .crt, or .cer files.
2. Capture golden PCRs from a canary device. Build the canary from a clean image, verify it end-to-end, then read PCRs with tpm2_pcrread sha256. Record every PCR you plan to gate.
3. Author a policy per device type. Start permissive (requireBoundCsrKey: true, requireSecureBoot: true, no expectedPcrs) so you can see how the fleet behaves before pinning to golden values. Then progressively add PCR expectations.
4. Enroll AKs for the fleet. Run tigertrust-agent enroll-tpm on each device (or batch during provisioning). Every AK gets its own Credential Activation cycle; enrolled_aks is the source of truth thereafter.
5. Plan the PCR-update workflow. Every firmware upgrade, kernel bump, bootloader change, or Secure Boot database update shifts PCRs. The canary flow is: roll firmware to canaries, capture new PCRs, update the policy, then roll fleet-wide. Skip this step and every device fails attestation after the OTA.
Compliance angle
If your fleet touches critical infrastructure or regulated sectors, attestation converts from "nice to have" to "explicit line item":
- IEC 62443-4-2 (Component Requirements) calls out hardware-rooted device identity and integrity of critical components. TPM 2.0 with attested issuance is the mechanism auditors recognize.
- NIST SP 800-193 (Platform Firmware Resilience) requires detection, protection, and recovery of firmware. PCR-gated issuance turns the CA into an enforcement point: firmware drift = no cert.
- ISO/SAE 21434 (Automotive Cybersecurity) puts weight on cryptographic binding of ECU identity to hardware. Attestation of PCR7 (Secure Boot) plus firmware PCRs satisfies the audit narrative for ECU certificate issuance.
You don't need to build the mechanism yourself; you need to prove to an auditor that "issuance is gated on hardware-verified state" is more than a slide.
Getting started
If you're new to attestation, start with a lab-scale pilot:
- Get a discrete TPM 2.0 module or use Intel PTT / AMD fTPM on existing hardware.
- Install the manufacturer's EK root certificate into your TigerTrust trust bundle.
- Run
tigertrust-agent enroll-tpmand confirm you see anenrolled_aksrow. - Request a certificate; watch the verifier log the six-step check list.
- Deliberately break something — flip a PCR expectation, revoke the EK trust — and confirm the CA refuses to sign with a structured reason code.
Once you trust the mechanics, everything else is policy authoring and canary discipline.
Wrap-up
Certificate lifecycle automation on its own is table stakes now. What separates a modern IoT PKI from a legacy one is whether the CA can prove what it's about to sign. TPM 2.0 remote attestation is how you prove it: firmware state via TPM2_Quote, TPM identity via Credential Activation against a manufacturer EK, key residency via TPM2_Certify, and structured failure reasons that let operators debug denials without reading through free-text logs.
If you're running certificates onto physical hardware — gateways, sensors, controllers, ECUs, medical devices, meters — the question isn't whether to add attestation. It's whether you'd rather add it before or after the first compromised-device incident.
Ready to see attested issuance in your environment? Book a TPM attestation demo or talk to our IoT security engineers.