Skip to content
This repository has been archived by the owner on Dec 13, 2023. It is now read-only.
/ waltid-mdoc Public archive

Kotlin Multiplatform mdoc library (ISO/IEC 18013-5:2021)

License

Notifications You must be signed in to change notification settings

walt-id/waltid-mdoc

Repository files navigation

[moved]

The new repo can be found here.

Kotlin Multiplatform mdoc library

by walt.id

Create credentials in mdoc format according to ISO/IEC 18013-5:2021 standard

CI/CD workflow for the walt.id mdoc Lib

Join community! Follow @walt_id

Getting Started

What is the mdoc library

This library implements the mdoc specification: ISO/IEC 18013-5:2021, Personal identification -- ISO-compliant driving licence -- Part 5: Mobile driving licence (mDL) application.

Features

  • Parse and verify mdocs and mdoc requests, with verification of MSO-validity, doc type, certificate chains, items tamper check, issuer and device signatures.
  • Create and sign mdoc documents with issuer-signed items and COSE Sign1 issuer authentication (mobile security object, MSO).
  • Present mdoc documents with selective disclosure of issuer-signed items and mdoc device authentication, based on COSE Mac0 or COSE Sign1.
  • Create mdoc requests object with COSE Sign1 reader authentication
  • Support for integration with various crypto libraries and frameworks, to perform the cryptographic operations and key management
  • Multiplatform support
    • Kotlin/Java for JVM
    • JavaScript
    • Native

Usage with Maven or Gradle (JVM)

Maven / Gradle repository:

https://maven.walt.id/repository/waltid/

Maven

[...]
<repositories>
  <repository>
    <id>waltid</id>
    <name>walt.id</name>
    <url>https://maven.walt.id/repository/waltid/</url>
  </repository>
</repositories>
[...]
<dependency>
    <groupId>id.walt</groupId>
    <artifactId>waltid-mdoc-jvm</artifactId>
    <version>[ version ]</version>
</dependency>

Gradle

Kotlin DSL

[...]
repositories {
  maven("https://maven.walt.id/repository/waltid/")
}
[...]
val mdocVersion = "1.xxx.0"
[...]
dependencies {
  implementation("id.walt:waltid-mdoc-jvm:$mdocVersion")
}

Usage with NPM/NodeJs (JavaScript)

Install NPM package:

npm install waltid-mdoc

Manual build from source:

./gradlew jsNodeProductionLibraryPrepare jsNodeProductionLibraryDistribution

Then include in your NodeJS project like this:

npm install /path/to/waltid-mdoc/build/productionLibrary

NodeJS example

Example script in:

examples/js

Execute like:

npm install
node index.js

Examples

Kotlin / JVM

Issue an mDL document to a holder

// instantiate simple cose crypto provider for issuer keys and certificates
val cryptoProvider = SimpleCOSECryptoProvider(
  listOf(
    COSECryptoProviderKeyInfo(ISSUER_KEY_ID, AlgorithmID.ECDSA_256, issuerKeyPair.public, issuerKeyPair.private, listOf(issuerCertificate), listOf(caCertificate)),
    COSECryptoProviderKeyInfo(DEVICE_KEY_ID, AlgorithmID.ECDSA_256, deviceKeyPair.public, deviceKeyPair.private)
  )
)
// create device key info structure of device public key, for holder binding
val deviceKeyInfo = DeviceKeyInfo(DataElement.fromCBOR(OneKey(deviceKeyPair.public, null).AsCBOR().EncodeToBytes()))

// build mdoc and sign using issuer key with holder binding to device key
val mdoc = MDocBuilder("org.iso.18013.5.1.mDL")
  .addItemToSign("org.iso.18013.5.1", "family_name", "Doe".toDE())
  .addItemToSign("org.iso.18013.5.1", "given_name", "John".toDE())
  .addItemToSign("org.iso.18013.5.1", "birth_date", FullDateElement(LocalDate(1990, 1, 15)))
  .sign(ValidityInfo(Clock.System.now(), Clock.System.now(), Clock.System.now().plus(365*24, DateTimeUnit.HOUR)),
    deviceKeyInfo, cryptoProvider, ISSUER_KEY_ID
  )
println("SIGNED MDOC:")
println(Cbor.encodeToHexString(mdoc))

Example output

SIGNED MDOC:
a267646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d65537061636573a1716f72672e69736f2e31383031332e352e3183d8185852a4686469676573744944006672616e646f6d501d5a0b315468e8e741c7d0fbf2267ea671656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456616c756563446f65d8185852a4686469676573744944016672616e646f6d505a212f6b1afa24c80fdf756859b6e0e571656c656d656e744964656e7469666965726a676976656e5f6e616d656c656c656d656e7456616c7565644a6f686ed818585ba4686469676573744944026672616e646f6d50595961fbb375b6330e60016e33e3caa471656c656d656e744964656e7469666965726a62697274685f646174656c656c656d656e7456616c7565d903ec6a313939302d30312d31356a697373756572417574688443a10126a1182159014b308201473081eea00302010202085851077f1cb3d768300a06082a8648ce3d04030230173115301306035504030c0c4d444f432054657374204341301e170d3233303830323136323231395a170d3233303830333136323231395a301b3119301706035504030c104d444f432054657374204973737565723059301306072a8648ce3d020106082a8648ce3d030107034200045f1c8ff18cb0b57445f16eec0584fcf69a6829d955a3284fa42e4d091f6da49196f5b9c917a39ecbf2bf7cdd06597169433c1d9cde0a9ee9772bd29b12fcb775a320301e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780300a06082a8648ce3d0403020348003045022075e093d7e7128060f42ca9a675b97c6312c46cbecd23afdbe8619e964eab37e2022100d9b522c7b80f93dd978a955d0ffdb5f64dc40fa9aa1aa6e10902b306821d13ed5901c3d8185901bea66776657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c756544696765737473a1716f72672e69736f2e31383031332e352e31a3005820534172b2a1e4082a7644b42299271711891b29adfd50b10a18524e8827d308ae0158204892baa76842258533af9eac579397d024cbff8536afda2da2b9c62a4b30704102582002fc10a9f125740b67e29264cd03ba4994a56f3377c62344d092c614cc18bdb06d6465766963654b6579496e666fa1696465766963654b6579a401022001215820f2862d595d95758368138cb90e3c0df01a432ce1f569ea0d26e80351cf6d0425225820fd20afda5943e95dbd6c679fe1ffb425ec92a65bfcfa2c2c1882669d3bed737267646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c76616c6964697479496e666fa3667369676e6564c0781e323032332d30382d30325431363a32323a31392e3235323531363736395a6976616c696446726f6dc0781e323032332d30382d30325431363a32323a31392e3235323531393730355a6a76616c6964556e74696cc0781e323032342d30382d30315431363a32323a31392e3235323532303435375a5840a59ce0142b6943b26da7a79a71167ab459702d4231a46990d573445034abee6fe275582686a71ab37fed5a6a0819c740bb79f6e24e7786022db07c7469cb1d09
View in diagnostic notation
{
  "docType": "org.iso.18013.5.1.mDL",
  "issuerSigned": {
    "nameSpaces": {
      "org.iso.18013.5.1": [
        24(<< {
          "digestID": 0,
          "random": h'1D5A0B315468E8E741C7D0FBF2267EA6',
          "elementIdentifier": "family_name",
          "elementValue": "Doe"
        } >>),
        24(<< {
          "digestID": 1,
          "random": h'5A212F6B1AFA24C80FDF756859B6E0E5',
          "elementIdentifier": "given_name",
          "elementValue": "John"
        } >>),
        24(<< {
          "digestID": 2,
          "random": h'595961FBB375B6330E60016E33E3CAA4',
          "elementIdentifier": "birth_date",
          "elementValue": 1004("1990-01-15")
        } >>)
      ]
    },
    "issuerAuth": [<< {
        1: -7
      } >>,
      {
        33: h'308201473081EEA00302010202085851077F1CB3D768300A06082A8648CE3D04030230173115301306035504030C0C4D444F432054657374204341301E170D3233303830323136323231395A170D3233303830333136323231395A301B3119301706035504030C104D444F432054657374204973737565723059301306072A8648CE3D020106082A8648CE3D030107034200045F1C8FF18CB0B57445F16EEC0584FCF69A6829D955A3284FA42E4D091F6DA49196F5B9C917A39ECBF2BF7CDD06597169433C1D9CDE0A9EE9772BD29B12FCB775A320301E300C0603551D130101FF04023000300E0603551D0F0101FF040403020780300A06082A8648CE3D0403020348003045022075E093D7E7128060F42CA9A675B97C6312C46CBECD23AFDBE8619E964EAB37E2022100D9B522C7B80F93DD978A955D0FFDB5F64DC40FA9AA1AA6E10902B306821D13ED'
      }, << 24(<< {
        "version": "1.0",
        "digestAlgorithm": "SHA-256",
        "valueDigests": {
          "org.iso.18013.5.1": {
            0: h'534172B2A1E4082A7644B42299271711891B29ADFD50B10A18524E8827D308AE',
            1: h'4892BAA76842258533AF9EAC579397D024CBFF8536AFDA2DA2B9C62A4B307041',
            2: h'02FC10A9F125740B67E29264CD03BA4994A56F3377C62344D092C614CC18BDB0'
          }
        },
        "deviceKeyInfo": {
          "deviceKey": {
            1: 2,
            -1: 1,
            -2: h'F2862D595D95758368138CB90E3C0DF01A432CE1F569EA0D26E80351CF6D0425',
            -3: h'FD20AFDA5943E95DBD6C679FE1FFB425EC92A65BFCFA2C2C1882669D3BED7372'
          }
        },
        "docType": "org.iso.18013.5.1.mDL",
        "validityInfo": {
          "signed": 0("2023-08-02T16:22:19.252516769Z"),
          "validFrom": 0("2023-08-02T16:22:19.252519705Z"),
          "validUntil": 0("2024-08-01T16:22:19.252520457Z")
        }
      } >>) >>, h'A59CE0142B6943B26DA7A79A71167AB459702D4231A46990D573445034ABEE6FE275582686A71AB37FED5A6A0819C740BB79F6E24E7786022DB07C7469CB1D09'
    ]
  }
}

Create, parse and verify a mdoc (mDL) request

val cryptoProvider = SimpleCOSECryptoProvider(listOf(
  COSECryptoProviderKeyInfo(READER_KEY_ID, AlgorithmID.ECDSA_256, readerKeyPair.public, readerKeyPair.private)
))
val sessionTranscript = ListElement(/*... create session transcript according to ISO/IEC FDIS 18013-5, section 9.1.5.1 ...*/)

val docReq = MDocRequestBuilder("org.iso.18013.5.1.mDL")
  .addDataElementRequest("org.iso.18013.5.1", "family_name", true)
  .addDataElementRequest("org.iso.18013.5.1", "birth_date", false)
  .sign(sessionTranscript, cryptoProvider, READER_KEY_ID)

val deviceRequest = DeviceRequest(listOf(docReq))
var devReqCbor = deviceRequest.toCBORHex()
println("DEVICE REQUEST: $devReqCbor")

val parsedReq = DeviceRequest.fromCBORHex(devReqCbor)
val firstParsedDocRequest = parsedReq.docRequests.first()
val reqVerified = firstParsedDocRequest.verify(
  MDocRequestVerificationParams(
    requiresReaderAuth = true,
    READER_KEY_ID,
    allowedToRetain = mapOf("org.iso.18013.5.1" to setOf("family_name")),
    ReaderAuthentication(sessionTranscript, firstParsedDocRequest.itemsRequest)
  ), cryptoProvider
)
println("Request verified: $reqVerified")
println("Requested doc type: ${firstParsedDocRequest.docType}")
println("Requested items:")
firstParsedDocRequest.nameSpaces.forEach { ns ->
  println("- NameSpace: $ns")
  firstParsedDocRequest.getRequestedItemsFor(ns).forEach {
    println("-- ${it.key} (intent-to-retain: ${it.value})")
  }
}

Example output:

DEVICE REQUEST: a26776657273696f6e63312e306b646f63526571756573747381a26c6974656d7352657175657374d8185857a267646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6a6e616d65537061636573a1716f72672e69736f2e31383031332e352e31a26b66616d696c795f6e616d65f56a62697274685f64617465f46a726561646572417574688443a10126a11821f6f65840d52b28bbd50252ea93181d9bbcb5b01cbeb11ae442a05bf839dcc3fb9dc6cb92c6fc5eaed6b430ee19a111a1678f2ea959cd8232c6c9828101016caffd3de771
Request verified: true
Requested doc type: org.iso.18013.5.1.mDL
Requested items:
- NameSpace: org.iso.18013.5.1
-- family_name (intent-to-retain: true)
-- birth_date (intent-to-retain: false)
View in diagnostic notation
{
  "version": "1.0",
  "docRequests": [
    {
      "itemsRequest": 24(<< {
      "docType": "org.iso.18013.5.1.mDL",
      "nameSpaces": {
        "org.iso.18013.5.1": {
          "family_name": true,
          "birth_date": false
        }
      }
    } >>),
    "readerAuth": [<< {
      1: -7
    } >>,
      {
        33: null
      },
      null, h'D52B28BBD50252EA93181D9BBCB5B01CBEB11AE442A05BF839DCC3FB9DC6CB92C6FC5EAED6B430EE19A111A1678F2EA959CD8232C6C9828101016CAFFD3DE771'
    ]
  }
  ]
}

Present mDL document with selective disclosure, for a given mdoc request

// try deserializing example from ISO/IEC FDIS 18013-5: D.4.1.2 mdoc response
val serializedDoc =
  "a36776657273696f6e63312e3069646f63756d656e747381a367646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d65537061636573a1716f72672e69736f2e31383031332e352e3186d8185863a4686469676573744944006672616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e971656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456616c756563446f65d818586ca4686469676573744944036672616e646f6d5820b23f627e8999c706df0c0a4ed98ad74af988af619b4bb078b89058553f44615d71656c656d656e744964656e7469666965726a69737375655f646174656c656c656d656e7456616c7565d903ec6a323031392d31302d3230d818586da4686469676573744944046672616e646f6d5820c7ffa307e5de921e67ba5878094787e8807ac8e7b5b3932d2ce80f00f3e9abaf71656c656d656e744964656e7469666965726b6578706972795f646174656c656c656d656e7456616c7565d903ec6a323032342d31302d3230d818586da4686469676573744944076672616e646f6d582026052a42e5880557a806c1459af3fb7eb505d3781566329d0b604b845b5f9e6871656c656d656e744964656e7469666965726f646f63756d656e745f6e756d6265726c656c656d656e7456616c756569313233343536373839d818590471a4686469676573744944086672616e646f6d5820d094dad764a2eb9deb5210e9d899643efbd1d069cc311d3295516ca0b024412d71656c656d656e744964656e74696669657268706f7274726169746c656c656d656e7456616c7565590412ffd8ffe000104a46494600010101009000900000ffdb004300130d0e110e0c13110f11151413171d301f1d1a1a1d3a2a2c2330453d4947443d43414c566d5d4c51685241435f82606871757b7c7b4a5c869085778f6d787b76ffdb0043011415151d191d381f1f38764f434f7676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676767676ffc00011080018006403012200021101031101ffc4001b00000301000301000000000000000000000005060401020307ffc400321000010303030205020309000000000000010203040005110612211331141551617122410781a1163542527391b2c1f1ffc4001501010100000000000000000000000000000001ffc4001a110101010003010000000000000000000000014111213161ffda000c03010002110311003f00a5bbde22da2329c7d692bc7d0d03f52cfb0ff75e7a7ef3e7709723a1d0dae146ddfbb3c039ce07ad2bd47a7e32dbb8dd1d52d6ef4b284f64a480067dfb51f87ffb95ff00eb9ff14d215de66af089ce44b7dbde9cb6890a2838eddf18078f7add62d411ef4db9b10a65d6b95a147381ea0d495b933275fe6bba75c114104a8ba410413e983dff004f5af5d34b4b4cde632d0bf1fd1592bdd91c6411f3934c2fa6af6b54975d106dcf4a65ae56e856001ebc03c7ce29dd9eef1ef10fc447dc9da76ad2aee93537a1ba7e4f70dd8eff0057c6dffb5e1a19854a83758e54528750946ec6704850cd037bceb08b6d7d2cc76d3317fc7b5cc04fb6707269c5c6e0c5b60ae549242123b0e493f602a075559e359970d98db89525456b51c951c8afa13ea8e98e3c596836783d5c63f5a61a99fdb7290875db4be88ab384bbbbbfc7183fdeaa633e8951db7da396dc48524fb1a8bd611a5aa2a2432f30ab420a7a6d3240c718cf031fa9ef4c9ad550205aa02951df4a1d6c8421b015b769db8c9229837ea2be8b1b0d39d0eba9c51484efdb8c0efd8d258daf3c449699f2edbd4584e7af9c64e3f96b9beb28d4ac40931e6478c8e76a24a825449501d867d2b1dcdebae99b9c752ae4ecd6dde4a179c1c1e460938f9149ef655e515c03919a289cb3dca278fb7bf177f4faa829dd8ce3f2ac9a7ecde490971fafd7dce15eed9b71c018c64fa514514b24e8e4f8c5c9b75c1e82579dc1233dfec08238f6add62d391acc1c5256a79e706d52d431c7a0145140b9fd149eb3a60dc5e88cbbc2da092411e9dc71f39a7766b447b344e847dcac9dcb5abba8d145061d43a6fcf1e65cf15d0e90231d3dd9cfe62995c6dcc5ca12a2c904a15f71dd27d451453e09d1a21450961cbb3ea8a956433b781f1ce33dfed54f0e2b50a2b71d84ed6db18028a28175f74fc6bda105c529a791c25c4f3c7a11f71586268f4a66b726e33de9ea6f1b52b181c760724e47b514520a5a28a283ffd9d81858ffa4686469676573744944096672616e646f6d58204599f81beaa2b20bd0ffcc9aa03a6f985befab3f6beaffa41e6354cdb2ab2ce471656c656d656e744964656e7469666965727264726976696e675f70726976696c656765736c656c656d656e7456616c756582a37576656869636c655f63617465676f72795f636f646561416a69737375655f64617465d903ec6a323031382d30382d30396b6578706972795f64617465d903ec6a323032342d31302d3230a37576656869636c655f63617465676f72795f636f646561426a69737375655f64617465d903ec6a323031372d30322d32336b6578706972795f64617465d903ec6a323032342d31302d32306a697373756572417574688443a10126a118215901f3308201ef30820195a00302010202143c4416eed784f3b413e48f56f075abfa6d87eb84300a06082a8648ce3d04030230233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e170d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004ace7ab7340e5d9648c5a72a9a6f56745c7aad436a03a43efea77b5fa7b88f0197d57d8983e1b37d3a539f4d588365e38cbbf5b94d68c547b5bc8731dcd2f146ba381a83081a5301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e0416041414e29017a6c35621ffc7a686b7b72db06cd12351301f0603551d2304183016801454fa2383a04c28e0d930792261c80c4881d2c00b300e0603551d0f0101ff04040302078030150603551d250101ff040b3009060728818c5d050102300a06082a8648ce3d040302034800304502210097717ab9016740c8d7bcdaa494a62c053bbdecce1383c1aca72ad08dbc04cbb202203bad859c13a63c6d1ad67d814d43e2425caf90d422422c04a8ee0304c0d3a68d5903a2d81859039da66776657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c756544696765737473a2716f72672e69736f2e31383031332e352e31ad00582075167333b47b6c2bfb86eccc1f438cf57af055371ac55e1e359e20f254adcebf01582067e539d6139ebd131aef441b445645dd831b2b375b390ca5ef6279b205ed45710258203394372ddb78053f36d5d869780e61eda313d44a392092ad8e0527a2fbfe55ae0358202e35ad3c4e514bb67b1a9db51ce74e4cb9b7146e41ac52dac9ce86b8613db555045820ea5c3304bb7c4a8dcb51c4c13b65264f845541341342093cca786e058fac2d59055820fae487f68b7a0e87a749774e56e9e1dc3a8ec7b77e490d21f0e1d3475661aa1d0658207d83e507ae77db815de4d803b88555d0511d894c897439f5774056416a1c7533075820f0549a145f1cf75cbeeffa881d4857dd438d627cf32174b1731c4c38e12ca936085820b68c8afcb2aaf7c581411d2877def155be2eb121a42bc9ba5b7312377e068f660958200b3587d1dd0c2a07a35bfb120d99a0abfb5df56865bb7fa15cc8b56a66df6e0c0a5820c98a170cf36e11abb724e98a75a5343dfa2b6ed3df2ecfbb8ef2ee55dd41c8810b5820b57dd036782f7b14c6a30faaaae6ccd5054ce88bdfa51a016ba75eda1edea9480c5820651f8736b18480fe252a03224ea087b5d10ca5485146c67c74ac4ec3112d4c3a746f72672e69736f2e31383031332e352e312e5553a4005820d80b83d25173c484c5640610ff1a31c949c1d934bf4cf7f18d5223b15dd4f21c0158204d80e1e2e4fb246d97895427ce7000bb59bb24c8cd003ecf94bf35bbd2917e340258208b331f3b685bca372e85351a25c9484ab7afcdf0d2233105511f778d98c2f544035820c343af1bd1690715439161aba73702c474abf992b20c9fb55c36a336ebe01a876d6465766963654b6579496e666fa1696465766963654b6579a40102200121582096313d6c63e24e3372742bfdb1a33ba2c897dcd68ab8c753e4fbd48dca6b7f9a2258201fb3269edd418857de1b39a4e4a44b92fa484caa722c228288f01d0c03a2c3d667646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c6964556e74696cc074323032312d31302d30315431333a33303a30325a584059e64205df1e2f708dd6db0847aed79fc7c0201d80fa55badcaf2e1bcf5902e1e5a62e4832044b890ad85aa53f129134775d733754d7cb7a413766aeff13cb2e6c6465766963655369676e6564a26a6e616d65537061636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f65820e99521a85ad7891b806a07f8b5388a332d92c189a7bf293ee1f543405ae6824d6673746174757300"
val mdocRespParsed = DeviceResponse.fromCBORHex(serializedDoc)
val mdoc = mdocRespParsed.documents[0]

val deviceAuthenticationBytes = Hex.decode("d818590271847444657669636541757468656e7469636174696f6e83d8185858a20063312e30018201d818584ba4010220012158205a88d182bce5f42efa59943f33359d2e8a968ff289d93e5fa444b624343167fe225820b16e8cf858ddc7690407ba61d4c338237a8cfcf3de6aa672fc60a557aa32fc67d818584ba40102200121582060e3392385041f51403051f2415531cb56dd3f999c71687013aac6768bc8187e225820e58deb8fdbe907f7dd5368245551a34796f7d2215c440c339bb0f7b67beccdfa8258c391020f487315d10209616301013001046d646f631a200c016170706c69636174696f6e2f766e642e626c7565746f6f74682e6c652e6f6f6230081b28128b37282801021c015c1e580469736f2e6f72673a31383031333a646576696365656e676167656d656e746d646f63a20063312e30018201d818584ba4010220012158205a88d182bce5f42efa59943f33359d2e8a968ff289d93e5fa444b624343167fe225820b16e8cf858ddc7690407ba61d4c338237a8cfcf3de6aa672fc60a557aa32fc6758cd91022548721591020263720102110204616301013000110206616301036e6663005102046163010157001a201e016170706c69636174696f6e2f766e642e626c7565746f6f74682e6c652e6f6f6230081b28078080bf2801021c021107c832fff6d26fa0beb34dfcd555d4823a1c11010369736f2e6f72673a31383031333a6e66636e6663015a172b016170706c69636174696f6e2f766e642e7766612e6e616e57030101032302001324fec9a70b97ac9684a4e326176ef5b981c5e8533e5f00298cfccbc35e700a6b020414756f72672e69736f2e31383031332e352e312e6d444cd81841a0")
val deviceAuthentication = DataElement.fromCBOR<EncodedCBORElement>(deviceAuthenticationBytes).decode<DeviceAuthentication>()
val ephemeralMacKey = Hex.decode("dc2b9566fdaaae3c06baa40993cd0451aeba15e7677ef5305f6531f3533c35dd")

val mdocRequest = MDocRequestBuilder(mdoc.docType.value)
  .addDataElementRequest("org.iso.18013.5.1", "family_name", true)
  .addDataElementRequest("org.iso.18013.5.1", "document_number", true)
  .build()

// present with selective disclosure, using device MAC
val presentedMdoc = mdoc.presentWithDeviceMAC(mdocRequest, deviceAuthentication, ephemeralMacKey)
println("Presented MDOC: ${presentedMdoc.toCBORHex()}")

Example Output

Presented MDOC: a367646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d65537061636573a1716f72672e69736f2e31383031332e352e3182d8185863a4686469676573744944006672616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e971656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456616c756563446f65d818586da4686469676573744944076672616e646f6d582026052a42e5880557a806c1459af3fb7eb505d3781566329d0b604b845b5f9e6871656c656d656e744964656e7469666965726f646f63756d656e745f6e756d6265726c656c656d656e7456616c7565693132333435363738396a697373756572417574688443a10126a118215901f3308201ef30820195a00302010202143c4416eed784f3b413e48f56f075abfa6d87eb84300a06082a8648ce3d04030230233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e170d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004ace7ab7340e5d9648c5a72a9a6f56745c7aad436a03a43efea77b5fa7b88f0197d57d8983e1b37d3a539f4d588365e38cbbf5b94d68c547b5bc8731dcd2f146ba381a83081a5301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e0416041414e29017a6c35621ffc7a686b7b72db06cd12351301f0603551d2304183016801454fa2383a04c28e0d930792261c80c4881d2c00b300e0603551d0f0101ff04040302078030150603551d250101ff040b3009060728818c5d050102300a06082a8648ce3d040302034800304502210097717ab9016740c8d7bcdaa494a62c053bbdecce1383c1aca72ad08dbc04cbb202203bad859c13a63c6d1ad67d814d43e2425caf90d422422c04a8ee0304c0d3a68d5903a2d81859039da66776657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c756544696765737473a2716f72672e69736f2e31383031332e352e31ad00582075167333b47b6c2bfb86eccc1f438cf57af055371ac55e1e359e20f254adcebf01582067e539d6139ebd131aef441b445645dd831b2b375b390ca5ef6279b205ed45710258203394372ddb78053f36d5d869780e61eda313d44a392092ad8e0527a2fbfe55ae0358202e35ad3c4e514bb67b1a9db51ce74e4cb9b7146e41ac52dac9ce86b8613db555045820ea5c3304bb7c4a8dcb51c4c13b65264f845541341342093cca786e058fac2d59055820fae487f68b7a0e87a749774e56e9e1dc3a8ec7b77e490d21f0e1d3475661aa1d0658207d83e507ae77db815de4d803b88555d0511d894c897439f5774056416a1c7533075820f0549a145f1cf75cbeeffa881d4857dd438d627cf32174b1731c4c38e12ca936085820b68c8afcb2aaf7c581411d2877def155be2eb121a42bc9ba5b7312377e068f660958200b3587d1dd0c2a07a35bfb120d99a0abfb5df56865bb7fa15cc8b56a66df6e0c0a5820c98a170cf36e11abb724e98a75a5343dfa2b6ed3df2ecfbb8ef2ee55dd41c8810b5820b57dd036782f7b14c6a30faaaae6ccd5054ce88bdfa51a016ba75eda1edea9480c5820651f8736b18480fe252a03224ea087b5d10ca5485146c67c74ac4ec3112d4c3a746f72672e69736f2e31383031332e352e312e5553a4005820d80b83d25173c484c5640610ff1a31c949c1d934bf4cf7f18d5223b15dd4f21c0158204d80e1e2e4fb246d97895427ce7000bb59bb24c8cd003ecf94bf35bbd2917e340258208b331f3b685bca372e85351a25c9484ab7afcdf0d2233105511f778d98c2f544035820c343af1bd1690715439161aba73702c474abf992b20c9fb55c36a336ebe01a876d6465766963654b6579496e666fa1696465766963654b6579a40102200121582096313d6c63e24e3372742bfdb1a33ba2c897dcd68ab8c753e4fbd48dca6b7f9a2258201fb3269edd418857de1b39a4e4a44b92fa484caa722c228288f01d0c03a2c3d667646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c6964556e74696cc074323032312d31302d30315431333a33303a30325a584059e64205df1e2f708dd6db0847aed79fc7c0201d80fa55badcaf2e1bcf5902e1e5a62e4832044b890ad85aa53f129134775d733754d7cb7a413766aeff13cb2e6c6465766963655369676e6564a26a6e616d65537061636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f65820e99521a85ad7891b806a07f8b5388a332d92c189a7bf293ee1f543405ae6824d
View in diagnostic notation
{
  "docType": "org.iso.18013.5.1.mDL",
  "issuerSigned": {
    "nameSpaces": {
      "org.iso.18013.5.1": [
        24(<< {
          "digestID": 0,
          "random": h'8798645B20EA200E19FFABAC92624BEE6AEC63ACEEDECFB1B80077D22BFC20E9',
          "elementIdentifier": "family_name",
          "elementValue": "Doe"
        } >>),
        24(<< {
          "digestID": 7,
          "random": h'26052A42E5880557A806C1459AF3FB7EB505D3781566329D0B604B845B5F9E68',
          "elementIdentifier": "document_number",
          "elementValue": "123456789"
        } >>)
      ]
    },
    "issuerAuth": [<< {
        1: -7
      } >>,
      {
        33: h'308201EF30820195A00302010202143C4416EED784F3B413E48F56F075ABFA6D87EB84300A06082A8648CE3D04030230233114301206035504030C0B75746F7069612069616361310B3009060355040613025553301E170D3230313030313030303030305A170D3231313030313030303030305A30213112301006035504030C0975746F706961206473310B30090603550406130255533059301306072A8648CE3D020106082A8648CE3D03010703420004ACE7AB7340E5D9648C5A72A9A6F56745C7AAD436A03A43EFEA77B5FA7B88F0197D57D8983E1B37D3A539F4D588365E38CBBF5B94D68C547B5BC8731DCD2F146BA381A83081A5301E0603551D120417301581136578616D706C65406578616D706C652E636F6D301C0603551D1F041530133011A00FA00D820B6578616D706C652E636F6D301D0603551D0E0416041414E29017A6C35621FFC7A686B7B72DB06CD12351301F0603551D2304183016801454FA2383A04C28E0D930792261C80C4881D2C00B300E0603551D0F0101FF04040302078030150603551D250101FF040B3009060728818C5D050102300A06082A8648CE3D040302034800304502210097717AB9016740C8D7BCDAA494A62C053BBDECCE1383C1ACA72AD08DBC04CBB202203BAD859C13A63C6D1AD67D814D43E2425CAF90D422422C04A8EE0304C0D3A68D'
      }, << 24(<< {
        "version": "1.0",
        "digestAlgorithm": "SHA-256",
        "valueDigests": {
          "org.iso.18013.5.1": {
            0: h'75167333B47B6C2BFB86ECCC1F438CF57AF055371AC55E1E359E20F254ADCEBF',
            1: h'67E539D6139EBD131AEF441B445645DD831B2B375B390CA5EF6279B205ED4571',
            2: h'3394372DDB78053F36D5D869780E61EDA313D44A392092AD8E0527A2FBFE55AE',
            3: h'2E35AD3C4E514BB67B1A9DB51CE74E4CB9B7146E41AC52DAC9CE86B8613DB555',
            4: h'EA5C3304BB7C4A8DCB51C4C13B65264F845541341342093CCA786E058FAC2D59',
            5: h'FAE487F68B7A0E87A749774E56E9E1DC3A8EC7B77E490D21F0E1D3475661AA1D',
            6: h'7D83E507AE77DB815DE4D803B88555D0511D894C897439F5774056416A1C7533',
            7: h'F0549A145F1CF75CBEEFFA881D4857DD438D627CF32174B1731C4C38E12CA936',
            8: h'B68C8AFCB2AAF7C581411D2877DEF155BE2EB121A42BC9BA5B7312377E068F66',
            9: h'0B3587D1DD0C2A07A35BFB120D99A0ABFB5DF56865BB7FA15CC8B56A66DF6E0C',
            10: h'C98A170CF36E11ABB724E98A75A5343DFA2B6ED3DF2ECFBB8EF2EE55DD41C881',
            11: h'B57DD036782F7B14C6A30FAAAAE6CCD5054CE88BDFA51A016BA75EDA1EDEA948',
            12: h'651F8736B18480FE252A03224EA087B5D10CA5485146C67C74AC4EC3112D4C3A'
          },
          "org.iso.18013.5.1.US": {
            0: h'D80B83D25173C484C5640610FF1A31C949C1D934BF4CF7F18D5223B15DD4F21C',
            1: h'4D80E1E2E4FB246D97895427CE7000BB59BB24C8CD003ECF94BF35BBD2917E34',
            2: h'8B331F3B685BCA372E85351A25C9484AB7AFCDF0D2233105511F778D98C2F544',
            3: h'C343AF1BD1690715439161ABA73702C474ABF992B20C9FB55C36A336EBE01A87'
          }
        },
        "deviceKeyInfo": {
          "deviceKey": {
            1: 2,
            -1: 1,
            -2: h'96313D6C63E24E3372742BFDB1A33BA2C897DCD68AB8C753E4FBD48DCA6B7F9A',
            -3: h'1FB3269EDD418857DE1B39A4E4A44B92FA484CAA722C228288F01D0C03A2C3D6'
          }
        },
        "docType": "org.iso.18013.5.1.mDL",
        "validityInfo": {
          "signed": 0("2020-10-01T13:30:02Z"),
          "validFrom": 0("2020-10-01T13:30:02Z"),
          "validUntil": 0("2021-10-01T13:30:02Z")
        }
      } >>) >>, h'59E64205DF1E2F708DD6DB0847AED79FC7C0201D80FA55BADCAF2E1BCF5902E1E5A62E4832044B890AD85AA53F129134775D733754D7CB7A413766AEFF13CB2E'
    ]
  },
  "deviceSigned": {
    "nameSpaces": 24(<< {} >>),
    "deviceAuth": {
      "deviceMac": [<< {
          1: 5
        } >>,
        {},
        null, h'E99521A85AD7891B806A07F8B5388A332D92C189A7BF293EE1F543405AE6824D'
      ]
    }
  }
}

Verify MSO and device auth

val mdocRequest = MDocRequestBuilder(mdoc.docType.value)
  .addDataElementRequest("org.iso.18013.5.1", "family_name", true)
  .addDataElementRequest("org.iso.18013.5.1", "document_number", true)
  .build()
val deviceAuthenticationBytes = Hex.decode("d818590271847444657669636541757468656e7469636174696f6e83d8185858a20063312e30018201d818584ba4010220012158205a88d182bce5f42efa59943f33359d2e8a968ff289d93e5fa444b624343167fe225820b16e8cf858ddc7690407ba61d4c338237a8cfcf3de6aa672fc60a557aa32fc67d818584ba40102200121582060e3392385041f51403051f2415531cb56dd3f999c71687013aac6768bc8187e225820e58deb8fdbe907f7dd5368245551a34796f7d2215c440c339bb0f7b67beccdfa8258c391020f487315d10209616301013001046d646f631a200c016170706c69636174696f6e2f766e642e626c7565746f6f74682e6c652e6f6f6230081b28128b37282801021c015c1e580469736f2e6f72673a31383031333a646576696365656e676167656d656e746d646f63a20063312e30018201d818584ba4010220012158205a88d182bce5f42efa59943f33359d2e8a968ff289d93e5fa444b624343167fe225820b16e8cf858ddc7690407ba61d4c338237a8cfcf3de6aa672fc60a557aa32fc6758cd91022548721591020263720102110204616301013000110206616301036e6663005102046163010157001a201e016170706c69636174696f6e2f766e642e626c7565746f6f74682e6c652e6f6f6230081b28078080bf2801021c021107c832fff6d26fa0beb34dfcd555d4823a1c11010369736f2e6f72673a31383031333a6e66636e6663015a172b016170706c69636174696f6e2f766e642e7766612e6e616e57030101032302001324fec9a70b97ac9684a4e326176ef5b981c5e8533e5f00298cfccbc35e700a6b020414756f72672e69736f2e31383031332e352e312e6d444cd81841a0")
val deviceAuthentication = DataElement.fromCBOR<EncodedCBORElement>(deviceAuthenticationBytes).decode<DeviceAuthentication>()
val ephemeralMacKey = Hex.decode("dc2b9566fdaaae3c06baa40993cd0451aeba15e7677ef5305f6531f3533c35dd")
val presentedMdoc = MDoc.fromCBORHex("a367646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d65537061636573a1716f72672e69736f2e31383031332e352e3182d8185863a4686469676573744944006672616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e971656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456616c756563446f65d818586da4686469676573744944076672616e646f6d582026052a42e5880557a806c1459af3fb7eb505d3781566329d0b604b845b5f9e6871656c656d656e744964656e7469666965726f646f63756d656e745f6e756d6265726c656c656d656e7456616c7565693132333435363738396a697373756572417574688443a10126a118215901f3308201ef30820195a00302010202143c4416eed784f3b413e48f56f075abfa6d87eb84300a06082a8648ce3d04030230233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e170d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004ace7ab7340e5d9648c5a72a9a6f56745c7aad436a03a43efea77b5fa7b88f0197d57d8983e1b37d3a539f4d588365e38cbbf5b94d68c547b5bc8731dcd2f146ba381a83081a5301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e0416041414e29017a6c35621ffc7a686b7b72db06cd12351301f0603551d2304183016801454fa2383a04c28e0d930792261c80c4881d2c00b300e0603551d0f0101ff04040302078030150603551d250101ff040b3009060728818c5d050102300a06082a8648ce3d040302034800304502210097717ab9016740c8d7bcdaa494a62c053bbdecce1383c1aca72ad08dbc04cbb202203bad859c13a63c6d1ad67d814d43e2425caf90d422422c04a8ee0304c0d3a68d5903a2d81859039da66776657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c756544696765737473a2716f72672e69736f2e31383031332e352e31ad00582075167333b47b6c2bfb86eccc1f438cf57af055371ac55e1e359e20f254adcebf01582067e539d6139ebd131aef441b445645dd831b2b375b390ca5ef6279b205ed45710258203394372ddb78053f36d5d869780e61eda313d44a392092ad8e0527a2fbfe55ae0358202e35ad3c4e514bb67b1a9db51ce74e4cb9b7146e41ac52dac9ce86b8613db555045820ea5c3304bb7c4a8dcb51c4c13b65264f845541341342093cca786e058fac2d59055820fae487f68b7a0e87a749774e56e9e1dc3a8ec7b77e490d21f0e1d3475661aa1d0658207d83e507ae77db815de4d803b88555d0511d894c897439f5774056416a1c7533075820f0549a145f1cf75cbeeffa881d4857dd438d627cf32174b1731c4c38e12ca936085820b68c8afcb2aaf7c581411d2877def155be2eb121a42bc9ba5b7312377e068f660958200b3587d1dd0c2a07a35bfb120d99a0abfb5df56865bb7fa15cc8b56a66df6e0c0a5820c98a170cf36e11abb724e98a75a5343dfa2b6ed3df2ecfbb8ef2ee55dd41c8810b5820b57dd036782f7b14c6a30faaaae6ccd5054ce88bdfa51a016ba75eda1edea9480c5820651f8736b18480fe252a03224ea087b5d10ca5485146c67c74ac4ec3112d4c3a746f72672e69736f2e31383031332e352e312e5553a4005820d80b83d25173c484c5640610ff1a31c949c1d934bf4cf7f18d5223b15dd4f21c0158204d80e1e2e4fb246d97895427ce7000bb59bb24c8cd003ecf94bf35bbd2917e340258208b331f3b685bca372e85351a25c9484ab7afcdf0d2233105511f778d98c2f544035820c343af1bd1690715439161aba73702c474abf992b20c9fb55c36a336ebe01a876d6465766963654b6579496e666fa1696465766963654b6579a40102200121582096313d6c63e24e3372742bfdb1a33ba2c897dcd68ab8c753e4fbd48dca6b7f9a2258201fb3269edd418857de1b39a4e4a44b92fa484caa722c228288f01d0c03a2c3d667646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c6964556e74696cc074323032312d31302d30315431333a33303a30325a584059e64205df1e2f708dd6db0847aed79fc7c0201d80fa55badcaf2e1bcf5902e1e5a62e4832044b890ad85aa53f129134775d733754d7cb7a413766aeff13cb2e6c6465766963655369676e6564a26a6e616d65537061636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f65820e99521a85ad7891b806a07f8b5388a332d92c189a7bf293ee1f543405ae6824d")
// validate issuer signature, tamper check and device mac
val certificateDER = mdoc.issuerSigned.issuerAuth!!.x5Chain!!
val cert = CertificateFactory.getInstance("X509").generateCertificate(ByteArrayInputStream(certificateDER)) as X509Certificate
val cryptoProvider = SimpleCOSECryptoProvider(listOf(
  COSECryptoProviderKeyInfo(ISSUER_KEY_ID, AlgorithmID.ECDSA_256, cert.publicKey, null, listOf(cert))
))

val mdocVerified = presentedMdoc.verify(MDocVerificationParams(
  VerificationType.DOC_TYPE and VerificationType.DEVICE_SIGNATURE and VerificationType.ISSUER_SIGNATURE and VerificationType.ITEMS_TAMPER_CHECK,
  ISSUER_KEY_ID,
  ephemeralMacKey = ephemeralMacKey,
  deviceAuthentication = deviceAuthentication,
  mDocRequest = mdocRequest
), cryptoProvider)
println("Verified: $mdocVerified")

Example Output

Verified: true

List mdoc properties and values

val presentedMdoc = MDoc.fromCBORHex("a367646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d65537061636573a1716f72672e69736f2e31383031332e352e3182d8185863a4686469676573744944006672616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e971656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456616c756563446f65d818586da4686469676573744944076672616e646f6d582026052a42e5880557a806c1459af3fb7eb505d3781566329d0b604b845b5f9e6871656c656d656e744964656e7469666965726f646f63756d656e745f6e756d6265726c656c656d656e7456616c7565693132333435363738396a697373756572417574688443a10126a118215901f3308201ef30820195a00302010202143c4416eed784f3b413e48f56f075abfa6d87eb84300a06082a8648ce3d04030230233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e170d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004ace7ab7340e5d9648c5a72a9a6f56745c7aad436a03a43efea77b5fa7b88f0197d57d8983e1b37d3a539f4d588365e38cbbf5b94d68c547b5bc8731dcd2f146ba381a83081a5301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e0416041414e29017a6c35621ffc7a686b7b72db06cd12351301f0603551d2304183016801454fa2383a04c28e0d930792261c80c4881d2c00b300e0603551d0f0101ff04040302078030150603551d250101ff040b3009060728818c5d050102300a06082a8648ce3d040302034800304502210097717ab9016740c8d7bcdaa494a62c053bbdecce1383c1aca72ad08dbc04cbb202203bad859c13a63c6d1ad67d814d43e2425caf90d422422c04a8ee0304c0d3a68d5903a2d81859039da66776657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c756544696765737473a2716f72672e69736f2e31383031332e352e31ad00582075167333b47b6c2bfb86eccc1f438cf57af055371ac55e1e359e20f254adcebf01582067e539d6139ebd131aef441b445645dd831b2b375b390ca5ef6279b205ed45710258203394372ddb78053f36d5d869780e61eda313d44a392092ad8e0527a2fbfe55ae0358202e35ad3c4e514bb67b1a9db51ce74e4cb9b7146e41ac52dac9ce86b8613db555045820ea5c3304bb7c4a8dcb51c4c13b65264f845541341342093cca786e058fac2d59055820fae487f68b7a0e87a749774e56e9e1dc3a8ec7b77e490d21f0e1d3475661aa1d0658207d83e507ae77db815de4d803b88555d0511d894c897439f5774056416a1c7533075820f0549a145f1cf75cbeeffa881d4857dd438d627cf32174b1731c4c38e12ca936085820b68c8afcb2aaf7c581411d2877def155be2eb121a42bc9ba5b7312377e068f660958200b3587d1dd0c2a07a35bfb120d99a0abfb5df56865bb7fa15cc8b56a66df6e0c0a5820c98a170cf36e11abb724e98a75a5343dfa2b6ed3df2ecfbb8ef2ee55dd41c8810b5820b57dd036782f7b14c6a30faaaae6ccd5054ce88bdfa51a016ba75eda1edea9480c5820651f8736b18480fe252a03224ea087b5d10ca5485146c67c74ac4ec3112d4c3a746f72672e69736f2e31383031332e352e312e5553a4005820d80b83d25173c484c5640610ff1a31c949c1d934bf4cf7f18d5223b15dd4f21c0158204d80e1e2e4fb246d97895427ce7000bb59bb24c8cd003ecf94bf35bbd2917e340258208b331f3b685bca372e85351a25c9484ab7afcdf0d2233105511f778d98c2f544035820c343af1bd1690715439161aba73702c474abf992b20c9fb55c36a336ebe01a876d6465766963654b6579496e666fa1696465766963654b6579a40102200121582096313d6c63e24e3372742bfdb1a33ba2c897dcd68ab8c753e4fbd48dca6b7f9a2258201fb3269edd418857de1b39a4e4a44b92fa484caa722c228288f01d0c03a2c3d667646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c6964556e74696cc074323032312d31302d30315431333a33303a30325a584059e64205df1e2f708dd6db0847aed79fc7c0201d80fa55badcaf2e1bcf5902e1e5a62e4832044b890ad85aa53f129134775d733754d7cb7a413766aeff13cb2e6c6465766963655369676e6564a26a6e616d65537061636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f65820e99521a85ad7891b806a07f8b5388a332d92c189a7bf293ee1f543405ae6824d")
presentedMdoc.nameSpaces.forEach { ns ->
  println("Namespace: $ns")
  presentedMdoc.getIssuerSignedItems(ns).forEach { issuerSignedItem ->
    println("- ${issuerSignedItem.elementIdentifier.value}: ${issuerSignedItem.elementValue.value.toString()}")
  }
}

Example Output

Presented MDOC: a367646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d65537061636573a1716f72672e69736f2e31383031332e352e3182d8185863a4686469676573744944006672616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e971656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456616c756563446f65d818586da4686469676573744944076672616e646f6d582026052a42e5880557a806c1459af3fb7eb505d3781566329d0b604b845b5f9e6871656c656d656e744964656e7469666965726f646f63756d656e745f6e756d6265726c656c656d656e7456616c7565693132333435363738396a697373756572417574688443a10126a118215901f3308201ef30820195a00302010202143c4416eed784f3b413e48f56f075abfa6d87eb84300a06082a8648ce3d04030230233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e170d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004ace7ab7340e5d9648c5a72a9a6f56745c7aad436a03a43efea77b5fa7b88f0197d57d8983e1b37d3a539f4d588365e38cbbf5b94d68c547b5bc8731dcd2f146ba381a83081a5301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e0416041414e29017a6c35621ffc7a686b7b72db06cd12351301f0603551d2304183016801454fa2383a04c28e0d930792261c80c4881d2c00b300e0603551d0f0101ff04040302078030150603551d250101ff040b3009060728818c5d050102300a06082a8648ce3d040302034800304502210097717ab9016740c8d7bcdaa494a62c053bbdecce1383c1aca72ad08dbc04cbb202203bad859c13a63c6d1ad67d814d43e2425caf90d422422c04a8ee0304c0d3a68d5903a2d81859039da66776657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c756544696765737473a2716f72672e69736f2e31383031332e352e31ad00582075167333b47b6c2bfb86eccc1f438cf57af055371ac55e1e359e20f254adcebf01582067e539d6139ebd131aef441b445645dd831b2b375b390ca5ef6279b205ed45710258203394372ddb78053f36d5d869780e61eda313d44a392092ad8e0527a2fbfe55ae0358202e35ad3c4e514bb67b1a9db51ce74e4cb9b7146e41ac52dac9ce86b8613db555045820ea5c3304bb7c4a8dcb51c4c13b65264f845541341342093cca786e058fac2d59055820fae487f68b7a0e87a749774e56e9e1dc3a8ec7b77e490d21f0e1d3475661aa1d0658207d83e507ae77db815de4d803b88555d0511d894c897439f5774056416a1c7533075820f0549a145f1cf75cbeeffa881d4857dd438d627cf32174b1731c4c38e12ca936085820b68c8afcb2aaf7c581411d2877def155be2eb121a42bc9ba5b7312377e068f660958200b3587d1dd0c2a07a35bfb120d99a0abfb5df56865bb7fa15cc8b56a66df6e0c0a5820c98a170cf36e11abb724e98a75a5343dfa2b6ed3df2ecfbb8ef2ee55dd41c8810b5820b57dd036782f7b14c6a30faaaae6ccd5054ce88bdfa51a016ba75eda1edea9480c5820651f8736b18480fe252a03224ea087b5d10ca5485146c67c74ac4ec3112d4c3a746f72672e69736f2e31383031332e352e312e5553a4005820d80b83d25173c484c5640610ff1a31c949c1d934bf4cf7f18d5223b15dd4f21c0158204d80e1e2e4fb246d97895427ce7000bb59bb24c8cd003ecf94bf35bbd2917e340258208b331f3b685bca372e85351a25c9484ab7afcdf0d2233105511f778d98c2f544035820c343af1bd1690715439161aba73702c474abf992b20c9fb55c36a336ebe01a876d6465766963654b6579496e666fa1696465766963654b6579a40102200121582096313d6c63e24e3372742bfdb1a33ba2c897dcd68ab8c753e4fbd48dca6b7f9a2258201fb3269edd418857de1b39a4e4a44b92fa484caa722c228288f01d0c03a2c3d667646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c6964556e74696cc074323032312d31302d30315431333a33303a30325a584059e64205df1e2f708dd6db0847aed79fc7c0201d80fa55badcaf2e1bcf5902e1e5a62e4832044b890ad85aa53f129134775d733754d7cb7a413766aeff13cb2e6c6465766963655369676e6564a26a6e616d65537061636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f65820e99521a85ad7891b806a07f8b5388a332d92c189a7bf293ee1f543405ae6824d
Namespace: org.iso.18013.5.1
- family_name: Doe
- document_number: 123456789

Sign a mobile eID document (ISO-IEC_23220-2)

    val mdoc = MDocBuilder("org.iso.23220.mID.1")
      .addItemToSign("org.iso.23220.1", "family_name", "Doe".toDE())
      .addItemToSign("org.iso.23220.1", "given_name", "John".toDE())
      .addItemToSign("org.iso.23220.1", "birth_date", FullDateElement(LocalDate(1990, 1, 15)))
      .addItemToSign("org.iso.23220.1", "sex", "1".toDE()) // ISO/IEC 5218
      .addItemToSign("org.iso.23220.1", "height", "175".toDE())
      .addItemToSign("org.iso.23220.1", "weight", "70".toDE())
      .addItemToSign("org.iso.23220.1", "birthplace", "Vienna".toDE())
      .addItemToSign("org.iso.23220.1", "nationality", "AT".toDE())
      .addItemToSign("org.iso.23220.1", "telephone_number", "0987654".toDE())
      .addItemToSign("org.iso.23220.1", "email_address", "[email protected]".toDE())
      .sign(ValidityInfo(Clock.System.now(), Clock.System.now(), Clock.System.now().plus(365*24, DateTimeUnit.HOUR)),
        deviceKeyInfo, cryptoProvider, ISSUER_KEY_ID
      )

Verify certain elements of the above signed mobile eID document (ISO-IEC_23220-2)

    val mdocRequest = MDocRequestBuilder(mdoc.docType.value)
      .addDataElementRequest("org.iso.23220.1", "family_name", true)
      .addDataElementRequest("org.iso.23220.1", "given_name", true)
      .addDataElementRequest("org.iso.23220.1", "birth_date", true)
      .build()

    val presentedMdoc = mdoc.presentWithDeviceSignature(mdocRequest, deviceAuthentication, cryptoProvider, DEVICE_KEY_ID)

    presentedMdoc.verify(
      MDocVerificationParams(
        VerificationType.forPresentation,
        ISSUER_KEY_ID, DEVICE_KEY_ID,
        deviceAuthentication = deviceAuthentication,
        mDocRequest =  mdocRequest
      ),
      cryptoProvider
    )

License

Licensed under the Apache License, Version 2.0

About

Kotlin Multiplatform mdoc library (ISO/IEC 18013-5:2021)

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages