Structure Overview
An mDOC contains two main signed components: issuerSigned (data from the issuer) and deviceSigned (proof from the holder's device during presentation).
docType
Identifies the document type. For mDL: 'org.iso.18013.5.1.mDL'
issuerSigned
Contains namespaces with signed data elements and the MSO (issuer's signature).
deviceSigned
Added during presentation. Contains device authentication proving holder possession.
nameSpaces
Organizes data elements by namespace (standard, jurisdiction-specific, custom).
Namespaces
Namespaces group related data elements and allow for standardized as well as custom extensions. Each namespace contains an array of IssuerSignedItems.
Contains the core mDL data elements defined by ISO 18013-5: name, birth date, portrait, driving privileges, age attestations, etc.
US-specific extensions for domestic driving privileges, name suffixes, organ donor status, veteran indicator, etc.
Issuers can define custom namespaces for additional data. Should use reverse domain notation (e.g., "com.example.myapp").
Standard mDL Data Elements
The org.iso.18013.5.1 namespace defines these standard data elements. Only a subset is required; most are optional.
| Element | Type | Description |
|---|---|---|
| family_name | tstr | Last name / surname |
| given_name | tstr | First name |
| birth_date | full-date | Date of birth (tag 1004) |
| issue_date | full-date | Date credential was issued |
| expiry_date | full-date | Date credential expires |
| issuing_country | tstr | ISO 3166-1 alpha-2 country code |
| issuing_authority | tstr | Name of issuing authority |
| document_number | tstr | License number |
| portrait | bstr | Photo (JPEG or JPEG2000) |
| driving_privileges | array | Array of vehicle categories |
| age_over_18 | bool | Is holder 18 or older? |
| age_over_21 | bool | Is holder 21 or older? |
IssuerSignedItem
Each data element is wrapped in an IssuerSignedItem structure that includes a random salt for privacy and a digestID that links to the MSO.
IssuerSignedItem = {
"digestID": 0, // uint - index in MSO digest array
"random": h'...', // bstr - salt for privacy
"elementIdentifier": "given_name", // tstr
"elementValue": "Alice" // any CBOR value
}
// The hash of this item appears in the MSO
// Hash = SHA-256(CBOR(IssuerSignedItem))digestID
Index into the MSO's valueDigests array. Links this item to its hash in the signed MSO.
random
Random bytes (salt) that make each hash unique, enabling selective disclosure without revealing other elements.
elementIdentifier
The name of the data element (e.g., "given_name", "birth_date").
elementValue
The actual value. Can be any CBOR data type (string, int, date, bytes, etc.).
Selective Disclosure via Salted Hashes
The MSO contains only the hashes of IssuerSignedItems. During presentation, the holder includes only the items they want to disclose. The verifier:
- 1. Receives IssuerSignedItems from holder
- 2. Computes hash of each IssuerSignedItem
- 3. Looks up digestID in MSO's valueDigests
- 4. Confirms computed hash matches MSO hash
DeviceResponse Structure
When presenting an mDOC, the wallet creates a DeviceResponse containing the selected elements from issuerSigned plus deviceSigned authentication.
DeviceResponse = {
"version": "1.0",
"documents": [
{
"docType": "org.iso.18013.5.1.mDL",
"issuerSigned": {
"nameSpaces": {
"org.iso.18013.5.1": [
// IssuerSignedItem for each disclosed claim
24(<< IssuerSignedItem >>),
24(<< IssuerSignedItem >>),
...
]
},
"issuerAuth": // COSE_Sign1 containing MSO
},
"deviceSigned": {
"nameSpaces": 24(<< {} >>), // Optional device-added claims
"deviceAuth": {
"deviceSignature": // COSE_Sign1 or
"deviceMac": // COSE_Mac0
}
},
"errors": null // Optional error codes
}
],
"status": 0 // 0 = OK
}