Apple and Android Attestation Formats

Once you accept direct attestation from platform authenticators, the formats you meet are no longer packed. This page covers the Apple anonymous format, Android key attestation and the legacy SafetyNet variant — what each proves, how each is verified, and why none of them gives you the device identity that teams often expect. It sits under Attestation vs Assertion Explained; the FIDO2 default format is covered in understanding packed attestation.


Format Reference

Format Chains to Carries a signature field Model identity
apple an Apple root no — the binding is a nonce in the certificate none by design
android-key a Google root yes keystore properties, not a model
android-safetynet a Google root, via a signed token inside the token legacy; being retired
none none

The absence of a signature field in the Apple format is the detail that most often breaks a verifier written against packed: there is nothing to verify in the usual place, because the binding lives in a certificate extension instead.

What each platform format offers Platform attestation formats are verifiable but deliberately reveal little about the individual device. Verifiable provenance, minimal device identity apple chains to an Apple root; anonymous by design, no model identity android-key chains to a Google root; can assert key properties from the hardware keystore android-safetynet a legacy attestation carried in a signed token; being retired none increasingly what synced platform passkeys produce regardless of the request

Root Cause Analysis

1. Expecting a signature field. An Apple statement has no sig. A verifier that requires one rejects every Apple registration, and the error message will point at a missing field rather than at the wrong assumption.

2. Skipping the nonce comparison. The Apple format binds a certificate to a ceremony by embedding a nonce derived from authenticatorData and the client-data hash. Without recomputing and comparing that nonce, a certificate from any ceremony would satisfy the check.

3. Treating Android key attestation as universally available. Its contents vary by vendor, by Android version and by whether the key was generated in the secure element. Fields you rely on may simply be absent on hardware you have not tested.

4. Building on SafetyNet. It is a legacy path that is being retired in favour of newer platform mechanisms. Code that requires it will break; code that accepts it as one of several formats will not.

5. Expecting a device identifier. None of these formats provides one. Apple’s is explicitly anonymous, and Android’s describes key protection rather than device identity.

Verifying an Apple anonymous statement The nonce is derived from the ceremony, embedded in the certificate, and must match what you compute. No signature field: the binding is the nonce nonce SHA-256 of authData + hash certificate extension carries the nonce compare byte-for-byte chain to the pinned Apple root The nonce binding stops a certificate from one ceremony vouching for another.

Step-by-Step Resolution

Step 1 — dispatch on fmt and accept the unknown

Route each format to its own verifier and route everything unrecognised to your documented no-device-claim path. New formats appear; a dispatch table with a hard failure at the end will meet one eventually.

Step 2 — implement the Apple path around the nonce

Compute SHA-256 over authenticatorData concatenated with the client-data hash, extract the nonce from the certificate extension, and compare byte-for-byte. Then validate the chain to a pinned Apple root.

Step 3 — implement the Android path around the keystore extension

Verify the statement signature, validate the chain to a pinned Google root, then read whichever keystore properties your policy consumes — treating every field as optional.

Step 4 — treat SafetyNet as deprecated but accepted

Verify it if you receive it; do not build policy that requires it.

Step 5 — record the format alongside the outcome

Which format a credential arrived with is a useful population statistic and the fastest way to notice a platform behaviour change.

What Android key attestation adds The Android format can carry assertions from the hardware keystore about how the key is protected. Richer claims, same fundamental limits it can assert the key is in secure hardware user authentication is required the key cannot be exported the boot state of the device it still cannot identify the individual device to you tell you the credential is unsynced survive a policy that blocks attestation be relied on across all Android builds Support varies across vendors and Android versions — treat every field as optional.

Verification and Testing

One captured registration per format, with its trust anchor, is the only fixture set that will keep this code honest. Synthetic statements test your verifier against your own assumptions rather than against the platforms.

For the Apple path, add a fixture whose nonce does not match the ceremony and assert it is rejected. That single test is what proves the binding is actually checked rather than merely parsed.

For the Android path, add a fixture missing an optional keystore field and assert that verification still succeeds while the policy branch handles the absence. Optional fields being treated as mandatory is the most common source of vendor-specific failures.

Add an unknown-format fixture and assert it reaches your no-device-claim path without throwing.


Pitfalls

1. One verifier for all formats. They share almost nothing; a shared code path hides at least one wrong assumption.

2. Requiring keystore properties that are optional. Produces failures confined to particular vendors and Android versions.

3. Assuming platform attestation identifies a device. It does not, and designing around the expectation that it might wastes effort.


Frequently Asked Questions

Will I receive attestation from a synced passkey at all?

Frequently not. Platform authenticators increasingly return no attestation statement regardless of what was requested, because a synced credential exists on several devices and there is no single device to attest to. Code that treats an absent statement as an error rejects a large and growing share of legitimate registrations.

Does Apple’s format let me distinguish one Mac from another?

No. It is anonymous by design: the statement proves the credential was created by genuine Apple hardware and nothing more. Device-level identity is deliberately withheld, and there is no configuration that changes this for a web relying party.

Is Android key attestation worth implementing?

Only if a policy consumes its keystore properties — for instance, requiring that the key is hardware-backed and that user authentication is enforced by the keystore. For a consumer product with no such requirement it is verification work with no consumer.

What replaces SafetyNet?

Newer platform integrity mechanisms, with the practical effect for a relying party being that fewer registrations carry that format over time. The right posture is to keep accepting it while it appears and to build nothing that depends on it.

Should the format influence what the credential can do?

Only if you have a written requirement it maps to. In most products the sensible design is that every verified registration produces an equally usable credential, and attestation influences only which credentials satisfy a higher-assurance policy for particular actions.

How do I obtain the platform roots?

From the platform vendors’ published certificate material, pinned in your deployment. As with any attestation root, retrieving it over the same channel as the statement it authenticates provides no assurance.

Do these formats appear in enterprise deployments differently?

They can. A managed device may produce richer attestation than the same hardware would outside management, because platform policy governs what is disclosed. That is worth knowing when a behaviour differs between a test device and a corporate one.


How should platform attestation change what a credential is allowed to do?

In most products, not at all. The credential is equally usable for sign-in whether or not a statement arrived, and the only defensible use of the format is as one input to a policy that gates something more sensitive than reading an account. Where a genuine requirement exists — a regulated workflow that must run on hardware-backed keys, for instance — express it as a tier rather than as an enrolment barrier: accept the credential, record what it did and did not prove, and let the higher-assurance surfaces ask for something stronger. That keeps enrolment open for everyone while giving the policy a real place to apply, and it avoids the failure mode where a platform behaviour change quietly stops a whole population from being able to register.

Recording the format alongside every registration also gives you a cheap early warning when a platform changes its behaviour, since a sudden shift in the distribution is visible long before anybody files a report about it.

Related