§ Trust DID Web - did:tdw
Specification Status: DRAFT
Latest Draft: https://github.com/bcgov/trustdidweb
- Editors:
- Stephen Curran
- John Jordan, BC Gov
- Andrew Whitehead
- Brian Richter
- Participate:
- GitHub repo
- File a bug
- Commit history
§ Abstract
The did:tdw
(Trust DID Web) method is an enhancement to the
did:web
protocol, providing a complementary web-based DID method that addresses limitations
of did:web
. Its features include:
- Ongoing publishing of all DID Document (DIDDoc) versions for a DID instead of,
or alongside a
did:web
DID/DIDDoc. - The same DID-to-HTTPS transformation as
did:web
. - The ability to resolve the full history of the DID using a verifiable chain of updates to the DIDDoc from genesis to deactivation.
- A self-certifying identifier (SCID) for the DID that is globally unique, embedded in the DID, and derived from the initial DIDDoc. The SCID enables DID portability, such as moving the DID’s web location (and so changing the DID string itself) while retaining a connection to the predecessor DID(s) and the DID’s verifiable history.
- DIDDoc updates include a proof signed by the DID Controller(s) authorized to update the DID.
- An optional mechanism for publishing “pre-rotation” keys to prevent the loss of control of a DID in cases where an active private key is compromised.
- DID URL path handling that defaults (but can be overridden) to automatically
resolving
<did>/path/to/file
by using a comparable DID-to-HTTPS translation as for the DIDDoc. - A DID URL path
<did>/whois
that defaults to automatically returning (if published by the DID controller) a Verifiable Presentation containing Verifiable Credentials with the DID as thecredentialSubject
, signed by the DID.
Combined, the additional features enable greater trust and security without
compromising the simplicity of did:web
. The incorporation of the DID Core
compatible “/whois” path, drawing inspiration from the traditional WHOIS
protocol [RFC3912], offers an easy-to-use, decentralized, trust registry.
The did:tdw
method aims to establish a more trusted and secure web environment by
providing robust verification processes and enabling transparency and
authenticity in the management of decentralized digital identities.
§ Definitions
- DID Log
- A log of JSON arrays each of which provides the information necessary to generate and validate a version of the DIDDoc from the previous version.
- JSON Lines
- A file of JSON Lines, as described on the site
https://jsonlines.org/. In short,
JSONL
is lines of JSON with whitespace removed and separated by a newline that is convenient for handling streaming JSON data or log files. - self-certifying identifier
- An object identifier derived from initial data such that an attacker could not
create a new object with the same identifier. The input for a
did:tdw
SCID is the initial DIDDoc with the placeholder{SCID}
wherever the SCID is to be placed. - parameters
did:tdw
parameters are a defined set of configurations that control how the issuer has generated the DID, and how the resolver should process the DID Log entries. The use of parameters allows for the controlled evolution ofdid:tdw
log handling, such as evolving the permitted hash algorithms.- ISO8601
- A date/time expressed using the ISO8601 Standard.
- DID Controller
- Per the [DID-CORE], a DID controller is an entity that is authorized to make changes to a DID document.
- Entry Hash
- A
did:tdw
entry hash is a hash generated using a formally defined process over the data of a log entry. The generated entry hash is subsequently put into the log entry and MUST be verified by a resolver. - Data Integrity
- W3C Data Integrity is a specification of mechanisms for ensuring the authenticity and integrity of structured digital documents using cryptography, such as digital signatures and other digital mathematical proofs.
- JSON Patch
- [RFC6902] is a web
standard format for describing how to change a JSON document from one state to
another. It is used in
did:tdw
to define how a DIDDoc is changed from one version to the next. - Key Pre-Rotation
- A technique for a controller of a cryptographic key to commit to the next public key that it will use for a purpose, without exposing the public key. It protects from an attacker that gains knowledger of the current private key from being able to rotate to a new key the controller does not know.
- DID Log Entry
- A DID Log Entry is a JSON array of items that define the authorized transformation of a DIDDoc from one version to the next. The initial entry establishes the DID and version 1 of the DIDDoc.
DID Portability
did:tdw
portability encompasses the ability to change the DID string for the
DID while retaining the SCID and the history of the DID. This is useful
when forced to change (such as when an organization is acquired by another,
resulting in a change of domain names) and when changing DID hosting service
providers.
- base32_lower
- Applies [RFC4648] to convert
data to a
base32
encoding, and then lower cases the result. Data encoded as base32 consists of a string of characters containing only the letters A-Z and digits 2-7. - Linked-VP
- A [DID-CORE]
service
entry that specifies where a verifiable presentation about the DID subject can be found. The Decentralized Identity Foundation hosts the Linked VP Specification. - Verifiable Credential
- A verifiable credential can represent all of the same information that a physical credential represents, adding technologies such as digital signatures, to make the credentials more tamper-evident and so more trustworthy than their physical counterparts. The Verifiable Credential Data Model is a W3C Standard.
- Verifiable Presentation
- A verifiable presentation data model is part W3C’s Verifiable Credential Data
Model that contains a set of verifiable credentials about a
credentialSubject
, and a signature across the set of VCs generated by that subject. In this specification, the use case of primary interest is where the DID is thecredentialSubject
and the DID signs the verifiable presentation. - JSON Canonicalization Scheme
- The [RFC8785] canonicalizes a JSON structure such that is suitable for verifiable hashing or signing.
- Decentralized Identifier
- Decentralized Identifiers (DIDs) [DID-CORE] are a type of identifier that enable verifiable, decentralized digital identities. A DID refers to any subject (e.g., a person, organization, thing, data model, abstract entity, etc.) as determined by the controller of the DID.
- DID Method
- DID methods are the mechanism by which a particular type of DID and its
associated DID document are created, resolved, updated, and deactivated. DID
methods are defined using separate DID method specifications. This document is
the DID Method Specification for
did:tdw
. - Verifiable Conditions
- The (proposed) verifiableConditions Specification defines a way to express complex conditions and additional metadata about verification methods. It can be used to combine verification methods to form conjugated conditions such as logical operations (like &&), thresholds, weighted thresholds, relationships, or delegation to external verification methods.
- multi-sig
- A cryptographic signature that to be valid MUST contain a defined threshold (for example, 4 of 7) individual signatures to be considered valid. The multi-signature key reference points to a verification method that defines what keys may contribute to the signature, and under what conditions the multi-signature is considered valid.
§ Overview
The evolution of Decentralized Identifiers (DID) continues to
be a dynamic area of development in the quest for secure and private digital
identity management. The did:web
method, praised for its simplicity and ease
of deployment, allows for DIDs to be associated with a domain’s reputation or
published on platforms such as GitHub. However, it is not without its challenges–
from trust layers inherited from the web and the absence of a verifiable history
for the DID. Addressing these concerns, the proposed did:tdw
(Trust DID Web)
method aims to enhance did:web
by introducing a verifiable history feature,
akin to what is available with ledger-based DIDs, without relying on a ledger.
This approach not only maintains backward compatibility but also offers an
additional layer of assurance for those requiring more robust verification
processes. By publishing the resulting DID as both did:web
and did:tdw
, it
caters to a broader range of trust requirements, from those who are comfortable
with the existing did:web
infrastructure to those seeking greater security
assurances provided by did:tdw
. This innovative step represents a significant
stride towards a more trusted and secure web, where the integrity of
cryptographic key publishing is paramount.
The key differences between did:web
and did:tdw
revolve around the core
issues of decentralization and security. did:web
is recognized for its
simplicity and cost-effectiveness, allowing for easy establishment of a
credential ecosystem. However, it is not inherently decentralized as it relies
on DNS domain names, which require centralized registries, and it lacks a
cryptographically verifiable, tamper-resistant, and persistently stored DID
document. In contrast, did:tdw
(Trust DID Web) is proposed as an enhancement
to did:web
, aiming to address these limitations by adding a verifiable history
to the DID without the need for a ledger. This method seeks to provide a more
decentralized approach by ensuring that the security of the embedded
self-certifying identifier does not depend on DNS. Additionally, did:tdw
is
capable of resolving a cryptographically verifiable trust registry and status
lists, using DID-Linked Resources, which did:web
lacks. These features are
designed to build a trusted web, offering a higher level of assurance for
cryptographic key publishing and management.
For backwards compatibility, and for verifiers that “trust” did:web
, a
did:tdw
can be trivially modified and published in parallel to a did:web
DID. For resolvers that want more assurance, did:tdw
provides a way to “trust
did:web” (or to enable a “trusted web” if you say it fast) enabled by the
features listed in the Abstract.
The following is a tl;dr
summary of how did:tdw
works:
did:tdw
uses the same DID-to-HTTPS tranformation asdid:web
, sodid:tdw
’sdid.jsonl
(JSON Lines) file is found in the same location asdid:web
’sdid.json
file.- The
did.jsonl
is a list of JSON DID log entries, one per line, whitespace removed (per JSON Lines), each of which contains the information needed to derive a version of the DIDDoc from its preceding version. - Each entry includes six JSON entries:
- A hash of the entry.
- The
versionId
of the DIDDoc, starting from 1 and incrementing. - The
versionTime
(as stated by the DID Controller) of the entry. - A set of
parameters
that impact the processing of the current and future log entries.- Example parameters are the version of the
did:tdw
specification and hash algorithm being used.
- Example parameters are the version of the
- The new version of the DIDDoc as either a
value
(the full document) or apatch
derived using JSON Patch to update the new version from the previous entry. - A Data Integrity (DI) proof across the entry, signed by a DID Controller authorized to update the DIDDoc.
- In generating the first version of the DIDDoc, the DID Controller calculates
the SCID for the DID, includes it as a
parameter
in the first log entry, and inserts it where needed in the initial (and all subsequent) DIDDocs. - A DID Controller generates and publishes the updated log file by making it available at the appropriate location on the web, based on the identifier of the DID.
- Given a
did:tdw
DID, a resolver converts the DID to an HTTPS URL, retrieves, and processes the log filedid.jsonl
, generating and verifying each log entry as per the requirements outlined in this specification.- In the process, the resolvers may collect all the DIDDoc versions and public keys (by reference) used by the DID currently, or in the past. This enables resolving both current and past DID URLs.
did:tdw
DID URLs with paths and/whois
are resolved to documents published by the DID Controller that are by default in the web location relative to thedid.jsonl
file. See the note below about the powerful capability enabled by the/whois
DID URL path.- Optionally, a DID Controller can generate and publish a
did:web
DIDDoc from the latestdid:tdw
DIDDoc by changing theid
to thedid:web
DID, and adding analsoKnownAs
for thedid:tdw
(indicating to a resolver that they can verify the DIDDoc, if wanted).
A resolver settling for just the `did:web` version of the DID does not get the
verifiability of the `did:tdw` log.
An example of a did:tdw
evolving through a series of versions can be seen in
the did:tdw Examples of this specification.
This draft specification was developed in parallel with the development of two
proof of concept implementations. The specification/implementation interplay
helped immensely in defining a practical, intuitive, straightforward, DID
method. The existing proof of concept implementations of the did:tdw
DID
Method are listed in the Implementors Guide. The current
Typescript implementation is less than 1000 lines of Typescript code.
§ The /whois
Use Case
This DID Method introduces what we hope will be a widely embraced convention for
all DID Methods – the /whois
path. This feature harkens back to the WHOIS
protocol that was created in the 1970s to provide a directory about people and
entities in the early days of ARPANET. In the 80’s, whois
evolved into
[RFC920] that has expanded into the global
whois feature we know today as
[RFC3912]. Submit a whois
request about a domain name, and get
back the information published about that domain.
We propose that the /whois
path for a DID enable a comparable, decentralized,
version of the WHOIS
protocol for DIDs. Notably, when <did>/whois
is
resolved (using a standard DID service
that follows the Linked-VP
specification), a Verifiable Presentation (VP) may be returned (if
published by the DID Controller) containing Verifiable Credentials with
the DID as the credentialSubject
, and the VP signed by the DID. Given a DID,
one can gather verifiable data about the DID Controller by resolving
<did>/whois
and processing the returned VP. That’s powerful – an efficient,
highly decentralized, trust registry. For did:tdw
, the approach is very simple
– transform the DID to its HTTPS equivalent, and execute a GET <https>/whois
.
Need to know who issued the VCs in the VP? Get the issuer DIDs from those VCs,
and resolve <issuer did>/whois
for each. This is comparable to walking a CA
(Certificate Authority) hierarchy, but self-managed by the DID Controllers –
and the issuers that attest to them.
The following is a use case for the /whois
capability. Consider an example of
the did:tdw
controller being a mining company that has exported a shipment and
created a “Product Passport” Verifiable Credential with information about the
shipment. A country importing the shipment (the Importer) might want to know
more about the issuer of the VC, and hence, the details of the shipment. They
resolve the <did>/whois
of the entity and get back a Verifiable Presentation
about that DID. It might contain:
- A verifiable credential issued by the Legal Entity Registrar for the
jurisdiction in which the mining company is headquartered.
- Since the Importer knows about the Legal Entity Registrar, they can automate this lookup to get more information about the company from the VC – its legal name, when it was registered, contact information, etc.
- A verifiable credential for a “Mining Permit” issued by the mining authority
for the jurisdiction in which the company operates.
- Perhaps the Importer does not know about the mining authority for that
jurisdiction. The Importer can repeat the
/whois
resolution process for the issuer of that credential. The Importer might (for example), resolve and verify thedid:tdw
DID for the Authority, and then resolve the/whois
DID URL to find a verifiable credential issued by the government of the jurisdiction. The Importer recognizes and trusts that government’s authority, and so can decide to recognize and trust the mining permit authority.
- Perhaps the Importer does not know about the mining authority for that
jurisdiction. The Importer can repeat the
- A verifiable credential about the auditing of the mining practices of the
mining company. Again, the Importer doesn’t know about the issuer of the audit
VC, so they resolve the
/whois
for the DID of the issuer, get its VP and find that it is accredited to audit mining companies by the London Metal Exchange according to one of its mining standards. As the Importer knows about both the London Metal Exchange and the standard, it can make a trust decision about the original Product Passport Verifiable Credential.
Such checks can all be done with a handful of HTTPS requests and the processing of the DIDs and verifiable presentations. If the system cannot automatically make a trust decision, lots of information has been quickly collected that can be passed to a person to make such a decision.
The result is an efficient, verifiable, credential-based, decentralized, multi-domain trust registry, empowering individuals and organizations to verify the authenticity and legitimacy of DIDs. The convention promotes a decentralized trust model where trust is established through cryptographic verification rather than reliance on centralized authorities. By enabling anyone to access and validate the information associated with a DID, the “/whois” path contributes to the overall security and integrity of decentralized networks.
§ did:tdw DID Method Specification
§ Target System
The target system of the Trust DID Web (TDW) DID method is the host (or domain) name when the domain specified by the DID is resolved through the Domain Name System (DNS).
§ Method Name
The namestring that identifies this DID method is: tdw
. A DID that uses this
method MUST begin with the following prefix: did:tdw
. Per the DID
specification, this string MUST be in lowercase. The remainder of the DID, after
the prefix, is the method-specific identifier,
specified below.
§ Method-specific Identifier
The method specific identifier is a fully qualified domain name that is secured by a TLS/SSL certificate with an optional path to the DID Log. The identifier MUST contain a self-certifying identifier (SCID) as either part of the subdomain component of the domain name, or as a component of the optional path. The content of the SCID is generated in creating the DID. The formal rules describing valid domain name syntax are described in [RFC1035], [RFC1123], and [RFC2181].
The domain name component of the method specific identifier MUST match the common name used in the SSL/TLS certificate, and it MUST NOT include IP addresses. A port MAY be included and the colon MUST be percent encoded to prevent a conflict with paths. Directories and subdirectories MAY optionally be included, delimited by colons rather than slashes.
The SCID, a globally unique identifier, is generated as part of the creation of the DID and placed into the DID identifier.
As specified in the following Augmented Backus-Naur Form (ABNF) notation
[RFC2234] the SCID MUST be present in the DID string, but
may be placed in the (optional) subdomain component of the domain, or as a
segment in the (optional) URL path. See examples below. The domain-segment
and
path-segment
elements refer to [RFC3986]’s ABNF for a Generic URL (page
49). Attempting to replicate here the full ABNF of those elements from that RFC
would inevitably be wrong.
tdw-did = "did:tdw:" *( domain-segment “.” ) scid 2*( “.” domain-segment ) *( ":" path-segment )
tdw-did = "did:tdw:" 2*( domain-segment “.” ) *( ":" path-segment ) (":" scid ) *( ":" path-segment )
domain-segment = ; A part of a domain name as defined in RFC3986, such as "example" and "com" in "example.com"
path-segment= ; A part of a URL path as defined in RFC3986, such as "path", "to", "folder" in "path/to/folder"
scid = 28+( lower-base32 )
lower-base32 = [2-7a-z]
did:tdw
DIDs and the corresponding web locations for their did:tdw
log file.
{SCID}
is a placeholder for where the generated SCID will be placed in the
examples.
subdomain
did:tdw:{SCID}.example.com
-->
https://{SCID}.example.com/.well-known/did.jsonl
path
did:tdw:example.com:dids:{SCID}
-->
https://example.com/dids/{SCID}/did.jsonl
path w/ port
did:tdw:example.com%3A3000:dids:{SCID}
-->
https://example.com:3000/dids/{SCID}/did.jsonl
The location of the did:tdw
did.jsonl
DID Log file is the same as
where the comparable did:web
did.json
file is published. A DID MAY choose to publish both DIDs and so both files.
§ DID Method Operations
§ Create (Register)
Creating a did:tdw
DID is done by carrying out the following steps.
- Define the DID string, and hence, the web location at which the DID Log
(
did.jsonl
) will be published. Identify (using the placeholder{SCID}
) where the required SCID will be placed in the DID string (ie.did:tdw:example.com:{SCID}
). - Create the initial DIDDoc (
did.json
) file for the DID, with whatever content is required. Wherever there is self-reference to the DID in the DIDDoc, use the absolute form defined in step 1, with the identified placeholder for the SCID (ie.did:tdw:example.com:{SCID}#key-1
).- As per Authorized Keys, the DIDDoc MUST contain at
least one
authentication
orverificationMethod
key type.
- As per Authorized Keys, the DIDDoc MUST contain at
least one
- Define a JSON array of valid parameters that affect the generation of the DID. The DID Generation and Validation Parameters section of this specification defines the permitted parameters.
- Pass the DID string, initial DIDDoc, and parameters to a
did:tdw
“Create” implementation that MUST:- Calculate the SCID for the DID as defined in the SCID Generation and Validation section of this specification.
- Replace in the DIDDoc the placeholder for the SCID
{SCID}
with the calculatedSCID
. - Generate a DID Entry as a JSON array with the following five JSON items:
- The SCID as the
entryHash
value:"4c99uuenu8gk6n3bgf09fuf350gx"
- An integer,
1
, that is the versionId for this first version of the DIDDoc:1
- A string that is the current time in ISO8601 format:
"2024-04-04T07:32:58Z"
- The parameters passed in as a JSON dict:
{"method":"did:tdw:1","scid":"4c99uuenu8gk6n3bgf09fuf350gx"}
- The contents of the initial DIDDoc, in the form:
{"value": <DIDDoc>}
- The SCID as the
- Calculate the Entry Hash (
entryHash
) of the DID Entry as defined in the Entry Hash Generation and Validation section of this specification. - Update the
entryHash
with the value produced in the previous step. - Generate a Data Integrity proof on the initial DIDDoc using an
authorized key from the DID, and the
entryHash
as the proofchallenge
. The definition of “authorized” in this case is specified in the Authorized Keys section of this specification. The proof becomes the sixth and last JSON item in the DID log entry. - Put the resulting entry, with extraneous white space removed as the
contents of a file
did.jsonl
and publish the file at the appropriate location defined by thedid:tdw
value.- This is a logical operation – how a deployment serves the
did.jsonl
content is not constrained.
- This is a logical operation – how a deployment serves the
A controller MAY generate an equivalent did:web
DIDDoc and publish it as
defined in the Publishing a Parallel did:web
DID section of this specification. The
did:web
DIDDoc could be used for backwards compatibility as a transition is
made from did:web
to did:tdw
. Verifiers using the did:web
lose the
verifiable properties and history of the did:tdw
for the convenience of the
simple retrieval of the did:web
DIDDoc.
§ Read (Resolve)
The following steps MUST be executed to resolve the DIDDoc for a did:tdw
DID:
- Replace
:
with/
in the method specific identifier to obtain the fully qualified domain name and optional path. - If the domain contains a port percent decode the colon.
- Generate an HTTPS URL to the expected location of the DIDDoc by prepending
https://
. - If no path has been specified in the URL, append
/.well-known
. - Append
/did.jsonl
to complete the URL. - Perform an HTTP GET request to the URL using an agent that can successfully negotiate a secure HTTPS connection, which enforces the security requirements as described in Security and privacy considerations.
- When performing the DNS resolution during the HTTP GET request, the client SHOULD utilize [RFC8484] in order to prevent tracking of the identity being resolved.
- Process the DID Log file as described below.
To process the retrieved DID Log file, the resolver MUST carry out the following steps:
- Process the Log entries in the order they appear in the file, applying the
parameters set on current and previous entries. As noted in the
Create (Register), each log entry consists of a JSON
array of 6 items:
entryHash
versionId
versionTime
parameters
- DIDDoc content – either the full
value
or a JSON Patchpatch
to be applied to the prior version of the DIDDoc. - A Data Integrity proof for the current version of the DIDDoc of the entry.
- For each entry:
- Update the currently active parameters with the parameters from the entry (if any). Continue processing using the now active set of parameters.
- Verify the Data Integrity proof in the entry, and ensure it is signed by an authorized key as defined in the Authorized Keys section of this specification.
- Verify the
entryHash
for the entry using the process defined in the Entry Hash Generation and Verification section of this specification. - Verify that the first log entry’s
versionId
is1
, and that theversionId
is incremented by one for each subsequent log entry. - Verify that the
versionTime
for each log entry is greater than the previous entry, and that theversionTime
values are all earlier than the current time. - For the initial version of the DIDDoc (
1
) verify that the SCID (defined in the parameters) is being used in the DID, and verifies according to the SCID Generation and Verification section of this specification. - Generate the version of the DIDDoc for the entry by using the JSON value
of the
value
item, or by using JSON Patch to apply the JSON value of thepatch
entry item to the previous version of the DIDDoc. - If Key Pre-Rotation is being used, verify that any added keys in the DIDDoc have a valid pre-rotation entry as defined in the Key Pre-Rotation Hash Generation and Verification section of this specification.
- Once each log entry has been processed, collect the following information
about each version:
- DIDDocument
versionId
versionTime
On completing the processing of all entries in the DID Log, respond to
the DID resolution request, including the application of query parameters such
as ?versionId=
and ?versionTime=
with the appropriate DIDDoc version.
The following error codes and descriptions may be returned when resolving a DID.
Document the full list of error codes that can be generated in resolving a DID.
- Code 404: The
did:tdw
DID Log filedid.jsonl
was not found.
§ Reading did:tdw DID URLs
A did:tdw
resolver MAY implement the resolution of the /whois
and a DID
URL Path using the whois LinkedVP Service and DID
URL Path Resolution Service as defined in
this specification by processing the DID Log and then dereferencing the
DID URL based on the contents of the DIDDoc. The client of a resolver that does
not implement those capabilities must use the resolver to resolve the
appropriate DIDDoc, and then process the resulting DID URLs themselves. Since
the default DID-to-HTTPS URL transformation is trivial, did:tdw
DID are strongly encouraged to use the default behavior for DID URL
Path resolution.
§ Update (Rotate)
To update a DID a new, verifiable DID Log Entry must be generated,
appended to the existing DID Log (did.jsonl
) and published to the
web location defined by the DID. The process to generate a verifiable DID follows a similar process to the Create process,
as follows:
- Make the desired changes to the DIDDoc. While the contents of a new DIDDoc
version are (mostly) up to the DID controller, there are some limitations:
- The
id
of the DIDDoc MAY be changed when the DID Controller wants to (or must) publish the DID at a different location and wants to retain the SCID and history of the DID. For details, see the section Moving a DID’s Web Location. - If Key Pre-Rotation is being used in the DID, only keys with a
valid
nextKeys
entry in a previous DIDDoc can be added, as defined in the Using Pre-Rotation Keys section of this specification.
- The
- Define a JSON array of valid parameters that affect the evolution of
the DID. The
did:tdw
DID Method Parameters section of this specification defines the permitted parameters. - Pass the current DID Log, the updated DIDDoc, and the parameters to a
did:tdw
update implementation which MUST:- Generate a DID Entry as a JSON array with the following JSON items:
- The
entryHash
from the previous DID Log Entry as theentryHash
value. - An integer that is one more than the
versionId
of the previous DID Log Entry. - A string that is the current time in ISO8601 format:
"2024-04-05T07:32:58Z"
- The parameters passed in as a JSON dict:
{}
- parameters from previous versions continue to apply and do
not need to be repeated in each version. As a result, the
parameters
item will often be an empty dict.
- parameters from previous versions continue to apply and do
not need to be repeated in each version. As a result, the
- Generate a JSON Patch to evolve the previous DIDDoc version to
the new DIDDoc version, and put the resulting patch in the item
{"patch": <DIDDoc Patch>}
. For details see the Generating and Applying a JSON Patch section of this specification.- An implementation MAY skip the JSON Patch process and
simply put the full new version of the DIDDoc in the item
{"value": <DIDDoc>}
as is done in the initial entry in the log.
- An implementation MAY skip the JSON Patch process and
simply put the full new version of the DIDDoc in the item
- The
- Calculate the Entry Hash (
entryHash
) of the DID Entry as defined in the Entry Hash Generation and Validation section of this specification. - Update the
entryHash
with the value produced in the previous step. - Generate a Data Integrity proof on the new DIDDoc of the entry
using an authorized key from the DID, and the
entryHash
as the proofchallenge
. The definition of “authorized” is formalized in the Authorized Keys section of this specification. The proof becomes the last JSON item in the entry. - Append the resulting entry to the existing contents of the DID file
did.jsonl
on a new line.
- Generate a DID Entry as a JSON array with the following JSON items:
- Update the DID Log file at the appropriate location defined by the
did:tdw
identifier.- This is a logical operation – how a deployment serves the
did.jsonl
content is not constrained.
- This is a logical operation – how a deployment serves the
A controller MAY generate an equivalent, updated did:web
DIDDoc and
publish it as defined in the Publishing a Parallel did:web
DID section of this specification.
A controller may use the move
DID log entry parameter to
change the DID string. That effectively creates a new DID, but a DID that
retains the SCID and verifiable history of the original DID. A DID Controller may do that when forced (for example, loss of domain name) or
by choice (moving from a DID hosting provider to another) without losing the
history and reputation of the DID. See the Moving a DID section
of the Implementers Guide for a discussion of moving a did:tdw
DID.
§ Deactivate (Revoke)
To deactivate the DID, the DID Controller SHOULD add to the DID log entry parameters the item "deactivated": true
. A DID MAY update the DIDDoc further to indicate the deactivation of
the DID, such as removing the authentication
key type entries, preventing
further updates to the DID/DIDDoc.
A resolver encountering in the DID log entry parameters the
item "deactivated": true
should return in the DIDDoc Metadata the JSON item
"deactivated": true
, as per the [DID-CORE] specification.
§ DID Method Processes
The DID Method Operations reference several processes that are executed during DIDDoc generation and DID resolution verification. Each of those processes is specified in the following sections.
§ did:tdw
DID Method Parameters
Entries in the did:tdw
DID Log file contain, as the 4th item, a JSON
object that define the DID processing parameters being used by the DID when publishing that and subsequent DID Entries. A DID Resolver
will use the same parameters when processing the DID Log to resolve the
DID. The parameters object MUST only include items defined in this
specification.
An example of the parameters item in the first DID Log entry for a DID:
{"method":"did:tdw:1","scid":"4c99uuenu8gk6n3bgf09fuf350gx"}
The permitted parameter items and (where applicable) enumerated values for those items are defined below.
method
: Defines the version of the DID Log processing specification to use when processing a given DID’s log file. As new versions of the processing specifications are defined, additional values will be added to the list of acceptable values.- This item MUST appear in the first DID Log entry.
- This item MAY appear in later DID Log entries to indicate that the processing rules for that and later entries have been changed to a different version.
- Acceptable values for this specification are:
did:tdw:1
: Requires that the rules defined in this specification be used in processing the log.
scid
: The value of the SCID for this DID.- This item MUST appear in the first DID log entry.
hash
: The hashing algorithm to use when executing hashes.- By default, the value is initialized to
sha256
. - Acceptable values:
sha256
: Use theSHA-256
algorithm from [RFC4634].
- By default, the value is initialized to
cryptosuite
: The Data Integrity cryptosuite to use when generating and verifying the authentication proofs on the DID log entries.- By default, the value is initialized to
eddsa-jcs-2022
- Acceptable values:
eddsa-jcs-2022
: Use the eddsa-jcs-2022 cryptosuite.
- By default, the value is initialized to
prerotation
: A boolean value indicating that subsequent authentication keys added to the DIDDoc (after this version) MUST have their hash included in anextKeys
parameter item.- The value is initialized to
false
until the item is included in an DID log entry. - Once the value is set to
true
in a DID log entry it MUST NOT be set tofalse
in a subsequent entry.
- The value is initialized to
nextKeys
: An array of strings that are hashes of future keys to be added to the DIDDoc.- The process for generating the hashes is defined in the Pre-Rotation Key Hash Generation and Validation section of this specification.
- If the parameter
prerotation
has been set totrue
, all keys added to a version of the DIDDoc after version 1 MUST have a corresponding hash listed in thenextKeys
items from a previous DID log entries. - See the section of this specification Using Pre-Rotation Keys for non-normative guidance in using pre-rotation keys.
moved
: A string that is a newdid:tdw
DID string. The newdid:tdw
:- MUST contain the same SCID.
- The accompanying DIDDoc MUST have the new DID as the value of the
top-level
id
. - The accompanying DIDDoc MUST have an
alsoKnownAs
array with all previous DID strings as entries in the array.
deactivated
: A JSON boolean that should be set totrue
when the DID is to be deactivated. See the deactivate (revoke) section of this specification for more details.ttl
: A number, the number of seconds that a cache entry for a resolveddid:tdw
DID should last, as recommended by the DID Controller. A resolver can use this value in deciding whether to retrieve a new version of the DID’sdid.jsonl
file. If not specified, resolvers may set a default based on the business needs of the resolver clients.- Caching of a
did:tdw
can be valuable in places where the business rules require resolving a number of DID URLs for the same DID. For example, a client might want call the resolver to the current DIDDoc, and then make repeated calls to get all of the previous versions of the DIDDoc. By caching the DIDDoc state, the resolver would not have to retrieve and process the DID Log on every call. - A Web Server handling one or more
did.jsonl
files MAY be configured to use a comparable HTTP TTL per [RFC9111].
- Caching of a
§ SCID Generation and Validation
The Self-certifying identifier or scid
is a required parameter in the
first DID log entry and is a portion of the hash of the initial DID
Document.
§ Generate SCID
To generate the required SCID for a did:tdw
DID, the DID Controller
MUST execute the following function:
left(base32_lower(hash(JCS(initial DIDDoc with placeholders))), <length>)
Where:
- The
initial DIDDoc with placeholders
is the initial DID Doc defined by the DID Controller with the placeholder{SCID}
put everywhere the SCID will be used in the resolved version 1 DIDDoc. At minimum, the{SCID}
MUST appear in the top levelid
item of the DIDDoc. It MAY occur elsewhere in the DIDDoc. JCS
is an implementation of the JSON Canonicalization Scheme [RFC8785]. It outputs a canonicalized representation of its input.hash
is eithersha256
or an alternative hash algorithm defined in thehash
item in the parameters. Its output is the hash of its input.base32_lower
as defined by the base32_lower function. Its output is the lower case of the Base32 encoded string of its input.left
extracts the<length>
number of characters from the string input.<length>
MUST be at least 28 characters.
§ Verify SCID
To verify the SCID of a did:tdw
DID being resolved, the resolver
MUST execute the following process:
- Extract from the parameters in the first DID log entry for
the DID the
scid
item’s value. - Verify that the length of the
scid
is at least 28 characters.- If less than 28 characters, terminate the resolution process with an error.
- Extract from the first DID log entry the
value
item’s value, which is the initial DIDDoc. - Treat the
value
s value as a string and do a text replacement of thescid
from the first step with{SCID}
. This should result in theinitial DIDDoc with placeholders
data needed for the next step. - Execute the hashing process defined in the generation defined above to
generate the value
calculatedSCID
.- For the
<length>
value, use the length of thescid
extracted in step 1.
- For the
- Verify that the
scid
matches thecalculatedSCID
.
§ Entry Hash Generation and Validation
The entryHash
is the first item in each DID log entry and is a hash
calculate across the entry, excluding the Data Integrity proof.
§ Generate Entry Hash
To generate the required hash for a did:tdw
DID entry, the DID Controller
MUST execute the following process:
- Make the value of the
entryHash
for this entry to theentryHash
of the previous entry. For the first entry in the log, set the value ofentryHash
to the SCID for the DID. - Create the full entry JSON array with elements
entryHash
,versionId
,versionTime
, anddidDocVersion
(which is either avalue
orpatch
). See an example below. - Calculate the hash string as
base32_lower(hash(JCS(entry)))
, where:JCS
is an implementation of the JSON Canonicalization Scheme ([RFC8785]). Its output is a canonicalized representation of its input.hash
is eithersha256
or an alternative hash algorithm defined in thehash
item in the parameters. Its output is the hash of its input JCS content.base32_lower
as defined by the base32_lower function. Its output is the lower case of the Base32 encoded string of the input hash.
- Replace the
entryHash
value in the entry with the calculated value from step 3.
Example of a DID log entry that is processed in step 3 to produce a hash. As
this is a first entry in a DID Log, the entryHash
is the SCID of the DID.
["4c99uuenu8gk6n3bgf09fuf350gx",1,"2024-04-15T19:56:18Z",{"method": "did:tdw:1","scid": "4c99uuenu8gk6n3bgf09fuf350gx"},{"value": {"@context": ["https://www.w3.org/ns/did/v1","https://w3id.org/security/multikey/v1"],"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","authentication": ["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"],"assertionMethod": ["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"],"verificationMethod": [{"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type": "Multikey","publicKeyMultibase": "z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"},{"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B","controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type": "Multikey","publicKeyMultibase": "z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"}]}}]
Resulting entry hash: 4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g
§ Verify Entry Hash
To verify the entryHash
for a did:tdw
DID entry, a DID Resolver MUST
execute the following process:
- Extract the first item in the DID log entry as the
entryHash
- Remove the Data Integrity proof (5th item) from the entry array.
- Set the first value of the entry to the
entryHash
of the previous entry. If this is the first entry in the log, set the value to the SCID for the DID. - Calculate the hash string as
base32_lower(hash(JCS(entry)))
, where:JCS
is an implementation of the JSON Canonicalization Scheme ([RFC8785]). Its output is a canonicalized representation of its input.hash
is either [sha256] or an alternative hash algorithm defined in thehash
item in the parameters. Its output is the hash of its input JCS content.base32_lower
as defined by the base32_lower function. Its output is the lower case of the Base32 encoded string of the input hash.
- Verify that the calculated value from Step 4 matches the extracted value from Step 1.
§ Authorized Keys
Each entry in the DID Log MUST include a Data Integrity proof
signed by a key authorized to control (create, update, deactivate) the DID.
For did:tdw
, the following defines the process for collecting the authorized
keys.
- Retrieve the DIDDoc in which the set of authorized controller DIDs is found.
For the first version (
1
) of the DID, that is the first (and only) DIDDoc. For all subsequent versions of the DID, the previous DIDDoc version is used. - From the DIDDoc, the top-level
controller
item is retrieved to create a (possibly empty) array of controller DIDs from the DIDDoc.- If the list of controller DIDs is empty, the DID being signed is added to the array.
- For each DID in the list, the set of
authentication
key type references are collected from within the DIDDoc.- If there are no
authentication
key type references, theverificationMethod
key references are collected. - If the controller DID is for an external DID, the key referenced MUST be present in the DIDDoc being processed.
- If there are no
The controller of the DID MUST use a key from the resulting key references to sign the DID Log entry.
A resolver of the DID MUST verify that the key used for signing the DID Log entry is in the list of authorized DID key references, and MUST verify the proof.
- [DID-CORE] is not clear (at least to the authors of this specification) on what key types define those authorized to update a DID.
- The requirement to have the key reference for external DIDs (not the
controlled DID) copied into the DIDDoc is to prevent an implementation from
having to resolve external DIDs (that could use any DID Method)
during the resolution of a DID. This might be too restrictive and could be
changed in an update to this specification. For example, it might be
reasonable to require that external DIDs of certain DID Methods
(such as
did:tdw
ordid:web
) be resolved as part of resolving the controlled DID. - In a future version of the specification, the authors would like to require support for verifiableConditions key types, to enable multi-sig DID control support, such as requiring “N of M” signatures must be in a proof for it to be valid.
§ Generating and Applying a JSON Patch
Each time a new did:tdw
version is created, the DID Controller
MAY generate a JSON Patch to concisely define the changes in the
DIDDoc from the previous version. A DID log entry that uses JSON Patch
has a JSON object with a patch
property, with the value the JSON Patch as its 5th item. A DID Controller MAY set the
fourth item of a DID log entry to be the JSON item value
, with its
value the complete DIDDoc. Typically (but not required), a DID Controller
will use value
for the first DID log entry and patch
for all
subsequent entries.
To create the value for a patch
item for a DID log entry, the DID Controller MUST:
- Have the fully resolved previous version of the DIDDoc.
- Have the updated new version of the DIDDoc to be added.
- Execute an implementation of JSON Patch that takes the two DIDDocs as inputs (previous before, new after) and outputs the resulting JSON Patch from before to after.
- Set the fourth item of the DID log entry to
{"patch": "<patch>"}
, removing all extraneous whitespace from the<patch>
.
When processing a DID log entry with a patch
, a resolver MUST:
- Have the fully resolved previous version of the DIDDoc.
- Execute an implementation of JSON Patch that takes the previous DIDDoc and the patch as inputs, and outputs the resulting new version of the DIDDoc.
§ Publishing a Parallel did:web
DID
Each time a did:tdw
version is created, the DID Controller MAY
generate a corresponding did:web
to publish along with the did:tdw
. To do
so, the DID Controller MUST:
- Start with the resolved DIDDoc from
did:tdw
. - Execute a text replacement across the DIDDoc of
did:tdw
todid:web
. - Add to the DIDDoc
alsoKnownAs
array, the fulldid:tdw
DID. If thealsoKnownAs
array does not exist in the DIDDoc, it MUST be added. - Publish the resulting DIDDoc as the file
did.json
at the web location determined by the specifieddid:web
DID to HTTP transformation.
Note that the SCID remains in the did:web
DID string.
The benefit of doing this is that resolvers that have not been updated to
support did:tdw
can continue to resolve the DID Controller's DIDs.
did:web
resolvers that are aware of did:tdw
features can use that knowledge,
and the existence of the alsoKnownAs
did:tdw
data in the DIDDoc to get the
verifiable history of the DID.
The risk of publishing the did:web
in parallel with the did:tdw
is that the
added security and convenience of using did:tdw
are lost.
§ Pre-Rotation Key Hash Generation and Validation
Pre-rotation is a term defining how a DID Controller can commit to the keys that will be added (“rotated to”) in future versions of the DIDDoc. The purpose of committing to future keys is that if the currently active keys are compromised by an attacker, the attacker should not be able to rotate the compromised keys to new ones only the attacker controls to take over the control of the DID. The effectiveness of pre-rotation is based on the idea that an attacker cannot compromised the future keys. See the non-normative section about Using Pre-Rotation Keys in the implementors guide section of this specification.
As described in the parameters
section of this specification, a DID Controller MAY define that
prerotation
is active for the DID. When that is the case, all additions of
new keys in future versions of the DIDDoc MUST have their hash in one or
more of the nextKeys
arrays of previous DID log entry parameters.
To create a hash to be included in the nextKeys array, the DID Controller MUST execute the following process:
- Generate a new key pair.
- Create the JSON dict Verification Material, defined in [DID-CORE], for the new key. An example of such an entry is defined below.
- Calculate the hash string as
base32_lower(hash(JCS(<verificationMaterial>)))
, where:JCS
is an implementation of the JSON Canonicalization Scheme [RFC8785]. Its output is a canonicalized representation of its input.hash
is eithersha256
or an alternative hash algorithm defined in thehash
item in the parameters. Its output is the hash of its input JCS content.base32_lower
as defined by the base32_lower function. Its output is the lower case of the Base32 encoded string of the input hash.
- Add the hash calculated in Step 3 to a DID log entry
nextKeys
item in the parameters (4th item of the entry array). - The JSON dict from Step 2 can be inserted into a future version of the DIDDoc.
When processing a DID log entry where the prerotation
parameter is
active, a resolver MUST:
- When processing each DID log entry, after verifying a DIDDoc, add an
optional array of
nextKeys
from the parameters into an array of hash strings.- The collection of the
nextKeys
from the current entry must occur after the processing and verification of that entries` DIDDoc version so that a new key and its pre-rotation hash cannot be added in the same entry.
- The collection of the
- For all DIDDoc versions after versionId 1, detect when a new key
Verification
Material is added to
a version of a DIDDoc. If so, for each new key:
- Extract the Verification Material JSON dict for the new key from the new DIDDoc.
- Calculate the hash string as
base32_lower(hash(JCS(verificationMaterial)))
, where:JCS
is an implementation of the JSON Canonicalization Scheme [RFC8785]. Its output is a canonicalized representation of its input.hash
is eithersha256
or an alternative hash algorithm defined in thehash
item in the parameters. Its output is the hash of its input JCS content.base32_lower
as defined by the base32_lower function. Its output is the lower case of the Base32 encoded string of the input hash.
- Check to see if the hash string is listed in the collected list of
nextKeys
.- If so, the new key is verified.
- If not, the verification process failed.
§ DID URL Resolution
The did:tdw
DID Method embraces the power and usefulness of DID URLs, along
with the semantic simplicity of using them in a web-based DID method.
Specifically, a did:tdw
implementation MUST:
- Resolve the
/whois
DID URL path using a [[spec:LINKED-VP]] service, whether or not it exists in thedid:tdw
DIDDoc, returning a Verifiable, if published by the DID Controller, found at the same path as thedid.jsonl
file is found with/whois.json
appended to it.- For example,
did:tdw:{SCID}.example.com/whois
returns the verifiable presentation fromhttps://{SCID}.example.com/.well-known/whois.json
.
- For example,
- Resolve any
did:tdw
DID URL using a [DID-CORE]relativeRef
DID parameter, whether or not a supporting service exists in thedid:tdw
DIDDoc, returning the file, found at the web location relative to where thedid.jsonl
file is found.- For example,
did:tdw:{SCID}.example.com/governance/issuers.json
returns the filehttps://{SCID}.example.com/.well-known/governance/issuer.json
- For example,
In both cases, a DID Controller MAY define services in the DIDDoc
that override the default services that MUST be resolved by the did:tdw
DID Method.
The sections below formalize the services that exist by default in did:tdw
and
how a DID Controller can override them.
§ whois LinkedVP Service
The #whois
service enables those that receive a did:tdw
DID to retrieve and
a Verifiable Presentation (and embedded Verifiable) the DID Controller has decided to publish about itself.
The intention is that anyone interested in a particular did:tdw
DID can
resolve the <did>/whois
DID URL, to retrieve a Verifiable published by the DID Controller that contains Verifiable Credentials to decide to publish a whois
verifiable presentation, along with which verifiable credentials to put into the
verifiable presentation.
See the The /whois
Use Case in this specification for
the background about why this capability is so useful, particularly for a
web-based DID Method like did:tdw
.
did:tdw
DIDs automatically supports a #whois
service endpoint with the
following definition based on the Linked VP specification, with the
serviceEndpoint
matching the did:tdw
DID-to-HTTPS DIDDoc transformation and
did.jsonl
changed to whois.json
.
{
"@context": "https://identity.foundation/linked-vp/contexts/v1",
"id": "#whois",
"type": "LinkedVerifiablePresentation",
"serviceEndpoint": "https://example.com/dids/<scid>/whois.json"
}
The returned whois.json
MUST contain a W3C VCDM verifiable signed by the DID and containing verifiable credentials
with the DID as the credentialSubject
.
A DID Controller MAY explicitly add to their DIDDoc a did:tdw
service with the "id": "#whois"
. Such an entry MUST override the implicit
service
above. If the DID Controller wants to publish the /whois
verifiable presentation in a different format than the W3C format, they MUST explicitly add to their DIDDoc a service with the
"id": "#whois"
to specify the name and implied format of the verifiable.
To resolve the DID URL <did:tdw DID>/whois
, the resolver MUST:
- Resolve the given
did:tdw
DID by retrieving, processing, and verifying the DID log for thedid:tdw
as defined in this specification. - Find the DIDDoc
service
with theid
#whois
, if any, or use the implicit service (above). - Resolve the
serviceEndpoint
URL, if possible, and return the document found.- If the
serviceEndpoint
URL can’t be resolved by the resolver (such as if the URL protocol is not supported by the resolver), the errorError XXX: YYY
MUST be returned. - If the file at the defined
serviceEndpoint
is not found,Error 404: Not Found
MUST be returned.
- If the
§ DID URL Path Resolution Service
The automatic resolution of did:tdw
DID URL paths follows the
[DID-CORE] relativeRef
specification, as follows:
- a DID path, such as example 2 in section 3.2 DID URL
Syntax gives the example:
did:example:123456/resume.pdf
- In turn, that can be treated as the following, as shown in example 8 in the
same section:
did:example:123456?service=files&relativeRef=/resume.pdf
- The
#files
service defined below then defines theserviceEndpoint
for therelativeRef
.- For
did:tdw
, that service is implicitly defined, with theserviceEndpoint
matching thedid:tdw
DID-to-HTTPS DIDDoc transformation anddid.jsonl
replaced by the DID URL Path.
- For
Thus, the implicit service for DID did:tdw:example.com:dids:<scid>
is:
{
"id": "#files",
"type": "relativeRef",
"serviceEndpoint": "https://example.com/dids/<scid>"
}
A DID Controller MAY explicitly add to their DIDDoc a service with
the "id": "#files"
. Such an entry MUST override the implicit service
defined above.
To resolve the DID URL <did:tdw DID>/path/to/file
, the resolver MUST:
- Resolve the given
did:tdw
DID by retrieving, processing, and verifying the DID log for thedid:tdw
as defined in this specification. - Find the DIDDoc
service
with theid
#files
, if any, or use the implicit service (above). - Resolve the
serviceEndpoint
URL with the DID URL Path appended, if possible, and return the document found at that location.- If the
serviceEndpoint
URL can’t be resolved by the resolver (such as if the URL protocol is not supported by the resolver), the errorError XXX: YYY
MUST be returned. - If the file at the path appended to the defined
serviceEndpoint
is not found, the errorError 404: Not Found
MUST be returned.
- If the
§ Security and Privacy Considerations
§ DNS Considerations
§ DNS Security Considerations
Implementers must secure DNS resolution to protect against attacks like Man in the Middle, following the detailed guidance in the did:web specification. The use of DNSSEC [RFC4033], [RFC4034], [RFC4035] is essential to prevent spoofing and ensure authenticity of DNS records.
§ DNS Privacy Considerations
Resolving a did:tdw
identifier can expose users to tracking by DNS providers
and web servers. To mitigate this risk, it’s recommended to use privacy-enhancing
technologies such as VPNs, TOR, or trusted universal resolver services, in line
with strategies outlined in the did:web
specification
including emerging RFCs such as Oblivious DNS over
HTTPS
for DNS privacy.
§ In-transit Security
For in-transit security, the guidance provided in the did:web specification regarding the encryption of traffic between the server and client should be followed.
§ International Domain Names
[DID-CORE] identifier syntax does not allow Unicode in method name nor method specific identifiers.
Implementers should be cautious when implementing support for DID URLs that rely on domain names or path components that contain Unicode characters.
See also:
§ Implementors Guide
§ Implementations
Proof of concept implementations of did:tdw
software for DID Controllers and resolvers can be found here:
- Typescript: https://github.com/bcgov/trustdidweb-ts
- Python: To be added
Both currently (as of 2024.04.11) support all of the features of did:tdw
except for Key Pre-Rotation and Verifiable Conditions.
The Typescript implementation is currently less than 1000 lines of Typescript code.
§ Using Pre-Rotation Keys
In an effort to prevent the loss of control over a decentralized identifier (DID) due to a compromised private key, pre-rotation keys are introduced. These commitments, made by the DID Controller, are declarations about the keys that will be published in future versions of the DID document, without revealing the keys themselves.
The primary goal of pre-rotation keys is to ensure that even if an attacker gains access to the current active key, they will not be able to take control of the DID. This safeguard is achieved because the attacker could not simply rotate to a key they generate and control. Rather, they would need to have also compromised the unpublished (and presumably securely stored) pre-rotation key in order to rotate the DID keys.
The cost of having pre-rotation protection is a much more complicated process to update the keys of a DID. The following are some considerations we have come across in considering how to use the pre-rotation feature. The feature definitely adds a layer of key management complexity in return for the benefit.
§ Key Rotation with Pre-Rotation
In using pre-rotation, a DID Controller should generate an “active” key for the DIDDoc where it can be used for “production” purposes (signing, decrypting), and generates the “next key” in an isolated location from production. This prevents both the “active” and “next key” from being compromised in the same attack. For example, an intruder gets into your infrastructure and is able to extract all of your private keys both DID control keys would be lost. Thus, we expect the feature to be used as follows:
- The DID Controller creating the DID would request from an isolated service the hash of the “next key” as defined in this specification. For example, an entity might have the “active” DID/key hosted by one Cloud Provider, and the “next key” by another, on the theory that an attacker might get into one environment or another but not both.
- When a key rotation is to be done, two entries are put in the log, using the following steps by the DID Controller:
- Get the full key reference entry from the isolated service for the pre-rotation “nextKey”.
- Locally generate a pre-rotation key hash for a new key that will soon become the “active” key.
- Add a DID log entry that includes the items from the previous two steps, and signs the proof using an authorized key (that presumably it controls, though not required).
- Although the DID log could be published now, it is probably best to hold off and publish it after adding a second, as described by the rest of the steps.
- Get a new pre-rotation hash from the isolated service.
- Get the full key-rotation key reference for the pre-rotation hash created for the last DID log entry.
- Add a DID Log entry that includes the items from the previous two step
- If the key rotated in the previous DID log entry was a/the
authorized key to make updates to the DID, call the isolated service to produce
the Data Integrity proof over the entry using the key the isolated
service controls.
- This step is not needed if the active service has a key authorized to sign the DIDDoc update.
- Publish the new DID log containing the two new entries.
§ Post Quantum Attacks
One of the potential benefits of this approach to pre-rotation is that it is
“post-quantum safe”. The idea is that in a post-quantum world, the availability
of the published key and signatures may enable the calculation of the
corresponding private key. Since the pre-rotation value is a hash of the
nextKey
and not the public key itself, a post-quantum attack would not
compromise that key, and so a further rotation by the attacker would not be
possible. If there was a (suspected) need to transition to using a quantum-safe
key, the same process listed above would be used, but key reference and the
pre-rotation hash added into the second DID log entry would presumably
both be for quantum-safe keys.
§ Challenges in Using Pre-Rotation
This draft specification states that once pre-rotation is enabled (via DID log entry parameter), it MUST apply to all of the keys in the DIDDoc. However, we’re not sure if that is needed, or if the pre-rotation should only apply to keys that are authorized to update the DID.
Key management is hard enough without having to maintain isolated key generation environments for creating keys for different purposes. Enabling connectivity between the key generation environments to enable automated key rotation while maintaining the key recovery environment as “isolated” is technically challenging.
§ Moving a DID
As noted in the did:tdw
DID Method Parameters section of this specification,
a did:tdw
DID can be “moved” by changing the DID string to one that resolves to a different HTTPS URL, as
long as:
- the SCID stays the same in the new DID,
- the DIDDoc is updated at the same time to have the new DID as the top-level
id
, and - the DIDDoc is updated at the same time to have the old DID string(s) as
alsoKnownAs
entries.
In moving the DID, the versionId
of the DID continues to increment.
While the feature does “bend” the rules for DIDs, we think there is significant value in supporting the specified functionality. These are the uses cases that we considered in adding the functionality.
§ Mergers, Acquisitions and Name Changes
Organizations change over time and such changes often involve names changes. Name changes in turn trigger domain name changes, as organizations match their Web location with their names. Mergers, acquisitions, and simple name changes, all can cause an organization’s “known” domain name to change, including the relinquishment of control over their previous domain name. When such changes occur, it is very unlikely that just because the organization’s DIDs use the old domain name will prevent the changes. Thus the DIDs need to “adapt” to the new domain – the domain name portion of the DID has to change. Ideally, the old location and domain can be retained and a web redirect used to resolve the old DID to the new, but even if that cannot be done, the ability to use the same SCID and retain the full history can be preserved.
§ DID Hosting Service Providers
Consider being able to replace the current identifiers we are given (email
addresses, phone numbers) with did:tdw
DIDs. Comparable hosting platforms
might publish our DIDs for us (ideally, with us in custody of our own private
keys…). Those DIDs, with the inherent public keys can be used for many
purposes – encrypted email (hello PGP!), messaging, secure file sharing, and
more.
From time to time in that imagined future, we may want to move our DIDs from one hosting service to another, just as we move from one email or mobile provider to another. With DIDs that can move and retain the history, we can make such moves smoothly. Contacts will see the change, but also see that the history of the DID remains.
§ Challenges in Moving a DID
While we see great value (and even a hard requirement) for being able to move a DID’s web location, it does create challenges in aligning with the [DID-CORE] specification. These challenges are listed below.
Moving a did:tdw
is actually the (partial or complete) deactivation of the old
DID and the creation of a new DID. The use of the SCID and the way it
is generated is designed to prevent an attacker from being able to create a DID
they control but with the same SCID as existing DID. Thus, “finding” a did:tdw
with the same SCID implies the DIDs are the same. That can be verified by
processing the DID Log.
By retaining the incrementing of the versionId
after a move, the “new” DID
does not start at versionId
of 1
. Further, resolving <new-did>?versionId=1
is going to return a DIDDoc with the top-level id
equal to the <old-did>
.
This is useful from a business perspective, but unexpected from a
[DID-CORE] perspective.
§ did:tdw
Example
The following shows the evolution of a did:tdw
from inception through several
versions, showing the DID, DIDDoc, DID Log, and some of the
intermediate data structures.
In the following, all of the data for the DID log entries are displayed
as prettified JSON for readability. In the log itself, the JSON has all
whitespace removed, and each line ends with a CR
.
§ DID Creation Data
These examples show the important structures used in the Create (Register) operation for a did:tdw
DID.
§ DIDDoc with SCID Placeholders
This is the version of the DIDDoc that the DID Controller constructs (however they see fit) and passes into the SCID Generation Process.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1"
],
"id": "did:tdw:example.com:{SCID}",
"controller": "did:tdw:example.com:{SCID}",
"authentication": [
"did:tdw:example.com:{SCID}#y4SDXopT"
],
"assertionMethod": [
"did:tdw:example.com:{SCID}#5b48Zj6B"
],
"verificationMethod": [
{
"id": "did:tdw:example.com:{SCID}#y4SDXopT",
"controller": "did:tdw:example.com:{SCID}",
"type": "Multikey",
"publicKeyMultibase": "z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"
},
{
"id": "did:tdw:example.com:{SCID}#5b48Zj6B",
"controller": "did:tdw:example.com:{SCID}",
"type": "Multikey",
"publicKeyMultibase": "z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"
}
]
}
§ DIDDoc with SCID In Place
After the SCID is generated, the {SCID}
placeholders are replaced by the generated SCID value.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1"
],
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"authentication": [
"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"
],
"assertionMethod": [
"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"
],
"verificationMethod": [
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"
},
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"
}
]
}
§ Entry Hash Generation Input
The first item in the entry hashing input for Version 1 of the DIDDoc is SCID of
the DID. The fifth item, containing the first version DIDDoc content is the full
DIDDoc (as indicated by the value
item).
[
"4c99uuenu8gk6n3bgf09fuf350gx",
1,
"2024-04-15T19:56:18Z",
{
"method": "did:tdw:1",
"scid": "4c99uuenu8gk6n3bgf09fuf350gx"
},
{
"value": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1"
],
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"authentication": [
"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"
],
"assertionMethod": [
"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"
],
"verificationMethod": [
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"
},
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"
}
]
}
}
]
§ First Log Entry
The following is the JSON prettified version of the entry log file that is published
as the did.jsonl
file. When published, all extraneous whitespace is removed, as
shown in the block below the pretty-printed version.
[
"4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g",
1,
"2024-04-15T19:56:18Z",
{
"method": "did:tdw:1",
"scid": "4c99uuenu8gk6n3bgf09fuf350gx"
},
{
"value": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1"
],
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"authentication": [
"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"
],
"assertionMethod": [
"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"
],
"verificationMethod": [
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"
},
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B",
"controller": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"
}
]
}
},
[
{
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"verificationMethod": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT",
"created": "2024-04-15T19:56:18Z",
"proofPurpose": "authentication",
"challenge": "4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g",
"proofValue": "z4vP3KptRsxFcjpatqHNpywvwV5AfmAYhkHsMbF8K1gKqRA7WZuoyLheF9tabMu2HCXPnvNEKijfMqpRqkfKZRAHi"
}
]
]
The same content as it is found in the did.jsonl
file:
["4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g",1,"2024-04-15T19:56:18Z",{"method":"did:tdw:1","scid":"4c99uuenu8gk6n3bgf09fuf350gx"},{"value":{"@context":["https://www.w3.org/ns/did/v1","https://w3id.org/security/multikey/v1"],"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","authentication":["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"],"assertionMethod":["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"],"verificationMethod":[{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type":"Multikey","publicKeyMultibase":"z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"},{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type":"Multikey","publicKeyMultibase":"z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"}]}},[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","verificationMethod":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","created":"2024-04-15T19:56:18Z","proofPurpose":"authentication","challenge":"4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g","proofValue":"z4vP3KptRsxFcjpatqHNpywvwV5AfmAYhkHsMbF8K1gKqRA7WZuoyLheF9tabMu2HCXPnvNEKijfMqpRqkfKZRAHi"}]]
§ did:web
Version of DIDDoc
As noted in the publishing a parallel did:web
DID section of this specification, here is
what the did:web
DIDDoc looks like for the did:tdw
above.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1"
],
"id": "did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"controller": "did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"alsoKnownAs": ["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx"],
"authentication": [
"did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"
],
"assertionMethod": [
"did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"
],
"verificationMethod": [
{
"id": "did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT",
"controller": "did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"
},
{
"id": "did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B",
"controller": "did:web:example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"
}
]
}
§ Version 2 of the DIDDoc
Time passes, and the DID Controller of the did:tdw
DID decides to
update its DID to a new version, version 2.
§ Target Version 2 DIDDoc
The DID Controller constructs the new target DIDDoc (below) in
preparation for passing it into the process to Update the did:tdw
DID.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1",
"https://identity.foundation/linked-vp/contexts/v1"
],
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"controller": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"
],
"authentication": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3"
],
"assertionMethod": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD"
],
"verificationMethod": [
{
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3",
"controller": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6MkuocstfAaHsJgRnQgfQdtJiECuWEMDAbQV61aCpsUrTh3"
},
{
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD",
"controller": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6MksNvDtgMutKMzjezRqj8JbYuCHNjHR5HBaF2ogJqvqaYD"
}
],
"service": [
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#whois",
"type": "LinkedVerifiablePresentation",
"serviceEndpoint": [
"https://example.com/docs/4c99uuenu8gk6n3bgf09fuf350gx/whois.json"
]
}
]
}
§ Version 2 Entry Hashing Input
The first item in the entry hashing input for Version 2 of the DIDDoc is the
entry hash generated for the Version 1 of the DIDDoc. The fifth item, containing the new
version DIDDoc content is in the form of a [RFC6902] JSON Patch (as
indicated by the patch
item), and are the set of operations to transition the
DIDDoc from version 1 to this new version 2 DIDDoc.
[
"53vtcxfvmvwfzyfw4b9cjeygccwbhm8j1v90by5k66jt4ahbhu50",
2,
"2024-04-15T19:56:18Z",
{},
{
"patch": [
{
"op": "replace",
"path": "/verificationMethod/1/publicKeyMultibase",
"value": "z6MksNvDtgMutKMzjezRqj8JbYuCHNjHR5HBaF2ogJqvqaYD"
},
{
"op": "replace",
"path": "/verificationMethod/1/controller",
"value": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"
},
{
"op": "replace",
"path": "/verificationMethod/1/id",
"value": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD"
},
{
"op": "replace",
"path": "/verificationMethod/0/publicKeyMultibase",
"value": "z6MkuocstfAaHsJgRnQgfQdtJiECuWEMDAbQV61aCpsUrTh3"
},
{
"op": "replace",
"path": "/verificationMethod/0/controller",
"value": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"
},
{
"op": "replace",
"path": "/verificationMethod/0/id",
"value": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3"
},
{
"op": "replace",
"path": "/assertionMethod/0",
"value": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD"
},
{
"op": "replace",
"path": "/authentication/0",
"value": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3"
},
{
"op": "replace",
"path": "/controller",
"value": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"
]
},
{
"op": "replace",
"path": "/id",
"value": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"
},
{
"op": "add",
"path": "/@context/2",
"value": "https://identity.foundation/linked-vp/contexts/v1"
},
{
"op": "add",
"path": "/service",
"value": [
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#whois",
"type": "LinkedVerifiablePresentation",
"serviceEndpoint": [
"https://example.com/docs/4c99uuenu8gk6n3bgf09fuf350gx/whois.json"
]
}
]
}
]
}
]
§ Log File For Version 2
The new version 2 did.jsonl
file contains two entries, one for each version
of the DIDDoc. The data integrity proof on the version 2 entry MUST be from
an authentication
key from the version 1 DIDDoc.
["4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g",1,"2024-04-15T19:56:18Z",{"method":"did:tdw:1","scid":"4c99uuenu8gk6n3bgf09fuf350gx"},{"value":{"@context":["https://www.w3.org/ns/did/v1","https://w3id.org/security/multikey/v1"],"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","authentication":["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"],"assertionMethod":["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"],"verificationMethod":[{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type":"Multikey","publicKeyMultibase":"z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"},{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type":"Multikey","publicKeyMultibase":"z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"}]}},[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","verificationMethod":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","created":"2024-04-15T19:56:18Z","proofPurpose":"authentication","challenge":"4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g","proofValue":"z4vP3KptRsxFcjpatqHNpywvwV5AfmAYhkHsMbF8K1gKqRA7WZuoyLheF9tabMu2HCXPnvNEKijfMqpRqkfKZRAHi"}]]
["53vtcxfvmvwfzyfw4b9cjeygccwbhm8j1v90by5k66jt4ahbhu50",2,"2024-04-15T19:56:18Z",{},{"patch":[{"op":"replace","path":"/verificationMethod/1/publicKeyMultibase","value":"z6MksNvDtgMutKMzjezRqj8JbYuCHNjHR5HBaF2ogJqvqaYD"},{"op":"replace","path":"/verificationMethod/1/controller","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"},{"op":"replace","path":"/verificationMethod/1/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD"},{"op":"replace","path":"/verificationMethod/0/publicKeyMultibase","value":"z6MkuocstfAaHsJgRnQgfQdtJiECuWEMDAbQV61aCpsUrTh3"},{"op":"replace","path":"/verificationMethod/0/controller","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"},{"op":"replace","path":"/verificationMethod/0/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3"},{"op":"replace","path":"/assertionMethod/0","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD"},{"op":"replace","path":"/authentication/0","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3"},{"op":"replace","path":"/controller","value":["did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"]},{"op":"replace","path":"/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"},{"op":"add","path":"/@context/2","value":"https://identity.foundation/linked-vp/contexts/v1"},{"op":"add","path":"/service","value":[{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#whois","type":"LinkedVerifiablePresentation","serviceEndpoint":["https://example.com/docs/4c99uuenu8gk6n3bgf09fuf350gx/whois.json"]}]}]},[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","verificationMethod":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","created":"2024-04-15T19:56:18Z","proofPurpose":"authentication","challenge":"53vtcxfvmvwfzyfw4b9cjeygccwbhm8j1v90by5k66jt4ahbhu50","proofValue":"z47viJruDDnAfpL6Zo3bowUB9Eumx1w7Qa8UwH6K1Df1Db6pExBMRvzdy9YgL452t3v5FmrKAnDGF7aQYgtG7bbga"}]]
§ Version 3
§ Version 3 Target DIDDoc
Here is the target update for the version 3 DIDDoc, as constructed by the DID Controller. It is the data used as input to the did:tdw
log entry generation process.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1",
"https://identity.foundation/linked-vp/contexts/v1",
"https://didcomm.org/messaging/v2"
],
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"controller": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"
],
"authentication": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CZSeAWLE"
],
"assertionMethod": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#9vYyiXiJ"
],
"keyAgreement": [
"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#qnYZ6fWH"
],
"verificationMethod": [
{
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CZSeAWLE",
"controller": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mkq7Qoa2LCvLCUiq9W2J9vXH1ooDqSX2ehWGUzCZSeAWLE"
},
{
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#9vYyiXiJ",
"controller": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6Mkr2D4ixckmQx8tAVvXEhMuaMhzahxe61qJt7G9vYyiXiJ"
},
{
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#qnYZ6fWH",
"controller": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx",
"type": "Multikey",
"publicKeyMultibase": "z6LSdYjdAE7ZY1Gh5VPAxDJdgbg45Lq6im3N9o6HqnYZ6fWH"
}
],
"service": [
{
"id": "did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#whois",
"type": "LinkedVerifiablePresentation",
"serviceEndpoint": [
"https://example.com/docs/4c99uuenu8gk6n3bgf09fuf350gx/whois.json"
]
},
{
"id": "did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#didcomm",
"type": "DIDCommMessaging",
"serviceEndpoint": {
"uri": "https://example.com/didcomm",
"accept": [
"didcomm/v2",
"didcomm/aip2;env=rfc587"
],
"routingKeys": [
"did:example:somemediator#somekey"
]
}
}
]
}
§ Log File For Version 3
The new version 3 did.jsonl
file contains three entries, one for each version
of the DIDDoc. The data integrity proof on the version 3 entry MUST be from
an authentication
key from the version 2 DIDDoc.
["4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g",1,"2024-04-15T19:56:18Z",{"method":"did:tdw:1","scid":"4c99uuenu8gk6n3bgf09fuf350gx"},{"value":{"@context":["https://www.w3.org/ns/did/v1","https://w3id.org/security/multikey/v1"],"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","authentication":["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT"],"assertionMethod":["did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B"],"verificationMethod":[{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type":"Multikey","publicKeyMultibase":"z6Mksta2t7db1WSx2JBorfYFcJnaJMBKUyupD2qPy4SDXopT"},{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#5b48Zj6B","controller":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx","type":"Multikey","publicKeyMultibase":"z6Mkw1KSvGWNAwSwWbcpwPgFARX4vKPa1xvcDMsJ5b48Zj6B"}]}},[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","verificationMethod":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","created":"2024-04-15T19:56:18Z","proofPurpose":"authentication","challenge":"4fbja27mgf0bumtbg2b4hbzqc2ux9a9crrqx7w6cfnd97k9u7k5g","proofValue":"z4vP3KptRsxFcjpatqHNpywvwV5AfmAYhkHsMbF8K1gKqRA7WZuoyLheF9tabMu2HCXPnvNEKijfMqpRqkfKZRAHi"}]]
["53vtcxfvmvwfzyfw4b9cjeygccwbhm8j1v90by5k66jt4ahbhu50",2,"2024-04-15T19:56:18Z",{},{"patch":[{"op":"replace","path":"/verificationMethod/1/publicKeyMultibase","value":"z6MksNvDtgMutKMzjezRqj8JbYuCHNjHR5HBaF2ogJqvqaYD"},{"op":"replace","path":"/verificationMethod/1/controller","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"},{"op":"replace","path":"/verificationMethod/1/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD"},{"op":"replace","path":"/verificationMethod/0/publicKeyMultibase","value":"z6MkuocstfAaHsJgRnQgfQdtJiECuWEMDAbQV61aCpsUrTh3"},{"op":"replace","path":"/verificationMethod/0/controller","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"},{"op":"replace","path":"/verificationMethod/0/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3"},{"op":"replace","path":"/assertionMethod/0","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#gJqvqaYD"},{"op":"replace","path":"/authentication/0","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3"},{"op":"replace","path":"/controller","value":["did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"]},{"op":"replace","path":"/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx"},{"op":"add","path":"/@context/2","value":"https://identity.foundation/linked-vp/contexts/v1"},{"op":"add","path":"/service","value":[{"id":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#whois","type":"LinkedVerifiablePresentation","serviceEndpoint":["https://example.com/docs/4c99uuenu8gk6n3bgf09fuf350gx/whois.json"]}]}]},[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","verificationMethod":"did:tdw:example.com:4c99uuenu8gk6n3bgf09fuf350gx#y4SDXopT","created":"2024-04-15T19:56:18Z","proofPurpose":"authentication","challenge":"53vtcxfvmvwfzyfw4b9cjeygccwbhm8j1v90by5k66jt4ahbhu50","proofValue":"z47viJruDDnAfpL6Zo3bowUB9Eumx1w7Qa8UwH6K1Df1Db6pExBMRvzdy9YgL452t3v5FmrKAnDGF7aQYgtG7bbga"}]]
["3nxcvupjdbetntt80ggnbxurkrz9bhh93nqega3ek5ex8xpfurb0",3,"2024-04-15T19:56:18Z",{},{"patch":[{"op":"add","path":"/service/1","value":{"id":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#didcomm","type":"DIDCommMessaging","serviceEndpoint":{"uri":"https://example.com/didcomm","accept":["didcomm/v2","didcomm/aip2;env=rfc587"],"routingKeys":["did:example:somemediator#somekey"]}}},{"op":"replace","path":"/verificationMethod/1/publicKeyMultibase","value":"z6Mkr2D4ixckmQx8tAVvXEhMuaMhzahxe61qJt7G9vYyiXiJ"},{"op":"replace","path":"/verificationMethod/1/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#9vYyiXiJ"},{"op":"replace","path":"/verificationMethod/0/publicKeyMultibase","value":"z6Mkq7Qoa2LCvLCUiq9W2J9vXH1ooDqSX2ehWGUzCZSeAWLE"},{"op":"replace","path":"/verificationMethod/0/id","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CZSeAWLE"},{"op":"add","path":"/verificationMethod/2","value":{"id":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#qnYZ6fWH","controller":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx","type":"Multikey","publicKeyMultibase":"z6LSdYjdAE7ZY1Gh5VPAxDJdgbg45Lq6im3N9o6HqnYZ6fWH"}},{"op":"replace","path":"/assertionMethod/0","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#9vYyiXiJ"},{"op":"replace","path":"/authentication/0","value":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CZSeAWLE"},{"op":"add","path":"/@context/3","value":"https://didcomm.org/messaging/v2"},{"op":"add","path":"/keyAgreement","value":["did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#qnYZ6fWH"]}]},[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","verificationMethod":"did:tdw:migrated.example.com:4c99uuenu8gk6n3bgf09fuf350gx#CpsUrTh3","created":"2024-04-15T19:56:18Z","proofPurpose":"authentication","challenge":"3nxcvupjdbetntt80ggnbxurkrz9bhh93nqega3ek5ex8xpfurb0","proofValue":"zedM9gUK9KvMLEXLePemFB2W5jBtscHN9WRPcxmkuRanPHsvK76M1mKHUKqJtApcdSsykRZtoHPJLiagJo3KKJsU"}]]
And so on…
§ References
- DID-CORE
- Decentralized Identifiers (DIDs) v1.0. Manu Sporny; Amy Guy; Markus Sabadello; Drummond Reed; 2022-07-19. Status: REC.
- RFC1035
- Domain names - implementation and specification. P. Mockapetris; 1987-11. Status: Internet Standard.
- RFC1123
- Requirements for Internet Hosts - Application and Support. R. Braden, Ed.; 1989-10. Status: Internet Standard.
- RFC2181
- Clarifications to the DNS Specification. R. Elz; R. Bush; 1997-07. Status: Proposed Standard.
- RFC2234
- Augmented BNF for Syntax Specifications: ABNF. D. Crocker, Ed.; P. Overell; 1997-11. Status: Proposed Standard.
- RFC3912
- WHOIS Protocol Specification. L. Daigle; 2004-09. Status: Draft Standard.
- RFC3986
- Uniform Resource Identifier (URI): Generic Syntax. T. Berners-Lee; R. Fielding; L. Masinter; 2005-01. Status: Internet Standard.
- RFC4033
- DNS Security Introduction and Requirements. R. Arends; R. Austein; M. Larson; D. Massey; S. Rose; 2005-03. Status: Proposed Standard.
- RFC4034
- Resource Records for the DNS Security Extensions. R. Arends; R. Austein; M. Larson; D. Massey; S. Rose; 2005-03. Status: Proposed Standard.
- RFC4035
- Protocol Modifications for the DNS Security Extensions. R. Arends; R. Austein; M. Larson; D. Massey; S. Rose; 2005-03. Status: Proposed Standard.
- RFC4634
- US Secure Hash Algorithms (SHA and HMAC-SHA). D. Eastlake 3rd; T. Hansen; 2006-07. Status: Informational.
- RFC4648
- The Base16, Base32, and Base64 Data Encodings. S. Josefsson; 2006-10. Status: Proposed Standard.
- RFC5895
- Mapping Characters for Internationalized Domain Names in Applications (IDNA) 2008. P. Resnick; P. Hoffman; 2010-09. Status: Informational.
- RFC6902
- JavaScript Object Notation (JSON) Patch. P. Bryan, Ed.; M. Nottingham, Ed.; 2013-04. Status: Proposed Standard.
- RFC8484
- DNS Queries over HTTPS (DoH). P. Hoffman; P. McManus; 2018-10. Status: Proposed Standard.
- RFC8785
- JSON Canonicalization Scheme (JCS). A. Rundgren; B. Jordan; S. Erdtman; 2020-06. Status: Informational.