Security
vTPM detection is the engineering primitive.
A TPM cert is structurally a TPM cert whether it came from an Infineon SLB 9672 or a software emulator running in a Docker container. The differentiator is who signed it and what manufacturer OID it claims. This page documents exactly how our classifier decides.
Two signals, checked in order
TCG manufacturer code, then issuer DN
Every EK certificate the platform produces can carry two pieces of evidence the classifier reads. It does not AND them — it takes the first that yields a class, manufacturer code first, issuer DN as the fallback:
- TCG manufacturer code (SAN attribute
2.23.133.2.1): a 4-byte ASCII vendor code the TPM asserts about itself —IFX(Infineon),INTC(Intel PTT),STM(STMicro),MSFT(Microsoft — Pluton or Hyper-V), and so on. Read first. - Issuer DN: what CA signed this cert. Used as the fallback when the manufacturer code is absent or unrecognized — a substring match against known vendor and cloud names (
Infineon,Nuvoton,Pluton,Azure,swtpm, …).
The classifier (TpmClassClassifier.cs) reads the manufacturer code first; if it maps to a known class it returns it, otherwise it falls back to the issuer-DN substring match. So IFX → HardwareDiscreteInfineon and INTC → FirmwareTpmIntelPtt without ever consulting the issuer, while a cert with no recognized manufacturer code is classified purely from who signed it. A couple of codes (MSFT, IBM) are shared across a hardware and a virtual use, so those — and only those — are disambiguated by an additional issuer substring check, described below.
Taxonomy
The full TpmClass enum
Each class slots into a group. Customer policies pick groups (e.g. ["hardware", "firmware-tpm"]) and the classifier expands them to the specific classes.
hardware
groupDiscrete TPM chips soldered to motherboards. Highest assurance.
HardwareDiscreteInfineon
Infineon OPTIGA RSA / ECC, IFX TPM EK Root CA
HardwareDiscreteStMicro
STMicro ST TPM, GlobalSign Trusted Computing CA
HardwareDiscreteNuvoton
NTC TPM EK Root CA, Nuvoton TPM Root CA 1xxx/2xxx
HardwareDiscreteOther
Vendor unknown but chain validates against a pinned vendor root.
firmware-tpm
groupIn-CPU TPMs. Cannot be swapped without replacing the CPU.
FirmwareTpmIntelPtt
Intel Platform Trust Technology, ODCA-backed.
FirmwareTpmAmdFtpm
AMD fTPM. Voltage-glitch risk on Zen 2/3 (faulTPM).
FirmwareTpmPluton
Microsoft Pluton, post-2022 OEMs.
cloud-vtpm
groupVirtual TPMs running inside cloud hypervisors. Rejected by strict policy; cross-validated under cloud-permissive.
CloudVtpmAwsNitro
AWS NitroTPM. Cross-validate via Nitro doc + EC2 IID.
CloudVtpmAzure
Azure vTPM. Cross-validate via IMDS attested data + DigiCert G2.
CloudVtpmGcp
GCP Shielded VM. Cross-validate via instance-identity JWT.
CloudVtpmHyperV
Generic Hyper-V vTPM (non-Pluton 2014).
emulated
groupSoftware emulators. Always rejected outside dev policy.
EmulatedSwtpm
Userspace swtpm. IBM manufacturer 0x49424D00. Chains to swtpm-localca.
mobile-hardware
groupMobile devices with hardware-backed key attestation.
MobileAndroidStrongbox
StrongBox secure element. attestationSecurityLevel = StrongBox.
MobileAndroidTee
Android TEE-backed attestation.
MobileAppleSecureEnclave
Apple Secure Enclave key attestation.
MobileAppleAppAttest
DCAppAttestService. iOS App Attest.
mobile-software
groupMobile attestation that didn't reach hardware-backing. Reduced assurance.
MobileAndroidSoftware
Android attestationSecurityLevel = Software.
The Microsoft ambiguity
Why MSFT can mean Pluton or Hyper-V
Both Pluton firmware TPMs and the Hyper-V vTPM assert the same MSFT manufacturer code, so the code alone can't separate them. The classifier disambiguates with a plain string.Containson the EK cert's issuer DN: if it contains Pluton the device is classified FirmwareTpmPluton; if it contains Host Guardian or vTPM it's CloudVtpmHyperV. An ambiguous Microsoft issuer that matches neither marker defaults to Pluton. This is a substring heuristic — not a chain-depth analysis — and the real gate on a Hyper-V vTPM is that the cloud-permissive path demands provider-signed instance-identity cross-validation before it is accepted.
swtpm and the IBM code
How the software emulator is actually caught
The swtpm software emulator ships asserting the TCG-allocated IBM manufacturer code (0x49424D00) out of the box — documented in SUSE's virt guide and upstream swtpm sources. Two things follow, and it matters to state them precisely:
- The IBM manufacturer code alone does notmean "virtual." A cert carrying the IBM code whose issuer is not an swtpm CA classifies as
HardwareDiscreteOther— a hardware class. There is no "IBM-is-virtual-by-default" rule and no per-class allow-list override. swtpmis caught by its issuer DN, not its manufacturer code: the classifier matches the issuer substringsswtpm,SW TPM, orSoftware TPMand returnsEmulatedSwtpm. When the IBM manufacturer code is present it is only mapped toEmulatedSwtpmif the issuer also containsswtpm; otherwise it staysHardwareDiscreteOther.
Either way, classification is not the load-bearing defense against a rogue emulator. An swtpm instance can name any issuer it likes, but it cannot forge a chain to a pinned TPM-manufacturer root: EK-certificate chain validation rejects it before its class ever matters. Detecting the swtpm issuer is a fast, honest label layered on top of that cryptographic gate — never a substitute for it.
Cloud cross-validation
The honest case for accepting cloud
Some customers legitimately operate in AWS / Azure / GCP and want device identity for their own infrastructure (containers in their own ECS, EKS, AKS, GKE). Strict rejection isn't the right policy for them. Instead, our cloud-permissive policy accepts cloud vTPMs only when they ship a fresh provider-signed instance-identity document binding the attestation to a specific cloud instance.
- AWS Nitro:
NitroAttestationVerifiervalidates the COSE_Sign1/ES384 signature against the pinned AWS Nitro Enclaves Root G1, thenEc2InstanceIdentityVerifierbinds the attestation to a specific EC2 instance via 16 per-region signing certs. - Azure:
AzureAttestedDataVerifiervalidates the PKCS#7 envelope against the pinned DigiCert Global Root G2, then binds via the IMDS attested-data instance identity. - GCP:
GcpInstanceIdentityJwtVerifiervalidates the JWT against Google's live JWKS with audience-as-nonce binding.
A relayed attestation from instance A cannot also produce an IID naming instance B. The cuckoo case closes cryptographically.