data class AuthorizationList(val purpose: Set<AttestationValue<AuthorizationList.KeyPurpose>>? = null, val algorithm: AttestationValue<AuthorizationList.Algorithm>? = null, val keySize: AttestationValue<AuthorizationList.KeySize>? = null, val digest: Set<AttestationValue<AuthorizationList.Digest>>? = null, val padding: Set<AttestationValue<AuthorizationList.Padding>>? = null, val ecCurve: AttestationValue<AuthorizationList.ECCurve>? = null, val rsaPublicExponent: AttestationValue<AuthorizationList.RsaPublicExponent>? = null, val mgfDigest: Set<AttestationValue<AuthorizationList.MgfDigest>>? = null, val rollbackResistance: AttestationValue<AuthorizationList.RollbackResistance>? = null, val earlyBootOnly: AttestationValue<AuthorizationList.EarlyBootOnly>? = null, val activeDateTime: AttestationValue<AuthorizationList.ActiveDateTime>? = null, val originationExpireDateTime: AttestationValue<AuthorizationList.OriginationExpireDateTime>? = null, val usageExpireDateTime: AttestationValue<AuthorizationList.UsageExpireDateTime>? = null, val usageCountLimit: AttestationValue<AuthorizationList.UsageCountLimit>? = null, val noAuthRequired: AttestationValue<AuthorizationList.NoAuthRequired>? = null, val userAuthType: AttestationValue<AuthorizationList.UserAuthType>? = null, val authTimeout: AttestationValue<AuthorizationList.AuthTimeout>? = null, val allowWhileOnBody: AttestationValue<AuthorizationList.AllowWhileOnBody>? = null, val trustedUserPresenceRequired: AttestationValue<AuthorizationList.TrustedUserPresenceRequired>? = null, val trustedConfirmationRequired: AttestationValue<AuthorizationList.TrustedConfirmationRequired>? = null, val unlockedDeviceRequired: AttestationValue<AuthorizationList.UnlockedDeviceRequired>? = null, val allApplications: AttestationValue<AuthorizationList.AllApplications>? = null, val creationDateTime: AttestationValue<AuthorizationList.CreationDateTime>? = null, val origin: AttestationValue<AuthorizationList.Origin>? = null, val rollbackResistant: AttestationValue<AuthorizationList.RollbackResistent>? = null, val rootOfTrust: AttestationValue<AuthorizationList.RootOfTrust>? = null, val osVersion: AttestationValue<AuthorizationList.OsVersion>? = null, val osPatchLevel: AttestationValue<AuthorizationList.OsPatchLevel>? = null, val attestationApplicationId: AttestationValue<AuthorizationList.AttestationApplicationId>? = null, val attestationIdBrand: AttestationValue<AuthorizationList.AttestationId.Brand>? = null, val attestationIdDevice: AttestationValue<AuthorizationList.AttestationId.Device>? = null, val attestationIdProduct: AttestationValue<AuthorizationList.AttestationId.Product>? = null, val attestationIdSerial: AttestationValue<AuthorizationList.AttestationId.Serial>? = null, val attestationIdImei: AttestationValue<AuthorizationList.AttestationId.Imei>? = null, val attestationIdMeid: AttestationValue<AuthorizationList.AttestationId.Meid>? = null, val attestationIdManufacturer: AttestationValue<AuthorizationList.AttestationId.Manufacturer>? = null, val attestationIdModel: AttestationValue<AuthorizationList.AttestationId.Model>? = null, val vendorPatchLevel: AttestationValue<AuthorizationList.PatchLevel.Vendor>? = null, val bootPatchLevel: AttestationValue<AuthorizationList.PatchLevel.Boot>? = null, val deviceUniqueAttestation: AttestationValue<AuthorizationList.DeviceUniqueAttestation>? = null, val attestationIdSecondImei: AttestationValue<AuthorizationList.AttestationId.SecondImei>? = null, val moduleHash: AttestationValue<AuthorizationList.ModuleHash>? = null, val attestationVersion: Int? = null) :
Asn1Encodable<Asn1Sequence> ,
PrettyPrintable(source) Intro
Authorization List ASN.1 sequence as defined by Google. Enum values as in the keymint definitions This is the meat of the AttestationKeyDescription attestation certificate extension. It is also used for secure key import.
Every value is nullable because two authorization lists are present in an attestation extension: once for software-enforced values, and once for hardware-enforced value. The actual values are scattered across both instances.
On Parsing
Parsing is lenient: If a value fails to parse, it is set to null. In reality, you won't care whether a value is structurally illegal or absent:
If you want to enforce it, it must be present and structurally valid, fulfilling your constraints
If you don't care for it, you don't care whether it is present, invalid, or absent altogether In case you still want to explore the raw value, check the raw ASN.1 Sequence from the certificate extension and fetch the raw value according to the explicit tag denoting said value.
Structural Properties and Design Decisions
Structurally, this data structure follows the ASN.1 schema exactly, meaning that it is a structural 1:1 mapping if the underlying ASN.1 structure. This as both advantages and disadvantages. The main disadvantage is that it is a bit cumbersome to use. The benefits far outweigh the shortcomings of this approach, though:
Just check the schema, and you know what's what. That means that there are no booleans, but an object indicating true or false is either present or absent
Re-Encoding produces the exact same ASN.1 structure that was parsed, byte-for-byte!
Creating Attestation statements for testing, fun, profit, or malicious intentions is a peak no-brainer; just follow the schema and set values!
Closing Remarks
Note that values found in header files as the one below conform with (autogenerated from?) the aidl files https://android.googlesource.com/platform/hardware/libhardware/+/refs/heads/main/include_all/hardware/keymaster_defs.h
Also note that some online sources do not match the specified ASN.1 values (in the following one PKCS7 has value 65 instead of 64) https://android.googlesource.com/platform/frameworks/base/+blame/45ff13e/core/java/android/security/keymaster/KeymasterDefs.java