Page Summary
-
The Identity Credential library on Android devices securely manages credentials, providing security features for issuers to ensure secure integration.
-
A signed nonce, or "challenge," is used when retrieving the device identity certificate to confirm its recency and prevent replay attacks.
-
Access control profiles allow issuers to define how data within Identity Credential is protected, including specifying user authentication requirements and access limitations.
-
Proof of provisioning verifies that a credential was successfully stored, and issuers should not issue Mobile Security Objects (MSOs) until receiving and verifying it.
-
Mobile Security Objects (MSOs) are used to ensure the integrity and authenticity of mDL data, containing digest values, a device key, validity information, and an issuing authority signature.
Identity Credential
Android devices use the Identity Credential library to securely manage credentials on the device. The Identity Credential library offers a number of security features that should be used by the issuer to ensure their integration with Google is as secure as possible.
Signed Nonce
The Identity Credential library takes a "challenge" (referred to in this API as the nonce) when retrieving the device identity certificate, sent to the issuer in the RegisterDeviceRequest. This nonce is signed and embedded in the attestation extension of the device identity certificate. This allows the issuer to have confidence in the recency of the certificate and attestation, and that it isn't being replayed by a server in the middle of the communications.
Access Control Profiles
Access control profiles are a way for the issuer to specify precisely how they want the data being stored within Identity Credential to be protected. The issuer is able to specify if user authentication is required to access the data element, and how long the user has to perform authentication. Future (not currently supported) use cases of this feature include limiting which readers are able to access the data element. Details on how to format access control profiles can be found in the Credential object format.
Proof of Provisioning
The proof of provisioning object is a way for issuers to know that the credential was successfully stored within Identity Credential. An issuer should not issue MSOs for a credential until they receive and verify the proof of provisioning. This object is documented more in the Identity Credential documentation.
Object Formats
Each of these objects are end-to-end encrypted between the device and the issuer. As a result, Google's servers do not have the capability to normalize these objects, and some of these objects may be in different formats than the rest of the API objects. For example, the Credential is formatted in CBOR rather than JSON, as that is what is expected at the Android level.
Credential
The credential contains the data elements, and how they should be accessed. It
contains two primary objects, provisionedData and accessControlProfiles. The
provisionedData contains all of the namespaces relevant to whatever the
credential type is. For example, for mobile driver's license, this would be
org.iso.18013.5.1 and org.aamva.18013.5.1. The data entries and values
inside of the namespaces specify the relevant access control profiles. This is
done as a list of ids, where the id corresponds to an access control profile in
the accessControlProfiles list. In the example below, the [0] in each data
entry refers to the access control profile with id 0, not index 0.
Below is an example of an unencoded CBOR map data item.
{ "provisionedData": { "org.iso.18013.5.1": [ { "name": "family_name", "value": "Smith", "accessControlProfiles": [ 1 ] }, { "name": "given_name", "value": "Stewart", "accessControlProfiles": [ 1 ] }, { "name": "birth_date", "value": { "tag": 1004, "value": "1965-09-01" }, "accessControlProfiles": [ 1 ] }, { "name": "issue_date", "value": { "tag": 1004, "value": "2022-08-01" }, "accessControlProfiles": [ 1 ] }, { "name": "expiry_date", "value": { "tag": 1004, "value": "2027-08-01" }, "accessControlProfiles": [ 1 ] }, { "name": "issuing_authority", "value": "IA", "accessControlProfiles": [ 1 ] }, { "name": "issuing_country", "value": "US", "accessControlProfiles": [ 1 ] }, { "name": "document_number", "value": "D04320785", "accessControlProfiles": [ 1 ] }, { "name": "portrait", "value": { "type": "Buffer", "data": [ 167, 30, 148, 218, 204, 75, 112, 162, 138, 40, 52, 63, 255 ] }, "accessControlProfiles": [ 1 ] }, { "name": "un_distinguishing_sign", "value": "USA", "accessControlProfiles": [ 1 ] }, { "name": "driving_privileges", "value": [ { "expiry_date": { "tag": 1004, "value": "2027-08-01" }, "issue_date": { "tag": 1004, "value": "2022-08-01" }, "vehicle_category_code": "B" } ], "accessControlProfiles": [ 1 ] }, { "name": "sex", "value": 1, "accessControlProfiles": [ 1 ] }, { "name": "height", "value": 170, "accessControlProfiles": [ 1 ] }, { "name": "weight", "value": 79, "accessControlProfiles": [ 1 ] }, { "name": "eye_colour", "value": "Blue", "accessControlProfiles": [ 1 ] }, { "name": "hair_colour", "value": "Gray", "accessControlProfiles": [ 1 ] }, { "name": "age_in_years", "value": 57, "accessControlProfiles": [ 1 ] }, { "name": "age_over_18", "value": true, "accessControlProfiles": [ 1 ] }, { "name": "age_over_21", "value": true, "accessControlProfiles": [ 1 ] }, { "name": "resident_address", "value": "1600 Amphitheatre Pkwy ", "accessControlProfiles": [ 1 ] }, { "name": "issuing_jurisdiction", "value": "US-CA", "accessControlProfiles": [ 1 ] }, { "name": "resident_city", "value": "Mountain View", "accessControlProfiles": [ 1 ] }, { "name": "resident_state", "value": "CA", "accessControlProfiles": [ 1 ] }, { "name": "resident_postal_code", "value": "94043", "accessControlProfiles": [ 1 ] }, { "name": "resident_country", "value": "US", "accessControlProfiles": [ 1 ] } ], "org.iso.18013.5.1.aamva": [ { "name": "DHS_compliance", "value": "F", "accessControlProfiles": [ 1 ] }, { "name": "domestic_driving_privileges", "value": [ { "domestic_vehicle_class": { "domestic_vehicle_class_code": "D", "domestic_vehicle_class_description": "Operator", "expiry_date": { "tag": 1004, "value": "2027-08-01" }, "issue_date": { "tag": 1004, "value": "2022-08-01" } }, "domestic_vehicle_restrictions": [ { "domestic_vehicle_restriction_code": "B", "domestic_vehicle_restriction_description": "Corrective lenses (also automated - vision screening)" } ] } ], "accessControlProfiles": [ 1 ] }, { "name": "aamva_version", "value": "1", "accessControlProfiles": [ 1 ] }, { "name": "family_name_truncation", "value": "N", "accessControlProfiles": [ 1 ] }, { "name": "given_name_truncation", "value": "N", "accessControlProfiles": [ 1 ] }, { "name": "organ_donor", "value": true, "accessControlProfiles": [ 1 ] } ] }, "accessControlProfiles": [ { "id": 1, "userAuthenticationRequired": true, "timeoutMillis": 10000 } ] }
This object should then be encoded in the CBOR format, encrypted, and then base64 encoded. If in the test environment, and the data is not being encrypted, it should be encoded in the CBOR format, and then base64 encoded.
Note that the above example is an unencoded CBOR map, not JSON. If a JSON string is encoded into CBOR, it will not be correctly parsed by the Android device.
Mobile Security Objects
ISO/IEC 18013-5 defines a Mobile Security Object (MSO) to ensure that the mDL data is not tampered with and that it was issued by a trusted authority.
MSO contains the following:
- Digest values: These are unique values that are generated for each data element in the mDL Credential. They are used to verify that the data has not been changed since the MSO was signed.
- Device key: This is a unique key that is generated for each mobile device that stores the Credential. It is used to bind the MSO to the device and to prevent it from being used on other devices.
- Validity information: This includes the start and end dates for which the MSO is valid.
- IA signature: This is a digital signature that is created by the Issuing Authority (IA) using its private key. It is used to verify that the MSO was issued by a trusted authority.
MSO has the following CCDL structure:
MobileSecurityObjectBytes = #6.24(bstr .cbor MobileSecurityObject)
MobileSecurityObject = {
"digestAlgorithm" : tstr, ; Message digest algorithm used
"valueDigests" : ValueDigests, ; Array of digests of all data elements
"deviceKeyInfo" : DeviceKeyInfo,
"docType" : tstr, ; DocType as used in Documents
"validityInfo" : ValidityInfo
}
DeviceKeyInfo = {
"deviceKey" : DeviceKey
? "keyAuthorizations" : KeyAuthorizations,
? "keyInfo" : KeyInfo
}
DeviceKey = COSE_Key ; Device key in COSE_Key as defined in RFC 8152
KeyAuthorizations = {
? "nameSpaces" : AuthorizedNameSpaces
? "dataElements" : AuthorizedDataElements
}
AuthorizedNameSpaces = [+ NameSpace]
AuthorizedDataElements = {+ NameSpace => DataElementsArray}
DataElementsArray = [+ DataElementIdentifier]
KeyInfo = { * int => any} ; Positive integers are RFU, negative integers may be used for proprietary use
ValueDigests = {
"nameSpaces" : NameSpacesDigests
}
NameSpacesDigests = {
+ NameSpace => DigestIDs
}
DigestIDs = {
+ DigestID => Digest
}
ValidityInfo = {
"signed" : tdate,
"validFrom" : tdate,
"validUntil" : tdate,
? "expectedUpdate" : tdate
}
NameSpace = tstr ; NameSpace as used in IssuerSigned
DigestID = uint ; DigestID as used in IssuerSigStatic Auth Data
The Static Auth Data, which comprises both the
digestIdMapping and the issuerAuth, should be constructed by the issuer.
The digestIdMapping for a specific namespace consists of an array of
IssuerSignedItem instances, each with a null value for the elementValue property.
Additionally, the issuerAuth is generated by signing the
MobileSecurityObjectBytes using COSE_Sign1.
StaticAuthDataBytes = (bstr .cbor StaticAuthData) StaticAuthData = { "digestIdMapping" : DigestIdMapping, "issuerAuth" : IssuerAuth } DigestIdMapping = { NameSpace => [ + IssuerSignedItemBytes ] } ; Defined in ISO 18013-5 ; NameSpace = String DataElementIdentifier = String DigestID = uint IssuerAuth = COSE_Sign1 ; The payload is MobileSecurityObjectBytes IssuerSignedItemBytes = #6.24(bstr .cbor IssuerSignedItem) IssuerSignedItem = { "digestID" : uint, ; Digest ID for issuer data auth "random" : bstr, ; Random value for issuer data auth "elementIdentifier" : DataElementIdentifier, ; Data element identifier "elementValue" : DataElementValue ; Data element value }
Upon invocation of the /provisionMobileSecurityObjects
endpoint, the StaticAuthDataBytes is encrypted using HPKE, and transmitted
as part of the response.
Here's a
code sample
for constructing MSOs and Static Auth Data.