Skip to content

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 IFXHardwareDiscreteInfineon and INTCFirmwareTpmIntelPtt 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

group

Discrete 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

group

In-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

group

Virtual 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

group

Software emulators. Always rejected outside dev policy.

  • EmulatedSwtpm

    Userspace swtpm. IBM manufacturer 0x49424D00. Chains to swtpm-localca.

mobile-hardware

group

Mobile 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

group

Mobile 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.
  • swtpm is caught by its issuer DN, not its manufacturer code: the classifier matches the issuer substrings swtpm, SW TPM, or Software TPM and returns EmulatedSwtpm. When the IBM manufacturer code is present it is only mapped to EmulatedSwtpm if the issuer also contains swtpm; otherwise it stays HardwareDiscreteOther.

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: NitroAttestationVerifier validates the COSE_Sign1/ES384 signature against the pinned AWS Nitro Enclaves Root G1, then Ec2InstanceIdentityVerifier binds the attestation to a specific EC2 instance via 16 per-region signing certs.
  • Azure: AzureAttestedDataVerifier validates 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.