Type: Primer
Category: Research — Keys & Secure Hardware
Series: Key containers on mobile devices, part 2 of 3
Reading time: ~9 min
Android key attestation is the only widely available way to prove to a remote party where a key lives — provided the verifier reads the right half of it.
The previous article ended on a limitation: every local method of asking what protects a key runs inside the application's own process, and reports whatever the platform says. That is adequate for choosing what to attempt and useless as evidence.
Key attestation is the mechanism that produces evidence. It matters most for credential issuance — an issuer signing a device-bound credential such as an mdoc or an SD-JWT VC with key binding needs to know that the holder's key is where the holder's software claims it is — and it is regularly consumed incorrectly.
What the certificate is
Requesting attestation at key generation causes the keystore to
return a certificate chain rather than a bare key. The leaf is a
standard X.509 v3 certificate with a fixed serial number of 1 and a
fixed subject of CN=Android Keystore Key — neither carries
information. The content sits in an extension with OID
1.3.6.1.4.1.11129.2.1.17.
That extension contains a DER-encoded structure:
KeyDescription ::= SEQUENCE {
attestationVersion INTEGER,
attestationSecurityLevel SecurityLevel,
keyMintVersion INTEGER,
keyMintSecurityLevel SecurityLevel,
attestationChallenge OCTET_STRING,
uniqueId OCTET_STRING,
softwareEnforced AuthorizationList,
hardwareEnforced AuthorizationList,
}
SecurityLevel takes the same three values as the
previous article: Software, TrustedEnvironment, StrongBox.
attestationChallenge carries a nonce supplied by the
verifier, which is what makes the certificate a fresh statement rather
than a replayable one.
The two lists
AuthorizationList appears twice, and the difference
between the two occurrences is the whole point of the mechanism.
The hardwareEnforced list contains authorizations collected or generated by code inside the secure hardware, not controlled by the platform. The TEE or secure element vouches for them and enforces them on every use of the key.
The softwareEnforced list contains authorizations enforced by the Android platform. AOSP's own framing is that these are trusted only as long as the device is running an OS that complies with the Android Platform Security Model — bootloader locked, verified boot in the Verified state.
The same tag can appear in either list. Which list it appears in determines what a verifier may conclude:
purpose,algorithm,keySize,ecCurve,digest,origin,noAuthRequired,userAuthType,rollbackResistancein hardwareEnforced: the secure hardware itself constrains how the key can be used. A key marked sign-only cannot be used to decrypt; a key requiring user authentication cannot be used without it.- The same tags in softwareEnforced: the constraint exists only as OS policy. It holds while the OS is intact and evaporates when it is not.
Two tags are always software-enforced and this is expected rather
than suspicious. attestationApplicationId — which
application requested the key — and creationDateTime have
no meaning inside secure hardware, which knows nothing about packages or
wall-clock time. They are still useful, but they are platform
statements, not hardware statements.
The verifier's obligation follows: read the security level,
and separately confirm that each authorization you are relying on
appears in the hardware-enforced list. A key can carry
attestationSecurityLevel = TrustedEnvironment while an
authorization the issuer cares about sits on the software side. Checking
only the level, or checking only that a tag is present somewhere,
produces a conclusion the certificate does not support.
The rest of the structure
Root of trust.
RootOfTrust ::= SEQUENCE {
verifiedBootKey OCTET_STRING,
deviceLocked BOOLEAN,
verifiedBootState VerifiedBootState,
verifiedBootHash OCTET_STRING
}
VerifiedBootState is Verified, SelfSigned, Unverified or
Failed. For an issuer, verifiedBootState = Verified and
deviceLocked = true are the conditions under which the
software-enforced list means anything at all.
A parsing note: verifiedBootHash is absent in
attestation schema versions 1 and 2. A parser written against the
current schema will fail on older devices.
Patch levels. osVersion,
osPatchLevel (as YYYYMM), vendorPatchLevel,
bootPatchLevel. These let an issuer set a floor on how
stale a device's software may be.
Identity fields. attestationIdBrand,
Device, Product, Manufacturer,
Model, Serial, Imei,
Meid, and a second IMEI field from KeyMint 3. These require
specific device support, are gated by the platform, and are frequently
unavailable to third-party applications. Do not design an issuance flow
that depends on them without confirming availability on the target
device population.
Validating the chain
The verifier builds the chain from leaf to root and confirms the root is a published Google attestation root.
There are currently two. The long-standing root is RSA-signed. A new
ECDSA P-384 root was introduced as part of the transition to remote key
provisioning and began signing chains on 1 February 2026. A
verifier must trust both, and can distinguish them by the
root's signature algorithm: SHA384withECDSA for the new
one, SHA256withRSA for the legacy one. Whether and when
devices chain exclusively to the new root is a transition detail to
confirm against Google's current documentation rather than assume.
Revocation status is published as JSON at
https://android.googleapis.com/attestation/status, keyed on
certificate serial number. It changes, so a verifier fetches it rather
than embedding it.
Google publishes a Kotlin verification library,
android/keyattestation. Using it is preferable to writing
an ASN.1 parser for a structure with version-dependent fields and two
lists that are easy to confuse.
A correction worth stating explicitly, because the two cases are widely conflated. Google's documentation observes that a device without hardware attestation is not thereby untrustworthy — the absence of attestation is a neutral signal, not a negative one, because plenty of legitimate devices simply lack the capability. That reasoning does not extend to a revoked certificate. A revoked certificate must fail validation of the attestation evidence it carries. The two situations are "we have no evidence" and "the evidence we have is void," and they call for different decisions.
Remote key provisioning
Historically, attestation keys were injected at the factory in batches, with a single key shared across at least 100,000 devices so that the attestation key could not serve as a device identifier. Remote key provisioning replaces this with per-device keys provisioned over the air, carrying short-lived certificates.
The practical consequences for an issuer:
- Two chain structures coexist. A factory-keyed device presents a chain through a vendor intermediate to the legacy root, with a long-lived leaf. An RKP device presents a rotated leaf through a provisioned intermediate to the newer root.
- Certificate validity windows are short. An issuer cannot cache a chain indefinitely and treat it as current.
- The extension schema is identical in both cases. Only the roots and the key lifecycle differ.
The exact status of RKP across releases — supported, required to be implemented, or the only mechanism for devices launching on a given version — is stated differently in different AOSP documents and is worth reconciling against current documentation before writing it into a specification.
What attestation does not prove
Five limits, each of which has produced a wrong assumption somewhere:
It does not prove the requesting application is
genuine. attestationApplicationId is
software-enforced. On an intact device it identifies the caller; on a
modified one it does not.
It does not prove the secure hardware is sound. Attestation is a statement made by the TEE about itself. Published work has extracted hardware-protected keys from a major vendor's TEE keymaster implementation through IV reuse, together with a downgrade attack that forced patched devices back into vulnerable behaviour. A certificate from a broken TEE is a correctly signed statement of something false.
It does not prove the chain is real on every device. Devices whose attestation keyboxes have leaked can be used to forge attestations, and tooling to do so circulates. This is a large part of why revocation checking and RKP exist.
It does not root in Google on every device. Hardware attestation is a standard AOSP capability and does not require Google Mobile Services to produce a certificate. But on a device without GMS certification, the chain roots in the manufacturer's own attestation root. A verifier that only trusts Google roots will reject an otherwise perfectly hardware-backed key. Supporting such devices means maintaining additional trust anchors, obtained through each manufacturer's own channels.
It does not prove anything about enrolment. The certificate says where a key is. It says nothing about whether the person presenting it is who the credential will claim they are.
The verifier's checklist
- Generate the key with a server-supplied challenge; confirm the challenge in the certificate matches.
- Build and validate the chain to a trusted root; support both Google roots, plus any manufacturer roots your device population requires.
- Check the revocation status list, freshly fetched.
- Check certificate validity windows.
- Read
attestationSecurityLevelandkeyMintSecurityLevel. - Confirm every authorization you rely on is in the hardware-enforced list.
- Confirm
verifiedBootState = VerifiedanddeviceLocked = truebefore granting any weight to software-enforced content. - Apply a patch-level floor appropriate to the credential's value.
- Record the whole chain and the parsed result. When a decision is questioned years later, the certificate is the only evidence that survives.
Steps 6 and 7 are the ones most often skipped, and skipping them turns a proof into a formality.
Series: Key containers on mobile devices
- Part 1: What "hardware-backed" means on Android.
- Part 3: Seven containers, ranked by what you can prove.
References
- Android Open Source Project. Key and ID attestation. https://source.android.com/docs/security/features/keystore/attestation
- Android Developers. Verify hardware-backed key pairs with key attestation. https://developer.android.com/privacy-and-security/security-key-attestation
- Google. android/keyattestation verification library. https://github.com/android/keyattestation
- Android Open Source Project. Remote key provisioning. https://source.android.com/docs/core/ota/modular-system/remote-key-provisioning
- Shakevsky A, Ronen E, Wool A (2022). Trust Dies in Darkness: Shedding Light on Samsung's TrustZone Keymaster Design. 31st USENIX Security Symposium, pp. 251–268. IACR ePrint 2022/208.
- GrapheneOS. Attestation compatibility guide. https://grapheneos.org/articles/attestation-compatibility-guide



