Back to Glossary
TPM & Attestation

Credential Activation

Also known as: TPM credential activation, MakeCredential ActivateCredential, AK enrollment, TPM2_MakeCredential

A TCG-standard TPM 2.0 protocol that cryptographically binds a device's Attestation Key to its manufacturer-certified Endorsement Key, proving the AK was generated inside the same TPM.

What Credential Activation is

Credential Activation is the protocol that answers the question "how do I know this Attestation Key really belongs to a real TPM, and specifically to this TPM?" It is specified in the TCG TPM 2.0 Library Specification and involves two commands — TPM2_MakeCredential on the verifier side and TPM2_ActivateCredential on the device side — arranged into a challenge/response exchange.

The name is unfortunate. "Credential" here does not mean password or token; it is a small encrypted payload the verifier constructs and the device has to unwrap. "Activation" does not mean turning something on; it means proving the device holds the keys required to decrypt the credential. Do not read too much into the vocabulary — read the protocol.

Every TigerTrust device that will use TPM-attested certificate issuance runs Credential Activation exactly once, when its Attestation Key (AK) is first enrolled. After that, every attestation trusts the persisted binding.

Why it exists

Without Credential Activation, an attacker could generate any RSA or ECC key pair anywhere, present its public half to the verifier as an "AK", and use it to sign forged TPM2_Quote structures. Quote signatures would validate, PCR digests would look internally consistent, and the entire attestation guarantee would collapse.

The trick is that the AK is generated inside the TPM but its public half looks identical to any other RSA/ECC key from the outside. The verifier needs a way to force the device to prove that the AK actually co-resides in a real TPM alongside a manufacturer-certified Endorsement Key (EK) — because only a TPM holding both can perform the specific TPM commands the challenge requires.

The protocol, step by step

The exchange:

agent                                        pki-core
  |                                              |
  |  POST /attestation/enroll/challenge          |
  |  { ekCertificatePem, akPublicAreaBase64 } -> |
  |                                              |  parse EK cert -> EK pub
  |                                              |  chain-verify against
  |                                              |    manufacturer trust store
  |                                              |  decode TPM2B_PUBLIC -> AK Name
  |                                              |  gen random 32B secret
  |                                              |  credactivation.Generate(
  |                                              |      akName, ekPub,
  |                                              |      symBlockSize, secret)
  |                                              |  -> (credBlob, encSecret)
  |  <- { challengeId,                           |  store SHA256(secret)
  |       credentialBlobBase64,                  |       + AK area + EK cert
  |       encryptedSecretBase64 }                |       (TTL 5min)
  |                                              |
  |  TPM2_ActivateCredential(                    |
  |    AK.Handle, EK.Handle,                     |
  |    credBlob, encSecret)                      |
  |  -> secret                                   |
  |                                              |
  |  POST /attestation/enroll/response           |
  |  { challengeId, recoveredSecretBase64 } ---> |
  |                                              |  SHA256(recovered) == stored?
  |  <- { enrolled: true, ... }                  |  yes -> persist enrolled AK
  |                                              |  no  -> 403 enrollment_failed

Two mechanisms make it unforgeable:

  • The credential blob is encrypted to the EK's public key, so only whoever holds the EK's private key — which never leaves the TPM — can decrypt it.
  • The wrapped secret is HMACed with a symmetric key derived from the AK's canonical Name (a SHA-256 of the AK's TPM2B_PUBLIC structure). Only a TPM that has the exact AK whose Name went into MakeCredential can derive that HMAC key.

Both conditions must hold simultaneously. Because TPM2_ActivateCredential requires the device to load both keys and executes both decryption steps inside the chip, there is no way to satisfy the challenge externally.

What proves what

Property provedHow
AK belongs to a real TPMOnly a TPM can execute TPM2_ActivateCredential
AK belongs to this specific TPMBoth the EK's private key (never exported) and the AK's Name must be present
The specific TPM is manufacturer-legitimateVerifier chain-verifies the EK certificate to the manufacturer root before issuing the challenge
FreshnessThe challenge secret is random and single-use; blobs cannot be replayed

What Credential Activation does not do

  • It does not attest to firmware or software state. That is the job of TPM2_Quote in the per-issuance flow.
  • It does not bind a CSR public key to the TPM. That is the job of TPM2_Certify.
  • It does not authorise a device to enrol — that is a policy decision the operator makes before initiating the challenge.

Credential Activation is one leg of a three-legged stool. Skip it and attackers can substitute arbitrary AKs; keep it and every subsequent attestation is trustworthy.

Common misconceptions

"Credential Activation issues a certificate." By itself, no. It proves the AK-to-EK binding. Some deployments then follow it by having a CA sign an AK certificate (TigerTrust does — with EKU tcg-kp-AIKCertificate and a SAN of the AK Name) so downstream services can validate the AK via standard cert-path validation. But the activation step and the certificate issuance are separate.

"I have to run it every time." No — once per device, per AK. TigerTrust persists the enrolled AK in an enrolled_aks table keyed by AK Name, and per-issuance attestations look up the binding rather than re-run the protocol.

"If it fails, the TPM is broken." Usually not. Common causes: EK certificate not chain-verifying because the manufacturer root is missing from your trust bundle; the wrong EK template used (RSA vs ECC); the agent talking to /dev/tpm0 instead of the resource-managed /dev/tpmrm0 and hitting a handle conflict.

"The credential blob is a secret I have to protect." It is encrypted to the EK, so exposing it in transit is not a compromise. Exposing the plaintext secret after the device recovers it is a compromise for that single challenge — the verifier compares hashes and the challenge expires in 5 minutes anyway.

"An attacker who steals the EK certificate can forge activation." No. The EK certificate is public. The private half of the EK, which is what decrypts the credential, lives inside the TPM and is unexportable.

How TigerTrust implements it

TigerTrust's verifier lives in services/pki-core/internal/attestation/enrollment.go and uses the go-tpm-tools/credactivation package to generate the challenge. The verifier chain-verifies the EK certificate against the configured manufacturer trust store, stamps the derived manufacturer name into the enrolment record for policy filtering (allowedEkManufacturers), and stores the SHA-256 of the challenge secret with a 5-minute TTL — no plaintext secret ever hits disk on the server side. The agent side lives in services/agent/internal/keyprovider/tpm_provider.go (ActivateAKCredential). Full details in the TPM_ATTESTATION design doc §3.1.

Related reading

  • TCG TPM 2.0 Library Specification, Part 3 — command definitions for TPM2_MakeCredential and TPM2_ActivateCredential.
  • github.com/google/go-tpm-tools/credactivation — reference implementation of the challenge generator.

Put this into practice

TigerTrust operationalises everything in this glossary — from Certificate Lifecycle Management to TPM 2.0 attestation and post-quantum readiness.

Last updated: August 26, 2026