Skip to content

baseid-mdl

The mdl crate implements the ISO/IEC 18013-5 mobile driving licence format, providing CBOR-encoded mdoc documents, Mobile Security Object (MSO) digest verification, COSE_Sign1 signing, and selective disclosure through the unified credential lifecycle traits.

  • mdoc CBOR encodingMobileDocument with namespaced DataElement entries, serializable to/from CBOR via ciborium
  • Mobile Security ObjectMobileSecurityObject computes SHA-256 digests of each data element and verifies integrity, supporting selective disclosure of element subsets
  • COSE_Sign1 signaturessign_mso / verify_signed_mso wrap MSOs in COSE_Sign1 envelopes using Ed25519, P-256, P-384, or secp256k1
  • Selective disclosure — present a subset of data elements while preserving MSO verification; omitted elements are simply not included
  • Lifecycle traitsMdocLifecycle implements CredentialIssuer, CredentialVerifier, and CredentialPresenter from baseid-core
  • Device authenticationDeviceAuth and ReaderAuth structures for device signature/MAC and reader certificate verification
use baseid_mdl::mdoc::{MobileDocument, DataElement};
use baseid_mdl::mso::{MobileSecurityObject, ValidityInfo};
use baseid_mdl::cose::{sign_mso, verify_signed_mso};
use baseid_crypto::KeyPair;
use baseid_core::types::KeyType;
use std::collections::BTreeMap;
// 1. Build an mdoc
let mut namespaces = BTreeMap::new();
namespaces.insert("org.iso.18013.5.1".to_string(), vec![
DataElement { identifier: "family_name".into(), value: serde_json::json!("Doe") },
DataElement { identifier: "given_name".into(), value: serde_json::json!("John") },
DataElement { identifier: "document_number".into(), value: serde_json::json!("DL-123456") },
]);
let doc = MobileDocument {
doc_type: "org.iso.18013.5.1.mDL".to_string(),
namespaces,
};
// 2. Create MSO with SHA-256 digests
let validity = ValidityInfo {
signed: "2024-01-01T00:00:00Z".into(),
valid_from: "2024-01-01T00:00:00Z".into(),
valid_until: "2025-01-01T00:00:00Z".into(),
};
let mso = MobileSecurityObject::create(&doc, validity)?;
// 3. Sign the MSO with COSE_Sign1
let kp = KeyPair::generate(KeyType::Ed25519)?;
let cose_bytes = sign_mso(&mso, &kp)?;
// 4. Verify and recover the MSO
let recovered = verify_signed_mso(&cose_bytes, &kp.public)?;
assert_eq!(recovered.doc_type, "org.iso.18013.5.1.mDL");

The MdocLifecycle struct provides the unified lifecycle interface using ClaimSet:

use baseid_mdl::lifecycle::MdocLifecycle;
use baseid_core::claims::{ClaimSet, DisclosureSelection};
use baseid_core::lifecycle::{CredentialIssuer, CredentialPresenter, CredentialVerifier, IssuanceOptions};
let lifecycle = MdocLifecycle::new(&signer, &verifier, "org.iso.18013.5.1.mDL");
// Issue
let mut claims = ClaimSet::new();
claims.insert("", "family_name", serde_json::json!("Doe"));
claims.insert("", "given_name", serde_json::json!("John"));
let issued = lifecycle.issue("did:key:issuer", Some("did:key:holder"), &claims, &IssuanceOptions::default())?;
// Selective disclosure -- reveal name, hide document_number
let disclosure = DisclosureSelection::new()
.reveal("family_name")
.reveal("given_name")
.hide("document_number");
let presented = lifecycle.present(&issued.data, &disclosure, &Default::default())?;
// Verify the presentation
let outcome = lifecycle.verify(&presented.data)?;
assert!(outcome.valid);
TypeDescription
MobileDocumentmdoc with doc_type and namespaced DataElement entries
DataElementSingle data element with identifier and value
MobileSecurityObjectSHA-256 digest tree over data elements
ValidityInfoSigned/valid_from/valid_until timestamps
DeviceAuthDevice signature or MAC for mDL presentation
ReaderAuthReader certificate and signature for reader authentication
MdocLifecycleImplements CredentialIssuer + CredentialVerifier + CredentialPresenter
  • baseid-mdl-online — ISO 18013-7 online presentation over OID4VP
  • baseid-core — lifecycle traits and ClaimSet used by MdocLifecycle
  • baseid-cryptoSigner/Verifier traits used for COSE_Sign1 operations
  • baseid-haip — HAIP profile that constrains mDL to mso_mdoc format