Android Attestation Deep Dive
This page explains how trust is established from boot through app installation and how that state is proven to a
back-end service via Android hardware attestation. It expands on certificate chains, the KeyDescription schema,
verification steps, and edge cases, and it ties these to the Android Verified Boot (AVB) chain and APK signing.
In contrast to iOS, Android requires no special setup procedure, and an app can use attestation
    Tip
Keep Figure 1 at your ready while digging through this page, as it will be referenced throughout!
How platform trust is established during boot
- Boot ROM (immutable in SoC) verifies the first-stage bootloader using SoC fuses / OEM root.
 - Bootloader verifies 
vbmetaand the partition chain via AVB.vbmetacontains the public key (or hash thereof) authorizing images and rollback indexes. - If verification passes and the bootloader is locked, boot proceeds with 
verifiedBootState = VERIFIED; otherwiseSELF_SIGNED,UNVERIFIED, orFAILEDstates are signaled. - dm-verity ensures runtime integrity of verified partitions (system/vendor/product).
 - Rollback protection: bootloader maintains rollback index slots in tamper-resistant storage; images signed with older rollback index are rejected. Not all devices advertise this.
 
What the attestation proves about the boot
The RootOfTrust structure in the attestation extension contains:
verifiedBootKey: hash of the AVB root public key that authorized the boot images.deviceLocked: boolean derived from bootloader lock state.verifiedBootState: one ofVERIFIED,SELF_SIGNED,UNVERIFIED,FAILED.- Patch claims: 
osVersion,osPatchLevel, and (on newer devices)bootPatchLevel/vendorPatchLevel. 
Policy implication: Your server can require deviceLocked=true, verifiedBootState=VERIFIED, and minimum patch
levels; optionally pin the expected verifiedBootKey (accept OEM keys only, or accept your enterprise/sovereign
AVB key(s) if you operate a trusted ROM program).
How trust is established for the app at install time
- Signature Scheme v2/v3/v4 embeds signatures over the app contents at the APK level (post-Android 7).
 - The platform verifies the signing certificate(s) when installing/updating an app.
 
What the attestation proves about the app
The AttestedApplicationId section contains:
- package_infos
    - package_name identifying your application
    - version indicating the version of the application
- signature_digests: values (SHA-256 digests of the signing certificate(s)) pulled
  from the Package Manager at attestation time.
Policy implication: Your server must check against the package name and signer digest(s) of your release build(s). If you use key rotation, store and accept all legitimate digests. Re-attest while enforcing application versions to enforce updates.
How attestation is produced (on-device) and verified (server-side)
On-device production
- App requests a new key from KeyMint/StrongBox with required properties (algorithm, size, purposes, user-auth requirements).
 - App calls attestKey with a fresh server-provided challenge.
 - KeyMint produces a certificate chain for the key:
- Leaf certificate embeds the attestation extension (
KeyDescription) withRootOfTrust,AttestedApplication, and AuthorizationLists. - Intermediates up to a Google Attestation Root (for hardware attestation on certified devices).
 
 - Leaf certificate embeds the attestation extension (
 - App sends {certChain, challenge, metadata} to your backend.
 
Server-side verification pipeline (normative checklist)
- Chain validation: X.509 path build and verify (signatures, BasicConstraints, EKU if present, issuer/subject continuity).
 - Time validity: validate NotBefore / NotAfter on intermediates; tolerate known leaf-time quirks only if you apply strict freshness windows (see §6).
 - Attestation root: anchor in Google’s published attestation-root set (keep updated).
 - Extension parse: parse 
KeyDescriptionwith a standards-compliant ASN.1/DER library; respect DER sorting for SET OF. - Challenge: exact match to your one-time challenge; reject reuse or replay.
 - Root-of-trust: require 
verifiedBootState = VERIFIED,deviceLocked = true; optionally pinverifiedBootKeyand enforce minimumosPatchLevel/vendorPatchLevel/bootPatchLevel. - App binding: require 
packageNameand signer digest(s) to match your allow-list; optionally pinversionCodevia an app-side claim bound to the challenge. - Key properties: check 
securityLevelinhardwareEnforcedis TrustedEnvironment or StrongBox; verifyuserAuthparameters (auth-per-use / timeouts) meet your policy. - Revocation: check against revoked attestation keys (Google feeds) and your own deny-lists; fail closed in high-assurance contexts.
 - Decision & logging: produce an auditable decision with specific reasons (e.g., “boot not verified”, “signer mismatch”, “patch too old”).
 
User authentication & key lifecycle in attestation
- User presence / authorization: If 
userAuthis required, KeyMint enforces biometric/PIN at key use. The authorization policy (per-use, validity window) appears in the AuthorizationLists and is remotely checkable. - Invalidation triggers (enforced by Android, no server telemetry needed):
- Disable/reset of secure lock screen → auth-bound keys invalidated.
 - Biometric enrollment changes (if so configured) → invalidate.
 - Bootloader unlock or verified-boot failure → keys wiped/unusable; subsequent attestations show
  
deviceLocked=falseor degradedverifiedBootState. - Factory reset → keys deleted.
 
 - Best practice: bind critical operations (e.g., credential issuance, high-value transactions) to auth-required keys whose attestation you already validated.
 
Certificate chains & trust anchors
- Expect a chain terminating in a Google Hardware Attestation Root for hardware-backed attestation.
 - Always validate full chain: signatures, validity, path length, EKU (if present).
 - Reject software/hybrid attestation unless explicitly allowed for test scenarios; keep a separate trust store for emulators.
 - Keep the attestation root set and revocation lists up to date on your server; retrieve and cache periodically.
 
Verification pitfalls to avoid
- Ignoring the challenge: always bind to a fresh, single-use nonce and reject replays.
 - Trusting package name alone: you must match signing certificate digest(s).
 - Accepting SELF_SIGNED states: only acceptable for tightly scoped test channels.
 - Relying solely on patch level: combine with verified boot, device lock, and (optionally) pinned 
verifiedBootKey. - Parsing ASN.1 with ad-hoc code: use a proper DER parser to handle 
SET OFordering and nested structures. 
References & libraries
- Developer guide (Key Attestation)
 - AOSP schema & extension documentation
 - Libraries (legacy)
 - Libraries (current)
 - Warden Supreme (this project)