JLINC DID Method Specification

version 2 - July 22, 2024

Abstract

This document specifies a method for creating and editing Decentralized IDs (DIDs). It conforms to the requirements specified in the DID specification currently published by the W3C Credentials Community Group.

Our goal is to provide a DID method that allows for key rotation and agent delegation. We achieve compactness by relying on convention over configuration, with key types, hashing algorithms and signing procedures defined in the version specification, so as to eliminate the need for verbose and redundant stanzas in the individual DID documents.

The did:jlinc method defines a key rotation technique as well as the operations required by DID Core. A relying party may resolve DIDs using HTTPS, without having to have recourse to any “universal” resolver service.

We acknowledge with gratitude ideas from did:web and from KERI that partly inspired this effort.

© Portable Data Corporation 2024

Table of Contents

  1. Notation and Conventions
  2. Definitions
  3. Overview
  4. Method Name
  5. Format
    5.1. DID document schema
    5.2. Example
  6. Operations
    6.1. Inception (creation)
    6.1.1 Inception via agent
    6.1.2 JWS header
    6.1.3 JWS payload
    6.1.4 JWS signature
    6.2. Resolution
    6.3. Update
    6.4. Revoke
  7. Security Considerations
  8. Privacy Considerations

1. Notation and Conventions

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

2. Definitions

3. Overview

This specification defines the JLINC methods for creating, resolving and modifying DID documents.

4. Method Name

The namestring that shall identify the JLINC DID method is: jlinc.

A DID that uses this method MUST begin with the following prefix: did:jlinc. Per the DID specification, this string MUST be in lowercase.

5. Format

The JLINC DID has the following ABNF format:

jlinc-did = "did:jlinc:" host ":" id-string
host = * host-char
id-string = 1* idchar
host-char = ALPHA / DIGIT / "-" / "."
idchar    = ALPHA / DIGIT / "." / "-" / "_" / pct-encoded
pct-encoded = "%" HEXDIG HEXDIG

The idchar consists of the characters in the BASE64 UrlSafe character set defined in RFC 4648 as base64url without padding.

5.1. DID document schema

The DID document MUST contain the following properties:

@context: the array [“https://www.w3.org/ns/did/v1”, “https://didspec.jlinc.io/v1/ctx.jsonld”]

version: a string in the semantic versioning format

instance: an integer denoting the position of this DID document in the array of updates. The inception DID doc is instance 0.

id: the jlinc DID that is the subject of this document

incp: an ISO 8601 formatted timestamp with milliseconds denoting the DID’s inception time

modf: an ISO 8601 formatted timestamp with milliseconds denoting the DID’s modification time, optional unless DID has been modified

actv: an object, containing at least - {sign: ***, ctrl: ***} - denoting the active signing and control keys

next: an object, containing at least - {ctrl: ***} - denoting hash of the next control key in key rotation

prev: an object containing at least - {sign: ***, ctrl: ***, end: *** } - denoting the most recently superseded signing and control keys and an ISO 8601 formatted timestamp with milliseconds denoting the time the keys were superseded, optional unless DID has been superseded

The document MAY contain a service property conforming to the DID core specification

5.2. Example

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://didspec.jlinc.io/v2.1/ctx.jsonld"
  ],
  "version": 3.0.0,
  "instance": 0,
  "id": "did:jlinc:did.jlinc.io:be54d07f06f2b70f04a24c1133ee4bcb",
  "incp": "2023-03-12T19:33:16.643Z",
  "actv": {
    "sign": "MzoJvNtBNX4b5xltYpdBk07ztb2OyxMiKqOnRdWRGSc",
    "ctrl": "HccjhsDiu7QNg_8ehFvTqroV5NTV1Cuk-TeMjn99tBY"
  },
  "next": {
    "ctrl": "kco5Oz6GKeoe6jqu-Xd8my_MzbWZIhYrK8t5ODwLNBU"
  },
  "service": [
    {
      "id": "did:jlinc:did.jlinc.io:be54d07f06f2b70f04a24c1133ee4bcb#linked-domain",
      "type": "LinkedDomains",
      "serviceEndpoint": "https://link.example.com"
    }
  ]
}

6. Operations

Version 3.0.0 of this DID method requires signing and controller keys be of type ED25519. Hashes must be of type SHA256. All hashes and keys are represented in Base64 format. The ID string of the DID is formed as follows:

IDstring = hash([actv:ctrlPubkey, actv:signPubkey, next:hash(ctrlPubkey)])

That is, a hash of an array consisting of the ‘active’ controller public key, the ‘active’ signing public key, and a hashed ’next’ controller public key.

6.1. Inception (DID creation)

First create an object in accordance with the schema above, and add in any other desired properties. If a service section is desired it SHOULD conform to the DID core spec for that section.

The signing and controlling keys, as well as the nextsigning and nextcontrolling keys are the public key portions of the result of:

{publickey, privatekey} = createKeypair()

All of the private keys SHOULD be carefully persisted. In particular the next private keys SHOULD be persisted in the most secure manner possible.

The signing and controlling public keys and the hashes of the “next” public keys are then entered into the document as described above.

Once complete, the object MUST be encoded into JSON.

The next inception step depends on whether the DID document is being sent directly to the storage from where it will be made available, i.e. the DID controller is acting as their own agent, or alternatively the DID document is being transmitted to an agent for storage and retrieval.

If the DID controller is acting as their own agent, then they must include a signing public key in the document, and implement whatever procedure is required to create and/or update documents on the desired storage resource, and form the URL portion of the DID to point to the resolver address.

If the controller is acting via an agent, the agent MUST implement the following procedure.

6.1.1 Inception via agent

If the DID document is being transmitted to an agent, then rather than transmitting the document in raw JSON form, it SHOULD be encapsulated in a JWS as described below.

6.1.2 JWS header

The JWS header MUST take the following form, with each field being required:

Property Value
alg One of the values described in JWS Web Algorithms or JWA Elliptic Curve.
NB: The “none” algorithm type MUST NOT be used.
typ The string “JWT”
jwk A JSON web key as described in JWK. Care should be taken not to include any private key material.
The JWK SHOULD include a “kid” field which SHOULD be set to the DID id value.
The public key represented in the JWK MUST be that of the DID controller.

Example:

alg: 'EdDSA',
typ: 'JWT',
jwk: {
  kty: 'OKP',
  crv: 'Ed25519',
  x: 'HccjhsDiu7QNg_8ehFvTqroV5NTV1Cuk-TeMjn99tBY',
  kid: 'did:jlinc:did.jlinc.io:k-c_YNhjMkTtyPcCsfbks4VYRTQWyQfZf5XBhQQtsXU'
}

6.1.3 JWS payload

The JWS payload MUST include the JWT standard properties “iss” (issuer identified as a DID), “iat” (issuance date/time in ISO 8601 format), and “jti” (JWT ID - a unique ID, MAY be a UUID). Other JWT standard properties MAY be included.

Two non-standard properties MUST be included:

  1. an “action” property that instructs the recipient what action is intended by the agent.
    This value MUST be one of “register”, “update”, or “revoke”.
  2. a “diddoc” property containing the DID document to be registered, updated or revoked, in JSON format.

Example:

iss: 'did:jlinc:did.jlinc.io:k-c_YNhjMkTtyPcCsfbks4VYRTQWyQfZf5XBhQQtsXU',
iat: '2023-03-12T19:33:16.643Z',
jti: '542beb17-8646-4088-a673-aed748c26771',
action: 'register',
diddoc: '{...}'

6.1.4 JWS signature

The JWS signature MUST be created with the DID controller’s private key as represented in both the DID document and the header JWK. The recipient SHOULD verify that these are both the same corresponding public key, as well as of course that the signature is valid.

6.2. Resolution

For content-addressed schemes, for example IPFS, the idchar is all that is necessary for resolution.

In the case of the https scheme, the “h:” is transformed to “https://” and subsequent colons are replaced with “/” characters to form the GET request URL. The responding server MAY return the raw JSON object representing the DID document, in which case it should use the standard HTTP content-type header “application/json”.

The responding server MAY instead return a signed JWS object encapsulating the JSON formatted DID document, signed by the “well-known” key of the responding server. In this case, the JWS SHOULD be formatted as described in 6.1.2 and 6.1.3 above, but with the “action” property replaced with “status” which MUST be one of “valid”, “updated” or “revoked”, and the “iat” property SHOULD represent the date/time at which the current status was established. For the HTTP content-type header it is recommended to use “application/jose”.

6.3 Update

Updates may include key rotation and/or updates to the service section or other parameters. The method is the same as described in 6.1 except that the “action” value MUST be “update”. In the case of a key rotation event, the JWS MUST be signed with the “next” controller key.

6.4 Revoke

The revocation method is the same as described in 6.1 except that the “action” value MUST be “revoke”. In the case of an agent initiated action, the JWS MUST be signed with the “next” controller key.

7. Security Considerations

All private keys must be held via secure methods, in particular the controller private keys which are used to make updates to the DID document, and most particularly the “next” private key which is required in order to rotate the DID’s keys in the event of a security breach. It is recommended that, if possible, the “next” private key be held securely offline until use.

It should be noted that as a basic principle of asymmetric key security, the private or secret key portion of any key pair should never be transmitted over the network. The security of this DID method rests on this principle, and experience has shown that implementers may inadvertently violate it in subtle ways.

Care must be taken that secret keys either do not and cannot leave the device on which they were created, or only do so in ways that do not involve remote networks (e.g. by printing out a representation of the key for archiving, or saving to local removable storage).

8. Privacy Considerations

In order to avoid cross-party correlation and subsequent breach of pseudonymity, it is recommended, use-case permitting, that a new pair-wise DID be created by each party for each relationship that they enter into using DIDs.

Privacy and confidentiality are often conflated, to the detriment of good design. Privacy measures such as access control as well as metadata control, which are implied in the anti-correlation measures mentioned above, are of course required, and implementers must carefully consider these requirements.

Additionally, this DID method was designed with the JLINC protocol in mind, and in particular to support the principle of Chain-Link Confidentiality as outlined in the seminal paper outlining that subject by Professor Woodrow Hartzog.