For the complete documentation index, see llms.txt. This page is also available as Markdown.

Platform Attestation

Android and iOS expose fundamentally different attestation capabilities to third-party wallet apps. This page explains what each platform can and cannot prove, how that asymmetry shapes the evidence Blerify returns to your verification endpoint, and how to write a policy that accounts for it.


Prerequisites

You should be familiar with Blerify's assurance tiers (Basic, Standard, Premium) and the general shape of the verification evidence response. If you haven't read Assurance Tiers yet, start there.


Why the platforms differ

At Standard and Premium tiers, Blerify asks the wallet to submit attestation data alongside the credential presentation. That data supports two claims: the signing key lives in secure hardware, and the user authenticated with their biometric before every signing operation.

On Android, a single API — Android Key Attestation — lets the wallet produce an X.509 certificate chain signed up to a Google-managed root. That chain encodes the key's properties directly: where it lives (TEE or StrongBox), whether biometric is required to use it, and whether the key is destroyed when a new biometric is enrolled. Every property is hardware-signed and cannot be forged by software, including on a rooted device.

On iOS, the equivalent API is Apple App Attest. It proves that an unmodified copy of the registered app, running on genuine Apple hardware, possesses the signing key. What it cannot prove is where inside the device the key lives, whether biometric is required for each signature, or whether the key will be invalidated on enrollment change. Apple provides no API that attests Secure Enclave key properties to third-party apps — the wallet reports those properties itself.

This is an architectural decision by Apple, not a limitation of any wallet implementation. The gap has been present since App Attest launched in 2021 and affects every third-party wallet on iOS.


What this means in the evidence response

The asymmetry surfaces in two places: fields whose values differ by platform, and _reason fields that explain why a field is absent.

security_level_attested

On Android, key_attestation.security_level — either STRONG_BOX or TRUSTED_ENVIRONMENT — is extracted directly from the hardware-signed certificate chain. Blerify sets security_level_attested: true.

On iOS, the wallet self-reports SECURE_ENCLAVE. Blerify sets security_level_attested: false.

attested: false on iOS means the key_biometric_binding properties are self-reported by the wallet. On a genuine device running an unmodified app, they accurately reflect how the Secure Enclave key was configured. On a jailbroken device, they can be forged. Android Key Attestation cannot be forged because the certificate chain is signed by hardware that the operating system cannot reach.

key_biometric_binding fields

These five fields describe the access-control policy that governs the signing key.

Field
What it means
Android
iOS

biometric_required

Biometric authentication is required before every signing operation

Hardware-attested

Self-reported

auth_type

Which authenticator the key accepts: FINGERPRINT, FACE, or DEVICE_CREDENTIAL

Hardware-attested

Self-reported

auth_timeout_seconds

Seconds of reuse allowed after authentication. 0 means every signing operation requires fresh authentication — no caching window

Hardware-attested

Self-reported

invalidated_on_enrollment_change

The key is destroyed if any new biometric is added to the device

Hardware-attested

Self-reported

attested

Whether the four fields above are hardware-attested (true) or self-reported (false)

Always true

Always false

auth_timeout_seconds: 0 combined with invalidated_on_enrollment_change: true is the strongest configuration. The key cannot be used without the holder's biometric at the moment of signing, and enrolling any new biometric on the device permanently destroys the key.

Strong biometric vs. device credential

Both platforms support two key-binding paths: the strong biometric path (fingerprint or face recognition) and the device credential path (PIN, pattern, or passcode). The path chosen at key-creation time determines what auth_type reports.

On the strong biometric path, auth_type is ["FINGERPRINT"], ["FACE"], or both, and invalidated_on_enrollment_change is true. On the device credential path, auth_type is ["DEVICE_CREDENTIAL"] and invalidated_on_enrollment_change is false — a PIN change does not destroy the key. This distinction matters for non-repudiation claims: a key on the device credential path cannot be made inaccessible to an attacker who knows the PIN.

device_attestation at Premium on iOS

At Premium, an Android wallet submits a Play Integrity token that produces a device-integrity verdict: locked bootloader, certified OS image, legitimate app install source, and recent security patches. These are independent signals that key attestation does not cover.

iOS has no equivalent API for third-party apps. App Attest, which is already fully consumed at Standard tier, verifies app identity against Apple's servers but does not produce a device-integrity verdict, cannot detect jailbreaks, and does not inspect the OS image.

At Premium on iOS, device_attestation is always null with device_attestation_reason: "platform_not_available".

This is not a failure — it is a structural platform constraint. The practical consequence is that the Premium upgrade on iOS comes entirely from the biometric layer. liveness_verification and coercion_check work identically on both platforms.

device_metadata attestation

Android Key Attestation embeds the device model and OS version in the hardware-signed certificate chain, so device_metadata.attested is true on Android. App Attest proves device genuineness but does not include model or OS version in the attestation object, so those values are self-reported by the wallet on iOS and device_metadata.attested is false.


The _reason field

Every optional evidence field has a companion _reason field. When the main field is populated, _reason is null. When the main field is null, _reason explains why.

Value
Meaning
What to do

null

The field is populated

N/A

platform_not_available

The platform has no API for this capability — for example, iOS device_attestation at Premium

Structural limit — accept, or apply a platform-specific policy rule

wallet_not_supported

The wallet does not implement Blerify extensions

Capability gap — downgrade assurance or direct users to a compatible wallet

not_requested

Your verification configuration did not request this tier or feature

Expected absence

user_declined

The user denied a required permission (camera access, biometric prompt)

Active refusal — route to manual review rather than treating identically to a structural platform limit

failed

Validation was attempted but the data was rejected — invalid token, spoof detected, assertion mismatch

Treat as a strong integrity signal — investigate

attestation_not_supported

Older Android device where the key is in hardware but cryptographic attestation is unavailable

Hardware-backed but unprovable — accept or downgrade per your policy

The _reason field is always present in the response schema — null when the main field is populated. You can rely on a consistent shape and never need to infer absence semantics from a missing field.

The distinction between platform_not_available and user_declined matters for policy. A device that structurally cannot produce a signal is different from a user who actively chose not to provide one. Consider routing user_declined to a separate review queue rather than treating it the same as a platform limit.

Similarly, attestation_not_supported on an older Android device is different from failed. The former is a legacy hardware limitation affecting less than 1% of the active Android fleet; the latter is an active integrity failure.


Platform comparison

Evidence field
Android
iOS

key_attestation.security_level

Hardware-attested (STRONG_BOX or TRUSTED_ENVIRONMENT)

Self-reported (SECURE_ENCLAVE)

key_attestation.security_level_attested

true

false

key_biometric_binding.*

All five fields hardware-attested

All five fields self-reported

key_biometric_binding.attested

true

false (always)

device_metadata.attested

true

false

device_metadata.attestation_source

android_key_attestation

wallet_self_reported

device_attestation at Premium

Play Integrity — device integrity, OS certification, app integrity

null, _reason: "platform_not_available"

liveness_verification at Premium

Full liveness — platform-neutral

Full liveness — platform-neutral

coercion_check at Premium

Facial analysis on liveness frames — platform-neutral

Facial analysis on liveness frames — platform-neutral


Key invalidation on enrollment change

Android

When a new biometric is enrolled after the signing key was created — for example, if someone adds their own fingerprint to a stolen phone — the key is destroyed automatically on the strong biometric path. The invalidated_on_enrollment_change: true field tells you this protection is active, and attested: true tells you it is hardware-enforced.

On the device credential path (auth_type: ["DEVICE_CREDENTIAL"]), the key is PIN-gated and a PIN change does not destroy it. Check auth_type to understand which path is in use before making non-repudiation claims.

iOS

The equivalent protection comes from an access-control flag set on the Secure Enclave key at creation time. A key created with this flag becomes inaccessible when any new biometric is enrolled — the Secure Enclave enforces this locally. The wallet self-reports this via invalidated_on_enrollment_change: true, and attested: false tells you it is locally enforced rather than remotely verifiable.

On the device credential path, enrollment changes do not invalidate the key, matching Android's device credential behavior.


TEE vs. StrongBox on Android

Android Key Attestation distinguishes two hardware security levels.

TEE (Trusted Execution Environment) is a hardware-isolated execution environment present on virtually all Android devices since Android 7.0. It runs in a secure partition of the same processor, enforcing memory separation between the normal Android OS and the secure world where keys are managed. TEE has a broader attack surface than discrete secure hardware — known CVEs exist for specific chipset implementations, and exploitation typically requires an attacker to first gain code execution on the device.

StrongBox is a dedicated, tamper-resistant secure processor with its own CPU, storage, and random number generator. It is not present on all devices — it is common on modern flagship phones but absent from many mid-range and budget devices. StrongBox is significantly harder to attack than TEE because it is physically separate hardware.

Both are accepted at Standard and Premium tiers. Blerify reports security_level so you can apply your own acceptance policy. Most regulated identity verification use cases accept TEE — exploiting it to bypass biometric-gated key signing requires chaining multiple chipset-specific vulnerabilities. If your requirements call for StrongBox-only, evaluate security_level in the evidence and enforce your policy accordingly.


Older Android devices and attestation_not_supported

A small fraction of Android devices — less than 1% of the active fleet — launched before Android 8.0 with hardware security modules that predate Key Attestation. On these devices, the signing key is still in hardware and the biometric gates still work, but Blerify cannot produce the X.509 certificate chain that proves hardware residency.

In this case, key_attestation_reason is "attestation_not_supported". Whether to accept a hardware-backed but unprovable key is a policy decision. Most verifiers treat it the same as a proven hardware-backed key given the low prevalence and the fact that the user still authenticated with their biometric to authorize the presentation.


Writing a policy that accounts for iOS

Accept iOS without device attestation. Most regulated use cases accept that iOS does not expose a Play Integrity equivalent for third-party apps. The combination of App Attest at Standard — proving genuine Apple hardware and an unmodified app — plus liveness at Premium covers the majority of identity verification and account-opening flows. Document the acceptance explicitly in your risk assessment.

Differentiate security_level_attested: false by platform. On iOS, this value always reflects a platform constraint, not a degraded or suspicious result. Pair it with a check on the platform field to confirm you are seeing the expected iOS self-reported case rather than an anomaly.

Treat attested: false differently from failed. An iOS key with attested: false and a valid App Attest assertion is meaningfully different from a key whose attestation failed validation. The former is a known platform limitation; the latter is an active integrity failure worth investigating. Your policy logic should handle them separately.

Use user_declined as an escalation signal. A user who denies the biometric prompt or camera permission has actively interrupted the flow. This is a different risk category from an iOS device that structurally cannot produce device attestation. Route user_declined to a review queue rather than treating it as equivalent to a structural absence.

Require liveness for high-value iOS flows. Since device attestation is unavailable on iOS, liveness_verification at Premium is the primary compensating control for transactions that warrant it. If you need the highest available assurance on iOS, make liveness a hard requirement in your verification configuration.

Do not block on "platform_not_available". Blocking iOS users because the platform cannot produce a Play Integrity equivalent would exclude a large share of legitimate users without a corresponding security benefit. Note the limitation, compensate with liveness where the risk warrants it, and document the accepted residual gap.


What the layered iOS evidence adds up to

At Premium on iOS, the combination of evidence across all layers supports a defensible assurance level even without hardware-attested key_biometric_binding and without device attestation.

  1. App Attest proves the request came from a genuine Apple device running an unmodified instance of the registered app. A modified or unauthorized app fails App Attest before any signing occurs.

  2. Secure Enclave key is configured by the wallet with enrollment-change invalidation. The key is tied to the biometric enrollment set at key-creation time and becomes inaccessible if that set changes. The Secure Enclave enforces this locally — Apple does not provide a remote attestation of it, but the wallet has no mechanism to bypass it on a genuine, unmodified device.

  3. Liveness verification confirms that the person physically present is the credential holder by comparing a live facial capture against the portrait embedded in the credential presentation.

The gap versus Android is that the Secure Enclave configuration is enforced by Apple's hardware rather than proven by a verifiable certificate chain. For most regulated use cases, that is an acceptable residual risk.


Non-repudiation and the biometric binding chain

At Standard tier, the combination of key attestation and biometric binding supports a non-repudiation argument: the credential was presented by someone who held the device, authenticated with the enrolled biometric, and whose signing key would have been destroyed had anyone modified the biometric enrollment set.

The argument is strongest on Android, where each property in key_biometric_binding is hardware-attested. On iOS, it relies on Apple's local enforcement of the Secure Enclave configuration rather than on a verifiable proof. In most jurisdictions this is sufficient to shift the burden of proof to the credential holder to demonstrate they did not authorize the presentation.

At Premium on iOS, liveness_verification strengthens the chain by confirming that the person who authorized the presentation was physically present and matched the credential's portrait.

Whether this evidence constitutes legally sufficient non-repudiation depends on the jurisdiction and applicable regulatory framework. Your legal team should evaluate the evidence chain against your specific requirements.


Next steps

Continue to Assurance Tiers — how Basic, Standard, and Premium differ, what each proves per platform, and how to choose the right tier for your use case.

See also: Biometric Binding · Verify a Credential · API Reference

Last updated