MASTG-KNOW-0044: Key Attestation

For applications that rely heavily on Android KeyStore for business-critical operations, such as multi-factor authentication using cryptographic primitives and secure client-side storage of sensitive data, Android provides the Key Attestation feature, which helps analyze and verify the security of cryptographic material managed through the Android KeyStore. Starting with Android 8.0 (API level 26), key attestation became mandatory for all new devices (Android 7.0 or higher) that require device certification for Google apps. These devices use attestation keys signed by the Google Hardware Attestation Root Certificate, and these keys can be verified through the key attestation process.

During key attestation, we can specify the alias of a key pair and, in return, receive a certificate chain that we can use to verify the properties of that key pair. If the chain's root certificate is the Google Hardware Attestation Root certificate and the hardware-backed key pair storage checks are satisfied, this provides assurance that the device supports hardware-level key attestation and that the key is stored in the hardware-backed keystore that Google believes to be secure. Alternatively, if the attestation chain has any other root certificate, Google does not make any claims about the security of the hardware.

Although the key attestation process can be implemented directly in the application, it is recommended that it be implemented on the server side for security reasons. The following are the high-level guidelines for the secure implementation of Key Attestation:

  • The server should initiate the key attestation process by generating a secure random number using a CSPRNG (Cryptographically Secure Random Number Generator) and sending it to the client as a challenge.
  • The client should call the setAttestationChallenge API with the challenge from the server, then retrieve the attestation certificate chain using the KeyStore.getCertificateChain method.
  • The attestation response should be sent to the server for verification, and the following checks should be performed:
    • Verify the certificate chain up to the root and perform certificate sanity checks, including validity, integrity, and trustworthiness. Check the Certificate Revocation Status List maintained by Google to confirm that none of the certificates in the chain were revoked.
    • Check whether the root certificate is signed with the Google attestation root key, which makes the attestation process trustworthy.
    • Extract the attestation certificate extension data from the first element of the certificate chain and perform the following checks:
      • Verify that the attestation challenge matches the value generated by the server when initiating the attestation process.
      • Verify the signature in the key attestation response.
      • Verify the Keymaster's security level to determine whether the device has a secure key storage mechanism. The security level will be one of Software, TrustedEnvironment, or StrongBox (see Android KeyStore for details on hardware-backed KeyStore). The client supports hardware-level key attestation when the security level is TrustedEnvironment or StrongBox and the attestation certificate chain includes a root certificate signed by the Google attestation root key.
      • Verify the client's status to ensure a full chain of trust - verified boot key, locked bootloader, and verified boot state.
      • Additionally, you can verify the key pair's attributes, such as purpose, access time, authentication requirement, etc.

Note

If that process fails for any reason, the key is not stored in the security hardware. That does not mean the key is compromised.

The typical Android Keystore attestation response is as follows:

{
    "fmt": "android-key",
    "authData": "9569088f1ecee3232954035dbd10d7cae391305a2751b559bb8fd7cbb229bd...",
    "attStmt": {
        "alg": -7,
        "sig": "304402202ca7a8cfb6299c4a073e7e022c57082a46c657e9e53...",
        "x5c": [
            "308202ca30820270a003020102020101300a06082a8648ce3d040302308188310b30090603550406130...",
            "308202783082021ea00302010202021001300a06082a8648ce3d040302308198310b300906035504061...",
            "3082028b30820232a003020102020900a2059ed10e435b57300a06082a8648ce3d040302308198310b3..."
        ]
    }
}

In the JSON snippet above, the keys have the following meanings:

  • fmt: Attestation statement format identifier
  • authData: Authenticator data for the attestation
  • alg: Algorithm used for the signature
  • sig: Signature
  • x5c: Attestation certificate chain

Note

The sig is generated by concatenating authData and clientDataHash (the challenge sent by the server) and signing with the credential's private key using the alg signing algorithm. The same is verified on the server side using the public key in the first certificate.

For more information on the implementation guidelines, you can refer to Google Sample Code.

From a security analysis perspective, the following checks can help ensure the secure implementation of Key Attestation:

  • Check whether key attestation is implemented entirely on the client side. In that case, it can be more easily bypassed through application tampering, method hooking, etc.
  • Check whether the server uses a random challenge when initiating key attestation. Failing to do so results in an insecure implementation vulnerable to replay attacks. Also, verify the challenge's randomness.
  • Check whether the server verifies the integrity of the key attestation response.
  • Check whether the server performs basic checks, such as integrity and trust verification, validity, etc., on the certificates in the chain.