Web 身份验证:
用于访问公钥凭证的 API
第 3 级

W3C候选推荐快照,

关于此文档的更多详细信息
此版本:
https://www.w3.org/TR/2026/CR-webauthn-3-20260113/
最新发布版本:
https://www.w3.org/TR/webauthn-3/
编辑草稿:
https://w3c.github.io/webauthn/
以前的版本:
历史:
https://www.w3.org/standards/history/webauthn-3/
实现报告:
https://www.w3.org/2020/12/webauthn-report.html
反馈:
GitHub
编辑:
(Okta)
(Self-Issued Consulting)
(Microsoft)
(Yubico)
(Cisco)
前任编辑:
(Google)
(Microsoft)
(Google)
(Google)
Jeff Hodges (formerly Google)
J.C. Jones (formerly Mozilla)
(PayPal)
(Microsoft)
(Nok Nok Labs)
贡献者:
John Bradley (Yubico)
Christiaan Brand (Google)
Adam Langley (Google)
Giridhar Mandyam (Qualcomm)
Pascoe (Apple)
Nina Satragno (Google)
Ki-Eun Shin (SK Telecom)
Nick Steele (1Password)
Jiewen Tan (Apple)
Shane Weeden (IBM)
Mike West (Google)
Jeffrey Yasskin (Google)
Anders Åberg (Bitwarden)
测试:
web-platform-tests webauthn/ (正在进行的工作)

摘要

本规范定义了一套 API,使得由 web 应用 创建和使用强健、可证明的、基于公钥且 作用域化 的凭证成为可能,目的是对用户进行强认证。概念上,一个或多个 公钥凭证(每个凭证都 作用域化 到给定的 WebAuthn 依赖方)由 web 应用按需创建并 绑定authenticators。用户代理在访问 authenticators 及其 公钥凭证 时进行中介,以维护用户隐私。Authenticators 负责确保在未获得 用户同意 时不执行任何操作。Authenticators 通过 attestationRelying Parties 提供其属性的密码学证明。本规范还描述了与 WebAuthn 一致的 authenticators 的功能模型,包括其签名和 attestation 功能。

本文档状态

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

要让Web认证规范推进到候选推荐(Candidate Recommendation)之后,需有两款浏览器实现支持新功能和扩展。 规范将通过Web平台测试(Web Platform Tests)第3级别进行测试。

本文件由Web认证工作组推荐流程发布为候选推荐快照。

欢迎对本规范提出反馈和建议,请使用Github issues。讨论也可见于public-webauthn@w3.org 归档

作为候选推荐发布,并不意味着 W3C及其成员的认可。 候选推荐快照已获得广泛评审,旨在收集实施经验,并有工作组成员承诺对实现提供免版税许可

本文件为草案,随时可能更新、替代或被其他文件废止。除作为工作进展外,不宜引用本文件作其他用途。

本候选推荐预期不会早于2026年2月10日晋升为推荐(Recommendation)。

本文件由遵循W3C专利政策的工作组制作。W3C维护了与本组成果相关的公开专利披露列表,该页面还包含专利披露说明。个人如知悉某专利包含必要权利要求,须按W3C专利政策第6条披露相关信息。

本文件受2025年8月18日W3C流程文件管理。

1. 简介

本节非规范性。

本规范定义了一套 API,使得由 作用域化 的、可证明的基于公钥的强凭证能够被 web 应用 创建和使用,以便对用户进行强认证。公钥凭证WebAuthn AuthenticatorWebAuthn Relying Party 的请求创建并存储,前提是获得了 用户同意。随后,公钥凭证 只能被属于该 Relying Partyorigin 访问。该作用域性由 符合性用户代理authenticators 共同强制执行。此外,不同 Relying Parties 之间的隐私也得到维护;Relying Parties 无法检测到其它为不同 Relying Parties 作用域化 的凭证的任何属性,甚至无法检测其是否存在。

Relying Parties 在涉及用户的两个不同但相关的仪式期间使用 Web Authentication API。第一个是 注册,在此期间,在 authenticator 上创建一个 公钥凭证,并将其 作用域化 到具有当前用户账户的 Relying Party(该账户可能已存在,也可能在此时创建)。第二个是 认证,在此期间,Relying Party 会收到一个证明已注册该 公钥凭证 的用户在场和同意的 认证断言。从功能上讲,Web Authentication API 包括扩展凭证管理 API 的 PublicKeyCredential,以及允许通过 navigator.credentials.create()navigator.credentials.get() 使用这些凭证的基础设施。前者用于 注册,后者用于 认证

总体而言,符合规范的 authenticators 保护 公钥凭证,并与用户代理交互以实现 Web Authentication API。符合规范的认证器可以通过在以下环境中的软件实现来实现:(a) 在通用计算设备上执行,(b) 在设备内的安全执行环境、可信平台模块 (TPM) 或 安全元件 (SE) 上,或 (c) 在设备外部。部署在设备上的认证器称为 平台认证器。部署在设备外的认证器(漫游认证器)可以通过诸如通用串行总线 (USB)、蓝牙低能耗 (BLE) 或近场通信 (NFC) 等传输方式访问。

1.1. 规范路线图

尽管许多 W3C 规范主要针对用户代理开发者,同时也面向 Web 应用开发者(即“Web 作者”),但 Web Authentication 的性质要求本规范为多类受众正确使用,如下所述。

所有受众 应当从 § 1.2 用例§ 1.3 示例 API 使用场景§ 4 术语 开始,并且还应参考 [WebAuthnAPIGuide] 以获得总体教程。除此之外,本文档的目标读者主要包括以下几类群体:

注意:Web Authentication API 本身外,本规范还定义了一个请求-响应的加密协议——在本规范中称为 WebAuthn/FIDO2 protocol——用于 WebAuthn Relying Party 服务器与 authenticator 之间,其中 Relying Party 的请求由一个 challenge 以及由 Relying Party 提供并发送给 authenticator 的其它输入数据组成。该请求通过 HTTPS、Relying Partyweb 应用WebAuthn API 以及用户代理与 authenticator 之间的平台特定通信通道的组合传达。authenticator 会以数字签名的 authenticator data 消息和其他输出数据进行回应,并经由相同路径反向传回给 Relying Party 服务器。协议细节会根据 认证注册 操作的不同而有所变化。另见 图 1图 2

对于 Web Authentication 部署的端到端安全而言非常重要的一点是 各组件(即 Relying Party 服务器、clientauthenticator)的角色,以及 § 13 安全性考虑§ 14 隐私考虑,应由 所有受众 所理解。

1.2. 用例

下面的用例场景展示了两种非常不同类型的 authenticators 和凭证在两种常见部署类型中的使用方式,并概述了其它场景。附加场景(含示例代码)稍后在 § 1.3 示例 API 使用场景 中给出。这些示例仅用于说明,功能可用性在不同客户端与认证器实现之间可能有所不同。

1.2.1. 具有多设备凭证的消费者

该用例说明了面向消费者的 Relying Party 如何利用用户设备内置的认证器,通过使用 多设备凭证(通常称为已同步的 passkeys)来提供抗钓鱼的登录。

1.2.1.1. 注册
1.2.1.2. 认证

1.2.2. 具有单设备凭证的员工

该用例说明了面向员工的 Relying Party 如何结合使用 漫游认证器(例如 USB 安全密钥)和 平台认证器(例如内置指纹传感器),以便用户拥有:

1.2.2.1. 注册

在此示例中,用户的雇主邮寄了一个预配置了设备绑定 passkey 的安全密钥给用户。

一个临时 PIN 已通过带外渠道(例如通过 RCS 消息)发送给用户。

1.2.2.2. 认证

1.2.3. 其他用例与配置

还存在各种其他的用例和配置,包括(但不限于):

1.3. 示例 API 使用场景

本节非规范性。

在本节中,我们将演示 公钥凭证 生命周期中的若干事件,并给出使用本 API 的相应示例代码。请注意这只是一个示例流程,并不限制 API 的使用范围。

正如前面部分所示,该流程聚焦于具有自身显示屏的 passkey 漫游认证器 的用例。此类认证器的一个示例是智能手机。本 API 也支持其它类型的认证器,前提是由 client platform 实现。例如,该流程对于嵌入在 客户端设备 中的认证器也无需修改即可工作。对于没有自身显示屏的认证器(类似智能卡)的情况,该流程也可工作,但需考虑特定实现细节。具体地,client platform 需要显示任何本应由认证器显示的提示,且认证器需允许 client platform 枚举认证器的所有凭证,以便客户端能够显示合适的提示信息。

1.3.1. 注册

这是首次流程,其中创建新凭证并向服务器注册。在此流程中,WebAuthn Relying Party 对平台认证器或漫游认证器均无偏好。

  1. 用户访问 example.com,页面提供了一个脚本。此时,用户可能已经使用传统用户名与密码或其它 Relying Party 可接受的方式登录,或正在创建新账户。

  2. Relying Party 脚本运行下面的代码段。

  3. client platform 搜索并定位认证器。

  4. client 连接到认证器,并在必要时执行配对操作。

  5. 认证器显示适当的 UI,提示用户提供生物识别或其它 授权手势

  6. 认证器向 client 返回响应,client 将响应返回给 Relying Party 脚本。如果用户拒绝选择认证器或提供授权,则返回相应错误。

  7. 如果创建了新凭证,

    • Relying Party 脚本将新生成的 凭证公钥 发送到服务器,并附带诸如来自认证器的来源与特性相关的证明(attestation)等附加信息。

    • 服务器将 凭证公钥 存储在其数据库中,并将其与用户以及 attestation 指示的认证特性关联,同时为日后使用存储一个便于识别的友好名称。

    • 脚本可能将诸如 凭证 ID 等数据存入本地存储,以通过缩小用户凭证选择范围来提升未来的用户体验。

下面是生成并注册新密钥的示例代码:

if (!window.PublicKeyCredential) { /* 客户端不支持。请处理错误。 */ }

var publicKey = {
  // challenge 由服务器生成;参见安全性注意事项
  challenge: new Uint8Array([21,31,105 /* 服务器生成的另外 29 个随机字节 */]),

  // Relying Party:
  rp: {
    name: "ACME Corporation"
  },

  // 用户:
  user: {
    id: Uint8Array.from(window.atob("MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII="), c=>c.charCodeAt(0)),
    name: "alex.mueller@example.com",
    displayName: "Alex Müller",
  },

  // 此 Relying Party 可接受 EdDSA、ES256 或 RS256 凭据,但
  // 更倾向于 EdDSA 凭据。
  pubKeyCredParams: [
    {
      type: "public-key",
      alg: -8 // IANA COSE 算法注册表中已注册的 "EdDSA"
    },
    {
      type: "public-key",
      alg: -7 // IANA COSE 算法注册表中已注册的 "ES256"
    },
    {
      type: "public-key",
      alg: -257 // 本规范为 "RS256" 注册的值
    }
  ],

  authenticatorSelection: {
    // 如果可能尽量使用 UV。这也是默认值。
    userVerification: "preferred"
  },

  timeout: 300000,  // 5 分钟
  excludeCredentials: [
    // 不要重新注册已拥有这些凭据的认证器
    {"id": Uint8Array.from(window.atob("ufJWp8YGlibm1Kd9XQBWN1WAw2jy5In2Xhon9HAqcXE="), c=>c.charCodeAt(0)), "type": "public-key"},
    {"id": Uint8Array.from(window.atob("E/e1dhZc++mIsz4f9hb6NifAzJpF1V4mEtRlIPBiWdY="), c=>c.charCodeAt(0)), "type": "public-key"}
  ],

  // 使 excludeCredentials 检查与使用 U2F 注册的凭据后向兼容
  extensions: {"appidExclude": "https://acme.example.com"}
};

// 注意:下面的方法调用将导致认证器显示界面。
navigator.credentials.create({ publicKey })
  .then(function (newCredentialInfo) {
    // 发送新的凭据信息到服务器进行验证和注册。
  }).catch(function (err) {
    // 没有可接受的认证器或用户拒绝授权。请妥善处理。
  });

1.3.2. 专门针对用户验证的平台认证器的注册

WebAuthn Relying Party 特别希望创建一个使用 用户验证平台认证器公钥凭证 时,以下为示例流程。

  1. 用户访问 example.com 并点击登录按钮,登录按钮将用户重定向至 login.example.com。

  2. 用户输入用户名和密码登录。登录成功后,用户被重定向回 example.com。

  3. Relying Party 脚本运行下面的代码段。

    1. 用户代理检查是否有 用户验证平台认证器 可用。如果没有,则终止此流程。

    2. Relying Party 询问用户是否希望与其创建凭证。如果不同意,则终止此流程。

    3. 用户代理和/或操作系统显示相应 UI,并引导用户使用可用的平台认证器创建凭证。

    4. 凭证创建成功后,Relying Party 脚本将新凭证传送给服务器。

if (!window.PublicKeyCredential) { /* Client not capable of the API. Handle error. */ }

PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
    .then(function (uvpaAvailable) {
        // If there is a user-verifying platform authenticator
        if (uvpaAvailable) {
            // Render some RP-specific UI and get a Promise for a Boolean value
            return askIfUserWantsToCreateCredential();
        }
    }).then(function (userSaidYes) {
        // If there is a user-verifying platform authenticator
        // AND the user wants to create a credential
        if (userSaidYes) {
            var publicKeyOptions = { /* Public key credential creation options. */};
            return navigator.credentials.create({ "publicKey": publicKeyOptions });
        }
    }).then(function (newCredentialInfo) {
        if (newCredentialInfo) {
            // Send new credential info to server for verification and registration.
        }
    }).catch(function (err) {
        // Something went wrong. Handle appropriately.
    });

1.3.3. 认证

当具有已注册凭证的用户访问网站并希望使用该凭证进行认证时,这是该流程。

  1. 用户访问 example.com,页面提供了一个脚本。

  2. 脚本向 client 请求一个认证断言(Authentication Assertion),并尽可能提供多的信息以缩小对用户可接受凭证的选择范围。这些信息可以来自注册后本地存储的数据,或通过提示用户输入用户名等方式获取。

  3. Relying Party 脚本运行下面的代码片段之一。

  4. client platform 搜索并定位认证器。

  5. client 连接到认证器,并在必要时执行配对操作。

  6. 认证器向用户展示需要其注意的通知。打开通知后,用户会看到一个友好的可接受凭证选择菜单,菜单使用创建凭证时提供的账户信息,并展示请求这些密钥的 origin 的部分信息。

  7. 认证器从用户处获取生物识别或其它 授权手势

  8. 认证器向 client 返回响应,client 将响应返回给 Relying Party 脚本。如果用户拒绝选择凭证或提供授权,则返回相应错误。

  9. 如果成功生成并返回断言,则:

    • 脚本将断言发送到服务器。

    • 服务器检查断言,提取 凭证 ID,在其数据库中查找已注册的凭证公钥,并验证断言签名。如果验证通过,服务器会查找与断言的 凭证 ID 相关联的身份;该身份即被认证。如果服务器无法识别该 凭证 ID(例如因不活跃而已被注销),则认证失败;每个 Relying Party 将按自己的方式处理此情况。

    • 服务器随后执行在成功认证后应执行的操作——返回成功页面、设置认证 cookie 等。

如果 Relying Party 脚本没有任何可用的提示(例如来自本地存储的数据)来帮助缩小凭证列表,则执行此类认证的示例代码可能如下所示:

if (!window.PublicKeyCredential) { /* Client not capable. Handle error. */ }

// credentialId is generated by the authenticator and is an opaque random byte array
var credentialId = new Uint8Array([183, 148, 245 /* more random bytes previously generated by the authenticator */]);
var options = {
  // The challenge is produced by the server; see the Security Considerations
  challenge: new Uint8Array([4,101,15 /* 29 more random bytes generated by the server */]),
  timeout: 300000,  // 5 minutes
  allowCredentials: [{ type: "public-key", id: credentialId }]
};

navigator.credentials.get({ "publicKey": options })
    .then(function (assertion) {
    // Send assertion to server for verification
}).catch(function (err) {
    // No acceptable credential or user refused consent. Handle appropriately.
});

另一方面,如果 Relying Party 脚本具有一些提示以帮助缩小凭证列表,则执行此类认证的示例代码可能如下所示。请注意此示例同时演示了如何使用 凭证属性扩展(Credential Properties Extension)

if (!window.PublicKeyCredential) { /* Client not capable. Handle error. */ }

var encoder = new TextEncoder();
var acceptableCredential1 = {
    type: "public-key",
    id: encoder.encode("BA44712732CE")
};
var acceptableCredential2 = {
    type: "public-key",
    id: encoder.encode("BG35122345NF")
};

var options = {
  // The challenge is produced by the server; see the Security Considerations
  challenge: new Uint8Array([8,18,33 /* 29 more random bytes generated by the server */]),
  timeout: 300000,  // 5 minutes
  allowCredentials: [acceptableCredential1, acceptableCredential2],
  extensions: { 'credProps': true }
};

navigator.credentials.get({ "publicKey": options })
    .then(function (assertion) {
    // Send assertion to server for verification
}).catch(function (err) {
    // No acceptable credential or user refused consent. Handle appropriately.
});

1.3.4. 中止认证操作

下面的示例展示了开发者如何使用 AbortSignal 参数来中止凭证注册操作。对认证操作同样适用类似过程。

const authAbortController = new AbortController();
const authAbortSignal = authAbortController.signal;

authAbortSignal.onabort = function () {
    // Once the page knows the abort started, inform user it is attempting to abort.
}

var options = {
    // A list of options.
}

navigator.credentials.create({
    publicKey: options,
    signal: authAbortSignal})
    .then(function (attestation) {
        // Register the user.
    }).catch(function (error) {
        if (error.name === "AbortError") {
            // Inform user the credential hasn't been created.
            // Let the server know a key hasn't been created.
        }
    });

// Assume widget shows up whenever authentication occurs.
if (widget == "disappear") {
    authAbortController.abort();
}

1.3.5. 退役

以下为在服务器端希望退役凭证的若干可能情形。请注意,所有这些情形均由服务器端处理,无需本规范所定义的 API 提供额外支持。

1.4. 平台特定实现指南

本规范定义了在通用情况下如何使用 Web Authentication。当在与特定平台支持(例如应用)相关的场景中使用 Web Authentication 时,建议查阅平台特定的文档和指南以获得额外的指导和限制说明。

2. 符合性

本规范定义了三种符合性类别。每一类的规范性成员都被指定为能够抵御来自其他类别中不符合规范或敌对成员的攻击。

2.1. 用户代理

用户代理必须按照 § 5 Web Authentication API 中的描述进行行为,才能被视为符合规范。符合性用户代理 可以以任何希望的方式实现本规范中给出的算法,只要最终结果与规范算法所描述的结果无法区分。

符合规范的用户代理还必须作为本规范的 IDL 片段的符合性实现,如 “Web IDL” 规范中所述。[WebIDL]

2.1.1. 将枚举作为 DOMString 类型的向后兼容性

枚举类型未在 Web IDL 的其它部分中被引用,因为那样会排除在不更新规范及其实现的情况下使用其他值的可能性。为了向后兼容,客户端平台Relying Parties 处理未知值非常重要。本规范的枚举用于文档记录和作为登记表。当这些枚举在其它位置表示时,它们被标记为 DOMString 类型,例如在 transports 中。

2.2. 认证器

WebAuthn Authenticator 必须提供 § 6 WebAuthn Authenticator Model 中定义的操作,并且这些操作必须按该部分中所述进行。这是一组功能与安全要求,使得认证器可被 符合性用户代理 使用。

§ 1.2 用例 所述,认证器可以实现于用户代理所依赖的操作系统中、外部硬件中,或两者的组合中。

2.2.1. 与 FIDO U2F 的向后兼容性

仅支持 § 8.6 FIDO U2F 证明语句格式Authenticators 无法存储 user handle,因此返回的 userHandle 将始终为 null。

2.3. WebAuthn Relying Parties

WebAuthn Relying Party 必须按照 § 7 WebAuthn Relying Party Operations 中的描述进行行为,以获得本规范提供的所有安全收益。有关更多讨论,请参见 § 13.4.1 WebAuthn Relying Parties 的安全性优势

2.4. 所有符合性类别

上述所有符合性类别成员执行的所有 CBOR 编码必须使用 CTAP2 规范的规范化 CBOR 编码形式。上述符合性类别的所有解码器应拒绝不按 CTAP2 规范化 CBOR 编码形式 有效编码的 CBOR,并且应当拒绝具有重复映射键的消息。

3. 依赖项

本规范依赖若干其它底层规范,下列列出,并在 通过引用定义的术语 中也有列出。

Base64url encoding

术语 Base64url Encoding 指的是使用 [RFC4648] 第 5 节中定义的、对 URL 和文件名安全的字符集的 base64 编码,去掉所有尾随的 '=' 字符(如第 3.2 节允许的)并且不包含任何换行、空白或其它额外字符。

CBOR

本规范中的若干结构(包括 attestation 语句和扩展)采用 Compact Binary Object Representation(CBOR)的 CTAP2 规范化 CBOR 编码形式 编码,如 [RFC8949] 所定义,并依照 [FIDO-CTAP] 的规定。

CDDL

本规范使用 CBOR 数据定义语言(CDDL)来描述所有 CBOR 编码数据的语法,参见 [RFC8610]

COSE

CBOR 对象签名与加密(COSE)参见 [RFC9052][RFC9053]。还使用了由 [IANA-COSE-ALGS-REG] 管理的 IANA COSE 算法注册表,该注册表最初由 [RFC8152] 建立,并由上述规范更新。

Credential Management

本文档所述的 API 是对在 [CREDENTIAL-MANAGEMENT-1] 中定义的 Credential 概念的扩展。

DOM

DOMException 及本文规范中使用的 DOMException 值在 [DOM4] 中定义。

ECMAScript

%ArrayBuffer%[ECMAScript] 中定义。

URL

domainhostportschemevalid domainvalid domain string 等概念在 [URL] 中定义。

Web IDL

本规范中的许多接口定义以及所有 IDL 均依赖于 [WebIDL]。该更新版本的 Web IDL 标准增加了对 Promise 的支持,Promise 现在是所有新 Web API 中首选的异步交互机制。

FIDO AppID

用于 确定调用应用的 FacetID 以及 确定调用者的 FacetID 是否被授权用于某 AppID 的算法(仅在 AppID 扩展 中使用)由 [FIDO-APPID] 定义。

文中关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 和 "OPTIONAL" 的解释应按照 BCP 14 的描述在 [RFC2119][RFC8174] 中的说明来理解,但仅当这些词以全大写形式出现时才适用,如本文所示。

4. 术语

Attestation

一般来说,attestation(证明) 是一种用于证明、确认或鉴别的陈述。在 WebAuthn 场景中,attestation 用于提供可验证的证据,证明某个 authenticator 的来源及其所发出的数据。这包括诸如 credential ID凭证密钥对签名计数器 等。

注册 仪式期间,会在 attestation object 中提供一个 attestation statement。另见 § 6.5 Attestation图 6。关于 client 是否以及如何将 attestation statementaaguid 部分的 attestation object 传送给 Relying Party,请参阅由 attestation conveyance 所描述的内容。

Attestation Certificate

用于 attestation key pair 的 X.509 证书,该密钥对由 authenticator 用以证明其制造来源和能力。在 注册 时,authenticator 使用其 attestation private key 对其生成并通过 authenticatorMakeCredential 操作返回的 Relying Party-特定的 credential public key(及其它数据)进行签名。Relying Parties 使用在 attestation certificate 中携带的 attestation public key 来验证 attestation signature。注意在 self attestation 的情况下,authenticator 没有单独的 attestation key pairattestation certificate;详见 self attestation 的说明。

Authentication
Authentication Ceremony

指的是一个ceremony,在该过程中,用户及包含或连接至少一个 authenticator 的用户 client platform 协同工作,通过密码学方式向 Relying Party 证明用户控制先前注册的 credential private key(见 Registration)。这包括 用户存在性测试用户验证

WebAuthn 的 authentication ceremony§ 7.2 验证认证断言 中定义,由 Relying Party 调用带有 publicKey 参数的 navigator.credentials.get() 操作来发起。参见 § 5 Web Authentication API 的介绍性概览和 § 1.3.3 认证 的实现示例。

Authentication Assertion
Assertion

authenticator 在执行 authenticatorGetAssertion 操作后返回的经加密签名的 AuthenticatorAssertionResponse 对象。

这对应于 [CREDENTIAL-MANAGEMENT-1] 规范中所述的一次性使用的 credentials 概念。

Authenticator
WebAuthn Authenticator

一种存在于硬件或软件中的密码学实体,能够在给定的 Relying Party 上为用户执行 register 操作,并在稍后对所注册的 public key credential 证明其拥有权(assert possession),并可选地向 Relying Party 进行 用户验证Authenticators 在注册和断言期间可以通过 attestation 报告其类型和安全特性。

WebAuthn Authenticator 可以是 漫游认证器、集成到 客户端设备 的专用硬件子系统,或者客户端或客户端设备的一个软件组件。WebAuthn Authenticator 不必局限于本地上下文运行,可以在客户端外部的服务器上生成或存储 credential key pair

一般假定一个 authenticator 仅有一个用户。如果多个自然人共享对某个 authenticator 的访问,则在该 authenticator 的上下文中,他们被视为代表同一用户。如果某个 authenticator 实现支持在隔离区中为多用户提供支持,则每个隔离区被视为具有单个用户且彼此之间无法访问对方凭证的独立 authenticator

Authorization Gesture

authorization gesture 指用户在仪式(如 registrationauthentication)过程中与认证器进行的物理交互。通过施加这样的 authorization gesture,用户对该ceremony 的继续表示 同意(即授权)。如果认证器具备能力,这可能涉及 用户验证,也可能仅涉及简单的 用户存在性测试

Backed Up

Public Key Credential Sources 可能以某种方式被备份,以便它们可以出现在生成它们的 generating authenticator 之外的其它认证器上。备份可以通过包括但不限于点对点同步、云同步、局域网同步和手动导入/导出等机制进行。另见 § 6.1.3 凭证备份状态

Backup Eligibility
Backup Eligible

一个 公钥凭据源生成认证器 会在创建时确定该 公钥凭据源 是否允许被 备份。备份资格通过 认证器数据标志 与当前 备份状态 一起标识。 备份资格属于一种 凭据属性,对于给定的 公钥凭据源 是永久不变的。 具有备份资格的 公钥凭据源 被称为 多设备凭据,而不具备备份资格的则称为 单设备凭据。另见 § 6.1.3 凭据备份状态

Backup State

由当前的 managing authenticator 决定的 multi-device credential 的当前备份状态。备份状态通过 authenticator dataflags 指示,且可随时间变化。另见 backup eligibility§ 6.1.3 凭证备份状态

Biometric Authenticator

任一实现了 biometric recognitionauthenticator

Biometric Recognition

基于生物和行为特征对个体进行自动识别的过程,参见 [ISOBiometricVocabulary]

Bound credential
"Authenticator contains a credential"
"Credential created on an authenticator"

当一个 public key credential sourcepublic key credential 被称为 bound 于它的 managing authenticator 时,意味着只有该 managing authenticator 能为绑定到它的 public key credential sources 生成 assertions

这也可以表述为“managing authenticator containsbound credential”,或“该 bound credential 是在其 managing authenticatorcreated on 的”。注意,服务器端凭证(server-side credential)可能并不物理存储在认证器的持久内存中,因此“bound to” 是主要术语。另见 § 6.2.2 凭证存储方式

Ceremony

ceremony 的概念(参见 [Ceremony])是对网络协议概念的扩展,加入了人类节点与计算机节点并存以及包含用户界面、人对人通信与承载数据的物理对象转移的通信链路。对协议来说的带外(out-of-band)在仪式中是带内(in-band)。在本规范中,RegistrationAuthentication 都是仪式,而 authorization gesture 通常是这些 ceremonies 的组成部分。

Client
WebAuthn Client

此处亦简称为 client。另见 Conforming User AgentWebAuthn Client 是一个中介实体,通常在用户代理内(全部或部分)实现。从概念上讲,它承载 Web Authentication API 的实现,并实现 [[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 等内部方法。它负责为底层的 authenticator operations 进行输入编排,并将这些操作的结果返回给 Web Authentication API 的调用者。

WebAuthn ClientWebAuthn Client Device 上运行,且与其是不同的实体。

Client Device
WebAuthn Client Device

运行 WebAuthn Client 的硬件设备,例如智能手机、笔记本或台式机,以及在该硬件上运行的操作系统。

下列是 WebAuthn Client deviceclient 之间的区别:

一个 客户端设备 和一个 客户端 共同组成一个 客户端平台

Client Platform

client deviceclient 合在一起构成 client platform。单一硬件设备可通过运行不同的操作系统和/或 clients 在不同时间成为多个不同的 client platforms 的一部分。

Client-Side

通常指用户的 client platformauthenticators 及连接这些组件的一切部分的组合。

Client-side discoverable Public Key Credential Source
Client-side discoverable Credential
Discoverable Credential
Passkey
[DEPRECATED] Resident Credential
[DEPRECATED] Resident Key

注意:历史上,client-side discoverable credentials 曾被称为 resident credentialsresident keys。由于术语 ResidentKeyresidentKeyWebAuthn APIAuthenticator Model(例如在字典成员名、算法变量名和操作参数中)被广泛使用,为了向后兼容,这些名称中的 resident 并未更改。此外,这里将 resident key 定义为等同于 client-side discoverable credential

Client-side discoverable Public Key Credential Source(简称 Discoverable Credential)是一个可被 authentication ceremonies 发现并用于认证的 public key credential source,适用于 Relying Party 不提供任何 credential ID 的情况,也就是 emptyallowCredentials 参数被传入 navigator.credentials.get() 时。这意味着 Relying Party 不必事先识别用户。

因此,一个支持 discoverable credential 的 authenticator 能够仅凭一个 RP ID 为一个 discoverable credential 生成 assertion signature,这要求相应的 public key credential source 被存储在认证器或 client platform 中。与之相对的 Server-side Public Key Credential Source 要求 authenticator 同时得到 RP IDcredential ID,但不要求在客户端侧存储该凭证源。

另见:client-side credential storage modalitynon-discoverable credential

注意:Client-side discoverable credentials 也可用于在 authentication ceremonies 中提供了 credential ID 的情况,即当调用 navigator.credentials.get() 并传入非 emptyallowCredentials 参数时。

Conforming User Agent

与底层的 client device 合作,实现 Web Authentication API 以及本规范中给出的算法,并处理 authenticatorsRelying Parties 之间通信的用户代理。

Credential ID

一个概率上唯一的 字节序列,用于识别 public key credential source 及其 authentication assertions。长度不超过 1023 字节。

Credential IDs 由 authenticators 以两种形式生成:

  1. 至少 16 字节且包含至少 100 位熵,或

  2. public key credential source(去掉其 Credential ID可变项)进行加密的形式,使得只有其 managing authenticator 能解密它。此形式使得认证器几乎无状态,依赖于 Relying Party 存储必要的状态。

    注意:[FIDO-UAF-AUTHNR-CMDS] 在 “Security Guidelines” 中包含了关于加密技术的指导。

Relying Parties 无需区别这两种 Credential ID 形式。

Credential Key Pair
Credential Private Key
Credential Public Key
User Public Key

credential key pair 是由 authenticator 生成并且相对于特定 WebAuthn Relying Party作用域化 的一对非对称加密密钥。它是 public key credential 的核心部分。

credential public keycredential key pair 的公钥部分。credential public keyregistration ceremony 中返回给 Relying Party

credential private keycredential key pair 的私钥部分。credential private key 被绑定到特定的 authenticator —— 即其 managing authenticator —— 并被期望永远不对任何其它方暴露,甚至不对认证器的拥有者暴露。

注意在 self attestation 的情况下,credential key pair 也被用作 attestation key pair,详见 self attestation 的说明。

注意:在 FIDO UAF 的 [UAFProtocol] 与 FIDO U2F 的 [FIDO-U2F-Message-Formats] 中,以及与之相关的本规范部分,credential public key 被称为 user public key

Credential Properties

credential propertypublic key credential source 的某些特征属性,例如它是否为 client-side discoverable credentialserver-side credential

Credential Record

为了实现 § 7 WebAuthn Relying Party Operations 中定义的算法,Relying Party 必须存储已注册的 public key credential sources 的一些属性。credential record struct 是这些属性在 user account 中存储的抽象表示。credential record 在 registration ceremony 中创建,并在随后的 authentication ceremonies 中使用。Relying Parties 可以根据需要或应用户请求删除 credential records。

为了实现 § 7.1 注册新凭证§ 7.2 验证认证断言 的所有步骤,建议存储下列 items

type

公钥凭据源类型

id

公钥凭据源凭据ID

publicKey

公钥凭据源凭据公钥

signCount

最近一次通过该 公钥凭据源 参与的任何 仪式 中,认证器数据 里的 签名计数器 的最新值。

transports

公钥凭据源注册 时,getTransports() 返回的值。

注意: 修改或移除 getTransports() 返回值中的 项目 可能会影响用户体验,甚至导致相应凭据无法使用。

uvInitialized

一个布尔值,表示该 公钥凭据源 的任意 凭据 是否设置过 UV 标志

当此值为 true 时,服务接受方 可以在 认证仪式 中将 UV 标志 视为一种 认证因子。 例如,如 uvInitializedtrue 并且 UV 标志已设置时,服务接受方 可以跳过密码提示,即便未要求 用户验证

当此值为 false 时,包括某个 认证仪式 会将其变为 true 的情形, UV标志 不能作为 认证因子 依赖。 这是因为 公钥凭据源 第一次将 UV 标志 置为 1 时,服务接受方认证器用户验证 之间尚未建立信任关系。 因此,将 uvInitializedfalse 更新为 true 时, 应当要求通过等同于 WebAuthn 用户验证 的额外 认证因子 进行授权。

backupEligible

公钥凭据源 创建时 BE 标志 的值。

backupState

最近一次通过该 公钥凭据源 参与的任何 仪式 中,认证器数据 里的 BS 标志 的最新值。

下列 items 为可选项:

attestationObject

公钥凭据源注册 时,attestationObject 属性的值。 存储该值可以让 服务接受方 日后引用此凭据的 证明声明

attestationClientDataJSON

当该 public key credential sourceregistered 时,clientDataJSON 属性的值。将此值与上述的 attestationObject 一起存储,可使 Relying Party 在以后重新验证 attestation signature

rpId

rp.id 参数的值, 在凭证注册期间通过 create() 操作指定。 此值是凭证的核心属性,用于确定该凭证可以使用的范围。 在注册时存储此值,有助于未来对凭证使用进行审计、排查认证问题或通过关联来源实现在不同域名间使用。

WebAuthn 扩展 可能定义处理该扩展所需的额外 itemsRelying Parties 也可以根据需要包含任何额外的 items,并且可以省略其实现中不需要的任何 items

用于凭证记录的 credential descriptor for a credential record 是一个具有下列内容的 PublicKeyCredentialDescriptor 值:

type

credential recordtype

id

credential recordid

transports

credential recordtransports

Generating Authenticator

Generating Authenticator 是参与导致创建给定 public key credential sourceauthenticatorMakeCredential 操作的认证器。对于 single-device credentials,生成认证器与该 managing authenticator 相同。对于 multi-device credentials,生成认证器可能与在某次 authentication 操作中参与的当前 managing authenticator 是否相同则不确定。

Human Palatability

一个被称为 human-palatable 的标识符,旨在便于典型用户记忆和重复,与例如随机生成的比特序列不同,参见 [EduPersonObjectClassSpec]

Non-Discoverable Credential

指一种 credential,其 credential ID 必须在调用 navigator.credentials.get() 时通过 allowCredentials 提供,因为它不可被 client-side discoverable。另见 server-side credentials

Registrable Origin Label

某域名的可注册域(registrable domain)的第一个 domain label,如果该可注册域为 null 则返回 null。例如,当 co.ukde 都是 public suffixes 时,example.co.ukwww.example.deregistrable origin label 均为 example

Public Key Credential

一般来说,凭据 是一个实体向另一个实体展示的数据,用于向后者 认证 前者的身份 [RFC4949]。术语 公钥凭据 可指以下之一:公钥凭据源、与 公钥凭据源 对应的、可能已经过证明凭据公钥,或是一次 认证断言。具体指哪一个通常取决于上下文。

注意:这在某种程度上是对 [RFC4949] 的一种“有意违反”。在英语中,“credential” 一词既可以表示用于证明的事物,也常被期望可被多次使用。在公钥系统中,用单一数据同时安全地满足这两点是不可能的。[RFC4949] 将 credential 定义为可以多次使用的事物(即公钥),而本规范在术语使用上更灵活。为避免歧义,本规范使用更具体的术语来标识与 [RFC4949] 中的 credential 相关的数据:
"Authentication information" (possibly including a private key)

Public key credential source

"Signed value"

Authentication assertion

[RFC4949] "credential"

Credential public keyattestation object

registration 时,authenticator 创建一个非对称密钥对,并将其 私钥部分 与来自 Relying Party 的信息存入一个 public key credential source公钥部分 被返回给 Relying Party,随后由其存入该用户的活动 user account。随后,仅由用其注册时所用的 RP ID 标识的相同实体(即该 Relying Party)才能在 authentication ceremonies 中使用该 public key credential,通过 get() 方法。Relying Party 使用其存储的 credential public key 来验证由该凭证产生的 authentication assertion

Public Key Credential Source

一个用于认证器生成 authentication assertionscredential source(参见 [CREDENTIAL-MANAGEMENT-1])。一个 public key credential source 由一个 struct 组成,其包含下列 items

type

其值为 PublicKeyCredentialType,默认值为 public-key

id

一个 Credential ID

privateKey

credential private key

rpId

公钥凭据源关联服务接受方标识符,用于标识此 服务接受方。 该标识由 rp.id 参数在 create() 操作中决定。

userHandle

public key credential source 在创建时关联的 user handle。该 item 可为空,但对于 discoverable credentials 来说,user handle 必须被填充。

otherUI

可选的其它信息,用于 authenticator 在其 UI 中显示。例如,这可能包含用户的 displayNameotherUI 是一个 mutable item,且不应以阻止该 public key credential source 更新其 otherUI 的方式进行绑定。

authenticatorMakeCredential 操作会创建一个绑定到 managing authenticatorpublic key credential source,并返回与其 credential private key 相关联的 credential public keyRelying Party 可使用该 credential public key 来验证由该 public key credential source 创建的 authentication assertions

Rate Limiting

通过限制在给定时间段内连续失败认证尝试次数来对抗暴力破解攻击的过程(亦称为节流)。若达到限制,认证器应对每次连续失败尝试施加指数增长的延迟,或禁用当前认证方式并在可用时提供另一个 authentication factor。Rate limiting 通常作为 user verification 的一部分实现。

Registration
Registration Ceremony

指的是在该 ceremony 中,用户、Relying Party 与用户的 client platform(包含或连接至少一个 authenticator)协同工作以创建 public key credential 并将其与 user account 关联。注意这包括使用 用户存在性测试user verification。成功的 registration ceremony 后,用户可以通过 authentication ceremony 进行认证。

WebAuthn 注册流程定义在 § 7.1 注册新凭据, 由Relying Party 调用 navigator.credentials.create() 方法, 并传入 publicKey 参数。 相关简介见 § 5 Web 身份认证 API,实现示例见 § 1.3.1 注册流程

Relying Party
WebAuthn Relying Party

web application 利用 Web Authentication API注册认证 用户的实体。

一个 Relying Party 实现通常由客户端脚本(在 client 中调用 Web Authentication API)和在服务器端执行 Relying Party 操作 及其它应用逻辑的组件共同组成。两部分之间的通信必须使用 HTTPS 或等效的传输安全,但除此之外超出本规范的范围。

注意:虽然 服务接受方(Relying Party) 这个术语在其他上下文(例如 X.509 和 OAuth)中也经常被使用,但在一个上下文中作为 服务接受方 的实体,在其他上下文中未必也是 服务接受方。在本规范中,WebAuthn 服务接受方 通常被简称为 服务接受方,并明确指 WebAuthn 上下文中的 服务接受方。需要注意的是,在任何具体实现中,WebAuthn 上下文可能被嵌入到更广泛的环境当中,例如基于 OAuth 的体系。

Relying Party Identifier
RP ID

WebAuthn API 的上下文中,relying party identifier 是用来标识代表其执行某次注册或认证仪式的 WebAuthn Relying Party 的一个 valid domain string。一个 public key credential 只能与其注册时所用的相同实体(由 RP ID 标识)一起用于 authentication

默认情况下,WebAuthn 操作的 RP ID 设置为调用者的 origineffective domain。调用者可以覆盖该默认值,只要调用者指定的 RP ID 调用者 origineffective domain 的可注册域后缀或与之相等。另见 § 5.1.3 Create a New Credential - PublicKeyCredential’s [[Create]](origin, options, sameOriginWithAncestors) Internal Method§ 5.1.4 Use an Existing Credential to Make an Assertion

RP ID是基于主机域名。它本身不包含协议端口,而origin包含这些信息。 RP ID决定了公钥凭证作用域。 即它决定公钥凭证可以被使用的 origin 集合,具体如下:

例如,若某 Relying Party 的 origin 为 https://login.example.com:1337,则合法的 RP IDlogin.example.com(默认)和 example.com,但不包括 m.login.example.comcom。另一个合法的 origin 示例为 http://localhost:8000,因为 origin 为 localhost

这样做是为了匹配广泛部署的环境凭证(例如 cookie,参见 [RFC6265])的行为。请注意,这比 document.domain 的 setter 提供的“同源”放宽程度更大。

这些对 origin 值的限制适用于 WebAuthn Clients

其它旨在在非 Web 平台(例如原生移动应用)上启用 WebAuthn public key credentials 的规范,可能会为将调用者绑定到 Relying Party Identifier 定义不同的规则。但 RP ID 的语法必须符合 valid domain strings 或 URI(参见 [RFC3986][URL])。

Server-side Public Key Credential Source
Server-side Credential
[DEPRECATED] Non-Resident Credential

注意:历史上,server-side credentials 曾被称为 non-resident credentials。为向后兼容,本规范中包含 "resident" 的若干 WebAuthn API 与 Authenticator Model 组件名称并未更改。

Server-side Public Key Credential Source(简称 Server-side Credential)是一个仅在 authentication ceremony 中可用的 public key credential source,前提为 Relying Partynavigator.credentials.get()allowCredentials 参数中提供其 credential ID。这意味着 Relying Party 必须管理该凭证的存储与发现,并且必须能够先识别用户以便找出要在 navigator.credentials.get() 调用中提供的 credential IDs

对于 server-side credential,不要求在 client-side 存储 public key credential source。这与 client-side discoverable credential 不同,后者无需先识别用户就可以在 navigator.credentials.get() 调用中提供用户的 credential ID 列表。

另见:server-side credential storage modalitynon-discoverable credential

Test of User Presence

test of user presence 是一种简单的 authorization gesture 与技术过程,用户通常通过简单地触碰认证器(也可能有其它方式)与认证器交互,从而得到布尔结果。注意这并不构成 user verification,因为用户存在性测试并不具备进行 生物识别识别 的能力,也不涉及诸如密码或 PIN 等共享秘密的呈现。

User Account

在本规范中, 用户账户 指的是将一组 凭据 [CREDENTIAL-MANAGEMENT-1] 映射到 服务接受方 资源(或其子集)上的关系,并由 服务接受方 维护和授权。 服务接受方 通过为凭据的 用户句柄 分配一个特定于 用户账户 的值,并将该凭据的 凭据记录 存储在 用户账户 中,从而将某个 公钥凭据 映射到 用户账户。 这种映射、凭据集合及其授权可以随着时间变化。 一个 用户账户 可能由一个或多个自然人(即“用户”)访问, 一个自然人也可能根据其自身及 服务接受方 的操作访问一个或多个 用户账户

User Consent

用户同意意味着用户认同他们被请求的内容,即包含阅读并理解提示的要素。authorization gesture 常作为指示 user consent 的仪式组件。

User Handle

用户句柄是用户账户的标识符,由服务接受方user.id 作为参数,在注册时指定。可发现凭据会存储该标识符,并且在以 allowCredentials 参数启动的认证仪式中,必须将其作为 response.userHandle 返回。

用户句柄的主要用途是在此类认证仪式中标识用户账户,但也可以使用凭据ID。主要区别在于,凭据ID认证器选择,每个凭据唯一,而用户句柄服务接受方选择,并且应对同一用户账户下所有注册的凭据保持一致。

认证器映射 RP ID用户句柄的二元组到公钥凭据源。 因此,每个认证器对于每个服务接受方、每个用户句柄,最多只会存储一个可发现凭据。因此,用户句柄的另一个用处是,在注册仪式期间,允许认证器判断何时需要用新的可发现凭据替换已有的。

用户句柄是一个不透明的字节序列,最大长度为64字节,不应展示给用户。其内容不得包含任何个人身份信息,详见§ 14.6.1 用户句柄内容

User Present

在成功完成 用户存在性测试 后,用户被称为 "present"。

User Verification

一种技术过程,authenticator 在本地授权调用 authenticatorMakeCredentialauthenticatorGetAssertion 操作。User verification 可以通过多种 authorization gesture 形式来实现,例如触摸加 PIN、密码输入,或 生物识别(例如指纹识别)。其目的在于区分不同的个体。另见 § 6.2.3 认证因子能力

注意 user verification 并不会向 Relying Party 提供用户的具体身份,但当对同一 credential 已经执行了两次或更多次带有 user verification 的仪式时,它表明是同一用户执行了这些仪式。不过,如果多个自然人共享对同一 authenticator 的访问,则同一用户未必总是同一自然人。

注意:将自然人区分开在很大程度上依赖于 client platformauthenticator 的能力。例如,有些设备旨在单个个人使用,但它们可能允许多名自然人注册指纹或知道相同的 PIN,从而能使用该设备访问相同的 user account(s)。

注意:调用 authenticatorMakeCredentialauthenticatorGetAssertion 操作意味着将使用认证器管理的密钥材料。

为保证安全,user verification 与使用 credential private keys 必须全部在定义 authenticator 的逻辑安全边界内发生。

User verification 程序可以实现 rate limiting 以防暴力破解攻击。

User Verified

在成功完成 user verification 过程后,用户被称为 "verified"。

5. Web 身份验证 API

本节规范性地指定了用于创建和使用 公钥凭证 的 API。基本思路是凭证属于用户,并由 管理 它们的 WebAuthn 认证器 负责,WebAuthn 依赖方 通过 客户端平台 与其交互。Relying Party 的脚本可以在取得 用户同意 后,请求浏览器为将来由该 Relying Party 使用创建一个新的凭证。见下文的

注册流程

脚本也可以请求用户许可,以便对现有凭证执行 认证 操作。见下文的

认证流程

所有此类操作均在认证器内执行,并由 客户端平台 代表用户进行中介。脚本在任何时刻都不会直接获得凭证本身;它只会以对象的形式获取关于凭证的信息。

除了上述的脚本接口外,认证器可以实现(或随同会实现该功能的客户端软件一起提供)一个用于管理的用户界面。这样的界面可用于例如将认证器重置为初始状态或检查认证器的当前状态。换言之,这类界面类似于浏览器为管理用户状态(例如历史记录、已保存密码和 cookie)提供的用户界面。诸如删除凭证之类的认证器管理操作被视为此类用户界面的职责,并有意从暴露给脚本的 API 中省略。

该 API 的安全属性由客户端与认证器共同提供。持有并 管理 凭证的认证器保证所有操作都相对于特定的 origin 进行 作用域化,并通过在其响应中包含 origin 来确保这些响应不能被重放到不同的 origin。具体而言,如在 § 6.3 认证器操作 中所定义,请求者的完整 origin 会被包含并签名于当创建新凭证时产生的 attestation object,以及所有由 WebAuthn 凭证生成的断言中。

此外,为了维护用户隐私并防止恶意 Relying Parties 探测属于其它 Relying Parties公钥凭证 的存在,每个 凭证 也被 作用域化 到一个 Relying Party 标识符(或称 RP ID)。此 RP ID 在所有操作中由客户端提供给 认证器,且 认证器 确保由某一 Relying Party 创建的 凭证 仅能在同一 RP ID 请求的操作中被使用。以这种方式将 originRP ID 分离,使得在单个 Relying Party 维护多个 origins 的情况下也能使用该 API。

客户端通过为每次操作向 认证器 提供 Relying PartyoriginRP ID 来协助这些安全措施。由于这是 WebAuthn 安全模型的一个组成部分,用户代理仅在 安全上下文 中向调用者公开此 API。对于 Web 上下文而言,这仅包括通过无错误建立的安全传输(例如 TLS)访问的上下文。

Web 身份验证 API 由下列各节中呈现的 Web IDL 片段的并集定义。合并的 IDL 列表见 IDL 索引

5.1. PublicKeyCredential 接口

PublicKeyCredential 接口继承自 Credential [CREDENTIAL-MANAGEMENT-1],并包含在创建新凭证或请求新断言时返回给调用者的属性。

[SecureContext, Exposed=Window]
interface PublicKeyCredential : Credential {
    [SameObject] readonly attribute ArrayBuffer              rawId;
    [SameObject] readonly attribute AuthenticatorResponse    response;
    readonly attribute DOMString?                            authenticatorAttachment;
    AuthenticationExtensionsClientOutputs getClientExtensionResults();
    static Promise<boolean> isConditionalMediationAvailable();
    PublicKeyCredentialJSON toJSON();
};
id

此属性继承自 Credential,但 PublicKeyCredential 覆盖了 Credential 的 getter, 改为返回对象的 [[identifier]] internal slot 中数据的 base64url 编码

rawId

此属性返回存储在 [[identifier]] 内部槽中的 ArrayBuffer

response, of type AuthenticatorResponse, readonly

此属性包含 认证器 对客户端请求创建 公钥凭证 或生成 认证断言 的响应。如果 PublicKeyCredential 是响应 create() 创建的, 该属性的值将为 AuthenticatorAttestationResponse; 否则, 若 PublicKeyCredential 是响应 get() 创建的, 则该属性的值将为 AuthenticatorAssertionResponse

authenticatorAttachment, of type DOMString, readonly, nullable

此属性报告在 navigator.credentials.create()navigator.credentials.get() 方法成功完成时生效的 认证器附着方式。 属性值应当为 AuthenticatorAttachment 的一个成员。 Relying Parties 应将未知值视为 null。

注意:如果在一次 注册认证仪式 的结果中,authenticatorAttachment 的值为 "cross-platform" 并且同时 isUserVerifyingPlatformAuthenticatorAvailable 返回 true,则说明用户在当次 仪式 中使用了一个 漫游认证器,同时存在可用的 平台认证器。因此 Relying Party 有机会提示用户注册可用的 平台认证器,以便启用更顺畅的用户体验流程。

认证器的 attachment modality 可能随时间变化。例如,某些手机起初可能只支持 平台附着,但随后通过更新也支持 跨平台附着

getClientExtensionResults()

此操作返回 [[clientExtensionsResults]] 的值, 它是一个包含扩展的 映射,映射条目为 扩展标识符客户端扩展输出,这些条目由扩展的 客户端扩展处理 产生。

isConditionalMediationAvailable()

PublicKeyCredential 重写此方法以指示在 conditional 介入下 navigator.credentials.get() 可用。WebAuthn 服务接受方 在尝试将 options.mediation 设置为 conditional 之前应当验证功能是否可用。

调用该方法时,会返回一个 Promise,如果 conditional 用户介入 可用,则解析为 true,否则为 false

此方法无参数,返回一个 Promise,Promise 的值为布尔值。

conditionalGet 功能等效于此 Promise 解析为 true

注意:如果没有此方法,则 conditional 用户介入 不可用于 navigator.credentials.get()

注意:此方法 表示 conditional 用户介入navigator.credentials.create() 中是否可用。 如需判断,请参阅 conditionalCreate 能力以及 getClientCapabilities()

toJSON()

此操作返回 RegistrationResponseJSONAuthenticationResponseJSON, 它们是反映 PublicKeyCredentialJSON 类型 表示,适合作为 application/json 有效负载提交给 Relying Party 服务器。客户端 负责像往常那样将值序列化为 JSON 类型,但必须采取额外步骤:先将任何 ArrayBuffer 值编码为 DOMString 值,方法是使用 base64url 编码

成员 RegistrationResponseJSON.clientExtensionResultsAuthenticationResponseJSON.clientExtensionResults 必须设置为 getClientExtensionResults() 的输出,其中任何 ArrayBuffer 值都必须使用 base64url 编码 转为 DOMString。这可以包括来自 IANA “WebAuthn Extension Identifiers” 注册表中注册但未在 § 9 WebAuthn 扩展 定义的扩展中返回的 ArrayBuffer 值。

成员 AuthenticatorAttestationResponseJSON.transports 必须设置为 getTransports() 的输出。

成员 AuthenticatorAttestationResponseJSON.publicKey 必须设置为 getPublicKey() 的输出。

成员 AuthenticatorAttestationResponseJSON.publicKeyAlgorithm 必须设置为 getPublicKeyAlgorithm() 的输出。

typedef DOMString Base64URLString;
// The structure of this object will be either
// RegistrationResponseJSON or AuthenticationResponseJSON
typedef object PublicKeyCredentialJSON;

dictionary RegistrationResponseJSON {
    required DOMString id;
    required Base64URLString rawId;
    required AuthenticatorAttestationResponseJSON response;
    DOMString authenticatorAttachment;
    required AuthenticationExtensionsClientOutputsJSON clientExtensionResults;
    required DOMString type;
};

dictionary AuthenticatorAttestationResponseJSON {
    required Base64URLString clientDataJSON;
    required Base64URLString authenticatorData;
    required sequence<DOMString> transports;
    // The publicKey field will be missing if pubKeyCredParams was used to
    // negotiate a public-key algorithm that the user agent doesn't
    // understand. (See section “Easily accessing credential data” for a
    // list of which algorithms user agents must support.) If using such an
    // algorithm then the public key must be parsed directly from
    // attestationObject or authenticatorData.
    Base64URLString publicKey;
    required COSEAlgorithmIdentifier publicKeyAlgorithm;
    // This value contains copies of some of the fields above. See
    // section “Easily accessing credential data”.
    required Base64URLString attestationObject;
};

dictionary AuthenticationResponseJSON {
    required DOMString id;
    required Base64URLString rawId;
    required AuthenticatorAssertionResponseJSON response;
    DOMString authenticatorAttachment;
    required AuthenticationExtensionsClientOutputsJSON clientExtensionResults;
    required DOMString type;
};

dictionary AuthenticatorAssertionResponseJSON {
    required Base64URLString clientDataJSON;
    required Base64URLString authenticatorData;
    required Base64URLString signature;
    Base64URLString userHandle;
};

dictionary AuthenticationExtensionsClientOutputsJSON {
};
[[type]]

PublicKeyCredential 接口对象[[type]] 内部槽 的值为字符串 "public-key"。

注: 这一点可通过 type 属性的 getter(从 Credential 继承) 得到。

[[discovery]]

PublicKeyCredential 接口对象[[discovery]] 内部槽 的值为 "remote"。

[[identifier]]

内部槽 包含由认证器选择的 凭证ID。 该 凭证ID 用于查找待使用的凭证,因此有望在同类型所有凭证、所有认证器间具有很高的全球唯一性概率。

此API对该标识符的格式没有限制,但要求其长度不得超过1023字节,并且必须足以让 认证器 能唯一选取密钥。 例如,没有板载存储的认证器可能会生成包含 凭证私钥,并用对称密钥包裹后的标识符。

[[clientExtensionsResults]]

内部槽 包含了 服务方 在调用 服务方navigator.credentials.create()navigator.credentials.get() 时请求的客户端扩展处理结果。

PublicKeyCredential接口对象 继承自 Credential 的 实现 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors), 并为以下操作定义了自己的实现: [[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)[[Store]](credential, sameOriginWithAncestors)

调用 CredentialsContainerpreventSilentAccess() 方法 对 PublicKeyCredential 凭证不会产生任何影响,因为它们始终需要用户交互。

5.1.1. CredentialCreationOptions 字典扩展

为了支持通过 navigator.credentials.create() 进行注册, 本文档按如下方式扩展了 CredentialCreationOptions 字典:

partial dictionary CredentialCreationOptions {
    PublicKeyCredentialCreationOptions      publicKey;
};

5.1.2. CredentialRequestOptions 字典扩展

为了支持通过 navigator.credentials.get() 获取断言, 本文档按如下方式扩展了 CredentialRequestOptions 字典:

partial dictionary CredentialRequestOptions {
    PublicKeyCredentialRequestOptions      publicKey;
};

5.1.3. Create a New Credential - PublicKeyCredential’s [[Create]](origin, options, sameOriginWithAncestors) Internal Method

PublicKeyCredentialinterface object[[Create]](origin, options, sameOriginWithAncestors) internal method 的实现 [CREDENTIAL-MANAGEMENT-1] 允许 WebAuthn Relying Party 脚本调用 navigator.credentials.create() 来请求创建一个新的 public key credential source,并将其绑定到一个authenticator

通过将 options.mediation 设置为 conditionalRelying Parties 可以表明他们希望在用户已同意创建凭证的情况下进行凭证注册且不显示显著的模态 UI。 服务方(Relying Party)应当首先使用 getClientCapabilities() 检查 client 是否支持 conditionalCreate 能力,以防止在该功能不可用时出现对用户可见的错误。 当 options.mediation 被设置为 conditional 时,客户端必须将 requireUserPresencerequireUserVerification 均设置为 FALSE,除非这些操作可以在仪式过程中被显式执行。

可以通过使用 AbortController 中止任何 navigator.credentials.create() 操作;详见 DOM § 3.3 在 API 中使用 AbortController 和 AbortSignal 对象 以获取详细说明。

internal method 接受三个参数:

origin

此参数是调用 create() 实现所确定的 relevant settings objectorigin

options

此参数是一个 CredentialCreationOptions 对象,其 options.publicKey 成员包含一个 PublicKeyCredentialCreationOptions 对象,指定将要创建的 public key credential 的期望属性。

sameOriginWithAncestors

此参数为布尔值,当且仅当调用者的 environment settings object 与其祖先同源时值为 true。若调用者为跨源则值为 false

注:调用此 internal method 表示此调用已被 permissions policy 所允许,该 policy 在 [CREDENTIAL-MANAGEMENT-1] 层面进行评估。 参见 § 5.9 Permissions Policy 集成

注: 此算法为同步: Promise 的解决/拒绝由 navigator.credentials.create() 处理。

本算法中使用的所有 BufferSource 对象必须在算法开始时进行快照,以避免潜在的同步问题。实现应当 获取该缓冲源所持字节的副本 并在算法相关部分使用该副本。

当调用此方法时,用户代理必须执行以下算法:

  1. 断言: options.publicKey 存在。

  2. 如果 sameOriginWithAncestorsfalse

    1. 如果 options.mediation 存在且其值为 conditional

      1. 抛出一个 "NotAllowedError" DOMException

    2. 如果调用 create() 实现所确定的 relevant global object 没有 transient activation

      1. 抛出一个 "NotAllowedError" DOMException

    3. 对该 relevant global object 消耗用户激活(Consume user activation)。

    4. 如果创建凭证的 origin 与该 relevant global object 的顶级来源(top-level origin)不同(即与用户地址栏中看到的来源不同),则 client 应当向用户明确说明此事实。

  3. pkOptionsoptions.publicKey 的值。

  4. 如果 pkOptions.timeout 存在,则检查其值是否位于由 client 定义的合理范围内;若不是,则将其修正为最接近该范围的值。将计时器 lifetimeTimer 设为此调整后的值。若 pkOptions.timeout 不存在,则将 lifetimeTimer 设为客户端特定的默认值。

    有关决定 pkOptions.timeout 的合理范围和默认值的指导,请参阅 推荐的 WebAuthn 仪式超时范围和默认值

    客户端在考虑有特殊需求的用户时应注意认知方面的指引来决定超时值。

  5. 如果 pkOptions.user.id 的长度不在 1 到 64 字节(含)之间,则抛出一个 TypeError

  6. callerOriginorigin。 如果 callerOriginopaque origin,则抛出一个 "NotAllowedError" DOMException

  7. effectiveDomaincallerOrigineffective domain。 如果该 effective domain 不是一个 有效域名,则抛出一个 "SecurityError" DOMException

    注:一个 effective domain 可能解析为一个 host,该 host 可以用多种方式表示,例如 domainIPv4 地址IPv6 地址opaque hostempty host。 此处仅允许使用 domain 格式的 host。此规定既为简化,也考虑到在与基于 PKI 的安全机制配合使用时直接使用 IP 地址可能带来的各种问题。

  8. If pkOptions.rp.id

    存在

    如果 pkOptions.rp.id 既不是 registrable domain 的后缀也不等于 effectiveDomain,且客户端

    支持 related origin requests
    1. rpIdRequestedpkOptions.rp.id 的值。

    2. 用参数 callerOriginrpIdRequested 运行 related origins validation procedure。如果结果为 false,则抛出一个 "SecurityError" DOMException

    不支持 related origin requests

    抛出一个 "SecurityError" DOMException

    不存在

    pkOptions.rp.id 设置为 effectiveDomain

    注: pkOptions.rp.id 表示调用者的 RP ID。除非调用者在调用 create() 时显式设置了 pkOptions.rp.idRP ID 默认为调用者 origineffective domain

  9. credTypesAndPubKeyAlgs 为一个新的 list,其 itemsPublicKeyCredentialTypeCOSEAlgorithmIdentifier 的配对。

  10. 如果 pkOptions.pubKeyCredParamssize

    为零

    Append 以下 PublicKeyCredentialTypeCOSEAlgorithmIdentifier 的配对到 credTypesAndPubKeyAlgs

    非零

    对于 pkOptions.pubKeyCredParams 的每个 current

    1. 如果 current.type 不包含此实现支持的 PublicKeyCredentialType,则 continue

    2. algcurrent.alg

    3. Append current.typealg 的配对到 credTypesAndPubKeyAlgs

    如果 credTypesAndPubKeyAlgs 为空,则抛出一个 "NotSupportedError" DOMException

  11. clientExtensions 为一个新的 map,并令 authenticatorExtensions 为一个新的 map

  12. 如果 pkOptions.extensions 存在,则对 每个 extensionIdclientExtensionInputpkOptions.extensions 执行以下操作:
    1. 如果 extensionId 不被此 client platform 支持,或不是一个 registration extension,则 continue

    2. Set clientExtensions[extensionId] 为 clientExtensionInput

    3. 如果 extensionId 不是一个 authenticator extension,则 continue

    4. authenticatorExtensionInput 为对 clientExtensionInput 运行 extensionIdclient extension processing 算法后得到的 (CBOR) 结果。如果该算法返回错误,则 continue

    5. Set authenticatorExtensions[extensionId] 为 base64url 编码authenticatorExtensionInput

  13. collectedClientData 为一个新的 CollectedClientData 实例,其字段为:

    type

    字符串 "webauthn.create".

    challenge

    base64url 编码pkOptions.challenge

    origin

    serializationcallerOrigin

    crossOrigin

    此处为传入到该 sameOriginWithAncestors 参数的值的逆。

    topOrigin

    如果传入的 sameOriginWithAncestors 参数为 false,则为 callerOrigintop-level originserialization,否则为 undefined

  14. clientDataJSON 成为从 collectedClientData 构造的 与 JSON 兼容的客户端数据的序列化

  15. clientDataHash 为由 clientDataJSON 表示的 序列化客户端数据的哈希

  16. 如果 options.signal 存在并且 已中止,则抛出该 options.signal中止原因

  17. issuedRequests 为一个新的 ordered set

  18. authenticators 表示一个值,该值在任何给定时刻为一个 集合,集合中的每个项为特定于 client platform 的句柄,每个项都标识在该时刻可用的 authenticator

    注:关于一个 authenticator 被视为“可用”的具体条件并未在此明确规定;这旨在表示 authenticators 可以通过各种机制被 热插(例如通过 USB)或被发现(例如通过 NFC 或蓝牙)到 client,或者永久内置于该 client 中。

  19. 如果 options.mediation 存在且其值为 conditional

    1. 如果用户代理最近没有调解过一次认证、该认证的来源不是 callerOrigin,或用户不同意此类凭证创建,则抛出一个 "NotAllowedError" DOMException

      何时认定一个认证仪式已完成由用户代理决定。该认证仪式可以通过除 Web Authentication API 之外的其他方式完成。

  20. 考虑 hints 的值,并由用户代理酌情设计用户界面以适应这些提示。

  21. 启动 lifetimeTimer

  22. lifetimeTimer 未到期时,针对 authenticators 中的每个 authenticator, 根据 lifetimeTimer 的状态和响应执行下列操作:
    如果 lifetimeTimer 到期,

    issuedRequests 中的每个 authenticator 调用 authenticatorCancel 操作,并将该 authenticatorissuedRequests 中移除。

    如果用户在用户代理界面中选择取消该过程,

    issuedRequests 中的每个 authenticator 调用 authenticatorCancel 操作,并将该 authenticatorissuedRequests 中移除。抛出一个 "NotAllowedError" DOMException

    如果 options.signal 存在并且 已中止

    issuedRequests 中的每个 authenticator 调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。然后抛出该 options.signal中止原因

    如果某个 authenticator 在此 client device 上变得可用,

    注:这包括在启动 lifetimeTimer 时该 authenticator 已可用的情况。

    1. authenticator 现在为 candidate authenticator

    2. 如果 pkOptions.authenticatorSelection 存在:

      1. 如果 pkOptions.authenticatorSelection.authenticatorAttachment 存在且其值不等于该 authenticatorauthenticator attachment modality,则 continue

      2. 如果 pkOptions.authenticatorSelection.residentKey

        存在且设置为 required

        如果该 authenticator 无法存储 client-side discoverable public key credential source,则 continue

        存在且设置为 preferreddiscouraged

        无影响。

        不存在

        如果 pkOptions.authenticatorSelection.requireResidentKey 被设置为 true 并且该 authenticator 无法存储 client-side discoverable public key credential source,则 continue

      3. 如果 pkOptions.authenticatorSelection.userVerification 被设置为 requiredauthenticator 无法执行 用户验证,则继续

    3. requireResidentKeycredential creation 的有效 resident key 要求,该值为布尔值,定义如下:

      如果 pkOptions.authenticatorSelection.residentKey

      存在且设置为 required

      requireResidentKeytrue

      存在且设置为 preferred

      如果该 authenticator

      具备 client-side credential storage modality

      requireResidentKeytrue

      不具备上述能力,或 client 无法确定认证器能力,

      requireResidentKeyfalse

      存在且设置为 discouraged

      requireResidentKeyfalse

      不存在

      requireResidentKeypkOptions.authenticatorSelection.requireResidentKey 的值。

    4. userVerificationcredential creation 的有效 user verification 要求,该值为布尔值,定义如下。如果 pkOptions.authenticatorSelection.userVerification

      被设置为 required
      1. 如果 options.mediation 被设置为 conditional 且在仪式期间无法收集 user verification,则抛出一个 ConstraintError DOMException

      2. userVerificationtrue

      被设置为 preferred

      如果该 authenticator

      具备 user verification

      userVerificationtrue

      不具备 user verification

      userVerificationfalse

      被设置为 discouraged

      userVerificationfalse

    5. enterpriseAttestationPossible 为一个布尔值,如下定义。如果 pkOptions.attestation

      被设置为 enterprise

      如果用户代理希望为 pkOptions.rp.id 支持企业级 attestation(参见第 8 步),则令 enterpriseAttestationPossibletrue,否则为 false

      否则

      enterpriseAttestationPossiblefalse

    6. attestationFormats 为一个字符串列表,初始值为 pkOptions.attestationFormats 的值。

    7. 如果 pkOptions.attestation

      被设置为 none

      attestationFormats 设为只包含字符串 “none” 的单元素列表。

    8. excludeCredentialDescriptorList 为一个新的 list

    9. 对于 pkOptions.excludeCredentials 中的每个凭证描述符 C

      1. 如果 C.transports 非空,并且该 authenticator 通过一个并未在 C.transports 中列出的传输方式连接, 客户端可以 继续(即跳过此条)。

        注:如果客户端选择 继续,这可能会导致在同一 authenticator 上意外注册多个与之绑定的凭证,如果 C.transports 中的传输提示不准确就会如此。 例如,存储的传输提示可能由于软件升级添加了新的连接选项而变得不准确。

      2. 否则, C 添加到 excludeCredentialDescriptorList

      3. 调用该 authenticator 上的 authenticatorMakeCredential 操作,参数为: clientDataHashpkOptions.rppkOptions.userrequireResidentKeyuserVerificationcredTypesAndPubKeyAlgsexcludeCredentialDescriptorListenterpriseAttestationPossibleattestationFormats, 以及 authenticatorExtensions
    10. authenticator 添加到 issuedRequests

    如果某个 authenticator 在此 client device 上不再可用,

    issuedRequests 中移除该 authenticator

    如果任何 authenticator 返回指示用户已取消操作的状态,
    1. issuedRequests 中移除该 authenticator

    2. issuedRequests 中剩余的每个 authenticator 调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。

      注: Authenticators 可能返回“用户取消了整个操作”的指示。用户代理如何向用户展示这一状态未在规范中规定。

    如果任何 authenticator 返回等同于 "InvalidStateError" 的错误状态,
    1. issuedRequests 中移除该 authenticator

    2. issuedRequests 中剩余的每个 authenticator 调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。

    3. 抛出一个 "InvalidStateError" DOMException

    注:该错误状态单独处理,因为 authenticator 仅在 excludeCredentialDescriptorList 标识出与该 authenticator 绑定的凭证并且用户已同意该操作时返回此错误。鉴于该明确同意,在该情况下向 Relying Party 区分该状态是可接受的。

    如果任何 authenticator 返回非等同于 "InvalidStateError" 的错误状态,

    issuedRequests 中移除该 authenticator

    注:此情况不表示对该操作存在 用户同意,因此错误详情对 Relying Party 隐藏,以防止泄露可能识别用户的信息。详情见 § 14.5.1 Registration Ceremony Privacy

    如果任何 authenticator 指示成功,
    1. issuedRequests 中移除该 authenticator。该认证器现在为 selected authenticator

    2. credentialCreationData 为一个 struct,其 items 如下:

      attestationObjectResult

      其值为成功的 authenticatorMakeCredential 操作返回的字节。

      注:该值为 attObj,如 § 6.5.4 生成 Attestation Object 所定义。

      clientDataJSONResult

      其值为 clientDataJSON 的字节。

      attestationConveyancePreferenceOption

      其值为 pkOptions.attestation 的值。

      clientExtensionResults

      其值为一个 AuthenticationExtensionsClientOutputs 对象,包含 extension identifierclient extension output 条目。条目由对每个 client extensionpkOptions.extensions 中的每个扩展运行其 client extension processing 算法以创建相应的 client extension outputs

    3. constructCredentialAlg 为一个算法,该算法接收一个 global object global,其步骤如下:

      1. 如果 credentialCreationData.attestationConveyancePreferenceOption 的值为:

        none

        用不具识别性的等价信息替换可能具有唯一识别性的字段:

        1. 如果 aaguidattested credential data 中为 16 个零字节, 且 credentialCreationData.attestationObjectResult.fmt 为 "packed",并且 "x5c" 未出现在 credentialCreationData.attestationObjectResult 中, 则说明正在使用 self attestation,并且无需进一步操作。

        2. 否则:

          1. credentialCreationData.attestationObjectResult.fmt 的值设为 "none",并将 credentialCreationData.attestationObjectResult.attStmt 设为一个空的 CBOR map。(参见 § 8.7 None Attestation Statement Format§ 6.5.4 生成 Attestation Object。)

        indirect

        客户端可以用更隐私友好且/或更易验证的等价数据替换 aaguidattestation statement(例如,使用 Anonymization CA)。

        directenterprise

        Relying Party 原样传递该 authenticatorAAGUIDattestation statement

      2. attestationObject 为一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建, 包含 credentialCreationData.attestationObjectResult 的字节值。

      3. idattestationObject.authData.attestedCredentialData.credentialId

      4. pubKeyCred 为一个新的 PublicKeyCredential 对象,该对象与 global 关联,其字段为:

        [[identifier]]

        id

        authenticatorAttachment

        与该 authenticator 当前的 authenticator attachment modality 相匹配的 AuthenticatorAttachment 值。

        response

        一个新的 AuthenticatorAttestationResponse 对象,与 global 关联,其字段为:

        clientDataJSON

        一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建, 包含 credentialCreationData.clientDataJSONResult 的字节。

        attestationObject

        attestationObject

        [[transports]]

        一个按字典序排列且唯一的零个或多个 DOMString 序列,表示该 authenticator 被认为支持的传输方式。该值应为 AuthenticatorTransport 的成员,但 client platforms 必须忽略未知值。

        如果用户代理不希望泄露该信息,则可以用一个旨在保护隐私的任意序列代替。该序列仍然必须有效,即按字典序排序且无重复。例如,可以使用空序列。无论哪种方式,在此情形下用户代理承担风险,即 Relying Party 的行为可能不理想。

        如果用户代理没有任何传输信息,应将该字段设置为空序列。

        注:用户代理如何发现给定 authenticator 支持的传输方式超出本规范范围,但可能包括来自 attestation certificate 的信息(例如 [FIDO-Transports-Ext]),在如 CTAP2 的认证器协议中传达的元数据,或关于 platform authenticators 的特殊情况知识。

        [[clientExtensionsResults]]

        一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建, 包含 credentialCreationData.clientExtensionResults 的字节。

      5. 返回 pubKeyCred

    4. issuedRequests 中其余的每个 authenticator 调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。

    5. 返回 constructCredentialAlg 并终止此算法。

  23. 抛出一个 "NotAllowedError" DOMException

在上述过程期间,用户代理应向用户展示一些 UI,以指导他们选择并授权认证器。当 options.mediation 被设置为 conditional 时, 应当避免显示显著的模态 UI,除非凭证创建已通过用户代理确定的方式先前获得同意。

5.1.3.1. Create Request Exceptions

本节非规范性。

WebAuthn Relying Parties 在调用 navigator.credentials.create() 时可能遇到若干异常。 有些异常可能有多种发生原因, 需要 WebAuthn Relying Parties 根据其对 WebAuthn 的使用来推断实际原因。

注:在处理任何 WebAuthn Extensions(包括在本规范之外定义的扩展)时可能抛出的异常不在此列出。

可以抛出以下 DOMException 异常:

AbortError

该流程被 AbortController 取消。参见 § 5.6 使用 AbortSignal 中止操作§ 1.3.4 中止认证操作

ConstraintError

要么 residentKey 被设置为 required 且没有可用的认证器支持常驻密钥, 要么 userVerification 被设置为 required 且没有可用的认证器能够执行 用户验证

InvalidStateError

在用户 同意 注册凭证之后,用于该流程的认证器识别到了 excludeCredentials 中的一个条目。

NotSupportedError

pubKeyCredParams 中没有条目的 type 属性为 public-key, 或者 认证器 不支持 pubKeyCredParams 指定的任何签名算法。

SecurityError

有效域 不是一个 有效域名, 或 rp.id 不等于也不是该 有效域 的可注册域名后缀。 在后一种情况下, 客户端 不支持 相关来源请求相关来源验证过程 失败。

NotAllowedError

一个涵盖多种可能原因的通用错误,包括常见的例如用户取消流程等原因。 其中一些原因在本规范中有说明,其他则为客户端特有。

可以抛出以下 simple exceptions

TypeError

options 参数不是一个有效的 CredentialCreationOptions 值, 或者 user.id 的值为空或超过 64 字节。

5.1.4. Use an Existing Credential to Make an Assertion

WebAuthn 服务方 调用 navigator.credentials.get({publicKey:..., ...}) 来发现并使用已有的 公钥凭证,并获得用户同意服务方 脚本可选择性地指定一些条件以表明其可接受的 公钥凭证来源客户端平台 定位与指定条件匹配的公钥凭证来源,并引导用户选择脚本被允许使用的一个。即使存在公钥凭证来源,用户也可能选择拒绝整个交互(例如为了保护隐私)。如果用户选择了一个公钥凭证来源,用户代理随后使用 § 6.3.3 The authenticatorGetAssertion Operation 对服务方提供的质询和其他收集的数据进行签名,生成认证断言,该断言被用作凭证

The navigator.credentials.get() 的实现 [CREDENTIAL-MANAGEMENT-1] 调用 PublicKeyCredential.[[CollectFromCredentialStore]]() 来收集任何在无需用户调解(大致相当于本规范的授权手势)即可用的凭证;如果没有恰好找到其中一个,则调用 PublicKeyCredential.[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 以让用户选择一个公钥凭证来源

由于本规范要求在创建任何断言时进行授权手势PublicKeyCredential 继承了 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors) 的默认行为,即返回空集合。 PublicKeyCredential[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 的实现详见下一节。

一般来说,用户代理应向用户显示一些用户界面,以指导其选择并授权用于完成操作的认证器。通过将 options.mediation 设置为 conditional服务方 可以指示除非发现凭证,否则不应显示显著的模态 UI。服务方应首先使用 isConditionalMediationAvailable()getClientCapabilities() 检查客户端是否支持 conditionalGet 能力,以防在该功能不可用时出现对用户可见的错误。

任何 navigator.credentials.get() 操作都可以通过使用 AbortController 来中止; 详见 DOM § 3.3 在 API 中使用 AbortController 和 AbortSignal 对象 以获取详细说明。

5.1.4.1. PublicKeyCredential’s [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) Internal Method

内部方法接受三个参数:

origin

该参数是由调用 get() 实现确定的相关设置对象(relevant settings object) 的 origin,即 CredentialsContainerRequest a Credential 抽象操作所确定的 origin。

options

该参数是一个 CredentialRequestOptions 对象,其 options.publicKey 成员包含一个 PublicKeyCredentialRequestOptions 对象,用于指定要发现的 public key credential 的期望属性。

sameOriginWithAncestors

该参数为布尔值,当且仅当调用者的 environment settings object 与其祖先同源(same-origin with its ancestors)时为 true。如果调用者为跨源,则为 false

注意: 调用此内部方法 表示该操作已被permissions policy 允许,该权限策略在 [CREDENTIAL-MANAGEMENT-1] 级别进行评估。参见 § 5.9 Permissions Policy integration

注意: 该算法为同步执行: Promise 的解析/拒绝由 navigator.credentials.get() 负责。

在此算法中使用的所有 BufferSource 对象必须在算法开始时进行快照,以避免潜在的同步问题。实现应当 获取缓冲源所持字节的副本 并在算法相关部分使用该副本。

当此方法被调用时,用户代理必须执行下列算法:

  1. 断言: options.publicKey 存在。

  2. pkOptionsoptions.publicKey 的值。

  3. 如果 options.mediation 存在且值为 conditional

    1. credentialIdFilterpkOptions.allowCredentials 的值。

    2. pkOptions.allowCredentials 设为

      注意: 这样可以防止在 conditional 请求期间使用 non-discoverable credentials

    3. 将定时器 lifetimeTimer 设为无穷大。

      注意:lifetimeTimer 设为无穷大,是为了让用户在整个 Document 的生命周期内与任何带有 "webauthn" autofill detail tokeninput 表单控件进行交互。例如,当用户点击此类输入字段时,用户代理可以渲染已发现凭证的列表供用户选择,并可能提供“尝试其他方式”的选项。

  4. 否则:

    1. credentialIdFilter 为一个 列表。

    2. 如果 pkOptions.timeout 存在,则检查其值是否在由 client 定义的合理范围内;若不在,则修正为最接近且位于该范围内的值。 将定时器 lifetimeTimer 设为此调整后值。如果 pkOptions.timeout 不存在,则将 lifetimeTimer 设为 client-特定的默认值。

      关于为 pkOptions.timeout 决定合理范围和值的指导,请参阅 推荐范围和默认值

      用户代理应在为有特殊需要的用户考虑超时时采用认知方面的指导原则。

  5. callerOriginorigin。 如果 callerOriginopaque origin,则抛出一个 "NotAllowedError" DOMException

  6. effectiveDomaincallerOrigineffective domain。 如果该 effective domain 不是一个 有效域名,则抛出一个 "SecurityError" DOMException

    注意: 一个 effective domain 可能解析为一个 host,而 host 可以以多种方式表示,例如 domainipv4 addressipv6 addressopaque hostempty host。 此处仅允许 domain 格式的表示。这样做既为简化,也考虑到在与基于 PKI 的安全结合使用时直接使用 IP 地址识别所带来的各种问题。

  7. 如果 pkOptions.rpId
    存在

    如果 pkOptions.rpId 不是 effectiveDomain 的可注册域后缀且与其不相等,且客户端支持:

    支持 related origin requests
    1. rpIdRequestedpkOptions.rpId 的值。

    2. 使用参数 callerOriginrpIdRequested 运行 related origins validation procedure。如果结果为 false,则抛出一个 "SecurityError" DOMException

    不支持 related origin requests

    抛出一个 "SecurityError" DOMException

    不存在

    pkOptions.rpId 设为 effectiveDomain

    注意: rpId 表示调用者的 RP ID。除非调用者在调用 get() 时明确设置了 pkOptions.rpId,否则 RP ID 默认为调用者的 origin 的 origineffective domain

  8. clientExtensions 为一个新的 map,并令 authenticatorExtensions 为一个新的 map

  9. 如果 pkOptions.extensions 存在,则对 pkOptions.extensions 中的每个 extensionIdclientExtensionInput 执行:

    1. 如果 extensionId 不被此 client platform 支持,或不是一个 authentication extension,则 继续下一个扩展

    2. Set clientExtensions[extensionId] 为 clientExtensionInput

    3. 如果 extensionId 不是一个 authenticator extension,则 继续下一个扩展

    4. authenticatorExtensionInput 为对 clientExtensionInput 运行该 extensionIdclient extension processing 算法后得到的(CBOR)结果。如果该算法返回错误,则 继续下一个扩展

    5. Set authenticatorExtensions[extensionId] 为 authenticatorExtensionInputbase64url 编码

  10. collectedClientData 为一个新的 CollectedClientData 实例,其字段为:

    type

    字符串 "webauthn.get"。

    challenge

    pkOptions.challengebase64url 编码

    origin

    callerOrigin序列化表示

    crossOrigin

    此值为传入此内部方法 的参数 sameOriginWithAncestors 的反值(inverse)。

    topOrigin

    如果传入的 sameOriginWithAncestors 参数为 false,则为 callerOrigin 的顶层 origin 的 序列化表示,否则为 undefined

  11. clientDataJSON 为由 collectedClientData 构造的 与 JSON 兼容的客户端数据序列化

  12. clientDataHash 为由 clientDataJSON 表示的序列化客户端数据的哈希,参见 说明

  13. 如果 options.signal 存在且 已中止(aborted),则抛出该 signal 的中止原因(abort reason)。

  14. issuedRequests 为一个新的 有序集合(ordered set)

  15. savedCredentialIds 为一个新的 map

  16. authenticators 表示一个值,该值在任一时刻为一个有序集合,其中每个标识在该时刻此 client platform 上当前可用的一个 authenticator 的本地句柄。

    注意: 何谓“可用的”认证器未作具体规定;这旨在表示认证器可以通过多种机制被热插拔(hot-plug,例如 USB)或被发现(例如 NFC 或蓝牙),或永久内置于客户端。

  17. silentlyDiscoveredCredentials 为一个新的 map,其 条目 形式为:DiscoverableCredentialMetadataauthenticator

  18. 根据 hints 的值并由用户代理酌情设计用户界面。

  19. 启动 lifetimeTimer

  20. lifetimeTimer 未到期时,基于 lifetimeTimer 以及 authenticators 中每个 authenticator 的状态与响应,执行下列操作:

    如果 lifetimeTimer 到期,

    issuedRequests 中的每个 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。

    如果用户在用户代理 UI 中选择取消该过程,

    issuedRequests 中的每个 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。抛出一个 "NotAllowedError" DOMException

    如果 options.signal 存在且 已中止

    issuedRequests 中的每个 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。然后抛出该 signal 的中止原因(abort reason)。

    如果 options.mediationconditional 且用户与带有 inputtextarea 表单控件交互, 且该控件具有 autocomplete 属性,其 non-autofill credential type"webauthn"
    注意: "webauthn"autofill detail token 必须紧接在最后一个类型为 "Normal" 或 "Contact" 的 autofill detail token 之后。例子:
    • "username webauthn"

    • "current-password webauthn"

    1. 如果 silentlyDiscoveredCredentials

      1. 提示用户可选地从 silentlyDiscoveredCredentials 中选择一个 DiscoverableCredentialMetadata。 提示应当展示每个 DiscoverableCredentialMetadata 的 otherUI 中的值,例如 namedisplayName

        credentialMetadata 为用户选择的 DiscoverableCredentialMetadata,如果用户有选择的话。

      2. 如果用户选择了一个 credentialMetadata

        1. publicKeyOptionspkOptions 的临时副本。

        2. authenticatorsilentlyDiscoveredCredentials[credentialMetadata] 的值。

        3. publicKeyOptions.allowCredentials 设置为只包含一个 PublicKeyCredentialDescriptor 列表, 其中该项的 id 的值设置为 credentialMetadataid 的值, 其 type 的值设置为 credentialMetadatatype

        4. authenticator 执行 issuing a credential request to an authenticator 算法,参数为 authenticatorsavedCredentialIdspublicKeyOptionsrpIdclientDataHashauthenticatorExtensions

          如果该调用返回 false,则 继续(跳过该认证器)。

        5. Append authenticatorissuedRequests

    如果 options.mediation 不是 conditional, 且 issuedRequests 为空, pkOptions.allowCredentials 非空, 且其中没有任何 authenticator 将可用于任何其中列出的 public key credentials

    向用户指示未找到合格凭证。当用户确认对话框后,抛出一个 "NotAllowedError" DOMException

    注意: 客户端平台可以通过检查当前 pkOptions.allowCredentials 中每个 PublicKeyCredentialDescriptor 项的 transports 成员来判断没有认证器会变得可用。例如,如果所有 PublicKeyCredentialDescriptor 项仅列出 internal,但所有平台认证器(platform authenticators)都已被尝试,则不存在满足请求的可能性。或者,所有 PublicKeyCredentialDescriptor 项可能列出了客户端平台不支持的 transports

    如果某个 authenticator 在此 client device 上变为可用,

    注意: 这也包括在启动 lifetimeTimer 时认证器已可用的情况。

    1. 如果 options.mediationconditional 且该 authenticator 支持 silentCredentialDiscovery 操作:

      1. collectedDiscoveredCredentialMetadata 为对该 authenticator 执行 silentCredentialDiscovery 操作(以 rpId 为参数) 的结果。

      2. collectedDiscoveredCredentialMetadata 中的每个 credentialMetadata

        1. 如果 credentialIdFilter 为空 或者 credentialIdFilter 包含一个项,其 id 的值等于 credentialMetadataid,则将 silentlyDiscoveredCredentials[credentialMetadata] 设为 authenticator

          注意: 在用户通过特定 UI 上的交互选择凭证时,将向该认证器发出请求(详见上文相关部分)。

    2. 否则:

      1. 执行 issuing a credential request to an authenticator 算法,参数为 authenticatorsavedCredentialIdspkOptionsrpIdclientDataHashauthenticatorExtensions

        如果该调用返回 false,则 继续(跳过该认证器)。

        注意: 如果 options.mediationconditional 且该 authenticator 不支持 silentCredentialDiscovery,则会走到此分支以允许在 conditionaluser mediation 请求中使用此类认证器。

      2. Append authenticatorissuedRequests

    如果某个 authenticator 在此 client device 上不再可用,

    issuedRequests移除authenticator

    如果任何 authenticator 返回表示用户取消操作的状态,
    1. issuedRequests移除authenticator

    2. issuedRequests 中的每个剩余 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。

      注意: 认证器可能返回“用户取消了整个操作”的指示,用户代理如何向用户呈现该状态未作规定。

    如果任何 authenticator 返回错误状态,

    issuedRequests移除authenticator

    如果任何 authenticator 指示成功,
    1. issuedRequests移除authenticator

    2. assertionCreationData 为一个 struct,其 items 如下:

      credentialIdResult

      如果 savedCredentialIds[authenticator] 存在,则将 credentialIdResult 的值设为 savedCredentialIds[authenticator] 的字节。否则,将其值设为在成功的 authenticatorGetAssertion 操作中返回的 credential ID 的字节(详见 § 6.3.3)。

      clientDataJSONResult

      其值为 clientDataJSON 的字节。

      authenticatorDataResult

      其值为该 authenticator 返回的 authenticator data 的字节。

      signatureResult

      其值为该 authenticator 返回的签名值的字节。

      userHandleResult

      如果该 authenticator 返回了 user handle,则将 userHandleResult 的值设为返回的 user handle 的字节。否则,将其设为 null。

      clientExtensionResults

      其值为一个 AuthenticationExtensionsClientOutputs 对象,包含 扩展标识符客户端扩展输出 的条目。这些条目是对 pkOptions.extensions 中的每个客户端扩展运行其 client extension processing 算法以创建对应的客户端扩展输出而生成的。

    3. 如果 credentialIdFilter 非空且 credentialIdFilter 不包含一个项,其 id 的值等于 credentialIdResult 的值,则 继续(跳过该认证器)。

    4. 如果 credentialIdFilter 为空且 userHandleResult 为 null,则 继续(跳过该认证器)。

    5. settings 为当前的 settings object。令 globalsettingsglobal object

    6. pubKeyCred 为与 global 关联的新 PublicKeyCredential 对象,其字段为:

      [[identifier]]

      一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建,包含 assertionCreationData.credentialIdResult 的字节。

      authenticatorAttachment

      与该 authenticator 当前 attachment modality 相匹配的 AuthenticatorAttachment 值。

      response

      一个新的与 global 关联的 AuthenticatorAssertionResponse 对象,其字段为:

      clientDataJSON

      一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建,包含 assertionCreationData.clientDataJSONResult 的字节。

      authenticatorData

      一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建,包含 assertionCreationData.authenticatorDataResult 的字节。

      signature

      一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建,包含 assertionCreationData.signatureResult 的字节。

      userHandle

      如果 assertionCreationData.userHandleResult 为 null,则将此字段设为 null。否则,将此字段设为一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建,包含 assertionCreationData.userHandleResult 的字节。

      [[clientExtensionsResults]]

      一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 创建,包含 assertionCreationData.clientExtensionResults 的字节。

    7. issuedRequests 中的每个剩余 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。

    8. 返回 pubKeyCred 并终止该算法。

  21. 抛出一个 "NotAllowedError" DOMException

5.1.4.2. 向 Authenticator 发出凭证请求

此子算法属于 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors), 包含了在给定的 credential 请求中,针对特定但与 UI 上下文无关的步骤,这些步骤用于向某个指定的 authenticator 请求凭证,所使用的是给定的 PublicKeyCredentialRequestOptions。 它由 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 从不同点调用,具体取决于当前的 user mediation(例如:conditional mediation)的限制。

此算法接受下列参数:

authenticator

一个特定于 client platform 的句柄,用于标识当前在该 client platform 上可用的某个 authenticator

savedCredentialIds

一个 map,其中包含 authenticatorcredential ID 的映射。此参数将在本算法中被修改。

pkOptions

该参数是一个 PublicKeyCredentialRequestOptions 对象,用以指定要发现的 public key credential 的期望属性。

rpId

请求的 RP ID

clientDataHash

clientDataJSON 表示的序列化客户端数据的哈希,参见 说明

authenticatorExtensions

一个 map,其中包含 extension identifiersbase64url 编码 的映射, 这些值是为 authenticator extensions 产生的 client extension processing 输出的编码结果。

如果 client 判定该 authenticator 无法处理该请求,则此算法返回 false;如果请求成功下发,则返回 true

下列为 向 Authenticator 发出凭证请求 的步骤:

  1. 如果 pkOptions.userVerification 被设置为 required 且该 authenticator 无法执行 user verification,则返回 false

  2. userVerification用于断言的有效用户验证要求,这是一个布尔值,按如下规则决定。如果 pkOptions.userVerification

    被设为 required

    userVerificationtrue

    被设为 preferred

    如果该 authenticator

    能够执行 user verification

    userVerificationtrue

    不能执行 user verification

    userVerificationfalse

    被设为 discouraged

    userVerificationfalse

  3. 如果 pkOptions.allowCredentials

    不为空
    1. allowCredentialDescriptorList 为一个新的 列表

    2. 执行一个 client platform 专用的过程,以决定 pkOptions.allowCredentials 所描述的哪些(如果有)public key credentials 是绑定(bound)到当前 authenticator 的,通过匹配 rpIdpkOptions.allowCredentials.idpkOptions.allowCredentials.type。 将 allowCredentialDescriptorList 设为此过滤后的列表。

    3. 如果 allowCredentialDescriptorList 为空,则返回 false

    4. distinctTransports 为一个新的 有序集合

    5. 如果 allowCredentialDescriptorList 恰好只有一个值,则将 savedCredentialIds[authenticator] 设为 allowCredentialDescriptorList[0].id 的值(详见 此处,见 § 6.3.3)。

    6. 对于 allowCredentialDescriptorList 中的每个凭证描述符 C追加 C.transports 中的每个值(如果有)到 distinctTransports

      注意: 由于 有序集合 的特性,这将仅聚合该 authenticator 的不同 transports 值到 distinctTransports 中。

    7. 如果 distinctTransports

      不为空

      客户端从 distinctTransports 中选择一个 transport 值,选择时可能结合本地关于与该 authenticator 配合使用的适当传输的配置知识。

      然后,使用所选的 transport,对该 authenticator 调用 authenticatorGetAssertion 操作,参数为 rpIdclientDataHashallowCredentialDescriptorListuserVerificationauthenticatorExtensions

      为空

      使用关于应与该 authenticator 配合使用的适当传输的本地配置知识,对该 authenticator 调用 authenticatorGetAssertion 操作,参数为 rpIdclientDataHashallowCredentialDescriptorListuserVerificationauthenticatorExtensions

    为空

    使用关于应与该 authenticator 配合使用的适当传输的本地配置知识,对该 authenticator 调用 authenticatorGetAssertion 操作,参数为 rpIdclientDataHashuserVerificationauthenticatorExtensions

    注意: 在此情形下,Relying Party 未提供可接受的凭证描述符列表。因此,authenticator 被要求使用其可能拥有的、并且作用域(scoped)到该 Relying Party(由 rpId 标识)的任何凭证。

  4. 返回 true

5.1.4.3. Get Request Exceptions

本节不具备规范性。

WebAuthn Relying Party 在调用 navigator.credentials.get() 时可能会遇到多种异常。 有些异常可能因多种原因发生, 需要 WebAuthn Relying Party 根据自身 WebAuthn 使用情况推断实际原因。

注意:任何 WebAuthn 拓展处理过程中可能抛出的异常(包括规范外定义的拓展),此处未列出。

可能抛出的 DOMException 异常包括:

AbortError

流程被 AbortController 取消。 参见 § 5.6 使用 AbortSignal 中断操作§ 1.3.4 中断认证操作

SecurityError

有效域名不是有效域名, 或者 rp.id 不等于或不是 有效域名的可注册域名后缀。 后者情况下, 客户端不支持相关域请求相关域名校验流程失败。

NotAllowedError

一种包含多种可能原因的兜底错误, 包括像用户取消流程这样常见的情况。 其中一些原因在规范中有说明, 其他则取决于具体客户端。

可能抛出的 简单异常包括:

TypeError

options 参数不是有效的 CredentialRequestOptions 值。

5.1.5. 存储现有凭证 - PublicKeyCredential 的 [[Store]](credential, sameOriginWithAncestors) 内部方法

对于 Web Authentication 的 PublicKeyCredential 类型,[[Store]](credential, sameOriginWithAncestors) 方法不受支持,因此其实现的 [[Store]](credential, sameOriginWithAncestors) 内部方法 总是抛出错误。

注意: 此算法为同步执行;Promise 的解析/拒绝由 navigator.credentials.store() 处理。

内部方法接受两个参数:

credential

此参数为一个 PublicKeyCredential 对象。

sameOriginWithAncestors

此参数为布尔值,当且仅当调用者的 environment settings object 与其祖先同源(same-origin with its ancestors)时为 true

当此方法被调用时,用户代理必须执行下列算法:

  1. 抛出一个 "NotSupportedError" DOMException

5.1.6. User-Verifying Platform Authenticator 的可用性 - PublicKeyCredential 的 isUserVerifyingPlatformAuthenticatorAvailable() 方法

WebAuthn Relying Parties 使用此方法来判断是否可以使用 user-verifying platform authenticator 来创建新凭证。 在调用时,client 将通过特定于 client platform 的过程去发现可用的 user-verifying platform authenticators。 如果发现了任一此类设备,则返回的 promise 会以 true 解析,否则以 false 解析。 基于该结果,Relying Party 可采取进一步措施引导用户创建凭证。

此方法无参数,返回一个布尔值。

partial interface PublicKeyCredential {
    static Promise<boolean> isUserVerifyingPlatformAuthenticatorAvailable();
};

5.1.7. Client 能力的可用性 - PublicKeyCredential 的 getClientCapabilities() 方法

WebAuthn Relying Parties 使用此方法来判断一组有限的 client 能力是否可用,从而为用户提供某些工作流或体验。例如,在某些客户端上仅当存在 hybrid 传输可用或 conditional mediation 不可用时(而不是显示用户名字段),RP 可能会在页面上提供一个登录按钮。

在调用时,client 通过特定于 client platform 的过程来发现这些能力的可用性。

此方法无参数,返回一个将能力键映射到布尔值的记录(record)。

partial interface PublicKeyCredential {
    static Promise<PublicKeyCredentialClientCapabilities> getClientCapabilities();
};

typedef record<DOMString, boolean> PublicKeyCredentialClientCapabilities;

PublicKeyCredentialClientCapabilities 中的键(Keys)必须按升序字典序排序。 键集合应包含 枚举值 集合(即 ClientCapability 的值),但客户端可按需省略某些键;见 § 14.5.4 披露客户端能力

当某项能力的值为 true 时,表示该功能已知当前被客户端支持。 当某项能力的值为 false 时,表示该功能已知当前不被客户端支持。 当某项能力作为键不存在时,该客户端功能的可用性未知(unknown)。

该键集合还应为客户端实现的每个扩展包含一个键,键的形式为在扩展标识符前加上字符串 extension:。对于每个实现的扩展,其对应值应为 true。如果某个客户端支持 getClientCapabilities(),但未将某扩展映射为 true,则 Relying Party 可以假定该客户端不会执行该扩展的客户端处理步骤,并且该扩展可能不会转发给 authenticator。

注意即便某扩展映射为 true,用于某次操作的 authenticator 也可能不支持该扩展,因此 Relying Parties 不得仅据此假定 authenticator 会执行该扩展的处理步骤。

5.1.8. 反序列化注册流程选项 - PublicKeyCredential 的 parseCreationOptionsFromJSON() 方法

WebAuthn Relying Party 使用此方法将 JSON 类型 表示的 navigator.credentials.create() 的选项 转换为 PublicKeyCredentialCreationOptions

此方法调用时,客户端 必须将 options 参数转换为新的、结构相同的 PublicKeyCredentialCreationOptions 对象,使用 base64url 编码 解码 DOMString 属性,这些属性在 PublicKeyCredentialCreationOptionsJSON 中对应 buffer source type 属性,在 PublicKeyCredentialCreationOptions 中也有。 此转换也必须应用于 客户端扩展输入,由 客户端处理。

AuthenticationExtensionsClientInputsJSON 可以包含 IANA 注册表 "WebAuthn Extension Identifiers" 中已注册但未在 § 9 WebAuthn Extensions定义的扩展。

如果 客户端 解析任何 JSON 类型 表示时遇到问题, 必须抛出 "EncodingError" DOMException ,并在描述中说明不兼容的值,并终止操作。

partial interface PublicKeyCredential {
    static PublicKeyCredentialCreationOptions parseCreationOptionsFromJSON(PublicKeyCredentialCreationOptionsJSON options);
};

dictionary PublicKeyCredentialCreationOptionsJSON {
    required PublicKeyCredentialRpEntity                    rp;
    required PublicKeyCredentialUserEntityJSON              user;
    required Base64URLString                                challenge;
    required sequence<PublicKeyCredentialParameters>        pubKeyCredParams;
    unsigned long                                           timeout;
    sequence<PublicKeyCredentialDescriptorJSON>             excludeCredentials = [];
    AuthenticatorSelectionCriteria                          authenticatorSelection;
    sequence<DOMString>                                     hints = [];
    DOMString                                               attestation = "none";
    sequence<DOMString>                                     attestationFormats = [];
    AuthenticationExtensionsClientInputsJSON                extensions;
};

dictionary PublicKeyCredentialUserEntityJSON {
    required Base64URLString        id;
    required DOMString              name;
    required DOMString              displayName;
};

dictionary PublicKeyCredentialDescriptorJSON {
    required DOMString              type;
    required Base64URLString        id;
    sequence<DOMString>             transports;
};

dictionary AuthenticationExtensionsClientInputsJSON {
};

5.1.9. 反序列化认证流程选项 - PublicKeyCredential 的 parseRequestOptionsFromJSON() 方法

WebAuthn Relying Parties 使用此方法将用于 navigator.credentials.get() 的选项的 JSON 表示转换为 PublicKeyCredentialRequestOptions

在调用时,client 必须将 options 参数转换为一个新的、结构相同的 PublicKeyCredentialRequestOptions 对象, 并使用 base64url 编码 解码出现在 DOMString 属性中对应于 PublicKeyCredentialRequestOptionsJSON 的那些值,这些值对应于 PublicKeyCredentialRequestOptions 中的 buffer source 类型属性。 该转换也必须应用于任何由 client extension inputs 所处理的扩展。

AuthenticationExtensionsClientInputsJSON 可能包括在 IANA “WebAuthn Extension Identifiers” 注册表中注册但未在本规范(§ 9 WebAuthn Extensions)中定义的扩展。

如果 client 在解析任何 JSON 表示时遇到问题,则必须抛出一个 "EncodingError" 的 DOMException,并附带不兼容值的描述,然后终止操作。

partial interface PublicKeyCredential {
    static PublicKeyCredentialRequestOptions parseRequestOptionsFromJSON(PublicKeyCredentialRequestOptionsJSON options);
};

dictionary PublicKeyCredentialRequestOptionsJSON {
    required Base64URLString                                challenge;
    unsigned long                                           timeout;
    DOMString                                               rpId;
    sequence<PublicKeyCredentialDescriptorJSON>             allowCredentials = [];
    DOMString                                               userVerification = "preferred";
    sequence<DOMString>                                     hints = [];
    AuthenticationExtensionsClientInputsJSON                extensions;
};

5.1.10. 向 Authenticator 发出凭证变更信号 - PublicKeyCredential 的 signal methods

partial interface PublicKeyCredential {
    static Promise<undefined> signalUnknownCredential(UnknownCredentialOptions options);
    static Promise<undefined> signalAllAcceptedCredentials(AllAcceptedCredentialsOptions options);
    static Promise<undefined> signalCurrentUserDetails(CurrentUserDetailsOptions options);
};

dictionary UnknownCredentialOptions {
    required DOMString                     rpId;
    required Base64URLString               credentialId;
};

dictionary AllAcceptedCredentialsOptions {
    required DOMString                     rpId;
    required Base64URLString               userId;
    required sequence<Base64URLString>     allAcceptedCredentialIds;
};

dictionary CurrentUserDetailsOptions {
    required DOMString                     rpId;
    required Base64URLString               userId;
    required DOMString                     name;
    required DOMString                     displayName;
};

WebAuthn Relying Parties 可以使用这些 signal methods 去通知 authenticators 有关 public key credentials 的状态,以便不正确或已撤销的凭证可以被更新、移除或隐藏。Clients 根据机会提供该功能,因为 authenticator 可能不支持更新其 credentials map,或者在请求发出时并未连接。此外,为避免在未取得 用户同意 的情况下泄露有关用户凭证的信息,signal methods 不会指示操作是否成功。一个成功解析的 promise 仅表示 options 对象格式正确。

每个 signal method 包含 authenticator actionsAuthenticators 可以在其 authenticator actions 上与本规范偏离,例如忽略某些它合理地认为与用户意愿相悖的更改,或在做出某些更改前询问用户。因此,Authenticator actions 被作为处理 signal methods 的推荐方式。

在某些情况下,如果某个 authenticator 无能力处理某项 authenticator actionclients 可以选择使用现有基础设施(例如 [FIDO-CTAP]authenticatorCredentialManagement 命令)来实现等效效果。

注意: Signal methods 故意避免等待 authenticators 完成执行 authenticator actions。此举旨在防止 WebAuthn Relying Parties 依据请求的时间信息在未取得 用户同意 的情况下得知其凭证是否可用,从而泄露隐私。

5.1.10.1. 异步 RP ID 验证算法

异步 RP ID 验证算法 允许 signal methods 并行地验证 RP IDs。该算法接受一个 DOMString 参数 rpId 并返回一个 promise;如果验证失败则该 promise 被拒绝。步骤如下:

  1. effectiveDomain相关设置对象origin有效域名。如果 effectiveDomain 不是有效域名,则返回一个被拒绝的 promise ,错误为 "SecurityError" DOMException

  2. 如果 rpId effectiveDomain 的可注册域名后缀或相等,则返回一个被解析的 promise,值为 undefined。

  3. 如果客户端不支持相关 origin 请求,则返回一个被拒绝的 promise,错误为"SecurityError" DOMException

  4. p一个新的 promise

  5. 以下步骤并行执行

    1. 如果以 callerOriginrpId 作为参数运行相关 origin 验证流程的结果为 true,则解析 p

    2. 否则,使用"SecurityError" DOMException拒绝 p

  6. 返回 p

5.1.10.2. signalUnknownCredential(options)

signalUnknownCredential 方法用于向 WebAuthn Relying Party 发出某个 credential id 未被识别的信号,例如因为该凭证被用户删除。与 signalAllAcceptedCredentials(options) 不同,此方法不需要传递整个被接受的 credential IDs 列表及 userHandle,从而避免向未认证的调用者泄露隐私(参见 § 14.6.3 通过 credential IDs 的隐私泄露)。

在调用 signalUnknownCredential(options) 时, client 执行下列步骤:

  1. 如果对 options.credentialId 进行 base64url 解码 的结果是错误,则返回以一个 TypeError 为原因被拒绝的 promise。

  2. p 为以 options.rpId 为参数执行 异步 RP ID 验证算法 的结果。

  3. p 成功后,按并行方式运行下列步骤:

    1. 对当前在该 client platform 上可用的每个 authenticator,调用 unknownCredentialId authenticator action,并以 options 作为输入。

  4. 返回 p

unknownCredentialId authenticator action 接受一个 UnknownCredentialOptions options 并按如下进行:

  1. authenticatorcredential map 中的每个 public key credential source credential

    1. 如果该 credentialrpId 等于 options.rpId 并且该 credentialid 等于对 options.credentialId 进行的 base64url 解码 的结果, 则从该 credentials map移除credential,或使用某个 authenticator-专用的过程将其隐藏以防止其在将来的 authentication ceremonies 中出现。

用户在凭据WebAuthn 依赖方提供的界面上删除了凭据。之后,当尝试使用WebAuthn 依赖方进行身份验证,且allowCredentials时, 认证器界面提供了他们之前删除的凭据作为选项。用户选择了该凭据。在拒绝本次登录尝试后,WebAuthn 依赖方执行如下操作:

PublicKeyCredential.signalUnknownCredential({
    rpId: "example.com",
    credentialId: "aabbcc"  // credential id the user just tried, base64url
});

然后 authenticator 将该 credential 从将来的 authentication ceremonies 中删除或隐藏。

5.1.10.3. signalAllAcceptedCredentials(options)

为给定用户发出其全部 credential ids 列表的信号。WebAuthn Relying Parties 应在用户已完成身份验证且不存在隐私泄露风险时,优先使用此方法而非 signalUnknownCredential()(参见 § 14.6.3 通过 credential IDs 的隐私泄露),因为该列表提供了用户的公钥凭证的完整快照,且可能反映尚未报告给当前已连接 authenticator 的更改。

在调用 signalAllAcceptedCredentials(options) 时, client 执行下列步骤:

  1. 如果对 options.userId 进行 base64url 解码 的结果是错误,则返回以 TypeError 为原因被拒绝的 promise。

  2. 对于 options.allAcceptedCredentialIds 中的每个 credentialId

    1. 如果对该 credentialId 进行 base64url 解码 的结果是错误,则返回以 TypeError 为原因被拒绝的 promise。

  3. p 为以 options.rpId 为参数执行 异步 RP ID 验证算法 的结果。

  4. p 成功后,并行运行下列步骤:

    1. 对当前在该 client platform 上可用的每个 authenticator,调用 allAcceptedCredentialIds authenticator action,并以 options 作为输入。

  5. 返回 p

名为 allAcceptedCredentialIdsauthenticator actions 接受一个 AllAcceptedCredentialsOptions options,其步骤如下:

  1. userId base64url 解码 options.userId 的结果。

  2. 断言:userId 不是错误。

  3. credentialcredentials map[options.rpId, userId].

  4. 如果 credential 不存在,则中止这些步骤。

  5. 如果 options.allAcceptedCredentialIds包含credentialid 进行 base64url 编码 后的结果,则 credentials map 中移除 credential,或采用特定于 authenticator 的程序,将其在未来的 认证仪式 中隐藏。

  6. 否则,如果 credential 已被特定于 authenticator 的程序隐藏,则撤销该操作,使 credential 在未来的 认证仪式 中可用。

某用户有两个凭证,其 credential ids base64url 编码后为 aabb。用户在 WebAuthn Relying Party 提供的 UI 上删除了凭证 aa。该 WebAuthn Relying Party 运行:

PublicKeyCredential.signalAllAcceptedCredentials({
    rpId: "example.com",
    userId: "aabbcc",  // user handle, base64url.
    allAcceptedCredentialIds: [
        "bb",
    ]
});

如果该 authenticator 在执行时已连接,它会删除或隐藏对应于 aacredential,以免其在将来的认证流程中出现。

注意: 在调用 signalAllAcceptedCredentials(options) 时,Authenticators 可能未连接。因此,WebAuthn Relying Parties 可能选择周期性地运行 signalAllAcceptedCredentials(options),例如在每次登录时。

注意: 未包含在 allAcceptedCredentialIds 中的凭证将被移除或隐藏,可能是不可逆的。Relying parties 必须谨慎,确保有效的凭证 ID 永远不会被遗漏。如果某个有效的 credential ID 被意外遗漏,Relying Party 应尽快在下次有机会时通过 signalAllAcceptedCredentials(options) 将其包含回列表中,以便在 authenticator 支持的情况下将其“取消隐藏”。

Authenticators 应尽可能选择将公钥凭证在一段时间内隐藏,而不是永久删除,以便在 WebAuthn Relying Party 意外遗漏有效的 credential IDs 时便于恢复。

5.1.10.4. signalCurrentUserDetails(options)

signalCurrentUserDetails 方法用于发出用户当前的 namedisplayName 的信号。

在调用 signalCurrentUserDetails(options) 时, client 执行下列步骤:

  1. 如果对 options.userId 进行 base64url 解码 的结果为错误,则返回以 TypeError 为原因被拒绝的 promise。

  2. p 为以 options.rpId 为参数执行 异步 RP ID 验证算法 的结果。

  3. p 成功后,并行运行下列步骤:

    1. 对当前在该 client platform 上可用的每个 authenticator,调用 currentUserDetails authenticator action,并以 options 作为输入。

  4. 返回 p

名为 currentUserDetailsauthenticator action 接受一个 CurrentUserDetailsOptions options,其步骤如下:

  1. userId 为对 options.userId 进行的 base64url 解码 的结果。

  2. 断言:userId 不是错误。

  3. credentialcredentials map[options.rpId, userId]

  4. 如果 credential 不存在,则中止这些步骤。

  5. 将该 credentialotherUI 更新为与 options.nameoptions.displayName 相匹配的值。

用户在 WebAuthn Relying Party 提供的 UI 上更新了其姓名。该 WebAuthn Relying Party 运行:

PublicKeyCredential.signalCurrentUserDetails({
    rpId: "example.com",
    userId: "aabbcc",  // user handle, base64url.
    name: "New user name",
    displayName: "New display name",
});

然后 authenticator 更新匹配凭证的 otherUI 信息。

注意: Authenticators 可能在执行 signalCurrentUserDetails(options) 时未连接。因此,WebAuthn Relying Parties 可能选择定期运行 signalCurrentUserDetails(options),例如在每次登录时。

5.2. Authenticator Responses (interface AuthenticatorResponse)

认证器 通过返回一个派生自 AuthenticatorResponse 接口的对象来响应 Relying Party 的请求:

[SecureContext, Exposed=Window]
interface AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      clientDataJSON;
};
clientDataJSON, of type ArrayBuffer, readonly

该属性包含了 与 JSON 兼容的序列化客户端数据,其 哈希值 由客户端在调用 create()get() 时传递给认证器(即客户端数据本身并不直接发送给认证器)。

5.2.1. Information About Public Key Credential (interface AuthenticatorAttestationResponse)

The AuthenticatorAttestationResponse 接口表示认证器对客户端请求创建新 公钥凭证 的响应。它包含有关新凭证的信息,这些信息可用于 在以后识别该凭证,并且包含用于让 WebAuthn 依赖方 在注册期间评估该凭证特性的元数据。

[SecureContext, Exposed=Window]
interface AuthenticatorAttestationResponse : AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      attestationObject;
    sequence<DOMString>                              getTransports();
    ArrayBuffer                                      getAuthenticatorData();
    ArrayBuffer?                                     getPublicKey();
    COSEAlgorithmIdentifier                          getPublicKeyAlgorithm();
};
clientDataJSON

该属性继承自 AuthenticatorResponse, 包含了传递给认证器以生成该凭证的 与 JSON 兼容的客户端数据序列化(见 § 6.5 Attestation)。 必须保留精确的 JSON 序列化形式,因为对序列化的客户端数据所计算的 哈希 就是基于该序列化结果计算的。

attestationObject, of type ArrayBuffer, readonly

该属性包含一个 attestation object,其对客户端是不透明的,并受到加密保护以防客户端篡改。attestation object 同时包含 authenticator data 和一个 attestation statement。 前者包含 AAGUID、唯一的 credential ID 以及 credential public keyattestation statement 的内容由认证器使用的 attestation statement format 决定。 它还包含了 Relying Party 的服务器在验证 attestation statement 时所需的任何额外信息,以及用于解码和验证 authenticator data 与客户端数据的 JSON 兼容序列化 的信息。更多细节见 § 6.5 Attestation§ 6.5.4 Generating an Attestation Object图 6

getTransports()

此操作返回 [[transports]] 的值。

getAuthenticatorData()

此操作返回包含在 attestationObject 中的 authenticator data。参见 § 5.2.1.1 Easily accessing credential data

getPublicKey()

此操作返回新凭证的 DER 格式的 SubjectPublicKeyInfo,如果不可用则返回 null。参见 § 5.2.1.1 Easily accessing credential data

getPublicKeyAlgorithm()

此操作返回新凭证的 COSEAlgorithmIdentifier。参见 § 5.2.1.1 Easily accessing credential data

[[transports]]

内部槽 包含按字典序排列的零个或多个唯一 DOMString。这些值表示认为认证器支持的传输方式,若信息不可用则为一个空序列。值应当是 AuthenticatorTransport 的成员,但 Relying Parties 应接受并存储未知值。

5.2.1.1. Easily accessing credential data

每个使用 [[Create]](origin, options, sameOriginWithAncestors) 方法的用户都需要解析并存储返回的 credential public key,以便验证将来的 authentication assertions。然而,credential public key 采用 COSE 格式(见 [RFC9052]),位于 credentialPublicKey 成员中,该成员属 attestedCredentialData,而 attestedCredentialData 位于 authenticator data 内,进而位于 attestation object(由 AuthenticatorAttestationResponse 传递) 的 attestationObject 中。 希望使用 attestationRelying Parties 必须自己解析 attestationObject 并取得 credential public key,因为该公钥副本就是认证器所签名的。然而,许多有效的 WebAuthn 用例并不需要 attestation。对于这些用例,用户代理可以完成解析工作,直接暴露 authenticator data,并将 credential public key 转换为更便于使用的格式。

因此,getPublicKey() 操作返回 credential public keySubjectPublicKeyInfo。该 ArrayBuffer 例如可以传递给 Java 的 java.security.spec.X509EncodedKeySpec、.NET 的 System.Security.Cryptography.ECDsa.ImportSubjectPublicKeyInfo 或 Go 的 crypto/x509.ParsePKIXPublicKey

使用 getPublicKey() 会带来一些限制:通过使用 pubKeyCredParams, Relying Party 可以与 authenticator 协商使用用户代理可能不理解的公钥算法。然而,如果 Relying Party 这样做,用户代理将无法把得到的 credential public key 转换为 SubjectPublicKeyInfo 格式,此时 getPublicKey() 的返回值将为 null。

credential public keyCOSEAlgorithmIdentifier 值为下列之一时,用户代理必须能够为 getPublicKey() 返回非空值:

一个 SubjectPublicKeyInfo 并不包含关于签名算法(例如应使用哪种哈希函数)的信息,而这些信息在 COSE 公钥中包含。为了解决这个问题,getPublicKeyAlgorithm() 返回该 credential public key 所对应的 COSEAlgorithmIdentifier

为了在许多情况下无需解析 CBOR,getAuthenticatorData() 返回 attestationObject 中的 authenticator dataauthenticator data 包含其他以二进制格式编码的字段。但没有提供访问这些子字段的辅助函数,因为 Relying Parties 在获取断言(getting an assertion)时就已经需要提取这些字段。与凭证创建(credential creation)中签名验证为可选不同,Relying Parties 在断言中应始终验证签名,因此必须从签名的 authenticator data 中提取字段。用于那里的相同函数也会在凭证创建期间使用。

Relying Parties 在使用这些函数之前应做功能检测,方法是测试 'getPublicKey' in AuthenticatorAttestationResponse.prototype 的值。

注意: getPublicKey()getAuthenticatorData() 仅在本规范的 Level 2 中新增。依赖这些函数存在的 Relying Parties 可能无法与较旧的用户代理互操作。

5.2.2. Web Authentication Assertion (interface AuthenticatorAssertionResponse)

The AuthenticatorAssertionResponse 接口表示认证器对客户端请求生成新的 authentication assertion 的响应,基于 WebAuthn 依赖方 的 challenge 以及可选的已知凭证列表。该响应包含一个证明持有 credential private key 的加密签名,并可选地包含对特定事务的 用户同意 的证据。

[SecureContext, Exposed=Window]
interface AuthenticatorAssertionResponse : AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      authenticatorData;
    [SameObject] readonly attribute ArrayBuffer      signature;
    [SameObject] readonly attribute ArrayBuffer?     userHandle;
};
clientDataJSON

该属性继承自 AuthenticatorResponse, 包含了传递给认证器以生成该断言的 与 JSON 兼容的客户端数据序列化(见 § 5.8.1 Client Data Used in WebAuthn Signatures (dictionary CollectedClientData))。 必须保留精确的 JSON 序列化形式,因为对序列化的客户端数据所计算的 哈希 就是基于该序列化结果计算的。

authenticatorData, of type ArrayBuffer, readonly

该属性包含认证器返回的 authenticator data。参见 § 6.1 Authenticator Data

signature, of type ArrayBuffer, readonly

该属性包含认证器返回的原始签名。参见 § 6.3.3 The authenticatorGetAssertion Operation

userHandle, of type ArrayBuffer, readonly, nullable

该属性包含认证器返回的 user handle,如果认证器未返回 user handle,则为 null。参见 § 6.3.3 The authenticatorGetAssertion Operation。如果在 authentication ceremony 中使用的 allowCredentials 选项为空列表(empty),则认证器必须始终返回一个 user handle;在其他情况下认证器可以选择返回或不返回。

5.3. Parameters for Credential Generation (dictionary PublicKeyCredentialParameters)

dictionary PublicKeyCredentialParameters {
    required DOMString                    type;
    required COSEAlgorithmIdentifier      alg;
};
该字典用于在创建新凭证时提供额外参数。
type, of type DOMString

该成员指定将被创建的凭证类型。其值应当是 PublicKeyCredentialType 的成员,但 client platforms 必须忽略未知值,忽略任何具有未知 typePublicKeyCredentialParameters

alg, of type COSEAlgorithmIdentifier

该成员指定用于新生成凭证的加密签名算法类型,从而也决定要生成的非对称密钥对的类型,例如 RSA 或 椭圆曲线。

注意: 我们使用 "alg" 作为成员名,而不是完整拼写 "algorithm",是因为它会被序列化到发往认证器的消息中,该消息可能通过低带宽链路发送。

5.4. Options for Credential Creation (dictionary PublicKeyCredentialCreationOptions)

dictionary PublicKeyCredentialCreationOptions {
    required PublicKeyCredentialRpEntity         rp;
    required PublicKeyCredentialUserEntity       user;

    required BufferSource                             challenge;
    required sequence<PublicKeyCredentialParameters>  pubKeyCredParams;

    unsigned long                                timeout;
    sequence<PublicKeyCredentialDescriptor>      excludeCredentials = [];
    AuthenticatorSelectionCriteria               authenticatorSelection;
    sequence<DOMString>                          hints = [];
    DOMString                                    attestation = "none";
    sequence<DOMString>                          attestationFormats = [];
    AuthenticationExtensionsClientInputs         extensions;
};
rp, of type PublicKeyCredentialRpEntity

该成员包含负责该请求的 Relying Party 的名称和标识符。

其值的 name 成员为 必需。详见 § 5.4.1 Public Key Entity Description (dictionary PublicKeyCredentialEntity) 以获取更多细节。

其值的 id 成员指定凭证应当作用于的 RP ID 的范围。如果省略, 则其值将默认为 CredentialsContainer 对象的 relevant settings objectorigineffective domain。详见 § 5.4.2 Relying Party Parameters for Credential Generation (dictionary PublicKeyCredentialRpEntity) 以获取更多细节。

user, of type PublicKeyCredentialUserEntity

该成员包含执行registration用户账户的名称和标识符。

其值的 namedisplayNameid 成员为 必需。 id 可以在将来的某些authentication ceremonies中作为 userHandle 返回,并用于覆盖在同一 authenticator 上、具有相同 rp.iduser.id 的可发现凭证(discoverable credentials)。 namedisplayName 可由authenticatorclient在将来的authentication ceremonies中使用, 以帮助用户选择一个credential,但这些字段不会在将来的authentication ceremonies的结果中返回给Relying Party

更多细节请参见 § 5.4.1 Public Key Entity Description (dictionary PublicKeyCredentialEntity)§ 5.4.3 User Account Parameters for Credential Generation (dictionary PublicKeyCredentialUserEntity)

challenge, of type BufferSource

该成员指定一个质询,authenticator 在为新创建的凭证生成 attestation object 时会对该质询(及其他数据)进行签名。参见 § 13.4.3 Cryptographic Challenges 中的安全注意事项。

pubKeyCredParams, of type sequence<PublicKeyCredentialParameters>

该成员列出了 Relying Party 支持的密钥类型和签名算法, 按照从最优先到最不优先的顺序排列。 允许有重复项,但实际上会被忽略。 客户端认证器 会尽最大努力创建最优先类型的凭据。 如果无法创建所列类型中的任何一种,create() 操作将失败。

希望支持广泛 authenticatorsRelying Parties 应当至少包含以下 COSEAlgorithmIdentifier 值:

  • -8 (EdDSA)

  • -7 (ES256)

  • -257 (RS256)

可以根据需要包含额外的签名算法。

下列由 [RFC9864] 引入的完全指定的 COSEAlgorithmIdentifier 值 不推荐 在 pubKeyCredParams 中使用:

  • -9 (ESP256); 建议改用或同时使用 -7 (ES256)。

  • -51 (ESP384); 建议改用或同时使用 -35 (ES384)。

  • -52 (ESP512); 建议改用或同时使用 -36 (ES512)。

  • -19 (Ed25519); 建议改用或同时使用 -8 (EdDSA)。

注:在 WebAuthn 中,值 -9 (ESP256)、-51 (ESP384)、-52 (ESP512) 和 -19 (Ed25519) 分别与 -7 (ES256)、-35 (ES384)、-36 (ES512) 和 -8 (EdDSA) 表示相同的事物,但由于在 § 5.8.5 Cryptographic Algorithm Identifier (typedef COSEAlgorithmIdentifier) 中规定了附加限制, 它们在实践中并不互换,因为许多实现支持后者标识符但不支持前者。因此为向后兼容,建议在 pubKeyCredParams 中优先使用后者标识符。

timeout, of type unsigned long

此可选成员指定以毫秒为单位的时间,表示 Relying Party 愿意等待调用完成的时长。 该字段被视为提示,client 可覆盖该值。

excludeCredentials, of type sequence<PublicKeyCredentialDescriptor>, defaulting to []

Relying Party 应当使用此可选成员列出映射到该用户账户的任何现有凭证(由 user.id 标识)。 这可确保不会在已存在映射到该用户账户 的凭证的 authenticator 上“创建”新凭证。 若会发生此情况,则请求 client 指导用户使用不同的authenticator,若失败则返回错误。

authenticatorSelection, of type AuthenticatorSelectionCriteria

Relying Party 可使用此可选成员指定 authenticator 必须或应当满足的能力和设置,以参与 create() 操作。 详见 § 5.4.4 Authenticator Selection Criteria (dictionary AuthenticatorSelectionCriteria)

hints, of type sequence<DOMString>, defaulting to []

此可选成员包含零个或多个来自 PublicKeyCredentialHint 的元素,以引导用户代理与用户交互。注意这些元素的类型为 DOMString,尽管它们取自该枚举。详见 § 2.1.1 Enumerations as DOMString types

attestation, of type DOMString, defaulting to "none"

Relying Party 可使用此可选成员指定关于 attestation conveyance 的偏好。 其值应当是 AttestationConveyancePreference 的成员。 Client platforms 必须忽略未知值,并将未知值视为该成员不存在。

默认值为 none

attestationFormats, of type sequence<DOMString>, defaulting to []

Relying Party 可使用此可选成员指定关于 attestation 语句格式的偏好,该格式由 authenticator 使用。 值应当从 IANA “WebAuthn Attestation Statement Format Identifiers” 注册表(由 [IANA-WebAuthn-Registries],由 [RFC8809] 建立)中选取。 值按从最优先到最不优先排序。允许重复但实际被忽略。该参数为参考性,authenticator 可使用未在此参数中列举的 attestation 语句。

默认值为空列表,表示无偏好。

extensions, of type AuthenticationExtensionsClientInputs

Relying Party 可使用此可选成员提供 client extension inputs, 请求 clientauthenticator 做额外处理。 例如,Relying Party 可能请求客户端返回关于所创建credential 的附加信息。

扩展框架在 § 9 WebAuthn Extensions 中定义。部分扩展在 § 10 Defined Extensions 中定义;请查阅由 [RFC8809] 建立的 IANA “WebAuthn Extension Identifiers” 注册表([IANA-WebAuthn-Registries])以获取已注册 WebAuthn Extensions 的最新列表。

5.4.1. 公钥实体描述(字典 PublicKeyCredentialEntity

PublicKeyCredentialEntity 字典描述一个 用户账户,或与之关联/限定(scope)的 WebAuthn Relying Party,即公钥凭证的归属对象。

dictionary PublicKeyCredentialEntity {
    required DOMString    name;
};
name, of type DOMString

实体的一个便于人类识别的名称。其作用取决于该 PublicKeyCredentialEntity 表示的对象:

  • [已弃用] 当被 PublicKeyCredentialRpEntity 继承时,它是供人类识别的 Relying Party 的标识,仅用于显示。例如 “ACME Corporation”、“Wonderful Widgets, Inc.” 或 “ОАО Примертех”。

    该成员被弃用是因为许多 clients 并不显示它,但为向后兼容仍然保留为必需的字典成员。 Relying Parties 可将其安全默认值设置为 RP ID

    • Relying Parties 在设置 name 的值或向用户显示该值时,应当按照 [RFC8266] 中针对 PRECIS FreeformClass 的 Nickname 配置文件在第 2.3 节规定的强制规则来执行。

    • Clients 在向用户显示 name 的值或在将该值作为 authenticatorMakeCredential 操作的参数之前,应该按照 [RFC8266] 中针对 PRECIS FreeformClass 的 Nickname 配置文件在第 2.3 节规定的强制规则来执行。

  • 当被 PublicKeyCredentialUserEntity 继承时,它是用于表示用户账户的一个便于人类识别的标识。该标识是 Clients 向用户显示的主要值,用以帮助用户理解某个凭证与哪个用户账户相关联。

    此标识的合适示例值包括 “alexm”、“+14255551234”、“alex.mueller@example.com”、“alex.mueller@example.com (prod-env)” 或 “alex.mueller@example.com (ОАО Примертех)”。

    • Relying Party 可允许用户选择该值。Relying Party 在设置 name 的值或向用户显示该值时,应当按照 [RFC8265] 中针对 PRECIS IdentifierClass 的 UsernameCasePreserved 配置文件在第 3.4.3 节规定的强制规则来执行。

    • Clients 在向用户显示 name 的值或在将该值作为 authenticatorMakeCredential 操作的参数之前,应当按照 [RFC8265] 中针对 PRECIS IdentifierClass 的 UsernameCasePreserved 配置文件在第 3.4.3 节规定的强制规则来执行。

clientsclient platformsauthenticators 显示 name 的值时,它们应始终使用用户界面元素在显示的值周围提供明确边界,并避免该值溢出到其他元素中 [css-overflow-3]

在存储 name 成员的值时,该值可以按 § 6.4.1 字符串截断 所述进行截断,使用的大小限制应大于或等于 64 字节。

5.4.2. 凭证生成时的Relying Party参数(字典 PublicKeyCredentialRpEntity

PublicKeyCredentialRpEntity 字典用于在创建新凭证时提供额外的 服务方 属性。

dictionary PublicKeyCredentialRpEntity : PublicKeyCredentialEntity {
    DOMString      id;
};
id, of type DOMString

用于标识该 服务方 实体的唯一标识符,用来设置 RP ID

5.4.3. 凭证生成时的用户账户参数(字典 PublicKeyCredentialUserEntity

PublicKeyCredentialUserEntity 字典用于在新建凭证时提供额外的用户账户属性。

dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
    required BufferSource   id;
    required DOMString      displayName;
};
id, of type BufferSource

user handle 属于进行用户账户的标识。 user handle 是一个不透明的字节序列,最大为 64 字节,不应向用户展示。

为确保安全操作,认证和授权决策必须基于此 id 成员,而不是基于 displayNamename 成员。参见 [RFC8266] 第 6.1 节。

user handle 不得包含可识别用户个人身份的信息,例如用户名或电子邮件地址;详见 § 14.6.1 User Handle Contentsuser handle 不得为空。

user handle 不应在不同用户账户之间使用相同的常量值,即便对于不可发现凭证也是如此,因为某些认证器总是创建可发现凭证。因此,若使用恒定的user handle,该用户将无法在同一Relying Party 下将该认证器用于多个用户账户

displayName, of type DOMString

用于表示用户账户的一个便于人类识别的名称,仅用于展示。Relying Party 应允许用户选择该值,并且不应对选择施加不必要的限制。如果找不到合适或便于人类识别的名称,Relying Party 应将此值设为空字符串。

此标识的合适示例值包括 “Alex Müller”、“Alex Müller (ACME Co.)” 或 “田中倫”。

  • Relying Parties 在将 displayName 设置为非空字符串或向用户显示非空值时,应按照 [RFC8266] 中针对 PRECIS FreeformClass 的 Nickname 配置文件第 2.3 节规定的强制规则执行。

  • Clients 在向用户显示非空的 displayName 值或在将其作为 authenticatorMakeCredential 操作的参数之前,应按照 [RFC8266] 中针对 PRECIS FreeformClass 的 Nickname 配置文件第 2.3 节规定的强制规则执行。

clientsclient platformsauthenticators 显示 displayName 的值时,应始终使用 UI 元素在显示的值周围提供明确的边界,并避免该值溢出到其他元素中 [css-overflow-3]

在存储 displayName 成员的值时,可按 § 6.4.1 字符串截断 中的描述进行截断,使用的大小限制应 >= 64 字节。

5.4.4. 认证器选择条件(字典 AuthenticatorSelectionCriteria

WebAuthn Relying Parties 可以通过 AuthenticatorSelectionCriteria 字典来指定认证器属性需求。

dictionary AuthenticatorSelectionCriteria {
    DOMString                    authenticatorAttachment;
    DOMString                    residentKey;
    boolean                      requireResidentKey = false;
    DOMString                    userVerification = "preferred";
};
authenticatorAttachment, of type DOMString

如果存在此成员,则会将符合条件的 authenticators 过滤为仅那些以指定 authenticator attachment modality 方式连接的认证器(另见 § 6.2.1 Authenticator Attachment Modality)。 如果此成员缺失,则接受任何连接方式。该值应为 AuthenticatorAttachment 的成员,但 client platforms 必须忽略未知值,将未知值视为该成员不存在

另见 authenticatorAttachment 成员(属于 PublicKeyCredential), 它可指示在成功的 create()get() 操作中使用了哪种 authenticator attachment modality

residentKey, of type DOMString

指定 Relying Party 希望创建 client-side discoverable credential 的程度。 出于历史原因,命名保留了已弃用的“resident”术语。该值应为 ResidentKeyRequirement 的成员,但 client platforms 必须忽略未知值,将未知值视为该成员不存在。如果未提供值,则当 requireResidentKeytrue 时,有效值为 required;若为 false 或缺失,则为 discouraged

有关 ResidentKeyRequirement 的值及语义的描述,请参阅 residentKey

requireResidentKey, of type boolean, defaulting to false

此成员为与 WebAuthn Level 1 向后兼容而保留,出于历史原因其命名保留了针对 discoverable credentials 的已弃用“resident”术语。Relying Parties 应当当且仅当 residentKey 被设置为 required 时,将其设置为 true

userVerification, of type DOMString, defaulting to "preferred"

此成员指定 Relying Party 对于 user verificationcreate() 操作中的要求。该值应为 UserVerificationRequirement 的成员,但 client platforms 必须忽略未知值,将未知值视为该成员不存在

有关 UserVerificationRequirement 的值及语义的描述,请参阅 userVerification

5.4.5. 认证器连接模式枚举(enum AuthenticatorAttachment

该枚举的值描述了 authenticatorsattachment modalitiesRelying Parties 在调用 navigator.credentials.create()创建凭证 时使用此项来表达首选的 authenticator attachment modality,而 clients 则用它来报告用于完成 registrationauthentication ceremonyauthenticator attachment modality

enum AuthenticatorAttachment {
    "platform",
    "cross-platform"
};

注: AuthenticatorAttachment 枚举故意不被引用,参见 § 2.1.1 枚举作为 DOMString 类型

platform

该值表示 platform attachment

cross-platform

该值表示 cross-platform attachment

注: authenticator attachment modality 的选择选项仅在 [[Create]](origin, options, sameOriginWithAncestors) 操作中可用。Relying Party 可以使用它,例如确保存用户具有可用于在另一个 client device 上进行认证的 roaming credential;或者专门注册一个便于在特定 client device 上重新认证的 platform credential[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 操作没有 authenticator attachment modality 的选择选项。 client 和用户将在当时使用可用且方便的任一 credential,但受 allowCredentials 选项的约束。

5.4.6. 常驻密钥需求枚举(enum ResidentKeyRequirement

enum ResidentKeyRequirement {
    "discouraged",
    "preferred",
    "required"
};

注意: ResidentKeyRequirement 枚举故意未被引用,参见 § 2.1.1 枚举作为 DOMString 类型

该枚举的值描述了 Relying Party客户端可发现凭据(之前称为 常驻凭据常驻密钥)的要求:

discouraged

Relying Party 更倾向于创建 服务端凭据,但也能接受 客户端可发现凭据客户端认证器 应在可能的情况下创建 服务端凭据

注意: Relying Party 不能强制要求所创建的凭据必须为 服务端凭据Credential Properties Extension 也可能不会返回 rk 属性的值。因此,有可能无法得知某凭据是否为 服务端凭据,也无法确认是否创建同一 用户句柄的第二个凭据会驱逐第一个。

preferred

Relying Party 强烈倾向于创建 客户端可发现凭据, 但也能接受 服务端凭据客户端认证器 应在可能的情况下创建 可发现凭据。 例如,客户端 应指导用户进行 用户验证 的设置,以便创建 可发现凭据。这优先于 userVerification 的设置。

required

Relying Party 要求必须创建 客户端可发现凭据客户端 必须在无法创建 客户端可发现凭据 时返回错误。

注意: Relying Party 可通过 Credential Properties Extension常驻密钥凭据属性 查询认证器是否创建了 客户端可发现凭据。 当 discouragedpreferred 被用于 options.authenticatorSelection.residentKey 时很有用, 因为在这些情况下 认证器 既可能创建 客户端可发现凭据,也可能创建 服务端凭据

5.4.7. 声明传递 偏好枚举(enum AttestationConveyancePreference

WebAuthn 服务方可使用 AttestationConveyancePreference 来指定在凭证生成期间关于 attestation conveyance 的偏好。

enum AttestationConveyancePreference {
    "none",
    "indirect",
    "direct",
    "enterprise"
};

注: AttestationConveyancePreference 枚举故意不被直接引用,详见 § 2.1.1 枚举作为 DOMString 类型

none

Relying Partyauthenticatorattestation 不感兴趣。例如,为了可能避免需要取得 用户同意 以将可识别信息转发给 Relying Party, 或者为了省去往返于 Attestation CAAnonymization CA 的一次请求。 如果 authenticator 生成了非 self attestationattestation statement, 则 client 会将其替换为 None attestation statement。

这是默认值,未知值将回退到此行为。

indirect

Relying Party 希望收到可验证的 attestation statement, 但允许 client 决定如何获取该 attestation statement。 客户端可以用由 Anonymization CA 生成的 attestation statement 来替换认证器生成的 attestation statement, 以保护用户隐私,或在异构生态中协助 Relying Parties 进行 attestation 验证。

注意:在此情况下并不保证 Relying Party 一定能获得可验证的 attestation statement。例如,当认证器使用 self attestationclient 未对该 attestation statement 做修改直接传递时,就可能发生这种情况。

direct

Relying Party 希望直接收到由 authenticator 原样生成的 attestation statement

enterprise

Relying Party 希望获得企业级的 attestation,即一种可能包含可唯一标识认证器信息的 attestation statement。 该选项用于企业内部的受控部署场景,组织希望将注册与特定认证器绑定。除非用户代理或认证器配置允许针对请求的 RP ID 提供此类 attestation,否则用户代理必须不提供此类 attestation。

如果允许,用户代理应当在调用时(参见 invocation time)向认证器发出请求企业级 attestation 的信号,并将得到的 AAGUIDattestation statement 原样传递给 Relying Party

5.5. 断言生成选项(字典 PublicKeyCredentialRequestOptions

PublicKeyCredentialRequestOptions 字典向 get() 提供生成断言所需的数据。其 challenge 成员必须存在,其它成员均为可选。

dictionary PublicKeyCredentialRequestOptions {
    required BufferSource                challenge;
    unsigned long                        timeout;
    DOMString                            rpId;
    sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
    DOMString                            userVerification = "preferred";
    sequence<DOMString>                  hints = [];
    AuthenticationExtensionsClientInputs extensions;
};
challenge, of type BufferSource

此成员指定一个质询,authenticator 在生成authentication assertion 时会将该质询与其他数据一并签名。参见 § 13.4.3 Cryptographic Challenges 的安全注意事项。

timeout, of type unsigned long

此可选成员指定以毫秒为单位的时间,表示 Relying Party 愿意等待调用完成的时长。 该值被视为提示,可能会被 client 覆盖。

rpId, of type DOMString

此可选成员指定由 Relying Party 声称的 RP IDclient 必须验证该 Relying Partyorigin 与该 RP IDscope 相匹配。 authenticator 必须验证该 RP ID 精确等于用于本次authentication ceremony 的该 credentialrpId

若未指定,其值将为 CredentialsContainer 对象的 relevant settings objectorigineffective domain

allowCredentials, of type sequence<PublicKeyCredentialDescriptor>, defaulting to []

此可选成员供 client 用于查找适合本次 authenticators 的项,以参与本次 authentication ceremony。 它可用于两种情形:

如果非 ,当列出的凭证均不可用时,客户端必须返回错误。

该列表按偏好程度降序排列:列表中的第一个项为最优先的凭证,最后一项为最不优先的凭证。

userVerification, of type DOMString, defaulting to "preferred"

此可选成员指定 Relying Party 对于 user verificationget() 操作中的要求。该值应为 UserVerificationRequirement 的成员, 但 client platforms 必须忽略未知值,且将未知值视为该成员不存在。符合条件的认证器会被筛选为仅包含那些能满足此要求的认证器。

有关 UserVerificationRequirement 的值及语义,请参见 userVerification 的描述。

hints, of type sequence<DOMString>, defaulting to []

此可选成员包含来自 PublicKeyCredentialHint 的零个或多个元素,用以指导用户代理与用户交互。注意这些元素的类型为 DOMString,尽管它们取自该枚举。参见 § 2.1.1 枚举作为 DOMString 类型

extensions, of type AuthenticationExtensionsClientInputs

Relying Party 可使用此可选成员提供 client extension inputs,请求 clientauthenticator 进行额外处理。

扩展框架定义见 § 9 WebAuthn Extensions。部分扩展定义见 § 10 Defined Extensions; 请查阅由 [RFC8809] 建立的 IANA “WebAuthn Extension Identifiers” 注册表 [IANA-WebAuthn-Registries] 以获取已注册的 WebAuthn Extensions 的最新列表。

5.6. 使用 AbortSignal 中止操作

建议开发者使用 AbortController 管理 [[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 操作。 详见 DOM § 3.3 AbortController 与 AbortSignal 用法

注意: DOM § 3.3 AbortController与AbortSignal用法明确规定,当 AbortSignal 被中止时,平台API必须立即拒绝Promise。 鉴于 [[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 逻辑结构复杂,两者分别在API主入口、认证会话前启动以及认证器会话期间三处检测该属性,确保遵从规范。

5.7. WebAuthn 扩展输入与输出

下列小节定义了用于传递 WebAuthn 扩展输入与输出的数据类型。

注意: 认证器扩展输出作为认证器数据的一部分传递(见表 1)。

注意:下方定义的类型——AuthenticationExtensionsClientInputsAuthenticationExtensionsClientOutputs ——适用于 注册扩展认证扩展。其名称中的 “Authentication...” 部分应视为 “WebAuthentication...” 的含义。

5.7.1. 认证扩展客户端输入(字典 AuthenticationExtensionsClientInputs

dictionary AuthenticationExtensionsClientInputs {
};

这是一个包含了零个或多个 客户端扩展输入值的字典,用于 WebAuthn 扩展

5.7.2. 认证扩展客户端输出(字典 AuthenticationExtensionsClientOutputs

dictionary AuthenticationExtensionsClientOutputs {
};

这是一个包含了零个或多个 客户端扩展输出值的字典,用于 WebAuthn 扩展

5.7.3. 认证扩展认证器输入(CDDL 类型 AuthenticationExtensionsAuthenticatorInputs

AuthenticationExtensionsAuthenticatorInputs = {
  * $$extensionInput
} .within { * tstr => any }

CDDL 类型 AuthenticationExtensionsAuthenticatorInputs 定义了一个 CBOR 映射, 包含了零个或多个 认证器扩展输入的值,用于 WebAuthn 扩展。 扩展可以按 § 9.3 扩展请求参数 的描述添加成员。

此类型不会暴露给 依赖方,仅供 客户端认证器使用。

5.7.4. 认证扩展认证器输出(CDDL 类型 AuthenticationExtensionsAuthenticatorOutputs

AuthenticationExtensionsAuthenticatorOutputs = {
  * $$extensionOutput
} .within { * tstr => any }

CDDL 类型 AuthenticationExtensionsAuthenticatorOutputs 定义了一个 CBOR 映射 ,包含了零个或多个 认证器扩展输出的值,用于 WebAuthn 扩展。 扩展可以按 § 9.3 扩展请求参数 的描述添加成员。

5.8. 支持性数据结构

公钥凭证类型采用了一些在其他规范中定义的数据结构,具体如下。

5.8.1. 用于WebAuthn 签名的客户端数据(字典 CollectedClientData

客户端数据表示 WebAuthn 依赖方客户端的上下文绑定。它是一个键为字符串、值可为任意 JSON 有效编码类型的键值映射。其结构由如下 Web IDL 定义。

注意:CollectedClientData 未来可能会扩展。因此在解析时应容忍未知的键和任意顺序的键。另见 § 5.8.1.2 有限校验算法

dictionary CollectedClientData {
    required DOMString           type;
    required DOMString           challenge;
    required DOMString           origin;
    boolean                      crossOrigin;
    DOMString                    topOrigin;
};

dictionary TokenBinding {
    required DOMString status;
    DOMString id;
};

enum TokenBindingStatus { "present", "supported" };
type, 类型为 DOMString

此成员在创建新凭证时包含字符串 "webauthn.create",在获取已有凭证断言时为 "webauthn.get"。该成员的目的是防止某些类型的签名混淆攻击(攻击者用一个合法签名替换另一个)。

challenge, 类型为 DOMString

此成员包含由依赖方提供的 challenge 的 base64url 编码。参见 § 13.4.3 密码挑战安全考量。

origin, 类型为 DOMString

此成员包含请求方的完全限定源(origin),由客户端提供给认证器,语法定义见[RFC6454]

crossOrigin, 类型为 boolean

此可选成员包含传给 内部方法sameOriginWithAncestors 参数的取反值。

topOrigin, 类型为 DOMString

此可选成员包含请求方的完全限定顶级源,语法定义见[RFC6454]。仅在调用上下文与其祖先非同源(即same-origin with its ancestors为假时)设置,亦即crossOrigintrue

[保留] tokenBinding

该可选成员包含有关在与 令牌绑定 协议 [TokenBinding]服务方 通信时的状态信息。其缺失表示客户端不支持令牌绑定

注意:虽然Token Binding 曾在 WebAuthn Level 1 和 Level 2 出现,其在 Level 3 不再使用。tokenBinding 字段被保留,不会被其他用途复用。

status, 类型为 DOMString

此成员应为TokenBindingStatus 的成员,但客户端平台必须忽略未知值,将未知值视为tokenBinding 成员不存在。已知时,该成员为下列之一:

supported

表示客户端支持 token binding,但与依赖方通信时未协商。

present

表示与依赖方通信时已使用 token binding。此时,必须包含id成员。

注意: 枚举TokenBindingStatus故意未被引用,详见§ 2.1.1 枚举作为 DOMString 类型

id, 类型为 DOMString

statuspresent 时,该成员必须存在, 并且是向 依赖方通信时所用 Token Binding ID 的 base64url 编码。

注意: 获得 Token Binding ID客户端平台特定的操作。

CollectedClientData 结构用于客户端计算如下内容:

客户端数据的 JSON 兼容序列化

这是对CollectedClientData 字典执行 JSON 兼容序列化算法 的结果。

序列化客户端数据的哈希

这是客户端数据的 JSON 兼容序列化的哈希(用 SHA-256 计算),由客户端构造。

5.8.1.1. 序列化

CollectedClientData 的序列化是 JSON 值序列化为字节算法的子集。它产生 CollectedClientData 的一个有效 JSON 编码,但也为校验器提供了可利用的附加结构而无需集成完整 JSON 解析器。推荐校验器采用标准 JSON 解析,但如需精简可采用下方有限算法。该校验仅需要 base64url 编码、追加字节串(可写入模板)、简单条件判断(假定输入无需转义)。

序列化算法通过将连续的字节串附加到最初为空的部分结果,直到获得完整结果。

  1. result 为空字节串。

  2. 附加 0x7b2274797065223a({"type":)到 result

  3. 附加 CCDToString(type) 到 result

  4. 附加 0x2c226368616c6c656e6765223a(,"challenge":)到 result

  5. 附加 CCDToString(challenge) 到 result

  6. 附加 0x2c226f726967696e223a(,"origin":)到 result

  7. 附加 CCDToString(origin) 到 result

  8. 附加 0x2c2263726f73734f726967696e223a(,"crossOrigin":)到 result

  9. 如果 crossOrigin 不存在或为 false

    1. 附加 0x66616c7365(false)到 result

  10. 否则:

    1. 附加 0x74727565(true)到 result

  11. 如果topOrigin 存在:

    1. 附加 0x2c22746f704f726967696e223a(,"topOrigin":)到 result

    2. 附加 CCDToString(topOrigin) 到 result

  12. 创建 CollectedClientData 的临时副本,并移除字段 typechallengeorigincrossOrigin (如有)、topOrigin(如有)。

  13. 如果临时副本无剩余字段:

    1. 附加 0x7d(})到 result

  14. 否则:

    1. 对临时副本执行 JSON 序列化为字节,结果为字节串 remainder

    2. 附加 0x2c(,)到 result

    3. 移除remainder的首字节。

    4. 附加 remainderresult

  15. 序列化结果为 result 的值。

函数 CCDToString 在上述算法中定义如下:

  1. encoded为空字节串。

  2. 附加 0x22(")到 encoded

  3. 对给定对象执行 ToString 转为字符串。

  4. 对结果字符串中的每个码点,如该码点:

    属于 {U+0020, U+0021, U+0023–U+005B, U+005D–U+10FFFF}

    将该码点的 UTF-8 编码附加到 encoded

    为 U+0022

    附加 0x5c22(\")到 encoded

    为 U+005C

    附加 0x5c5c(\\)到 encoded

    否则

    附加 0x5c75(\u),再加以四位小写十六进制表示该码点的数字。

  5. 附加 0x22(")到 encoded

  6. 函数返回 encoded 的值。

5.8.1.2. 有限校验算法

如无法支持完整 JSON 解析器,校验器可用如下算法校验编码后的CollectedClientData

  1. 算法输入为:

    1. 字节串 clientDataJSON,即序列化的clientDataJSON

    2. 字符串 type,为期望的type

    3. 字节串 challenge,为 PublicKeyCredentialRequestOptionsPublicKeyCredentialCreationOptions中给定的 challenge 字节串。

    4. 字符串 origin,为发起请求的预期origin

    5. 可选字符串 topOrigin,为可用时发起请求的预期 topOrigin

    6. 布尔值 requireTopOrigin,仅当需在 topOrigin 已定义但topOrigin 不在 clientDataJSON 时校验失败才为 true。 该算法与 Web Authentication Level 2 的JSON 兼容序列化算法向后兼容,前提requireTopOriginfalse

  2. 定义 expected 为空字节串。

  3. 附加 0x7b2274797065223a({"type":)到 expected

  4. 附加 CCDToString(type) 到 expected

  5. 附加 0x2c226368616c6c656e6765223a(,"challenge":)到 expected

  6. challenge 执行base64url 编码,得字符串 challengeBase64

  7. 附加 CCDToString(challengeBase64) 到 expected

  8. 附加 0x2c226f726967696e223a(,"origin":)到 expected

  9. 附加 CCDToString(origin) 到 expected

  10. 附加 0x2c2263726f73734f726967696e223a(,"crossOrigin":)到 expected

  11. topOrigin 已定义:

    1. 附加 0x74727565(true)到 expected

    2. requireTopOrigin 为 true 或 0x2c22746f704f726967696e223a(,"topOrigin":)为 clientDataJSON 偏移 expected 长度之后的前缀:

      1. 附加 0x2c22746f704f726967696e223a(,"topOrigin":)到 expected

      2. 附加 CCDToString(topOrigin) 到 expected

  12. 否则(topOrigin 未定义):

    1. 附加 0x66616c7365(false)到 expected

  13. expected 不是 clientDataJSON 的前缀,则校验失败。

  14. clientDataJSON 不比 expected 至少多一字节,校验失败。

  15. clientDataJSON 位于 expected 长度偏移的字节:

    为 0x7d

    校验成功。

    为 0x2c

    校验成功。

    其他

    校验失败。

5.8.1.3. 未来拓展

为兼容有限校验算法,本规范后续版本不得从 CollectedClientData 中移除字段 typechallengeorigincrossOrigintopOrigin。 也不得更改序列化算法以改变这些字段的序列化顺序,或在其中插入新字段。

如向 CollectedClientData 添加字段,则采用有限校验算法的校验器将无法处理,直到上述算法扩展支持这些新字段。升级时新字段也需遵循以上限制。算法更新还需兼容历史序列化,即新增第六字段在老代理生成的序列化中可能第六位或不存在。

5.8.2. 凭证类型枚举(枚举 PublicKeyCredentialType

enum PublicKeyCredentialType {
    "public-key"
};

注意: PublicKeyCredentialType 枚举被有意设计为不被直接引用,详见 § 2.1.1 枚举作为 DOMString 类型

本枚举定义了合法的凭证类型。这是一个扩展点,日后随着新凭证类型的定义可以加入更多取值。此枚举的值用于根据认证器类型对认证断言和证明结构进行版本标记。

当前只定义了一种凭证类型,即 "public-key"。

5.8.3. 凭证描述符(字典 PublicKeyCredentialDescriptor

dictionary PublicKeyCredentialDescriptor {
    required DOMString                    type;
    required BufferSource                 id;
    sequence<DOMString>                   transports;
};

该字典用于标识一个具体的公钥凭证。 在 create() 中用于避免在同一认证器上重复创建凭证, 在 get() 中用于判定客户端是否以及如何能够访问该凭证。

凭证记录的凭证描述符是该凭证记录属性的一个子集, 并反映了 PublicKeyCredential 对象由 create()get() 返回的部分字段。

type, of type DOMString

该成员包含调用方所引用的public key credential的类型。该值应当是PublicKeyCredentialType的成员,但client platforms必须忽略任何具有未知PublicKeyCredentialDescriptortype的条目。 但是,如果由于type未知而导致所有元素都被忽略,则必须产生错误,因为空的allowCredentials 在语义上与非空不同。

此项应当设置为表示所识别的public key credential sourcecredential recordtype项的值。 这对应于type 字段在PublicKeyCredential中的含义。

id, of type BufferSource

该成员包含调用方所引用的public key credentialcredential ID

此项应当设置为表示所识别的public key credential sourcecredential recordid项的值。 这对应于由PublicKeyCredentialrawId字段。

transports, of type sequence<DOMString>

此可选成员包含关于客户端可能如何与调用方所引用的public key credential的管理authenticator通信的提示。 其值应当是AuthenticatorTransport的成员,但client platforms必须忽略未知值。

此项应当设置为表示所识别的public key credential sourcecredential recordtransports项的值。 这对应于由create() 操作创建的PublicKeyCredential结构的response.getTransports()方法。

5.8.4. 认证器传输类型枚举(枚举 AuthenticatorTransport

enum AuthenticatorTransport {
    "usb",
    "nfc",
    "ble",
    "smart-card",
    "hybrid",
    "internal"
};

注意: The AuthenticatorTransport enumeration is deliberately not referenced, see § 2.1.1 枚举作为 DOMString 类型.

认证器 可能实现各种 传输方式 来与 客户端 通信。该枚举定义了有关客户端可能如何与特定认证器通信以获取针对特定凭证的断言的提示。请注意,这些提示代表 WebAuthn 依赖方 关于如何到达认证器的最佳判断。依赖方 通常会通过 getTransports() 了解 公钥凭证 支持的传输方式。
usb

表示相应的 认证器 可以通过可拆卸的 USB 进行通信。

nfc

表示相应的 认证器 可以通过近场通信(NFC)进行通信。

ble

表示相应的 认证器 可以通过 Bluetooth Smart(蓝牙低功耗 / BLE)进行通信。

smart-card

表示相应的 认证器 可以通过带接触的 ISO/IEC 7816 智能卡进行通信。

hybrid

表示相应的 认证器 可以使用(通常是分离的)数据传输和近距机制的组合来通信。例如,这支持在台式计算机上使用智能手机进行认证。

internal

表示相应的 认证器 使用客户端设备特定的传输进行联系,即它是一个 平台认证器。这些认证器不能从 客户端设备 中移除。

5.8.5. 密码算法标识符 (typedef COSEAlgorithmIdentifier)

typedef long COSEAlgorithmIdentifier;
A COSEAlgorithmIdentifier’s value is a number identifying a cryptographic algorithm. The algorithm identifiers SHOULD be values registered in the IANA COSE Algorithms registry [IANA-COSE-ALGS-REG], for instance, -7 for "ES256" and -257 for "RS256".

COSE 算法注册表允许在 COSE 密钥 中由其他参数指定一定的自由度。为了促进互操作性,本规范对 凭证公钥 做出以下附加保证:

  1. 算法为 -7(ES256)的密钥必须将 crv 参数指定为 1(P-256),且不得使用压缩点形式。

  2. 算法为 -9(ESP256)的密钥不得使用压缩点形式。

  3. 算法为 -35(ES384)的密钥必须将 crv 参数指定为 2(P-384),且不得使用压缩点形式。

  4. 算法为 -51(ESP384)的密钥不得使用压缩点形式。

  5. 算法为 -36(ES512)的密钥必须将 crv 参数指定为 3(P-521),且不得使用压缩点形式。

  6. 算法为 -52(ESP512)的密钥不得使用压缩点形式。

  7. 算法为 -8(EdDSA)的密钥必须将 crv 参数指定为 6(Ed25519)。(在 COSE 中这些总是使用压缩形式。)

这些限制与 第 2.1 节 中的建议一致,见 [RFC9053]

注意: 使用这些算法正确实现签名验证需要许多检查。其中一项是,在处理未压缩的椭圆曲线点时,实现在使用该点前应检查该点确实位于曲线上。之所以强调此检查,是因为它特别容易在密码库与其他代码之间出现遗漏。

5.8.6. 用户验证要求枚举(枚举 UserVerificationRequirement

enum UserVerificationRequirement {
    "required",
    "preferred",
    "discouraged"
};

WebAuthn 依赖方可以部分操作要求用户验证,部分不要求,可用此类型灵活表达需求。

注意: UserVerificationRequirement 枚举被有意设计为不被直接引用,详见 § 2.1.1 枚举作为 DOMString 类型

required

责任方 要求本次操作进行用户验证,如果响应未设置UV 标志,则整个流程将失败。 如果无法进行用户验证客户端必须返回错误。

preferred

责任方 优先考虑在本次操作中进行用户验证(如有可能),但如果响应未设置UV 标志,本次操作不会失败。

discouraged

责任方 不希望在本次操作中进行用户验证(例如,为了最大限度减少用户交互流程的中断)。

5.8.7. 客户端能力枚举(枚举 ClientCapability

enum ClientCapability {
    "conditionalCreate",
    "conditionalGet",
    "hybridTransport",
    "passkeyPlatformAuthenticator",
    "userVerifyingPlatformAuthenticator",
    "relatedOrigins",
    "signalAllAcceptedCredentials",
    "signalCurrentUserDetails",
    "signalUnknownCredential"
};

此枚举定义了WebAuthn 依赖方可能用于实现特定工作流和用户体验的有限客户端能力集。

依赖方可通过 getClientCapabilities() 方法获取 PublicKeyCredential 支持的能力。

注意: ClientCapability 枚举被有意设计为不被直接引用,详见 § 2.1.1 枚举作为 DOMString 类型

conditionalCreate

WebAuthn 客户端支持用于注册流程conditional调解。

详见 § 5.1.3 新建凭证 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 内部方法

conditionalGet

WebAuthn 客户端支持用于认证流程conditional调解。

该能力等价于 isConditionalMediationAvailable() 返回 true

详见§ 5.1.4 使用现有凭证生成断言

hybridTransport

WebAuthn 客户端支持 hybrid 传输方式。

passkeyPlatformAuthenticator

WebAuthn 客户端支持本地或通过 hybrid 传输方式使用 passkey 平台认证器

userVerifyingPlatformAuthenticator

WebAuthn 客户端支持 用户验证型平台认证器

relatedOrigins

WebAuthn 客户端支持相关来源请求

signalAllAcceptedCredentials

WebAuthn 客户端支持 signalAllAcceptedCredentials()

signalCurrentUserDetails,

WebAuthn 客户端支持 signalCurrentUserDetails()

signalUnknownCredential

WebAuthn 客户端支持 signalUnknownCredential()

5.8.8. 用户代理提示枚举(枚举 PublicKeyCredentialHint

enum PublicKeyCredentialHint {
    "security-key",
    "client-device",
    "hybrid",
};

注意: PublicKeyCredentialHint 枚举被故意没有引用,详见 § 2.1.1 作为 DOMString 类型的枚举

WebAuthn Relying Parties 可以使用该枚举向用户代理传达关于如何最佳完成请求的提示。这些提示不是要求,并不约束用户代理,但可通过 Relying Party 对请求的上下文信息,指导用户代理优化体验。提示按优先级递减的顺序提供,因此若有两个提示冲突,则第一个生效。提示也可能重叠:若定义了更具体的提示,Relying Party 仍可发送较不具体的提示,以便某些可能无法识别更具体提示的用户代理使用。在此情况下,应先发送最具体的提示,再发送较不具体的提示。 若同一提示出现多次,则第二次及其后的均被忽略。

提示可以与凭据中的 transportsauthenticatorAttachment 信息相矛盾。当发生这种情况时,应当以提示为准。(注意,transports 字段在使用 可发现凭据 时不会提供,此时提示是表达此类请求部分方面的唯一方式。)

security-key

表示 责任方 认为用户将用实体安全密钥来满足此请求。例如,企业 责任方 可以在为员工分发了安全密钥并仅允许这些 认证器 用于 注册认证 时设置此提示。

为兼容旧版用户代理,在 PublicKeyCredentialCreationOptions 中使用此提示时,应将 authenticatorAttachment 设置为 cross-platform

client-device

表示 责任方 认为用户将用附属于 客户端设备平台认证器 来完成请求。

为兼容旧版用户代理,在 PublicKeyCredentialCreationOptions 中使用此提示时,应将 authenticatorAttachment 设置为 platform

hybrid

表示 责任方 认为用户会用如智能手机等通用型 认证器 来满足请求。例如,面向消费者的 责任方 认为仅有少部分客户拥有专用安全密钥。此选项也隐含本地 平台认证器 不应在界面中突出显示。

为兼容旧版用户代理,在 PublicKeyCredentialCreationOptions 中使用此提示时,应将 authenticatorAttachment 设置为 cross-platform

5.9. 权限策略集成

本规范定义了两个策略控制功能,由特性标识符标记 "publickey-credentials-create" 和 "publickey-credentials-get"。 它们的默认允许列表都是 'self'。[Permissions-Policy]

Document权限策略决定该文档中的任何内容是否 被允许成功调用Web Authentication API,即通过 navigator.credentials.create({publicKey:..., ...})navigator.credentials.get({publicKey:..., ...}) 。如果在某一文档中被禁用,则此文档中的任何内容都不会被允许使用 上述方法:尝试调用将返回错误

注意:[CREDENTIAL-MANAGEMENT-1]中定义的算法会执行实际的权限策略评估。这是因为这种策略评估需要在能访问当前设置对象时进行。[[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 内部方法没有这样的访问权限,因为它们被CredentialsContainer并行方式调用,相关抽象操作包括创建Credential请求Credential,参考[CREDENTIAL-MANAGEMENT-1]

5.10. iframe 元素内使用 Web Authentication

Web Authentication API 默认在跨源 iframe 中禁用。 若需覆盖此默认策略,并允许跨源 iframe 调用 Web Authentication API[[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 方法, 需在 allow 属性中指定 iframe 元素,同时在 allow 属性的值中分别包含 publickey-credentials-createpublickey-credentials-get 特性标识符令牌。

在嵌入式环境下使用 WebAuthn API 的 责任方 应查阅 § 13.4.2 嵌入式使用的可见性考虑,了解关于 界面修饰 及可能的应对措施。

默认情况下,Web Authentication 要求 RP ID 等于 origin有效域名,或为 可注册域名后缀(registrable domain suffix)。

这会使得在使用多个国家/地区域名(如 example.com、example.co.uk、example.sg)、需支持其它品牌或备用域名(如 myexampletravel.com、examplecruises.com),以及需要平台即服务(PaaS)来支持移动应用等的大型环境中,部署变得具有挑战性。

WebAuthn 责任方 可以选择允许 WebAuthn 客户端 在一组有限的相关 origin 上创建和使用凭据。 这些 责任方 必须选择一个在所有相关 origin 间通用的 RP ID 进行所有流程。

必须在该 webauthn well-known URL([RFC8615])下为 RP ID 提供一个 JSON 文档,并要求通过 HTTPS 服务。此 JSON 文档返回格式如下:

例如,RP ID 为 example.com

{
    "origins": [
        "https://example.co.uk",
        "https://example.de",
        "https://example.sg",
        "https://example.net",
        "https://exampledelivery.com",
        "https://exampledelivery.co.uk",
        "https://exampledelivery.de",
        "https://exampledelivery.sg",
        "https://myexamplerewards.com",
        "https://examplecars.com"
    ]
}

支持该功能的 WebAuthn 客户端 必须至少支持五个 可注册 origin 标签。客户端策略应定义上限以防止滥用。

WebAuthn 客户端 请求此 well-known 端点时,必须不带 凭据、不带 referrer,且须使用 https: 协议。当跟随重定向时,WebAuthn 客户端 必须明确要求所有重定向也使用 https: 协议

支持该功能的 WebAuthn 客户端 应在响应 getClientCapabilities() 时包含 relatedOrigins 字段。

5.11.1. 关联来源验证

关联来源验证过程 ,给定参数 callerOriginrpIdRequested,流程如下:

  1. maxLabels 为客户端策略允许的最多可注册 origin 标签数量。

  2. 以不带凭据、不带referrer,并使用 https: 协议的方式,获取 RP ID rpIdRequestedwebauthn well-known URL [RFC8615](即 https://rpIdRequested/.well-known/webauthn)。

    1. 如果获取失败、响应内容类型不是 application/json、或者最终(跟随重定向后)的状态码不是 200,则抛出 "SecurityError" DOMException

    2. 如果响应体不是合法的 JSON 对象,则抛出 "SecurityError" DOMException

    3. 如果 JSON 对象中的 origins 属性不存在,或不是字符串数组,则抛出 "SecurityError" DOMException

  3. labelsSeen 为一个新的空集合

  4. 对于 origins 中的每一个 originItem

    1. url 为以 originItem 为输入运行 URL 解析器的结果。 如果解析失败,则继续

    2. domainurl有效域名。 如果为 null,则继续

    3. labeldomain可注册 origin 标签

    4. 如果 label 为空或为 null,继续

    5. 如果 labelsSeen 的数量大于等于 maxLabelslabelsSeen包含 label,则继续

    6. 如果 callerOriginurl同源,则返回 true

    7. 如果 labelsSeen 的数量小于 maxLabels,则 label 添加到 labelsSeen

  5. 返回 false

6. WebAuthn 认证器模型

Web Authentication API 隐含了针对 WebAuthn Authenticator 的特定抽象功能模型。本节 描述该 认证器模型

客户端平台 可以用任何方式实现和暴露该抽象模型。但在具体认证器的 Web Authentication API 行为必须与§ 5 Web Authentication API中定义的行为一致,无法区分。

注意:[FIDO-CTAP] 是该模型的具体实例之一,但它返回的数据与 WebAuthn API 算法期望的有所不同。CTAP2 响应消息是使用整数键(而非本规范定义的同对象所用的字符串键)构建的 CBOR 映射。客户端需对这些数据进行所需的转换。[FIDO-CTAP] 规范在 §6. Authenticator API 中详细说明了 CTAP2 整数键和 WebAuthn 字符串键的映射关系。

对于认证器,本模型定义了其必须支持的逻辑操作,以及其向 客户端和 WebAuthn 责任方暴露的数据格式。但并不定义认证器与 客户端设备 的通信细节,除非这些细节与 责任方 的互操作性相关。例如,该抽象模型不定义通过 USB 或 NFC 等传输方式连接认证器与客户端的协议。同理,抽象模型不定义具体错误码或错误返回方式,但会根据客户端需要定义错误行为。因此,具体错误码仅作为说明哪些错误情况必须能区分(或不能区分),以保证客户端实现合规且安全。

责任方如有需要可通过在 创建凭据生成断言时指定认证器相关特性——即通过 凭据创建选项断言生成选项——来影响认证器选择。这些选项会由 WebAuthn API 的底层算法收集,并传递给下方定义的相关 认证器操作

在该抽象模型中,认证器负责密钥管理和加密签名。认证器可嵌入于 WebAuthn 客户端,也可完全独立于客户端设备。认证器内部可含有安全等级高于其余认证器部分的加密模块。这点对嵌入于 WebAuthn 客户端的认证器尤为重要,因为此时该加密模块(例如 TPM)可能比认证器其它部分更可信。

每个认证器存储一个 凭据映射表,是一个 映射,键为 (rpId, userHandle),值为 公钥凭据源

此外,每个认证器都有一个认证器声明全局唯一标识符(Authenticator Attestation Globally Unique Identifier,简称 AAGUID),这是一个128位的标识符, 用于指示认证器的类型(如厂商和型号)。AAGUID 必须由制造商选择,并且在该制造商生产的所有本质相同的认证器间保持一致, 且与其他类型认证器的 AAGUID 高概率不同。给定类型的认证器的 AAGUID 应随机生成以确保这一点。 Relying Party 可以利用 AAGUID 结合其它信息源推断认证器的某些属性, 例如认证级别和密钥保护强度。Relying Party 也可以尝试通过 AAGUID 识别认证器制造商, 而无需请求和验证 声明,但如果没有 声明,AAGUID 并不能被确认为真实。

认证器的核心功能是生成绑定到多种上下文数据的 WebAuthn 签名。 这些数据在签名请求从服务器到认证器的各层被观察并写入。服务器在验证签名时会将这些绑定项与期望值核对。这些上下文绑定项分为两类:一类由 责任方或客户端添加,称为客户端数据;另一类由认证器添加,称为认证器数据。认证器对 客户端数据进行签名,但内容无关。为节省带宽和认证器处理需求,客户端会先对 客户端数据进行哈希处理,仅将结果传递给认证器。认证器最终签名的内容是 序列化客户端数据的哈希值与其自身的 认证器数据 组合。

该设计目标总结如下:

认证器会生成用于两种场景的加密签名:

  1. 当通过 authenticatorMakeCredential 操作创建新的 公钥凭据时,会生成一个 声明签名(attestation signature)。声明签名为认证器及凭据的某些属性提供加密证明。例如,声明签名 弹性认证器类型(如其 AAGUID)及 凭据公钥声明签名由选择的 声明私钥签名,具体键由要求的 声明类型决定。 关于声明的更多信息见 § 6.5 声明

  2. 调用 authenticatorGetAssertion 方法时会生成一个 断言签名。其代表认证器对用户已对此操作(如登录或支付)同意的声明。因此,断言签名表示认证器拥有某个 凭据私钥且已经确认、在合理能力范围内,交易发起者与当初创建凭据同意人是同一用户。此签名还声明了额外信息,如客户端数据,比如如何获得 用户同意,认证器向用户显示的提示等。断言签名格式见 下文图 4

术语 WebAuthn 签名指的是 声明签名断言签名。签名格式和生成流程见下文说明。

6.1. 认证器数据(Authenticator Data)

认证器数据结构编码了由认证器进行的上下文绑定。这些绑定由认证器自身控制,并且其可信度来源于WebAuthn Relying Party对认证器安全属性的评估。在一种极端情况下,认证器可以嵌入在客户端中,其绑定的可信度可能不会比客户端数据更高。另一种极端情况下,认证器可能是具有高安全级别硬件和软件的独立实体,并通过安全通道与客户端连接。在这两种情况下,Relying Party接收的认证器数据格式相同,并利用其对认证器的了解进行信任决策。

认证器数据采用紧凑且可扩展编码格式。这样设计是因为认证器可能是功能有限,低功耗的设备,其软件栈远比客户端平台简单。

认证器数据结构是长度为37字节或以上的字节数组,布局见表格

名称 长度(字节) 描述
rpIdHash 32 RP ID的SHA-256哈希, 凭据作用域
flags 1 标志位(第0位为最低有效位):
signCount 4 签名计数器,32位无符号大端整数。
attestedCredentialData 可变(如存在) 证明凭据数据(如存在)。详见§ 6.5.1 Prove Credential Data。长度取决于 凭据ID长度凭据ID凭据公钥
extensions 可变(如存在) 扩展自定义的认证器数据。这是一个使用扩展标识符为键、认证器扩展输出为值的CBOR [RFC8949]映射。详见§ 9 WebAuthn扩展
认证器数据结构布局。表格中“名称”列仅供本文档参考, 在实际认证器数据表示中并不存在。

RP ID最初是认证器在创建凭据和生成断言时从客户端接收到的。但它与其他客户端数据有重要不同。首先,不像客户端数据,凭据的RP ID在多个操作之间不会变化,而是整个凭据生命周期保持不变。其次,在authenticatorGetAssertion操作时会由认证器验证,必须确保所请求凭据绑定的RP ID客户端提供的RP ID完全一致。

认证器生成认证器数据结构时需执行如下步骤:

展示了认证器数据结构的直观表示。

认证器数据结构布局。
注意: 认证器数据会自行描述长度:若ATED标志未设置,长度固定为37字节。证明凭据数据(仅AT标志设置时出现)会自行描述长度。如果设置了ED标志,总长度为37字节加证明凭据数据长度(如设置AT标志),再加扩展输出(CBOR映射)的长度。

确定证明凭据数据长度(可以变化)时,要先根据前段凭据ID长度确定凭据公钥起始,再确定凭据公钥长度。参见RFC9052 第7节

6.1.1. 签名计数器(Signature Counter)注意事项

认证器应实现签名计数器功能。计数器在认证器中按每个凭据单独存储,或在整个认证器范围内全局存储。某凭据的初始签名计数器值由 signCount (即由认证器数据authenticatorMakeCredential操作中返回)指定。签名计数器会在每次成功 authenticatorGetAssertion操作后递增一个正值,后续的值会再次通过 WebAuthn责任方收到的认证器数据返回。签名计数器主要用于辅助责任方检测认证器克隆,尤其对于保护措施有限的认证器这种检测尤为重要。

未实现签名计数器的认证器,会让 signCount认证器数据中始终为零。

责任方会存储最近一次authenticatorGetAssertion操作的签名计数器。(或如从未对该凭据进行过assertion操作,则保存authenticatorMakeCredential操作时的计数器。)在后续 authenticatorGetAssertion操作时,责任方会将已存的签名计数器和断言的认证器数据中最新返回的 signCount 进行比较。如有非零项,且新 signCount 小于等于存储值,可能存在认证器克隆、认证器故障,或责任方接收到的断言顺序与认证器实际生成顺序不一致。

检测到签名计数器值异常并不能确定本次操作是由克隆认证器还是原认证器完成。责任方应根据自身实际情况针对非递增情况合理应对,如风险容忍度或可能导致该情况的运营因素。

认证器:

6.1.2. FIDO U2F 签名格式兼容性

断言签名(即对认证器数据结构与序列化客户端数据哈希的拼接签名)格式兼容FIDO U2F认证签名格式(参见第5.4节)。

这是因为FIDO U2F认证响应消息中已签名数据的前37字节恰为合法的认证器数据,剩余32字节为序列化客户端数据哈希。该结构中rpIdHash即FIDO U2F的application parameter,除UP外其他flags始终为0,attestedCredentialDataextensions始终不存在。因此,可用本协议的断言签名验证FIDO U2F认证签名。

6.1.3. 凭据备份状态

凭据备份资格与当前备份状态BEBS标志字段表示(详见上表)。

BE 标志authenticatorMakeCredential操作时设定,并且不得更改。

BS 标志可以根据公钥凭据源当前状态变化。下表定义了有效组合及其含义。

BE BS 描述
0 0 该凭据为单设备凭据
0 1 此组合不允许。
1 0 该凭据为多设备凭据且当前未备份
1 1 该凭据为多设备凭据且当前已备份
BEBS 标志位组合

建议责任方将这些标志的最新值与用户账户一起存储,以供后续评估。

以下是责任方可能用于这些标志的部分(非详尽)情形:

6.2. 认证器分类

许多用例依赖于所用认证器的能力。 本节定义了这些能力的部分术语、主要组合及其能支持哪些用例。

例如:

上述示例阐释了认证器类型的主要特征:

这些特征彼此独立,可以任意组合,下表则列举命名了部分有代表性的认证器类型

认证器类型 认证器连接形态 凭据存储形式 认证因子能力
二次因子平台认证器 平台 任意 单因子认证
用户验证平台认证器 平台 任意 多因子认证
二次因子漫游认证器 跨平台 服务端存储 单因子认证
密钥漫游认证器 跨平台 客户端存储 多因子认证
密钥平台认证器 平台 (transport = internal) 或 跨平台 (transport = hybrid) 客户端存储 多因子认证
若干认证器类型名称定义

第二因子平台认证器在同一客户端设备上重新认证时很方便, 可用于新会话启动及恢复已有会话时增加一层安全保护。 第二因子漫游认证器更适合用于首次在某客户端设备认证, 或在多个用户共享的客户端设备上认证。

Passkey 平台认证器Passkey 游走认证器 支持无密码的多因素 认证。 除了证明持有凭证私钥之外, 这些认证器还支持作为第二认证因子用户验证, 通常是 PIN 或生物识别认证器因此可以同时作为两种认证因子, 实现多因素 认证,同时无需与Relying Party共享密码。 这些认证器还支持可发现凭据,也称为Passkey, 即支持无需输入用户名的认证流程。

用户验证平台认证器类型已大部分被Passkey平台认证器替代, 但其定义仍被isUserVerifyingPlatformAuthenticatorAvailable 方法使用。

中未命名的组合,应用场景较少:

下述小节将更详细定义认证器连接类型凭据存储类型认证因子能力的相关方面。

6.2.1. 认证器连接形态

客户端可通过多种机制与认证器通信。例如,客户端可以调用客户端设备专有API与物理绑定于本机的认证器通信。也可以通过标准化的跨平台传输协议(如蓝牙,见§ 5.8.4认证器传输枚举)发现并与跨平台连接认证器通信。本地集成于客户端设备的认证器称为平台认证器,而由跨平台协议可达的则为漫游认证器

某些平台认证器在不同情境下也可能充当漫游认证器。例如,集成于移动设备的平台认证器可以通过蓝牙,把自身作为漫游认证器进行使用。 此时,运行在该移动设备上的客户端会将该认证器识别为平台认证器, 而运行在另一台客户端设备并通过蓝牙与同一认证器通信的客户端则会把它识别为漫游认证器

平台认证器的主要应用场景是注册特定客户端设备为“可信设备”, 这样客户端设备本身就成为未来持有物认证因子,用于日后的认证。 这样用户无需为了后续认证流程(如认证流程)专门准备漫游认证器,例如无需特意去口袋里找钥匙扣或手机。

漫游认证器的使用场景包括: 第一次在新客户端设备认证, 在很少用的客户端设备、 多用户共享的客户端设备, 或者没有集成平台认证器客户端设备; 以及因策略或个人偏好希望认证器与所用的客户端设备分离的情形。 漫游认证器也可用于存储 备份凭据,以备其它认证器丢失时使用。

6.2.2. 凭据存储形式

  1. 在嵌入于认证器客户端客户端设备的持久性存储中,例如在安全元件中。 对于客户端可发现的公钥凭据源属于技术要求。

  2. 通过加密(封装)公钥凭据源,使得仅本认证器才能解密(解封)并将所得密文作为凭据ID凭据ID责任方存储,并通过 allowCredentials 配置项回传给认证器, 用于 get() 操作,从而允许认证器解密并使用公钥凭据源

    这使认证器具有无限凭据存储能力,因为加密后的公钥凭据源责任方而非认证器存储——但这也意味着以此方式存储的凭据在被认证器使用前,必须先从责任方检索回来。

认证器支持哪种存储策略定义了该认证器凭据存储类型,具体如下:

注意:可发现凭据能力认证器可以同时支持两种存储策略。在这种情况下,认证器可自行决定不同凭据采用哪种存储策略,受限于 residentKeyrequireResidentKey 配置项的约束。

6.2.3. 认证因子能力

认证因子中,有三类广泛的方式可在认证流程中用来证明身份:你拥有的东西你知道的东西你本人的特征。例如,物理钥匙、密码和指纹分别属于这三类。

所有WebAuthn 认证器都属于“你拥有的东西”类,但若某个认证器支持用户验证,它也可以充当另外一种或两种认证因子。例如,如果该认证器能验证 PIN,则 PIN 属于“你知道的东西”;而生物识别认证器可验证的则属于“你本人的特征”。因此,支持用户验证认证器被称为支持多因子。相反,不支持多因子的认证器则称为仅支持单因子。注意,一个单一的多因子能力认证器可能支持多种模式的用户验证,这意味着它可以作为三种类型的认证因子

尽管用户验证是在认证器本地执行,而不是由责任方执行,认证器会在返回给责任方的已签名响应中通过设置UV 标志来表明是否进行了用户验证。责任方因此可以使用该UV 标志来验证在某次注册认证流程中是否使用了额外的认证因子。随后,可通过检查认证器的 attestation 声明来评估该 UV 标志的真实性。

6.3. 认证器操作

WebAuthn 客户端必须在调用认证器的任何操作之前与认证器建立连接。该连接定义了一个认证器会话。认证器必须在会话之间保持隔离;它可以通过只允许任意时刻存在一个会话,或提供更复杂的会话管理来实现这一点。

客户端可以在认证器会话中调用下列操作。

6.3.1. 按 Credential ID 查找凭据源 算法

credential id の検索の結果は、credential id credentialIdauthenticator authenticator 内で検索した結果を、以下のアルゴリズムに従って得られたものとする。

  1. 如果 authenticator 能将 credentialId 解密为一个 public key credential source credSource

    1. credSource.id 设为 credentialId

    2. 返回 credSource

  2. 对于 authenticatorcredentials map 中的每个 public key credential source credSource

    1. 如果 credSource.id 等于 credentialId,则返回 credSource

  3. 返回 null

6.3.2. authenticatorMakeCredential 操作

在调用此操作之前,客户端必须先调用authenticatorCancel操作,以中止认证器会话中所有其他正在进行的操作。

该操作接受如下输入参数:

hash

由客户端提供的序列化客户端数据的哈希

rpEntity

责任方的 PublicKeyCredentialRpEntity

userEntity

用户账户的 PublicKeyCredentialUserEntity,包含责任方提供的user handle

requireResidentKey

由客户端确定的用于凭据创建的有效 resident key 要求,布尔值。

requireUserPresence

常量布尔值 true,或当 options.mediation 被设置为 conditional 且用户代理先前已收集到用户同意时为 FALSE

requireUserVerification

由客户端确定的用于凭据创建的有效用户验证要求,布尔值。

credTypesAndPubKeyAlgs

一个由 PublicKeyCredentialType 与公钥算法(COSEAlgorithmIdentifier)配对构成的序列,按优先到不优先排序,表示责任方要求。认证器会尽力创建其能支持的最优先的凭据。

excludeCredentialDescriptorList

一个可选的 PublicKeyCredentialDescriptor 对象列表,由责任方提供,意在若认证器已知其中任何一项,则不应创建新凭据。excludeCredentialDescriptorList 包含一组已知凭据。

enterpriseAttestationPossible

布尔值,指示认证器可能返回可识别个人的 attestation。

attestationFormats

一系列字符串,表示责任方对 attestation 声明格式的偏好(从最偏好到最不偏好)。若认证器返回 attestation,则会尽力使用其支持的最偏好的格式。

extensions

一个由客户端根据责任方请求的扩展构建的 CBOR 映射(有序映射),键为扩展标识符,值为对应的认证器扩展输入。

当调用此操作时,认证器必须执行以下过程:

  1. 检查所有提供的参数是否在语法上是良构且长度正确。若不是,返回等价于 "UnknownError" 的错误码并终止操作。

  2. 检查 credTypesAndPubKeyAlgs 中是否至少有一组 PublicKeyCredentialType 与加密参数的组合是受支持的。若没有,返回等价于 "NotSupportedError" 的错误码并终止操作。

  3. 对于 excludeCredentialDescriptorList 中的每个 descriptor

    1. 如果在此认证器中 查找 descriptor.id 返回非空,且返回项的 RP ID 与类型分别与 rpEntity.idexcludeCredentialDescriptorList.type 匹配,则收集一个包含授权手势以确认用户同意创建新凭据。该授权手势必须包含一个用户在场测试。若用户

      确认同意创建新凭据

      返回等价于 "InvalidStateError" 的错误码并终止操作。

      不同意创建新凭据

      返回等价于 "NotAllowedError" 的错误码并终止操作。

      注意:授权手势 的目的并不是继续创建凭据, 而是出于隐私原因,授权披露 descriptor.id 与该 绑定凭据相关的 认证器这一事实。 如果用户同意,客户端Relying Party 可以检测到这一点,并引导用户使用其他 认证器。 如果用户不同意, 认证器不会披露 descriptor.id 与其 绑定凭据相关的事实, 并会响应为用户拒绝创建凭据的情形。

  4. 如果 requireResidentKeytrue 且认证器不能存储客户端可发现的凭据源,则返回等价于 "ConstraintError" 的错误码并终止操作。

  5. 如果 requireUserVerificationtrue 且认证器不能执行用户验证,则返回等价于 "ConstraintError" 的错误码并终止操作。

  6. 一旦授权手势 完成并取得用户同意,生成新的凭据对象:

    1. 令 (publicKey, privateKey) 为一对新的密钥,使用 credTypesAndPubKeyAlgs 中第一个该认证器支持的 PublicKeyCredentialType 与加密参数组合生成。

    2. userHandleuserEntity.id

    3. credentialSource 为一个新的 public key credential source,其字段如下:

      type

      public-key.

      privateKey

      privateKey

      rpId

      rpEntity.id

      userHandle

      userHandle

      otherUI

      认证器选择包含的任何其他信息。

    4. 如果 requireResidentKeytrue 或认证器选择创建一个客户端可发现的凭据源:

      1. credentialId 为一个新的 credential id

      2. credentialSource.id 设为 credentialId

      3. credentials 为该认证器的 credentials map

      4. credentials[(rpEntity.id, userHandle)] 设为 credentialSource

    5. 否则:

      1. credentialId 为序列化并加密 credentialSource 的结果,以便只有该认证器能解密它。

  7. 如果在创建新凭据对象期间发生任何错误,返回等价于 "UnknownError" 的错误码并终止操作。

  8. processedExtensions 为对 extensions 中每个受支持的扩展标识符 → 认证器扩展输入 执行认证器扩展处理 的结果。

  9. 如果该认证器

    是 U2F 设备

    则新凭据的签名计数器值设为零。(U2F 设备可能支持签名计数器,但在创建凭据时不返回计数器。)

    支持全局签名计数器

    在生成authenticator data 时使用全局签名计数器的实际值。

    支持按凭据的签名计数器

    为该计数器分配资源,将其与新凭据关联,并将计数器初始值设为零。

    不支持签名计数器

    则新凭据的签名计数器值始终为零。

  10. attestedCredentialData 为包含 credentialIdpublicKeyattested credential data 字节数组。

  11. attestationFormatattestationFormats 中第一个受支持的 attestation statement format identifier,同时考虑 enterpriseAttestationPossible。若 attestationFormats 不包含受支持的值,则令 attestationFormat 为该认证器最偏好的 attestation 格式标识符。

  12. authenticatorData 为在 § 6.1 Authenticator Data 中指定的字节数组,包括作为 attestedCredentialDataattestedCredentialData 与(若有)作为 extensionsprocessedExtensions

  13. 使用在 § 6.5.4 Generating an Attestation Object 中指定的过程、选定的attestation statement format attestationFormat,以及值 authenticatorDatahash(并根据 enterpriseAttestationPossible 的值进行考虑),为新凭据创建一个attestation object。有关 attestation 的更多细节,见 § 6.5 Attestation

在成功完成此操作后,认证器将attestation object 返回给客户端。

6.3.3. authenticatorGetAssertion 操作

在调用此操作之前,客户端必须先调用authenticatorCancel操作,以中止认证器会话中所有其他正在进行的操作。

该操作接受如下输入参数:

rpId

调用方的 RP ID,由用户代理和客户端确定

hash

由客户端提供的序列化客户端数据的哈希

allowCredentialDescriptorList

一个可选的由 PublicKeyCredentialDescriptor 组成的列表,描述责任方可接受的凭据(可能由客户端过滤),如果有的话。

requireUserPresence

常量布尔值 true。 这里作为伪参数包含,是为了简化将此抽象认证器模型应用于可能希望将用户在场测试设为可选的实现,虽然 WebAuthn 并未设为可选。

requireUserVerification

由客户端提供的用于断言的有效用户验证要求,布尔值。

extensions

一个由客户端根据责任方请求的扩展构建的 CBOR 映射(有序映射),键为扩展标识符,值为对应的认证器扩展输入。

当此方法被调用时,认证器 必须执行以下过程:

  1. 检查所有提供的参数是否在语法上良构且长度正确。若不是,返回等价于 "UnknownError" 的错误码并终止操作。

  2. credentialOptions 为一个新的空的集合,用于存放public key credential sources

  3. 如果提供了 allowCredentialDescriptorList,则对于其每个 descriptor

    1. credSource 为在本认证器中 查找 descriptor.id 的结果。

    2. credSource 非空,则将其追加credentialOptions

  4. 否则(未提供 allowCredentialDescriptorList),对于该认证器的 credentials map 中的每个 keycredSource,将 credSource 追加到 credentialOptions

  5. credentialOptions 中移除其 rpId 不等于 rpId 的任何项。

  6. 如果此时 credentialOptions 为空,返回等价于 "NotAllowedError" 的错误码并终止操作。

  7. 提示用户从 credentialOptions 中选择一个 public key credential source 作为 selectedCredential。同时收集确认使用该 selectedCredential授权手势以确认用户同意。若认证器具备输出能力,则提示可由认证器显示,否则由用户代理显示。

    requireUserVerificationtrue,则授权手势必须包含用户验证

    requireUserPresencetrue,则授权手势必须包含一次用户在场测试

    若用户不同意,返回等价于 "NotAllowedError" 的错误码并终止操作。

  8. processedExtensions 为对 extensions 中每个受支持的扩展标识符 → 认证器扩展输入 执行认证器扩展处理 的结果。

  9. 按认证器采用的策略,将与所选凭据关联的按凭据的签名计数器或全局签名计数器递增某个正值。如果认证器不实现签名计数器,则让签名计数器值保持为零。

  10. authenticatorData 为在 § 6.1 Authenticator Data 中指定的字节数组,包括(若有)作为 extensionsprocessedExtensions,并排除 attestedCredentialData

  11. signature 为使用 selectedCredentialprivateKey 对串联 authenticatorData || hash 生成的断言签名。如图所示,简单无分隔的串联是安全的,因为认证器数据自述其长度,而序列化客户端数据的哈希总是最后一个元素。

    生成断言签名
  12. 若在生成断言签名期间发生任何错误,返回等价于 "UnknownError" 的错误码并终止操作。

  13. 向用户代理返回:
    • 如果客户端提供的 allowCredentialDescriptorList 长度大于等于 2,或未提供该列表,则返回 selectedCredential.id

      注:若客户端在 allowCredentialDescriptorList 中仅提供了恰好一个凭据且它被成功使用,则不会返回其凭据 ID,因为客户端已经知道它,这在可能受限的连接上节省了传输字节。

    • authenticatorData

    • signature

    • selectedCredential.userHandle

      注:在提供了 allowCredentialDescriptorList 的情况下,返回的 userHandle 值可能为 null,参见:userHandleResult

如果认证器找不到任何与指定标准相符且对应于指定责任方凭据,则终止操作并返回错误。

6.3.4. authenticatorCancel 操作

此操作不接受输入参数,也不返回结果。

当客户端在一个认证器会话中调用此操作时,会终止该会话中任何正在进行的 authenticatorMakeCredentialauthenticatorGetAssertion 操作。认证器停止提示或接受与已取消操作相关的任何用户输入。客户端忽略来自认证器关于已取消操作的任何后续响应。

如果在一个没有正在进行的 authenticatorMakeCredentialauthenticatorGetAssertion 操作的认证器会话中调用此操作,则会被忽略。

6.3.5. silentCredentialDiscovery 操作

这是一个认证器可选支持的操作,以启用 conditional 用户介入的中介

它接受以下输入参数:

rpId

调用方的 RP ID,由客户端确定。

当调用此操作时,认证器 必须执行以下过程:

  1. collectedDiscoverableCredentialMetadata 为一个新的列表,其项为 DiscoverableCredentialMetadata 结构体,包含下列字段:

    type

    一个 PublicKeyCredentialType

    id

    一个 Credential ID

    rpId

    一个 Relying Party Identifier

    userHandle

    一个 user handle

    otherUI

    认证器用以在其 UI 中提供信息的其他内容。

  2. 对于该认证器的 credentials map 中的每个 public key credential source credSource

    1. 如果 credSource 不是客户端可发现的凭据,则继续下一个项。

    2. 如果 credSource.rpId 不等于 rpId,则继续下一个项。

    3. discoveredCredentialMetadata 为一个新的 DiscoverableCredentialMetadata 结构体,其字段为 credSourcetypeidrpIduserHandleotherUI 的副本。

    4. discoveredCredentialMetadata 追加到 collectedDiscoverableCredentialMetadata

  3. 返回 collectedDiscoverableCredentialMetadata

6.4. 字符串处理

认证器可能需要存储由责任方选择的任意字符串,例如在namedisplayName 在一个 PublicKeyCredentialUserEntity 中。 本节讨论处理可能呈现给人的任意字符串的一些实际后果。

6.4.1. 字符串截断

API 中的每个任意字符串都需要对可能在认证器上可用的有限资源做出某种适配。 当所选的适配方式是字符串截断时,需要小心避免损坏字符串值。

例如,仅基于 Unicode 代码点的截断可能会导致一个字形簇被截断。 这可能会使该字形簇渲染为不同的字形,从而可能改变字符串的含义,而不是完全移除该字形。 例如, 显示了一个 UTF-8 编码字符串末尾,其编码为 65 字节长。 如果截断到 64 字节,则首先移除末尾的 0x88 字节以满足大小限制。 由于那会留下不完整的 UTF-8 代码点,该代码点的其余部分也必须被移除。 由于那会留下不完整的字形簇,该字形簇的其余部分也应被移除。

UTF-8 编码字符串末尾,显示不同截断边界的位置。

处理这些问题的责任主要落在客户端,以避免给认证器带来理解字符编码和 Unicode 字符属性的负担。 以下小节定义了客户端和认证器各自可能执行字符串截断时的要求。

6.4.1.1. 客户端进行的字符串截断

WebAuthn 客户端 截断字符串时, 截断行为在可被责任方观察到时必须满足下列要求:

选择一个大于或等于指定最小支持长度的大小限制。 可以截断字符串,使其在 UTF-8 字符编码下的字节长度满足该限制。 此截断必须尊重 UTF-8 代码点边界,并且应当尊重字形簇边界 [UAX29]。 由此得到的截断值可能短于所选的大小限制, 但不得短于满足大小限制且在字形簇边界处结束的最长前缀子字符串。

如果认证器满足这些要求,客户端可以让认证器执行截断; 否则客户端必须在将字符串值转发给认证器之前执行截断。

此外,仅在字节边界上截断会引起一个已知问题,用户代理应注意:如果认证器使用[FIDO-CTAP],那么来自认证器的后续消息可能包含无效的 CBOR,因为该值被标记为 CBOR 字符串,因此要求为有效的 UTF-8。因此,在与认证器交互时,用户代理应当:

  1. 确保发送到认证器的任何字符串都是有效编码的。

  2. 处理字符串被截断导致编码无效的情况。例如,可以丢弃末尾的任何不完整代码点,或用 U+FFFD 替换之。

6.4.1.2. 认证器进行的字符串截断

因为WebAuthn 认证器可能在受限环境中实现, 相较于对客户端的要求,对认证器的要求更宽松。

WebAuthn 认证器截断字符串时, 截断行为必须满足下列要求:

选择一个大于或等于指定最小支持长度的大小限制。 可以截断字符串,使其在 UTF-8 字符编码下的字节长度满足该限制。 此截断应当尊重 UTF-8 代码点边界,并且可以尊重字形簇边界 [UAX29]。 由此得到的截断值可能短于所选的大小限制, 但不得短于满足大小限制且在字形簇边界处结束的最长前缀子字符串。

6.4.2. 语言与方向编码

为了在上下文中正确显示,字符串的语言和基础方向可能是必需的信息。API 中的字符串可能需要写入固定功能的认证器,然后在不同平台上读取并显示。

为与现有不支持专用语言和方向元数据字段的固定功能认证器兼容, Web Authentication Level 2 包含了将此类元数据嵌入字符串本身的规定,以确保它以原子方式传输。 该编码并不推荐;客户端认证器可以在新值中忽略这种编码。 客户端认证器可以检测并处理现有字符串中按 Web Authentication Level 2 §6.4.2. Language and Direction Encoding 所述编码的语言和方向元数据。

相反,未来版本的Web Authentication API可能提供专用的语言与方向元数据字段。

6.5. 声明(Attestation)

认证器如果可能,应当也提供某种形式的声明。 如果认证器提供声明,基本要求是对于每个凭据公钥,认证器能够生成一个可被WebAuthn 责任方验证的声明语句。通常,这个声明语句包含使用声明私钥对被证明的凭据公钥和一个挑战进行签名的签名,以及提供声明公钥证明来源信息的证书或类似数据, 使责任方能够做出信任决策。然而,如果不存在声明密钥对,则认证器可以使用相应的凭据私钥凭据公钥执行自我声明,或不执行任何声明(无声明)。所有这些信息都会在每次生成新的公钥凭据时由认证器返回,整体形式为一个attestation objectattestation object 与包含attested credential dataauthenticator data以及attestation statement之间的关系如下面的所示。

如果某个认证器采用自我声明无声明,则不会为责任方提供可用于做出信任决策的来源信息。在这些情况下,认证器并不能向责任方提供关于其操作的保证。

Attestation object 布局,说明所包含的authenticator data(包含attested credential data)和attestation statement
注: 该图仅示例了 packed attestation statement format。在 § 8 已定义的 Attestation Statement Formats 中定义了其它若干attestation statement formats

attestation object 的一个重要组成部分是 attestation statement。这是一个特定类型的已签名数据对象,包含关于公钥凭据自身以及创建该凭据的认证器的陈述。它包含使用声明机构密钥创建的attestation signature(自我声明情形除外,在自我声明时使用的是凭据私钥)。为了正确解释attestation statement责任方需要理解与声明相关的两个方面:

  1. attestation statement format 是认证器将签名表示为特定形式并将各种上下文绑定纳入声明语句的方式。换言之,它定义了语句的语法。各种已有组件和操作系统平台(例如 TPM 与 Android OS)此前已经定义了attestation statement formats。本规范以可扩展方式支持多种此类格式,如在 § 6.5.2 Attestation Statement Formats 中定义的那样。格式本身由字符串标识,如 § 8.1 Attestation Statement Format Identifiers 所述。

  2. 声明类型定义了声明语句及其底层信任模型的语义。 具体来说,它规定了Relying Party在验证某个声明语句的加密有效性后,如何建立对该声明语句的信任。 本规范支持若干种声明类型,详见 § 6.5.3 声明类型

一般而言,attestation statement formatsattestation types 之间没有简单的映射关系。例如,在 § 8.2 Packed Attestation Statement Format 中定义的“packed”attestation statement format可以与所有attestation types结合使用,而其它格式和类型的适用性则更有限。

声明的隐私、安全和操作特性取决于:

attestation typeattestation statement format认证器选择; 责任方只能通过设置 attestationattestationFormats 参数来表明其偏好。

预计大多数认证器将支持少量的attestation typesattestation statement formats,而责任方将根据策略决定可接受的attestation types责任方还需要根据他们所掌握的关于这些认证器的信息来理解其所信任的认证器的特性。例如,FIDO 元数据服务 [FIDOMetadataService] 提供了一种获取此类信息的途径。

6.5.1. 被证明的凭据数据(Attested Credential Data)

被证明的凭据数据是一个可变长度字节数组, 在为凭据生成attestation object时被加入到authenticator data中。其格式如 所示。

名称 长度(字节) 描述
aaguid 16 认证器的AAGUID
credentialIdLength 2 表示credentialId的字节长度 L,为 16 位无符号大端整数。该值必须 ≤ 1023。
credentialId L Credential ID
credentialPublicKey 可变 以 COSE_Key 格式编码的凭据公钥,如 Section 7 所定义,使用 CTAP2 规范 CBOR 编码形式。 COSE_Key 编码的凭据公钥必须包含 "alg" 参数并且不得包含其它可选参数。"alg" 参数必须包含一个 COSEAlgorithmIdentifier 值。 编码的凭据公钥还必须包含相关密钥类型规范所要求的任何额外必需参数,即对密钥类型 "kty" 和算法 "alg" 的必需参数(参见 RFC9053 第2节)。
被证明的凭据数据 布局。表中“名称”列仅供本文档参考,并不出现在实际的attested credential data 表示中。
6.5.1.1. 以 COSE_Key 格式编码的 credentialPublicKey 值示例

本节提供了用于 ES256、PS256 和 RS256 签名算法的 COSE_Key 编码的椭圆曲线与 RSA 公钥示例。这些示例遵循上文对credentialPublicKey 值规定的规则,并以 CDDL 表示以便清晰说明。

RFC9052 第7节 定义了所有 COSE_Key 编码密钥的一般框架。 特定算法的具体密钥类型在 RFC9053 中定义,及其它规范中也有说明。

下面是一个使用 P-256 曲线、用于 ES256 签名算法(ECDSA w/ SHA-256)的 COSE_Key 编码的椭圆曲线公钥(EC2 格式)示例(参见 RFC9053 第7.1节):

{
  1:   2,  ; kty: EC2 key type
  3:  -7,  ; alg: ES256 signature algorithm
 -1:   1,  ; crv: P-256 curve
 -2:   x,  ; x-coordinate as byte string 32 bytes in length
           ; e.g., in hex: 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d
 -3:   y   ; y-coordinate as byte string 32 bytes in length
           ; e.g., in hex: 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c
}

下面是上述椭圆曲线公钥以 CTAP2 规范 CBOR 编码形式 编码的表示,出于清晰起见此处保留空白和换行以匹配上面的 CDDL 表示:

A5
   01  02

   03  26

   20  01

   21  58 20   65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d

   22  58 20   1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c

下面是一个 COSE_Key 编码的 2048 位 RSA 公钥示例(参见 RFC8230 第4节),用于 PS256 签名算法(RSASSA-PSS with SHA-256):

{
  1:   3,  ; kty: RSA key type
  3: -37,  ; alg: PS256
 -1:   n,  ; n:   RSA modulus n byte string 256 bytes in length
           ;      e.g., in hex (middle bytes elided for brevity): DB5F651550...6DC6548ACC3
 -2:   e   ; e:   RSA public exponent e byte string 3 bytes in length
           ;      e.g., in hex: 010001
}

下面是与上例相同的 COSE_Key 编码 RSA 公钥示例,用于 RS256 签名算法(RSASSA-PKCS1-v1_5 with SHA-256):

{
  1:   3,  ; kty: RSA key type
  3:-257,  ; alg: RS256
 -1:   n,  ; n:   RSA modulus n byte string 256 bytes in length
           ;      e.g., in hex (middle bytes elided for brevity): DB5F651550...6DC6548ACC3
 -2:   e   ; e:   RSA public exponent e byte string 3 bytes in length
           ;      e.g., in hex: 010001
}

6.5.2. 声明语句格式(Attestation Statement Formats)

如上所述,attestation statement format 是一种数据格式,用于表示认证器对一组上下文绑定的加密签名。每一种attestation statement format 必须使用下面的模板来定义:

初始的指定的attestation statement formats 列表见 § 8 已定义的 Attestation Statement Formats

6.5.3. 声明类型(Attestation Types)

WebAuthn 支持若干attestation types,它们定义了attestation statements及其底层信任模型的语义:

注:本规范并不定义任何明确表示由认证器所采用的attestation types 的数据结构。进行attestation statement 验证的责任方——即在调用 navigator.credentials.create() 时选择了非 none 的 attestation conveyance,并验证收到的attestation statement——将在验证过程中确定所采用的attestation type。参见 § 8 已定义的 Attestation Statement Formats 中“验证过程”小节。另见 § 14.4.1 声明隐私。对于本节中定义的除 SelfNone 之外的所有attestation types,在完成verification 后,责任方应将信任路径匹配到可接受的根证书,参考 第 23 步§ 7.1 注册新凭据)。区分这些attestation types 主要用于根据责任方策略判断声明是否可接受。

基本声明(Basic Attestation) (Basic)

在基本声明的情况下(参见 [UAFProtocol]),认证器的声明密钥对 针对某一认证器“型号”(即一批认证器)。因此,同一或相似型号的认证器常常共享相同的声明密钥对。关于更多信息参见 § 14.4.1 声明隐私

基本声明 也称为 批量声明

自我声明(Self Attestation) (Self)

自我声明(亦称为代理基本声明)的情况下,认证器没有任何特定的声明密钥对。相反,它使用凭据私钥 来创建attestation signature。缺乏对声明私钥具有有意义保护措施的认证器通常使用这种声明类型。

声明 CA(Attestation CA) (AttCA)

在此情况下,认证器基于受信任的平台模块(TPM)并持有认证器特定的“endorsement key”(EK)。该密钥用于与受信任第三方——Attestation CA(也称为“Privacy CA”)——安全通信(参见 [TCG-CMCProfile-AIKCertEnroll])。认证器可以生成多个声明身份密钥对(AIK),并请求 Attestation CA 为每个 AIK 签发 AIK 证书。采用此方法时,此类认证器可以将 EK(作为全局关联句柄)的暴露限制在 Attestation CA(们)之内。AIK 可以为每个认证器生成的公钥凭据单独请求,并作为attestation certificates 传递给责任方

注:该概念通常导致多个声明证书。最近请求的声明证书称为“活动”的(active)。

匿名化 CA(Anonymization CA) (AnonCA)

在此情况下,认证器使用一个匿名化 CA,该 CA 动态为每个凭据生成attestation certificates,以致于呈现给责任方attestation statements不提供可用于唯一识别或跟踪的信息。

注:传达 attestation statements 的数据结构对于类型为 AttCAAnonCA 的声明与类型为 Basic 的声明使用相同的数据结构,因此这三种声明类型通常只能依赖外部提供的关于attestation certificates 内容的知识来区分。

无声明(None

在此情况下,不存在任何声明信息。另见 § 8.7 None Attestation Statement Format

6.5.4. 生成 Attestation Object

要生成一个attestation object(见:图 6) 给定:

attestationFormat

一个attestation statement format

authData

一个包含authenticator data的字节数组。

hash

序列化客户端数据的哈希(client data hash)。

认证器必须:

  1. attStmt 为基于 authDatahash 运行 attestationFormat签名过程 的结果。

  2. fmtattestationFormatattestation statement format 标识符

  3. 作为 CBOR 映射返回 attestation object,其语法如下并用本算法初始化的变量填充:

    attObj = {
        authData: bytes,
    
        ; Each choice in $$attStmtType defines the fmt value and attStmt structure
        $$attStmtType
    } .within attStmtTemplate
    
    attStmtTemplate = {
        authData: bytes,
        fmt: text,
        attStmt: (
          { * tstr => any } ; Map is filled in by each concrete attStmtType
          //
          [ * any ]         ; attStmt may also be an array
        )
    }
    

6.5.5. Packed 声明、FIDO U2F 声明及断言签名的签名格式

建议任何新定义的声明格式不要使用 ASN.1 编码,而应将签名表示为等效的固定长度字节数组且内部无结构,使用与 COSE 签名在 RFC9053RFC8230 中定义的相同表示法。

下列签名格式定义满足此要求,并可作为为未在此显式提及的其他签名算法推导相同格式的示例:

7. WebAuthn Relying Party 操作

A 注册认证流程 开始于 WebAuthn 依赖方 分别创建一个 PublicKeyCredentialCreationOptionsPublicKeyCredentialRequestOptions 对象,该对象对该流程的参数进行编码。依赖方在此阶段 SHOULD 注意不要泄露敏感信息;详情请参见 § 14.6.2 用户名枚举

在成功执行 create()get() 之后, 依赖方的脚本会从客户端接收一个包含 AuthenticatorAttestationResponseAuthenticatorAssertionResponse 结构的 PublicKeyCredential。随后必须将该结构的内容传递给依赖方服务器,使用本规范范围之外的方法。此节描述依赖方在收到这些结构后必须执行的操作。

7.1. 注册新凭证

为了执行一次 注册流程依赖方 MUST 按照下述步骤进行:

  1. options 为一个新的 CredentialCreationOptions 结构,按依赖方对该流程的需求进行配置。令 pkOptionsoptions.publicKey

  2. 调用 navigator.credentials.create() 并将 options 作为参数传入。令 credential 为成功解析的 promise 的结果。 如果 promise 被拒绝,则以对用户可见的错误中止该流程,或根据被拒绝的 promise 中可得的上下文,引导用户体验。例如,如果 promise 被以等同于 "InvalidStateError" 的错误码拒绝,用户可能被指示使用不同的 认证器。 有关不同错误上下文及导致这些错误的情况的信息,见 § 6.3.2 authenticatorMakeCredential 操作

  3. responsecredential.response。 如果 response 不是 AuthenticatorAttestationResponse 的实例, 则以对用户可见的错误中止该流程。

  4. clientExtensionResults 为调用 credential.getClientExtensionResults() 的结果。

  5. JSONtext 为对 response.clientDataJSON 的值运行 UTF-8 解码 的结果。

    Note: 使用任何实现的 UTF-8 解码 都是可以的,只要其结果与规范中 UTF-8 解码 算法的结果相同。特别地,任何前导字节顺序标记 (BOM) 必须被剥离。

  6. C,即在凭证创建期间声称已收集的 客户端数据,为对 JSONtext 运行实现特定的 JSON 解析器的结果。

    Note: C 可以是任何实现特定的数据结构表示,只要 C 的组件可被引用,以满足本算法的要求。

  7. 验证 C.type 的值为 webauthn.create

  8. 验证 C.challenge 的值等于 pkOptions.challenge 的 base64url 编码。

  9. 验证 C.origin 的值为依赖方期望的 origin。 参见 § 13.4.9 验证凭证的来源 以获取指导。
  10. 如果 C.crossOrigin 存在且为 true, 验证依赖方期望该凭证是在一个与其父级非 祖先不同源 的 iframe 中创建的。

  11. 如果 C.topOrigin 存在:

    1. 验证依赖方期望该凭证是在一个与其父级非 祖先不同源 的 iframe 中创建的。

    2. 验证 C.topOrigin 的值与依赖方期望被子框架化的页面的 origin 匹配。 参见 § 13.4.9 验证凭证的来源 以获取指导。

  12. hash 为对 response.clientDataJSON 使用 SHA-256 计算哈希的结果。

  13. attestationObject 字段进行 CBOR 解码,以从 AuthenticatorAttestationResponse 结构中获取声明的格式 fmt认证器数据 authData,以及声明语句 attStmt

  14. 验证 rpIdHashauthData 中是依赖方期望的 RP ID 的 SHA-256 哈希。

  15. 如果 options.mediation 未设置为 conditional, 验证 UP 位在 flags 中被设置。

  16. 如果依赖方要求此注册进行 用户验证, 验证 UV 位在 flags 中被设置。

  17. 如果 BE 位在 flags 中未被设置, 验证 BS 位也未被设置。

  18. 如果依赖方使用凭证的 备份资格 来指导其用户体验流程和/或策略,请评估 BE 位在 flags 中的值。

  19. 如果依赖方使用凭证的 备份状态 来指导其用户体验流程和/或策略,请评估 BS 位在 flags 中的值。

  20. 验证 authDatacredential public key 的 "alg" 参数是否匹配 alg 属性与 pkOptions.pubKeyCredParams 中某一项的 items 相匹配。

  21. 通过对 fmt 进行区分大小写的 US-ASCII 比对,确定声明语句格式是否为受支持的 WebAuthn Attestation Statement Format Identifier 之一。已注册的 WebAuthn Attestation Statement Format Identifier 值的最新列表由 IANA 的 "WebAuthn Attestation Statement Format Identifiers" 注册表维护,参见 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)。

  22. 使用声明语句格式 fmt 的验证过程对 attStmt 进行验证,确保证明语句 attStmt 是正确的、并传达了有效的 attestation 签名,验证过程以 attStmtauthDatahash 为输入。

    Note: 每个 声明语句格式 指定其自己的 验证过程。见 § 8 已定义的声明语句格式 以获取初始定义的格式,及 [IANA-WebAuthn-Registries] 以获取最新列表。

  23. 如果验证成功,从可信来源或策略中获取该 attestation 类型和声明语句格式 fmt 所接受的信任锚列表(即 attestation 根证书)。例如,FIDO 元数据服务 [FIDOMetadataService] 提供了一种获取此类信息的方法,可使用 aaguid,该字段位于 attestedCredentialData 中的 authData
  24. 使用在第 21 步 中验证过程的输出评估 attestation 的可信性,如下所示:
    • 如果未提供 attestation,验证在依赖方政策下接受 None attestation 是否可接受。

    • 如果使用了 self attestation,验证在依赖方政策下是否接受 self attestation

    • 否则,使用作为验证过程输出返回的 X.509 证书作为 attestation trust path,以验证 attestation 公钥要么正确地链向可接受的根证书,要么本身就是可接受的证书(即其与在 第 22 步 中获取的根证书可能相同)。

    如果 attestation 语句被视为不可信,依赖方 SHOULD 使该 注册流程 失败。

    NOTE: 然而,如果政策允许,依赖方 MAY 注册该 credential ID 和凭证公钥,但将该凭证视为具有 self attestation(见 § 6.5.3 Attestation Types)。如果这样做,依赖方即在断言没有加密证明表明该公钥凭证是在特定认证器型号上生成的。详见 [FIDOSecRef][UAFProtocol] 以获取更详细的讨论。

  25. 验证 credentialId 的长度 ≤ 1023 字节。超过此长度的 Credential ID SHOULD 导致依赖方使本次 注册流程 失败。

  26. 验证 credentialId 尚未为任何用户注册。如果该 credentialId 已知,则依赖方 SHOULD 使本次 注册流程 失败。

    Note: 依赖方拒绝重复 credential IDs 的理由如下: credential IDs 含有足够的熵,意外重复的可能性极低。然而,除 self attestation 之外的 attestation 类型并不包含自签名以在注册时明确证明对凭证私钥的占有。因此,一个已经获得某站点用户的 credential ID 和凭证公钥的攻击者(这可能通过各种方式实现)可以尝试将受害者的凭证注册为自己的凭证。如果依赖方接受此新注册并替换了受害者的现有凭证注册,并且凭证是可发现的,那么受害者下一次尝试登录时可能会被迫登录到攻击者的账户。在该状态下受害者保存到站点的数据将可被攻击者访问。

  27. credentialRecord 为一个新的 凭证记录,其包含如下内容:
    type

    credential.type

    id

    credential.idcredential.rawId, 以依赖方偏好的格式为准。

    publicKey

    authData 中的 凭证公钥

    signCount

    authData.signCount

    uvInitialized

    UV 标志在 authData 中的值。

    transports

    response.getTransports() 返回的值。

    backupEligible

    authDataBE 标志的值。

    backupState

    authDataBS 标志的值。

    新的 凭证记录 也 MAY 包含以下可选内容:

    attestationObject

    response.attestationObject

    attestationClientDataJSON

    response.clientDataJSON

    rpId

    pkOptions.rp.id

    依赖方 MAY 还包含任何附加的结构项(struct items)根据需要。 作为非规范性的示例,依赖方可能允许用户为凭证设置一个“昵称”以帮助用户记住在账户设置中哪个 credential 与哪个 认证器 绑定。

  28. 根据依赖方的要求,处理 clientExtensionResults 中的 客户端扩展输出authDataextensions 中的 认证器扩展输出。 根据每个扩展,处理步骤可能被具体规定,或者由依赖方决定如何处理扩展输出。依赖方 MAY 忽略任何或全部扩展输出。

    客户端 MAY 设置额外的 认证器扩展客户端扩展, 从而导致在 认证器扩展输出客户端扩展输出 中出现依赖方在 pkOptions.extensions 中未请求的值。依赖方 MUST 准备好处理这种情况,或通过忽略未请求的扩展,或通过拒绝 attestation 来应对。依赖方可以基于本地策略和所使用的扩展来做出决定。

    由于扩展对客户端和认证器均为可选,依赖方 MUST 也准备好处理未执行全部或部分请求扩展的情况。

  29. 如果以上所有步骤都成功,将 credentialRecord 存储在 用户账户 中,该账户由 pkOptions.user 指定,并按适当方式继续 注册流程。否则,使注册流程失败。

    如果依赖方在此情况下不使 注册流程 失败,则依赖方是在接受没有加密学证据证明该 公钥凭证 已由任何特定 认证器 型号生成的事实。依赖方 MAY 将该凭证视为与 无 attestation 等价(见 § 6.5.3 Attestation Types)。 详见 [FIDOSecRef][UAFProtocol] 以获取更详细的讨论。

    验证 attestation 对象 需要依赖方在上述第 22 步 中有一种可信的方法来确定可接受的信任锚。此外,如果使用证书,依赖方 MUST 能够获取中间 CA 证书的证书状态信息。如果客户端未在 attestation 信息中提供证书链,依赖方 MUST 也能构建 attestation 证书链。

7.2. 验证认证断言

为了执行一次认证流程依赖方 MUST 按照如下步骤进行:

  1. options 为新的 CredentialRequestOptions 结构,按依赖方对该流程的需求进行配置。 令 pkOptionsoptions.publicKey

  2. 调用 navigator.credentials.get() 并将 options 作为参数传入。 令 credential 为 successfully resolved 的 promise 的结果。 如果 promise 被拒绝,则以对用户可见的错误中止该流程,或根据被拒绝的 promise 中获得的上下文引导用户体验。不同错误情境导致的说明,参见 § 6.3.3 authenticatorGetAssertion 操作

  3. responsecredential.response。 如果 response 不是 AuthenticatorAssertionResponse 的实例, 则以对用户可见的错误中止该流程。

  4. clientExtensionResults 为调用 credential.getClientExtensionResults() 的结果。

  5. 如果 pkOptions.allowCredentials 不为空, 验证 credential.id 标识的是 公钥凭据 列表中的一项, 该列表为 pkOptions.allowCredentials

  6. 识别被认证的用户,并令 credentialRecord 为该 凭证记录

    如果用户在认证流程开始前已被识别,例如通过用户名或 Cookie,

    验证已识别的 用户账户 包含一个 凭证记录, 且该记录的 id 等于 credential.rawId。 令 credentialRecord 为此 凭证记录。 如果 response.userHandle 存在, 验证其等于该 用户句柄

    如果用户在认证流程开始前未被识别,

    验证 response.userHandle 存在。 验证通过 response.userHandle 识别的 用户账户 包含 凭证记录, 且其 id 等于 credential.rawId。 令 credentialRecord 为该 凭证记录

  7. cDataauthDatasig 分别表示 responseclientDataJSONauthenticatorData、 和 signature 的值。

  8. JSONtext 为对 cData 运行 UTF-8 解码 的结果。

    Note: 只要与 UTF-8 解码 算法一致,可用任何实现的解码方式。特别地,必须移除任何首部字节顺序标记 (BOM)。

  9. C,即用于签名声明的 客户端数据,为对 JSONtext 运行实现相关 JSON 解析器的结果。

    Note: C 可以为任意实现相关的数据结构表示,只要 C 组件可被算法引用。

  10. 验证 C.type 的值为字符串 webauthn.get

  11. 验证 C.challenge 的值等于 pkOptions.challenge 的 base64url 编码。

  12. 验证 C.origin 的值为依赖方期望的 origin。 参见 § 13.4.9 验证凭证的来源 以获取指导。
  13. 如果 C.crossOrigin 存在且为 true, 验证依赖方期望此凭证是在与祖先不同源的 iframe 中使用的。

  14. 如果 C.topOrigin 存在:

    1. 验证依赖方期望此凭证是在与祖先不同源的 iframe 中使用的。

    2. 验证 C.topOrigin 的值与依赖方期望被子框架化页面的 origin 匹配。参见 § 13.4.9 验证凭证的来源 获取指导。

  15. 验证 authDatarpIdHash 是否是依赖方期望的 RP ID 的 SHA-256 哈希值。

    Note: 若使用 appid 扩展,此步需特殊逻辑。详见 § 10.1.1 FIDO AppID 扩展(appid)

  16. 验证 authDataUP 位在 flags 中被设置。

  17. 判断本次断言是否需要 用户验证。仅当 pkOptions.userVerification 设置为 required 时,才 SHOULD 要求 用户验证

    如果要求 用户验证,验证 authDataUV 位在 flags 中被设置; 否则,忽略其 UV 标志

  18. 如果 authDataBE 位未被设置,需验证 BS 位未被设置。

  19. 如果凭证的 备份状态 被用作依赖方业务逻辑或策略的一部分, 令 currentBecurrentBs 分别为 authData BEBS 位的值。 并与 credentialRecord.backupEligiblecredentialRecord.backupState 比较:

    1. credentialRecord.backupEligible 被设置,需验证 currentBe 被设置。

    2. credentialRecord.backupEligible 未被设置,需验证 currentBe 未被设置。

    3. 应用依赖方本地策略(如有)。

    Note: 详见 § 6.1.3 凭证备份状态,了解依赖方可如何处理 BS 标志

  20. hash 为对 cData 运行 SHA-256 哈希后的结果。

  21. 利用 credentialRecord.publicKey, 校验 sig 是否为 authDatahash 二进制串联的有效签名。

    注意: 此验证步骤与 FIDO U2F 认证器生成的签名兼容。参见 § 6.1.2 FIDO U2F 签名格式兼容性

  22. authData.signCount 非零,或 credentialRecord.signCount 非零, 则运行如下子步骤:

    • 如果 authData.signCount

      大于 credentialRecord.signCount
      签名计数器有效。
      小于等于 credentialRecord.signCount
      这是一种信号,表明认证器可能已被克隆,但不是证据。例如,这可能意味着:
      • 可能存在两个或更多份凭证私钥,且正在并行使用。

      • 认证器出现故障。

      • 存在竞态条件,即依赖方处理断言响应的顺序与认证器生成时的顺序不一致。

      依赖方应结合自身运维特性将此信息纳入风险评分。 是否在此情况下更新 credentialRecord.signCount ,或是否直接使认证流程失败,由依赖方自行决定。

      签名计数器的更多注意事项,见 § 6.1.1 签名计数器注意事项

  23. 按依赖方需求,处理 clientExtensionResults 中的 客户端扩展输出authDataextensions认证器扩展输出。 对于每个 扩展, 处理步骤可能具体规定,也可能由依赖方自行决定如何处理扩展输出。 依赖方 MAY 忽略任意扩展输出。

    客户端 MAY 设置额外的 认证器扩展客户端扩展, 从而使未被 依赖方pkOptions.extensions 请求的值,出现在 认证器扩展输出客户端扩展输出中。 依赖方 MUST 准备好处理这些情况,可选择忽略未请求的扩展或拒绝该断言。依赖方可根据本地策略及所用扩展做出决定。

    由于所有扩展对客户端和认证器均为可选,依赖方 MUST 也要准备好处理未执行全部请求扩展的情况。

  24. 用新状态值更新 credentialRecord
    1. credentialRecord.signCount 更新为 authData.signCount 的值。

    2. credentialRecord.backupState 更新为 currentBs 的值。

    3. credentialRecord.uvInitializedfalse, 则更新其为 authDataUV 位的值。 此更改 SHOULD 需授权一次等同于 WebAuthn 用户验证 的认证因子; 若无此授权,则跳过该步骤。

    如依赖方除 WebAuthn 认证流程之外还执行其他安全检查,则上述状态更新 SHOULD 延迟到所有附加检查完成且成功后进行。

  25. 如上述所有步骤均成功,则按需继续 认证流程。否则,使认证流程失败。

8. 定义的证明声明格式

WebAuthn 支持可插拔的证明声明格式。本节定义了一组初始格式。

8.1. 证明声明格式标识符

证明声明格式由一个字符串进行标识,该字符串称为 证明声明格式标识符,由证明声明格式的创建者选择。

证明声明格式标识符应在 IANA 建立的 “WebAuthn Attestation Statement Format Identifiers” 注册表 [IANA-WebAuthn-Registries] 中注册,见 [RFC8809]。 所有注册的证明声明格式标识符彼此唯一。

未注册的证明声明格式标识符应采用小写反向域名命名方式,并使用开发者已注册的域名,以确保标识符唯一。所有证明声明格式标识符长度不得超过 32 个八位字节,且只能包含可打印的美国 ASCII 字符,不包括反斜杠和双引号,即与 [RFC5234] 所定义的 VCHAR 一致,但不含 %x22 和 %x5c。

注意:这意味着基于域名的证明声明格式标识符仅可包含 LDH 标签[RFC5890]

实现必须严格区分大小写地匹配 WebAuthn 证明声明格式标识符。

若证明声明格式可能存在多个版本,建议其标识符中包含版本号。实际上,不同的版本即被视为不同的格式,例如 packed2 代表 § 8.2 Packed Attestation Statement Format 的新版本。

下列小节介绍目前定义并注册的证明声明格式及其标识符。 已注册的证明声明格式标识符的最新列表由 IANA “WebAuthn Attestation Statement Format Identifiers” 注册表维护,见 [IANA-WebAuthn-Registries],依据 [RFC8809] 设立。

8.2. Packed 证明声明格式

这是一种针对 WebAuthn 优化的 attestation 声明格式。它采用非常紧凑但仍具可扩展性的编码方式。该格式可由资源有限(如安全元件等)的 认证器 实现。

Attestation 声明格式标识符

packed

支持的 Attestation 类型

BasicSelfAttCA

语法

Packed Attestation 声明的语法由如下 CDDL 定义:

$$attStmtType //= (
                      fmt: "packed",
                      attStmt: packedStmtFormat
                  )

packedStmtFormat = {
                       alg: COSEAlgorithmIdentifier,
                       sig: bytes,
                       x5c: [ attestnCert: bytes, * (caCert: bytes) ]
                   } //
                   {
                       alg: COSEAlgorithmIdentifier
                       sig: bytes,
                   }

各字段语义如下:

alg

一个 COSEAlgorithmIdentifier ,其中包含生成 attestation 签名 的算法标识。

sig

包含 attestation 签名 的字节串。

x5c

该数组元素包含 attestnCert 及其证书链(如有),均为 X.509 格式编码。attestation 证书 attestnCert 必须为数组的首个元素。

attestnCert

以 X.509 格式编码的 attestation 证书。

签名过程

此 attestation 声明格式的签名过程类似于生成断言签名的过程

  1. authenticatorData 表示 attestation 的认证器数据clientDataHash 表示 序列化客户端数据的哈希

  2. 如使用 BasicAttCA attestation,认证器通过拼接 authenticatorDataclientDataHash,用选定的 attestation 私钥 签名作为 sigx5c 设置为 attestnCert 紧跟相关证书链(如有)。alg 设置为 attestation 私钥的算法。

  3. 如用到 self attestation,认证器通过拼接 authenticatorDataclientDataHash,用凭证私钥签名作为 sigalg 设置为凭证私钥的算法,省略其它字段。

验证过程

给定 验证过程输入attStmtauthenticatorDataclientDataHash验证过程 如下:

  1. 验证 attStmt 是符合上述语法的有效 CBOR,并对其进行 CBOR 解码以提取各字段。

  2. 若存在 x5c

    • 使用 x5cattestnCertalg 指定的算法,验证 sig 是否是 authenticatorDataclientDataHash 拼接的有效签名。

    • 验证 attestnCert 满足 § 8.2.1 Packed Attestation 证书要求

    • attestnCert 包含 OID 1.3.6.1.4.1.45724.1.1.4id-fido-gen-ce-aaguid)扩展,验证该扩展的值与 authenticatorData 中的 aaguid 一致。

    • 可选:检查 x5c 并参考外部知识,判断 attStmtBasic 还是 AttCA attestation。

    • 如验证成功,返回实现相关的 attestation 类型(Basic、AttCA 或不确定性)以及 attestation 信任路径 x5c

  3. 如果不存在 x5c,则为 self attestation

8.2.1. Packed Attestation 证书要求

Attestation 证书必须包含下列字段/扩展:

此外,带有 id-ad-ocsp 条目的 Authority Information Access(AIA)扩展和 CRL Distribution Point 扩展 [RFC5280] 都是可选的,因为许多 attestation 证书的状态可以通过认证器元数据服务获知。例如可见 FIDO Metadata Service [FIDOMetadataService]

某型号认证器固件可通过扩展 OID 1.3.6.1.4.1.45724.1.1.5id-fido-gen-ce-fw-version)区分。存在时,其为非负整数,每发布新固件版本加一。该扩展不得标记为 critical。

示例:下述 attestation 证书包含上述扩展 OID 及必须字段:

-----BEGIN CERTIFICATE-----
MIIBzTCCAXOgAwIBAgIUYHS3FJEL/JTfFqafuAHvlAS+hDYwCgYIKoZIzj0EAwIw
QTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC1dlYkF1dGhuIFdHMRwwGgYDVQQDDBNF
eGFtcGxlIEF0dGVzdGF0aW9uMCAXDTI0MDEwMzE3NDUyMVoYDzIwNTAwMTA2MTc0
NTIxWjBBMQswCQYDVQQGEwJVUzEUMBIGA1UECgwLV2ViQXV0aG4gV0cxHDAaBgNV
BAMME0V4YW1wbGUgQXR0ZXN0YXRpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AATDQN9uaFFH4BKBjthHTM1drpb7gIuPod67qyF6UdL4qah6XUp6tE7Prl+DfQ7P
YH9yMOOcci3nr+Q/jOBaWVERo0cwRTAhBgsrBgEEAYLlHAEBBAQSBBDNjDlcJu3u
3mU7AHl9A8o8MBIGCysGAQQBguUcAQEFBAMCASowDAYDVR0TAQH/BAIwADAKBggq
hkjOPQQDAgNIADBFAiA3k3aAUVtLhDHLXOgY2kRnK2hrbRgf2EKdTDLJ1Ds/RAIh
AOmIblhI3ALCHOaO0IO7YlMpw/lSTvFYv3qwO3m7H8Dc
-----END CERTIFICATE-----

上述属性在证书中的结构如下:

30 21                                    -- SEQUENCE
  06 0B 2B 06 01 04 01 82 E5 1C 01 01 04 -- OID 1.3.6.1.4.1.45724.1.1.4
  04 12                                  -- OCTET STRING
    04  10                               -- OCTET STRING
      CD 8C 39 5C 26 ED EE DE            -- AAGUID cd8c395c-26ed-eede-653b-00797d03ca3c
      65 3B 00 79 7D 03 CA 3C 

30 12                                    -- SEQUENCE
  06 0B 2B 06 01 04 01 82 E5 1C 01 01 05 -- OID 1.3.6.1.4.1.45724.1.1.5
  04 03                                  -- OCTET STRING
    02 01                                -- INTEGER
      2A                                 -- Firmware version: 42

8.2.2. 企业级 Packed Attestation 的证书要求

企业级 packed attestation 可另外包含扩展 OID 1.3.6.1.4.1.45724.1.1.2 (id-fido-gen-ce-sernum)。如存在,该扩展针对特定 AAGUID,每台设备为唯一 octet string。该值在出厂重置时保持不变,但可与其他序列号或硬件标识区分。此扩展不得标记为 critical,值作为 OCTET STRING 编码。在非企业 attestation 中不得出现此扩展。

8.3. TPM Attestation 声明格式

本 attestation 声明格式通常用于以受信任平台模块(TPM)为加密引擎的认证器。

Attestation 声明格式标识符

tpm

支持的 Attestation 类型

AttCA

语法

TPM Attestation 声明的语法如下:

$$attStmtType // = (
                       fmt: "tpm",
                       attStmt: tpmStmtFormat
                   )

tpmStmtFormat = {
                    ver: "2.0",
                    (
                        alg: COSEAlgorithmIdentifier,
                        x5c: [ aikCert: bytes, * (caCert: bytes) ]
                    )
                    sig: bytes,
                    certInfo: bytes,
                    pubArea: bytes
                }

上述各字段含义如下:

ver

签名所符合的 TPM 规范版本。

alg

一个 COSEAlgorithmIdentifier ,包含用于生成 attestation 签名 的算法标识。

x5c

aikCert 及其证书链(均为 X.509 编码)。

aikCert

用于 attestation 的 AIK 证书(X.509 编码)。

sig

attestation 签名,为 TPMT_SIGNATURE 结构,详见 [TPMv2-Part2] 11.3.4。

certInfo

用于签名的 TPMS_ATTEST 结构,详见 [TPMv2-Part2] 10.12.8。

pubArea

TPMT_PUBLIC 结构(见 [TPMv2-Part2] 12.2.4),TPM 用于表示凭证公钥。

签名过程

authenticatorData 表示 attestation 的认证器数据clientDataHash 表示 序列化客户端数据的哈希

authenticatorDataclientDataHash 拼接为 attToBeSigned

[TPMv2-Part3] 18.2 节的方法、attestation 私钥生成签名,其中 extraData 参数设为 attToBeSigned 的哈希,哈希算法由 "alg" 确定。(如 “RS256” 算法则用 SHA-256 哈希。)

pubArea 字段设为凭证公钥的 public area(TPMT_PUBLIC 结构),certInfo 字段(TPMS_ATTEST 结构)为同名输出参数,sig 字段即上述签名结果。

Note:pubArea 通过 TPM2_ReadPublic 命令读出,该命令返回 TPM2B_PUBLIC 结构。TPM2B_PUBLIC 为两字节长度加 TPMT_PUBLIC 结构。填入 pubArea 前需移除前两字节。

验证过程

给定 验证过程输入 attStmtauthenticatorDataclientDataHash验证过程如下:

验证 attStmt 是否为符合上述语法定义的有效 CBOR,并对其进行 CBOR 解码以提取包含的字段。

验证 pubAreaparametersunique 字段所指公钥与 authenticatorDatacredentialPublicKey 相同。

authenticatorDataclientDataHash 拼接为 attToBeSigned

验证 certInfo 完整性:

  • 验证 x5c 是否存在。

  • 验证 aikCert 是否符合 § 8.3.1 TPM 声明语句证书要求 中的要求。

  • 如果 aikCert 包含 OID 1.3.6.1.4.1.45724.1.1.4id-fido-gen-ce-aaguid)的扩展,则验证该扩展的值是否与 authenticatorData 中的 aaguid 相匹配。

  • 验证 sig 是否为使用 aikCert 中声明公钥,并采用 alg 指定算法对 certInfo 进行的有效签名。

校验 certInfo 是否有效: 注:certInfo 为 TPMS_ATTEST 结构。

  • 校验 magic 设置为 TPM_GENERATED_VALUE

  • 校验 type 设置为 TPM_ST_ATTEST_CERTIFY

  • 校验 extraDataattToBeSigned 用 "alg" 算法对应的哈希。

  • 校验 attested 含有 [TPMv2-Part2] 10.12.3 指定的 TPMS_CERTIFY_INFO 结构, 其 name 字段对应 pubArea 的有效 Name(用 [TPMv2-Part1] 16 节方法和 pubArea 的 nameAlg 算出)。

    Note: TPM 总会用当前 pubArea 的 nameAlg 生成 name 字段。

    Note: 标准认证结构中其余字段 qualifiedSignerclockInfofirmwareVersion 可忽略。 这些字段也许会被混淆;如有效可作为风险引擎输入。

  • 如验证成功,返回实现相关的 attestation 类型 AttCAattestation 信任路径 x5c

8.3.1. TPM Attestation 声明证书要求

TPM attestation 证书 必须包含以下字段/扩展:

8.4. Android Key 证明声明格式

当相关的 认证器 是运行在 Android "N" 或更高版本平台上的 平台认证器 时, 声明语句基于Android 密钥 attestation。 在这些情况下,attestation 声明由运行在安全操作环境下的组件生成,但 attestation 的认证器数据 是在该环境之外产生的。WebAuthn 依赖方应检查 声称用于 attestation 的认证器数据 与 attestation 证书扩展数据字段保持一致。

Attestation 声明格式标识符

android-key

支持的 Attestation 类型

Basic

语法

Android 密钥 attestation 声明只包括 Android attestation 声明本身,即一系列 DER 格式编码的 X.509 证书。详见 Android 官方文档。 其语法定义如下:

$$attStmtType //= (
                      fmt: "android-key",
                      attStmt: androidStmtFormat
                  )

androidStmtFormat = {
                      alg: COSEAlgorithmIdentifier,
                      sig: bytes,
                      x5c: [ credCert: bytes, * (caCert: bytes) ]
                    }

签名过程

authenticatorData 表示 attestation 的认证器数据clientDataHash 表示 序列化客户端数据的哈希

通过调用 keyStore.getCertificateChain(myKeyUUID),并将 clientDataHash 作为 challenge(如用 setAttestationChallenge)申请 Android Key Attestation。将 x5c 设为返回值。

认证器将 authenticatorDataclientDataHash 拼接后,用凭证私钥签名得到 sigalg 设为签名算法。

验证过程

给定 验证过程输入 attStmtauthenticatorDataclientDataHash验证过程如下:

  • 验证 attStmt 是有效的符合上述语法的 CBOR,对其进行解码并提取字段。

  • x5c 第一个证书的公钥及 alg 算法,验证 sig 是否为 authenticatorDataclientDataHash 拼接的有效签名。

  • 验证 x5c 第一个证书中的公钥与 authenticatorDatacredentialPublicKey 一致。

  • 验证 attestation 证书 扩展数据 中的 attestationChallenge 字段等于 clientDataHash

  • 利用 attestation 证书 扩展数据中的合适授权列表,验证如下内容:

    • AuthorizationList.allApplications 字段在两个授权列表(softwareEnforcedteeEnforced)中都不存在,因 PublicKeyCredential 必须作用域限制RP ID

    • 下面两个字段,若 RP 只接受来自受信执行环境的密钥仅用 teeEnforced,否则用 teeEnforcedsoftwareEnforced 的并集:

      • AuthorizationList.origin 字段值为 KM_ORIGIN_GENERATED

      • AuthorizationList.purpose 字段值为 KM_PURPOSE_SIGN

  • 如验证成功,返回实现相关的 attestation 类型 Basicattestation 信任路径 x5c

8.4.1. Android Key Attestation 声明证书要求

Android Key Attestation attestation 证书Android key attestation 证书扩展数据 标识为 OID 1.3.6.1.4.1.11129.2.1.17,其 schema 见Android 官方文档

8.5. Android SafetyNet Attestation 声明格式

Note: 本格式已废弃,后续版本将被移除。

认证器 是某些 Android 平台上的 平台认证器 时, 声明语句可能基于 SafetyNet API。 此时 认证器数据完全由 SafetyNet API 的调用者(通常为 Android 应用)控制,attestation 声明则对平台健康状况及调用应用的身份给出声明 (见 SafetyNet 文档 获取详情)。

Attestation 声明格式标识符

android-safetynet

支持的 Attestation 类型

Basic

语法

Android Attestation 声明的语法如下:

$$attStmtType //= (
                      fmt: "android-safetynet",
                      attStmt: safetynetStmtFormat
                  )

safetynetStmtFormat = {
                          ver: text,
                          response: bytes
                      }

上述字段意义如下:

ver

提供 SafetyNet API 的 Google Play Services 版本号。

response

SafetyNet API 的 getJwsResult() 的 UTF-8 编码结果。其为 JWS [RFC7515] 对象(见 SafetyNet 官方文档),采用 Compact Serialization。

签名过程

authenticatorData 表示 attestation 的认证器数据clientDataHash 表示 序列化客户端数据的哈希

authenticatorDataclientDataHash 拼接,进行 SHA-256 哈希,结果为 attToBeSigned

申请 SafetyNet attestation,参数 nonce 设为 attToBeSigned。将 response 设为其结果,ver 设为认证器中运行的 Google Play Services 版本。

验证过程

给定 验证过程输入 attStmtauthenticatorDataclientDataHash验证过程如下:

  • 验证 attStmt 是有效的符合上述语法的 CBOR,对其进行解码并提取字段。

  • 按照 SafetyNet 官方文档 验证 ver 版本下 response 为合法 SafetyNet 响应。目前 SafetyNet 响应仅有一种格式,ver 预留未来使用。

  • 验证 response payload 的 nonce 属性等于 authenticatorDataclientDataHash 拼接经 SHA-256 哈希后的 Base64 值。

  • 按照 SafetyNet 官方文档 验证 response 实际来自 SafetyNet 服务。

  • 如验证成功,返回实现相关的 attestation 类型 Basicattestation 信任路径 x5c

8.6. FIDO U2F Attestation 声明格式

本 attestation 声明格式适用于采用 [FIDO-U2F-Message-Formats] 定义格式的 FIDO U2F 认证器。

Attestation 声明格式标识符

fido-u2f

支持的 Attestation 类型

BasicAttCA

语法

FIDO U2F attestation 声明格式如下:

$$attStmtType //= (
                      fmt: "fido-u2f",
                      attStmt: u2fStmtFormat
                  )

u2fStmtFormat = {
                    x5c: [ attestnCert: bytes ],
                    sig: bytes
                }

上述字段意义如下:

x5c

单元素数组,包含 X.509 格式的 attestation 证书。

sig

attestation 签名。 签名针对客户端收到的(原始)U2F 注册响应报文 [FIDO-U2F-Message-Formats] 生成。

签名过程

attested credentialcredentialPublicKey算法不是 -7("ES256"),则返回错误。 否则,令 authenticatorData 表示 attestation 的认证器数据clientDataHash序列化客户端数据的哈希。 (SHA-256 生成 clientDataHash 长度为 32 字节。)

[FIDO-U2F-Message-Formats] 第 4.3 节生成注册响应,application 参数为给定凭证 RP ID 的 SHA-256 哈希,challenge 参数为 clientDataHash,key handle 参数为当前凭证的 credential ID。注册响应消息中的原始签名部分(不包括 user 公钥、key handle、声明证书)作为 sig,声明公钥证书作为 x5c

验证过程

给定 验证过程输入 attStmtauthenticatorDataclientDataHash验证过程如下:

  1. 验证 attStmt 是有效的符合上述语法的 CBOR,对其进行解码并提取字段。

  2. 检查 x5c 仅有一个元素并设 attCert 为该元素。certificate public key 取 attCert 所含公钥,非 P-256 曲线 EC 公钥则返回错误。

  3. authenticatorData 提取 rpIdHash,从 authenticatorData.attestedCredentialData 提取 credentialIdcredentialPublicKey

  4. 将 COSE_KEY 格式 credentialPublicKey(见 RFC9052 第 7 节)转为 Raw ANSI X9.62 公钥格式(见 FIDO-Registry 3.6.2)。

    • xcredentialPublicKey 的 "-2" 键对应的 32 字节值;若长度不等或无此键,返回错误。

    • ycredentialPublicKey 的 "-3" 键对应的 32 字节值;若长度不等或无此键,返回错误。

    • publicKeyU2F0x04 || x || y 拼接。

      Note: 这表示未压缩 ECC key 格式。

  5. verificationData0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F 拼接(见 4.3 节)。

  6. certificate public keyverificationData,按 [SEC1] 4.1.4 节及 SHA-256 校验 sig

  7. 可补充检查 x5c 并结合外部知识判断 attStmtBasic 还是 AttCA

  8. 如验证成功,返回实现相关的 attestation 类型 BasicAttCA 或不确定,以及 attestation 信任路径 x5c

8.7. None Attestation 声明格式

none attestation 声明格式用于当 WebAuthn 依赖方 表明不希望接收 attestation 信息时,替换任何 认证器生成的attestation 声明,参见 § 5.4.7 Attestation Conveyance Preference Enumeration (enum AttestationConveyancePreference)

认证器 也 MAY 直接生成此格式的 attestation 声明, 如其不支持 attestation

Attestation 声明格式标识符

none

支持的 Attestation 类型

None

语法

none attestation 声明的语法如下:

$$attStmtType //= (
                      fmt: "none",
                      attStmt: emptyMap
                  )

emptyMap = {}
签名过程

返回上述固定 attestation 声明。

验证过程

返回实现相关的 attestation 类型 None 及空 attestation 信任路径

8.8. Apple 匿名声明格式

该声明格式仅由 Apple 用于支持 WebAuthn 的某些类型的 Apple 设备。

声明格式标识符

apple

支持的声明类型

匿名化 CA

语法

Apple 声明语法定义如下:

$$attStmtType //= (
                      fmt: "apple",
                      attStmt: appleStmtFormat
                  )

appleStmtFormat = {
                      x5c: [ credCert: bytes, * (caCert: bytes) ]
                  }

上述字段的含义如下:

x5c

credCert 及其证书链,每个都为 X.509 格式编码。

credCert

用于声明的凭据公钥证书,X.509 格式编码。

签名流程
  1. authenticatorData 表示用于声明的认证器数据,clientDataHash 表示序列化客户端数据的哈希

  2. authenticatorDataclientDataHash 连接,形成 nonceToHash

  3. nonceToHash 进行 SHA-256 哈希,生成 nonce

  4. 由 Apple 匿名声明 CA 为凭据公钥生成 X.509 证书,并将 nonce 作为 OID 1.2.840.113635.100.8.2 的证书扩展包含其中。credCert 表示该证书。此证书不仅作为声明证明,且包含的 nonce 证明声明为实时生成。此外,nonce 亦保护 authenticatorData客户端数据的完整性。

  5. 设置 x5ccredCert 及其证书链。

验证流程

已知验证流程输入 attStmtauthenticatorDataclientDataHash,则验证步骤如下:

  1. 验证 attStmt 是否为符合上述语法的有效 CBOR,并对其进行 CBOR 解码以提取各个字段。

  2. authenticatorDataclientDataHash 连接,形成 nonceToHash

  3. nonceToHash 进行 SHA-256 哈希,生成 nonce

  4. 确认 nonce 等于 credCert 中 OID 1.2.840.113635.100.8.2 扩展的值。

  5. 验证凭据公钥等于 credCert 的 Subject Public Key。

  6. 如验证通过,返回表示声明类型匿名化 CA 及声明信任路径 x5c 的实现相关值。

8.9. 复合声明格式

“compound” 声明格式用于在一次动作中传递多个自包含声明。

声明格式标识符

compound

支持的声明类型

任意。见 § 6.5.3 声明类型

语法

复合声明语法定义如下:

$$attStmtType //= (
                      fmt: "compound",
                      attStmt: [2* nonCompoundAttStmt]
                  )

nonCompoundAttStmt = { $$attStmtType } .within { fmt: text .ne "compound", * any => any }
签名流程

不适用

验证流程

已知验证流程输入 attStmtauthenticatorDataclientDataHash,其验证流程如下:

  1. 对于 attStmt 中的每个 subStmt, 按 attestation 声明格式标识符 subStmt.fmt验证过程验证过程输入 subStmtauthenticatorDataclientDataHash,逐一评估。

    如一个或多个 subStmt 验证失败,请根据 依赖方 策略判断合适的结果。

  2. 如有足够多(由 依赖方 策略决定)验证通过, 则返回代表所有成功 验证过程输出的实现相关值的任意组合。

9. WebAuthn 扩展

生成公钥凭据及请求、生成认证断言的机制(定义于§ 5 Web Authentication API)可通过扩展进行适应。每种情形通过定义注册扩展 及/或 认证扩展实现。

每个扩展都是客户端扩展,意味着扩展涉及与客户端的通信与处理。客户端扩展定义了以下步骤和数据:

当创建公钥凭证或请求认证断言时,WebAuthn 依赖方可以请求一组扩展的使用。这些扩展将在所请求操作期间被调用(如果客户端和/或WebAuthn 认证器支持的话)。依赖方为每个扩展,通过 get() 调用(用于认证扩展)或 create() 调用(用于注册扩展),向客户端发送客户端扩展输入客户端对每一个它所支持的扩展执行客户端扩展处理,并按各扩展的要求,扩充客户端数据,将扩展标识符客户端扩展输出值包括在内。

扩展也可以是认证器扩展,意味着该扩展涉及与认证器的通信和处理。认证器扩展定义了以下步骤和数据:

对于认证器扩展来说,作为客户端扩展处理的一部分,客户端还会为每个扩展生成 CBOR 格式的认证器扩展输入值(通常基于相应的客户端扩展输入值), 并通过 create() 调用(用于注册扩展),或 get() 调用(用于认证扩展)传递给认证器。这些认证器扩展输入值 以CBOR 格式的键值对表示,键指定为扩展标识符,值为相应认证器扩展输入。认证器对其支持的扩展执行额外处理,并针对各扩展返回CBOR 格式的认证器扩展输出。 由于认证器扩展输出作为已签名认证器数据的一部分返回,认证器扩展同样 MAY 指定未签名扩展输出,例如用于输出依赖于认证器数据本身的情形。 客户端扩展处理的部分内容,就是利用认证器扩展输出未签名扩展输出作为输入生成客户端扩展输出

所有 WebAuthn 拓展 对客户端和认证器来说都是可选的。因此,任何由 Relying Party 请求的拓展可能会被客户端浏览器或操作系统忽略,且根本不会传递给认证器,或者也可能被认证器忽略。 忽略拓展在 WebAuthn API 处理时绝不会视为失败,所以当 Relying Parties 在任何 API 调用中包含拓展,他们必须准备好应对部分或全部拓展被忽略的情况。

所有WebAuthn 扩展必须以这样的方式定义,确保客户端或认证器不支持该扩展也不会危及用户安全或隐私。 例如,如果扩展要求客户端处理,可将其设计为,仅仅将客户端扩展输入从 JSON 直接转为 CBOR,会导致产生语义上无效的认证器扩展输入值,从而使认证器忽略该扩展。由于所有扩展均为可选,这不会导致 API 操作的功能性失败。

IANA 的 "WebAuthn Extension Identifiers" 注册表 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)可查询最新注册的WebAuthn 扩展列表。

9.1. 扩展标识符

扩展通过字符串标识,称为扩展标识符,由扩展定义者选择。

扩展标识符应在 IANA“WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)进行注册。 所有已经注册的扩展标识符应保证全局唯一。

未注册的扩展标识符亦应尽量全球唯一,例如包含定义实体前缀,如 myCompany_extension

所有扩展标识符最长32字节,仅包含可打印 USASCII 字符, 不允许反斜线和双引号,即为 [RFC5234] VCHAR 集合中的可打印字符,但不包括 %x22 和 %x5c。实现需区分大小写比对扩展标识符。

有多个版本的扩展,标识符建议含版本,如 myCompany_extension_01,不同版本视为不同扩展。

§ 10 已定义扩展给出了额外的扩展与其标识符。详见 IANA“WebAuthn Extension Identifiers”注册表 [IANA-WebAuthn-Registries] 以获取最新的注册扩展标识符。

9.2. 扩展定义方法

扩展的定义必须指定一个 扩展标识符、需要通过 get()create() 方法发送的 客户端扩展输入参数、 客户端扩展处理规则,以及一个 客户端扩展输出值。 如果该扩展需要与认证器通信(即为 认证器扩展), 还必须指定通过 authenticatorGetAssertionauthenticatorMakeCredential 方法发送的 CBOR 认证器扩展输入参数, 认证器扩展处理规则,以及 CBOR认证器扩展输出值。 扩展可以指定 未签名扩展输出

任何被客户端处理的客户端扩展 MUST 返回一个客户端扩展输出值,这样WebAuthn 依赖方才能知晓扩展已被客户端处理。同理,任何需要认证器处理的扩展 MUST 返回认证器扩展输出,以让依赖方知道扩展已被认证器处理。如果扩展本身不要求任何结果值,应定义为返回一个 JSON 布尔类型的客户端扩展输出结果,值设为 true 以表示扩展已被理解并处理。类似地,任何不需结果的认证器扩展 MUST 返回值,并 SHOULD 返回 CBOR 布尔类型的认证器扩展输出,值设为 true 以表示扩展已被理解并处理。

9.3. 扩展请求参数扩展

扩展定义一个或两个请求参数。客户端扩展输入 (可以用 JSON 编码的值),在 get()create() 调用时,从WebAuthn 依赖方传入客户端, 而CBOR 认证器扩展输入 用于在这些调用期间,客户向认证器传递认证器扩展

依赖方 通过在 extensions 参数中为扩展增加一项,同时请求该扩展,并设置其客户端扩展输入create()get() 调用时,条目的 key 为扩展标识符,值为客户端扩展输入

Note: 其他文档可能会规定扩展的输入不总是用扩展标识符 作为 entry key。 上述约定对新扩展依然适用。

var assertionPromise = navigator.credentials.get({
    publicKey: {
        // 其他成员省略
        extensions: {
            // entry key 标识 "webauthnExample_foobar" 扩展,
            // value 为带两个输入参数的 map:
            "webauthnExample_foobar": {
              foo: 42,
              bar: "barfoo"
            }
        }
    }
});

扩展定义 MUST 指定其客户端扩展输入允许的值。客户端 SHOULD 忽略那些客户端扩展输入无效的扩展。如果某扩展无需从依赖方获得参数,应被定义为接受布尔类型客户端参数,并由 true 表示依赖方请求该扩展。

仅影响客户端处理的扩展无需指定 认证器扩展输入。具有认证器处理的扩展必须指定从 客户端扩展输入 计算 认证器扩展输入的方法,并且必须为 CDDL 类型 AuthenticationExtensionsAuthenticatorInputsAuthenticationExtensionsAuthenticatorOutputs 定义扩展,通过为 $$extensionInput$$extensionOutput group sockets 使用 扩展标识符 作为条目键来实现。 不需要输入参数的扩展,因此定义为取布尔型 客户端扩展输入 并且值为 true, 也应将 认证器扩展输入 定义为常量布尔值 true(CBOR 主类型 7,值 21)。

下面的例子定义了标识符为 webauthnExample_foobar 的扩展 的 认证器扩展输入 类型为无符号整数, 并将 认证器扩展输出 定义为至少一个字节字符串组成的数组:

$$extensionInput //= (
  webauthnExample_foobar: uint
)
$$extensionOutput //= (
  webauthnExample_foobar: [+ bytes]
)

由于部分认证器通过低带宽连接(如蓝牙低功耗或 NFC)通信,故扩展参数设计 SHOULD 尽量精简。

9.4. 客户端扩展处理

扩展 MAY 在创建凭证或生成断言时,对客户端定义额外处理要求。扩展的客户端扩展输入可作为该客户端处理的输入。对于每一个支持的客户端扩展,客户端会在 clientExtensions 有序 map 中增加一项,key 为扩展标识符,value 为扩展的客户端扩展输入

同理,客户端扩展输出getClientExtensionResults() 返回结果中作为字典表现,key 为扩展标识符,value 为各扩展的 客户端扩展输出。与客户端扩展输入类似,客户端扩展输出可用 JSON 编码。 被忽略的扩展不得有返回值。

需要认证器处理的扩展 MUST 定义 如何由客户端扩展输入确定CBOR 认证器扩展输入 ,及如何由 CBOR 认证器扩展输出(及如用到则还有未签名扩展输出),去确定客户端扩展输出

9.5. 认证器扩展处理

每个被处理的认证器扩展,其 CBOR 认证器扩展输入值,将包含在authenticatorMakeCredentialauthenticatorGetAssertion 操作的 extensions 参数中。该 extensions 参数为 CBOR map,key 为扩展标识符,value 为该扩展的认证器扩展输入

同样,扩展输出在extensions 部分的认证器数据中体现。 extensions字段为 CBOR map,key 为扩展标识符,value 为该扩展的 认证器扩展输出

未签名扩展输出 独立于 认证器数据 返回,由认证器作为独立 map 返回,key 仍然是 扩展标识符。该 map 仅包含利用未签名输出的认证器扩展项。未签名输出主要用于扩展输出自身为认证器数据签名(否则需对自身签名,不可行)或某些扩展输出无需发送到依赖方的场景。

Note:[FIDO-CTAP] 中,未签名扩展输出作为一个顶层字段 unsignedExtensionOutputs(CBOR map)由 authenticatorMakeCredentialauthenticatorGetAssertion 均会返回。

对于每个支持的扩展,将按该扩展的认证器扩展处理规则,由认证器扩展输入及其它输入,生成 认证器扩展输出(如有还包括未签名扩展输出)。 被忽略的扩展不得有返回值。

10. 已定义扩展

本节及其小节定义了应注册于 IANA“WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)的扩展,可供致力于广泛互操作性的用户代理实现。

10.1. 客户端扩展

本节定义仅为客户端扩展的扩展。

10.1.1. FIDO AppID扩展(appid)

此扩展允许WebAuthn 依赖方在曾通过传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 注册过凭据的情况下, 请求断言。 FIDO API 为依赖方使用了另一种标识符,叫做 AppID [FIDO-APPID],使用这些 API 创建的任何凭据都将 限定在该标识符下。 如果没有此扩展,需要重新注册凭据,才能限定RP ID

除了设置 appid 扩展输入, 使用此扩展还需要依赖方做一些额外处理, 以便用户可以用已注册的 U2F 凭据认证

  1. allowCredentials 选项中列出所需 U2F 凭据,位于 get() 方法中:

    • type 成员设为 public-key

    • id 成员设为目标凭据各自的 U2F 密钥句柄。注意 U2F 密钥句柄通常采用base64url 编码,但在用于 id 时需解码为二进制形式。

    allowCredentials 可以同时包含 WebAuthn 凭据 ID 和 U2F 密钥句柄; 通过此扩展声明 appid 不影响用户使用基于RP ID注册的 WebAuthn 凭据, rpId 中声明。

  2. 验证断言时, 需注意rpIdHash 可能是 AppID 的哈希,而非RP ID 的哈希。

此扩展不支持创建 FIDO 兼容凭据。因此,WebAuthn 创建的凭据与 FIDO JavaScript API 不兼容。

注意: appid 应设置为依赖方 先前在传统 FIDO API 使用过的 AppID。 这可能不同于将依赖方当前 WebAuthn RP ID 翻译为 AppID 格式的结果, 例如,先前使用的 AppID 可能是 "https://accounts.example.com" 而当前使用的RP ID 可能是 "example.com"。

扩展标识符

appid

适用操作

认证

客户端扩展输入

单一 DOMString,指定 FIDO AppID

partial dictionary AuthenticationExtensionsClientInputs {
  DOMString appid;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
  DOMString appid;
};
客户端扩展处理
  1. facetId 为将调用方origin 传递到 FIDO 应用程序 FacetID 判定算法的结果。

  2. appId 为扩展输入值。

  3. facetIdappId 一并传递到 FIDO FacetID 是否被授权给 AppID 的算法。 若该算法拒绝 appId,则返回 "SecurityError" DOMException

  4. 构建 allowCredentialDescriptorList时, 若 U2F 认证器表明某凭据不适用(如返回 SW_WRONG_DATA),则客户端必须以 U2F 应用参数为 appId 的 SHA-256 哈希值重新尝试。 若此举得到适用凭据,客户端须将其加入 allowCredentialDescriptorList。此时 appId 替换原 rpId 参数(用于 authenticatorGetAssertion)。

  5. output 为布尔值 false

  6. 创建 assertionCreationData时, 若断言是 U2F 认证器用 appId 的 SHA-256 哈希而非 RP ID 的哈希为参数生成的,则将 output 设为 true

注意: 实际中,不少实现并未完整实现 FacetID 是否被授权给 AppID 的算法 的第四步及后续步骤。 相反,实际第三步中主机上的比较被放宽,允许同一站点上的主机。 同一站点

客户端扩展输出

返回output的值。若为 true,则在 验证断言时, 依赖方应 期望rpIdHashAppID 的哈希而非RP ID 的哈希。

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appid;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
  boolean appid;
};
认证器扩展输入

无。

认证器扩展处理

无。

认证器扩展输出

无。

10.1.2. FIDO AppID 排除扩展(appidExclude)

此注册扩展允许WebAuthn 依赖方排除包含由传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 创建的特定凭据的认证器。

在 FIDO U2F JavaScript API 向 WebAuthn 过渡期间,依赖方的用户群体中可能已经注册了一批传统凭据。appid 扩展可以让登录流程平滑过渡,但在过渡注册流程时, excludeCredentials 字段对包含传统凭据的认证器无效,因为其内容被视为 WebAuthn 凭据。 此扩展指示客户端平台excludeCredentials 的内容同时视为 WebAuthn 凭据与传统 FIDO 凭据。注意 U2F 密钥句柄通常采用base64url 编码,但用于 excludeCredentials 时,需还原为二进制形式。

扩展标识符

appidExclude

适用操作

注册

客户端扩展输入

单一 DOMString,指定 FIDO AppID

partial dictionary AuthenticationExtensionsClientInputs {
  DOMString appidExclude;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
  DOMString appidExclude;
};
客户端扩展处理

创建新凭据时:

  1. 确定 RP ID后立刻执行下述步骤:

    1. facetId 取调用方的 origin, 传入 FIDO 判定调用应用 FacetID 的算法

    2. appId 取扩展输入 appidExclude 的值。

    3. facetIdappId 一起传入 FIDO FacetID 是否被授权给 AppID 的算法。 若该算法拒绝 appId, 则返回 "SecurityError" DOMException 并终止 新凭据创建算法及后续步骤。

      注意: 实际中,不少实现未完整实现 FacetID 是否被授权给 AppID 的算法第四步及后续。实际第三步中,主机比较被放宽,允许接受同一站点的主机。

    4. 否则,继续正常流程。

  2. 调用 authenticatorMakeCredential前执行下述步骤:

    1. authenticator 支持 U2F 协议 [FIDO-U2F-Message-Formats],则对 excludeCredentialDescriptorList 中的每个 凭据描述符 C 依次处理

      1. 通过向 authenticator 发送 U2F_AUTHENTICATE 消息,检查 C 是否由该 authenticator 的 U2F 创建,消息的“五个部分”如下:

        控制字节

        0x07(“仅检测”)

        挑战参数

        32 个随机字节

        应用参数

        appId 的 SHA-256 哈希

        密钥句柄长度

        C.id 的字节长度

        密钥句柄

        C.id 的值,即凭据 ID

      2. 如果 authenticator 响应 message:error:test-of-user-presence-required(即成功),则停止对该 authenticator 的正常处理,并以平台特定方式指示该认证器无效。例如可通过 UI 呈现,或请求来自 用户同意,收到后按 InvalidStateError 对待。 请求 用户同意 可再次发送 U2F_AUTHENTICATE 消息,除 控制字节 设为 0x03(“强制用户在场并签名”)外,其余同上,本次响应可忽略。

    2. 继续正常流程。

客户端扩展输出

返回值 true,表示依赖方该扩展已被处理。

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appidExclude;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
  boolean appidExclude;
};
认证器扩展输入

无。

认证器扩展处理

无。

认证器扩展输出

无。

10.1.3. 凭据属性扩展(credProps

客户端注册扩展用以在一次注册仪式创建 公钥凭据源时,将客户端已知的部分凭据属性反馈给请求方WebAuthn 依赖方

目前只定义了一种凭据属性客户端可发现凭据属性

扩展标识符

credProps

适用操作

注册

客户端扩展输入

布尔值 true,表明该扩展由依赖方请求。

partial dictionary AuthenticationExtensionsClientInputs {
    boolean credProps;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
    boolean credProps;
};
客户端扩展处理

rk 设置为 调用 authenticatorMakeCredential 操作时的 requireResidentKey 参数值。

客户端扩展输出

clientExtensionResults["credProps"]["rk"] 设为 调用 authenticatorMakeCredential 操作时的 requireResidentKey 参数值。

dictionary CredentialPropertiesOutput {
    boolean rk;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    CredentialPropertiesOutput credProps;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
    CredentialPropertiesOutput credProps;
};
rk, 类型为 boolean

该属性为可选,抽象上称为客户端可发现凭据属性驻留密钥凭据属性, 表示 PublicKeyCredential (由注册仪式结果返回) 是否为客户端可发现凭据的布尔值。 若 rktrue,则为可发现凭据。 若为 false,则为服务器侧凭据。 若 rk 缺省,则未知其是 可发现凭据还是 服务器侧凭据

注意:有些 认证器 会创建 可发现凭据,即使 客户端平台 并未请求。由于这个原因,客户端平台 可能不得不省略 rk 属性,因为他们无法确保把它设置为 falseRelying Party 应当假定,如果支持 credProps 拓展,则 客户端平台会努力填充 rk 属性。因此,缺失 rk 说明所创建的凭据很可能是 不可发现凭据

认证器扩展输入

无。

认证器扩展处理

无。

认证器扩展输出

无。

10.1.4. 伪随机函数扩展 (prf)

客户端注册扩展认证扩展允许依赖方对与某凭据相关的伪随机函数(PRF)求值。该扩展提供的 PRF 可将任意长度 BufferSource 映射为 32 字节 BufferSource

举例而言,PRF 输出可作为对称密钥对用户数据进行加密。如此一来,若不能获得相应凭据断言,则无法解密这些数据。利用下述约定,在一次断言操作中对两个输入分别求 PRF,可在 断言期间定期轮换加密密钥,即每次选择新随机输入,数据用新输出重新加密。只要评估输入不可预测,即使攻击者可执行 用户验证 且短暂获取认证器,也无法获知密钥,除非知道正确 PRF 输入。

该扩展建模自 [FIDO-CTAP]hmac-secret 扩展,但亦可采用其他方式实现。 它是独立的 客户端扩展,因为 hmac-secret 要求输入输出只能由用户代理加密; 并保障 WebAuthn 与底层平台其它用途隔离。 这种隔离通过将所给 PRF 输入和上下文字符串做哈希实现, 可防止在任意输入下调用 PRF。

hmac-secret 扩展每个凭据提供两个 PRF:其中之一用于已执行 用户验证 的请求,其余则用于其它请求。 本扩展每个凭据仅暴露一个 PRF,并且如用 hmac-secret 作为底层实现,该 PRF 必须选择用于 用户验证 的那一个,如有需要应覆盖 UserVerificationRequirement

本扩展同样可用于未采用 [FIDO-CTAP]认证器。 客户端与认证器之间的接口以及 PRF 的实现方式仅做抽象说明。

注意: 基于 hmac-secret 实现时,会产生原本不会存在的认证器扩展输出。 这些输出为加密数据,依赖方无法使用, 但客户端也不能删除,因为认证器数据已签名。

扩展标识符

prf

适用操作

注册认证

客户端扩展输入
dictionary AuthenticationExtensionsPRFValues {
    required BufferSource first;
    BufferSource second;
};
dictionary AuthenticationExtensionsPRFValuesJSON {
    required Base64URLString first;
    Base64URLString second;
};

dictionary AuthenticationExtensionsPRFInputs {
    AuthenticationExtensionsPRFValues eval;
    record<DOMString, AuthenticationExtensionsPRFValues> evalByCredential;
};
dictionary AuthenticationExtensionsPRFInputsJSON {
    AuthenticationExtensionsPRFValuesJSON eval;
    record<DOMString, AuthenticationExtensionsPRFValuesJSON> evalByCredential;
};

partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsPRFInputs prf;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
    AuthenticationExtensionsPRFInputsJSON prf;
};
eval, 类型为 AuthenticationExtensionsPRFValues

要对 PRF 求值的一个或两个输入。并非所有认证器都支持在创建凭据时对 PRF 求值,所以输出可能会、也可能不会提供。若未提供,则需 断言以获取输出。

evalByCredential, 类型为 record<DOMString, AuthenticationExtensionsPRFValues>

base64url 编码凭据 ID映射到 PRF 输入的记录,对应凭据就用这些输入求值。仅在断言allowCredentials 非空时适用。

客户端扩展处理 (注册)
  1. 若存在 evalByCredential ,返回名为 “NotSupportedError” 的 DOMException

  2. 若存在 eval

    • salt1SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || eval.first) 的值。

    • eval.second 存在,则 salt2SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || eval.second) 的值。

  3. 若认证器支持 CTAP2 hmac-secret 扩展 [FIDO-CTAP]

    1. 在认证器扩展输入中将 hmac-secret 设为 true

    2. 若已定义 salt1,且未来 CTAP 扩展允许在创建时对 PRF 求值,则用 salt1salt2 分别配置 hmac-secret 输入。

    3. 在认证器扩展输出中设 enabledhmac-secret 的值,若缺省则为 false

    4. results 设为解密后的 PRF 结果(如有)。

  4. 若认证器不支持 CTAP2 hmac-secret 扩展 [FIDO-CTAP], 但支持与下述抽象认证器处理兼容的其它实现:

    1. enabled 设为 true

    2. 若已定义 salt1,采用未规定的机制传递 salt1salt2 给认证器。

    3. 用未规定机制接收认证器 PRF 输出, results 设为结果值(如有)。

客户端扩展处理 (认证)
  1. evalByCredential 不为空,但 allowCredentials 为空,返回名为 “NotSupportedError” 的 DOMException

  2. evalByCredential 的任一为空字符串,或不是有效base64url 编码,或不等于 id 中某元素的值(经 base64url 解码),则返回名为 “SyntaxError” 的 DOMException

  3. 初始化 prf 扩展输出为空字典。

  4. ev 为 null,尝试寻找有效 PRF 输入:

    1. evalByCredential 存在,且包含键为将要返回凭据credential ID 的 base64url 编码的项,则 ev 为该项的值。

    2. 如未找到且 eval 存在,则 ev 为该值。

  5. ev 非 null:

    1. salt1SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || ev.first) 的值。

    2. ev.second 存在,则 salt2SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || ev.second)

    3. 如认证器支持 CTAP2 hmac-secret 扩展 [FIDO-CTAP]

      1. 发送 hmac-secret 扩展至认证器,参数为 salt1 和(如有)salt2

      2. 对扩展结果解密,将 results 设为 PRF 结果(如有)。

    4. 如认证器不支持 CTAP2 hmac-secret 扩展 [FIDO-CTAP], 但支持与下述抽象认证器处理兼容的其它实现:

      1. 用未规定机制将 salt1salt2(如有)传递给认证器作为 PRF 输入。

      2. 用未规定机制接收认证器返回的 PRF 输出 resultsresults 设为 results

认证器扩展输入/输出

本扩展对认证器实现为抽象,无论使用 [FIDO-CTAP] hmac-secret 扩展还是其它未规定的接口,均不规范化输入输出的 CBOR 格式。

认证器扩展处理

支持 [FIDO-CTAP] hmac-secret 扩展的认证器 依照该扩展的规范处理。

不支持 [FIDO-CTAP] hmac-secret认证器 可实现如下抽象过程:

  1. PRF 为当前 凭据相关的伪随机函数,如未初始化则初始化:

    PRF 为输出精确为 32 字节的伪随机函数,从不少于 2256 个这样的函数均匀随机选取。 PRF 选择需与 用户验证 状态无关; PRF 不得用于本扩展以外的其它用途。 PRF 与凭据的绑定需持续整个凭据生命周期。

  2. 用未规定机制接收 salt1 和(可选)salt2,如无则二者为 undefined。

  3. salt1 存在:

    1. resultsAuthenticationExtensionsPRFValues 结构,对应如下输入:

      • 设置 results.firstPRF(salt1)

      • salt2 存在, 设置 results.secondPRF(salt2)

    2. 使用某种未指定的机制将 results 作为 PRF 输出传递给 客户端

客户端扩展输出
dictionary AuthenticationExtensionsPRFOutputs {
    boolean enabled;
    AuthenticationExtensionsPRFValues results;
};
dictionary AuthenticationExtensionsPRFOutputsJSON {
    boolean enabled;
    AuthenticationExtensionsPRFValuesJSON results;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsPRFOutputs prf;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
    AuthenticationExtensionsPRFOutputsJSON prf;
};
enabled, 类型为 boolean

仅在注册时,当 PRF 可用于该凭据时才为 true。认证时不返回该属性。

results, 类型为 AuthenticationExtensionsPRFValues

PRF 对 evalevalByCredential 输入的运算结果。在 注册过程中该输出可能缺省;可见 eval 相关说明。

针对某些用例,例如如果 PRF 输出用于仅在客户端派生加密密钥, 当 PublicKeyCredential 被发送到远程服务器时, 可能需要省略此 results 输出, 例如用于执行 § 7 WebAuthn Relying Party Operations 中的流程。 特别需要注意, 由 PublicKeyCredential.toJSON() 返回的 RegistrationResponseJSONAuthenticationResponseJSON 如果存在则会包含此 results 输出。

10.1.5. 大对象(Large blob)存储扩展(largeBlob

客户端注册扩展认证扩展允许Relying Party存储与凭据关联的不透明数据。由于认证器只能存储少量数据,而大多数Relying Party是能够为用户存储任意数量状态的在线服务,该功能仅在特定场景下有用。例如,Relying Party可能希望发放证书而不是运行集中式认证服务。

注:Relying Party可以假定不透明数据在写入空间受限设备时会被压缩,因此无需自行压缩。

由于证书系统需要对凭据的公钥进行签名,而该公钥仅在凭据创建后才可获得,此扩展不会在注册阶段添加写入 blob 的能力。但如果希望日后使用认证扩展Relying Party在创建凭据时应使用注册扩展

由于证书体积相较于典型认证器的存储能力较大,用户代理应考虑适当的提示和确认机制,以更好地引导用户合理分配有限资源并防止滥用。

注:为实现互操作,用户代理在认证器上使用[FIDO-CTAP]存储大 blob 时,应依据该规范中针对large, per-credential blobs的相关要求执行。

注:使用[FIDO-CTAP]作为跨平台传输协议的漫游认证器仅支持针对可发现凭据的此Large Blob扩展,除非authenticatorSelection.residentKey被设置为preferredrequired,否则可能返回错误。但不使用[FIDO-CTAP]认证器则不一定将此扩展限制于可发现凭据

扩展标识符

largeBlob

适用操作

注册认证

客户端扩展输入
partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsLargeBlobInputs largeBlob;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
    AuthenticationExtensionsLargeBlobInputsJSON largeBlob;
};

enum LargeBlobSupport {
  "required",
  "preferred",
};

dictionary AuthenticationExtensionsLargeBlobInputs {
    DOMString support;
    boolean read;
    BufferSource write;
};
dictionary AuthenticationExtensionsLargeBlobInputsJSON {
    DOMString support;
    boolean read;
    Base64URLString write;
};
support, 类型为 DOMString

一个DOMString,必须取自LargeBlobSupport的值之一。(见§ 2.1.1 枚举类型为DOMString。)仅在注册过程中有效。

read, 类型为 boolean

布尔值,表示Relying Party希望获取与当前声明凭据关联的已写入blob,仅在认证阶段有效。

write, 类型为BufferSource

不透明字节串,Relying Party希望将其与已有凭据存储。仅在认证阶段有效。

客户端扩展处理(注册
  1. 如果出现readwrite

    1. 返回DOMException ,其名称为“NotSupportedError”。

  2. 如果support 存在且值为required

    1. supported 设为true

      注:这是为了支持可以存储大blob认证器出现的情况。该步骤发生在扩展处理步骤12,即[[Create]](origin, options, sameOriginWithAncestors)流程中。如果没有可用认证器,AuthenticationExtensionsLargeBlobOutputs会被放弃。

    2. 当有候选认证器步骤22[[Create]](origin, options, sameOriginWithAncestors))出现时,在处理任何options 之前,若该候选认证器不支持存储大blob,则跳过(即忽略该候选认证器)。

  3. 否则(即support缺失或其值为preferred):

    1. 若已经选定认证器且该认证器支持大blob,则supported 设为true,否则为false

客户端扩展处理(认证
  1. 如果出现support

    1. 返回DOMException ,其名称为“NotSupportedError”。

  2. 如果readwrite同时出现:

    1. 返回DOMException ,其名称为“NotSupportedError”。

  3. 如果read 存在且为true

    1. 初始化客户端扩展输出largeBlob

    2. 如果有认证器在[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)流程中返回成功,尝试读取与声明凭据关联的任何largeBlob数据。

    3. 如果成功,将blob设为结果。

      注:如果读取不成功,largeBlob会存在于AuthenticationExtensionsClientOutputs 中,但blob成员不存在。

  4. 如果出现write

    1. 如果allowCredentials不正好包含一个元素:

      1. 返回DOMException ,其名称为“NotSupportedError”。

    2. assertion操作成功,尝试将write内容存储到指定认证器和凭据上。

    3. 如果成功,将written设为true,否则为false

客户端扩展输出
partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsLargeBlobOutputs largeBlob;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
    AuthenticationExtensionsLargeBlobOutputsJSON largeBlob;
};

dictionary AuthenticationExtensionsLargeBlobOutputs {
    boolean supported;
    ArrayBuffer blob;
    boolean written;
};
dictionary AuthenticationExtensionsLargeBlobOutputsJSON {
    boolean supported;
    Base64URLString blob;
    boolean written;
};
supported, 类型为 boolean

仅当所创建凭据支持大blob存储时为true。仅出现在注册输出中。

blob, 类型为ArrayBuffer

rawId标识凭据相关的不透明字节串,仅当readtrue时有效。

written, 类型为boolean

布尔值,指明write内容是否已成功存储于指定认证器及凭据。

认证器扩展处理

本扩展指示用户代理将large blob存储到认证器上或从认证器中读取large blob。因此,不为Relying Party指定任何直接的认证器交互。

10.2. 认证器扩展

本节定义既是客户端扩展又是认证器扩展的扩展。

本节当前为空。

11. 用户代理自动化

为用户代理自动化和Web 应用测试,本文件定义了若干 [WebDriver] 扩展命令

11.1. WebAuthn WebDriver 扩展能力

为了声明下文定义的扩展命令的可用性,定义了一个新的扩展能力

能力 关键字 值类型 描述
虚拟认证器支持 "webauthn:virtualAuthenticators" boolean 指示端节点是否支持所有虚拟认证器命令。

校验能力时,针对 "webauthn:virtualAuthenticators"value 的扩展子步骤如下:

  1. 如果 value 不是布尔值,则返回 WebDriver 错误, 错误码为 WebDriver error code invalid argument

  2. 否则,将 deserialized 设为 value

匹配能力时,针对 "webauthn:virtualAuthenticators"value 的扩展子步骤如下:

  1. 如果 valuetrue,且端节点不支持任何虚拟认证器命令, 则匹配失败。

  2. 否则,匹配成功。

11.1.1. 认证器扩展能力

此外,为本规范中定义的每个认证器扩展(即定义了认证器扩展处理的扩展)都定义了扩展能力:

能力 关键字 值类型 描述
伪随机函数扩展支持 "webauthn:extension:prf" boolean 指示端节点的 WebAuthn WebDriver 实现是否支持 prf 扩展。
大对象存储扩展支持 "webauthn:extension:largeBlob" boolean 指示端节点的 WebAuthn WebDriver 实现是否支持largeBlob 扩展。
credBlob 扩展支持 "webauthn:extension:credBlob" boolean 指示端节点的 WebAuthn WebDriver 实现是否支持 credBlob 扩展(见 [FIDO-CTAP])。

校验能力时,针对 认证器扩展能力 keyvalue 的扩展子步骤如下:

  1. 如果 value 不是布尔值,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  2. 否则,将 deserialized 设为 value

匹配能力时,针对 认证器扩展能力keyvalue 的扩展子步骤如下:

  1. 如果 valuetrue,且端节点 WebAuthn WebDriver 实现不支持该 key 标识的认证器扩展, 则匹配失败。

  2. 否则,匹配成功。

实现已定义认证器扩展的 User-Agent 应实现相应的认证器扩展能力

11.2. 虚拟认证器

这些 WebDriver 扩展命令用于创建和交互虚拟认证器:也即认证器模型的软件实现。虚拟认证器存放于虚拟认证器数据库。 每个存储的虚拟认证器具备以下属性:

authenticatorId

一个非空字符串,由[RFC3986]附录A中unreserved规则允许的最多48个字符组成,用于唯一标识虚拟认证器

protocol

虚拟认证器使用的协议,可为"ctap1/u2f""ctap2""ctap2_1"之一 [FIDO-CTAP]

transport

虚拟的AuthenticatorTransport通道。如果transport设为internal,则 认证器模拟平台附件。否则,模拟跨平台附件

hasResidentKey

true时,认证器支持客户端可发现凭据

hasUserVerification

true时,认证器支持用户验证

isUserConsenting

决定所有用户同意授权操作,以及扩展来讲,所有在虚拟认证器上执行的用户在场测试的结果。设为true时,总是授予用户同意。设为false时,则拒绝。

isUserVerified

决定在虚拟认证器上进行用户验证的结果。设为true时, 用户验证总是成功。为false时则失败。

注意: 如果hasUserVerificationfalse,该属性无效。

extensions

字符串数组,包含扩展标识符,表示该虚拟认证器支持的扩展。

虚拟认证器必须支持其extensions数组中出现的所有认证器扩展, 也不得支持extensions数组未包含的任意认证器扩展

defaultBackupEligibility

决定任何新建公钥凭据源可备份性凭据属性的默认状态。在用此虚拟认证器执行authenticatorMakeCredential操作时, 该值必须反映在BE 认证器数据标志位中。

defaultBackupState

决定任何新建公钥凭据源备份状态凭据属性的默认状态。在用此虚拟认证器执行authenticatorMakeCredential操作时, 该值必须反映在BS 认证器数据标志位中。

11.3. 添加虚拟认证器

添加虚拟认证器 WebDriver 扩展命令会创建一个软件虚拟认证器。定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator

认证器配置是一个 JSON 对象,以 parameters 形式传递给远端步骤。其包含如下 keyvalue 对:

Key 值类型 有效值 默认值
protocol string "ctap1/u2f", "ctap2", "ctap2_1"
transport string AuthenticatorTransport 的值
hasResidentKey boolean true, false false
hasUserVerification boolean true, false false
isUserConsenting boolean true, false true
isUserVerified boolean true, false false
extensions string array 含有扩展标识符的数组 空数组
defaultBackupEligibility boolean true, false false
defaultBackupState boolean true, false false

远端步骤如下:

  1. 如果 parameters 不是 JSON 对象,返回WebDriver 错误,错误码为invalid argument

    注意:parameters 是一个认证器配置对象。

  2. authenticator 为新的虚拟认证器

  3. parameters 中每一个可枚举的 自有属性

    1. key 为属性名。

    2. value获取属性 keyparameters 的结果。

    3. 如无 认证器配置中与 key 匹配的 key,则返回WebDriver 错误,错误码为 invalid argument

    4. value 非该 key 的有效值,返回WebDriver 错误,错误码为invalid argument

    5. 设置属性 key 的值为 valueauthenticator

  4. 认证器配置中有默认值的每个属性:

    1. key 不是 authenticator 的属性,设置属性 keydefaultauthenticator

  5. 认证器配置中的每个属性:

    1. key 不是 authenticator 的属性,返回WebDriver 错误,错误码为invalid argument

  6. authenticator.extensions 中每个 extension

    1. 如果 extension 不是 扩展标识符且由 endpoint node WebAuthn WebDriver 实现支持,则返回 WebDriver 错误,错误码为 unsupported operation

  7. 生成一个有效且唯一的authenticatorId

  8. 设置属性 authenticatorIdauthenticatorIdauthenticator

  9. authenticator存入虚拟认证器数据库

  10. 返回成功,并附带 authenticatorId 数据。

11.4. 移除虚拟认证器

移除虚拟认证器 WebDriver 扩展命令会移除先前创建的 虚拟认证器。 定义如下:

HTTP 方法 URI 模板
DELETE /session/{session id}/webauthn/authenticator/{authenticatorId}

远端步骤如下:

  1. 如果 authenticatorId 未匹配任何存于虚拟认证器数据库中的对象,返回 WebDriver 错误,错误码为invalid argument

  2. 虚拟认证器数据库中移除由 authenticatorId 标识的 虚拟认证器

  3. 返回成功

11.5. 添加凭据

添加凭据 WebDriver 扩展命令会将公钥凭据源注入到已有 虚拟认证器中。定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator/{authenticatorId}/credential

凭据参数是一个 JSON 对象,以 parameters 形式传递给远端步骤。其包含如下 keyvalue 对:

Key 描述 值类型
credentialId 凭据 ID,采用Base64url编码 string
isResidentCredential 设为true,则创建客户端可发现凭据false时,创建服务器端凭据 boolean
rpId 凭据限定的依赖方ID string
privateKey 包含单个私钥的非对称密钥包,符合[RFC5958],用Base64url编码 string
userHandle 与凭据关联的userHandle,Base64url编码。可选。 string
signCount 签名计数器的初始值 number
largeBlob 与凭据关联的大blob,Base64url编码。可选。 string
backupEligibility 可备份性模拟值。未设置时,采用虚拟认证器defaultBackupEligibility 属性。模拟的可备份性必须反映在BE 认证器数据 标志中。 boolean
backupState 备份状态模拟值。未设置则取虚拟认证器defaultBackupState。模拟的备份状态必须反映在BS 认证器数据 标志中。 boolean
userName 与凭据关联的 username。未设置则为空字符串。 string
userDisplayName 与凭据关联的 userdisplayName,未设置则为空字符串。 string

远端步骤如下:

  1. 如果 parameters 不是 JSON 对象,返回WebDriver 错误,错误码为invalid argument

    注意:parameters凭据参数对象。

  2. credentialId 为对 parameterscredentialId 属性值做Base64url 解码的结果。

  3. credentialId 解析失败,返回WebDriver 错误,错误码为invalid argument

  4. isResidentCredentialparametersisResidentCredential 属性值。

  5. isResidentCredential 未定义,返回 WebDriver 错误,错误码为invalid argument

  6. rpIdparametersrpId 属性值。

  7. rpId 非法,返回 WebDriver 错误,错误码为invalid argument

  8. privateKey 为对 parametersprivateKey 属性值做Base64url 解码的结果。

  9. privateKey 解析失败,返回 WebDriver 错误,错误码为invalid argument

  10. privateKey 非合法 P-256 曲线 ECDSA 私钥 [RFC5958] 编码,返回 WebDriver 错误,错误码为invalid argument

  11. parametersuserHandle 属性有定义:

    1. userHandle 为对其做Base64url 解码的结果。

    2. userHandle 解析失败,返回 WebDriver 错误,错误码为invalid argument

  12. 否则:

    1. isResidentCredentialtrue,返回 WebDriver 错误,错误码为invalid argument

    2. userHandlenull

  13. authenticatorId 未匹配任何虚拟认证器,返回WebDriver 错误,错误码为invalid argument

  14. authenticator 为由 authenticatorId 匹配到的虚拟认证器

  15. isResidentCredentialtrueauthenticatorhasResidentKeyfalse,返回 WebDriver 错误,错误码为invalid argument

  16. authenticator 支持 largeBlob 扩展且 parameterslargeBlob 属性有定义:

    1. largeBlob 为对属性做Base64url 解码的结果。

    2. largeBlob 解析失败,返回 WebDriver 错误,错误码为invalid argument

  17. 否则:

    1. largeBlobnull

  18. backupEligibilityparametersbackupEligibility 属性值。

  19. backupEligibility 未定义,将其设为 authenticatordefaultBackupEligibility 值。

  20. backupStateparametersbackupState 属性值。

  21. backupState 未定义,将其设为 authenticatordefaultBackupState 值。

  22. userNameparametersuserName 属性值。

  23. userName 未定义,将其设为空字符串。

  24. userDisplayNameparametersuserDisplayName 属性值。

  25. userDisplayName 未定义,将其设为空字符串。

  26. credential: 如果 isResidentCredentialtrue,则为新的 客户端可发现公钥凭据源;否则为 服务器端公钥凭据源。属性如下:

    type

    public-key

    id

    credentialId

    privateKey

    privateKey

    rpId

    rpId

    userHandle

    userHandle

    otherUI

    userNameuserDisplayName 组装。

  27. 设置 credential可备份性凭据属性backupEligibility

  28. 设置 credential备份状态凭据属性backupState

  29. 签名计数器 counter 与该 credential 相关联,初始值为 parameterssignCount0

  30. largeBlobnull,则将大blob 关联到该 credential

  31. credentialcounter 存储到该 authenticator 的数据库。

  32. 返回成功

11.6. 获取凭据

获取凭据 WebDriver 扩展命令会返回指定虚拟认证器中的每个公钥凭据源凭据参数对象,无论该凭据是通过添加凭据还是 navigator.credentials.create() 存储的。 定义如下:

HTTP 方法 URI 模板
GET /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials

远端步骤如下:

  1. authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument

  2. credentialsArray 为空数组。

  3. 对于由 authenticatorId 标识的认证器管理的每个公钥凭据源 credential,构造相应的凭据参数 对象,追加至 credentialsArray

  4. 返回成功并包含 credentialsArray 数据。

11.7. 移除凭据

移除凭据 WebDriver 扩展命令将从虚拟认证器中删除一个公钥凭据源。定义如下:

HTTP 方法 URI 模板
DELETE /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}

远端步骤如下:

  1. 如果 authenticatorId 未匹配到任何存储在虚拟认证器数据库 虚拟认证器数据库中的对象,则返回WebDriver 错误,其WebDriver 错误码invalid argument

  2. authenticator 为由 authenticatorId 标识的虚拟认证器

  3. 如果 credentialId 未匹配到由 authenticator 管理的任何公钥凭证源,则返回WebDriver 错误, 其WebDriver 错误码invalid argument

  4. 移除由 authenticator 管理、由 credentialId 标识的公钥凭证源

  5. 返回成功

11.8. 移除全部凭据

移除全部凭据 WebDriver 扩展命令将从虚拟认证器中删除其存储的全部公钥凭据源。定义如下:

HTTP 方法 URI 模板
DELETE /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials

远端步骤如下:

  1. authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument

  2. 移除由 authenticatorId 标识的虚拟认证器管理的全部公钥凭据源

  3. 返回成功

11.9. 设置用户已验证

设置用户已验证 扩展命令用于设置虚拟认证器上的 isUserVerified 属性。 定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator/{authenticatorId}/uv

远端步骤如下:

  1. parameters 非 JSON 对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  2. authenticatorId 未匹配任何虚拟认证器,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  3. isUserVerifiedparameters 的已定义属性,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  4. authenticator 为由 authenticatorId 标识的虚拟认证器

  5. authenticatorisUserVerified 属性设为 parametersisUserVerified 属性值。

  6. 返回成功

11.10. 设置凭据属性

设置凭据属性 扩展命令允许设置虚拟认证器公钥凭据源backupEligibilitybackupState凭据属性。定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}/props

设置凭据属性参数是一个 JSON 对象,通过 parameters 传递给 远端步骤。 其包含以下 keyvalue 对:

关键字 描述 值类型
backupEligibility 可备份性凭据属性boolean
backupState 备份状态 凭据属性boolean

远端步骤如下:

  1. 如果 parameters 不是 JSON 对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

    注意: parameters 是一个 设置凭据属性参数 对象。

  2. 如果 authenticatorId 未匹配任何存于 虚拟认证器 数据库 Virtual Authenticator Database中的对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  3. credential 为由 credentialId 匹配到的 公钥凭据源,该凭据由 authenticator 管理。

  4. 如果 credential 为空,返回 WebDriver 错误 ,错误码为 WebDriver error codeinvalid argument

  5. backupEligibilityparametersbackupEligibility 属性值。

  6. 如果 backupEligibility 已定义,则将 credential可备份性凭据属性设置为 backupEligibility 的值。

    注意: 通常,backupEligibility 属性对于一个公钥凭据源来说是永久的。 设置凭据属性允许为测试或调试目的临时修改其值。

  7. backupStateparametersbackupState 属性值。

  8. 如果 backupState 已定义,则将 credential备份状态凭据属性 设置为 backupState 的值。

  9. 返回 成功

12. IANA 考虑事项

12.1. WebAuthn 声明语句格式标识符注册更新

本节对 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表 [IANA-WebAuthn-Registries] 中,§ 8 定义的声明语句格式中列出的格式进行了更新,前述注册表由 [RFC8809] 建立,初始注册源于 [WebAuthn-1],现指定引用为本规范。

12.2. WebAuthn 声明语句格式标识符注册

本节将 § 8 定义的声明语句格式中新定义的格式注册到由 [RFC8809] 建立的 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表中。

12.3. WebAuthn 扩展标识符注册更新

本节对 IANA "WebAuthn Extension Identifiers" 注册表 [IANA-WebAuthn-Registries] 中,§ 10 已定义扩展部分中列出的扩展标识符值进行了更新,前述注册表由 [RFC8809] 建立,初始注册源于 [WebAuthn-1],现指定引用为本规范。

12.4. WebAuthn 扩展标识符注册

本节将以下列出的 扩展标识符 值(在第 § 10 定义的扩展 节中新定义)注册到 IANA “WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries] 中,该注册表由 [RFC8809] 建立。

12.5. Well-Known URI 注册

本节将以下 well-known URI 注册到 IANA “Well-Known URIs” 注册表 [IANA-Well-Known-URIs] 中。

13. 安全考虑

本规范定义了一个 Web API 和一个加密对等实体身份验证协议。 Web 身份验证 API 允许 Web 开发者(即“作者”)在其 注册身份验证 仪式 中利用 Web 身份验证协议。 组成 Web 身份验证协议端点的实体是用户控制的 WebAuthn 认证器 和承载 依赖方Web 应用程序WebAuthn 依赖方 计算环境。 在此模型中,用户代理与 WebAuthn 客户端 一起,构成了 认证器依赖方 之间的中介。 此外,认证器 可以向 依赖方 证明 其来源。

目前,本规范不包含详细的安全注意事项。但是,[FIDOSecRef] 文档提供了适用于本规范的安全分析。 此外,[FIDOAuthnrSecReqs] 文档套件提供了有关 认证器 安全特性的有用信息。

以下小节包含当前的 Web 身份验证特定的安全注意事项。 它们按受众分类; 一般的安全注意事项是本节的直接小节, 而专门针对 认证器客户端依赖方 实施者的 安全注意事项则归类在各自的小节中。

13.1. 凭证 ID 未签名

伴随 身份验证断言凭证 ID 未被签名。 这不是问题,因为如果 认证器 返回了错误的 凭证 ID,或者 如果攻击者拦截并操纵了 凭证 ID,其后果只是 WebAuthn 依赖方 将无法查找正确的 凭证公钥 来验证返回的已签名 认证器数据 (即 断言),从而导致交互以错误结束。

13.2. 客户端与认证器之间的物理邻近性

在 WebAuthn 认证器模型 中,通常假设 漫游认证器 在物理上靠近 客户端 并与其直接通信。 这种安排具有一些重要的优势。

客户端认证器 之间的物理邻近性承诺是 你拥有的东西 身份验证因子 的关键优势。 例如,如果 漫游认证器 只能通过 USB 或蓝牙通信, 这些传输方式的有限范围确保任何恶意行为者 必须物理上处于该范围内才能与 认证器 交互。 对于可以远程调用的 认证器 来说,这不一定是真的 —— 即使 认证器 验证了 用户存在, 用户也可能被诱骗授权远程发起的恶意请求。

客户端认证器 之间的直接通信意味着 客户端 可以强制执行 范围 限制以保护 凭证。 相反,如果 客户端认证器 之间的通信由第三方调解, 那么 客户端 必须信任第三方来 强制执行 范围 限制并控制对 认证器 的访问。 未能做到其中任何一点都可能导致 恶意的 依赖方 接收到对其他 依赖方 有效的 身份验证断言, 或者导致恶意用户获得对其他用户的 身份验证断言 的访问权限。

如果设计的解决方案中 认证器 不需要在物理上靠近 客户端, 或者 客户端认证器 不 直接通信, 设计者应考虑这如何影响 范围 限制的执行 以及 认证器 作为 你拥有的东西 身份验证因子的强度。

13.3. 针对 认证器 的安全注意事项

13.3.1. 证明证书层次结构

建议采用三层证明证书层次结构(即证明根证书、证明颁发 CA、证明证书)。此外,建议为每个 WebAuthn 认证器 设备系列(即型号)使用单独的颁发 CA,以帮助隔离特定版本的认证器型号的问题。

如果证明根证书不专用于单个 WebAuthn 认证器 设备系列(即 AAGUID),则 AAGUID 应在证明证书本身中指定,以便可以对照 认证器数据 进行验证。

13.3.2. 证明证书和证明证书 CA 泄露

当用于颁发证明证书的中间 CA 或根 CA 遭到泄露时,WebAuthn 认证器证明密钥对 仍然是安全的,尽管其证书不再可信。WebAuthn 认证器 制造商如果记录了其 认证器 型号的 证明公钥,则可以从新的中间 CA 或新的根 CA 为这些密钥颁发新的 证明证书。如果根 CA 发生更改,WebAuthn 依赖方 必须 相应地更新其受信任的根证书。

如果 WebAuthn 认证器 证明证书私钥 遭到泄露,则必须由颁发 CA 撤销该证书。如果泄露是由于固件缺陷造成的,WebAuthn 认证器制造商可能需要发布固件更新,并将新的 证明私钥证书 注入到已制造的 WebAuthn 认证器 中。(发生此过程的过程不在 本规范范围内。)如果 WebAuthn 认证器 制造商没有此能力,那么 依赖方 可能无法再信任来自受影响的 WebAuthn 认证器 的任何进一步 证明声明

另请参阅 § 13.4.5 已撤销的证明证书 中关于 依赖方 的相关安全注意事项。

13.4. 针对 依赖方 的安全注意事项

13.4.1. WebAuthn 依赖方的安全优势

本规范为 WebAuthn 依赖方 提供的主要优势包括:

  1. 可以使用广泛兼容、易于使用的多因素身份验证来保护用户和账户。

  2. 依赖方 不需要向用户配置 认证器 硬件。相反,每个用户可以独立获取 任何符合要求的 认证器,并将同一个 认证器 用于任意数量的 依赖方依赖方 可以选择性地通过检查从 认证器 返回的 证明声明 来对 认证器 的安全属性强制执行要求。

  3. 身份验证仪式 可以抵御 中间人攻击。 关于 注册仪式,请参见下方的 § 13.4.4 证明限制

  4. 依赖方 可以自动支持多种类型的 用户验证 —— 例如 PIN、生物识别和/或 未来方法 —— 而无需或仅需很少的代码更改,并且可以让每个用户通过其选择的 认证器 来决定他们更喜欢使用哪种方法。

  5. 依赖方 不需要存储额外的秘密即可获得上述优势。

正如在 一致性 节中所述,依赖方 必须按照 § 7 WebAuthn 依赖方操作 中的描述行事 以获得上述所有安全优势。但是,下面 § 13.4.4 证明限制 中描述了一个与此稍有不同的值得注意的用例。

13.4.2. 嵌入式使用的可见性注意事项

在嵌入式上下文(例如,如 § 5.10 在 iframe 元素中使用 Web 身份验证 中所述的 iframe 中)中简单使用 WebAuthn,可能会使用户容易受到 UI 红色ressing 攻击(也称为“点击劫持”)的侵害。即攻击者将其自己的 UI 覆盖在 依赖方 的预期 UI 之上,并试图诱骗用户对 依赖方 执行非预期操作。例如,使用这些技术,攻击者可能能够诱骗用户购买商品、转账等。

尽管特定于 WebAuthn 的 UI 通常由 客户端平台 处理,因此不容易受到 UI 红色ressing 的影响,但对于拥有嵌入式 WebAuthn 内容的 依赖方 来说,确保其内容的 UI 对用户可见可能很重要。一种新兴的方法是观察实验性的 Intersection Observer v2isVisible 属性的状态。例如,在嵌入式上下文中运行的 依赖方 脚本如果检测到 isVisble 被设置为 false,可能会在弹出窗口中预先加载自身,从而避开其内容的任何遮挡。

13.4.3. 加密挑战

作为加密协议,Web 身份验证依赖于随机挑战来避免重放攻击。因此,PublicKeyCredentialCreationOptions.challengePublicKeyCredentialRequestOptions.challenge 的值必须由 依赖方 在其信任的环境(例如,在服务器端)中随机生成, 并且客户端响应中返回的 challenge 值必须与生成的值匹配。这应以不依赖客户端行为的方式完成,例如,依赖方 应暂时存储挑战,直到操作完成。容忍不匹配将危及协议的安全性。

挑战的有效期应类似于 WebAuthn 仪式超时的建议范围和默认值 的上限。

为了防止重放攻击,挑战必须包含足够的熵,以使得猜测它们是不可行的。因此,挑战应至少为 16 字节长。

13.4.4. 证明限制

本节不是规范性的。

注册新凭证 时,如果存在 证明声明,则可能允许 WebAuthn 依赖方 推断出关于各种 认证器 质量的保证。 例如,认证器 型号,或它如何存储和保护 凭证私钥。 但是,重要的是要注意,证明声明 本身不提供 任何手段让 依赖方 验证 证明对象 是否由用户预期的 认证器 生成,而不是由 中间人攻击者 生成。 例如,此类攻击者可以使用注入到 依赖方 脚本中的恶意代码。 因此,依赖方 必须依靠其他手段(例如 TLS 和相关技术)来保护 证明对象 免受 中间人攻击 的侵害。

假设 注册仪式 已安全完成,并且 认证器 保持 凭证私钥 的机密性,那么使用该 公钥凭证 的后续 身份验证仪式 可以抵御 中间人攻击 的篡改。

上述讨论适用于所有 证明类型。在所有情况下,中间人攻击者 都可以替换 PublicKeyCredential 对象,包括 证明声明 和 待注册的 凭证公钥,并随后篡改通过同一攻击者传递的、范围为 同一 依赖方 的未来 身份验证断言

这种攻击可能会被检测到;由于 依赖方 注册的是攻击者的 凭证公钥 而不是用户的公钥,因此攻击者必须篡改与该 依赖方 的所有后续 身份验证仪式: 未受影响的仪式将失败,从而可能揭示攻击。

自我证明 之外的 证明类型 可以增加此类攻击的难度,因为 依赖方 可以向用户显示 认证器 信息(例如型号名称)。因此,攻击者可能需要使用 与用户的 认证器 型号相同的 genuine 认证器,或者用户可能会注意到 依赖方 报告的 认证器 型号与其预期的不同。

注: 与针对传统密码身份验证的 中间人攻击 相比,攻击者实施上述所有 中间人攻击 变体的难度都更高。

13.4.5. 已撤销的证明证书

如果由于中间证明 CA 证书被撤销而导致 证明证书 验证失败,并且 依赖方 的策略 要求在这些情况下拒绝注册/身份验证请求,则建议 依赖方 同时注销(或标记为相当于“自我证明”的信任级别)在 CA 泄露日期之后使用链接到同一中间 CA 的 证明证书 注册的 公钥凭证。因此,建议 依赖方注册 期间记住中间证明 CA 证书,以便如果 注册 是在撤销此类证书之后执行的,则注销相关的 公钥凭证

另请参阅 § 13.3.2 证明证书和证明证书 CA 泄露 中关于 认证器 的相关安全注意事项。

13.4.6. 凭证丢失和密钥移动性

本规范没有定义用于备份 凭证私钥 或在 认证器 之间共享它们的协议。 通常,期望 凭证私钥 永远不会离开创建它的 认证器。因此,丢失 认证器 通常意味着丢失所有 凭证 绑定 到丢失的 认证器,如果用户只有一个 凭证依赖方 注册,这可能会将用户锁定在账户之外。除了备份或共享私钥之外,Web 身份验证 API 允许为同一用户注册多个 凭证。例如,用户可能在常用的 客户端设备 上注册 平台凭证,并注册一个或多个 漫游凭证 作为备份以及用于新设备或不常用的 客户端设备

依赖方 应该 允许并鼓励用户为同一 用户账户 注册多个 凭证依赖方 应该利用 excludeCredentialsuser.id 选项来确保这些不同的 凭证 绑定 到不同的 认证器

13.4.7. 无保护账户检测

本节不是规范性的。

此安全注意事项适用于支持以非 allowCredentials 参数作为第一步的 身份验证仪式依赖方。 例如,如果将使用 服务器端凭证 的身份验证作为第一步。

在这种情况下,allowCredentials 参数有泄露哪些 用户账户 已注册 WebAuthn 凭证以及哪些未注册的风险, 这可能是账户保护强度的信号。 例如,假设攻击者可以通过仅提供用户名来启动 身份验证仪式, 并且 依赖方 对某些 用户账户 响应非空的 allowCredentials, 而对其他 用户账户 响应失败或密码挑战。 然后攻击者可以得出结论,后者的 用户账户 可能不需要 WebAuthn 断言 即可成功进行身份验证, 从而将攻击重点集中在这些可能较弱的账户上。

此问题类似于 § 14.6.2 用户名枚举§ 14.6.3 通过凭证 ID 泄露隐私 中描述的问题,可以用类似的方式缓解。

13.4.8. 代码注入攻击

依赖方公钥凭证范围 内的 上执行的任何恶意代码都可能使 WebAuthn 可能提供的任何及所有安全保证失效。 WebAuthn 客户端 仅在 安全上下文 中公开 WebAuthn API, 这可以缓解最基本的攻击,但应与 依赖方 采取的额外预防措施相结合。

代码注入可以通过多种方式发生; 本节试图指出一些可能的场景并建议合适的缓解措施, 但这并非详尽无遗的列表。

13.4.9. 验证凭证的源

注册凭证 和 当 验证断言 时, 依赖方 必须 验证 客户端数据origin 成员。

依赖方 不得 接受意外的 origin 值, 因为这样做可能允许恶意网站获取有效的 凭证。 虽然 WebAuthn 凭证的 范围 防止在 它们注册的 RP ID 之外的域上使用它们, 但 依赖方 的源验证 提供了额外的保护层, 以防故障的 认证器 未能强制执行凭证 范围。 另请参阅 § 13.4.8 代码注入攻击 中关于潜在恶意子域的讨论。

验证可以通过精确字符串匹配或 依赖方 需要的任何其他方法来执行。 例如:

验证 客户端数据topOrigin 成员时适用类似的注意事项。 当 topOrigin 存在时,依赖方 必须验证其值是否符合预期。 此验证可以通过精确字符串匹配或 依赖方 需要的任何其他方法来执行。 例如:

14. 隐私考虑

[FIDO-Privacy-Principles] 中的隐私原则也适用于本规范。

本节按受众分类; 一般的隐私注意事项是本节的直接小节, 而专门针对 认证器客户端依赖方 实施者的 隐私注意事项则归类在各自的小节中。

14.1. 去匿名化预防措施

本节不是规范性的。

Web 身份验证 API 设计的许多方面都出于隐私考虑。本规范中考虑的主要问题是保护用户的个人身份,即识别自然人或属于同一自然人的不同身份之间的关联。尽管 Web 身份验证 API 不使用或不提供任何形式的全球身份,但使用了以下类型潜在可关联的标识符:

上述某些信息必须与 依赖方 共享。以下各节描述了为防止恶意的 依赖方 利用它来发现用户的个人身份而采取的措施。

14.2. 匿名、有范围、不可关联的 公钥凭证

本节不是规范性的。

虽然 凭证 ID凭证公钥 必须与 WebAuthn 依赖方 共享以实现强身份验证,但它们的设计旨在最大限度地减少识别性,并且不在 依赖方 之间共享。

此外,客户端可发现公钥凭证源 可以选择性地包含由 依赖方 指定的 用户句柄。然后,凭证 可用于识别和 身份验证 用户。 这意味着注重隐私的 依赖方 可以允许创建没有传统用户名的 用户账户,从而进一步提高 依赖方 之间的不可关联性。

14.3. 认证器本地的 生物特征识别

生物特征认证器认证器 内部执行 生物特征识别 —— 尽管对于 平台认证器,根据实现的不同,生物特征数据可能对 客户端 可见。生物特征数据不会透露给 WebAuthn 依赖方;它仅在本地用于执行 用户验证 以授权创建和 注册 或使用 身份验证 公钥凭证。因此,恶意的 依赖方 无法通过生物特征数据发现用户的个人身份,并且 依赖方 发生的安全漏洞也不会泄露生物特征数据,导致攻击者可以用来伪造其他 依赖方 的登录。

如果 依赖方 需要 生物特征识别,这由执行 用户验证生物特征认证器 在本地执行,然后通过在签名的 断言 响应中设置 UV 标志 来发出结果信号,而不是向 依赖方 透露生物特征数据本身。

14.4. 针对 认证器 的隐私注意事项

14.4.1. 证明隐私

证明证书证明密钥对 可用于跟踪用户或将同一用户的各种在线身份链接在一起。 这可以通过多种方式缓解,包括:

14.4.2. 存储在认证器中的个人身份信息隐私

认证器 可以向 客户端 提供本规范定义之外的额外信息,例如, 以便 客户端 能够提供丰富的用户界面,用户可以在其中选择要用于 身份验证仪式凭证。如果 认证器 选择这样做,除非已成功执行 用户验证,否则不应透露个人身份信息。如果 认证器 支持使用同时注册的多个用户进行 用户验证,则 认证器 不应透露当前 已验证 用户以外的用户的个人身份信息。因此,无法进行 用户验证认证器 不应存储个人身份信息。

为了本讨论的目的,作为 PublicKeyCredentialUserEntityid 成员传达的 用户句柄 不被视为个人身份信息;请参阅 § 14.6.1 用户句柄内容

这些建议旨在防止能够物理访问 认证器 的对手提取有关 认证器 注册用户的个人身份信息。

14.5. 针对 客户端 的隐私注意事项

14.5.1. 注册仪式隐私

为了保护用户在未经 同意 的情况下被识别, [[Create]](origin, options, sameOriginWithAncestors) 方法的实现需要注意不要泄露可能使恶意的 WebAuthn 依赖方 区分以下情况的信息, 其中“排除”意味着 依赖方excludeCredentials 中列出的至少一个 凭证 绑定认证器

如果上述情况是可区分的,则会泄露信息,恶意的 依赖方 可以通过探测哪些 凭证 可用来识别用户。例如,一种此类信息泄露是,一旦被排除的 认证器 变得可用,客户端立即返回失败响应。在这种情况下 —— 尤其如果被排除的 认证器平台认证器 —— 依赖方 可以检测到 仪式 在用户手动可行地取消它之前就被取消了,从而得出结论,用户至少拥有 凭证 列表中的一个 excludeCredentials 参数。

然而,如果在返回可区分的错误之前用户已 同意 创建新凭证,则上述情况就不构成问题,因为在这种情况下,用户已确认了共享将要泄露的信息的意图。

14.5.2. 身份验证仪式隐私

为了保护用户在未经 同意 的情况下被识别, [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 方法的实现需要注意不要泄露可能使恶意的 WebAuthn 依赖方 区分以下情况的信息, 其中“命名”意味着 依赖方allowCredentials 中列出了 凭证

如果上述情况是可区分的,则会泄露信息,恶意的 依赖方 可以通过探测哪些 凭证 可用来识别用户。 例如,如果客户端仅在发现 包含 命名 凭证认证器 之后,才显示用于取消或继续进行 身份验证仪式 的说明和控件,则可能会发生此类信息泄露。在这种情况下,如果 依赖方 知道这种 客户端 行为, 依赖方 可以检测到 仪式 是由用户取消的,而不是超时,从而得出结论,用户至少拥有 凭证 列表中的一个 allowCredentials 参数可用。

可以通过显示允许用户随时取消 身份验证仪式 的控件来解决此问题, 无论是否有任何命名 凭证 可用。

14.5.3. 操作系统账户之间的隐私

如果 平台认证器 包含在具有多用户操作系统的 客户端设备 中,平台认证器客户端设备 应协同工作,以确保任何 平台凭证 的存在仅向创建该 平台凭证 的操作系统用户公开。

14.5.4. 披露客户端功能

getClientCapabilities 方法帮助 WebAuthn 依赖方 制定注册和身份验证体验,这些体验在客户端和/或用户方面具有很高的成功概率。

WebAuthn 客户端 对某项功能的支持或不支持可能会带来指纹识别风险。为了降低此风险,客户端应倾向于从返回的记录中省略某个键,而不是返回 false 值。省略该键(如 § 5.1.7 客户端功能的可用性 - PublicKeyCredential 的 getClientCapabilities() 方法 中所述)比明确确认不支持某个功能提供更小的指纹识别表面。客户端实现可能还希望根据客户端策略和/或用户同意来限制功能披露。

14.6. 针对 依赖方 的隐私注意事项

14.6.1. 用户句柄内容

由于 用户句柄§ 14.4.2 存储在认证器中的个人身份信息隐私 中不被视为个人身份信息, 并且由于 认证器 可能会在首先执行 用户验证 之前透露 用户句柄依赖方 不得在 用户句柄 中包含个人身份信息(例如电子邮件 地址或用户名)。这包括个人身份信息的哈希值,除非哈希函数使用 依赖方 私有的 值进行了 加盐,因为哈希无法防止探测可猜测的输入值。建议让 用户句柄 为 64 个随机字节,并将此值存储在 用户账户 中。

14.6.2. 用户名枚举

在启动 注册身份验证仪式 时, 存在 WebAuthn 依赖方 可能泄露有关其注册用户的敏感信息的风险。例如,如果 依赖方 使用电子邮件地址作为用户名,攻击者尝试为 "alex.mueller@example.com" 启动 身份验证 仪式,并且 依赖方 响应失败,但随后成功为 "j.doe@example.com" 启动了 身份验证仪式,那么攻击者可以得出结论,"j.doe@example.com" 已注册,而 "alex.mueller@example.com" 未注册。因此,依赖方 泄露了可能的敏感信息,即 "j.doe@example.com" 在此 依赖方 拥有 用户账户

以下是 依赖方 可实施以缓解或防止由于此类攻击导致的信息泄露的非规范性、非详尽措施列表:

14.6.3. 通过凭证 ID 泄露隐私

本节不是规范性的。

此隐私注意事项适用于支持以非 allowCredentials 参数作为第一步进行 身份验证仪式依赖方。 例如,如果将使用 服务器端凭证 的身份验证作为第一步。

在这种情况下,allowCredentials 参数有泄露个人身份信息的风险, 因为它将用户的 凭证 ID 暴露给未经身份验证的调用者。 凭证 ID 的设计旨在使其在 依赖方 之间不可关联,但 凭证 ID 的长度可能提示创建它的 认证器 类型。 用户很可能会对多个 依赖方 使用相同的用户名和 认证器 集, 因此,allowCredentials凭证 ID 的数量及其长度 可能会用作全局关联句柄以对用户进行去匿名化。 知道用户的 凭证 ID 还使得仅凭借对用户其中一个 认证器 的短暂物理访问,即可确认有关用户身份的猜测。

为了防止此类信息泄露,依赖方 可以例如:

如果上述预防措施不可用, 即如果仅给定用户名就需要暴露 allowCredentials依赖方 可以使用 § 14.6.2 用户名枚举 中讨论的返回假想 凭证 ID 的相同方法来缓解隐私泄露。

发出信号 表明未识别 凭证 id 时, WebAuthn 依赖方 应使用 signalUnknownCredential(options) 方法而不是 signalAllAcceptedCredentials(options) 方法,以避免将 凭证 ID 暴露给未经身份验证的调用者。

15. 无障碍可及性注意事项

用户验证-capable 认证器, whether 漫游 or 平台, should offer users more than one user verification method. For example, both fingerprint sensing and PIN entry. This allows for fallback to other user verification means if the selected one is not working for some reason. Note that in the case of 漫游 认证器, the authenticator and platform might work together to provide a user verification method such as PIN entry [FIDO-CTAP].

依赖方, at 注册 time, SHOULD provide affordances for users to complete future 授权操作 correctly. This could involve naming the authenticator, choosing a picture to associate with the device, or entering freeform text instructions (e.g., as a reminder-to-self).

Ceremonies relying on timing, e.g., a 注册典礼 (见 timeout) or an 认证典礼 (见 timeout), ought to follow [WCAG21]’s Guideline 2.2 Enough Time. If a client platform determines that a 依赖 方-supplied timeout does not appropriately adhere to the latter [WCAG21] guidelines, then the 客户端平台 MAY adjust the timeout accordingly.

The WebAuthn 典礼超时的推荐范围及默认值 is as follows:

16. 测试向量

本节为非规范性内容。

本节列举了可用于验证实现的示例值。

示例以伪代码形式,成对呈现为同一注册认证流程,使用同一个凭证,字节串字面量和注释采用CDDL [RFC8610] 记法。 这些示例并不穷尽,也未包含WebAuthn扩展

这些示例以输入到输出的流程结构展现,并包含部分中间值。 在注册示例中,服务方定义challenge 输入, 客户端生成clientDataJSON 输出, 认证器 生成attestationObject 输出。 在认证示例中,服务方定义challenge 输入, 客户端生成clientDataJSON 输出, 认证器 生成 authenticatorDatasignature 输出。 其他与加密无关的输入和输出未包括在内。

认证器的实现者可检查其生成的 attestationObjectauthenticatorDatasignature 输出结构与示例一致。 客户端实现者可检查其生成的clientDataJSON 输出结构是否一致。 服务方实现者可检查他们可否用相同 challenge 输入成功验证注册输出,以及用相同 challenge 输入、 凭证公钥凭证ID 成功验证认证输出。

所有示例使用RP ID example.orgorigin https://example.org, 如适用还包含topOrigin https://example.com。 除非另有说明,示例均为无声明情况。 注意,组合对象如clientDataJSONattestationObject与声明证书等,可能包含伪代码未特别说明的其他通常为常量的数据。

所有随机值均通过HKDF-SHA-256 [RFC5869] ,以CDDL中'WebAuthn test vectors'为标记的基础输入密钥材料(等价为h’576562417574686e207465737420766563746f7273')确定性生成。 ECDSA签名采用确定性nonce [RFC6979]。 示例中的RSA密钥由不小于1024的两个最小梅森素数2p - 1 构成。

注意:

注意: 实现CTAP2 [FIDO-CTAP]认证器返回的声明对象 所用密钥与本规范定义的不同。 这些示例反映了WebAuthn服务方期望接收的声明对象格式, 因此由CTAP2输出的声明对象 需经过密钥转换才能与这些示例位级一致。

16.1. 声明信任根证书

所有包含 声明 的示例都使用下文作为 attestation_ca_cert 给出的声明信任根证书,采用 X.509 DER 编码 [RFC5280]:

attestation_ca_key = h'7809337f05740a96a78eedf9e9280499dcc8f2aa129616049ec1dccfe103eb2a'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='Attestation CA', L=32)
attestation_ca_serial_number = h'ed7f905d8bd0b414d1784913170a90b6'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='Attestation CA', L=16)
attestation_ca_cert = h'30820207308201ada003020102021100ed7f905d8bd0b414d1784913170a90b6300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a3062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d030107034200043269300e5ff7b699015f70cf80a8763bf705bc2e2af0c1b39cff718b7c35880ca30f319078d91b03389a006fdfc8a1dcd84edfa07d30aa13474a248a0dab5baaa3423040300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e0416041445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d04030203480030450220483063b6bb08dcc83da33a02c11d2f42203176893554d138c614a36908724cc8022100f5ef2c912d4500b3e2f5b591d0622491e9f220dfd1f9734ec484bb7e90887663'

16.2. 无声明的 ES256 凭证

注册:

challenge = h'00c30fb78531c464d2b6771dab8d7b603c01162f2fa486bea70f283ae556e130'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256', L=32)

credential_private_key = h'6e68e7a58484a3264f66b77f5d6dc5bc36a47085b615c9727ab334e8c369c2ee'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256', L=32)
client_data_gen_flags = h'f9'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'06441e0e375c4c1ad70620302532c4e5' = b64'BkQeDjdcTBrXBiAwJTLE5Q'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256', L=16)
aaguid = h'8446ccb9ab1db374750b2367ff6f3a1f'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256', L=16)
credential_id = h'f91f391db4c9b2fde0ea70189cba3fb63f579ba6122b33ad94ff3ec330084be4'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'ba'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256', L=1)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22414d4d507434557878475453746e63647134313759447742466938767049612d7077386f4f755657345441222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20426b5165446a646354427258426941774a544c453551227d'
attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b559000000008446ccb9ab1db374750b2367ff6f3a1f0020f91f391db4c9b2fde0ea70189cba3fb63f579ba6122b33ad94ff3ec330084be4a5010203262001215820afefa16f97ca9b2d23eb86ccb64098d20db90856062eb249c33a9b672f26df61225820930a56b87a2fca66334b03458abf879717c12cc68ed73290af2e2664796b9220'

认证:

challenge = h'39c0e7521417ba54d43e8dc95174f423dee9bf3cd804ff6d65c857c9abf4d408'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256', L=32)

client_data_gen_flags = h'4a'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'38'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224f63446e55685158756c5455506f334a5558543049393770767a7a59425039745a63685879617630314167222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'3046022100f50a4e2e4409249c4a853ba361282f09841df4dd4547a13a87780218deffcd380221008480ac0f0b93538174f575bf11a1dd5d78c6e486013f937295ea13653e331e87'

16.3. 带自签声明的 ES256 凭证

注册:

challenge = h'7869c2b772d4b58eba9378cf8f29e26cf935aa77df0da89fa99c0bdc0a76f7e5'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed-self.ES256', L=32)

credential_private_key = h'b4bbfa5d68e1693b6ef5a19a0e60ef7ee2cbcac81f7fec7006ac3a21e0c5116a'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed-self.ES256', L=32)
client_data_gen_flags = h'db'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed-self.ES256', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'53d8535ef284d944643276ffd3160756' = b64'U9hTXvKE2URkMnb_0xYHVg'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed-self.ES256', L=16)
aaguid = h'df850e09db6afbdfab51697791506cfc'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed-self.ES256', L=16)
credential_id = h'455ef34e2043a87db3d4afeb39bbcb6cc32df9347c789a865ecdca129cbef58c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed-self.ES256', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'fd'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed-self.ES256', L=1)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2265476e4374334c55745936366b336a506a796e6962506b31716e666644616966715a774c33417032392d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205539685458764b453255526b4d6e625f307859485667227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a263616c672663736967584630440220067a20754ab925005dbf378097c92120031581c73228d1fb4f5b881bcd7da98302207fc7b147558c7c0eba3af18bd9d121fa3d3a26d17fe3f220272178f473b6006d68617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000df850e09db6afbdfab51697791506cfc0020455ef34e2043a87db3d4afeb39bbcb6cc32df9347c789a865ecdca129cbef58ca5010203262001215820eb151c8176b225cc651559fecf07af450fd85802046656b34c18f6cf193843c5225820927b8aa427a2be1b8834d233a2d34f61f13bfd44119c325d5896e183fee484f2'

认证:

challenge = h'4478a10b1352348dd160c1353b0d469b5db19eb91c27f7dfa6fed39fe26af20b'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed-self.ES256', L=32)

client_data_gen_flags = h'1f'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed-self.ES256', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'8136f9debcfa121496a265c6ce2982d5' = b64'gTb53rz6EhSWomXGzimC1Q'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed-self.ES256', L=16)
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'a1'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed-self.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a225248696843784e534e493352594d45314f7731476d3132786e726b634a5f6666707637546e2d4a71386773222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206754623533727a36456853576f6d58477a696d433151227d'
signature = h'304402203310b9431903c401f1be2bdc8d23a4007682dbbddcf846994947b7f465daf84002204e94dd00047b316061b3b99772b7efd95994a83ef584b3b6b825ea3550251b66'

16.4. 在 clientDataJSON 中带 "crossOrigin": true 的 ES256 凭证

注册:

challenge = h'3be5aacd03537142472340ab5969f240f1d87716e20b6807ac230655fa4b3b49'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.crossOrigin', L=32)

credential_private_key = h'96c940e769bd9f1237c119f144fa61a4d56af0b3289685ae2bef7fb89620623d'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.crossOrigin', L=32)
client_data_gen_flags = h'71'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.crossOrigin', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'cd9aae12d0d1f435aaa56e6d0564c5ba' = b64'zZquEtDR9DWqpW5tBWTFug'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.crossOrigin', L=16)
aaguid = h'883f4f6014f19c09d87aa38123be48d0'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.crossOrigin', L=16)
credential_id = h'6e1050c0d2ca2f07c755cb2c66a74c64fa43065c18f938354d9915db2bd5ce57'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.crossOrigin', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'27'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.crossOrigin', L=1)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a224f2d57717a514e5463554a484930437257576e7951504859647862694332674872434d475666704c4f306b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a207a5a7175457444523944577170573574425754467567227d'
attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54500000000883f4f6014f19c09d87aa38123be48d000206e1050c0d2ca2f07c755cb2c66a74c64fa43065c18f938354d9915db2bd5ce57a501020326200121582022200a473f90b11078851550d03b4e44a2279f8c4eca27b3153dedfe03e4e97d225820cbd0be95e746ad6f5a8191be11756e4c0420e72f65b466d39bc56b8b123a9c6e'

认证:

challenge = h'876aa517ba83fdee65fcffdbca4c84eeae5d54f8041a1fc85c991e5bbb273137'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.crossOrigin', L=32)

client_data_gen_flags = h'57'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.crossOrigin', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'f76a5c4d50f401bcbeab876d9a3e9e7e' = b64'92pcTVD0Aby-q4dtmj6efg'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256.crossOrigin', L=16)
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'0c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='none.ES256.crossOrigin', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50500000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a226832716c463771445f65356c5f505f62796b7945377135645650674547685f49584a6b655737736e4d5463222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2039327063545644304162792d713464746d6a36656667227d'
signature = h'3046022100eb12fcf23b12764c0f122e22371fab92e283879fd798f38ee1841c951b6e40e7022100c76237ff9db77b3c56f30837cda6a09acfa2e915544e609c0733b1184036d1cf'

16.5. 在 clientDataJSON 中带 "topOrigin" 的 ES256 凭证

注册:

challenge = h'4e1f4c6198699e33c14f192153f49d7e0e8e3577d5ac416c5f3adc92a41f27e5'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.topOrigin', L=32)

credential_private_key = h'a2d6de40ab974b80d8c1ef78c6d4300097754f7e016afe7f8ea0ad9798b0d420'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.topOrigin', L=32)
client_data_gen_flags = h'54'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.topOrigin', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
aaguid = h'97586fd09799a76401c200455099ef2a'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.topOrigin', L=16)
credential_id = h'b8ad59b996047ab18e2ceb57206c362da57458793481f4a8ebf101c7ca7cc0f1'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.topOrigin', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'a0'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.topOrigin', L=1)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a225468394d595a68706e6a504254786b68555f53646667364f4e58665672454673587a72636b7151664a2d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22746f704f726967696e223a2268747470733a2f2f6578616d706c652e636f6d227d'
attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b5410000000097586fd09799a76401c200455099ef2a0020b8ad59b996047ab18e2ceb57206c362da57458793481f4a8ebf101c7ca7cc0f1a5010203262001215820a1c47c1d82da4ebe82cd72207102b380670701993bc35398ae2e5726427fe01d22582086c1080d82987028c7f54ecb1b01185de243b359294a0ed210cd47480f0adc88'

认证:

challenge = h'd54a5c8ca4b62a8e3bb321e3b2bc73856f85a10150db2939ac195739eb1ea066'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.topOrigin', L=32)

client_data_gen_flags = h'77'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.topOrigin', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'52216824c5514070c0156162e2fc54a5' = b64'UiFoJMVRQHDAFWFi4vxUpQ'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.topOrigin', L=16)
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'9f'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256.topOrigin', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50500000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22315570636a4b53324b6f34377379486a7372787a68572d466f51465132796b3572426c584f6573656f4759222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22746f704f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205569466f4a4d56525148444146574669347678557051227d'
signature = h'3045022100b5a70c81780d5fcc9a4f2ae9caae99058f8accaf58b91fb59329646c28ac6ffc022012e101c165db3c8e9957f0c54dd6ca9b56bc3bd2f280bd2faa6c1d02c6e5c171'

16.6. 具有非常长凭证 ID 的 ES256 凭证

注册:

challenge = h'1113c7265ccf5e65124282fa1d7819a7a14cb8539aa4cdbec7487e5f35d8ec6c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.long-credential-id', L=32)

credential_private_key = h'6fd2149bb5f1597fe549b138794bde61893b2dc32ca316de65f04808dac211dc'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.long-credential-id', L=32)>
client_data_gen_flags = h'90'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.long-credential-id', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
aaguid = h'8f3360c2cd1b0ac14ffe0795c5d2638e'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.long-credential-id', L=16)>
credential_id = h'3a761a4e1674ad6c4305869435c0eee9c286172c229bb91b48b4ada140c0863417031305cce5b4a27a88d7fe728a5f5a627de771b4b40e77f187980c124f9fe832d7136010436a056cce716680587d23187cf1fc2c62ae86fc3e508ee9617ffc74fbc10488ec16ec5e9096328669a898709b655e549738c666c1ae6281dc3b5f733c251d3eefb76ee70a3805ca91bcc18e49c8dc7f63ebcb486ba8c3d6ab52b88ff72c6a5bb47c32f3ee8683a3ddc8abf60870448ec8a21b5bdcb183c7dead870255575a6df96eb1b6a2a1019780cba9e4887b17ff1164bbbcc10eb0d86ed75984cd3fa3419103024507dfd9ce8f92c56af7914cb0bb50b87ba82a312bb7dcd93028dbdcd6adb266979667158335171e3682d37755701edbf9d872846a291d49e57ef09da1ec637f5052ed2aa7407f7e61827468e94b461844f4c67be5fa9c6055a566f8fdfc29d4bf78a9ff275f552cc68ba543fa3962eea36fd1ea8453764577d021d0a181efc1f6100ab2e4110039e21ee16970bda7432b6134492155afc126295b3a2eccd12c66a68e340969e995e3e8c9c476e395cfc21203414110779474f1c9797406637dbe414f132519d3bf0ce4f01734ef0e1a12c3ad604ff15d766b1624db6a5a7ccbff7bc35c9908df94aba277e0af48f04ff3d16381c47e5a37ed3988a67a3b1ecaa926336b33391fff04128f869991c9fabd905b6fe3ceef5f8b630ec1c5d2636d5b1961ad5ca5004170f6f5e482792aad989b0287fe91e5c479403397152f1fa56aa79b156eb47e6c8ea3eb175c34cfb38ad8e772874639b1023d4d01395c94e55831671cc022aa6fa1e02a02c2e4abc776f6960e51f83b71a8c0f207b6a347573977812c9aa5480b0011aa739bd4b76c18c000cc4757cceccb920f007c40c00e37e5ab21476cd9f6054a8fffb55a108f5c706e2cea2049d81fd321ff47d2a5761b0800955ab1d4f4889f55a84e2601c684f17a4ade7453ea49591d0b59c8d9a765052f62219cf6ef4a5dd9539f0617d6ebbebce7c000455475d18449e25c49ef9a1e3efe18c09082ebe2058d7c347defaa92f0664553b805c7d76bbfce5f330aca220ac90a789380fc479ea0d8793205813cca590a912f699ad52f991a1bc0a503c3ec4b2a696719e3c26591a87127f7305cc7e72f4c8e39355ebb06a5b1042990f38710ee7aa612ee4374bb82e878585a70a96c2a6b47f101a4ff154be4fd76a3167577a5cc54d9167c154c69ac35485e44cc898b719e1be3cc9c0fb5624b8f8a0dae10947a41bf848b6c1bb33d1006ec077d7e286e3f2a7b4843716390119449fe2721e81a5ed2333d331c7120765da58fadae73c19d9a8c4509cf8ac1e9d98b799a5274509069739b5823f3fb496663820033426988eefca53e580e0f9e0dfe0992fc2e53a97e053639f98577058f995bdbd41cefdb'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.long-credential-id', L=1023)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'69'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.long-credential-id', L=1)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22455250484a6c7a50586d5553516f4c364858675a7036464d75464f61704d322d7830682d587a5859374777222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d74646e6f6e656761747453746d74a0686175746844617461590483bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b549000000008f3360c2cd1b0ac14ffe0795c5d2638e03ff3a761a4e1674ad6c4305869435c0eee9c286172c229bb91b48b4ada140c0863417031305cce5b4a27a88d7fe728a5f5a627de771b4b40e77f187980c124f9fe832d7136010436a056cce716680587d23187cf1fc2c62ae86fc3e508ee9617ffc74fbc10488ec16ec5e9096328669a898709b655e549738c666c1ae6281dc3b5f733c251d3eefb76ee70a3805ca91bcc18e49c8dc7f63ebcb486ba8c3d6ab52b88ff72c6a5bb47c32f3ee8683a3ddc8abf60870448ec8a21b5bdcb183c7dead870255575a6df96eb1b6a2a1019780cba9e4887b17ff1164bbbcc10eb0d86ed75984cd3fa3419103024507dfd9ce8f92c56af7914cb0bb50b87ba82a312bb7dcd93028dbdcd6adb266979667158335171e3682d37755701edbf9d872846a291d49e57ef09da1ec637f5052ed2aa7407f7e61827468e94b461844f4c67be5fa9c6055a566f8fdfc29d4bf78a9ff275f552cc68ba543fa3962eea36fd1ea8453764577d021d0a181efc1f6100ab2e4110039e21ee16970bda7432b6134492155afc126295b3a2eccd12c66a68e340969e995e3e8c9c476e395cfc21203414110779474f1c9797406637dbe414f132519d3bf0ce4f01734ef0e1a12c3ad604ff15d766b1624db6a5a7ccbff7bc35c9908df94aba277e0af48f04ff3d16381c47e5a37ed3988a67a3b1ecaa926336b33391fff04128f869991c9fabd905b6fe3ceef5f8b630ec1c5d2636d5b1961ad5ca5004170f6f5e482792aad989b0287fe91e5c479403397152f1fa56aa79b156eb47e6c8ea3eb175c34cfb38ad8e772874639b1023d4d01395c94e55831671cc022aa6fa1e02a02c2e4abc776f6960e51f83b71a8c0f207b6a347573977812c9aa5480b0011aa739bd4b76c18c000cc4757cceccb920f007c40c00e37e5ab21476cd9f6054a8fffb55a108f5c706e2cea2049d81fd321ff47d2a5761b0800955ab1d4f4889f55a84e2601c684f17a4ade7453ea49591d0b59c8d9a765052f62219cf6ef4a5dd9539f0617d6ebbebce7c000455475d18449e25c49ef9a1e3efe18c09082ebe2058d7c347defaa92f0664553b805c7d76bbfce5f330aca220ac90a789380fc479ea0d8793205813cca590a912f699ad52f991a1bc0a503c3ec4b2a696719e3c26591a87127f7305cc7e72f4c8e39355ebb06a5b1042990f38710ee7aa612ee4374bb82e878585a70a96c2a6b47f101a4ff154be4fd76a3167577a5cc54d9167c154c69ac35485e44cc898b719e1be3cc9c0fb5624b8f8a0dae10947a41bf848b6c1bb33d1006ec077d7e286e3f2a7b4843716390119449fe2721e81a5ed2333d331c7120765da58fadae73c19d9a8c4509cf8ac1e9d98b799a5274509069739b5823f3fb496663820033426988eefca53e580e0f9e0dfe0992fc2e53a97e053639f98577058f995bdbd41cefdb'

认证:

challenge = h'ef1deba56dce48f674a447ccf63b9599258ce87648e5c396f2ef0ca1da460e3b'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.long-credential-id', L=32)

client_data_gen_flags = h'80'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.long-credential-id', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'e5'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.long-credential-id', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22377833727057334f53505a307045664d396a75566d53574d36485a4935634f573875384d6f647047446a73222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'304502203ecef83fb12a0cae7841055f9f87103a99fd14b424194bbf06c4623d3ee6e3fd022100d2ace346db262b1374a6b70faa51f518a42ddca13a4125ce6f5052a75bac9fb6'

16.7. 使用 ES256 凭证的 Packed 声明

注册:

challenge = h'c1184a5fddf8045e13dc47f54b61f5a656b666b59018f16d870e9256e9952012'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES256', L=32)

credential_private_key = h'36ed7bea2357cefa8c4ec7e134f3312d2e6ca3058519d0bcb4c1424272010432'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES256', L=32)
client_data_gen_flags = h'8d'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'f5af1b3588ca0a05ab05753e7c29756a' = b64'9a8bNYjKCgWrBXU-fCl1ag'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES256', L=16)
aaguid = h'876ca4f52071c3e9b25509ef2cdf7ed6'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES256', L=16)
credential_id = h'c9a6f5b3462d02873fea0c56862234f99f081728084e511bb7760201a89054a5'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES256', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'4f'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES256', L=1)
attestation_private_key = h'ec2804b222552b4b277d1f58f8c4343c0b0b0db5474eb55365c89d66a2bc96be'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES256', L=32)
attestation_cert_serial_number = h'88c220f83c8ef1feafe94deae45faad0'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a227752684b58393334424634543345663153324831706c61325a725751475046746877365356756d56494249222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20396138624e596a4b436757724258552d66436c316167227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c6726637369675847304502203f19ec4b229f46ab8c45eff29b904ff10c0390dc40bf1216f04a78f4ceba3425022100fe7041a32759aff05a0f9f26c70a999c7a284451ba89234a1d3483c25e21925b637835638159022530820221308201c8a00302010202110088c220f83c8ef1feafe94deae45faad0300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004a91ba4389409dd38a428141940ca8feb1ac0d7b4350558104a3777a49322f3798440f378b3398ab2d3bb7bf91322c92eb23556f59ad0a836fec4c7663b0e4dc3a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414a589ba72d060842ab11f74fb246bdedab16f9b9b301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d040302034700304402201726b9d85ecd8a5ed51163722ca3a20886fd9b242a0aa0453d442116075defd502207ef471e530ac87961a88a7f0d0c17b091ffc6b9238d30f79f635b417be5910e768617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d00000000876ca4f52071c3e9b25509ef2cdf7ed60020c9a6f5b3462d02873fea0c56862234f99f081728084e511bb7760201a89054a5a50102032620012158201cf27f25da591208a4239c2e324f104f585525479a29edeedd830f48e77aeae522582059e4b7da6c0106e206ce390c93ab98a15a5ec3887e57f0cc2bece803b920c423'

认证:

challenge = h'b1106fa46a57bef1781511c0557dc898a03413d5f0f17d244630c194c7e1adb5'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES256', L=32)

client_data_gen_flags = h'75'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'019330c8cc486c3f3eba0b85369eabf1' = b64'AZMwyMxIbD8-uguFNp6r8Q'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.ES256', L=16)
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'46'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0c', info='packed.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273524276704770587676463446524841565833496d4b4130453958773858306b526a44426c4d6668726255222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20415a4d77794d78496244382d756775464e7036723851227d'
signature = h'30450220694969d3ee928de6f02ef23a9c644d7d779916451734a94b432542f498a1ebe90221008b0819c824218a97152cd099c55bfb1477b29d900a49a64018314f9bfccda163'

16.8. 使用 ES384 凭证的 Packed 声明

注册:

challenge = h'567b030b3e186bc1d169dd45b79f9e0d86f1fd63474da3eade5bdb8db379a0c3'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES384', L=32)

credential_private_key = h'271e37d309c558c0f35222b37abba7500377d68e179e4c74b0cb558551b2e5276b47b90a317ca8ebbe1a12c93c2d5dd9'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES384', L=48)
client_data_gen_flags = h'32'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES384', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
aaguid = h'e950dcda3bdae1d087cda380a897848b'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES384', L=16)
credential_id = h'953ae2dd9f28b1a1d5802c83e1f65833bb9769a08de82d812bc27c13fc6f06a9'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES384', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'db'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES384', L=1)
attestation_private_key = h'8d979fbb6e49c4eeb5925a2bca0fcdb023d3fb90bcadce8391da9da4ed2aee9a'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES384', L=32)
attestation_cert_serial_number = h'3d0a5588bb87ebb1d4cee4a1807c1b7c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES384', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22566e7344437a3459613848526164314674352d65445962785f574e4854615071336c76626a624e356f4d4d222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022100c56ecc970b7843833e0f461fde26233f61eb395161d481558c08b9c6ed61675b022029f5e05033705cd0f9b0a07e149468ec308a4f84906409efdceb1da20a7518d6637835638159022530820221308201c7a00302010202103d0a5588bb87ebb1d4cee4a1807c1b7c300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000417e5cc91d676d370e36aa7de40c25aacb45a3845f13d2932088ece2270b9b431241c219c22d0c256c9438ade00f2c05e62f8ef906b9b997ae9f3c460c2db66f5a360305e300c0603551d130101ff04023000300e0603551d0e04160414c7c8dd95382a2230e4c0dd3664338fa908169a9c301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020348003045022054068cc9ae038937b7c468c307edb9c6927ffdeb6a20070c483eb40330f99f10022100cf41953919c3c04693d6b1f42a613753f204e70e85fc6e9b17036170b83596e068617574684461746158c5bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55900000000e950dcda3bdae1d087cda380a897848b0020953ae2dd9f28b1a1d5802c83e1f65833bb9769a08de82d812bc27c13fc6f06a9a5010203382220022158304866bd8b01da789e9eb806e5eab05ae5a638542296ab057a2f1bbce9b58f8a08b9171390b58a37ac7fffc2c5f45857da2258302a0b024c7f4b72072a1f96bd30a7261aae9571dd39870eb29e55c0941c6b08e89629a1ea1216aa64ce57c2807bf3901a'

认证:

challenge = h'ff41c3d25dbd8966fb61e28ef5e47041e137ed268520412d76202ba0ad2d1453'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES384', L=32)

client_data_gen_flags = h'0c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES384', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'af'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES384', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a225f304844306c32396957623759654b4f39655277516545333753614649454574646941726f4b307446464d222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'3065023100e4efbb46745ed00e67c4d51ab2bacab2af62ffa8b7c5fecec6d7d9bf2582275034a713a3dd731685eee81adfaf6aa63f0230161655353f07e018a3c2539f8de7c8c4cf88d4c32d2be29fe4e76fa096ecc9458bbfe0895d57129ab324130e6f0692db'

16.9. 使用 ES512 凭证的 Packed 声明

注册:

challenge = h'4ee220cd92b07e11451cb4c201c5755bd879848e492a9b12d79135c62764dc2fd28ead4808cafe5ad1de8fa9e08d4a8eeafea4dfb333877b02bc503f475d3b0c1394a7683baaf4f2477829f7b8cf750948985558748c073068396fcfdcd3f245bf2038e6bb38d7532768aad13be8c118f727722e7426139041e9caca503884c5'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES512', L=128)

credential_private_key = h'f11120594f6a4944ac3ba59adbbc5b85016895b649f4cc949a610f4b48be47b318850bacb105f747647bba8852b6b8e52a0b3679f1bbbdfe18c99409bcb644fa45'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES512', L=65)
client_data_gen_flags = h'6d'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES512', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'a37a958ce2f6b535a6e06c64cc8fd082' = b64'o3qVjOL2tTWm4GxkzI_Qgg'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES512', L=16)
aaguid = h'39d8ce6a3cf61025775083a738e5c254'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES512', L=16)
credential_id = h'd17d5af7e3f37c56622a67c8462c9e1c6336dfccb8b61d359dc47378dba58ce4'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES512', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'cf'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES512', L=1)
attestation_private_key = h'ffbc89d5f75994f52dc5e7538ee269402d26995d40c16fb713473e34fca98be4'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES512', L=32)
attestation_cert_serial_number = h'8a128b7ebe52b993835779e6d9b81355'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES512', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22547549677a5a4b7766684646484c544341635631573968356849354a4b707353313545317869646b33435f536a713149434d722d577448656a366e676a55714f3676366b33374d7a683373437646415f5231303744424f5570326737717654795233677039376a5064516c496d465659644977484d47673562385f63305f4a46767941343572733431314d6e614b72524f2d6a424750636e636935304a684f5151656e4b796c4134684d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206f3371566a4f4c327454576d3447786b7a495f516767227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022100ce158f6c04aa5c14c0dd3e1103cf93664896fb5c337a66dbd7dba31546ff0d41022071cbcd0d3b8e218a6d05374e0ef8031329d25059002ac1603d02d5fd8a0a29cb637835638159022730820223308201c8a0030201020211008a128b7ebe52b993835779e6d9b81355300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004940b68885291536e2f7c60c05acfb252e7eebcf4304425dd93ab7b1962f20492bf18dc0f12862599e81fb764ac92151f9a78fcbb35d7a26c8c52949b18133c06a360305e300c0603551d130101ff04023000300e0603551d0e04160414c7c8dd95382a2230e4c0dd3664338fa908169a9c301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100832c8b64c4f0188bd32e1bec63e13301cdc03165d3ef840d1f3dabb9a5719f83022100add57a9d5bedec98f29222dfc97ea795d055ee13a02a153d02be9ce00aedeb9168617574684461746158e9bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d0000000039d8ce6a3cf61025775083a738e5c2540020d17d5af7e3f37c56622a67c8462c9e1c6336dfccb8b61d359dc47378dba58ce4a5010203382320032158420083240a2c3ad21a3dc0a6daa3d8bc05a46d7cd9825ba010ae2a22686c2d6d663d7d5f678987fb1e767542e63dc197ae915e25f8ee284651af29066910a2cc083f50225842017337df47ab5cce5d716ef8caffa97a3012689b1f326ea6c43a1ba9596c72f71f0122390143552b42be772b4c35ffb961220c743b486a601ea4cb6d5412f5b078d3'

认证:

challenge = h'08d3190c6dcb3d4f0cb659a0333bf5ea124ddf36a0cd33d5204b0d7a22a8cc26f2e4f169d200285c77b3fb22e0f1c7f49a87d4be2d25e92d797808ddaaa9b5715efd3a6ada9339d3052a687dbc5d2f8c871b0451e0691f57ad138541b7b72e7aa8933729ec1c664bf2e4dedae1616d08ecefa80a2a53b103663ce5a881048829'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES512', L=128)

client_data_gen_flags = h'ac'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES512', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'52'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.ES512', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22434e4d5a4447334c5055384d746c6d674d7a763136684a4e337a61677a5450564945734e65694b6f7a436279355046703067416f5848657a2d794c67386366306d6f66557669306c3653313565416a6471716d31635637394f6d72616b7a6e544253706f666278644c3479484777525234476b66563630546855473374793536714a4d334b6577635a6b7679354e376134574674434f7a7671416f71553745445a6a7a6c7149454569436b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'3081870242009bda02fe384e77bcb9fb42b07c395b7a53ec9d9616dd0308ab8495c2141c8364c7d16e212a4a4fb8e3987ff6c99eafd64d8484fd28c3fc7968f658a9033d1bb1b802416383e9f3ee20c691b66620299fef36bea2df4d39c92b2ead92f58e7b79ab0d9864d2ebf3b0dcc66ea13234492ccee6e9d421db43c959bcb94c162dc9494136c9f6'

16.10. 使用 RS256 凭证的 Packed 声明

注册:

challenge = h'bea8f0770009bd57f2c0df6fea9f743a27e4b61bbe923c862c7aad7a9fc8e4a6'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.RS256', L=32)

; The two smallest Mersenne primes 2^p - 1 where p >= 1024
private_key_p = 2^1279 - 1 = h'7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
private_key_q = 2^2203 - 1 = h'07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
client_data_gen_flags = h'1c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.RS256', L=1)
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
aaguid = h'428f8878298b9862a36ad8c7527bfef2'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.RS256', L=16)
credential_id = h'992a18acc83f67533600c1138a4b4c4bd236de13629cf025ed17cb00b00b74df'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.RS256', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'7e'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.RS256', L=1)
attestation_private_key = h'08a1322d5aa5b5b40cd67c2cc30b038e7921d7888c84c342d50d79f0c5fc3464'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.RS256', L=32)
attestation_cert_serial_number = h'1f6fb7a5ece81b45896b983a995da5f3'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.RS256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2276716a776477414a76566679774e3976367039304f69666b7468752d6b6a79474c48717465705f49354b59222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c672663736967584730450221008b8c5c6ea8c142c032e0be69e1353d44461c5c9109941cdda951b976eb95b6b302204d52f406c19e254b3ff9589bd18070fb055ac8db12fdd0a6734bea9d7168e900637835638159022630820222308201c7a00302010202101f6fb7a5ece81b45896b983a995da5f3300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004b7b36b7542a11120b443c794d0c99fdc25a06b76586413d81e086163ef6fe147a557afc34e2861d9057d6d465d4705a0310550bdeeb5f35ee35b9425ab859981a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414fb37b647bccfb9e54d989eaaacc1633868703fb3301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100b86bc129d92afca7d9869a39f70f139a305b4073a39eb654d81424bed5757d91022100cf9f7c60cab7c4a7d3e7f0020f281a93d4fd0a9f95121b989f56932a68885fba68617574684461746159021bbfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000428f8878298b9862a36ad8c7527bfef20020992a18acc83f67533600c1138a4b4c4bd236de13629cf025ed17cb00b00b74dfa4010303390100205901b403fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012143010001'

认证:

challenge = h'295f59f5fa8fe62c5aca9e27626c78c8da376ae6d8cd2dd29aebad601e1bc4c5'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.RS256', L=32)

client_data_gen_flags = h'0e'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.RS256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'ba'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.RS256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224b56395a39667150356978617970346e596d7834794e6f33617562597a5333536d75757459423462784d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'01063d52d7c39b4d432fc7063c5d93e582bdcb16889cd71f888d67d880ea730a428498d3bc8e1ee11f2b1ecbe6c292b118c55ffaaddefa8cad0a54dd137c51f1eec673f1bb6c4d1789d6826a222b22d0f585fc901fdc933212e579d199b89d672aa44891333e6a1355536025e82b25590256c3538229b55737083b2f6b9377e49e2472f11952f79fdd0da180b5ffd901b4049a8f081bb40711bef76c62aed943571f2d0575304cb549d68d8892f95086a30f93716aee818f8dc06e96c0d5e0ed4cfa9fd8773d90464b68cf140f7986666ff9c9e3302acd0535d60d769f465e2ab57ef8aabc89fccfef7ba32a64154a8b3d26be2298f470b8cc5377dbe3dfd4b0b45f8f01e63bde6cfc76b62771f9b70aa27cf40152cad93aa5acd784fd4b90f676e2ea828d0bf2400aebbaae4153e5838f537f88b6228346782a93a899be66ec77de45b3efcf311da6321c92e6b0cd11bfe653bf3e98cee8e341f02d67dbb6f9c98d9e8178090cfb5b70fbc6d541599ac794ae2f1d4de1286ec8de8c2daf7b1d15c8438e90d924df5c19045220a4c8438c1b979bbe016cf3d0eeec23c3999d4882cc645b776de930756612cdc6dd398160ff02a6'

16.11. 使用 Ed25519 凭证的 Packed 声明

注册:

challenge = h'a8abf9dabdc6b0df63466b39bda9e8a34a34e185337a59f1c579990676d3b3bd'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.EdDSA', L=32)

private_key = h'971f38c0f73aaf0c5a614eb5e26430ae1ea0ed13e4f425d96e9662349340b0b3'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.EdDSA', L=32)>
client_data_gen_flags = h'bd'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.EdDSA', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'07f0d3e60ed90fffbd3932d85f922f11' = b64'B_DT5g7ZD_-9OTLYX5IvEQ'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.EdDSA', L=16)
aaguid = h'd5aa33581e8ca478e20fe713f5d32ff2'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.EdDSA', L=16)>
credential_id = h'ce9f840ed96599580cd140fbc7bb3230633f50f61041aff73308ae71caa8a2bd'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.EdDSA', L=32)>
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'32'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.EdDSA', L=1)>
attestation_private_key = h'fbe7f950684f23afd045072a8b287ad29528707c662672850ac69733ffe0db85'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.EdDSA', L=32)>
attestation_cert_serial_number = h'b2cfc9ea33c8643b0e1a760463eaf164'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.EdDSA', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22714b763532723347734e396a526d733576616e6f6f306f303459557a656c6e7878586d5a426e6254733730222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20425f44543567375a445f2d394f544c59583549764551227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758483046022100d83f60bd80269537583218858aefb03ac57d45fa06e42feaae332d187f62da9f022100a02bd3cb6f7e1d283c93bad1f3f4b5a4c0494463da7fdbf256949116754d1f17637835638159022730820223308201c8a003020102021100b2cfc9ea33c8643b0e1a760463eaf164300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004dd2b7a564b73b8c0b81c4c62e521925c4d1198ec9f583dbf1eebe364b65cd9c29a9bdf346aaa81fb6b9507e5249a52fdaf8e39e26b0b7dc45992a7e233b70f70a360305e300c0603551d130101ff04023000300e0603551d0e041604140ae27546bc7eccb1b4b597bd354f0c0b1f1f8f8e301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100a0d434ecb5fc3bfd7da5f41904517ad2836249f561bd834ba7a438a8ab7a4ce8022100fac845bb7a02513b58e9f319654dbe49b0f02b95835bac568c71f8a18cdde9ab6861757468446174615881bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54100000000d5aa33581e8ca478e20fe713f5d32ff20020ce9f840ed96599580cd140fbc7bb3230633f50f61041aff73308ae71caa8a2bda401010327200621582044e06ddd331c36a8dc667bab52bcae63486c916aa5e339e6acebaa84934bf832'

认证:

challenge = h'895957e01c633a698348a2d8a31a54b7db27e8c1c43b2080d79ae2190267bfd2'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.EdDSA', L=32)

client_data_gen_flags = h'8c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.EdDSA', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'ab'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.EdDSA', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50100000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2269566c583442786a4f6d6d44534b4c596f7870557439736e364d48454f7943413135726947514a6e763949222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'f5c59c7e46c34f6f8cc197101ddf9934fa2595f68eb1913a637e8419eb9ba4cfdfc48f85393bc0d40b011f0d6fecb097d6607525713223a0dc0d453993dae00b'

16.12. 使用 Ed448 凭证的 Packed 声明

注册:

challenge = h'2578d0801b5a005b5451e540121788cb01949e187b91db13f58755403efbf337'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.Ed448', L=32)

private_key = h'ed479eecf63bd89e3898434798bb3c417bfc8284f6f011958bc0e78edbf6a2a640c0e358b1b1452a1f3782c400dabb4134192dee3031869a45'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.Ed448', L=57)>
client_data_gen_flags = h'e3'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.Ed448', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'050a80de27875521cc4c3316c06da42b' = b64'BQqA3ieHVSHMTDMWwG2kKw'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.Ed448', L=16)
aaguid = h'41c913aeda925fe02273322e34c2ae67'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.Ed448', L=16)
credential_id = h'224fcde324e6b075ede55098a24b9ddce5f5a7c71d23703efd528a38f8a5f33c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.Ed448', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'3b'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.Ed448', L=1)>
attestation_private_key = h'd90faf5cc3f7853456b09124dd870250347f9c9ff66dba363aecd9194c665715'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.Ed448', L=32)>
attestation_cert_serial_number = h'cff4228697d6e5ac47480b2390677f05'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.Ed448', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a224a586a5167427461414674555565564145686549797747556e6868376b6473543959645651443737387a63222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2042517141336965485653484d54444d577747326b4b77227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022100c5430b6b53f6b8fd1e5fa46ae7ebb8f9e9ae0d10ebc748e876e2d979b39b1382022008c5cda8af174f2d3c050d5d14eec0721031364cb12924a06633d4924c6bcad3637835638159022730820223308201c8a003020102021100cff4228697d6e5ac47480b2390677f05300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004b85aaf790c824037cfe9fc56ab8d7ce6fbfaff2e3fe7c8d745734c3c6e3c6ce880d505ccdb1e2c3738680e6f49f475e4d8d0b6c29060e6e0d7a6392fb69094cea360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414fa8f81c2dcc0e194ae5034c7e79dcf6d9d8593e2301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100e761f54215ad92f27c2c14b9eea3e39e8c22429e833ecba5be918987aa72e0e6022100d5a714df479c238586b7d9e6684ea84991087038b0fef6a29b57b66b74df05fd686175746844617461589bbfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54100000000d5aa33581e8ca478e20fe713f5d32ff20020ce9f840ed96599580cd140fbc7bb3230633f50f61041aff73308ae71caa8a2bda4010103383420072158398051ef4f94670b5abf17da2e9558ba6eba94eb8704363915b4d666de287ad329de9f1f075211aba602dc6e7a5e52b15a8ee1c984a9f8887380'

认证:

challenge = h'1a942f401d8d8e36fe888c35c22b718217802fc6685bf139c47b311408128693'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.Ed448', L=32)

client_data_gen_flags = h'2d'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.Ed448', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'5ca1e381b5e009e01760db2eb632316f' = b64'XKHjgbXgCeAXYNsutjIxbw'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.Ed448', L=16)
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'fc'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0c', info='packed.Ed448', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51d00000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22477051765142324e6a6a622d6949773177697478676865414c385a6f575f4535784873784641675368704d222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20584b486a6762586743654158594e7375746a49786277227d'
signature = h'071db921430e13ca1a607eedb96cbd30fd63946a06e731217cad6fd82ba3b930d482308a2c101752a2518cff70918d4a20f29bd2eda4f45a80bba6c4ad85b10fb721b1849725b7dbef315d5fb101c6dab890b06d94a8b52a74b5848f68e6152af24867b7555d2b22b8955cbff5c87de73b00'

16.13. 使用 ES256 凭证的 TPM 声明

注册:

challenge = h'cfc82cdf1ceee876120aa88f0364f0910193460cfb97a317b2fe090694f9a299'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='tpm.ES256', L=32)

credential_private_key = h'80c60805e564f6d33e7abdff9d32e3db09a6219fe378a268d23107191b18e39f'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='tpm.ES256', L=32)>
client_data_gen_flags = h'84'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='tpm.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
aaguid = h'4b92a377fc5f6107c4c85c190adbfd99'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='tpm.ES256', L=16)>
credential_id = h'ec27bec7521c894bbb821105ea3724c90e770cf1fa354157ef18d0f18f78bea9'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='tpm.ES256', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'af'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='tpm.ES256', L=1)>
attestation_private_key = h'6210f09e0ce7593e851a880a4bdde2d2192afeac46104abce1a890a5a71cf0c6'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='tpm.ES256', L=32)
attestation_cert_serial_number = h'311fc42da0ab10c43a9b1bf3a75e34e2'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='tpm.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a227a38677333787a753648595343716950413254776b51475452677a376c364d587376344a427054356f706b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d746374706d6761747453746d74a663616c67266373696758463044022066e5826a652091030fd444e33c3eca2bc6dc548cf3045013addb38aa6457a21002203f3a5c95c9e707d0e555041bcc8698ee4ebc04e26cc8bae459705471789851766376657263322e30637835638159023a30820236308201dca0030201020210311fc42da0ab10c43a9b1bf3a75e34e2300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d03010703420004c54e3f109094f60d7699b7db5d838569ffd1f3e1c9e897cd9eb40063f9402e3e9937e936cf1fcd5eb743ff443c97ab2edcd7c8e0e6cf6cfd413b8ab19fffa769a381d33081d0300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604145f546cb6973d4981e80fcdc7463859f5879680e4301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e30100603551d250409300706056781050803305e0603551d110101ff04543052a450304e314c3014060567810502010c0b69643a30303030303030303014060567810502030c0b69643a3030303030303030301e060567810502020c15576562417574686e207465737420766563746f7273300a06082a8648ce3d0403020348003045022063c9a2797b8066f1db34dd609f1ab6695607e7a98e9ff8090a68853c9a9fc949022100a55831a39f5b8a2aa9a68837829cabf43fea2a5cea4859ae851cac78e6ac3e97677075624172656158560023000b0004000000000010001000030010002041202698c9d9753fb4bb3f27cd09fe6b8afdb76438ee2ae54d7c9dade10d864b0020d8735115cdb330a63ea1d6e43d5000f4bd56f99bce83ee1d73301fc270116d076863657274496e666f5869ff544347801700000020277d0e05579dd013215a62273f7f3a3e7e191ead2654a3036d75a5a3ee37a6b0000000000000000011111111222222223300000000000000000022000b9c42d8aad5939331b9af3711af179f17123178098c9a7d0ca89fcd1fc800f3c7000068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d000000004b92a377fc5f6107c4c85c190adbfd990020ec27bec7521c894bbb821105ea3724c90e770cf1fa354157ef18d0f18f78bea9a501020326200121582041202698c9d9753fb4bb3f27cd09fe6b8afdb76438ee2ae54d7c9dade10d864b225820d8735115cdb330a63ea1d6e43d5000f4bd56f99bce83ee1d73301fc270116d07'

认证:

challenge = h'00093b66c21d5b5e89f7a07082118907ea3e502d343b314b8c5a54d62db202fb'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='tpm.ES256', L=32)

client_data_gen_flags = h'86'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='tpm.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'87'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='tpm.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2241416b375a7349645731364a393642776768474a422d6f2d554330304f7a464c6a46705531693279417673222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'3045022060dc76b1607ec716c6e5eba8d056695ed6bc47b2e3d7a729c34e759e3ab66aa0022100d010a9e8fddcb64c439dfdca628ddb33cf245d567d157d9f66f942601bed9b38'

16.14. 使用 ES256 凭证的 Android Key 声明

注册:

challenge = h'3de1f0b7365dccde3ff0cbf25e26ffa7baff87ef106c80fc865dc402d9960050'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='android-key.ES256', L=32)

credential_private_key = h'd4328d911acb0ebcc42aad29b29ffb55d5bc31d8af7ca9a16703d56c21abc7b4'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='android-key.ES256', L=32)>
client_data_gen_flags = h'73'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='android-key.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'555d5c42e476a8b33f6a63dfa07ccbd2' = b64'VV1cQuR2qLM_amPfoHzL0g'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='android-key.ES256', L=16)
aaguid = h'ade9705e1ce7085b899a540d02199bf8'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='android-key.ES256', L=16)
credential_id = h'0a4729519788b6ed8a2d772b494e186244d8c798c052960dbc8c10c915176795'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='android-key.ES256', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'1e'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='android-key.ES256', L=1)>
attestation_cert_serial_number = h'1ff91f76b63f44812f998b250b0286bf'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='android-key.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2250654877747a5a647a4e345f384d76795869625f7037725f682d385162494438686c334541746d57414641222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205656316351755232714c4d5f616d50666f487a4c3067227d'
attestationObject = h'a363666d746b616e64726f69642d6b65796761747453746d74a363616c67266373696758483046022100e95512982aa3f216cff2e87c8ec57057b8529f674eaabeccaa27fd03d8779f19022100afb6bf459da4a826f00d01fc6b60712ff31dc4eb331619c8f874bb17e4314e94637835638159026f3082026b30820210a00302010202101ff91f76b63f44812f998b250b0286bf300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000499169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accfdd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6ba381a83081a5300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604141ac81e50641e8d1339ab9f7eb25f0cd5aac054b0301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e3045060a2b06010401d679020111043730350202012c0201000201000201000420b435028d7b6a8f83bb461d41c19b053a9d3cdb30351a4f374cd4cde8dbefb606040030003000300a06082a8648ce3d040302034900304602210081671f2474f336e6b5a868d28b47cd054c0ed4261f531fcdf1a1ceed19f600ad022100e7ac683848c34842a432ff4a26e9dbc537b88e83fc4cb59138de3ca3a3e1081468617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000ade9705e1ce7085b899a540d02199bf800200a4729519788b6ed8a2d772b494e186244d8c798c052960dbc8c10c915176795a501020326200121582099169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accf225820dd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6b'

认证:

challenge = h'e4ee05ca9dbced74116540f24ed9adc62aae8507560522844ffa7eea14f7af86'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='android-key.ES256', L=32)

client_data_gen_flags = h'43'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='android-key.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'ab127107eff182bc3230beb5f1dad29c' = b64'qxJxB-_xgrwyML618drSnA'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='android-key.ES256', L=16)
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'4a'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='android-key.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22354f344679703238375851525a55447954746d74786971756851645742534b45545f702d36685433723459222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2071784a78422d5f78677277794d4c3631386472536e41227d'
signature = h'3045022100a2b5e37da43ceb63566f6e2817c6cbef261073d0cadfd213ff6229bd33ddea6c02203d77eb3202fc92b9b5bb843ef082c7766f8c7f23194c92708ff2f3d1de765a8f'

16.15. 使用 ES256 凭证的 Apple 匿名声明

注册:

challenge = h'f7f688213852007775009cf8c096fda89d60b9a9fb5a50dd81dd9898af5a0609'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='apple.ES256', L=32)

credential_private_key = h'de987bd9d43eeb44728ce0b14df11209dff931fb56b5b1948de4c0da1144ded0'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='apple.ES256', L=32)>
client_data_gen_flags = h'5f'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='apple.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
extraData_random = h'4e32cf9e939a5d052b14d71b1f6b5364' = b64'TjLPnpOaXQUrFNcbH2tTZA'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='apple.ES256', L=16)
aaguid = h'748210a20076616a733b2114336fc384'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='apple.ES256', L=16)
credential_id = h'9c4a5886af9283d9be3e9ec55978dedfdce2e3b365cab193ae850c16238fafb8'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='apple.ES256', L=32)
; auth_data_UV_BE_BS determines the UV, BE and BS bits of the authenticator data flags, but BS is set only if BE is
auth_data_UV_BE_BS = h'2a'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='apple.ES256', L=1)>
attestation_cert_serial_number = h'394275613d5310b81a29ce90f48b61c1'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='apple.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22395f61494954685341486431414a7a34774a6239714a316775616e37576c4464676432596d4b396142676b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20546a4c506e704f6158515572464e6362483274545a41227d'
attestationObject = h'a363666d74656170706c656761747453746d74a1637835638159025c30820258308201fea0030201020210394275613d5310b81a29ce90f48b61c1300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d030107034200048a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761af728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136ca38196308193300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e0416041412f1ce6c0ae39b403bfc9200317bc183a4e4d766301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e303306092a864886f76364080204263024a1220420d7a86e7233fb843eb0eeb407d8b76ff7e4f82d218cf5dbb461d752073f5cb29a300a06082a8648ce3d0403020348003045022070f5c2ede3000e9dae358d412b26a4acbf18f4cdeb80f5b13fcd564d090c39ec022100f672e2c3dbe117c9b1490b3c660abf5dcd74398187082dacb58b6744de4aca6068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54900000000748210a20076616a733b2114336fc38400209c4a5886af9283d9be3e9ec55978dedfdce2e3b365cab193ae850c16238fafb8a50102032620012158208a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761a225820f728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136c'

认证:

challenge = h'd3eb2964641e26fed023403a72dde093b19c4ba9008c3f9dd83fcfd347a66d05'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='apple.ES256', L=32)

client_data_gen_flags = h'c2'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='apple.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'e2'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='apple.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22302d73705a4751654a76375149304136637433676b37476353366b416a442d6432445f503030656d625155222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'3046022100ee35db795ce28044e1f8231d68b3d79a9882f7415aa35c1b5ac74d24251073c8022100dcc65691650a412d0ceef843710c09827acf26c7845bddac07eec95863e7fc4c'

16.16. 使用 ES256 凭证的 FIDO U2F 声明

注册:

challenge = h'e074372990b9caa507a227dfc67b003780c45325380d1a90c20f81ed7d080c06'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='fido-u2f.ES256', L=32)

credential_private_key = h'51bd002938fa10b83683ac2a2032d0a7338c7f65a90228cfd1f61b81ec7288d0'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='fido-u2f.ES256', L=32)>
client_data_gen_flags = h'00'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='fido-u2f.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
aaguid = h'afb3c2efc054df425013d5c88e79c3c1'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='fido-u2f.ES256', L=16)
credential_id = h'a4ba6e2d2cfec43648d7d25c5ed5659bc18f2b781538527ebd492de03256bdf4'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='fido-u2f.ES256', L=32)
attestation_private_key = h'66fda477a2a99d14c5edd7c1041a297ba5f3375108b1d032b79429f42349ce33'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='fido-u2f.ES256', L=32)
attestation_cert_serial_number = h'04f66dc6542ea7719dea416d325a2401'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='fido-u2f.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22344851334b5a4335797155486f696666786e73414e344445557955344452715177672d4237583049444159222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d74686669646f2d7532666761747453746d74a26373696758473045022100f41887a20063bb26867cb9751978accea5b81791a68f4f4dd6ea1fb6a5c086c302204e5e00aa3895777e6608f1f375f95450045da3da57a0e4fd451df35a31d2d98a637835638159022530820221308201c7a003020102021004f66dc6542ea7719dea416d325a2401300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000456fffa7093dede46aefeefb6e520c7ccc78967636e2f92582ba71455f64e93932dff3be4e0d4ef68e3e3b73aa087e26a0a0a30b02dc2aa2309db4c3a2fc936dea360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414420822eb1908b5cd3911017fbcad4641c05e05a3301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d040302034800304502200d0b777f0a0b181ad2830275acc3150fd6092430bcd034fd77beb7bdf8c2d546022100d4864edd95daa3927080855df199f1717299b24a5eecefbd017455a9b934d8f668617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54100000000afb3c2efc054df425013d5c88e79c3c10020a4ba6e2d2cfec43648d7d25c5ed5659bc18f2b781538527ebd492de03256bdf4a5010203262001215820b0d62de6b30f86f0bac7a9016951391c2e31849e2e64661cbd2b13cd7d5508ad225820503b0bda2a357a9a4b34475a28e65b660b4898a9e3e9bbf0820d43494297edd0'

认证:

challenge = h'f90c612981d84f599438de1a500f76926e92cc84bef8e02c6e23553f00485435'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='fido-u2f.ES256', L=32)

client_data_gen_flags = h'2c'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='fido-u2f.ES256', L=1)>
; extraData is added to clientDataJSON iff bit 0x01 of client_data_gen_flags is 1
; auth_data_UV_BS sets the UV and BS bits of the authenticator data flags, but BS is set only if BE was set in the registration
auth_data_UV_BS = h'd1'   ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='fido-u2f.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50100000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a222d5178684b59485954316d554f4e3461554139326b6d36537a49532d2d4f417362694e5650774249564455222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'304402206172459958fea907b7292b92f555034bfd884895f287a76200c1ba287239137002204727b166147e26a21bbc2921d192ebfed569b79438538e5c128b5e28e6926dd7'

16.17. WebAuthn 扩展的测试向量 WebAuthn Extensions

本节列出用于 WebAuthn 扩展 的示例值。

16.17.1. 伪随机函数扩展(prf)

本节列出伪随机函数(prf)扩展的示例值。

由于 prf 扩展与 CTAP2 的 hmac-secret 扩展 [FIDO-CTAP] 集成, 因此示例分为两部分: 与 WebAuthn prf 扩展相关、适用于 WebAuthn 客户端WebAuthn 服务方 的示例输入与输出; 以及展示 WebAuthn prf 扩展与 CTAP2 hmac-secret 扩展之间映射的示例, 适用于 WebAuthn 客户端WebAuthn 认证器

16.17.1.1. Web 身份验证 API

下面的示例可用于测试 WebAuthn 客户端 实现以及 WebAuthn 服务方prf 扩展的使用。 这些示例并非详尽无遗。

本节中使用的伪随机值按如下方式生成:

16.17.1.2. CTAP2 的 hmac-secret 扩展

下面的示例可用于测试 WebAuthn 客户端 实现中 prf 扩展如何使用 [FIDO-CTAP]hmac-secret 扩展。 这些示例采用 CDDL [RFC8610] 记法给出。 这些示例并非详尽无遗。

本节中使用的输入与伪随机值按如下方式生成:

17. 致谢

我们感谢以下人士对本规范的审阅和贡献: Yuriy Ackermann, James Barclay, Richard Barnes, Dominic Battré, Julien Cayzac, Domenic Denicola, Rahul Ghosh, Brad Hill, Nidhi Jaju, Jing Jin, Wally Jones, Ian Kilpatrick, Axel Nennker, Zack Newman, Yoshikazu Nojima, Kimberly Paulhamus, Adam Powers, Yaron Sheffer, Anne van Kesteren, Johan Verrept, and Boris Zbarsky.

感谢 Adam Powers 创建整体的 注册认证 流程图(图 1图 2)。

我们感谢 Anthony Nadalin, John Fontana, 和 Richard Barnes 作为 Web Authentication 工作组 的共同主席所做的贡献。

我们也感谢 Simone Onofri, Philippe Le Hégaret, Wendy Seltzer, Samuel Weiler, 和 Harry Halpin 作为我们的 W3C 团队联系人所做的贡献。

18. 修订历史

本节为非规范性内容。

本节总结了随时间对本规范所做的重要更改。

18.1. 自 Web Authentication Level 2 以来的更改 [webauthn-2-20210408]

18.1.1. 实质性更改

Web 身份验证 API 及其操作方式所做的更改如下。

更改包括:

弃用内容:

新增功能:

18.1.2. 编辑性更改

为提高清晰性、可读性、可导航性及文档的相似方面,作出了以下更改。

索引

本规范定义的术语

引用文献定义的术语

参考文献

规范性引用

[CREDENTIAL-MANAGEMENT-1]
Nina Satragno; Marcos Caceres. 凭证管理(第1级). 2025年10月28日. WD. URL: https://www.w3.org/TR/credential-management-1/
[CSP2]
Mike West; Adam Barth; Daniel Veditz. 内容安全策略(第2级). 2016年12月15日. REC. URL: https://www.w3.org/TR/CSP2/
[DOM4]
Anne van Kesteren. DOM 标准. 常驻标准. URL: https://dom.spec.whatwg.org/
[ECMAScript]
ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. 编码标准. 常驻标准. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准. 常驻标准. URL: https://fetch.spec.whatwg.org/
[FIDO-APPID]
D. Balfanz; et al. FIDO AppID 与 Facet 规范. 2018年2月27日. FIDO Alliance 实现草案. URL: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-appid-and-facets-v2.0-id-20180227.html
[FIDO-CLIENT-TO-AUTHENTICATOR-PROTOCOL-V2.1]
客户端到认证器协议(CTAP). 编辑草稿. URL: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html
[FIDO-CTAP]
J. Bradley; et al. 客户端到认证器协议(CTAP). 2022年6月21日. FIDO Alliance 拟议标准. URL: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html
[FIDO-Privacy-Principles]
FIDO Alliance. FIDO 隐私原则. FIDO Alliance 白皮书. URL: https://fidoalliance.org/wp-content/uploads/2014/12/FIDO_Alliance_Whitepaper_Privacy_Principles.pdf
[FIDO-Registry]
R. Lindemann; D. Baghdasaryan; B. Hill. FIDO 预定义值注册表. 2019年12月17日. FIDO Alliance 拟议标准. URL: https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html
[FIDO-U2F-Message-Formats]
D. Balfanz; J. Ehrensvard; J. Lang. FIDO U2F 原始消息格式. FIDO Alliance 实现草案. URL: https://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-message-formats-v1.1-id-20160915.html
[HTML]
Anne van Kesteren; et al. HTML 标准. 常驻标准. URL: https://html.spec.whatwg.org/multipage/
[I18N-GLOSSARY]
Richard Ishida; Addison Phillips. 国际化术语表. 2024年10月17日. NOTE. URL: https://www.w3.org/TR/i18n-glossary/
[IANA-COSE-ALGS-REG]
IANA CBOR 对象签名与加密(COSE)算法注册表. URL: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
[IANA-WebAuthn-Registries]
IANA. Web Authentication (WebAuthn) 注册表. URL: https://www.iana.org/assignments/webauthn/
[IANA-Well-Known-URIs]
IANA. 已知 URIs(Well-Known URIs). URL: https://www.iana.org/assignments/well-known-uris/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 常驻标准. URL: https://infra.spec.whatwg.org/
[Permissions-Policy]
Ian Clelland. 权限策略. 2025年10月6日. WD. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
S. Bradner. RFC 中指示要求级别的关键词. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC3986]
T. Berners-Lee; R. Fielding; L. Masinter. 统一资源标识符(URI):通用语法. 2005年1月. 互联网标准. URL: https://www.rfc-editor.org/rfc/rfc3986
[RFC4648]
S. Josefsson. Base16、Base32 和 Base64 数据编码. 2006年10月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc4648
[RFC4949]
R. Shirey. 互联网安全术语表,版本 2. 2007年8月. 参考资料. URL: https://www.rfc-editor.org/rfc/rfc4949
[RFC5234]
D. Crocker, Ed.; P. Overell. 语法规范的扩展 BNF:ABNF. 2008年1月. 互联网标准. URL: https://www.rfc-editor.org/rfc/rfc5234
[RFC5280]
D. Cooper; et al. 互联网 X.509 公钥基础设施证书和证书撤销列表(CRL)配置文件. 2008年5月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc5280
[RFC5890]
J. Klensin. 应用程序的国际化域名(IDNA):定义与文档框架. 2010年8月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc5890
[RFC6454]
A. Barth. Web 来源概念. 2011年12月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc6454
[RFC7515]
M. Jones; J. Bradley; N. Sakimura. JSON Web Signature(JWS). 2015年5月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc7515
[RFC8152]
J. Schaad. CBOR 对象签名与加密(COSE). 2017年7月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc8152
[RFC8174]
B. Leiba. RFC 2119 关键词大小写歧义. 2017年5月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc8174
[RFC8230]
M. Jones. 在 CBOR 对象签名与加密(COSE)消息中使用 RSA 算法. 2017年9月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc8230
[RFC8264]
P. Saint-Andre; M. Blanchet. PRECIS 框架:在应用协议中准备、强制和比较国际化字符串. 2017年10月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc8264
[RFC8265]
P. Saint-Andre; A. Melnikov. 表示用户名和密码的国际化字符串的准备、强制与比较. 2017年10月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc8265
[RFC8266]
P. Saint-Andre. 表示昵称的国际化字符串的准备、强制与比较. 2017年10月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc8266
[RFC8610]
H. Birkholz; C. Vigano; C. Bormann. 简洁数据定义语言(CDDL):用于表达 CBOR 与 JSON 数据结构的记法约定. 2019年6月. IETF 拟议标准. URL: https://tools.ietf.org/html/rfc8610
[RFC8615]
M. Nottingham. 已知统一资源标识符(URIs). 2019年5月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc8615
[RFC8809]
Jeff Hodges; Giridhar Mandyam; Michael B. Jones. Web Authentication(WebAuthn)注册表. 2020年8月. IETF 拟议标准. URL: https://www.rfc-editor.org/rfc/rfc8809
[RFC8949]
C. Bormann; P. Hoffman. 简洁二进制对象表示(CBOR). 2020年12月. 互联网标准. URL: https://www.rfc-editor.org/rfc/rfc8949
[RFC9052]
J. Schaad. CBOR 对象签名与加密(COSE):结构与过程. 2022年8月. 互联网标准. URL: https://www.rfc-editor.org/rfc/rfc9052
[RFC9053]
J. Schaad. CBOR 对象签名与加密(COSE):初始算法. 2022年8月. 参考资料. URL: https://www.rfc-editor.org/rfc/rfc9053
[SEC1]
SEC1:椭圆曲线密码学,第2版. URL: http://www.secg.org/sec1-v2.pdf
[SP800-800-63r3]
Paul A. Grassi; Michael E. Garcia; James L. Fenton. NIST 特别出版物 800-63:数字身份指南. 2017年6月. URL: https://pages.nist.gov/800-63-3/sp800-63-3.html
[TCG-CMCProfile-AIKCertEnroll]
Scott Kelly; et al. TCG 基础设施工作组:用于 AIK 证书注册的 CMC 配置文件. 2011年3月24日. 已发布. URL: https://trustedcomputinggroup.org/wp-content/uploads/IWG_CMC_Profile_Cert_Enrollment_v1_r7.pdf
[TokenBinding]
A. Popov; et al. 令牌绑定协议 1.0 版. 2018年10月. IETF 拟议标准. URL: https://tools.ietf.org/html/rfc8471
[TPMv2-EK-Profile]
TCG TPM 家族 2.0 的 EK 证书配置文件. URL: https://trustedcomputinggroup.org/wp-content/uploads/TCG-EK-Credential-Profile-V-2.5-R2_published.pdf
[TPMv2-Part1]
受信任平台模块库,第1部分:架构. URL: https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf
[TPMv2-Part2]
受信任平台模块库,第2部分:结构. URL: https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
[TPMv2-Part3]
受信任平台模块库,第3部分:命令. URL: https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-3-Commands-01.38.pdf
[URL]
Anne van Kesteren. URL 标准. 常驻标准. URL: https://url.spec.whatwg.org/
[WCAG21]
Michael Cooper; et al. Web 内容可访问性指南(WCAG)2.1. 2025年5月6日. REC. URL: https://www.w3.org/TR/WCAG21/
[WEBAUTHN-2-20210408]
Jeff Hodges; et al. Web 身份验证:访问公钥凭证的 API - 第2级. 2021年4月8日. REC. URL: https://www.w3.org/TR/2021/REC-webauthn-2-20210408/
[WEBAUTHN-3-20250127]
Tim Cappalli; et al. Web 身份验证:访问公钥凭证的 API - 第3级. 2025年1月27日. WD. URL: https://www.w3.org/TR/2025/WD-webauthn-3-20250127/
[WebDriver]
Simon Stewart; David Burns. WebDriver. 2018年6月5日. REC. URL: https://www.w3.org/TR/webdriver1/
[WEBDRIVER2]
Simon Stewart; David Burns. WebDriver. 2025年10月28日. WD. URL: https://www.w3.org/TR/webdriver2/
[WebIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 常驻标准. URL: https://webidl.spec.whatwg.org/

补充性参考

[Ceremony]
Carl Ellison. 典礼设计与分析. 2007. URL: https://eprint.iacr.org/2007/399.pdf
[CSS-OVERFLOW-3]
Elika Etemad; Florian Rivoal. CSS 溢出模块 第3级. 2025年10月7日. WD. URL: https://www.w3.org/TR/css-overflow-3/
[EduPersonObjectClassSpec]
EduPerson. 持续更新. URL: https://refeds.org/eduperson
[FIDO-Transports-Ext]
FIDO Alliance. FIDO U2F 认证器传输扩展. FIDO Alliance 拟议标准. URL: https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-authenticator-transports-extension-v1.2-ps-20170411.html
[FIDO-UAF-AUTHNR-CMDS]
R. Lindemann; J. Kemp. FIDO UAF 认证器命令. FIDO Alliance 实现草案. URL: https://fidoalliance.org/specs/fido-uaf-v1.1-id-20170202/fido-uaf-authnr-cmds-v1.1-id-20170202.html
[FIDOAuthnrSecReqs]
D. Biggs; et al. FIDO 认证器安全要求. FIDO Alliance 最终文件. URL: https://fidoalliance.org/specs/fido-security-requirements-v1.0-fd-20170524/
[FIDOMetadataService]
R. Lindemann; B. Hill; D. Baghdasaryan. FIDO 元数据服务. 2018年2月27日. FIDO Alliance 实现草案. URL: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-metadata-service-v2.0-id-20180227.html
[FIDOSecRef]
R. Lindemann; et al. FIDO 安全参考. 2018年2月27日. FIDO Alliance 实现草案. URL: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-security-ref-v2.0-id-20180227.html
[FIDOU2FJavaScriptAPI]
D. Balfanz; A. Birgisson; J. Lang. FIDO U2F JavaScript API. FIDO Alliance 拟议标准. URL: https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-javascript-api-v1.2-ps-20170411.html
[ISOBiometricVocabulary]
ISO/IEC JTC1/SC37. 信息技术 — 词汇 — 生物识别. 2012年12月15日. 国际标准:ISO/IEC 2382-37:2012(E) 第一版. URL: http://standards.iso.org/ittf/PubliclyAvailableStandards/c055194_ISOIEC_2382-37_2012.zip
[RFC3279]
L. Bassham; W. Polk; R. Housley. 用于互联网 X.509 公钥基础设施证书和证书撤销列表(CRL)配置文件的算法与标识符. 2002年4月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc3279
[RFC5869]
H. Krawczyk; P. Eronen. 基于 HMAC 的提取与扩展密钥派生函数(HKDF). 2010年5月. 参考资料. URL: https://www.rfc-editor.org/rfc/rfc5869
[RFC5958]
S. Turner. 非对称密钥包. 2010年8月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc5958
[RFC6265]
A. Barth. HTTP 状态管理机制. 2011年4月. 建议标准. URL: https://httpwg.org/specs/rfc6265.html
[RFC6979]
T. Pornin. 数字签名算法(DSA)与椭圆曲线数字签名算法(ECDSA)的确定性使用. 2013年8月. 参考资料. URL: https://www.rfc-editor.org/rfc/rfc6979
[RFC8017]
K. Moriarty, Ed.; et al. PKCS #1:RSA 密码规范 2.2 版. 2016年11月. 参考资料. URL: https://www.rfc-editor.org/rfc/rfc8017
[RFC9864]
M.B. Jones; O. Steele. 用于 JSON 对象签名与加密(JOSE)和 CBOR 对象签名与加密(COSE)的完全指定算法. 2025年10月. 拟议标准. URL: https://www.rfc-editor.org/rfc/rfc9864
[UAFProtocol]
R. Lindemann; et al. FIDO UAF 协议规范 v1.0. FIDO Alliance 拟议标准. URL: https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-protocol-v1.0-ps-20141208.html
[UAX29]
UNICODE 文本分割. URL: http://www.unicode.org/reports/tr29/
[WebAuthn-1]
Dirk Balfanz; et al. Web 身份验证:访问公钥凭证的 API 第1级. 2019年3月4日. REC. URL: https://www.w3.org/TR/webauthn-1/
[WebAuthnAPIGuide]
Web 身份验证 API 指南. 实验性. URL: https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API

IDL 索引

[SecureContext, Exposed=Window]
interface PublicKeyCredential : Credential {
    [SameObject] readonly attribute ArrayBuffer              rawId;
    [SameObject] readonly attribute AuthenticatorResponse    response;
    readonly attribute DOMString?                            authenticatorAttachment;
    AuthenticationExtensionsClientOutputs getClientExtensionResults();
    static Promise<boolean> isConditionalMediationAvailable();
    PublicKeyCredentialJSON toJSON();
};

typedef DOMString Base64URLString;
// The structure of this object will be either
// RegistrationResponseJSON or AuthenticationResponseJSON
typedef object PublicKeyCredentialJSON;

dictionary RegistrationResponseJSON {
    required DOMString id;
    required Base64URLString rawId;
    required AuthenticatorAttestationResponseJSON response;
    DOMString authenticatorAttachment;
    required AuthenticationExtensionsClientOutputsJSON clientExtensionResults;
    required DOMString type;
};

dictionary AuthenticatorAttestationResponseJSON {
    required Base64URLString clientDataJSON;
    required Base64URLString authenticatorData;
    required sequence<DOMString> transports;
    // The publicKey field will be missing if pubKeyCredParams was used to
    // negotiate a public-key algorithm that the user agent doesn't
    // understand. (See section “Easily accessing credential data” for a
    // list of which algorithms user agents must support.) If using such an
    // algorithm then the public key must be parsed directly from
    // attestationObject or authenticatorData.
    Base64URLString publicKey;
    required COSEAlgorithmIdentifier publicKeyAlgorithm;
    // This value contains copies of some of the fields above. See
    // section “Easily accessing credential data”.
    required Base64URLString attestationObject;
};

dictionary AuthenticationResponseJSON {
    required DOMString id;
    required Base64URLString rawId;
    required AuthenticatorAssertionResponseJSON response;
    DOMString authenticatorAttachment;
    required AuthenticationExtensionsClientOutputsJSON clientExtensionResults;
    required DOMString type;
};

dictionary AuthenticatorAssertionResponseJSON {
    required Base64URLString clientDataJSON;
    required Base64URLString authenticatorData;
    required Base64URLString signature;
    Base64URLString userHandle;
};

dictionary AuthenticationExtensionsClientOutputsJSON {
};

partial dictionary CredentialCreationOptions {
    PublicKeyCredentialCreationOptions      publicKey;
};

partial dictionary CredentialRequestOptions {
    PublicKeyCredentialRequestOptions      publicKey;
};

partial interface PublicKeyCredential {
    static Promise<boolean> isUserVerifyingPlatformAuthenticatorAvailable();
};

partial interface PublicKeyCredential {
    static Promise<PublicKeyCredentialClientCapabilities> getClientCapabilities();
};

typedef record<DOMString, boolean> PublicKeyCredentialClientCapabilities;

partial interface PublicKeyCredential {
    static PublicKeyCredentialCreationOptions parseCreationOptionsFromJSON(PublicKeyCredentialCreationOptionsJSON options);
};

dictionary PublicKeyCredentialCreationOptionsJSON {
    required PublicKeyCredentialRpEntity                    rp;
    required PublicKeyCredentialUserEntityJSON              user;
    required Base64URLString                                challenge;
    required sequence<PublicKeyCredentialParameters>        pubKeyCredParams;
    unsigned long                                           timeout;
    sequence<PublicKeyCredentialDescriptorJSON>             excludeCredentials = [];
    AuthenticatorSelectionCriteria                          authenticatorSelection;
    sequence<DOMString>                                     hints = [];
    DOMString                                               attestation = "none";
    sequence<DOMString>                                     attestationFormats = [];
    AuthenticationExtensionsClientInputsJSON                extensions;
};

dictionary PublicKeyCredentialUserEntityJSON {
    required Base64URLString        id;
    required DOMString              name;
    required DOMString              displayName;
};

dictionary PublicKeyCredentialDescriptorJSON {
    required DOMString              type;
    required Base64URLString        id;
    sequence<DOMString>             transports;
};

dictionary AuthenticationExtensionsClientInputsJSON {
};

partial interface PublicKeyCredential {
    static PublicKeyCredentialRequestOptions parseRequestOptionsFromJSON(PublicKeyCredentialRequestOptionsJSON options);
};

dictionary PublicKeyCredentialRequestOptionsJSON {
    required Base64URLString                                challenge;
    unsigned long                                           timeout;
    DOMString                                               rpId;
    sequence<PublicKeyCredentialDescriptorJSON>             allowCredentials = [];
    DOMString                                               userVerification = "preferred";
    sequence<DOMString>                                     hints = [];
    AuthenticationExtensionsClientInputsJSON                extensions;
};

partial interface PublicKeyCredential {
    static Promise<undefined> signalUnknownCredential(UnknownCredentialOptions options);
    static Promise<undefined> signalAllAcceptedCredentials(AllAcceptedCredentialsOptions options);
    static Promise<undefined> signalCurrentUserDetails(CurrentUserDetailsOptions options);
};

dictionary UnknownCredentialOptions {
    required DOMString                     rpId;
    required Base64URLString               credentialId;
};

dictionary AllAcceptedCredentialsOptions {
    required DOMString                     rpId;
    required Base64URLString               userId;
    required sequence<Base64URLString>     allAcceptedCredentialIds;
};

dictionary CurrentUserDetailsOptions {
    required DOMString                     rpId;
    required Base64URLString               userId;
    required DOMString                     name;
    required DOMString                     displayName;
};

[SecureContext, Exposed=Window]
interface AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      clientDataJSON;
};

[SecureContext, Exposed=Window]
interface AuthenticatorAttestationResponse : AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      attestationObject;
    sequence<DOMString>                              getTransports();
    ArrayBuffer                                      getAuthenticatorData();
    ArrayBuffer?                                     getPublicKey();
    COSEAlgorithmIdentifier                          getPublicKeyAlgorithm();
};

[SecureContext, Exposed=Window]
interface AuthenticatorAssertionResponse : AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      authenticatorData;
    [SameObject] readonly attribute ArrayBuffer      signature;
    [SameObject] readonly attribute ArrayBuffer?     userHandle;
};

dictionary PublicKeyCredentialParameters {
    required DOMString                    type;
    required COSEAlgorithmIdentifier      alg;
};

dictionary PublicKeyCredentialCreationOptions {
    required PublicKeyCredentialRpEntity         rp;
    required PublicKeyCredentialUserEntity       user;

    required BufferSource                             challenge;
    required sequence<PublicKeyCredentialParameters>  pubKeyCredParams;

    unsigned long                                timeout;
    sequence<PublicKeyCredentialDescriptor>      excludeCredentials = [];
    AuthenticatorSelectionCriteria               authenticatorSelection;
    sequence<DOMString>                          hints = [];
    DOMString                                    attestation = "none";
    sequence<DOMString>                          attestationFormats = [];
    AuthenticationExtensionsClientInputs         extensions;
};

dictionary PublicKeyCredentialEntity {
    required DOMString    name;
};

dictionary PublicKeyCredentialRpEntity : PublicKeyCredentialEntity {
    DOMString      id;
};

dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
    required BufferSource   id;
    required DOMString      displayName;
};

dictionary AuthenticatorSelectionCriteria {
    DOMString                    authenticatorAttachment;
    DOMString                    residentKey;
    boolean                      requireResidentKey = false;
    DOMString                    userVerification = "preferred";
};

enum AuthenticatorAttachment {
    "platform",
    "cross-platform"
};

enum ResidentKeyRequirement {
    "discouraged",
    "preferred",
    "required"
};

enum AttestationConveyancePreference {
    "none",
    "indirect",
    "direct",
    "enterprise"
};

dictionary PublicKeyCredentialRequestOptions {
    required BufferSource                challenge;
    unsigned long                        timeout;
    DOMString                            rpId;
    sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
    DOMString                            userVerification = "preferred";
    sequence<DOMString>                  hints = [];
    AuthenticationExtensionsClientInputs extensions;
};

dictionary AuthenticationExtensionsClientInputs {
};

dictionary AuthenticationExtensionsClientOutputs {
};

dictionary CollectedClientData {
    required DOMString           type;
    required DOMString           challenge;
    required DOMString           origin;
    boolean                      crossOrigin;
    DOMString                    topOrigin;
};

dictionary TokenBinding {
    required DOMString status;
    DOMString id;
};

enum TokenBindingStatus { "present", "supported" };

enum PublicKeyCredentialType {
    "public-key"
};

dictionary PublicKeyCredentialDescriptor {
    required DOMString                    type;
    required BufferSource                 id;
    sequence<DOMString>                   transports;
};

enum AuthenticatorTransport {
    "usb",
    "nfc",
    "ble",
    "smart-card",
    "hybrid",
    "internal"
};

typedef long COSEAlgorithmIdentifier;

enum UserVerificationRequirement {
    "required",
    "preferred",
    "discouraged"
};

enum ClientCapability {
    "conditionalCreate",
    "conditionalGet",
    "hybridTransport",
    "passkeyPlatformAuthenticator",
    "userVerifyingPlatformAuthenticator",
    "relatedOrigins",
    "signalAllAcceptedCredentials",
    "signalCurrentUserDetails",
    "signalUnknownCredential"
};

enum PublicKeyCredentialHint {
    "security-key",
    "client-device",
    "hybrid",
};

partial dictionary AuthenticationExtensionsClientInputs {
  DOMString appid;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
  DOMString appid;
};

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appid;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
  boolean appid;
};

partial dictionary AuthenticationExtensionsClientInputs {
  DOMString appidExclude;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
  DOMString appidExclude;
};

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appidExclude;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
  boolean appidExclude;
};

partial dictionary AuthenticationExtensionsClientInputs {
    boolean credProps;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
    boolean credProps;
};

dictionary CredentialPropertiesOutput {
    boolean rk;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    CredentialPropertiesOutput credProps;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
    CredentialPropertiesOutput credProps;
};

dictionary AuthenticationExtensionsPRFValues {
    required BufferSource first;
    BufferSource second;
};
dictionary AuthenticationExtensionsPRFValuesJSON {
    required Base64URLString first;
    Base64URLString second;
};

dictionary AuthenticationExtensionsPRFInputs {
    AuthenticationExtensionsPRFValues eval;
    record<DOMString, AuthenticationExtensionsPRFValues> evalByCredential;
};
dictionary AuthenticationExtensionsPRFInputsJSON {
    AuthenticationExtensionsPRFValuesJSON eval;
    record<DOMString, AuthenticationExtensionsPRFValuesJSON> evalByCredential;
};

partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsPRFInputs prf;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
    AuthenticationExtensionsPRFInputsJSON prf;
};

dictionary AuthenticationExtensionsPRFOutputs {
    boolean enabled;
    AuthenticationExtensionsPRFValues results;
};
dictionary AuthenticationExtensionsPRFOutputsJSON {
    boolean enabled;
    AuthenticationExtensionsPRFValuesJSON results;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsPRFOutputs prf;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
    AuthenticationExtensionsPRFOutputsJSON prf;
};

partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsLargeBlobInputs largeBlob;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
    AuthenticationExtensionsLargeBlobInputsJSON largeBlob;
};

enum LargeBlobSupport {
  "required",
  "preferred",
};

dictionary AuthenticationExtensionsLargeBlobInputs {
    DOMString support;
    boolean read;
    BufferSource write;
};
dictionary AuthenticationExtensionsLargeBlobInputsJSON {
    DOMString support;
    boolean read;
    Base64URLString write;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsLargeBlobOutputs largeBlob;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
    AuthenticationExtensionsLargeBlobOutputsJSON largeBlob;
};

dictionary AuthenticationExtensionsLargeBlobOutputs {
    boolean supported;
    ArrayBuffer blob;
    boolean written;
};
dictionary AuthenticationExtensionsLargeBlobOutputsJSON {
    boolean supported;
    Base64URLString blob;
    boolean written;
};

MDN

AuthenticatorAssertionResponse/authenticatorData

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

AuthenticatorAssertionResponse/signature

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

AuthenticatorAssertionResponse/userHandle

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

AuthenticatorAssertionResponse

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

AuthenticatorAttestationResponse/attestationObject

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

AuthenticatorAttestationResponse/getTransports

FirefoxNoneSafari16+Chrome74+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

AuthenticatorAttestationResponse

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

AuthenticatorResponse/clientDataJSON

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

AuthenticatorResponse

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile48+
MDN

PublicKeyCredential/getClientExtensionResults

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

PublicKeyCredential/isUserVerifyingPlatformAuthenticatorAvailable_static

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

PublicKeyCredential/rawId

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

PublicKeyCredential/response

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

PublicKeyCredential

In all current engines.

Firefox60+Safari13+Chrome67+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android92+iOS Safari?Chrome for Android70+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

Headers/Feature-Policy/publickey-credentials-get

In only one current engine.

FirefoxNoneSafariNoneChrome84+
OperaNoneEdge84+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera MobileNone

Headers/Permissions-Policy/publickey-credentials-create

In only one current engine.

FirefoxNoneSafariNoneChrome88+
OperaNoneEdge88+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera MobileNone

Headers/Permissions-Policy/publickey-credentials-get

In only one current engine.

FirefoxNoneSafariNoneChrome88+
OperaNoneEdge88+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera MobileNone