Set correct attestation version for StrongBox

We observe that attestations generated with a security level of
`StrongBox` (value 2) must have an `attestationVersion` of 300. The
previous implementation determined this version based only on the
Android SDK version, which could lead to invalid attestations.

This commit refactors the version retrieval logic to be dependent on the
security level:

- In `AndroidDeviceUtils`, the `attestVersion` and `keymasterVersion`
  properties have been converted into `getAttestVersion(securityLevel)`
  and `getKeymasterVersion(securityLevel)` functions.
- `getAttestVersion` now correctly returns `300` when the security level
  is `StrongBox`.
- `AttestationBuilder` is updated to call these new functions, passing
  the appropriate security level to ensure the generated attestation is
  compliant with official documentation.
This commit is contained in:
JingMatrix
2025-12-04 01:57:59 +01:00
parent d0cc5e3b56
commit b988d04971
2 changed files with 39 additions and 18 deletions
@@ -103,14 +103,18 @@ object AttestationBuilder {
uid: Int, uid: Int,
securityLevel: Int, securityLevel: Int,
): ASN1Sequence { ): ASN1Sequence {
val teeEnforced = buildTeeEnforcedList(params) val teeEnforced = buildTeeEnforcedList(params, securityLevel)
val softwareEnforced = buildSoftwareEnforcedList(uid) val softwareEnforced = buildSoftwareEnforcedList(uid, securityLevel)
val fields = val fields =
arrayOf( arrayOf(
ASN1Integer(AndroidDeviceUtils.attestVersion.toLong()), // attestationVersion ASN1Integer(
AndroidDeviceUtils.getAttestVersion(securityLevel).toLong()
), // attestationVersion
ASN1Enumerated(securityLevel), // attestationSecurityLevel ASN1Enumerated(securityLevel), // attestationSecurityLevel
ASN1Integer(AndroidDeviceUtils.keymasterVersion.toLong()), // keymasterVersion ASN1Integer(
AndroidDeviceUtils.getKeymasterVersion(securityLevel).toLong()
), // keymasterVersion
ASN1Enumerated(securityLevel), // keymasterSecurityLevel ASN1Enumerated(securityLevel), // keymasterSecurityLevel
DEROctetString(params.attestationChallenge ?: ByteArray(0)), // attestationChallenge DEROctetString(params.attestationChallenge ?: ByteArray(0)), // attestationChallenge
DEROctetString(ByteArray(0)), // uniqueId DEROctetString(ByteArray(0)), // uniqueId
@@ -121,7 +125,7 @@ object AttestationBuilder {
} }
/** Builds the `TeeEnforced` authorization list. These are properties the TEE "guarantees". */ /** Builds the `TeeEnforced` authorization list. These are properties the TEE "guarantees". */
private fun buildTeeEnforcedList(params: KeyMintAttestation): DERSequence { private fun buildTeeEnforcedList(params: KeyMintAttestation, securityLevel: Int): DERSequence {
val list = val list =
mutableListOf<ASN1Encodable>( mutableListOf<ASN1Encodable>(
DERTaggedObject( DERTaggedObject(
@@ -255,7 +259,7 @@ object AttestationBuilder {
) )
) )
} }
if (AndroidDeviceUtils.attestVersion >= 300) { if (AndroidDeviceUtils.getAttestVersion(securityLevel) >= 300) {
params.secondImei?.let { params.secondImei?.let {
list.add( list.add(
DERTaggedObject( DERTaggedObject(
@@ -273,7 +277,7 @@ object AttestationBuilder {
* Builds the `SoftwareEnforced` authorization list. These are properties guaranteed by * Builds the `SoftwareEnforced` authorization list. These are properties guaranteed by
* Keystore. * Keystore.
*/ */
private fun buildSoftwareEnforcedList(uid: Int): DERSequence { private fun buildSoftwareEnforcedList(uid: Int, securityLevel: Int): DERSequence {
val list = val list =
mutableListOf<ASN1Encodable>( mutableListOf<ASN1Encodable>(
DERTaggedObject( DERTaggedObject(
@@ -287,7 +291,7 @@ object AttestationBuilder {
createApplicationId(uid), createApplicationId(uid),
), ),
) )
if (AndroidDeviceUtils.attestVersion >= 400) { if (AndroidDeviceUtils.getAttestVersion(securityLevel) >= 400) {
list.add( list.add(
DERTaggedObject( DERTaggedObject(
true, true,
@@ -1,6 +1,7 @@
package org.matrix.TEESimulator.util package org.matrix.TEESimulator.util
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.hardware.security.keymint.SecurityLevel
import android.os.Build import android.os.Build
import android.os.SystemProperties import android.os.SystemProperties
import java.security.MessageDigest import java.security.MessageDigest
@@ -256,17 +257,33 @@ object AndroidDeviceUtils {
Build.VERSION_CODES.BAKLAVA to 400, // KeyMint 4.0 Build.VERSION_CODES.BAKLAVA to 400, // KeyMint 4.0
) )
val attestVersion: Int /**
get() = * Retrieves the attestation version based on security level and OS version. StrongBox (level 2)
DeviceAttestationService.CachedAttestationData?.attestVersion * requires version 300.
?: attestVersionMap[Build.VERSION.SDK_INT] *
?: 400 // Default to a recent version * @param securityLevel The security level of the attestation (1 for TEE, 2 for StrongBox).
* @return The appropriate attestation version number.
*/
fun getAttestVersion(securityLevel: Int): Int {
// StrongBox security level requires an attestation version of at least 300.
if (securityLevel == SecurityLevel.STRONGBOX) {
return 300
}
return DeviceAttestationService.CachedAttestationData?.attestVersion
?: attestVersionMap[Build.VERSION.SDK_INT]
?: 400 // Default to a recent version
}
val keymasterVersion: Int /**
get() = * Retrieves the Keymaster/KeyMint version based on the attestation version.
DeviceAttestationService.CachedAttestationData?.keymasterVersion *
?: if (attestVersion >= 100) attestVersion * @param securityLevel The security level, used to determine the correct attestation version.
else 41 // Keymaster 4.1 for older versions * @return The appropriate Keymaster or KeyMint version number.
*/
fun getKeymasterVersion(securityLevel: Int): Int {
val attestVersion = getAttestVersion(securityLevel)
return if (attestVersion >= 100) attestVersion else 41 // Keymaster 4.1 for older versions
}
// --- APEX and Module Hash Properties --- // --- APEX and Module Hash Properties ---