Issuing verifiable credentials in the SD-JWT VC and mdoc/mDL formats, mandated in eIDAS 2.0

Takahiko Kawasaki
14 min readFeb 2, 2024

Introduction

The digital identity industry is abuzz with discussions about Verifiable Credentials. Particularly in Europe, the establishment of the EU Digital Identity Wallet (EUDIW) to manage Verifiable Credentials is mandated by eIDAS 2.0 (a set of regulations and technical specifications). As a result, there is a rapid pace of progress in the development and implementation of related technical specifications.

Against this backdrop, at the “OpenID Summit Tokyo 2024” held on January 19, 2024, Mr. Torsten Lodderstedt from the German government agency SPRIND, Mr. Amir Sharif from the Italian research institution FBK, and Mr. Joseph Heenan from the OpenWallet Foundation, visited Japan as speakers and delivered presentations on topics related to digital identity wallets.

At the same event, I (Takahiko Kawasaki) also took the stage and conducted a demonstration of issuing two verifiable credentials simultaneously in the SD-JWT VC and mdoc/mDL formats, which are mandated in eIDAS 2.0.

In this article, I would like to reflect on the content of my presentation.

VC/VP Specifications

The specifications related to Verifiable Credentials (VC) and Verifiable Presentations (VP) can be categorized into two main groups: one group pertains to the formats of VC/VP, and the other group deals with the transmission of VC/VP.

While there are other related specifications, I introduced the following three specifications regarding the format.

W3C VCDM is considered the primary source of information for the Issuer-Wallet-Verifier model definition.

SD-JWT VC is a verifiable credential format based on the SD-JWT format, which enables selective disclosure.

mdoc is a data structure defined in the ISO/IEC 18013-5:2021 document titled ‘Personal identification, ISO-compliant driving licence, Part 5: Mobile driving licence (mDL) application,’ and it is based on the binary format CBOR (RFC 8949). mDL, a type of mdoc, is defined within the same ISO document and represents a mobile driver’s license. mDL includes information specific to a driver’s license, such as driving_privileges, in addition to personal information like the family name and given name.

The specifications central to the transmission of VC/VP are as follows:

  • OpenID for Verifiable Credential Issuance (OID4VCI)
  • OpenID for Verifiable Presentations (OID4VP)
  • Self-Issued OpenID Provider version 2 (SIOPv2)

OID4VCI is a technical specification defining the issuance procedures for verifiable credentials. In my demo, I performed the issuance of SD-JWT VC and mdoc/mDL based on the latest working group draft of this specification.

⚠️ NOTE: Due to the high frequency of changes in the OID4VCI specification, the version published on openid.net may not be suitable as reference documents for implementers. Implementers are advised to refer to the working group draft that automatically follows the updates in the main branch of the openid/OpenID4VCI repository.

SD-JWT

Selective Disclosure

Before conducting the demo, I briefly introduced SD-JWT, which serves as the foundation for SD-JWT VC.

The credential issuer, responsible for issuing verifiable credentials, prepares the information to embed into the verifiable credential. In this example, the issuer is preparing the name, date of birth, and address.

Then, the credential issuer prepares a key pair based on an asymmetric key algorithm,

and generates a signature with the private key using the prepared information as input.

The credential issuer generates a verifiable credential that includes the information and the signature.

The credential issuer issues the generated verifiable credential to the wallet.

The wallet selectively chooses the information to disclose (selective disclosure) and creates a verifiable presentation. In this example, it discloses the name and date of birth while keeping the address undisclosed.

The wallet presents the generated verifiable presentation to the verifier.

The verifier, through some means, obtains the public key corresponding to the private key used by the credential issuer for the signature.

The verifier uses the obtained public key to verify the signature included in the verifiable presentation.

However, this signature verification fails.

The reason is that even though the signature was generated with the input ‘name, date of birth, address,’ the verifier only received ‘name and date of birth.’ When the verifier attempts to recalculate the signature with the input ‘name, date of birth,’ the values of the received signature and the recalculated signature do not match.

To achieve selective disclosure while keeping the signature valid, careful consideration is required. Existing techniques such as BBS+ (Boneh-Lynn-Shacham signature plus) or CL Signatures (Camenisch-Lysyanskaya Signatures) provide methods for selective disclosure. However, for various reasons, a new format called SD-JWT has been developed.

SD-JWT Format

In a typical JWT, the payload section directly embeds claim names and their corresponding values.

To generate SD-JWT, first, extract a pair of claim name and claim value.

Then, prepend any salt with sufficient entropy to the pair,

and create a JSON array.

Encode this JSON array using base64url. The resulting string, generated in this way, is referred to as ‘Disclosure’ in the SD-JWT specification.

Then, create an array named _sd at the original location where the claim pair was placed,

and add the digest value of the disclosure to that array.

Repeat the same process for the set of claims for which selective disclosure is desired.

Create a JWT with the prepared payload using the above steps. The specification refers to this JWT as an Issuer-signed JWT.

And then, list the disclosures at the end,

and concatenate them with tildes (~).

This resulting string is an SD-JWT.

I’ll skip the detailed explanation, but for the mechanism called Key Binding, sometimes the public key is embedded in the payload section of the Issuer-signed JWT, and a Key Binding JWT is appended to the end of the SD-JWT.

The overall process of SD-JWT generation looks like the following:

Now, let’s say we receive an SD-JWT containing all the disclosures. In this case, by decoding the disclosures using base64url, we can obtain all the pairs of claim names and claim values.

On the other hand, if only a subset of disclosures is included, we can only obtain the pairs of claim names and claim values corresponding to the disclosures.

What makes this advantageous is that even if only a subset of disclosures is included, the signature of the Issuer-signed JWT remains valid. In other words, when you recalculate the signature using the header of the Issuer-signed JWT and the payload section containing the _sd array as input, it matches the signature attached to the Issuer-signed JWT.

OID4VCI

OID4VCI is a technical specification that defines the issuance procedures for verifiable credentials.

Concept

The concept itself is relatively simple. Firstly, the authorization server issues an access token to the wallet.

The wallet presents the access token to the credential issuer.

The credential issuer issues a verifiable credential to the wallet.

Access Token Issuance

While the concept is simple, there are multiple defined procedures for issuing access tokens that can be used for verifiable credential issuance.

Firstly, if there is a credential offer issued by the credential issuer, and it includes a pre-authorized code,

the wallet can obtain an access token by presenting that pre-authorized code to the token endpoint.

On the other hand, if the credential offer includes an issuer state,

the wallet sends an authorization request containing that issuer state to the authorization endpoint, and receives an authorization code,

then, it follows the standard authorization code flow to obtain an access token from the token endpoint.

Additionally, there is a method defined that doesn’t use a credential offer but employs the RAR object defined in RFC 9396 OAuth 2.0 Rich Authorization Requests.

Depending on the credential issuer’s configuration, shortcuts may be provided as values for the scope parameter. In such cases, the scope parameter can be used.

So, in the OID4VCI specification, four methods are defined for obtaining an access token.

Verifiable Credential Issuance

By presenting the access token to the credential endpoint of the credential issuer, the wallet can obtain a verifiable credential.

However, the credential endpoint may not be able to generate the requested verifiable credential immediately upon receiving the access token. In such cases, the credential endpoint issues a transaction ID instead of the verifiable credential.

The wallet, upon receiving the transaction ID, later presents the transaction ID along with the access token to the credential issuer’s deferred credential endpoint. If the verifiable credential is ready, it is obtained. If it is not yet ready, an issuance_pending error is returned.

If you want to obtain multiple verifiable credentials at once, you can use the batch credential endpoint instead of the credential endpoint.

Similar to the credential endpoint, the batch credential endpoint may not be able to generate the requested verifiable credentials immediately. In such cases, a separate transaction ID is returned for each verifiable credential that cannot be issued immediately.

Similar to the previous example, by presenting the issued transaction ID to the deferred credential endpoint, you can obtain the corresponding verifiable credential.

The following diagram illustrates the paths of the verifiable credential issuance introduced so far.

Demo

In the demo, I obtained an access token using the pre-authorized code flow, presented that access token to the batch credential endpoint, and obtained verifiable credentials in the SD-JWT VC format and mdoc/mDL format.

⚠️ NOTE: I used the pre-authorized code flow in the demo because the procedure is simple. However, due to security concerns, the Italian ecosystem does not employ the pre-authorized code flow.

Preparation

Set up several shell variables for the demo.

CLIENT_ID=218232426
TOKEN_ENDPOINT=https://trial.authlete.net/api/token
BATCH_CREDENTIAL_ENDPOINT=https://trial.authlete.net/api/batch_credential

The trial.authlete.net appearing in the variable values is a demo authorization server and credential issuer. Its implementation is available at authlete/java-oauth-server.

Obtaining a credential offer

Access the https://trial.authlete.net/api/offer/issue to generate a demo credential offer containing a pre-authorized code. For more details about the steps, please refer to ‘4.1.2. Pre-Authorized code’.

Set the issued pre-authorized code in a shell variable.

PRE_AUTHORIZED_CODE=${The issued pre-authorized code}

Obtaining an access token

Obtain an access token using the pre-authorized code flow.

curl -s $TOKEN_ENDPOINT \
-d client_id=$CLIENT_ID \
-d grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code \
-d pre-authorized_code=$PRE_AUTHORIZED_CODE

Set the issued access token in a shell variable.

ACCESS_TOKEN=${The issued access token}

Obtaining verifiable credentials

Submit a batch credential request to the batch credential endpoint.

curl -s $BATCH_CREDENTIAL_ENDPOINT \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"credential_requests": [
{
"format": "vc+sd-jwt",
"vct": "https://credentials.example.com/identity_credential"
},
{
"format": "mso_mdoc",
"doctype": "org.iso.18013.5.1.mDL",
"claims": {
"org.iso.18013.5.1": {
"family_name": {}, "given_name": {}, "birth_date": {},
"issue_date": {}, "expiry_date": {}, "issuing_country": {},
"document_number": {}, "driving_privileges": {}
}
}
}
]
}'

The message body of the request is in JSON format. Within this JSON, there is an array named credential_requests, and each element of this array is a JSON object. Each JSON object contains information specifying the verifiable credential to be obtained. In this example, the first JSON object specifies SD-JWT VC, and the second JSON object specifies mdoc.

The endpoint returns a JSON like the following:

{
"credential_responses": [
{
"credential": "eyJraWQiOiJKMUZ3SlA4N0M2LVFOX1dTSU9tSkFRYzZuNUNRX2JaZGFGSjVHRG5XMVJrIiwidHlwIjoidmMrc2Qtand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsIl9zZCI6WyIwczNiazZYcC02ZW1rV3cxTFd2OWthaGk5YjNUV0c2NDJLV3dpZEZKeHlvIiwiM3BSUGNUUjItSkJySjhVRjVkZGhtcDhwbDA3MEpheWpoMWEzZVVWRDZNZyIsIjZ6UEtKS2pzc2Y0Q1JNNmhUeDZZVUdQdzRBbm1ZWHZocnFuZDlmdTZMcUkiLCJBVnFKdDdkcWNEVWZLNmJPSEg0UTFEODVfMVNmLXRwM0d0QlM1Mk1Bb3FVIiwiQldydzdVV2YzdjF4cjdOOXFoSFpXMHMwa0FERDVGbFgtUmNQV2dCZEFJOCIsIkhtcHVfdVo4dWo4b2ViMXIyaGg2YmdUY3dNbEJoVHNrUjIxR2tZZVd4TW8iLCJNQ1JpVkRYc3I3MTJ1WW9NRUtWeEJfMmFxX0oweENfa08yNTdwQ3N0RlB3IiwiTUc3WElRV1Y5RFE2dC12WDdmZERUblZ6bnpTZUwwY2gtX0NtNkkyM3ZDWSIsIlB5VEVrajdFdUhScGljdFk5Z1ZpQTVhcTBrYTd2SzJZdDRrX04wbzlTb3ciXSwiaWF0IjoxNzA1MDE4MjA1LCJ2Y3QiOiJodHRwczovL2NyZWRlbnRpYWxzLmV4YW1wbGUuY29tL2lkZW50aXR5X2NyZWRlbnRpYWwiLCJfc2RfYWxnIjoic2hhLTI1NiJ9.ll4JdW-ksNDyVGx-OTueQYojpUYXhUZ6J31fFKGall2SsT5LQt-I5w24AiYhDvxYWRGRCmJF5UI-_3SpNE83wQ~WyJJZEJuZ2xIcF9URGRyeUwycGJLZVNBIiwic3ViIiwiMTAwNCJd~WyJDd0lYNU11clBMZ1VFRnA2U2JhM0dnIiwiZ2l2ZW5fbmFtZSIsIkluZ2EiXQ~WyJveUYtR3Q5LXVwa1FkU0ZMX0pTekNnIiwiZmFtaWx5X25hbWUiLCJTaWx2ZXJzdG9uZSJd~WyJMZG9oSjQ5d2gwcTBubWNJUG92SVhnIiwiYmlydGhkYXRlIiwiMTk5MS0xMS0wNiJd~"
},
{
"credential": "omdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGxpc3N1ZXJTaWduZWSiam5hbWVTcGFjZXOhcW9yZy5pc28uMTgwMTMuNS4xiNgYWFukaGRpZ2VzdElEAWZyYW5kb21QcbnmTIHt0_17t-AcHkKZbHFlbGVtZW50SWRlbnRpZmllcmppc3N1ZV9kYXRlbGVsZW1lbnRWYWx1ZdkD7GoyMDI0LTAxLTEy2BhYXKRoZGlnZXN0SUQCZnJhbmRvbVBRwvzBVJYBc2plhd7vXZwTcWVsZW1lbnRJZGVudGlmaWVya2V4cGlyeV9kYXRlbGVsZW1lbnRWYWx1ZdkD7GoyMDI1LTAxLTEy2BhYWqRoZGlnZXN0SUQDZnJhbmRvbVDcuBh2xE6SqxDDECOY9H3CcWVsZW1lbnRJZGVudGlmaWVya2ZhbWlseV9uYW1lbGVsZW1lbnRWYWx1ZWtTaWx2ZXJzdG9uZdgYWFKkaGRpZ2VzdElEBGZyYW5kb21QHu5Fe96gJQH-NeOAvSuJdHFlbGVtZW50SWRlbnRpZmllcmpnaXZlbl9uYW1lbGVsZW1lbnRWYWx1ZWRJbmdh2BhYW6RoZGlnZXN0SUQFZnJhbmRvbVDI-4b03R-29ljFhUoZMHP0cWVsZW1lbnRJZGVudGlmaWVyamJpcnRoX2RhdGVsZWxlbWVudFZhbHVl2QPsajE5OTEtMTEtMDbYGFhVpGhkaWdlc3RJRAZmcmFuZG9tUCJlXpl0UAxhiiN9BwSnLeBxZWxlbWVudElkZW50aWZpZXJvaXNzdWluZ19jb3VudHJ5bGVsZW1lbnRWYWx1ZWJVU9gYWFukaGRpZ2VzdElEB2ZyYW5kb21QbWz_ggUxytSax7_FqCzoEHFlbGVtZW50SWRlbnRpZmllcm9kb2N1bWVudF9udW1iZXJsZWxlbWVudFZhbHVlaDEyMzQ1Njc42BhYoqRoZGlnZXN0SUQIZnJhbmRvbVBbSwOg91lMspu_ctBa2uqgcWVsZW1lbnRJZGVudGlmaWVycmRyaXZpbmdfcHJpdmlsZWdlc2xlbGVtZW50VmFsdWWBo3V2ZWhpY2xlX2NhdGVnb3J5X2NvZGVhQWppc3N1ZV9kYXRl2QPsajIwMjMtMDEtMDFrZXhwaXJ5X2RhdGXZA-xqMjA0My0wMS0wMWppc3N1ZXJBdXRohEOhASahGCFZAWEwggFdMIIBBKADAgECAgYBjJHZwhkwCgYIKoZIzj0EAwIwNjE0MDIGA1UEAwwrSjFGd0pQODdDNi1RTl9XU0lPbUpBUWM2bjVDUV9iWmRhRko1R0RuVzFSazAeFw0yMzEyMjIxNDA2NTZaFw0yNDEwMTcxNDA2NTZaMDYxNDAyBgNVBAMMK0oxRndKUDg3QzYtUU5fV1NJT21KQVFjNm41Q1FfYlpkYUZKNUdEblcxUmswWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQCilV5ugmlhHJzDVgqSRE5d8KkoQqX1jVg8WE4aPjFODZQ66fFPFIhWRP3ioVUi67WGQSgTY3F6Vmjf7JMVQ4MMAoGCCqGSM49BAMCA0cAMEQCIGcWNJwFy8RGV4uMwK7k1vEkqQ2xr-BCGRdN8OZur5PeAiBVrNuxV1C9mCW5z2clhDFaXNdP2Lp_7CBQrHQoJhuPcNgYWQHopWd2ZXJzaW9uYzEuMG9kaWdlc3RBbGdvcml0aG1nU0hBLTI1Nmx2YWx1ZURpZ2VzdHOhcW9yZy5pc28uMTgwMTMuNS4xqAFYIKuS8FCeCcvDMwZgEezuuVv-DYsUpdypJp9abJrqHAmXAlggu7D-3vr-NrLg3zigunUzEKFqYAyG5sA-ffvmDjRxZ24DWCC2OBnhoZFhqE7s8PRfdej8t5frp-HgF_2X4qMtzvEY6ARYIBF_rl93VR21umkIdSMiWqFmT5Jxs0n3H5SWonWrJoDrBVggKDvVyMU358Le0n6TkVb2c0BbhbSMJwpswtPLNiZrTR8GWCAFZzJwAmnC7QcMQwq72FDQlmPxk0434cZbh6_rt1VagQdYIHwBHQ3-sVPtco-RcUhuYYq6iivujjYyJmQBbQ_OdhFDCFggcjT2HYgkoxnwWP-9jqO_6-D-d69H9UW2xjpDWrknlvBnZG9jVHlwZXVvcmcuaXNvLjE4MDEzLjUuMS5tRExsdmFsaWRpdHlJbmZvo2ZzaWduZWTAdDIwMjQtMDEtMTJUMDA6MTA6MDVaaXZhbGlkRnJvbcB0MjAyNC0wMS0xMlQwMDoxMDowNVpqdmFsaWRVbnRpbMB0MjAyNS0wMS0xMlQwMDoxMDowNVpYQHFzEb09NFyFlj533FE_1B9I2rku90K52ar64Id1CyOUXWXzhINeVfoJU1cfxgCT2CX1369cGd_TQxSjhVx8bpY"
}
],
"c_nonce": "BvPJWhd3jvBCeooQTzSBNk0TCU4BHq150odu_vpAvSY",
"c_nonce_expires_in": 86052
}

The response includes an array named credential_responses, and each element in the array corresponds to the elements in the credential_requests array of the request.

Each element is a JSON object, and if the object contains the credential property, its value is the issued verifiable credential.

SD-JWT VC

In this example, the value of the credential property within the first JSON object is the verifiable credential in the SD-JWT VC format.

eyJraWQiOiJKMUZ3SlA4N0M2LVFOX1dTSU9tSkFRYzZuNUNRX2JaZGFGSjVHRG5XMVJrIiwidHlwIjoidmMrc2Qtand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsIl9zZCI6WyIwczNiazZYcC02ZW1rV3cxTFd2OWthaGk5YjNUV0c2NDJLV3dpZEZKeHlvIiwiM3BSUGNUUjItSkJySjhVRjVkZGhtcDhwbDA3MEpheWpoMWEzZVVWRDZNZyIsIjZ6UEtKS2pzc2Y0Q1JNNmhUeDZZVUdQdzRBbm1ZWHZocnFuZDlmdTZMcUkiLCJBVnFKdDdkcWNEVWZLNmJPSEg0UTFEODVfMVNmLXRwM0d0QlM1Mk1Bb3FVIiwiQldydzdVV2YzdjF4cjdOOXFoSFpXMHMwa0FERDVGbFgtUmNQV2dCZEFJOCIsIkhtcHVfdVo4dWo4b2ViMXIyaGg2YmdUY3dNbEJoVHNrUjIxR2tZZVd4TW8iLCJNQ1JpVkRYc3I3MTJ1WW9NRUtWeEJfMmFxX0oweENfa08yNTdwQ3N0RlB3IiwiTUc3WElRV1Y5RFE2dC12WDdmZERUblZ6bnpTZUwwY2gtX0NtNkkyM3ZDWSIsIlB5VEVrajdFdUhScGljdFk5Z1ZpQTVhcTBrYTd2SzJZdDRrX04wbzlTb3ciXSwiaWF0IjoxNzA1MDE4MjA1LCJ2Y3QiOiJodHRwczovL2NyZWRlbnRpYWxzLmV4YW1wbGUuY29tL2lkZW50aXR5X2NyZWRlbnRpYWwiLCJfc2RfYWxnIjoic2hhLTI1NiJ9.ll4JdW-ksNDyVGx-OTueQYojpUYXhUZ6J31fFKGall2SsT5LQt-I5w24AiYhDvxYWRGRCmJF5UI-_3SpNE83wQ~WyJJZEJuZ2xIcF9URGRyeUwycGJLZVNBIiwic3ViIiwiMTAwNCJd~WyJDd0lYNU11clBMZ1VFRnA2U2JhM0dnIiwiZ2l2ZW5fbmFtZSIsIkluZ2EiXQ~WyJveUYtR3Q5LXVwa1FkU0ZMX0pTekNnIiwiZmFtaWx5X25hbWUiLCJTaWx2ZXJzdG9uZSJd~WyJMZG9oSjQ5d2gwcTBubWNJUG92SVhnIiwiYmlydGhkYXRlIiwiMTk5MS0xMS0wNiJd~

Since parts in SD-JWT VC are encoded in base64url, decoding an SD-JWT VC is not a particularly challenging process. By using the decode-sd-jwt script in the authlete/oid4vci-demo repository, you can obtain the following decoding result:

{
"kid": "J1FwJP87C6-QN_WSIOmJAQc6n5CQ_bZdaFJ5GDnW1Rk",
"typ": "vc+sd-jwt",
"alg": "ES256"
}
{
"iss": "https://trial.authlete.net",
"_sd": [
"0s3bk6Xp-6emkWw1LWv9kahi9b3TWG642KWwidFJxyo",
"3pRPcTR2-JBrJ8UF5ddhmp8pl070Jayjh1a3eUVD6Mg",
"6zPKJKjssf4CRM6hTx6YUGPw4AnmYXvhrqnd9fu6LqI",
"AVqJt7dqcDUfK6bOHH4Q1D85_1Sf-tp3GtBS52MAoqU",
"BWrw7UWf3v1xr7N9qhHZW0s0kADD5FlX-RcPWgBdAI8",
"Hmpu_uZ8uj8oeb1r2hh6bgTcwMlBhTskR21GkYeWxMo",
"MCRiVDXsr712uYoMEKVxB_2aq_J0xC_kO257pCstFPw",
"MG7XIQWV9DQ6t-vX7fdDTnVznzSeL0ch-_Cm6I23vCY",
"PyTEkj7EuHRpictY9gViA5aq0ka7vK2Yt4k_N0o9Sow"
],
"iat": 1705018205,
"vct": "https://credentials.example.com/identity_credential",
"_sd_alg": "sha-256"
}
{
"digest": "6zPKJKjssf4CRM6hTx6YUGPw4AnmYXvhrqnd9fu6LqI",
"WyJJZEJuZ2xIcF9URGRyeUwycGJLZVNBIiwic3ViIiwiMTAwNCJd": [
"IdBnglHp_TDdryL2pbKeSA",
"sub",
"1004"
]
}
{
"digest": "MG7XIQWV9DQ6t-vX7fdDTnVznzSeL0ch-_Cm6I23vCY",
"WyJDd0lYNU11clBMZ1VFRnA2U2JhM0dnIiwiZ2l2ZW5fbmFtZSIsIkluZ2EiXQ": [
"CwIX5MurPLgUEFp6Sba3Gg",
"given_name",
"Inga"
]
}
{
"digest": "3pRPcTR2-JBrJ8UF5ddhmp8pl070Jayjh1a3eUVD6Mg",
"WyJveUYtR3Q5LXVwa1FkU0ZMX0pTekNnIiwiZmFtaWx5X25hbWUiLCJTaWx2ZXJzdG9uZSJd": [
"oyF-Gt9-upkQdSFL_JSzCg",
"family_name",
"Silverstone"
]
}
{
"digest": "Hmpu_uZ8uj8oeb1r2hh6bgTcwMlBhTskR21GkYeWxMo",
"WyJMZG9oSjQ5d2gwcTBubWNJUG92SVhnIiwiYmlydGhkYXRlIiwiMTk5MS0xMS0wNiJd": [
"LdohJ49wh0q0nmcIPovIXg",
"birthdate",
"1991-11-06"
]
}

The following diagram illustrates the relationship between the SD-JWT VC and the decoded contents.

mdoc/mDL

The value of the credential property within the second JSON object is the verifiable credential in the mdoc/mDL format.

omdkb2NUeXBldW9yZy5pc28uMTgwMTMuNS4xLm1ETGxpc3N1ZXJTaWduZWSiam5hbWVTcGFjZXOhcW9yZy5pc28uMTgwMTMuNS4xiNgYWFukaGRpZ2VzdElEAWZyYW5kb21QcbnmTIHt0_17t-AcHkKZbHFlbGVtZW50SWRlbnRpZmllcmppc3N1ZV9kYXRlbGVsZW1lbnRWYWx1ZdkD7GoyMDI0LTAxLTEy2BhYXKRoZGlnZXN0SUQCZnJhbmRvbVBRwvzBVJYBc2plhd7vXZwTcWVsZW1lbnRJZGVudGlmaWVya2V4cGlyeV9kYXRlbGVsZW1lbnRWYWx1ZdkD7GoyMDI1LTAxLTEy2BhYWqRoZGlnZXN0SUQDZnJhbmRvbVDcuBh2xE6SqxDDECOY9H3CcWVsZW1lbnRJZGVudGlmaWVya2ZhbWlseV9uYW1lbGVsZW1lbnRWYWx1ZWtTaWx2ZXJzdG9uZdgYWFKkaGRpZ2VzdElEBGZyYW5kb21QHu5Fe96gJQH-NeOAvSuJdHFlbGVtZW50SWRlbnRpZmllcmpnaXZlbl9uYW1lbGVsZW1lbnRWYWx1ZWRJbmdh2BhYW6RoZGlnZXN0SUQFZnJhbmRvbVDI-4b03R-29ljFhUoZMHP0cWVsZW1lbnRJZGVudGlmaWVyamJpcnRoX2RhdGVsZWxlbWVudFZhbHVl2QPsajE5OTEtMTEtMDbYGFhVpGhkaWdlc3RJRAZmcmFuZG9tUCJlXpl0UAxhiiN9BwSnLeBxZWxlbWVudElkZW50aWZpZXJvaXNzdWluZ19jb3VudHJ5bGVsZW1lbnRWYWx1ZWJVU9gYWFukaGRpZ2VzdElEB2ZyYW5kb21QbWz_ggUxytSax7_FqCzoEHFlbGVtZW50SWRlbnRpZmllcm9kb2N1bWVudF9udW1iZXJsZWxlbWVudFZhbHVlaDEyMzQ1Njc42BhYoqRoZGlnZXN0SUQIZnJhbmRvbVBbSwOg91lMspu_ctBa2uqgcWVsZW1lbnRJZGVudGlmaWVycmRyaXZpbmdfcHJpdmlsZWdlc2xlbGVtZW50VmFsdWWBo3V2ZWhpY2xlX2NhdGVnb3J5X2NvZGVhQWppc3N1ZV9kYXRl2QPsajIwMjMtMDEtMDFrZXhwaXJ5X2RhdGXZA-xqMjA0My0wMS0wMWppc3N1ZXJBdXRohEOhASahGCFZAWEwggFdMIIBBKADAgECAgYBjJHZwhkwCgYIKoZIzj0EAwIwNjE0MDIGA1UEAwwrSjFGd0pQODdDNi1RTl9XU0lPbUpBUWM2bjVDUV9iWmRhRko1R0RuVzFSazAeFw0yMzEyMjIxNDA2NTZaFw0yNDEwMTcxNDA2NTZaMDYxNDAyBgNVBAMMK0oxRndKUDg3QzYtUU5fV1NJT21KQVFjNm41Q1FfYlpkYUZKNUdEblcxUmswWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQCilV5ugmlhHJzDVgqSRE5d8KkoQqX1jVg8WE4aPjFODZQ66fFPFIhWRP3ioVUi67WGQSgTY3F6Vmjf7JMVQ4MMAoGCCqGSM49BAMCA0cAMEQCIGcWNJwFy8RGV4uMwK7k1vEkqQ2xr-BCGRdN8OZur5PeAiBVrNuxV1C9mCW5z2clhDFaXNdP2Lp_7CBQrHQoJhuPcNgYWQHopWd2ZXJzaW9uYzEuMG9kaWdlc3RBbGdvcml0aG1nU0hBLTI1Nmx2YWx1ZURpZ2VzdHOhcW9yZy5pc28uMTgwMTMuNS4xqAFYIKuS8FCeCcvDMwZgEezuuVv-DYsUpdypJp9abJrqHAmXAlggu7D-3vr-NrLg3zigunUzEKFqYAyG5sA-ffvmDjRxZ24DWCC2OBnhoZFhqE7s8PRfdej8t5frp-HgF_2X4qMtzvEY6ARYIBF_rl93VR21umkIdSMiWqFmT5Jxs0n3H5SWonWrJoDrBVggKDvVyMU358Le0n6TkVb2c0BbhbSMJwpswtPLNiZrTR8GWCAFZzJwAmnC7QcMQwq72FDQlmPxk0434cZbh6_rt1VagQdYIHwBHQ3-sVPtco-RcUhuYYq6iivujjYyJmQBbQ_OdhFDCFggcjT2HYgkoxnwWP-9jqO_6-D-d69H9UW2xjpDWrknlvBnZG9jVHlwZXVvcmcuaXNvLjE4MDEzLjUuMS5tRExsdmFsaWRpdHlJbmZvo2ZzaWduZWTAdDIwMjQtMDEtMTJUMDA6MTA6MDVaaXZhbGlkRnJvbcB0MjAyNC0wMS0xMlQwMDoxMDowNVpqdmFsaWRVbnRpbMB0MjAyNS0wMS0xMlQwMDoxMDowNVpYQHFzEb09NFyFlj533FE_1B9I2rku90K52ar64Id1CyOUXWXzhINeVfoJU1cfxgCT2CX1369cGd_TQxSjhVx8bpY

This value is encoded in base64url, representing CBOR data. Therefore, when decoded, it becomes binary data, which is not human-readable. For this situation, I have prepared an online tool called ‘CBOR Zone’ for parsing CBOR data. Please feel free to use it.

For example, if you input the above mdoc into CBOR Zone, select CBOR Diagnostic Notation (RFC 8949, 8. Diagnostic Notation, RFC 8610, Appendix G. Extended Diagnostic Notation) as the output format, and click the ‘Generate’ button, you will obtain the following information:

{
"docType": "org.iso.18013.5.1.mDL",
"issuerSigned": {
"nameSpaces": {
"org.iso.18013.5.1": [
24(<<
{
"digestID": 1,
"random": h'71b9e64c81edd3fd7bb7e01c1e42996c',
"elementIdentifier": "issue_date",
"elementValue": 1004("2024-01-12")
}
>>),
24(<<
{
"digestID": 2,
"random": h'51c2fcc1549601736a6585deef5d9c13',
"elementIdentifier": "expiry_date",
"elementValue": 1004("2025-01-12")
}
>>),
24(<<
{
"digestID": 3,
"random": h'dcb81876c44e92ab10c3102398f47dc2',
"elementIdentifier": "family_name",
"elementValue": "Silverstone"
}
>>),
24(<<
{
"digestID": 4,
"random": h'1eee457bdea02501fe35e380bd2b8974',
"elementIdentifier": "given_name",
"elementValue": "Inga"
}
>>),
24(<<
{
"digestID": 5,
"random": h'c8fb86f4dd1fb6f658c5854a193073f4',
"elementIdentifier": "birth_date",
"elementValue": 1004("1991-11-06")
}
>>),
24(<<
{
"digestID": 6,
"random": h'22655e9974500c618a237d0704a72de0',
"elementIdentifier": "issuing_country",
"elementValue": "US"
}
>>),
24(<<
{
"digestID": 7,
"random": h'6d6cff820531cad49ac7bfc5a82ce810',
"elementIdentifier": "document_number",
"elementValue": "12345678"
}
>>),
24(<<
{
"digestID": 8,
"random": h'5b4b03a0f7594cb29bbf72d05adaeaa0',
"elementIdentifier": "driving_privileges",
"elementValue": [
{
"vehicle_category_code": "A",
"issue_date": 1004("2023-01-01"),
"expiry_date": 1004("2043-01-01")
}
]
}
>>)
]
},
"issuerAuth": [
h'a10126',
{
33: h'3082015d30820104a0030201020206018c91d9c219300a06082a8648ce3d04030230363134303206035504030c2b4a3146774a50383743362d514e5f5753494f6d4a415163366e3543515f625a6461464a3547446e5731526b301e170d3233313232323134303635365a170d3234313031373134303635365a30363134303206035504030c2b4a3146774a50383743362d514e5f5753494f6d4a415163366e3543515f625a6461464a3547446e5731526b3059301306072a8648ce3d020106082a8648ce3d03010703420004028a5579ba09a58472730d582a49113977c2a4a10a97d63560f1613868f8c5383650eba7c53c52215913f78a85548baed61904a04d8dc5e959a37fb24c550e0c300a06082a8648ce3d040302034700304402206716349c05cbc446578b8cc0aee4d6f124a90db1afe04219174df0e66eaf93de022055acdbb15750bd9825b9cf672584315a5cd74fd8ba7fec2050ac7428261b8f70'
},
24(<<
{
"version": "1.0",
"digestAlgorithm": "SHA-256",
"valueDigests": {
"org.iso.18013.5.1": {
1: h'ab92f0509e09cbc333066011eceeb95bfe0d8b14a5dca9269f5a6c9aea1c0997',
2: h'bbb0fedefafe36b2e0df38a0ba753310a16a600c86e6c03e7dfbe60e3471676e',
3: h'b63819e1a19161a84eecf0f45f75e8fcb797eba7e1e017fd97e2a32dcef118e8',
4: h'117fae5f77551db5ba69087523225aa1664f9271b349f71f9496a275ab2680eb',
5: h'283bd5c8c537e7c2ded27e939156f673405b85b48c270a6cc2d3cb36266b4d1f',
6: h'056732700269c2ed070c430abbd850d09663f1934e37e1c65b87afebb7555a81',
7: h'7c011d0dfeb153ed728f9171486e618aba8a2bee8e36322664016d0fce761143',
8: h'7234f61d8824a319f058ffbd8ea3bfebe0fe77af47f545b6c63a435ab92796f0'
}
},
"docType": "org.iso.18013.5.1.mDL",
"validityInfo": {
"signed": 0("2024-01-12T00:10:05Z"),
"validFrom": 0("2024-01-12T00:10:05Z"),
"validUntil": 0("2025-01-12T00:10:05Z")
}
}
>>),
h'717311bd3d345c85963e77dc513fd41f48dab92ef742b9d9aafae087750b23945d65f384835e55fa0953571fc60093d825f5dfaf5c19dfd34314a3855c7c6e96'
]
}
}

When applying syntax highlighting, the decoded mdoc looks like the following.

Implementation Experiments

In Europe, the following consortia have been formed, and large-scale experiments (called Large Scale Pilots) related to digital identity wallets are being conducted.

Within the OpenID Foundation, the GAIN POC Community Group is conducting experiments with OID4VCI. My company, Authlete, is also participating in the GAIN POC and providing a credential issuer implementation that complies with the OID4VCI specification.

In Japan, under the leadership of the Trusted Web Promotion Council, several proof-of-concept experiments are underway to implement Verifiable Credential-related standard specifications such as OID4VCI.

Detailed Explanation of OID4VCI Specification

On Authlete’s website, there is a detailed explanation of the OID4VCI specification, so please refer to it. Probably, there won’t be a more detailed explanatory document released in the future than this.

Finally

For the following reasons, I believe the demo of successfully issuing SD-JWT VC and mdoc/mDL simultaneously with a batch credential request was the world’s first:

  1. A significant number of specification changes were made at the end of 2023 (and more changes were made in January 2024, too).
  2. Support for the batch credential endpoint is optional.
  3. SD-JWT VC is a new verifiable credential format.
  4. Detailed specifications of mdoc/mDL can only be known by purchasing the ISO document.

Working diligently on the implementation of Verifiable Credential-related specifications, I was invited as a speaker to the ‘2nd International Workshop on Trends in Digital Identity’ (TDI 2024) scheduled to be held in Rome, Italy on April 9th, 2024. I will be sharing insights gained from implementation experience during the event.

Following TDI 2024, there will be the OAuth Security Workshop 2024 (OSW 2024) held in the same location from April 10th to 12th. As Dr. Daniel Fett, the organizer of OSW, joined Authlete in April 2023, Authlete will once again serve as the main sponsor for OSW, as it did last year at OSW 2023.

With Daniel contributing to the specifications of SD-JWT and SD-JWT VC, and Joseph taking on roles such as a director at the OpenWallet Foundation and co-chair of the Digital Credentials Protocols (DCP) Working Group, Authlete has found itself deeply involved in the realms of digital identity wallets and verifiable credentials. If you are interested in this field, feel free to contact Authlete!

--

--

Takahiko Kawasaki

Co-founder and representative director of Authlete, Inc., working as a software engineer since 1997. https://www.authlete.com/