可验证凭证渲染方法 v1.0

W3C 工作草案

关于本文档的更多详细信息
此版本:
https://www.w3.org/TR/2026/WD-vc-render-method-20260405/
最新发布版本:
https://www.w3.org/TR/vc-render-method/
最新编辑者草案:
https://w3c.github.io/vc-render-method/
历史记录:
https://www.w3.org/standards/history/vc-render-method/
提交历史
编辑者:
Dmitri Zagidulin (MIT 数字凭证 联盟)
Manu Sporny (Digital Bazaar)
Patrick St. Louis (Open Security and Identity)
Hendry POH (新加坡资讯通信媒体发展局)
Isaac KOH (新加坡资讯通信媒体发展局)
作者:
Manu Sporny (Digital Bazaar)
Dmitri Zagidulin (MIT 数字凭证 联盟)
Calvin Cheng (新加坡政府科技局)
Kyle Huang Junyuan (新加坡政府 科技局)
Patrick St. Louis (Open Security and Identity)
反馈:
GitHub w3c/vc-render-method (拉取请求, 新问题, 未解决的问题)

摘要

本规范描述了可验证凭证数据模型的一种扩展机制,该机制可用于通过 视觉、听觉或触觉媒介来表示可验证凭证。它涵盖了 将可验证凭证渲染到实体文档、数字图像、 屏幕阅读器或盲文输出。

本文档的状态

本节描述本文档在发布时的状态。 当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准和草案 索引中找到。

这是一份实验性规范,并且正在定期修订。它 不适合用于生产部署。

本文档由可验证凭证工作 组作为 工作草案发布,并使用 推荐标准轨道

作为工作草案发布并不 意味着获得 W3C 及其成员的认可。

这是一份草案文档,可能随时被其他文档 更新、替换或废弃。除作为正在进行中的工作外, 不宜引用本文档。

本文档由一个根据 W3C 专利 政策运作的小组制作。 W3C 维护一个 任何专利披露的公开列表, 这些披露与该小组的交付物有关; 该页面还包含 披露专利的说明。任何实际 知悉某项专利并认为该专利包含 必要权利要求的个人, 必须根据 W3C 专利政策第 6 节披露相关信息。

本文档受 2025年8月18日 W3C 流程文档管辖。

1. 引言

颁发者有特定方式, 想要通过视觉、听觉或触觉机制向观察者表达可验证凭证时, 可以使用渲染方法。例如,某个员工徽章凭证的颁发者可能希望包含 其企业徽标的丰富图像,并将员工信息具体放置在徽章的 特定区域。他们还可能希望为有与视力相关的 无障碍需求的个人提供该徽章重要方面的音频朗读。

1.1 术语

以下术语用于描述本规范中的概念。

声明
关于某个主体作出的断言。
凭证
颁发者作出的一组一个或多个声明。 凭证中的声明可以关于不同的主体

我们对凭证的定义不同于 NIST 对 凭证的定义

数据 最小化
将共享数据量严格限制为成功完成任务或目标所需的 最小量的行为。
去中心化标识符
一种基于 URL 的可移植标识符,也称为 DID, 与某个实体相关联。这些标识符最常用于 可验证凭证,并与 主体相关联,使得 可验证凭证本身可以很容易地 从一个 凭证存储库移植到另一个,而无需 重新颁发该凭证。 DID 的一个示例是 did:example:123456abcdef
去中心化标识符文档
也称为 DID document,这是一个 可使用可验证数据 注册表访问的文档,其中包含 与特定去中心化 标识符相关的信息,例如 关联的凭证存储库和公钥 信息。
默认图
包含所有未明确属于 命名图声明
派生谓词
关于可验证凭证中另一个属性的值的、 可验证的布尔断言。这些在零知识证明风格的 可验证呈示中很有用,因为它们可以 限制信息披露。 例如,如果某个可验证凭证包含用于 以厘米表示特定身高的属性,则派生谓词 可能会引用可验证 凭证中的身高属性, 表明颁发者证明身高值满足 最低身高要求,而无需实际披露具体身高 值。例如,主体高于 150 厘米。
数字签名
一种用于证明数字消息真实性的数学方案。
实体
任何可以在陈述中作为抽象名词或具体名词被引用的事物。 实体包括但不限于人、组织、物理事物、 文档、抽象概念、虚构角色以及任意文本。任何 实体都可能在生态系统中执行角色,只要它有能力这样做。请注意, 有些实体从根本上无法采取行动,例如字符串 "abc" 无法颁发凭证。
一组声明,形成一个由主体 及其与其他主体或数据之间关系组成的信息网络。每个声明都是 某个图的一部分;对于命名图, 这是显式的,或者 对于默认图则是隐式的。
持有者
实体可以通过拥有一个或多个 可验证凭证并从中生成 可验证呈示 而执行的一种角色。持有者通常但不总是其所持有的 可验证凭证主体。 持有者将其 凭证存储在凭证存储库中。
身份
用于跨上下文跟踪实体的手段。数字 身份能够跨数字上下文跟踪和定制实体交互, 通常使用标识符和属性。身份信息的意外 分发或使用可能损害隐私。此类信息的收集 和使用应遵循 数据最小化原则。
身份提供者
身份提供者有时缩写为 IdP,是一种 为持有者创建、维护和管理身份信息的系统, 同时向联盟或分布式网络中的 依赖方应用提供认证服务。 在这种情况下,持有者始终是主体。即使 可验证凭证是不记名凭证,也假定这些 可验证凭证仍由主体持有,如果并非如此, 则它们已被攻击者窃取。本规范不使用该术语, 除非将本文档中的概念与其他 规范进行比较或映射。本规范将身份 提供者 概念解耦为两个不同的概念:颁发者持有者
颁发者
实体可以通过对一个或 多个主体作出声明, 由这些声明创建可验证凭证,并将该可验证凭证传输给 持有者而执行的一种角色。
命名图
与特定属性(例如 verifiableCredential)相关联的。这些属性 会产生独立的,其中包含相应 JSON 对象中定义的所有声明
呈示
从一个或多个可验证凭证派生的数据, 这些凭证由一个或 多个颁发者颁发,并与特定的验证者共享。
凭证存储库
一种程序,例如存储保险库或个人可验证凭证 钱包,用于存储并保护对持有者可验证凭证的访问。
选择性披露
持有者能够就共享哪些 信息作出细粒度决策的能力。
主体
声明所涉及的事物。
用户代理
一种程序,例如浏览器或其他 Web 客户端,它在 持有者颁发者验证者之间 调解通信。
验证
对来自特定颁发者声明, 能够满足验证者针对特定用途的 业务要求的保证。本 规范定义了验证者如何核验可验证凭证可验证呈示
它还规定验证者在依赖可验证 凭证中的声明之前,先对这些声明进行确认。然而,这种确认的手段 差异很大,并且超出本规范的范围。预期 验证者会针对某些 声明信任某些颁发者, 并应用他们自己的规则来确定哪些凭证中的哪些声明 适合由他们的系统使用。
可验证凭证
可验证凭证是一种防篡改凭证,其作者身份 可以通过密码学方式验证。可验证凭证可用于构建 可验证呈示,而后者也可以 通过密码学方式验证。
可验证数据注册表
系统可以通过调解标识符、密钥及其他相关数据(例如 可验证凭证模式、撤销 注册表、颁发者公钥 等)的创建和核验 而执行的一种角色,这些数据可能是使用可验证凭证所必需的。一些 配置可能需要面向主体的可关联标识符。一些 注册表,例如 UUID 和公钥注册表,可能只是充当 标识符的命名空间。
可验证呈示
可验证呈示是一种防篡改的呈示,其编码方式 使数据的作者身份可在密码学 核验过程之后被信任。某些类型的可验证呈示可能包含 从原始可验证凭证合成而来、但不包含 原始可验证凭证的数据 (例如,零知识证明)。
核验
可验证凭证可验证 呈示是否分别为颁发者或呈示者的真实且当前的陈述进行评估。 这包括检查:凭证(或 呈示)是否符合规范;证明方法是否满足;以及 如果存在,状态检查是否成功。对凭证进行核验并不 意味着对凭证中编码的声明的真实性进行评估。
验证者
实体通过接收一个或多个 可验证凭证,并可选地将其置于 可验证呈示中进行处理而执行的一种角色。其他 规范可能将此概念称为依赖方
核验材料
可作为密码学公钥或任何其他用于 核验证明的数据的信息。
URL
统一资源定位符,如 [URL] 所定义。URL 可以被解引用, 从而产生某个资源,例如文档。解引用 或获取 URL 的规则由 URL scheme定义。本规范 不使用术语 URI 或 IRI,因为这些术语被认为会 使 Web 开发者感到困惑。

1.2 一致性

除标记为非规范性的章节外,本规范中的所有编写指南、图示、示例和注释 均为非规范性内容。本规范中的其他所有内容均为规范性内容。

本文档中的关键词 MAYMUSTMUST NOTOPTIONALRECOMMENDEDREQUIREDSHOULD 应按 BCP 14 [RFC2119] [RFC8174] 中所述进行解释,且仅当它们像此处所示以全 大写形式出现时才如此解释。

一致的渲染方法是数据 模型的任何具体表达,只要它符合本规范中的规范性陈述。 具体而言,本文档第 2. 数据模型和第 2.2.4.2 算法 节中的所有相关规范性陈述MUST得到执行。

一致的处理器是任何以 软件和/或硬件实现、用于生成或消费 一致的渲染方法的算法。一致的处理器MUST在 消费不一致文档时产生错误。

本文档还包含一些含有 JSON 和 JSON-LD 内容的示例。其中 一些示例包含无效 JSON 字符,例如内联 注释(//)以及使用省略号(...)表示 对示例价值不大的信息。提醒实现者, 如果希望将这些信息用作有效 JSON 或 JSON-LD,应移除这些内容。

2. 数据模型

以下各节概述了本规范用于渲染方法的数据模型

2.1 renderMethod 属性

renderMethod 属性是可验证凭证数据模型 规范 [VC-DATA-MODEL-2.0] 中的一个 保留扩展点颁发者可以在 可验证凭证中使用此 属性,以表达一个或多个首选 渲染方法。

renderMethod
renderMethod 属性的值MUST指定一个或 多个渲染方法,软件可以使用这些方法通过视觉、听觉或 触觉机制来表达 可验证凭证。每个 renderMethodMUST指定其 type,例如 TemplateRenderMethod。每个渲染 提示的精确内容由具体的 renderMethod type 定义决定。

2.2 TemplateRenderMethod

颁发者希望为 可验证凭证指定基于模板的渲染指令时,他们MAY添加一个使用 以下所述数据模型的 renderMethod 属性。

属性 描述
id 一个OPTIONAL字符串,它遵循 URL 标准,并且在获取时, 会解引用到一个渲染模板。
type 一个REQUIRED字符串,其值MUSTTemplateRenderMethod
renderSuite 一个REQUIRED字符串,用于标识 生成具体渲染所使用的算法。
name 一个OPTIONAL的、人类可读的字符串,可显示出来以提供 将要执行的渲染类型提示。此属性可用于 允许个人在多个呈示模式之间进行选择的 图形界面中。
description 一个OPTIONAL的、人类可读的字符串,相比 name, 它提供了关于特定渲染何时可能有用的更详细 描述。
renderProperty 一个OPTIONAL列表,其中包含字符串值;每个值均符合 JavaScript 对象表示法(JSON) Pointer语法,用于指定在使用此特定渲染方法时, 从可验证凭证中暴露哪些属性。如果 未提供 renderProperty,则在使用渲染方法时,假定会共享整个 可验证凭证
template 一个OPTIONALURL映射, 它提供或引用 将用于执行渲染的模板。如果该值是URL, 则它MAY是包含模板 代码的 data: URL [RFC2397]。如果该值 是映射,则它MUST符合以下规则:
属性 描述
id 一个REQUIRED字符串,它遵循 URL 标准, 并且在获取时, 会解引用到诸如 SVG 或 PDF 文件之类的模板。
mediaType 一个RECOMMENDED字符串,用于标识 id 值的媒体类型, 如 媒体类型 规范和注册过程中所规定。
digestMultibase 模板文件的一个OPTIONAL的、采用 multibase 编码的 Multihash。 multibase 值MUSTu(base64url-nopad),并且 multihash 值MUST为具有 256 位输出的 SHA-2(0x12)。
digestMultibase 如果指定了 id,则这是所引用渲染方法的一个 OPTIONAL的、采用 multibase 编码的 Multihash。 multibase 值MUSTu (base64url-nopad),并且 multihash 值MUST为具有 256 位输出的 SHA-2(0x12)。

上面展示的数据模型在下面示例中的可验证凭证中表达。

示例 1:颁发者使用 render 属性
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.w3.org/ns/credentials/examples/v2",
    "https://w3id.org/vc/render-method/v1"
  ],
  "id": "http://example.edu/credentials/3732",
  "type": ["VerifiableCredential", "UniversityDegreeCredential"],
  "issuer": "https://example.edu/issuers/14",
  "validFrom": "2010-01-01T19:23:24Z",
  "credentialSubject": {
    "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
    "degree": {
      "type": "BachelorDegree",
      "name": "Bachelor of Science and Arts"
    }
  },
  "renderMethod": {
    "type": "TemplateRenderMethod",
    "renderSuite": "svg-mustache",
    "template": {
      "id": "https://example.edu/credential-templates/BachelorDegree",
      "mediaType": "image/svg+xml",
      "digestMultibase": "zQmerWC85Wg6wFl9znFCwYxApG270iEu5h6JqWAPdhyxz2dR",
      "renderProperty": [
        "/issuer", "/validFrom", "/credentialSubject/degree/name"
      ]
    }
  }
  
}

在上面的示例中,颁发者为学士学位提供了一个基于 Mustache 的 SVG 渲染 模板,该模板将使用 renderProperty 中列出的 可验证凭证中的具体 信息进行填充。

2.2.1 svg-mustache 渲染套件

svg-mustache 渲染套件使用 Mustache 模板语言 修改 SVG 文件,然后使用该文件来渲染 可验证凭证的视觉表示。

在下面的示例中,一个完全嵌入的 SVG 文件被用作渲染 模板。

示例 2:svg-mustache 渲染 套件的基本用法
{
  ...
  "renderMethod": {
    "type": "TemplateRenderMethod",
    "renderSuite": "svg-mustache",
    // SVG 文件嵌入在 VC 中
    "template": "data:image/svg+xml;base64,Qjei89...3jZpW"
  }
}

下一个示例链接到 Web 上的 SVG 文件,并通过使用 digestMultibase 属性保护它免遭修改。

示例 3:用于 SVG 渲染 模板的远程托管 SVG 文件
{
...
"renderMethod": {
  "type": "TemplateRenderMethod",
  "renderSuite": "svg-mustache",
  "template": {
    // 此 SVG 文件从 Web 获取
    "id": "https://degree.example/credential-templates/bachelors",
    "mediaType": "image/svg+xml",
    "digestMultibase": "zQmerWC85Wg6wFl9znFCwYxApG270iEu5h6JqWAPdhyxz2dR"
  }
}

下一个示例链接到 Web 上的渲染模板,并使用 digestMultibase 属性保护它:

示例 4:远程托管的 SVG 渲染方法
{
...
"renderMethod": {
  // 此渲染方法从 Web 获取
  "id": "https://degrees.example/bachelors-svg.jsonld",
  "mediaType": "application/ld+json",
  "type": "TemplateRenderMethod",
  "renderSuite": "svg-mustache",
  "digestMultibase": "zQmG270iEu5h6JqWAPdhyxz2dRerWC85Wg6wFl9znFCwYxAp"
}

2.2.2 pdf-mustache 渲染套件

pdf-mustache 渲染套件使用 Mustache 模板语言 修改 PDF 文件,然后使用该文件来渲染 可验证凭证的视觉表示。

在下面的示例中,一个完全嵌入的 PDF 文件被用作渲染 模板。

示例 5:pdf-mustache 渲染 套件的基本用法
{
  ...
  "renderMethod": {
    "type": "TemplateRenderMethod",
    "renderSuite": "pdf-mustache",
    // 此 PDF 文件嵌入在 VC 中
    "template": "data:application/pdf;base64,k309SK...pwK83b"
  }
}

下一个示例链接到 Web 上的 PDF 文件,并通过使用 digestMultibase 属性保护它免遭 修改。

示例 6:用于 PDF 渲染 模板的远程托管 PDF 文件
{
...
"renderMethod": {
  "type": "TemplateRenderMethod",
  "renderSuite": "pdf-mustache",
  "template": {
    // 此 PDF 文件从 Web 获取
    "id": "https://degree.example/bachelors.pdf",
    "mediaType": "application/pdf",
    "digestMultibase": "zQmznFCwYxApG270iEu5h6JqWAPdhyxz2dRerWC85Wg6wFl9"
  }
}

下一个示例链接到 Web 上的渲染模板,并使用 digestMultibase 属性保护它:

示例 7:远程托管的 PDF 渲染模板
{
...
"renderMethod": {
  // 此渲染方法从 Web 获取
  "id": "https://degrees.example/bachelors-pdf.jsonld",
  "type": "TemplateRenderMethod",
  "renderSuite": "pdf-mustache",
  "digestMultibase": "zQmEu5h6JqWAPdhyxmz2dRerWC85Wg6wFl9znFCwYxApG270"
}

2.2.3 nfc 渲染 套件

nfc 渲染套件通过无线 NFC 连接传输表示 可验证凭证的二进制载荷。

在下面的示例中,一个完全嵌入的 NFC 载荷被用作渲染 模板,它只披露与该 凭证相关联的条形码标识符。

示例 8:nfc 渲染套件的用法
{
  ...
  "renderMethod": {
    "type": "TemplateRenderMethod",
    "renderSuite": "nfc",
    "name": "Tap to send",
    // NFC 载荷被嵌入
    "template": "data:application/octet-stream;base64,2QZkpQGDG...G8XJWnROcY4Biw",
    // 仅通过 NFC 传输条形码
    "renderProperty": ["/credentialSubject/barcode"]
  }
  ...
}

2.2.4 html 渲染 套件

html 渲染套件允许模板作者提供 HTML 模板 来渲染可验证凭证。HTML 可以作为 templatetemplate.id(当 template 的值是对象时)的值, 通过远程方式引用,或通过 data: URL 引用。HTML 片段中的 JavaScript 负责渲染通过 HTML 数据块 (即 <script type="application/vc"></script>)提供的经过筛选的 可验证凭证数据,该数据块与 HTML 模板一起托管在 沙盒化 iframe 中。

示例 9:使用 HTML 渲染套件的示例 VC
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.w3.org/ns/credentials/examples/v2"
  ],
  "type": [
    "VerifiableCredential",
    "NameCredential"
  ],
  "issuer": {
    "id": "did:example:1234",
    "name": "The Issuer"
  },
  "credentialSubject": {
    "name": "Example Name",
    "notRendered": "should not appear"
  },
  "renderMethod": {
    "type": "TemplateRenderMethod",
    "renderSuite": "html",
    "renderProperty": [
      "/issuer/name",
      "/credentialSubject/name"
    ],
    "template": {
      "id": "https://test.example/credential-templates/NameCredential.html",
      "mediaType": "text/html",
      "digestMultibase": "zQmerWC85Wg6wFl9znFCwYxApG270iEu5h6JqWAPdhyxz2dR"
    },
    "outputPreference": {
      "mode": [
        "visual"
      ],
      "mediaType": "application/html",
      "style": {
        "width": "800px",
        "height": "800px"
      }
    }
  }
}

实现MUST提供一种环境,使 JavaScript 能够 使用经过筛选的可验证凭证数据安全地渲染 HTML 模板。以下 术语用于描述此环境:

宿主页面
为渲染 HTML 模板提供安全环境。
模板 代码
在渲染方法中提供或由其远程引用的 HTML 片段。
包装器 代码
包装 HTML 模板的代码,用于提供额外的安全 限制,并与宿主页面通信。

至少,该环境MUST阻止导航、外部 内容加载以及对宿主页面的访问,以防止跟踪和其他 隐私损害。

例如,基于浏览器的实现可以使用以下组合来提供此类环境: 对宿主页面施加内容安全策略 [CSP3] 限制、对托管 HTML 模板的 iframe 进行沙盒化,以及包装器 代码;该包装器代码包装 HTML 模板以添加额外的 CSP 限制,并 提供与宿主页面的 ready 和 error 事件通信。

1 宿主页面与 iframe + 包装器代码之间的通信
2.2.4.1 宿主页面

宿主页面(通常是钱包或可验证凭证渲染器)MUST 阻止 HTML 模板导航顶级浏览上下文、 访问外部内容、访问宿主页面以及 加载任何远程 内容。

如果使用宿主页面,则适用以下规则:

  • 内容安全策略(CSP)限制MUST包括 frame-src 'none'。 这会强制 iframe 使用 srcdoc 而不是 src, 从而阻止 浏览器加载 HTML 模板。进而,这会迫使 宿主页面代码预加载远程引用的模板 代码,并在将模板注入包装器代码之前, 根据相关的 digestMultibase 值检查响应。
  • 在托管 HTML 模板的 iframeMUST设置 sandbox="allow-scripts", 以防止导航和顶级访问。
示例 10:最小宿主页面
<html>
  <head>
    <meta http-equiv="content-security-policy" content="frame-src 'none'">
  </head>
  <body>
    <iframe id="renderer" sandbox="allow-scripts allow-modals" srcdoc=""></iframe>
  </body>
</html>
2.2.4.1.1 模板代码

renderMethod 中的 template 属性引用的 HTML 模板代码MUST是一个 HTML 片段,其中包含 渲染可验证凭证所必需的 HTML、CSS 和 JavaScript。该 模板代码MUST NOT 包含任何 <html><head><body> 标签, 因为这些将由包装器 代码提供。

示例 11:示例 HTML 模板片段
<div>
  <script>
    document.addEventListener('DOMContentLoaded', (event) => {
      console.log('running template render script');

      // 将凭证显示为 JSON,作为示例渲染器;这里也可以
      // 改为执行任何其他操作,包括 mustache/其他风格的
      // 模板处理,以生成用于显示的 HTML

      // FIXME: 确定数据块/script 标签的最佳名称/位置
      const credential = JSON.parse(document.querySelector(
        'head > script[name="credential"]').innerHTML);

      document.querySelector('#credentialSubject-name').innerText =
        credential.credentialSubject.name;
      document.querySelector('#issuer-name').innerText =
        credential.issuer.name;

      // TBD: 向宿主发出渲染完成信号
      window.renderMethodReady();
    });
  </script>
  <style>
    h1 {
      color: blue;
    }
  </style>

  <h1 id="credentialSubject-name"></h1>
  <p>颁发者:<span id="issuer-name"></span></p>
</div>
2.2.4.1.2 包装器代码

模板 HTML 片段MUST被包装在包装器代码中, 该包装器代码提供包含部分可验证凭证的数据块, 并添加额外的 CSP 策略,以阻止导航和外部 内容加载。具体而言,包装器 代码MUST添加以下 CSP 限制:default-src data: 'unsafe-inline',以阻止 模板 代码发出任何 网络请求。

示例 12:用于在 iframe[srcdoc] 中包装模板和凭证的包装器代码
<html>
  <head>
    <meta http-equiv="content-security-policy" content="default-src data: 'unsafe-inline'">
    <script name="credential" type="application/vc">${JSON.stringify(credential)}</script>
  </head>
  <body>${template}</body>
</html>

为完成设置,宿主页面MUST包装器 代码(在填入 可验证凭证模板代码后)注入 iframe 的 srcdoc 属性中,这将运行包装器 代码模板代码中包含的任何 JavaScript。

示例 13:包含模板 和凭证的组合包装器代码
<html>
  <head>
    <meta http-equiv="content-security-policy" content="default-src 'none' data: 'unsafe-inline'">

<!-- 注入到包装器代码中的凭证数据块。 -->
<script name="credential" type="application/vc">{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.w3.org/ns/credentials/examples/v2"
  ],
  "type": [
    "VerifiableCredential",
    "NameCredential"
  ],
  "issuer": {
    "id": "did:example:1234",
    "name": "The Issuer"
  },
  "credentialSubject": {
    "name": "Example Name"
  }
}</script>
<!-- 凭证数据块结束 -->

</head>
<body>

<!-- 注入到包装器代码中的模板 HTML。 -->
<div>
  <script>
    console.log('running template render script');

    // 将凭证显示为 JSON,作为示例渲染器;这里也可以
    // 改为执行任何其他操作,包括 mustache/其他风格的
    // 模板处理,以生成用于显示的 HTML

    // FIXME: 确定数据块/script 标签的最佳名称/位置
    const credential = JSON.parse(document.querySelector(
      'head > script[name="credential"]').innerHTML);

    document.querySelector('#credentialSubject-name').innerText =
      credential.credentialSubject.name;
    document.querySelector('#issuer-name').innerText =
      credential.issuer.name;

    // TBD: 向宿主发出渲染完成信号
    window.renderMethodReady()
  </script>
  <style>
    h1 {
      color: blue;
    }
  </style>

  <h1 id="credentialSubject-name"></h1>
  <p>颁发者:<span id="issuer-name"></span></p>
</div>
<!-- 模板 HTML 结束 -->

  </body>
</html>
2.2.4.1.3 Ready 和 Error 事件

包装器代码中创建的 iframe MUST提供一个通信通道, 以允许模板在渲染完成时,或在 渲染期间发生错误时通知宿主页面。这可以使用 postMessage API 以及由包装器代码设置的 MessageChannel 来实现。

下面显示的 JavaScript 会添加到上述宿主页面中, 为 iframe 添加 onload 事件以设置 MessageChannel。该 宿主页面 还会创建一个 Promise,当从 包装器代码收到 ready 消息时解析, 或在收到 error 消息时拒绝。包装器代码 还提供一个 window.renderMethodReady 方法,供模板用来 通知宿主页面渲染完成或返回 错误消息。

示例 14:为设置 MessageChannel 而添加到宿主页面的内容
// 一个 promise,在渲染准备就绪时解析(或在失败时拒绝);
// 可用于显示内容或错误
let resolveRender;
let rejectRender;
const readyPromise = new Promise((resolve, reject) => {
  resolveRender = resolve;
  rejectRender = reject;
});

// 设置通信通道,供 iframe 中的模板代码使用
renderer.onload = () => {
  // 创建 MessageChannel;将一个端口传递给 iframe
  const channel = new MessageChannel();
  // 启动消息队列,以便 iframe 加载时消息不会丢失
  channel.port1.start();
  // 处理 `ready` 消息
  channel.port1.onmessage = function ready(event) {
    if(event.data === 'ready') {
      // 取消隐藏 iframe,因为它已准备就绪
      resolveRender();
    } else {
      rejectRender(new Error(event.data?.error?.message));
    }
    channel.port1.onmessage = undefined;
  };
  // 发送 "start" 消息;将 `port2` 发送给 iframe 用于返回通信
  renderer.contentWindow.postMessage('start', '*', [channel.port2]);
};

// 设置对 ready 或 error 的事件响应
// NOTE: 本节取决于钱包/渲染器的 UX 需求
readyPromise.then(() => {
  console.log('rendering ready');
  const renderer = document.getElementById('renderer');
  renderer.hidden = false;
}).catch(err => {
  const errorMessage = document.getElementById('error-message');
  errorMessage.style.display = 'block';
  errorMessage.innerText = 'Rendering failed: ' + err.message;
  console.error('rendering failed', err);
});
示例 15:用于连接 MessageChannel 并创建 `renderMethodReady` 的包装器代码补充
// 添加 promise,它将解析为来自
// 父窗口的通信端口
const portPromise = new Promise(resolve => {
  window.addEventListener('message', function start(event) {
    if(event.data === 'start' && event.ports?.[0]) {
      window.removeEventListener('message', start);
      resolve(event.ports[0]);
    }
  });
});

// 将一个函数附加到 window,供模板在
// “准备就绪”(或发生错误)时调用,该函数会向
// 父级发送消息,以便父级决定是否显示 iframe
window.renderMethodReady = function(err) {
  portPromise.then(port => port.postMessage(
    !err ? 'ready' : {error: {message: err.message}}));
};

通过此设置,模板 JavaScript 可以调用 window.renderMethodReady() 来通知宿主页面渲染完成,或者调用 window.renderMethodReady(new Error("error message")) 来通知宿主页面 发生错误。

2.2.4.2 算法

以下各节概述了 html 渲染 套件用于安全渲染 HTML 模板的算法。只要安全和隐私结果以及输出相同, MAY使用替代算法。

2.2.4.2.1 宿主页面

宿主页面MUST创建一个 iframe 元素来托管 HTML 模板。该 宿主页面MUSTiframe 上的 sandbox 属性设置为 allow-scripts,以防止导航和顶级访问。

  1. vc 为要渲染的可验证凭证
  2. renderMethodvc 中选定的 renderMethod 属性,其中 renderMethod.typeTemplateRenderMethod,且 renderMethod.renderSuitehtml
  3. 如果 renderMethod.template字符串,则令 templaterenderMethod.template 的值。
  4. 如果 renderMethod.template映射,则令 template 为 获取 renderMethod.template.id 中 URL 的结果。

如果存在 renderMethod.renderProperty,则宿主页面MUST筛选可验证凭证 vc, 使其仅包含 renderMethod.renderProperty 中指定的属性。如果 不存在 renderMethod.renderProperty,则使用整个可验证凭证

此筛选MUST通过应用 Data Integrity ECDSA Cryptosuites v1.0 规范 [VC-DI-ECDSA] 第 3.4.13 节 selectJsonLd 中定义的 selectJsonLd 算法来完成,该算法应用于 renderMethod.renderProperty 中存在的 JSON Pointer [RFC6901] 值。

宿主页面MUST通过将经过筛选的 可验证凭证和 HTML 模板嵌入到上面定义的包装器代码模板中, 来创建包装器代码

  1. wrapperCode 为一个 HTML Document,其中在 <head> 中包含 <meta http-equiv="Content-Security-Policy" content="default-src data: 'unsafe-inline'">
  2. datablock 为一个 typeapplication/vc 的 HTML 数据块。
  3. datablock 的内容设置为字符串化 JSON 格式的 经过筛选的可验证 凭证
  4. datablock 插入 wrapperCode<head> 中。
  5. template 的值插入 wrapperCode<body> 中。

宿主页面MUSTiframesrcdoc 属性 设置为生成的包装器代码

  1. iframesrcdoc 属性设置为 wrapperCode 的字符串化 HTML。

宿主页面MUST包装器代码建立 通信通道,以接收如上所述的 readyerror 消息。

  1. renderPromise 为一个新的 Promise,它:
    1. resolve 时,可用于向用户显示 iframe
    2. reject 时,向用户显示错误消息。
  2. iframeonload 事件中:
    1. channel 为新的 MessageChannel
    2. channel 上创建并启动新的 port1 监听器, 该监听器监听来自现在已通过 wrapperCode 注入到 iframe 中的 template 代码的 ready 消息。
    3. port1 监听器中,如果收到 ready 消息, 则解析 renderPromise。 如果收到 error 消息,则使用错误 消息拒绝 renderPromise
    4. 使用 postMessagechannelport2 发送到 iframe 内容窗口。

宿主页面SHOULD使用 renderPromise 来确定渲染何时 完成,或渲染期间是否发生错误。

2.2.4.2.2 包装器代码

包装器代码MUST设置为 通过 MessageChannel 接收来自宿主页面的通信,并提供 window.renderMethodReady 方法,供 模板代码使用。

  1. window.onload 事件中……
    1. port 为通过 message 事件从宿主页面接收的 MessagePort
    2. 创建 window.renderMethodReady 函数,该函数……
      1. 如果在没有参数的情况下调用,则通过 port宿主页面发送 ready 消息。
      2. 如果使用 Error 参数调用,则通过 port宿主页面 发送带有错误消息的 error 消息。

2.3 EmbeddedRenderer

EmbeddedRenderer 由颁发者用于渲染可验证 凭证。可验证凭证通过文档中引用的 Template Renderer 网站, 在嵌入的 <iframe> 内以 HTML 形式渲染。这种安排允许使用 OpenAttestationMerkleProofSignature2018 进行交互式选择性披露。

Template Renderer 是嵌入在 iframe 中的 Web 应用程序。它基于 选定的模板渲染可验证凭证,并且必须监听来自 Host 应用程序的 特定消息,以便促进渲染 过程。

目前存在许多 EmbeddedRenderer 颁发者 和 embedded renderer 实现。

颁发者希望为 可验证凭证指定嵌入式渲染指令时,他们MAY添加一个 使用以下所述数据模型的 renderMethod 属性。

属性 描述
id 一个 URL,用于定位实现 EmbeddedRenderer Action API 的网站。
type type 属性MUSTEmbeddedRenderer
renderName id 指定的网站用于渲染 文档的模板名称。可以为 embedded renderer 使用不同模板,以呈现可验证 凭证的不同 HTML 视图。

上面展示的数据模型在下面示例中的 可验证凭证中表达。

示例 16:颁发者使用 renderMethod 属性
  {
    "@context": [
      "https://www.w3.org/ns/credentials/v2",
      "https://w3id.org/security/data-integrity/v2",
      "https://trustvc.io/context/render-method-context-v2.json",
    ],
    "credentialSubject": {
     ...
    },
    "type": ["VerifiableCredential"],
    "issuer": "did:web:trustvc.github.io:did:1",
    "validFrom": "2024-04-01T12:19:52Z",
    "id": "urn:uuid:01992e54-cc5e-700e-a80b-60ddf0fffca9",
  },
  "renderMethod": [
      {
        "type": "EMBEDDED_RENDERER",
        "templateName": "DEMO_CERTIFICATE",
        "id": "https://generic-templates.tradetrust.io"
      }
  ]
}

可验证凭证指定了位于 https://generic-templates.tradetrust.io 的嵌入式渲染器,并使用名为 DEMO_CERTIFICATE 的模板。

embedded renderer 可以支持不同模板,以提供 可验证凭证的不同视图。下面是同一 可验证凭证使用不同模板的两种渲染效果。

证书模板
2 证书模板
成绩单模板
3 成绩单模板

2.3.1 Action API

Host 是借助 Template Renderer 显示文档的应用程序。Template Renderer MUST是嵌入在由 renderMethod.id 指定的 iframe 中的 Web 应用程序。它MUST使用 postMessage API 与 Host 应用程序通信以执行操作。

所有操作都遵循相同结构。它们由 typepayload 组成:

  1. type 表示正在执行的操作类型,例如 RENDER_DOCUMENT 表示渲染文档。操作的 type 是 必需的。
  2. payload 表示与该 type 相关联的可选数据,例如 要渲染的文档内容。

一个开源参考实现可在 GitHub 上获得。

Host 与 Template Renderer 之间的交互如下图所示。

序列图
4 序列图
2.3.1.1 Host 到 Frame 的操作

当 iframe 首次显示时,host 会向 iframe 发送命令 以渲染文档。支持的 4 种操作类型 如下所述。

type payload 操作
GET_TEMPLATES
{ type: "GET_TEMPLATES" }
获取 renderer 针对给定文档支持的模板列表。 模板列表由 iframe 中的 UPDATE_TEMPLATES 调用返回。
SELECT_TEMPLATE
{
  type: "SELECT_TEMPLATE",
  payload: "CUSTOM_TEMPLATE"
}
选择用于渲染的模板。它应来自 GET_TEMPLATES 返回的列表。如果未找到,则使用默认模板。
RENDER_DOCUMENT
{
  type: "RENDER_DOCUMENT",
  payload: {
    document: {
      credentialSubject: ...,
      renderMethod: ...
    }
  }
}
使用所选模板在 IFRAME 内渲染可验证凭证。 Document 是可验证凭证的 JSON 对象形式。
PRINT
{ type: "PRINT" }
MUST显示打印对话框,以便可以 打印 IFRAME 的内容。
2.3.1.2 Frame 到 Host 的操作

iframe 使用这些操作来更新 host,以便进行格式调整 或选择性遮盖。

type payload 操作
OBFUSCATE
{
  type: "OBFUSCATE",
  payload: "a[0].b.c",
}
这用于选择性遮盖。Host 会获知 已被混淆字段的路径,以便 host 可以 创建一个更新后的文档版本,其中所选字段 已被混淆。
UPDATE_HEIGHT
{
  type: "UPDATE_HEIGHT",
  payload: 150,
}
以像素为单位通知 Host 嵌入式 iframe 的高度,以便 Host 可以在浏览器中调整大小。
UPDATE_TEMPLATES
{
  type: "UPDATE_TEMPLATES",
  payload: [
    {
      id: "template1",
      label: "template1",
    },
    {
      id: "template2",
      label: "template2",
    }
  ]
}
通知 Host 可从 RENDER_METHOD 或 GET_TEMPLATES 调用中使用的模板名称列表。

3. 算法

以下各节概述了本规范用于渲染方法的算法。

3.1 渲染 (TemplateRenderMethod)

Mustache 模板语言用于 生成可验证凭证的视觉表示。 详见 Mustache 5.0 规范

A. 安全注意事项

本节是非规范性的。

问题 1:安全注意事项摘要

下面列出的安全注意事项需要转换为 各节:

B. 隐私注意事项

本节是非规范性的。

问题 2:隐私注意事项摘要

下面列出的隐私注意事项需要转换为 各节:

C. 国际化 注意事项

本节是非规范性的。

问题 3:国际化注意事项摘要

下面列出的国际化注意事项需要 转换为各节:

D. 参考文献

D.1 规范性引用

[CSP3]
内容安全策略第 3 级。Mike West; Antonio Sartori。W3C。2026年4月1日。W3C 工作草案。URL:https://www.w3.org/TR/CSP3/
[infra]
Infra 标准。Anne van Kesteren;Domenic Denicola。WHATWG。现行标准。URL:https://infra.spec.whatwg.org/
[RFC2119]
用于在 RFC 中指示 要求级别的关键词。S. Bradner。IETF。1997年3月。最佳现行实践。URL:https://www.rfc-editor.org/rfc/rfc2119
[RFC2397]
"data" URL 方案。L. Masinter。IETF。1998年8月。提议标准。URL:https://www.rfc-editor.org/rfc/rfc2397
[RFC6838]
媒体类型规范和注册 过程。N. Freed;J. Klensin;T. Hansen。IETF。2013年1月。最佳现行 实践。URL:https://www.rfc-editor.org/rfc/rfc6838
[RFC6901]
JavaScript 对象表示法(JSON) Pointer。P. Bryan,编;K. Zyp;M. Nottingham,编。IETF。2013年4月。提议 标准。URL:https://www.rfc-editor.org/rfc/rfc6901
[RFC8174]
RFC 2119 关键词中大小写的歧义。B. Leiba。IETF。2017年5月。最佳现行实践。URL:https://www.rfc-editor.org/rfc/rfc8174
[URL]
URL 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://url.spec.whatwg.org/
[VC-DATA-MODEL-2.0]
可验证凭证数据模型 v2.0。Ivan Herman;Michael Jones;Manu Sporny;Ted Thibodeau Jr;Gabe Cohen。W3C。 2025年5月15日。W3C 推荐标准。URL:https://www.w3.org/TR/vc-data-model-2.0/
[VC-DI-ECDSA]
数据完整性 ECDSA 密码套件 v1.0。Manu Sporny;Dave Longley;Greg Bernstein。W3C。2025年5月15日。W3C 推荐标准。URL:https://www.w3.org/TR/vc-di-ecdsa/