去中心化标识符(DID)是一种用于可验证的"自主权"数字身份的新型标识符。DID 完全由 DID 控制者掌控,独立于任何集中式注册机构、身份提供者或证书颁发机构。DID 解析为 DID 文档——描述如何使用该特定 DID 的简单文档。

本文档规定了解析 DID 和解引用 DID URL 的算法与指南。此外,本文档描述了与 DID 解析过程相关的输入和输出元数据,并进一步描述了 DID 解析请求可能返回的数据结构。 本文档依赖于核心 DID 规范 Decentralized Identifiers (DIDs) v1.1, 该规范详细描述了底层 DID 架构。

欢迎对本文档提出意见。请直接在 GitHub 上提交问题, 或发送至 public-did-wg@w3.org订阅存档)。

本规范的部分工作由美国国土安全部科学技术局根据合同 HSHQDC-17-C-00019 资助。本规范的内容不一定反映美国政府的立场或政策, 也不应推断为官方认可。

本规范的工作也得到了由 Christopher Allen、Shannon Appelcline、 Kiara Robles、Brian Weller、Betty Dhamers、Kaliya Young、Kim Hamilton Duffy、 Manu Sporny、Drummond Reed、Joe Andrieu 和 Heather Vescent 推动的 Rebooting the Web of Trust 社区的支持。

引言

DID resolution 是为给定的 DID 获取 DID document 的过程。这是可以对任何 DID 执行的四种必需操作之一("读取";其他三种分别是"创建"、"更新"和"停用")。这些操作的具体细节取决于 DID method。 在 DID resolution 的基础上,DID URL dereferencing 是为给定的 DID URL 检索资源表示的过程。能够执行这些过程的软件和/或硬件称为 DID resolver

本规范定义了 DID resolutionDID URL dereferencing 过程的通用要求、算法(包括其输入和结果)、架构选项以及各种注意事项。

请注意,虽然本规范定义了 DID 解析的一些基本功能,但与 DID 的 verifiable data registry 通信所需的实际步骤由适用的 DID method 规范定义。

实现者概览

通过使用标准的 resolve(did, resolutionOptions) 接口(如 DID 解析章节中所定义)调用 DID resolver,可以获取 DID document 及其附带的元数据 (例如 `contentType`、证明、版本信息),应用程序可以使用这些信息来验证用户的加密密钥、服务端点或状态。

例如,一个钱包应用可以使用 `versionTime` 参数解析 did:example:123?versionTime=2021-05-10T17:00:00Z 以检索该 DID 在过去某一时刻的状态,或者客户端可以解引用一个 DID URL, 如 did:example:123?service=files&relativeRef=/resume.pdf (参见此处的详细示例), 以获取用户通过 DID 文档中声明的服务存储的简历。

此外,本规范的 DID URL 解引用算法展示了客户端如何通过 片段(例如 #key-1)从 DID document 中提取特定的验证方法 (参见此处的详细示例)。 在实践中,实现者通过 DID Resolution Test Suite 验证其解析器, 该测试套件测试规范性的 MUST 要求和错误条件(如无效 DID、已停用 DID、不支持的方法、 相对 URL 扩展等),以确保客户端应用程序能够可靠地依赖不同 DID 方法的正确解析行为。

conforming DID resolver(合规 DID 解析器)是指符合 中相关规范性声明的、以软件和/或硬件实现的任何算法。

conforming DID URL dereferencer(合规 DID URL 解引用器)是指符合 中相关规范性声明的、以软件和/或硬件实现的任何算法。

目标读者

本规范有三类主要读者:合规 DID 方法的实现者;合规 DID 解析器的实现者;以及 希望使用 DID 解析器解析 DID 的系统和服务的实现者。目标读者包括但不限于 软件架构师、数据建模师、应用开发者、服务开发者、测试人员、运维人员和 用户体验(UX)专家。参与去中心化身份、可验证凭证和安全存储等广泛标准工作的 其他人员也可能有兴趣阅读本规范。

用例

DID 解析规范旨在通过定义标准化接口来支持广泛的用例,以独立于任何特定 DID 的 DID 方法来解析 DID 和解引用 DID URL。这些用例包括:

术语

DID 参数

DID URL 语法支持一种简单的参数格式 (参见 [[DID-CORE]] 中的 Query 章节)。向 DID URL 添加 DID 参数意味着该参数成为 resource 标识符的一部分。

did:example:123?versionTime=2021-05-10T17:00:00Z
	
did:example:123?service=files&relativeRef=/resume.pdf
	

对于存在的每个 DID 参数,其关联值必须(MUST)是根据 RFC3987 第 3.1 节序列化为 ASCII 的 标量值字符串。

某些 DID 参数完全独立于任何特定的 DID method,并且对所有 DIDs 的工作方式相同。其他 DID 参数并非所有 DID methods 都支持。在支持可选参数的情况下,它们预期在支持它们的 DID methods 之间统一运行。以下表格提供了在所有 DID methods 之间以相同方式运行的常见 DID 参数。对所有 DID 参数的支持是可选的(OPTIONAL)。

参数名称 描述
service 通过服务 ID 从 DID document 中标识一个 service
serviceType 通过服务类型从 DID document 中标识一组一个或多个 services
relativeRef 根据 RFC3986 第 4.2 节的相对 URI 引用,用于标识 service endpoint 处的 resource,该服务端点通过 service 参数从 DID document 中选择。
versionId 标识要解析的 DID document 的特定版本(版本 ID 可以是顺序的、UUID 或方法特定的)。
versionTime 标识要解析的 DID document 的特定版本时间戳。即在指定 `versionTime` 之前对 DID 有效的最新版本的 DID document。如果存在,关联值必须(MUST)是一个 ASCII 字符串,且为有效的 XML 日期时间值,如 W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes [[XMLSCHEMA11-2]] 第 3.3.7 节所定义。此日期时间值必须(MUST)标准化为 UTC 00:00:00 且不含亚秒小数精度。例如:2020-12-20T19:17:47Z
hl DID document 的资源哈希,用于添加完整性保护,如 [[?HASHLINK]] 中所指定。此参数为非规范性的。

实现者以及 DID method 规范作者可能使用此处未列出的其他 DID 参数。为了最大化互操作性,建议(RECOMMENDED)DID 参数使用 DID 文档属性扩展机制 [[?DID-EXTENSIONS-PROPERTIES]],以避免与具有不同语义的相同 DID 参数的其他用途发生冲突。

DID 参数可以(MAY)在存在明确用例的情况下使用,即该参数需要成为 URL 的一部分,以比单独使用 DID 更高的精度引用 resource。预期 DID 参数 在相同功能可以通过向 DID resolver 传递输入元数据来表达时,使用 DID 参数。

DID resolutionDID URL dereferencing 函数可以通过向 DID resolver 传递不属于 DID URL 来影响其行为。这类似于 HTTP,其中某些参数可以包含在 HTTP URL 中,或者在解引用过程中作为 HTTP 头传递。重要的区别在于:作为 DID URL 一部分的 DID 参数应当用于指定正在标识什么 resource,而不属于 DID URL 的输入元数据应当用于控制如何解析或解引用该 resource

DID 解析

DID resolution 函数通过使用适用 DID method 的"读取"操作将 DID 解析为 DID document,如 Method Operations 中所述。

所有合规的 DID resolvers 实现以下函数,其抽象形式如下:

resolve(did, resolutionOptions) →
   « didResolutionMetadata, didDocument, didDocumentMetadata »
      

所有合规的 DID resolvers 必须(MUST)为至少一种 DID method 实现 DID resolution 函数,并且必须(MUST)能够以至少一种合规 representation 返回 DID document

合规的 DID resolver 实现不以任何方式改变此函数的签名。DID resolver 实现可以(MAY)将 resolve 函数映射到方法特定的内部函数以执行实际的 DID resolution 过程。DID resolver 实现可以(MAY)在此处指定的 resolve 函数之外实现和暴露具有不同签名的额外函数。

resolve 函数的输入变量如下:

did
这是要解析的 DID。此输入是必需的(REQUIRED),且值必须(MUST)是 中定义的合规 DID
resolutionOptions
一个元数据结构,包含除 did 本身之外的 resolve 函数的输入选项。此结构在 中进一步定义。此输入是必需的(REQUIRED),但结构可以(MAY)为空。

此函数返回多个值,不对这些值如何一起返回施加限制。resolve 的返回值是 didResolutionMetadatadidDocumentdidDocumentMetadata。这些值描述如下:

didResolutionMetadata
一个元数据结构,包含与 DID resolution 过程结果相关的值。此结构是必需的(REQUIRED),在解析过程中出现错误的情况下,此结构禁止(MUST NOT)为空。此结构在 中进一步定义。如果解析不成功,此结构必须(MUST)包含描述错误的 error 属性。参见 章节。
didDocument
如果解析成功,此值必须(MUST)是一个能够以 规范的一种合规 representations 表示的 DID document。已解析的 DID documentid 的值必须(MUST)与被解析的 DID 字符串等价。如果解析不成功,此值必须(MUST)为空。
didDocumentMetadata
如果解析成功,此值必须(MUST)是一个 元数据结构。此结构包含关于 didDocument 属性中 DID document 的元数据。如果解析不成功,此输出必须(MUST)是一个空的 元数据结构。此结构在 中进一步定义。

DID 解析选项

这是一个元数据结构,包含 DID Resolution 过程的输入选项。

此结构中可能的属性及其可能的值应当(SHOULD)在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册。本规范定义了以下常见输入选项:

accept
调用者首选的 DID document representation 的媒体类型。媒体类型必须(MUST)表示为 ASCII 字符串DID resolver 实现应当(SHOULD)使用此值来确定返回的 didDocumentrepresentation(如果支持且可用该 representation)。此属性是可选的(OPTIONAL)。
expandRelativeUrls
一个布尔标志,指示 DID resolverDID document 中的 相对 DID URL 扩展为符合 DID URL 语法的绝对 DID URL。
versionId
参见 中的定义。
versionTime
参见 中的定义。

DID 解析元数据

这是一个元数据结构,包含关于 DID Resolution 过程的元数据。

此元数据通常在每次调用 DID Resolution 函数时发生变化,因为它表示解析过程本身的数据。

此元数据的来源是 DID resolver

DID 解析元数据的示例包括:

此结构中可能的属性及其可能的值应当(SHOULD)在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册。本规范定义了以下常见元数据属性:

contentType
返回的 didDocument 的媒体类型。此属性是可选的(OPTIONAL)。如果存在,此属性的值必须(MUST)是一个 ASCII 字符串,即合规 representations 的媒体类型。在这种情况下,resolve 函数的调用者必须(MUST)在确定如何解析和处理 didDocument 时使用此值。
error
[[RFC9457]] 中定义的错误数据结构。当解析过程中出现错误时,此属性是必需的(REQUIRED)。本规范定义的错误可在 章节中找到。其他错误应当(SHOULD)在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册。
proof

某些 DID resolversDID URL dereferencers 在执行 DID ResolutionDID URL Dereferencing 函数时使用证明。详见

DID resolution 元数据可以(MAY)包含 proof 属性。如果存在,其值必须(MUST)是一个 集合,其中每个项目是一个表示证明的 映射。此属性的使用和证明类型与 DID method 无关。

DID 文档元数据

这是一个元数据结构,包含关于 DID Resolution 过程的元数据。

此元数据通常不会在 DID Resolution 函数的调用之间发生变化,除非 DID document 发生更改,因为它表示关于 DID document 的数据。

此元数据的来源是 DID controller 和/或 DID method。 由 DID 控制者证明的 DID 文档元数据没有内在的准确性保证。建议客户端在依赖 DID 文档元数据来指导业务逻辑时保持谨慎。

DID 文档元数据的示例包括:

此结构中可能的属性及其可能的值应当(SHOULD)在 DID Document Properties Extensions [[?DID-EXTENSIONS-PROPERTIES]] 中注册。本规范定义了以下常见元数据属性。

created
DID document 元数据应当(SHOULD)包含 created 属性,以指示 Create 操作的时间戳。该属性的值必须(MUST)是格式化为 XML Datetime字符串,标准化为 UTC 00:00:00 且不含亚秒小数精度。例如:2020-12-20T19:17:47Z
updated
DID document 元数据应当(SHOULD)包含 updated 属性,以指示已解析文档版本的最后一次 Update 操作的时间戳。该属性的值必须(MUST)遵循与 created 属性相同的格式规则。如果从未对 DID document 执行过 Update 操作,则省略 updated 属性。如果 updated 属性存在,当两个时间戳之间的差异小于一秒时,其值可以与 created 属性的值相同。
deactivated
如果 DID 已被停用DID document 元数据必须(MUST)包含此属性,其布尔值为 true。如果 DID 未被停用,此属性是可选的(OPTIONAL),但如果包含,必须(MUST)具有布尔值 false
nextUpdate
如果已解析的文档版本不是文档的最新版本,DID document 元数据可以(MAY)包含 nextUpdate 属性。它指示下一次 Update 操作的时间戳。该属性的值必须(MUST)遵循与 created 属性相同的格式规则。
versionId
DID document 元数据应当(SHOULD)包含 versionId 属性,以指示已解析文档版本的最后一次 Update 操作的版本。该属性的值必须(MUST)是一个 ASCII 字符串
nextVersionId
如果已解析的文档版本不是文档的最新版本,DID document 元数据可以(MAY)包含 nextVersionId 属性。它指示下一次 Update 操作的版本。该属性的值必须(MUST)是一个 ASCII 字符串
equivalentId

DID method 可以定义逻辑等价的不同 DID 形式。例如,DID 在注册到 verifiable data registry 之前采用一种形式,注册后采用另一种形式。在这种情况下,DID method 规范可能需要将一个或多个逻辑等价于已解析 DIDDIDs 表示为 DID document 的属性。这就是 equivalentId 属性的用途。

DID document 元数据可以(MAY)包含 equivalentId 属性。如果存在,其值必须(MUST)是一个 集合,其中每个项目是符合 章节规则的 字符串。该关系声明每个 equivalentId 值在逻辑上等价于 id 属性值,因此指向相同的 DID subject。每个 equivalentId DID 值必须(MUST)由与 id 属性值相同的 DID method 产生,并且是其形式之一。(例如,did:example:abc == did:example:ABC

合规的 DID method 规范必须(MUST)保证每个 equivalentId 值在逻辑上等价于 id 属性值。

请求方应保留 idequivalentId 属性中的值,以确保与其中任何值的后续交互都能作为逻辑等价正确处理(例如,在数据库中保留所有变体,以便与任何一个的交互都映射到相同的底层账户)。

equivalentId 是比 alsoKnownAs 更强的等价形式,因为这种等价性必须(MUST)由管辖的 DID method 保证。使用 equivalentId 意味着同一个 DID document 描述了 equivalentId DIDid 属性 DID

如果请求方未保留 idequivalentId 属性中的值,并确保与其中任何值的后续交互都能作为逻辑等价正确处理,则可能出现负面或意外问题。强烈建议实现者遵守与此元数据属性相关的指令。

canonicalId

canonicalId 属性与 equivalentId 属性相同,不同之处在于:a)它与单个值而非集合关联,b)该 DID 被定义为在包含它的 DID document 范围内 DID subject 的规范 ID。

DID document 元数据可以(MAY)包含 canonicalId 属性。如果存在,其值必须(MUST)是符合 章节规则的 字符串。该关系声明 canonicalId 值在逻辑上等价于 id 属性值,并且 canonicalId 值由 DID method 定义为在包含它的 DID document 范围内 DID subject 的规范 ID。canonicalId 值必须(MUST)由与 id 属性值相同的 DID method 产生,并且是其形式之一。(例如,did:example:abc == did:example:ABC)。

合规的 DID method 规范必须(MUST)保证 canonicalId 值在逻辑上等价于 id 属性值。

请求方应使用 canonicalId 值作为 DID subject 的主要 ID 值,并将所有其他等价值视为次要别名(例如,更新系统中对应的主要引用以反映新的规范 ID 指令)。

canonicalIdequivalentId 是相同的等价声明,只是它被约束为单个值,该值被定义为在 DID document 范围内 DID subject 的规范值。与 equivalentId 一样,使用 canonicalId 意味着同一个 DID document 描述了 canonicalId DID 和 id 属性 DID

如果解析方未使用 canonicalId 值作为 DID 主体的主要 ID 值,并将所有其他等价值视为次要别名,则可能出现与用户体验相关的负面或意外问题。强烈建议实现者遵守与此元数据属性相关的指令。

proof

许多 DID methods 在执行 方法操作时使用证明。详见

DID document 元数据可以(MAY)包含 proof 属性。如果存在,其值必须(MUST)是一个 集合,其中每个项目是一个表示证明的 映射。此属性的使用和证明类型是 DID method 特定的。

DID 解析算法

以下 DID resolution 算法必须(MUST)由合规的 DID resolver 实现。

  1. 验证输入 DID 是否符合 DID 语法的 `did` 规则。如果不符合,DID resolver 必须(MUST)返回以下结果:
    1. didResolutionMetadata错误对象,type 设置为 INVALID_DID
    2. didDocumentnull
    3. didDocumentMetadata«[ ]»
  2. 确定输入 DID 的 DID 方法是否被实现此算法的 DID resolver 支持。如果不支持,DID resolver 必须(MUST)返回以下结果:
    1. didResolutionMetadata错误对象,type 设置为 METHOD_NOT_SUPPORTED
    2. didDocumentnull
    3. didDocumentMetadata«[ ]»
  3. 通过执行输入 DID method 定义的 Read 操作,获取输入 DIDDID document
    1. 输入 DID 外,此算法的所有额外解析选项必须(MUST)传递给输入 DID methodRead 操作。
    2. 如果输入 DID 不存在,返回以下结果:
      1. didResolutionMetadata错误对象,type 设置为 NOT_FOUND
      2. didDocumentnull
      3. didDocumentMetadata«[ ]»
    3. 如果输入 DID 已被停用,返回以下结果:
      1. didResolutionMetadata«[ ... ]»
      2. didDocumentnull
      3. didDocumentMetadata«[ "deactivated" → true, ... ]»
    4. 否则,Read 操作的结果称为输出 DID document。此结果必须(MUST)以对应于 accept 输入 DID 解析选项合规表示形式来表示。
  4. 如果输入 DID 解析选项包含值为 trueexpandRelativeUrls 选项:
    1. 遍历输出 DID document 中的所有 servicesverification methodsverification relationships
    2. 如果 serviceverification method (包括嵌入在 verification relationships 中的)的 id 属性值是 相对 DID URL,或者 verification relationship相对 DID URL
      1. 根据 [[[DID-CORE]]] 中 Relative DID URLs 章节的规则,将 相对 DID URL 解析为符合 DID URL 语法的绝对 DID URL
    3. 通过将 相对 DID URL 替换为已解析的绝对 DID URLs 来更新输出 DID document
  5. 返回以下结果:
    1. didResolutionMetadata«[ ... ]»
    2. didDocument输出 DID 文档
    3. didDocumentMetadata«[ "contentType" → 输出 DID 文档媒体类型, ... ]»

DID URL 解引用

DID URL dereferencing 函数将 DID URL 解引用为一个 resource,其内容取决于 DID URL 的各组成部分,包括 DID method、方法特定标识符、路径、查询和片段。此过程依赖于 DID URL 中包含的 DIDDID resolutionDID URL dereferencing 可能涉及多个步骤(例如,当正在解引用的 DID URL 包含片段时),该函数被定义为在所有步骤完成后返回最终资源。下图描述了上述关系。


DID 解析为 DID 文档;DID URL 包含 DID;DID URL 解引用为 DID 文档片段或外部资源。
DID URL 解引用概览 另见:叙述性描述

图的左上部分包含一个黑色轮廓的矩形,标记为"DID"。

图的左下部分包含一个黑色轮廓的矩形,标记为"DID URL"。此矩形包含四个较小的黑色轮廓矩形,水平排列相邻。这些较小的矩形依次标记为"DID"、"path"、"query"和"fragment"。

图的右上部分包含一个黑色轮廓的矩形,标记为"DID document"。此矩形包含三个较小的黑色轮廓矩形。这些较小的矩形标记为"id"、"(property X)"和"(property Y)",并被多组省略号包围。一条标记为"DID document - relative fragment dereference"的黑色弯曲箭头从标记为"(property X)"的矩形延伸,指向标记为"(property Y)"的矩形。

图的右下部分包含一个黑色轮廓的椭圆形,标记为"Resource"。

一条标记为"resolves to a DID document"的黑色箭头从图左上部分标记为"DID"的矩形延伸,指向图右上部分标记为"DID document"的矩形。

一条标记为"refers to"的黑色箭头从图右上部分标记为"DID document"的矩形延伸,指向图右下部分标记为"Resource"的椭圆形。

一条标记为"contains"的黑色箭头从图左下部分标记为"DID URL"的矩形中标记为"DID"的小矩形延伸,指向图左上部分标记为"DID"的矩形。

一条标记为"dereferences to a DID document"的黑色箭头从图左下部分标记为"DID URL"的矩形延伸,指向图右上部分标记为"DID document"的矩形。

一条标记为"dereferences to a resource"的黑色箭头从图左下部分标记为"DID URL"的矩形延伸,指向图右下部分标记为"Resource"的椭圆形。

所有合规的 DID URL dereferencers 实现以下函数,其抽象形式如下:

dereference(didUrl, dereferenceOptions) →
   « dereferencingMetadata, contentStream, contentMetadata »
      

dereference 函数的输入变量如下:

didUrl
作为单个 字符串的合规 DID URL。这是要解引用的 DID URL。要解引用 DID fragment,必须(MUST)使用包含 DID fragment 的完整 DID URL。此输入是必需的(REQUIRED)。

虽然将任何 didUrl 传递给 DID URL 解引用器都是有效的,但实现者应参考 以进一步了解 DID URL 预期如何被解引用的常见模式。

dereferencingOptions
一个元数据结构,包含除 didUrl 本身之外的 dereference 函数的输入选项。此结构在 中进一步定义。此输入是必需的(REQUIRED),但结构可以(MAY)为空。

此函数返回多个值,不对这些值如何一起返回施加限制。dereference 的返回值是 dereferencingMetadatacontentStreamcontentMetadata。这些值描述如下:

dereferencingMetadata
一个元数据结构,包含与 DID URL dereferencing 过程结果相关的值。此结构是必需的(REQUIRED),在解引用过程中出现错误的情况下,此结构禁止(MUST NOT)为空。此结构在 中进一步定义。如果解引用不成功,此结构必须(MUST)包含描述错误的 error 属性。参见 章节。
contentStream
如果调用 dereferencing 函数且成功,此值必须(MUST)包含对应于 DID URLresourcecontentStream 可以(MAY)是可以以一种合规 representations 序列化的 resource(如 DID document)、verification methodservice,或通过解析过程可以获取的任何其他可通过媒体类型标识的资源格式。如果解引用不成功,此值必须(MUST)为空。
contentMetadata
如果解引用成功,此值必须(MUST)是一个 元数据结构,但该结构可以(MAY)为空。此结构包含关于 contentStream 的元数据。如果 contentStreamDID document,此值必须(MUST)是 DID Resolution 中描述的 didDocumentMetadata 结构。如果解引用不成功,此输出必须(MUST)是一个空的 元数据结构。此结构在 中进一步定义。

合规的 DID URL dereferencing 实现不以任何方式改变这些函数的签名。DID URL dereferencing 实现可以将 dereference 函数映射到方法特定的内部函数以执行实际的 DID URL dereferencing 过程。DID URL dereferencing 实现可以在此处指定的 dereference 函数之外实现和暴露具有不同签名的额外函数。

DID URL 解引用选项

这是一个元数据结构,包含 DID URL Dereferencing 过程的输入选项。

此结构中可能的属性及其可能的值应当(SHOULD)在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册。本规范定义了以下常见输入选项:

accept
调用者首选的 contentStream 媒体类型。媒体类型必须(MUST)表示为 ASCII 字符串DID URL dereferencer 实现应当(SHOULD)使用此值来确定返回值中包含的 representationcontentType(如果支持且可用该 representation)。
verificationRelationship
调用者期望从 DID URL 解引用得到的 verificationMethod 被授权的 verificationRelationship。如果存在,关联值必须(MUST)是一个 ASCII 字符串。如果 DID URL 未解引用到 verificationMethod,或者 DID 文档未为指定的 verificationRelationship 授权该 verificationMethod,则必须(MUST)引发错误。

DID URL 解引用元数据

这是一个元数据结构,包含关于 DID URL Dereferencing 过程的元数据。

此元数据通常在每次调用 DID URL Dereferencing 函数时发生变化,因为它表示解引用过程本身的数据。

此元数据的来源是 DID URL dereferencer

此结构中可能的属性及其可能的值应当(SHOULD)在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册。本规范定义了以下常见元数据属性:

contentType
如果解引用成功,返回的 contentStream 的媒体类型应当(SHOULD)使用此属性表示。媒体类型值必须(MUST)表示为 ASCII 字符串
error
[[RFC9457]] 中定义的错误数据结构。当解引用过程中出现错误时,此属性是必需的(REQUIRED)。本规范定义的错误可在 章节中找到。其他错误应当(SHOULD)在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册。
proof

某些 DID resolversDID URL dereferencers 在执行 DID ResolutionDID URL Dereferencing 函数时使用证明。详见

DID URL dereferencing 元数据可以(MAY)包含 proof 属性。如果存在,其值必须(MUST)是一个 集合,其中每个项目是一个表示证明的 映射。此属性的使用和证明类型与 DID method 无关。

DID URL 内容元数据

这是一个元数据结构,包含关于 DID URL Dereferencing 过程的元数据。

此元数据通常不会在 DID URL Dereferencing 函数的调用之间发生变化,除非内容发生更改,因为它表示关于内容的数据。

此元数据的来源是 DID controller 和/或 DID method

此结构中可能的属性及其可能的值应当(SHOULD)在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册。本规范不定义常见属性。

DID URL 解引用算法

以下 DID URL dereferencing 算法必须(MUST)由合规的 DID resolver 实现。根据 [[RFC3986]],它由以下三个步骤组成:解析 DID;解引用资源;以及解引用片段(仅当输入 DID URL 包含 DID fragment 时):

解引用资源

  1. 验证输入 DID URL 是否符合 DID URL 语法的 `did-url` 规则。如果不符合,DID URL dereferencer 必须(MUST)返回以下结果:
    1. dereferencingMetadata错误对象,type 设置为 INVALID_DID_URL
    2. contentStreamnull
    3. contentMetadata«[ ]»
  2. 通过执行 中定义的 DID resolution 算法,获取输入 DIDDID document。所有解引用选项输入 DID URL 的所有 DID 参数必须(MUST)作为解析选项传递给 DID Resolution 算法。
  3. 如果输入 DID 在 VDR 中不存在,DID URL dereferencer 必须(MUST)返回以下结果:
    1. dereferencingMetadata错误对象,type 设置为 NOT_FOUND
    2. contentStreamnull
    3. contentMetadata«[ ]»
  4. 否则,DID resolution 算法的 didDocument 结果称为已解析的 DID document
  5. 如果存在,从输入 DID URL 中分离 DID fragment,并继续使用调整后的输入 DID URL
  6. 如果输入 DID URL 不包含 DID path 且不包含 DID query
    did:example:1234
    DID URL dereferencer 必须(MUST)按以下方式返回已解析的 DID document已解析的
    1. dereferencingMetadata«[ ... ]»
    2. contentStream已解析的 DID 文档
    3. contentMetadata«[ 已解析的 DID 文档元数据
  7. 如果输入 DID URL 包含 DID 参数 hl
    did:example:1234?hl=zQmWvQxTqbG2Z9HPJgG57jjwR154cKhbtJenbyYTWkjgF3e

    TODO: 指定处理 `hl` DID 参数的算法。

  8. 如果输入 DID URL 包含 DID 参数 service 和/或 DID 参数 serviceType,以及可选的 DID 参数 relativeRef
    did:example:1234?service=files&relativeRef=%2Fmyresume%2Fdoc%3Fversion%3Dlatest
    1. 已解析的 DID document 中,选择满足以下条件的所有 services
      1. 如果输入 DID URL 包含 DID 参数 service: 如果 serviceid 属性与 service DID 参数的值匹配,则选择该服务。如果 id 属性或 service DID 参数或两者都包含相对引用,则必须(MUST)根据 RFC3986 第 5 节:引用解析和 [[[DID-CORE]]] 中 相对 DID URL 章节中指定的规则解析并使用对应的绝对 URI 来确定匹配。
      2. 如果输入 DID URL 包含 DID 参数 serviceType: 如果 servicetype 属性与 serviceType DID 参数的值匹配,则选择该服务。
      所选的 services 构成一个称为所选 services 的列表。
    2. 如果输入 DID URL 包含 DID 参数 relativeRef
      1. 对每个所选 service
        1. 如果所选 serviceserviceEndpoint 属性值是一个 映射,跳过此所选 service
        2. 如果所选 serviceserviceEndpoint 属性值是一个 字符串,将此值添加到所选 service endpoint URL 列表中。
        3. 如果所选 serviceserviceEndpoint 属性值是一个 集合,将其中所有 字符串项添加到所选 service endpoint URL 列表中。
      2. 对每个所选 service endpoint URL,按以下方式执行 RFC3986 第 5 节:引用解析中指定的算法:
        1. 基础 URI 值为所选 service endpoint URL
        2. 相对引用DID 参数 relativeRef 的值。
        3. 所选 service endpoint URL 更新为"引用解析"算法的结果。

        解析 service endpoint——特别是当它是 DID 时——可能导致 resolution cycle(解析循环),即一组导致无限循环的步骤。例如,service endpoint 可能通过一系列解析间接指回先前已解引用的标识符。递归解析 service endpointDID resolver 应检测并处理此类循环,以防止无限循环或解析失败。进一步指导请参见 解析循环章节。

    3. 如果 accept 输入 DID 解引用选项缺失,或其值为 DID documentrepresentation 的媒体类型:
      1. 已解析的 DID document 中的 services 更新为仅包含所选 services
      2. 返回以下结果:
        1. dereferencingMetadata«[ ... ]»
        2. content包含所选服务的已解析 DID 文档
        3. contentMetadata«[ 已解析的 DID 文档元数据
    4. 如果 accept 输入 DID 解析选项的值为 text/uri-list
      1. 返回以下结果:
        1. dereferencingMetadata«[ ... ]»
        2. content« 所选服务端点 URL »
        3. contentMetadata«[ "contentType" → "text/uri-list", ... ]»
    5. 否则,返回以下结果:
      1. dereferencingMetadata错误对象,type 设置为 REPRESENTATION_NOT_SUPPORTED
      2. contentnull
      3. contentMetadata«[ ]»
  9. 否则,如果输入 DID URL 包含 DID path 和/或 DID query
    did:example:1234/custom/path?customquery
    1. 适用的 DID method 可以(MAY)指定如何解引用输入 DID URLDID path 和/或 DID query
      did:example:1234/resources/1234
    2. 扩展规范可以(MAY)指定如何解引用输入 DID URLDID path
      did:example:1234/whois
    3. 扩展规范可以(MAY)指定如何解引用输入 DID URLDID query
      did:example:1234?transformKey=JsonWebKey
    4. 客户端可以(MAY)以应用特定的方式解引用输入 DID URL
  10. 如果此算法、适用的 DID method、扩展规范或客户端都无法解引用输入 DID URL,返回以下结果:
    1. dereferencingMetadata错误对象,type 设置为 NOT_FOUND
    2. contentStreamnull
    3. contentMetadata«[ ]»

解引用片段

如果输入 DID URL 包含 DID fragment,则片段的解引用取决于资源的媒体类型([[RFC2046]]),即 的结果。

  1. 如果 的结果是输出 DID document,且输入 DID URL 解引用选项包含 verificationRelationship 选项:
    1. verificationRelationshipverificationRelationship 选项的值。
    2. verificationMethod 为根据 DID 文档媒体类型的规则从输出 DID document 中解引用 DID fragment 的结果。
    3. 如果 verificationMethod 不是 合规验证方法,必须(MUST)引发错误,且应当(SHOULD)传达错误类型 INVALID_VERIFICATION_METHOD
    4. 如果 verificationMethod 未通过引用(URL)或通过值(对象)与输出 DID document 中由 verificationRelationship 标识的 验证关系数组关联,必须(MUST)引发错误,且应当(SHOULD)传达错误类型 INVALID_RELATIONSHIP_FOR_VERIFICATION_METHOD
    5. 返回 verificationMethod
  2. 如果 的结果是所选 service endpoint URL,且输入 DID URL 包含 DID fragment
    did:example:1234?service=files&relativeRef=%2Fmyresume%2Fdoc%3Fversion%3Dlatest#intro
    1. 如果所选 service endpoint URL 包含 fragment 组件,引发错误。
    2. DID fragment 附加到所选 service endpoint URL。换言之,所选 service endpoint URL"继承"了输入 DID URLDID fragment
    3. 返回所选 service endpoint URL
  3. 否则,按资源的媒体类型([[RFC2046]])定义的方式解引用 DID 片段。例如,如果资源是媒体类型为 application/did 的 DID 文档表示,则片段按与 JSON-LD 1.1: application/ld+json 媒体类型 [JSON-LD11] 关联的规则处理。

DID fragment 的使用与 [[RFC3986]] 中片段标识符的定义一致。它标识的是次要资源,是主要资源DID document)的子集。

DID fragment 的此行为类似于 HTTP URL 中片段的处理方式,即当解引用它返回带有 Location 头的 HTTP 3xx(重定向)响应时(参见 [[RFC7231]] 第 7.1.2 节)。

示例

示例:解引用到验证方法

给定以下输入 DID URL

	did:example:123456789abcdefghi#keys-1
	

... 以及以下已解析的 DID document

	{
		"@context":[
			"https://www.w3.org/ns/did/v1.1",
			"https://didcomm.org/messaging/contexts/v2",
			"https://identity.foundation/linked-vp/contexts/v1"
		],
		"id": "did:example:123456789abcdefghi",
		"verificationMethod": [{
			"id": "did:example:123456789abcdefghi#keys-1",
			"type": "Multikey",
			"controller": "did:example:123456789abcdefghi",
			"publicKeyMultibase": "z6MkmM42vxfqZQsv4ehtTjFFxQ4sQKS2w6WR7emozFAn5cxu"
		}],
		"service": [{
			"id": "did:example:123456789abcdefghi#messages",
			"type": "DIDCommMessaging",
			"serviceEndpoint": "https://example.com/messages/8377464"
		}, {
			"id": "did:example:123456789abcdefghi#linkedvp",
			"type": "LinkedVerifiablePresentation",
			"serviceEndpoint": "https://example.com/verifiable-presentation.jsonld"
		}]
	}
	

... 则 算法的结果为以下输出资源

	{
		"@context": "https://www.w3.org/ns/did/v1.1",
		"id": "did:example:123456789abcdefghi#keys-1",
		"type": "Multikey",
		"controller": "did:example:123456789abcdefghi",
		"publicKeyMultibase": "z6MkmM42vxfqZQsv4ehtTjFFxQ4sQKS2w6WR7emozFAn5cxu"
	}
	
展示 DID URL 如何解引用到验证方法的图表
将 DID URL 解引用到验证方法。

示例:解引用到服务端点 URL

给定以下输入 DID URL

	did:example:123456789abcdefghi?service=messages&relativeRef=%2Fsome%2Fpath%3Fquery#frag
	

... 以及上一节中相同的已解析的 DID document

... 则 算法的结果为以下所选 service endpoint URL

	https://example.com/messages/8377464/some/path?query#frag
	
展示 DID URL 如何解引用到服务端点 URL 的图表
将 DID URL 解引用到服务端点 URL。

元数据结构

DID ResolutionDID URL dereferencing 及其他 DID 相关过程中通常涉及输入和输出元数据。用于传达此元数据的结构必须(MUST)是一个属性 映射。每个属性名必须(MUST)是一个 字符串。每个属性值必须(MUST)是 字符串数字映射列表集合布尔值null。任何复杂数据结构(如映射或列表)中的值也必须(MUST)是这些数据类型之一。在 DID Resolution Extensions [[?DID-EXTENSIONS-RESOLUTION]] 中注册的所有元数据属性定义必须(MUST)定义值类型,包括对该值的任何其他格式或限制(例如,格式化为日期的字符串)。建议(RECOMMENDED)属性定义使用字符串作为值。整个元数据结构必须(MUST)可根据 [[INFRA]] 规范中的 JSON 序列化规则进行序列化。实现可以(MAY)将元数据结构序列化为其他数据格式。

所有使用元数据结构作为输入或输出的函数实现都能够以确定性方式完全表示此处描述的所有数据类型。由于使用元数据结构的输入和输出是根据数据类型而非其序列化来定义的,因此 representation 的方法是函数实现内部的,超出本规范的范围。

以下示例展示了一个可能用作 DID 解析输入元数据的 JSON 编码元数据结构。

{
"accept": "application/did"
}
  

此示例对应于以下格式的元数据结构:

«[
"accept" → "application/did"
]»
  

下一个示例展示了当 DID 未找到时可能用作 DID 解析元数据的 JSON 编码元数据结构。

{
"error": "notFound"
}
  

此示例对应于以下格式的元数据结构:

«[
"error" → "notFound"
]»
  

下一个示例展示了可能用作 DID 文档元数据的 JSON 编码元数据结构,用于描述与 DID document 相关联的时间戳。

{
"created": "2019-03-23T06:35:22Z",
"updated": "2023-08-10T13:40:06Z"
}
  

此示例对应于以下格式的元数据结构:

«[
"created" → "2019-03-23T06:35:22Z",
"updated" → "2023-08-10T13:40:06Z"
]»
  

DID 解析架构

方法架构

DID resolution 算法涉及根据其 DID methodDID 执行 Read 操作(参见 )。

每个 DID 方法都定义了此方法操作,即 DID resolver 如何从 DID 获取 DID 文档。底层数据格式、协议、技术基础设施和流程在不同 DID methods 之间可能差异很大。

DID 方法注意事项的示例包括以下内容:

基于上述注意事项以及 DID method's "读取"操作的性质,DID resolververifiable data registry 之间的交互可被视为 verifiable readunverifiable read

展示 DID 方法的'可验证读取'实现的图表。
DID methodverifiable read 实现。
展示 DID 方法的'不可验证读取'实现的图表。
DID methodunverifiable read 实现。

verifiable read 在适用 DID method 下可能的范围内最大化对"读取"操作结果的完整性和正确性的信心。这可以通过多种方式实现,例如以下方式:

unverifiable read 没有这样的保证,因此不太理想,例如:

verifiable read 是否可能不仅取决于 DID method 本身,还取决于 DID resolver 实现该 DID method 的方式。DID methods 可以(MAY)允许多种实现其"读取"操作的方式,并应当(SHOULD)提供关于至少一种实现 verifiable read 的方式的指导。

verifiable read 相关的保证始终受到 DID method's 底层 verifiable data registry 的架构、协议、加密元素和其他方面的限制。被认为最强的 verifiable read 实现形式是那些不需要与任何远程网络交互的形式(例如,参见 [[DID-KEY]]),以及那些最小化对特定网络基础设施依赖的形式,将"信任根"减少到经验证的熵和密码学(例如,参见 [[KERI]])。

为了启用 verifiable reads,许多 DID 方法使用数字签名、状态证明、Merkle 树包含证明、加密事件日志或其他类型的证明。如果 DID method 使用此类证明,它必须(MUST)在其 DID 方法规范中指定如何使用它们来验证"读取"操作结果的正确性。

DID method 也可以(MAY)将此类证明包含在 DID document 本身中,或包含在 DID 文档元数据proof 属性中。这可能使 client 能够独立验证 DID Resolution 过程的结果,即使它不信任 DID resolver

请注意,来自 DID method 的证明是 DID method 特定的,必须在适用 DID method 的技术框架内理解。DID documentDID 文档元数据上的简单签名并不一定证明对 DID 的控制权,也不保证 DID document 对于该 DID 是正确的。这些证明有助于验证 DID Resolution 过程结果的完整性和真实性(就 DID method 本身而言)。然而,它们不保证 clientDID resolver 之间的 binding 是安全的。另请参见

解析器架构

DID resolutionDID URL dereferencing 的算法定义为抽象函数(参见 )。

这些算法由 DID resolversDID URL dereferencers 实现,由 client 通过 binding 调用。绑定定义了如何使用具体的编程或通信接口访问抽象函数。

绑定的示例包括以下内容:

基于上述注意事项以及绑定的性质,clientDID resolverDID URL dereferencer 之间的交互可被视为 local bindingremote binding

展示具有'本地绑定'的 DID 解析器的图表。
DID resolverlocal binding
展示具有'远程绑定'的 DID 解析器的图表。
DID resolverremote binding

在可能的情况下,首选 local bindings,因为它们最大限度地减少对第三方和中间方的依赖,降低安全风险,并最大化对 DID resolutionDID URL dereferencing 函数结果的完整性和正确性的信心。

在某些情况下,可能无法使用 local binding;例如,在受限的物联网(IoT)环境中,或当 DID method 需要复杂的基础设施时,或当需要支持多种不同的 DID methods 时。

如果 client 使用 remote binding,适用以下注意事项:

DID resolver 也可以(MAY)在 DID 解析元数据proof 属性中包含证明。此包含可能使 client 能够独立验证 DID Resolution 过程的结果,只要它信任 DID resolver

请注意,来自 DID resolver 的证明与 DID method 无关,可以由 DID resolver 跨所有 DID 方法普遍应用。这些证明有助于验证 DID Resolution 过程结果的完整性和真实性(就 DID resolver 本身而言)。然而,它们不保证适用 DID method 的"读取"操作的结果本身是正确的。另请参见

多方法支持

DID resolver 必须(MUST)支持至少一种 DID methodDID resolution 算法,并且可以(MAY)支持多种 DID methods

展示支持多种 DID 方法的 DID 解析器的图表。
支持多种 DID methodsDID resolver

在这种情况下, 中关于 verifiable readunverifiable read 实现的上述注意事项分别适用于每个支持的 DID method

代理解析

DID resolver 可以(MAY)调用另一个 DID resolver,后者作为代理执行 中定义的 DID resolution 算法。

第一个 DID resolver 随后充当 client 的角色,并为调用第二个 DID resolver 选择合适的 binding。例如,DID resolver 可以通过 local binding(如命令行工具)调用,后者又通过 remote binding(如 HTTP(S) 绑定)调用另一个 DID resolver

在使用代理解析时,"下游"解析器应当(SHOULD)以透明的方式保留来自"上游"解析器的所有 DID 解析元数据DID 文档元数据,包括可能存在的任何证明。在此过程中,"下游"解析器可以(MAY)添加自己的 DID 解析元数据,包括关于代理解析过程本身的任何元数据。

展示两个 DID 解析器的图表,一个通过'本地绑定'调用,另一个通过'远程绑定'调用。
client 通过 local binding 调用 DID resolver,后者通过 remote binding 调用另一个 DID resolver,后者再从 DID method 读取。

这类似于 DNS 架构中"存根解析器"调用"递归解析器",尽管这些概念并非完全可比(DNS 解析使用单一的具体协议,而 DID 解析是由不同 DID methods 和不同 bindings 实现的抽象函数)。

客户端侧解引用

DID URL 解引用算法的不同部分可能由解析器架构的不同组件执行。

具体来说,当解引用带有 DID fragmentDID URL 时,解引用资源DID resolver 完成,而 解引用片段client 完成。

示例

给定 DID URL did:xyz:1234#keys-1,可以通过 local binding 调用 DID resolver 来执行 解引用资源(即 DID document),client 可以通过 解引用片段(即 DID document 的一部分)来完成 DID URL dereferencing 算法。

展示由 DID 解析器和客户端进行的 DID URL 客户端侧解引用的图表
DID resolverclient 进行的 DID URL 客户端侧解引用。

给定 DID URL did:xyz:1234?service=agent&relativeRef=%2Fsome%2Fpath%3Fquery#frag,可以调用 DID resolver 来执行 解引用资源(即 service endpoint URL),client 可以通过 解引用片段(即带片段的 service endpoint URL)来完成 DID URL dereferencing 算法。

展示由 DID 解析器和客户端进行的 DID URL 客户端侧解引用的图表
DID resolverclient 进行的 DID URL 客户端侧解引用。

给定 DID URL did:xyz:1234#keys-1,可以通过 local binding 调用 DID resolver,后者通过 remote binding 调用另一个 DID resolver 来执行 解引用资源(即 DID document),client 可以通过 解引用片段(即 DID document 的一部分)来完成 DID URL dereferencing 算法。

展示由两个 DID 解析器和客户端进行的 DID URL 客户端侧解引用的图表
客户端侧解引用(结合代理解析),由两个 DID resolversclientDID URL 进行。

DID 解析结果

本节定义了一个表示 中所述算法结果的 JSON 数据结构。DID resolution result 包含 DID document 以及 DID 解析元数据DID 文档元数据

此数据结构的媒体类型定义为 `application/did-resolution`。

示例

{
	"didDocument": {
		"@context": "https://www.w3.org/ns/did/v1",
		"id": "did:example:123456789abcdefghi",
		"authentication": [{
			"id": "did:example:123456789abcdefghi#keys-1",
			"type": "Ed25519VerificationKey2018",
			"controller": "did:example:123456789abcdefghi",
			"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
		}],
		"service": [{
			"id":"did:example:123456789abcdefghi#vcs",
			"type": "VerifiableCredentialService",
			"serviceEndpoint": "https://example.com/vc/"
		}]
	},
	"didResolutionMetadata": {
		"contentType": "application/did",
		"retrieved": "2024-06-01T19:73:24Z",
	},
	"didDocumentMetadata": {
		"created": "2019-03-23T06:35:22Z",
		"updated": "2023-08-10T13:40:06Z",
		"method": {
			"nymResponse": {
				"result": {
					"data": "{\"dest\":\"WRfXPg8dantKVubE3HX8pw\",\"identifier\":\"V4SGRU86Z58d6TV7PBUe6f\",\"role\":\"0\",\"seqNo\":11,\"txnTime\":1524055264,\"verkey\":\"H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV\"}",
					"type": "105",
					"txnTime": 1.524055264E9,
					"seqNo": 11.0,
					"reqId": 1.52725687080231475E18,
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"dest": "WRfXPg8dantKVubE3HX8pw"
				},
				"op": "REPLY"
			},
			"attrResponse": {
				"result": {
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"seqNo": 12.0,
					"raw": "endpoint",
					"dest": "WRfXPg8dantKVubE3HX8pw",
					"data": "{\"endpoint\":{\"xdi\":\"http://127.0.0.1:8080/xdi\"}}",
					"txnTime": 1.524055265E9,
					"type": "104",
					"reqId": 1.52725687092557056E18
				},
				"op": "REPLY"
			}
		}
	}
}

DID URL 解引用结果

本节定义了一个表示 中所述算法结果的 JSON 数据结构。DID URL dereferencing result 包含内容以及 DID URL 解引用元数据DID URL 内容元数据

此数据结构的媒体类型定义为 `application/did-url-dereferencing`。

示例

{
	"content": {
		"@context": "https://www.w3.org/ns/did/v1",
		"id": "did:example:123456789abcdefghi",
		"authentication": [{
			"id": "did:example:123456789abcdefghi#keys-1",
			"type": "Ed25519VerificationKey2018",
			"controller": "did:example:123456789abcdefghi",
			"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
		}],
		"service": [{
			"id":"did:example:123456789abcdefghi#vcs",
			"type": "VerifiableCredentialService",
			"serviceEndpoint": "https://example.com/vc/"
		}]
	},
	"didUrlDereferencingMetadata": {
		"contentType": "application/did",
		"retrieved": "2024-06-01T19:73:24Z",
	},
	"contentMetadata": {
		"created": "2019-03-23T06:35:22Z",
		"updated": "2023-08-10T13:40:06Z",
		"method": {
			"nymResponse": {
				"result": {
					"data": "{\"dest\":\"WRfXPg8dantKVubE3HX8pw\",\"identifier\":\"V4SGRU86Z58d6TV7PBUe6f\",\"role\":\"0\",\"seqNo\":11,\"txnTime\":1524055264,\"verkey\":\"H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV\"}",
					"type": "105",
					"txnTime": 1.524055264E9,
					"seqNo": 11.0,
					"reqId": 1.52725687080231475E18,
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"dest": "WRfXPg8dantKVubE3HX8pw"
				},
				"op": "REPLY"
			},
			"attrResponse": {
				"result": {
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"seqNo": 12.0,
					"raw": "endpoint",
					"dest": "WRfXPg8dantKVubE3HX8pw",
					"data": "{\"endpoint\":{\"xdi\":\"http://127.0.0.1:8080/xdi\"}}",
					"txnTime": 1.524055265E9,
					"type": "104",
					"reqId": 1.52725687092557056E18
				},
				"op": "REPLY"
			}
		}
	}
}

错误

本规范中描述的算法会抛出特定类型的错误。实现者可能会发现将这些错误传达给其他库或软件系统很有用。本节为错误提供了特定的 URL 和描述,以便实现本规范所述技术的生态系统在发生错误时可以更有效地互操作。此外,本规范使用了 [[CID]] 规范 第 3.5 节处理错误中定义的一些错误。

实现者应当(SHOULD)使用 [[RFC9457]] 来编码错误数据结构。如果使用 [[RFC9457]]:

INVALID_DID
DID Resolution 过程中检测到无效 DID。参见 章节。
INVALID_DID_DOCUMENT
[=DID document=] 格式错误。参见 章节。
NOT_FOUND
DID resolver 无法找到此解析请求产生的 DID document。参见 章节。
REPRESENTATION_NOT_SUPPORTED
通过 accept 输入元数据属性请求的 representation 不被 DID method 和/或 DID resolver 实现支持。参见 章节。
INVALID_DID_URL
DID URL dereferencing 过程中检测到无效 DID URL。参见 章节。
METHOD_NOT_SUPPORTED
DID 的 DID 方法不被 DID resolver 支持。参见 章节。
INVALID_OPTIONS
DID ResolutionDID URL dereferencing 提供的一个或多个选项无效。
INTERNAL_ERROR
DID ResolutionDID URL dereferencing 过程中发生意外错误。
FEATURE_NOT_SUPPORTED
DID resolver 不支持请求的功能。`detail` 字段的值应当(SHOULD)提供解析器不支持的功能的较长描述。
https://w3id.org/security#INVALID_PUBLIC_KEY
DID ResolutionDID URL dereferencing 过程中检测到无效的公钥值。
https://w3id.org/security#INVALID_PUBLIC_KEY_LENGTH
DID ResolutionDID URL dereferencing 过程中,rawPublicKeyBytes 的字节长度与关联 multicodecValue 的预期公钥长度不匹配。
https://w3id.org/security#INVALID_PUBLIC_KEY_TYPE
DID ResolutionDID URL dereferencing 过程中检测到无效的公钥类型。
https://w3id.org/security#UNSUPPORTED_PUBLIC_KEY_TYPE
DID ResolutionDID URL dereferencing 过程中检测到不支持的公钥类型。

绑定

本节为 章节中的抽象算法定义绑定。

HTTP(S) 绑定

本节定义了一个 DID resolver binding,通过 HTTP(S) 端点暴露 DID resolution 和/或 DID URL dereferencing 函数(包括所有解析/解引用选项和元数据)。参见

HTTP(S) 绑定需要一个已知的 HTTP(S) URL,可以在该 URL 处调用 DID resolver。此 URL 称为 DID resolver HTTP(S) 端点

此绑定通常被视为 remote binding,但如果 HTTP(S) 端点在本地环境中运行(如 localhost),也可以是 local binding

使用此绑定,可以按以下方式执行 DID resolution 函数(参见 )和/或 DID URL dereferencing 函数(参见 ):

  1. 使用 DID resolver HTTP(S) 端点初始化请求 HTTP(S) URL
    https://resolver.example/1.0/identifiers/
  2. 对于 DID resolution 函数:
    1. 输入 DID 附加到请求 HTTP(S) URL
      https://resolver.example/1.0/identifiers/did:example:1234
    2. Accept HTTP 请求头设置为 `application/did-resolution` 以请求完整的 ,或者
    3. Accept HTTP 请求头设置为 accept 解析选项的值以仅请求结果中的 didDocument 值。
  3. 对于 DID URL dereferencing 函数:
    1. 输入 DID URL 附加到请求 HTTP(S) URL
      https://resolver.example/1.0/identifiers/did:example:1234?service=files&relativeRef=/resume.pdf
    2. Accept HTTP 请求头设置为 `application/did-url-dereferencing` 以请求完整的 ,或者
    3. Accept HTTP 请求头设置为 accept 解引用选项的值以仅请求结果中的 contentStream 值。
  4. 对于 HTTP(S) GET 绑定:
    1. 如果提供了除 accept 之外的其他解析选项解引用选项
      1. 输入 DID 必须(MUST)进行 URL 编码(如 RFC3986 第 2.1 节中所指定)。
      2. 将除 accept 之外的所有解析选项编码为请求 HTTP(S) URL 中的查询参数。
    2. 请求 HTTP(S) URL 上执行 HTTP GET 请求。这将在远程 DID resolver 上调用 DID resolutionDID URL dereferencing 函数。
      GET https://resolver.example/1.0/identifiers/did%3Aexample%3A1234?option1=value1&option2=value2 HTTP/1.1
      Accept: application/did-resolution
      
      GET https://resolver.example/1.0/identifiers/did%3Aexample%3A1234%3Fservice%3Dfiles%26relativeRef%3D%2Fresume.pdf?option1=value1&option2=value2 HTTP/1.1
      Accept: application/did-url-dereferencing
      
  5. 对于 HTTP(S) POST 绑定:
    1. 如果提供了除 accept 之外的其他解析选项解引用选项
      1. 将除 accept 之外的所有解析选项编码为 HTTP 请求 POST 主体中的 JSON 结构。
    2. 请求 HTTP(S) URL 上执行 HTTP POST 请求。这将在远程 DID resolver 上调用 DID resolutionDID URL dereferencing 函数。
      POST https://resolver.example/1.0/identifiers/did:example:1234 HTTP/1.1
      Accept: application/did-resolution
      
      {
          "option1": "value1",
          "option2": "value2"
      }
      POST https://resolver.example/1.0/identifiers/did:example:1234?service=files&relativeRef=/resume.pdf HTTP/1.1
      Accept: application/did-url-dereferencing
      
      {
          "option1": "value1",
          "option2": "value2"
      }
  6. 如果 DID resolutionDID URL dereferencing 函数在 didResolutionMetadatadereferencingMetadata 中返回 error 元数据属性,则 HTTP 响应状态码必须(MUST)根据以下表格对应 error 元数据属性的值:
    错误 HTTP 状态码
    INVALID_DID 400
    INVALID_DID_URL 400
    INVALID_OPTIONS 400
    NOT_FOUND 404
    REPRESENTATION_NOT_SUPPORTED 406
    INVALID_DID_DOCUMENT 500
    METHOD_NOT_SUPPORTED 501
    INVALID_PUBLIC_KEY 500
    INVALID_PUBLIC_KEY_LENGTH 500
    INVALID_PUBLIC_KEY_TYPE 500
    UNSUPPORTED_PUBLIC_KEY_TYPE 501
    INTERNAL_ERROR 500
    (any other value) 500
  7. 如果 DID resolutionDID URL dereferencing 函数在 didDocumentMetadatacontentMetadata 中返回值为 truedeactivated 元数据属性:
    1. HTTP 响应状态码必须(MUST)为 410
  8. 对于 DID resolution 函数:
    1. 如果 Content-Type HTTP 响应头的值为 `application/did-resolution`:
      1. HTTP 主体必须(MUST)包含作为 DID resolution 函数结果的 DID resolution result(参见 )。
    2. 如果函数成功并返回 didDocument
      1. HTTP 响应状态码必须(MUST)为 200
      2. HTTP 响应必须(MUST)包含 Content-Type HTTP 响应头。其值必须(MUST)为 didResolutionMetadatacontentType 元数据属性的值(参见 )。
      3. HTTP 响应主体必须(MUST)包含作为 DID resolution 函数结果的 didDocument,以对应 Content-Type HTTP 响应头的表示形式。
  9. 对于 DID URL dereferencing 函数:
    1. 如果 Content-Type HTTP 响应头的值为 `application/did-url-dereferencing`:
      1. HTTP 主体必须(MUST)包含作为 DID URL dereferencing 函数结果的 DID URL dereferencing result(参见 )。
    2. 如果函数成功并在 dereferencingMetadata 中返回 contentStream 和值为 text/uri-listcontentType 元数据属性:
      1. HTTP 响应状态码必须(MUST)为 303
      2. HTTP 响应必须(MUST)包含 Location 头。此头的值必须(MUST)为所选 service endpoint URL
      3. HTTP 响应主体必须(MUST)为空。
    3. 如果函数成功并返回具有任何其他 contentTypecontentStream
      1. HTTP 响应状态码必须(MUST)为 200
      2. HTTP 响应必须(MUST)包含 Content-Type HTTP 响应头。其值必须(MUST)为 dereferencingMetadatacontentType 元数据属性的值(参见 )。
      3. HTTP 响应主体必须(MUST)包含作为 DID URL dereferencing 函数结果的 contentStream,以对应 Content-Type HTTP 响应头的表示形式。

参见此处获取对应 HTTP(S) 绑定的 OpenAPI 定义。

DID 解析示例

给定以下 DID resolver HTTP(S) 端点

https://resolver.example/1.0/identifiers/

以及给定以下输入 DID

did:example:123

请求 HTTP(S) URL 为:

https://resolver.example/1.0/identifiers/did:example:123

示例:返回 DID 解析结果

可以通过 HTTP(S) 绑定按以下方式调用 resolve() 函数:

GET https://resolver.example/1.0/identifiers/did:example:123 HTTP/1.1
Accept: application/did-resolution

响应如下:

HTTP 200 OK
Content-Type: application/did-resolution

{
	"didDocument": {
		"@context": [ "https://www.w3.org/ns/did/v1.1" ],
		"id": "did:example:123",
		"verificationMethod": [{
			...
		}],
		"service": [{
			...
		}]
	},
	"didResolutionMetadata": {
		"contentType": "application/did"
	},
	"didDocumentMetadata": {
		...
	}
}

示例:返回 DID 文档

可以通过 HTTP(S) 绑定按以下方式调用 resolve() 函数:

GET https://resolver.example/1.0/identifiers/did:example:123 HTTP/1.1
Accept: application/did

响应如下:

HTTP 200 OK
Content-Type: application/did

{
	"@context": [ "https://www.w3.org/ns/did/v1.1" ],
	"id": "did:example:123",
	"verificationMethod": [{
		...
	}],
	"service": [{
		...
	}]
}

DID URL 解引用示例

示例:返回 DID URL 解引用结果

可以通过 HTTP(S) 绑定按以下方式调用 dereference() 函数:

GET https://resolver.example/1.0/identifiers/did:example:123?versionId=2 HTTP/1.1
Accept: application/did-url-dereferencing

响应如下:

HTTP 200 OK
Content-Type: application/did-url-dereferencing

{
	"content": {
		"@context": [ "https://www.w3.org/ns/did/v1.1" ],
		"id": "did:example:123",
		"verificationMethod": [{
			...
		}],
		"service": [{
			...
		}]
	},
	"dereferencingMetadata": {
		"contentType": "application/did"
	},
	"contentMetadata": {
		...
	}
}

示例:返回资源

可以通过 HTTP(S) 绑定按以下方式调用 dereference() 函数:

GET https://resolver.example/1.0/identifiers/did:example:123?versionId=2 HTTP/1.1
Accept: application/did

响应如下:

HTTP 200 OK
Content-Type: application/did

{
	"@context": [ "https://www.w3.org/ns/did/v1.1" ],
	"id": "did:example:123",
	"verificationMethod": [{
		...
	}],
	"service": [{
		...
	}]
}

安全注意事项

身份验证/授权

DID resolutionDID URL dereferencing 不涉及任何身份验证或授权功能。类似于 DNS 解析,任何人都可以执行此过程,而无需任何凭证或非公开知识。

解释 DID 不一定是全局可解析的,例如成对或 N 方"对等"DID。

参见 [[RFC3339]]: URI 具有全局范围,无论上下文如何都以一致的方式解释,尽管解释的结果可能与最终用户的上下文有关。

一个高级想法是 DID 解析的结果可能是上下文相关的或依赖于策略,参见此评论

一个相关主题是 DID 文档的(部分)是否可以加密,例如 w3c/did-core/issues/25。另请参见 IPID DID 方法中片段的使用。

缓存

DID resolver 可以维护 DID documents 的通用缓存。它也可以维护特定于某些 DID methods 的缓存。

noCache 解析选项可用于请求特定的缓存行为。

解析选项是可选的(OPTIONAL)。

此属性的可能值为:

缓存行为可以通过 DID resolver 的配置、noCache 解析选项或 DID 文档内容(例如 `cacheMaxTtl` 字段)或这些属性的组合来控制。

实现 noCache 的解析器可能更容易受到拒绝服务攻击,因为恶意客户端可以绕过缓存来强制执行昂贵的网络请求和资源消耗。请求使用 noCache 进行解析的客户端应预期某些解析器会拒绝绕过缓存的解析请求。拒绝无缓存解析的解析器必须(MUST)响应 FEATURE_NOT_SUPPORTED 错误,明确表示不允许绕过缓存,以便客户端可以尝试不使用 noCache 进行解析。

JSON-LD 上下文完整性

如果从远程位置获取 JSON-LD 上下文文件,攻击者可能会篡改上下文文件(例如通过入侵服务器或通过中间人攻击拦截请求)。

因此,强烈建议执行远程 JSON-LD 上下文 URL 检索的任何 DID resolver 使用上下文文件及其对应哈希的注册表(或功能等效的机制)来帮助确保端到端安全性。预期实现如果资源的加密哈希值与预期哈希值不匹配则抛出错误。

版本控制

如果提供了 versionIdversionTime DID 参数,DID resolution 算法会返回 DID document 的特定版本。

DID 参数 versionIdversionTime 是互斥的。

versionId DID 参数的使用是 DID method 特定的。其可能的值可能包括顺序号、随机 UUID、内容哈希等。

DID 文档元数据可以(MAY)包含一个 versionId 属性,该属性随对 DID 文档执行的每次 Update 操作而变化。

虽然大多数 DID methods 支持 Update 操作,但不要求 DID methods 保留所有先前的 DID document 版本,因此并非所有 DID methods 都支持版本控制。

VDR 网络分叉

使用分布式系统(如分布式账本)作为 VDR(verifiable data registry)的 DID methods 需要管理可能发生网络分叉的潜在风险。因此,使用分布式系统作为 VDR 的 DID method 规范应当(SHOULD)指定一种方式,以将其使用的 VDR 与此类分叉区分开来。

解析循环

DID resolver 客户端解引用 DID document 中的标识符和链接资源时——特别是 verificationMethodcontrolleralsoKnownAs 等字段——它可能会遇到 resolution cycle。当 DID document 引用另一个 DID(或 URL)最终导回先前解引用的标识符,形成循环时,就会发生这种情况。DID resolver 在解引用引用 service endpointDID URL 时也可能遇到这种情况。

did:example:alice
	└── verificationMethod.controller → did:example:bob
		└── verificationMethod.controller → did:example:alice

执行递归解引用的 DID resolvers 及其客户端应预期、检测和处理此类循环

安全和性能风险:如果未检测和缓解循环,递归解引用可能导致:

缓解指导:递归跟踪外部 DID document 引用的组件应跟踪已经解引用的标识符,检测循环发生的时间并采取适当行动。此外,开发者可能希望限制递归深度或广度以减少潜在攻击面。

隐私注意事项

DID 解析和解引用请求者的画像分析

DID resolversDID URL dereferencers 将能够记录对其解析和解引用服务的请求。随着时间的推移,这些日志可能被用于跟踪和分析发出这些服务请求的客户端。为了缓解这种隐私风险,客户端应向其信任的服务发出此类请求,例如由于现有的业务关系或因为该服务运行在其控制的基础设施上。客户端还可以采取措施混淆其对服务的请求,以限制关联和画像分析的可能性。

与其他技术的关系

用于将标识符解析为互联网地址的最常见机制之一是 [[?RFC1034]] 中描述的全球域名系统(DNS)。DNS 以及用于将域名映射到互联网协议地址的过程和系统是托管网站的常见需求。

[[[DID]]] 规范引入了一种不依赖全球域名系统的新型标识符,并引入了不需要集中化架构任何部分的标识符解析过程的概念。这种新架构允许去中心化地创建和管理全局可解析的标识符,以对抗标识符寻租和审查。它使个人能够完全拥有和控制其标识符,而不是从第三方租用标识符。

获取 [=DID URLs=] 的个人在其软件中使用它们,就像他们继续使用基于 DNS 的 URL 一样。软件使用 [=DID resolver=] 接口(在本规范中定义)来确定要检索的资源的位置。[=DID resolution=] 的过程,就像 DNS 解析的过程一样,对个人来说是不透明的,在软件内部发生而不需要个人的任何直接参与。

与 DNS 集中化相关的研究以及 [=DIDs=] 和 [=DID resolution=] 的相应发明记录在 [[[?DID]]] 规范中与 DID 的历史相关的章节中。

DID 解析资源

  1. DID Core 规范中的 DID 解析器
  2. Universal Resolver
  3. did-client
  4. uPort DID resolver