Skip to main content

App Attestation

App Attestation checks that the application talking to nevisFIDO is your genuine, unmodified application, published through the official store. It defends against repackaged, tampered and cloned applications, and against scripts that speak the protocol without any application at all.

For the threat model and how the platform mechanisms work, see Application Attestation. This page covers what to configure.

nevisFIDO uses the Google Play Integrity API on Android and the Apple DeviceCheck services on iOS.

What App Attestation is not

Three separate features have similar names. Mixing them up leads to configuring the wrong fields.

FeatureQuestion it answersWhere it is configured
App AttestationIs this my genuine application?The App Attestation fields described below, switched on per authenticator by a policy extension
FIDO UAF Full Basic AttestationIs this a genuine authenticator of the claimed model?The FIDO UAF policy and the Metadata field
Android Key AttestationIs the key really held in certified secure hardware?Android Verification Level, which builds on Full Basic Attestation
Android Permissive Mode does not apply here

Android Permissive Mode relaxes FIDO UAF Full Basic Attestation only. It is not a dry run switch for App Attestation. The Android Reload Interval and Android Proxy fields likewise belong to Full Basic Attestation, where they control the key revocation list. For the difference between the attestation types, see Surrogate and Full Basic Attestation.

Before you start

Collect these items. Most of them come from outside Nevis and take time to obtain.

  • The application must support App Attestation. For the Nevis Access App this is chosen when the application is ordered, and the Google Cloud project number has to be supplied at that point for Android. See Ordering an Access App.
  • Android: a Google service account JSON file with access to the Play Integrity API, and the application registered in Google Play. See Google Play App Integrity, or Google Play App Integrity for your own application.
  • Android: the package name of the published application.
  • iOS: your Apple team identifier, a DeviceCheck key with its key identifier, and the bundle identifier of the application.
  • Outbound connectivity from nevisFIDO to Google and Apple, directly or through a proxy. On Android, nevisFIDO has to reach https://playintegrity.googleapis.com.

Configuring the nevisFIDO UAF Instance

Set these fields on the nevisFIDO UAF Instance pattern, in the Application Attestation (App Attestation) area.

Android

  • Android Service Account: upload the service account JSON file provided by Google. Use a variable holding a nevisAdmin secret file, or a Kubernetes file secret with k8s-secret-file://, so the credential is not stored in plain configuration.

iOS

  • iOS Team Identifier: the 10-character identifier of the team that signs your applications, from the Apple developer account portal. It is also known as the App ID prefix, without the trailing dot.
  • iOS DeviceCheck Key Identifier: the 10-character identifier of your DeviceCheck key.
  • iOS DeviceCheck Key: the DeviceCheck private key file, in PEM format. Create it in the Apple developer portal under the DeviceCheck capability. As with the Android service account, supply it through a secret.
  • iOS Attestation Limit: how many attestation keys one device may generate within 30 days. The default is 20. A device normally generates one key for the lifetime of the installation, so a high count suggests a compromised device. Raise the limit in development environments, where reinstallation is frequent.
Supply the DeviceCheck key, not the push key

iOS DeviceCheck Key expects the DeviceCheck private key. It is not the Apple Push Notification service key that you configure for push messages. The two are different credentials created under different capabilities in the Apple developer portal, and supplying the push key here makes attestation fail on every iOS device.

Connectivity

  • Proxy Address, Proxy User and Proxy Password: route the requests to the Google and Apple backend services through a proxy. Leave them empty when nevisFIDO reaches the internet directly.

These three fields serve App Attestation. Do not confuse them with the separately named Android Proxy fields, which belong to Full Basic Attestation.

Credential policy

  • iOS App Attestation Policy: the extId of the nevisIDM credential policy used for the iOS App Attestation Generic credentials that nevisFIDO stores. This is a nevisIDM credential policy, not a FIDO UAF policy. Changing it does not affect credentials that already exist.

Switching enforcement on

Configuring the fields above does not enforce anything by itself. Enforcement is requested per authenticator, through an extension in the FIDO UAF policy. If an authenticator carries no such extension, no App Attestation is performed for it.

Add the extension to the authenticators in your policy file. On Android:

{
"id": "ch.nevis.auth.fido.uaf.android-app-attestation-policy",
"data": "{ \"allowed_package_names\": [ \"my.application.packagename\" ] }"
}

On iOS:

{
"id": "ch.nevis.auth.fido.uaf.ios-app-attestation-policy",
"data": "{ \"allowed_bundle_ids\": [ \"my.application.bundleid\" ], \"allowed_environments\": [ \"production\" ] }"
}

allowed_package_names and allowed_bundle_ids are optional. When they are omitted, every application listed in the facets is accepted. allowed_environments restricts iOS to development, production, or both. For the full attribute reference, see Application Attestation.

Upload the policy files in the Policies field. See Policies.

Rolling it out without locking users out

Because enforcement lives in the policy, and a policy is selected per operation, you can introduce App Attestation gradually instead of switching it on for everyone at once.

  1. Configure the platform credentials first and leave the policy extensions out. Nothing changes for users at this stage.
  2. Create a second policy file, for example attested.json, that carries the extensions. Keep default.json unchanged.
  3. Select the new policy for a pilot group only, either from a Policy field expression or from the relying party. See Policies.
  4. Watch the nevisFIDO logs for attestation failures and confirm that the pilot registrations succeed on both platforms.
  5. Only then move the extensions into default.json.

Include development in allowed_environments while testing with builds that are not from the store, and remove it before going live.

Users on an application build that does not support App Attestation will fail once enforcement reaches them. Confirm the rollout of the application version before the rollout of the policy.

When attestation fails

A failed attestation usually surfaces as a registration or authentication that does not complete, without an obvious reason on the device. Work through the following:

  • Policy: does the authenticator the user is offered actually carry the extension you think it does, and is the correct policy being selected for the operation?
  • Identifiers: does the package name match the published Android application, and does the bundle identifier match the published iOS application? A mismatch rejects every request.
  • Environment: is the iOS build a store build, while allowed_environments permits only production, or the reverse during testing?
  • Facets: is the application listed in the facets? When allowed_package_names or allowed_bundle_ids are omitted, the facets are the accepted set.
  • Credentials: is the Android service account still authorized for the Play Integrity API, and is the iOS key the DeviceCheck key rather than the push key?
  • Connectivity: can nevisFIDO reach the Google and Apple services, and is the proxy configuration correct? On Android this means reaching https://playintegrity.googleapis.com. These are outbound calls at registration time, so a blocked egress route fails the whole operation.
  • Attestation limit: has a test device exceeded iOS Attestation Limit through repeated reinstallation?