YinkoShield

Knowledge Center / Checkpoint architectures / checkpoint architectures · 2025·11

Apple App Attest and DeviceCheck — the attestation/assertion split

Apple ships two related but distinct services for app and device integrity on iOS. App Attest is a two-step cryptographic model: attest an app-instance key once, then sign each subsequent call with assertions against that key. DeviceCheck is a separate per-device flag service — two bits and a last-update date, durable across reinstalls. They solve different problems, and operators frequently use both.

[ apple — app attest + device check ] step 1 · attestation (one-time) app-instance key generated (App Attest model) app calls attestKey(keyId, challenge) Apple returns CBOR attestation object binds key → genuine app, genuine device verified once, server-side, then trusted for the keyId keyId step 2 · assertion (per call) server issues challenge app calls generateAssertion(keyId, clientData) assertion signs challenge ‖ clientData hash server verifies with attested key + counter repeats per protected call device check · two-bit per-device server-side flags App stores 2 bits per device on Apple's server (e.g., "this account has been compromised before") separate from App Attest; not a runtime checkpoint, a long-lived per-device durable flag pair attest = identity of the runtime · assert = each call by it · device-check = durable per-device memory
App Attest is a two-step model. The attestation binds an app-instance key to a genuine app on a genuine device once; assertions sign each subsequent call with that key. DeviceCheck is a separate per-device two-bit flag service.

1. App Attest — the attestation step

App Attest, introduced in iOS 14, is built around an app-instance key generated by the App Attest service according to Apple’s App Attest model [1] — Secure Enclave-backed on supported devices. The key is bound to the app and the device; the private key never leaves the platform key store. The first time the app intends to use the key with a given relying party, it calls DCAppAttestService.attestKey(keyId, clientDataHash:) and Apple returns a CBOR-encoded attestation object [1] — the format identifier is apple-appattest, modelled on the WebAuthn attestation object structure with an Apple-specific authenticatorData.

The attestation object contains a certificate chain rooted in Apple’s App Attest Root CA, a credential identifier derived from the key, and a counter initialised at zero. The relying party verifies the chain server-side, confirms the signed clientData hash matches the request hash they originated, checks the attested public key matches the key the app intends to use, and records the attested public key + counter for that user.

Attestation is a one-time event per keyId. Once the relying party has verified an attestation, the attested key is treated as trusted for that user until invalidated. Re-attestation happens when the user reinstalls the app, restores from a different device, or — under specific platform-defined circumstances — when the Secure Enclave invalidates the key.

2. App Attest — the assertion step

Once the attestation is on file, every protected request from the app uses an assertion: the app calls DCAppAttestService.generateAssertion(keyId, clientDataHash:) and App Attest generates a signature over the data the app provides, using the attested key [1]. The relying party verifies the signature using the attested public key, increments the recorded counter, and rejects the request if the new counter is not strictly greater than the recorded value.

The cryptographic effect is straightforward: each protected call carries a signature that the relying party can verify, bound to a key whose origin (a genuine app, on a genuine device, within App Attest’s integrity guarantees) was established at attestation time and whose use is monotonic via the counter.

3. DeviceCheck — the separate per-device flag service

DeviceCheck predates App Attest and addresses a different problem [2]: associating a small amount of durable per-device state with the operator’s view of that device, persisting across app reinstall on the same physical device. (Apple’s documentation describes durability across reinstall; behaviour across iCloud account changes is not explicitly specified, though the bits are scoped per-developer per-device-identifier server-side.)

The service offers exactly two bits per app-per-device, plus a last-update date. The relying party reads the bits via Apple’s servers using a token the app produces, and writes new values the same way. The classic use case is an operator that has flagged a device for prior compromise: even if the user reinstalls the app to “clear” their state, the two bits persist with Apple and the operator can re-apply the flag.

DeviceCheck is not a runtime checkpoint. It does not say anything about the device at the moment of the call. It is a small, durable, per-device datastore that only the relying party can write — and only Apple can host.

4. What the model proves and where it stops

Together, App Attest and DeviceCheck form a stack with a clear boundary:

  • App Attest assertions prove a relying-party-issued challenge was signed by an attested key on a known device, in a current call.
  • The attestation chain roots that proof in Apple’s CA, bounding the population of devices and apps that can produce valid assertions.
  • DeviceCheck maintains durable per-device flags that survive reinstall.

What the stack does not provide — by design, out of scope of the API — is a signed account of what the app did between assertions. Each assertion is a checkpoint: a signature at the moment the API was called. The runtime trajectory between assertions is not part of what App Attest signs, and DeviceCheck holds two bits, not a record of the call sequence. This boundary is the same one Play Integrity draws on the Android side, and it is the boundary Execution Evidence Infrastructure (EEI) — the device-identity infrastructure layer for banking and payments — is designed to compose with, not replace.

5. Cross-references

6. External references

[1] Apple. Establishing your app’s integrity (App Attest). developer.apple.com/documentation/devicecheck/establishing_your_app_s_integrity. Cited 2025-11-05.

[2] Apple. DeviceCheck framework. developer.apple.com/documentation/devicecheck. Cited 2025-11-05.

[3] Apple. Apple Platform Security — Secure Enclave. support.apple.com/guide/security/secure-enclave-sec59b0b31ff/web. Cited 2025-11-05.