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

W3C 工作草案

关于此文档的更多详细信息
此版本:
https://www.w3.org/TR/2025/WD-webauthn-3-20250127/
最新发布版本:
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 技术报告索引的 https://www.w3.org/TR/ 中找到。

本文档由 Web Authentication Working Group 作为工作草案通过 Recommendation track 发布。本文档旨在成为一份 W3C Recommendation。 欢迎对本规范提供反馈和意见。请使用 Github issues。讨论也可以在 public-webauthn@w3.org 归档 中找到。

作为工作草案的发布并不意味着 W3C 及其成员的认可。该文档为草稿,可能随时被更新、替换或被其他文档取代。不应将此文档引用为除工作进行中的资料以外的内容。

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

本文档受 2023年11月03日 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) { /* Client not capable. Handle error. */ }

var publicKey = {
  // The challenge is produced by the server; see the Security Considerations
  challenge: new Uint8Array([21,31,105 /* 29 more random bytes generated by the server */]),

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

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

  // This Relying Party will accept either an ES256 or RS256 credential, but
  // prefers an ES256 credential.
  pubKeyCredParams: [
    {
      type: "public-key",
      alg: -7 // "ES256" as registered in the IANA COSE Algorithms registry
    },
    {
      type: "public-key",
      alg: -257 // Value registered by this specification for "RS256"
    }
  ],

  authenticatorSelection: {
    // Try to use UV if possible. This is also the default.
    userVerification: "preferred"
  },

  timeout: 300000,  // 5 minutes
  excludeCredentials: [
    // Don't re-register any authenticator that has one of these credentials
    {"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"}
  ],

  // Make excludeCredentials check backwards compatible with credentials registered with U2F
  extensions: {"appidExclude": "https://acme.example.com"}
};

// Note: The following call will cause the authenticator to display UI.
navigator.credentials.create({ publicKey })
  .then(function (newCredentialInfo) {
    // Send new credential info to server for verification and registration.
  }).catch(function (err) {
    // No acceptable authenticator or user refused consent. Handle appropriately.
  });

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 == "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

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 的 registration ceremony§ 7.1 注册新凭证 中定义,由 Relying Party 调用带有 publicKey 参数的 navigator.credentials.create() 操作来发起。参见 § 5 Web Authentication 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]]

The PublicKeyCredential 接口对象’s [[type]] 内部槽’s value is the string "public-key".

注意: 这一点通过从 type 属性 getter(继承自 Credential)体现出来。

[[discovery]]

The PublicKeyCredential 接口对象’s [[discovery]] 内部槽’s value is "remote".

[[identifier]]

This 内部槽包含由认证器选择的credential ID。 该 credential ID 用于查找并使用凭证,因此预计在相同类型的所有凭证以及所有认证器之间具有很高概率的全局唯一性。

此 API 不限制该标识符的格式,唯一的要求是其长度 不得超过 1023 字节,并且必须足以让authenticator 唯一地选择一个密钥。 例如,没有板载存储的认证器可能会创建包含被对称密钥包裹的credential private key 的标识符,该对称密钥被烧录到认证器中。

[[clientExtensionsResults]]

This 内部槽包含在 Relying Party 调用以下任一方法时,请求的客户端扩展处理结果: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) 内部方法 的实现(见 [CREDENTIAL-MANAGEMENT-1])允许 WebAuthn Relying Party 脚本 调用 navigator.credentials.create() 来请求创建一个绑定到某个 authenticator 的新的 public key credential sourcebound 的凭证。

通过将 options.mediation 设为 conditionalRelying Parties 可以表明如果用户已同意创建凭证,则希望在不显示显著模态 UI 的情况下注册凭证。 Relying Party 应先使用 getClientCapabilities() 检查 client 是否支持 conditionalCreate 功能,以避免在该功能不可用时出现面向用户的错误。 当 options.mediation 被设置为 conditional 时,客户端必须将 requireUserPresencerequireUserVerification 都设置为 FALSE,除非这些项可以在仪式期间显式执行。

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

内部方法接受三个参数:

origin

此参数是由调用 create() 实现确定的相关设置对象(relevant settings object)的 origin

options

此参数是一个 CredentialCreationOptions 对象,其 options.publicKey 成员包含一个 PublicKeyCredentialCreationOptions 对象,用以指定待创建的 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.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. 对相关全局对象执行 Consume user activation 操作。

    4. 如果创建凭证的 origin 与相关全局对象的顶层 origin(top-level origin)不同(即与用户在地址栏看到的 origin 不同), 则 client 应向用户明确说明此事实。

  3. pkOptionsoptions.publicKey 的值。

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

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

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

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

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

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

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

  8. 如果 pkOptions.rp.id

    存在

    如果 pkOptions.rp.id 不是 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.id,否则 RP ID 默认为调用者的 origin 的 effective domain

  9. credTypesAndPubKeyAlgs 为一个新的列表,该列表的条目PublicKeyCredentialTypeCOSEAlgorithmIdentifier 的配对。

  10. 如果 pkOptions.pubKeyCredParams大小

    为零

    Append 下列 PublicKeyCredentialTypeCOSEAlgorithmIdentifier 配对添加到 credTypesAndPubKeyAlgs

    非零

    pkOptions.pubKeyCredParams 的每个项 current 执行下列操作:

    1. 如果 current.type 不包含此实现所支持的 PublicKeyCredentialType, 则 继续下一个项

    2. algcurrent.alg

    3. Append current.typealg 的配对到 credTypesAndPubKeyAlgs

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

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

  12. 如果 pkOptions.extensions 存在,则对 pkOptions.extensions 中的每个 extensionIdclientExtensionInput 执行下列操作:
    1. 如果 extensionId 不被此 client platform 支持,或不是一个 registration extension,则 继续下一个扩展

    2. clientExtensions[extensionId] 设置为 clientExtensionInput

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

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

    5. authenticatorExtensions[extensionId] 设置为 authenticatorExtensionInputbase64url 编码

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

    type

    字符串 "webauthn.create"。

    challenge

    pkOptions.challengebase64url 编码

    origin

    callerOrigin序列化表示

    crossOrigin

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

    topOrigin

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

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

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

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

  17. issuedRequests 为新的 有序集合(ordered set)

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

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

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

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

      由用户代理决定何时认为某次认证仪式已完成。该认证仪式可以通过 Web Authentication API 之外的其它方式完成。

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

  21. 启动 lifetimeTimer

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

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

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

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

    如果 options.signal 存在且 已中止

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

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

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

    1. authenticator 现在为 候选认证器(candidate authenticator)

    2. 如果 pkOptions.authenticatorSelection 存在:

      1. 如果 pkOptions.authenticatorSelection.authenticatorAttachment 存在且其值与该 authenticatorattachment modality 不符,则 继续(跳过此认证器)。

      2. 如果 pkOptions.authenticatorSelection.residentKey

        若存在且设为 required

        如果该 authenticator 无法存储一个 client-side discoverable public key credential source,则 继续(跳过此认证器)。

        若存在且设为 preferreddiscouraged

        无影响。

        若不存在

        如果 pkOptions.authenticatorSelection.requireResidentKey 被设置为 true 且该 authenticator 无法存储 client-side discoverable public key credential source,则 继续(跳过此认证器)。

      3. 如果 pkOptions.authenticatorSelection.userVerification 被设置为 required 且该 authenticator 无法执行 user verification,则 继续(跳过此认证器)。

    3. requireResidentKey用于凭证创建的有效 resident key 要求,为布尔值,按如下规则决定:

      如果 pkOptions.authenticatorSelection.residentKey

      存在且设为 required

      requireResidentKeytrue

      存在且设为 preferred

      如果该 authenticator

      支持 client-side credential storage modality

      requireResidentKeytrue

      不支持 client-side credential storage modality,或客户端无法确定认证器能力,

      requireResidentKeyfalse

      存在且设为 discouraged

      requireResidentKeyfalse

      不存在

      requireResidentKeypkOptions.authenticatorSelection.requireResidentKey 的值。

    4. userVerification用于凭证创建的有效 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 为一个新的 列表

    9. pkOptions.excludeCredentials 中的每个凭证描述符 C 执行:

      1. 如果 C.transports 非空,且该 authenticator 是通过一个不在 C.transports 列表中的传输方式连接的,则客户端可以选择 继续(跳过)

        注意: 若客户端选择 继续,这可能导致在同一认证器上意外注册多个绑定到同一 bound 的凭证,如果存储的传输提示(transports)并不准确。例如,软件升级可能添加新的连接选项,从而使先前存储的传输提示变得不准确。

      2. 否则,将 C 追加excludeCredentialDescriptorList

    10. 在该 authenticator 上调用 authenticatorMakeCredential 操作,参数为 clientDataHashpkOptions.rppkOptions.userrequireResidentKeyuserVerificationcredTypesAndPubKeyAlgsexcludeCredentialDescriptorListenterpriseAttestationPossibleattestationFormatsauthenticatorExtensions
    11. 将该 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. 将该 authenticatorissuedRequests移除。该认证器现在为 选定认证器(selected authenticator)

    2. credentialCreationData 为一个 struct,其 items 包括:

      attestationObjectResult

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

      注意: 此值即在 § 6.5.4 Generating an Attestation Object 中定义的 attObj

      clientDataJSONResult

      其值为 clientDataJSON 的字节。

      attestationConveyancePreferenceOption

      其值为 pkOptions.attestation 的值。

      clientExtensionResults

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

    3. constructCredentialAlg 为一个算法,该算法接受一个全局对象 global,其步骤如下:

      1. 如果 credentialCreationData.attestationConveyancePreferenceOption 的值为:

        none

        用非识别性(non-identifying)版本替换可能具有唯一识别性的字段:

        1. 如果 attested credential data 中的 aaguid 为 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 Generating an Attestation Object)。

        indirect

        客户端可以用更有利于隐私或更易验证的版本替换 aaguidattestation statement(例如,采用 Anonymization CA)。

        directenterprise

        不作修改地将认证器的 AAGUIDattestation statement 传送给 Relying Party

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

      3. idattestationObject.authData.attestedCredentialData.credentialId

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

        [[identifier]]

        id

        authenticatorAttachment

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

        response

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

        clientDataJSON

        一个新的 ArrayBuffer, 使用 global%ArrayBuffer% 构造方法创建,内容为 credentialCreationData.clientDataJSONResult 的字节。

        attestationObject

        attestationObject

        [[transports]]

        一个按字典序排列的不重复 DOMString 序列,表示认为 authenticator 支持的传输方式。 这些值应属于 AuthenticatorTransport, 但客户端平台必须忽略未知值。

        如果用户代理不希望泄露此信息,则可以用任意设计用于保护隐私的序列替代。该序列仍必须有效,即按字典序排序且无重复项。例如可使用空序列。不论如何,这种情况下用户代理需承担服务接受方行为不佳的风险。

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

        注意:用户代理如何发现某个认证器支持的传输方式,超出本规范范围,但可包括来自 证明证书(如 [FIDO-Transports-Ext])、CTAP2 等 认证器 协议中的元数据或针对某些平台认证器的特殊知识。

        [[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 扩展(包括本规范之外定义的扩展)时可能引发的异常并未在此列出。

下列 DOMException 异常可能被抛出:

AbortError

该仪式被 AbortController 取消。 参见 § 5.6 使用 AbortSignal 中止操作§ 1.3.4 中止认证操作 示例

ConstraintError

要么 residentKey 被设置为 required 且没有可用的认证器支持驻留密钥;要么 userVerification 被设置为 required 且没有可用的认证器能够执行 user verification

InvalidStateError

用于本次仪式的认证器在用户已对注册凭证表示 同意 后识别出 excludeCredentials 中的某个条目。

NotSupportedError

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

SecurityError

effective domain 不是一个 有效域名, 或者 rp.id 并非等于或不是 effective domain 的可注册域后缀。 在后者情况下,client 不支持 related origin requestsrelated origins validation procedure 校验失败。

NotAllowedError

一个涵盖多种可能原因的通用错误,包括常见情况例如用户取消了该仪式。 本规范中有些原因在各处已有记录,另一些原因则与客户端实现相关。

下列 simple exceptions 也可能被抛出:

TypeError

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

5.1.4. Use an Existing Credential to Make an Assertion

WebAuthn Relying Parties 调用 navigator.credentials.get({publicKey:..., ...}) 以发现并使用现有的 public key credential,并取得用户的 同意Relying Party 脚本可选择性地指定一些条件来表明哪些 public key credential sources 对其是可接受的。client platform 会定位满足指定条件的 public key credential sources,并指导用户选择一个脚本被允许使用的凭证。用户也可能选择拒绝整个交互,即使存在 public key credential source,例如为了维护隐私。如果用户选择了一个 public key credential source,用户代理随后使用 § 6.3.3 The authenticatorGetAssertion Operation 将 Relying Party 提供的 challenge 和其它收集的数据签名成一个 authentication assertion,该断言被用作一个 credential

navigator.credentials.get() 的实现(见 [CREDENTIAL-MANAGEMENT-1])会调用 PublicKeyCredential.[[CollectFromCredentialStore]]() 来收集任何应可在无 用户调停(大致对应本规范的 authorization gesture)情况下可用的 credentials,如果未找到恰好一个这样的凭证,则调用 PublicKeyCredential.[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 以让用户选择一个 public key credential source

鉴于本规范要求为创建任何 assertions 提供 authorization gesturePublicKeyCredential 继承了 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors) 的默认行为,即返回空集合。PublicKeyCredential[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 的实现在下一节中说明。

通常,用户代理应向用户显示一些 UI 以指导其在选择并授权认证器以完成操作时的交互。通过将 options.mediation 设为 conditionalRelying Parties 可以表明在未发现凭证时不应显示显著的模态 UI,除非确实发现了凭证。 Relying Party 应先使用 isConditionalMediationAvailable()getClientCapabilities() 检查 client 是否支持 conditionalGet 功能,以避免在该功能不可用时产生面向用户的错误。

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

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 项的 list,该项的 id 值设为 credentialMetadataid 的值,且其 id 值设为 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 Parties 在调用 navigator.credentials.get() 时可能会遇到若干异常。 某些异常可能由多种原因引起,WebAuthn Relying Parties 需要结合它们对 WebAuthn 的使用来推断实际原因。

注意: 在处理任何 WebAuthn 扩展(包括本规范之外定义的扩展)时可能引发的异常并未在此列出。

下列 DOMException 异常可能被抛出:

AbortError

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

SecurityError

effective domain 不是一个 有效域名, 或者 rp.id 并非等于或不是 effective domain 的可注册域后缀。 在后者情况下,client 不支持 related origin requestsrelated origins validation procedure 校验失败。

NotAllowedError

一个涵盖多种可能原因的通用错误,包括常见情形例如用户取消该流程。 本规范中有些原因在各处已有记录,另一些原因与客户端实现相关。

下列 simple exceptions 也可能被抛出:

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();
};

注意: 从一个被 browsing context 调用此方法时,如果据 Web Authentication API 的 "allowed to use" 算法判断该 API 在该上下文被“禁用”,——即受 permissions policy 的约束——则返回的 promise 会被拒绝,拒绝原因为名为 "NotAllowedError" 的 DOMException。 另请参阅 § 5.9 Permissions Policy integration

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 会执行该扩展的处理步骤。

注意: 从一个被 browsing context 调用此方法时,如果据 Web Authentication API 的 "allowed to use" 算法判断该 API 在该上下文被“禁用”,——即受 permissions policy 的约束——则返回的 promise 会被拒绝,拒绝原因为名为 "NotAllowedError" 的 DOMException。 另请参阅 § 5.9 Permissions Policy integration

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

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

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

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

如果 client 在解析任何 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 为相关设置对象(relevant settings object)的 origineffective domain。如果 effectiveDomain 不是 有效域名,则返回 "SecurityError" 命名的拒绝的 promise(即一个 DOMException)。

  2. 如果 rpIdeffectiveDomain 的可注册域后缀或与其相等,则返回 解析为 undefined 的 promise。

  3. 如果客户端不支持 related origin requests,则返回以 "SecurityError" 命名的被拒绝的 promise。

  4. p 为一个新的 promise。

  5. 并行执行下列步骤:

    1. 如果对 callerOriginrpId 运行 related origins validation procedure 的结果为 true,则 解析 p

    2. 否则,拒绝 p,拒绝原因为 "SecurityError" 的 DOMException

  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 为对 options.userId 进行的 base64url 解码 的结果。

  2. 断言:userId 不是错误。

  3. credentialcredentials map[options.rpId, userId]

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

  5. 如果 options.allAcceptedCredentialIds 不包含对该 credentialid 进行的 base64url 编码 的结果,则从 credentials map 中移除该 credential,或使用某个 authenticator-专用的过程将其隐藏以防止其在将来的 authentication ceremonies 中出现。

  6. 否则,如果该 credential 已被某个 authenticator-专用过程隐藏,则撤销该隐藏操作,使该 credential 在将来的 authentication ceremonies 中重新可见。

某用户有两个凭证,其 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 成员指定凭证应当作用域(scoped)到的 RP ID。若省略,则其值将为 CredentialsContainer 对象的 relevant settings objectorigineffective domain。更多细节见 § 5.4.2 Relying Party Parameters for Credential Generation (dictionary PublicKeyCredentialRpEntity)

user, of type PublicKeyCredentialUserEntity

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

其值的 namedisplayNameid 成员为必需项。id 在未来某些认证流程中可以作为 userHandle 被返回,并用于覆盖在同一 authenticator 上具有相同 rp.iduser.id 的可发现凭证(discoverable credentials)。namedisplayName 可以被 authenticatorclient 在未来的认证流程中用于帮助用户选择凭证,但不会在未来的认证流程结果中返回给 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

该成员指定一个 challenge,认证器在为新创建的凭证生成 attestation object 时会与其它数据一同对其进行签名。参见安全注意事项 § 13.4.3 Cryptographic Challenges

pubKeyCredParams, of type sequence<PublicKeyCredentialParameters>

该成员列出了 Relying Party 支持的密钥类型和签名算法,按从最优先到最不优先的顺序排列。允许重复,但会被有效忽略。clientauthenticator 会尽最大努力创建最优先类型的凭证。如果无法创建任何列出的类型,则 create() 操作将失败。

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

  • -8 (Ed25519)

  • -7 (ES256)

  • -257 (RS256)

可根据需要加入更多签名算法。

timeout, of type unsigned long

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

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

Relying Party 应使用此可选成员列出映射到该 用户账号 的任何现有凭证(由 user.id 标识)。这可确保新的凭证不会在已经包含映射到该用户账号的凭证的 authenticator 上创建。如果会出现这种情况,则请求客户端引导用户使用不同的 authenticator,如果失败则返回错误。

authenticatorSelection, of type AuthenticatorSelectionCriteria

Relying Party 可使用此可选成员指定认证器必须或应满足的能力与设置,以参与 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] 建立),并按偏好顺序排列。允许重复但会被忽略。该参数为建议性,authenticator 可以使用未在该参数中列举的 attestation 语句。

默认值为空列表,表示不偏好任何格式。

extensions, of type AuthenticationExtensionsClientInputs

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

扩展框架在 § 9 WebAuthn Extensions 中定义。一些扩展在 § 10 Defined Extensions 中定义;请参阅由 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)维护的注册表,以获取已注册 WebAuthn 扩展 的最新列表。

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

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

dictionary PublicKeyCredentialEntity {
    required DOMString    name;
};
name类型为 DOMString

该实体的用户友好名称。其作用依赖PublicKeyCredentialEntity 的具体用法:

客户端客户端平台认证器 展示 name 应使用 UI 元素清晰包裹,避免内容溢出到其它元素中。

存储 name 时允许进行截断,详见 § 6.4.1 字符串截断,建议阈值不少于64字节。

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

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

dictionary PublicKeyCredentialRpEntity : PublicKeyCredentialEntity {
    DOMString      id;
};
id类型为 DOMString

Relying Party 实体的唯一标识符,用作 RP ID

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

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

dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
    required BufferSource   id;
    required DOMString      displayName;
};
id类型为 BufferSource

用户账户user handleuser handle 是一个最大长度不超过64字节的不透明字节序列(byte sequence),不应向用户展示。

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

user handle 禁止包含用户的个人身份信息(PII),如用户名、邮箱等;详见 § 14.6.1 User Handle 内容user handle 不能为空。

即使是 不可发现凭证,不同用户的 user handle不应是常量,否则若认证器一律创建可发现凭证,多用户会互相影响。

displayName 类型为 DOMString

用户账户的一个用户友好名称,仅用于显示。Relying Party 应让用户自主选择,且不应做过多限制。如果没有合适用户友好名称,则应设为空字符串。

例如: "Alex Müller", "Alex Müller (ACME Co.)", "田中倫" 等。

客户端客户端平台认证器 展示 displayName,应通过UI包裹,防止UI溢出。

存储 displayName 时可截断,建议最小64字节,详见 § 6.4.1 字符串截断

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

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

dictionary AuthenticatorSelectionCriteria {
    DOMString                    authenticatorAttachment;
    DOMString                    residentKey;
    boolean                      requireResidentKey = false;
    DOMString                    userVerification = "preferred";
};
authenticatorAttachment类型为 DOMString

若存在,仅筛选与指定认证器连接模式匹配的认证器(详见 § 6.2.1)。如无则不限模式。值建议为 AuthenticatorAttachment 的成员,但 客户端平台 必须忽略未知值。

另见 authenticatorAttachment ,用于确认成功注册/认证使用的连接模式。

residentKey类型为 DOMString

指定 Relying Party 希望创建的 客户端可发现凭证 的程度。“resident” 为历史术语,值建议为 ResidentKeyRequirement 内成员,平台必须忽略未知值。若缺省则根据 requireResidentKey 判断。详见该枚举描述。

requireResidentKey类型为 boolean, 默认 false

为兼容Level 1保留,建议仅当 residentKeyrequired 时设为 true。

userVerification类型为 DOMString,默认 "preferred"

指定 Relying Party用户验证 的需求。建议值为 UserVerificationRequirement,平台必须忽略未知值。

详见 UserVerificationRequirement 中各值定义。

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

该枚举的值描述认证器连接模式Relying Party 在调用 navigator.credentials.create() 创建凭证时用于表达其对 认证器连接的偏好,客户端据此报告操作所用实际连接模式。

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

注意: AuthenticatorAttachment 枚举故意未被直接引用,见 § 2.1.1 DOMString类型枚举

platform

表示 平台型连接

cross-platform

表示 跨平台连接

注意: 认证器连接模式 选项仅在 [[Create]](origin, options, sameOriginWithAncestors) 操作支持。RP 可用以确保创建漫游凭证或本地凭证,便于跨设备使用或当前设备便捷认证。[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 操作无此选项,届时客户端和用户会选择最合适凭证,受 allowCredentials 限制。

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

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

注意: ResidentKeyRequirement 枚举故意未被直接引用,见 § 2.1.1 DOMString类型枚举

该枚举描述 Relying Party客户端可发现凭证(以前称为常驻凭证resident credential或resident key)的需求:

discouraged

Relying Party 更倾向于创建 服务器端凭证,但亦接受 客户端可发现凭证。客户端与认证器应尽量创建服务器端凭证。

注意:Relying Party 无法要求必须创建为服务器端凭证,并且 Credential Properties Extension 可能不返回 rk 字段,因此RP可能无法准确得知类型以及凭证复用行为。

preferred

Relying Party 更倾向于创建 客户端可发现凭证,但亦接受服务器端凭证。客户端与认证器应尽量创建可发现凭证,必要时指导用户启用用户验证,其优先级高于 userVerification

required

Relying Party 要求必须创建 客户端可发现凭证。如若无法创建,客户端必须返回错误。

注意:Relying Party 可通过 Credential Properties Extensionresident key credential property 判断是否创建了可发现凭证。这在 authenticatorSelection.residentKeydiscouragedpreferred 时尤为重要,因为此时认证器可创建任意类型。

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

WebAuthn Relying Parties 可以使用 AttestationConveyancePreference 指定在凭证生成时关于声明传递的偏好。

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

注意: AttestationConveyancePreference 枚举特意未被直接引用,详见 § 2.1.1 DOMString类型枚举

none

Relying Party 不关心认证器声明。例如,为了避免处理向 Relying Party 传递标识信息时获取用户同意,或减少与 Attestation CAAnonymization CA 往返。当 认证器 生成的 声明语句 不是自声明时,客户端 会将其替换为 None 类型声明语句。

这是默认选项,未知值也将视为此行为。

indirect

Relying Party 希望获得可验证的声明语句,但允许 客户端 决定如何获取该声明语句。客户端可用 Anonymization CA 生成的声明替换认证器声明以保护隐私,或帮RP验证。

注意:此方式不能保证 Relying Party 能一定获取到可验证声明。比如若认证器使用 自声明,客户端未做更改时即如此。

direct

Relying Party 希望直接获得认证器生成的声明语句原文。

enterprise

Relying Party 希望获得企业声明,即可能包含可唯一标识认证器信息的声明语句。适用于受控的企业场景以绑定注册到特定认证器。除非代理或认证器配置允许,不能提供企业声明给请求 RP ID。如允许,代理应在调用生成凭证时向认证器表明请求企业声明,并原封不动传递回 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类型为 BufferSource

该成员指定认证器生成认证断言时与其它数据一起签名的challenge。参见安全注意事项 § 13.4.3 加密挑战

timeout类型为 unsigned long

该可选成员指定get()调用允许等待的毫秒数。此值为提示,实际等候时间可能由客户端覆盖。

rpId类型为 DOMString

该可选成员指定 Relying Party 所声明的 RP ID客户端 必须验证 Relying Partyorigin 是否与此 RP ID 所作用域一致。认证器 必须确保该 RP ID 完全等于将被用于凭证rpId。 如未指定,该值为 CredentialsContainer 对象的 相关设置对象origin有效域名

allowCredentials类型为 sequence<PublicKeyCredentialDescriptor>,默认为 []

该可选成员用于 客户端 查找本次认证流程中可用的 认证器。主要有两种用法:

若非空数组,若均不可用客户端必须报错。列表按喜好降序排列。

userVerification类型为 DOMString,默认"preferred"

该可选成员指定RP对 get() 操作的用户验证需求。建议信息为相应枚举成员,平台须忽略未知值,只筛选能满足该需求的认证器。

详见 UserVerificationRequirement 描述。

hints类型为 sequence<DOMString>,默认为[]

可选成员,包含零或多个 PublicKeyCredentialHint 元素指导代理与用户交互。注意其类型为 DOMString,详见 § 2.1.1 枚举字符串类型

extensions类型为 AuthenticationExtensionsClientInputs

Relying Party 可使用该可选成员用于输入扩展请求客户端或认证器做特殊处理。扩展框架定义见 § 9 WebAuthn 扩展,扩展注册表见 [IANA-WebAuthn-Registries]

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主入口、认证会话前启动以及认证器会话期间三处检测该属性,确保遵从规范。

可见性焦点 状态影响 Window 关联文档的 [[Create]][[DiscoverFromExternalSource]] 操作是否继续。当与文档关联的 Window 失去焦点时,上述操作应中止。

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

此可选成员包含与Token Binding协议 [TokenBinding]相关的信息。缺省表示客户端不支持 token binding

注意:虽然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, 类型为 DOMString

该成员包含调用者所指公钥凭证的类型。其值应为 PublicKeyCredentialType 的成员,但客户端平台必须忽略类型未知的 PublicKeyCredentialDescriptor。 但若所有元素都因类型未知被忽略,则必须报错,因为空的 allowCredentials 在语义上有特殊意义。

此值应设置为代表被标识公钥凭证源凭证记录中的 type 项。该字段对应 type 字段, 同步于 PublicKeyCredential

id, 类型为 BufferSource

该成员包含调用者所指公钥凭证的凭证 ID

应设置为代表被标识公钥凭证源凭证记录中的 id 项。这对应于 rawId 字段, 是 PublicKeyCredential 的一部分。

transports, 类型为 sequence<DOMString>

该可选成员包含客户端可能如何与被标识公钥凭证管理认证器通信的提示。 其值应为 AuthenticatorTransport 的成员, 但客户端平台必须忽略未知值。

应设置为标识的公钥凭证源凭证记录transports 项。它对应于 response.getTransports() 方法, 来源为用 PublicKeyCredential 结构和 create() 操作创建的对象。

5.8.4. 认证器传输类型枚举(枚举 AuthenticatorTransport

enum AuthenticatorTransport {
    "usb",
    "nfc",
    "ble",
    "smart-card",
    "hybrid",
    "internal"
};

注意: AuthenticatorTransport 枚举被有意设计为不被直接引用,详见 § 2.1.1 枚举作为 DOMString 类型

认证器可能实现多种传输方式用于与客户端通信。本枚举定义了客户端可能如何与某认证器通信以获取某一凭证断言的提示。注意这些提示反映的是WebAuthn 依赖方对认证器可达方式的最佳认知。依赖方通常通过 getTransports() 方法获知某公钥凭证支持的传输类型。
usb

表示对应的认证器可以通过可拔插的 USB 连接。

nfc

表示对应的认证器可以通过近场通信(NFC)连接。

ble

表示对应的认证器可以通过蓝牙低功耗(Bluetooth Low Energy / BLE)连接。

smart-card

表示对应的认证器可以通过带接点的 ISO/IEC 7816 智能卡接入。

hybrid

表示对应的认证器可以通过数据传输与邻近机制的结合(通常是分离的)通信。例如支持用智能手机在桌面电脑上认证。

internal

表示对应的认证器通过客户端设备专用传输方式接入,即为平台认证器。这类认证器无法从客户端设备移除。

5.8.5. 密码算法标识符(类型定义 COSEAlgorithmIdentifier

typedef long COSEAlgorithmIdentifier;
COSEAlgorithmIdentifier 的值是用于标识密码算法的数字。 算法标识符应取自 IANA COSE 算法注册表 [IANA-COSE-ALGS-REG],如 "ES256" 用 -7,"RS256" 用 -257

COSE 算法注册表留有由COSE 密钥中其它参数指定的选项空间。为促进互操作性,本规范对凭证公钥作如下额外要求:

  1. 算法为 ES256(-7)的密钥必须将 crv 参数指明为 P-256 (1),且不得使用压缩点格式。

  2. 算法为 ES384(-35)的密钥必须将 crv 参数指明为 P-384 (2),不得使用压缩点格式。

  3. 算法为 ES512(-36)的密钥必须将 crv 参数指明为 P-521 (3),不得使用压缩点格式。

  4. 算法为 EdDSA(-8)的密钥必须将 crv 参数指明为 Ed25519 (6)。(这类密钥在 COSE 中总是压缩的。)

这些约束与 [RFC9053] 第 2.1 节 的推荐做法一致。

注意:要正确实现这些算法的签名校验需做很多检查。其中之一是处理未压缩椭圆曲线点时,应校验该点真正在曲线上。此检查易被加密库和其他代码遗漏,需特别重视。

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 信赖方可以使用该枚举向用户代理传达关于请求如何最好完成的提示。这些提示不是强制要求,用户代理并不受其约束,但可以作为依据,利用信赖方对于请求的上下文信息,改善用户体验。提示会按优先级从高到低排列,因此如果两个提示存在冲突,则第一个为准。提示也可能重叠:如果定义了更具体的提示,信赖方仍可以为不认识更具体提示的用户代理发送更不具体的提示。在这种情况下,最具体的提示应在更不具体之前发送。 若同一提示出现多次,第二次及之后的会被忽略。

提示可能与身份凭据的 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认证API,即, 通过 navigator.credentials.create({publicKey:..., ...})navigator.credentials.get({publicKey:..., ...}) 。如果在文档中被禁用,则该文档的内容均无法使用上述方法:尝试调用将会返回错误

注意: [CREDENTIAL-MANAGEMENT-1]中定义的算法实际执行权限策略的评估。因为需要当可以访问当前设置对象时进行评估。[[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)内部方法无此访问能力,因为它们是被CredentialsContainer创建凭据请求凭据抽象操作并行调用的。[CREDENTIAL-MANAGEMENT-1]

5.10. iframe 元素内使用 Web Authentication

Web 认证 API 默认在跨域 iframe 中被禁用。 如需覆盖默认策略,并允许跨域 iframe 调用 Web认证API[[Create]](origin, options, sameOriginWithAncestors)[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 方法, 需要在 allow 属性中 添加 publickey-credentials-createpublickey-credentials-get 特性标识符, 并写入 allow 属性值中。

信赖方在嵌入式场景下使用 WebAuthn API 时,建议复习 § 13.4.2 嵌入式可见性注意事项,了解UI 伪装及其可能的缓解措施。

默认情况下,Web 认证要求RP ID 必须等于 来源有效域名,或者是 可注册域名后缀

这对使用多个国家/地区域名(如 example.com、example.co.uk、example.sg)、需要备用/品牌域名(如 myexampletravel.com、examplecruises.com),以及平台服务商支持的移动应用部署等大型环境来说带来挑战。

WebAuthn信赖方 可选择启用此功能,让 WebAuthn 客户端 允许在一定范围内的关联来源 创建和使用凭据。该信赖方必须为所有有关来源使用同一 RP ID

需在 RP ID 的 webauthn well-known URL [RFC8615] 处托管 JSON 文档,并通过 HTTPS 提供。文档返回要求如下:

例如,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客户端 至少需支持5个可注册来源标签。客户端策略应定义上限以防止滥用。

WebAuthn客户端访问该well-known端点时,必须不带凭据、不带referrer,且使用https: 协议。若出现重定向,所有重定向也必须显式为https:协议。

支持该功能的WebAuthn客户端 应在 getClientCapabilities() 响应内包含 relatedOrigins

5.11.1. 关联来源验证

关联来源验证过程 ,给定参数 callerOriginrpIdRequested,流程如下:

  1. maxLabels 为客户端策略允许的最大可注册来源标签个数。

  2. 拉取 rpIdRequestedwebauthn well-known URL [RFC8615] (即 https://rpIdRequested/.well-known/webauthn),不带凭据、不带referrer且使用https: 协议

    1. 若拉取失败、响应内容类型非 application/json,或(跟随重定向后)响应码非200,则抛出 "SecurityError" DOMException

    2. 若资源主体不是有效JSON对象,则抛出 "SecurityError" DOMException

    3. 若JSON对象的 origins 属性缺失或者不是字符串数组,则抛出 "SecurityError" DOMException

  3. labelsSeen 初始化为空集合

  4. 对每个 originItem 属于 origins

    1. url 为用 originItem 运行 URL 解析器所得;若失败,继续

    2. domainurl有效域,若为 null,继续

    3. labeldomain可注册来源标签

    4. label为空或null,继续

    5. labelsSeen大小大于等于maxLabelslabelsSeen包含label继续

    6. callerOriginurl属于同源,返回true

    7. labelsSeen 大小 小于 maxLabels添加 labellabelsSeen

  5. 返回false

6. WebAuthn 认证器模型

Web认证API 隐含了一套针对WebAuthn认证器 的抽象功能模型。 本节描述该认证器模型

客户端平台可按需实现和暴露本抽象模型。不过,当平台支持的认证器上运行的 Web 认证 API 实现时, 客户端的行为必须与§ 5 Web认证API中定义的行为无法区分。

注意: [FIDO-CTAP] 是该模型的一个具体实例,但它返回的数据与 WebAuthn API 算法所期望的存在差异。CTAP2 响应消息使用整数键构造 CBOR 映射,而本规范定义的相同对象使用字符串键。客户端需要对数据进行必要的转换。[FIDO-CTAP] 规范在 §6. 认证器API中详细阐述了 CTAP2 整数键与 WebAuthn 字符串键之间的映射。

对认证器来说,本模型定义它们必须支持的逻辑操作和向客户端与WebAuthn信赖方暴露的数据格式。然而,除非为与信赖方互操作所必需,否则该模型不定义认证器与客户端设备通信的细节。例如,不定义经 USB 或 NFC 之类传输连接认证器的协议。 同样,也不定义特定的错误码及其返回方式;不过, 会按客户端所需以错误行为的形式给出。因此,文中提及具体错误码旨在说明 哪些错误条件必须能互相区分(或不能),从而保证客户端实现的合规与安全。

信赖方可以在创建凭据时和/或生成断言时,通过指定各类认证器特性,影响认证器的选择,这些特性通过凭据创建选项断言生成选项传递。底层算法将这些选项整理后传递给下文定义的相关认证器操作

在该抽象模型中,认证器负责密钥管理与加密签名。它可以嵌入在 WebAuthn 客户端内部,也可单独置于其他设备内。认证器本身可以包含一个加密模块,其安全级别高于认证器的其他部分。对于集成在 WebAuthn 客户端中的认证器,这一点尤为重要,因为在这种情况下,该加密模块(例如 TPM)可被视为比认证器其余部分更可信。

每个认证器存储一个 凭据映射(credentials map),即从 (rpId, userHandle) 到 公钥凭据源有序映射

此外,每个认证器有一个认证器验证全局唯一标识(AAGUID,AAGUID), 这是一个128位标识符,表示认证器类型(例如品牌和型号)。AAGUID 必须由制造商选择,对所有基本一致的设备一致,且与其他认证器类型的 AAGUID 有很高概率不同。AAGUID 应该随机生成以确保唯一性。信赖方可以借助AAGUID,通过其他信息源,推断认证器的认证级别和密钥防护强度。信赖方也可尝试据此识别认证器制造商——不过如未要求并验证证明(attestation),AAGUID 并非可证明真实身份。

认证器的核心功能是提供WebAuthn签名,签名内容绑定了多种上下文数据。这些数据会在签名请求自服务器发出到设备的过程中被观察并附加。对于服务器来说,验证签名时需检验这些绑定是否符合预期。这些上下文绑定分为两类:由 信赖方或客户端添加的称为 客户端数据;由认证器添加的为 认证器数据。认证器只对客户端数据进行哈希并加以签名,不关心内容本身。为节省带宽及处理量,客户端将 客户端数据 哈希后,将哈希值传送给认证器,由认证器对该哈希加上本身认证器数据的组合进行签名。

该设计目标总结如下:

认证器生成加密签名用于两种不同目的:

  1. 证明签名(attestation signature):当通过authenticatorMakeCredential操作创建新的公钥凭据时生成。证明签名为认证器及凭据的某些特性提供加密佐证。例如签名会声明认证器类型(AAGUID)以及凭据公钥。签名由证明私钥完成,其选择依据所需的证明类型。详细可见§ 6.5证明

  2. 断言签名(assertion signature):调用 authenticatorGetAssertion 方法时生成。用于认证器声明用户已就某事务给出同意,如登录、付款等。因此,断言签名声明,某一 认证器 持有特定 凭据私钥,并已最合理地判断交易发起人确为签名创建人;还会声明客户端数据(如同意方式、提示内容)供调用者参考。断言签名格式见下方图 4

术语 WebAuthn签名 同时指 证明签名断言签名。这些签名的格式和生成过程在下文中详细说明。

6.1. 认证器数据(Authenticator Data)

认证器数据结构用于编码由认证器进行的上下文绑定。这些绑定由认证器自行控制,其信任等级依赖于WebAuthn信赖方对认证器安全属性的评估。在某些极端情况下,认证器可能嵌入在客户端,其绑定与客户端数据相比可信度不高;而在另一极端,认证器可能为通过安全通道与客户端相连的高安全性硬件/软件独立实体。无论哪种情况,信赖方获得的认证器数据格式是相同的,并会依据对认证器的了解做出信任决策。

认证器数据采用紧凑但可扩展的编码格式。这是因为认证器可能是功能有限、功耗极低且软件堆栈远比客户端平台简单的设备。

认证器数据结构是一个不少于37字节的字节数组,布局如所示。

名称 长度(字节数) 描述
rpIdHash 32 RP ID的SHA-256哈希,凭据作用域即此RP ID。
flags(标志位) 1 标志位(比特0为最低有效位):
signCount 4 签名计数器,32位无符号大端整数。
attestedCredentialData 可变(若存在) 证明凭据数据(如存在)。详见§ 6.5.1 证明凭据数据。长度依赖于credential ID长度及被证明的credential IDcredential public key的长度。
extensions 可变(如存在) 扩展定义的认证器数据。这是一个以扩展标识符为键、以认证器扩展输出为值的CBOR映射,详见§ 9 WebAuthn扩展
认证器数据布局。名称列中的各名称仅供本文内部引用,在实际认证器数据表示中并不存在。

RP ID在凭据创建以及生成断言时最初由客户端接收。然而它与其他客户端数据有重要区别:首先,其值不像客户端数据那样会在不同操作之间变化,而是在凭据生命期内保持不变;其次,在authenticatorGetAssertion期间,认证器会校验所请求凭据RP ID客户端传入一致。

认证器生成认证器数据结构的步骤如下

显示了认证器数据结构的直观表示。

认证器数据结构布局图。
注意: 认证器数据可自描述其长度:如未设置ATED标志,长度始终为37字节。证明凭据数据(仅在AT位为1时存在)自身可描述长度。若ED位为1,则总长度为37+证明凭据数据(如有)长度+扩展输出(CBOR映射)长度。

判断证明凭据数据的长度,需要先根据前面的credentialId长度确定credentialPublicKey的起始位置,再判断credentialPublicKey长度;参见RFC9052第7节

6.1.1. 签名计数器(Signature Counter)注意事项

认证器应实现签名计数器功能。签名计数器可按凭据单独存储,也可全局存储于认证器主体。凭据初始签名计数器的值,由signCount字段指明,来源于认证器数据,由authenticatorMakeCredential产生。每次authenticatorGetAssertion操作成功,签名计数器按正数递增,并在随后的认证器数据中返回给WebAuthn信赖方签名计数器用于协助信赖方检测认证器克隆,尤其对保护措施有限的认证器意义更大。

未实现签名计数器的认证器,其signCount值应恒为0。

信赖方保存最近一次authenticatorGetAssertion操作返回的签名计数器,如尚未通过authenticatorGetAssertion,则保存authenticatorMakeCredential时的计数器。在随后的authenticatorGetAssertion操作中,信赖方比对本地保存的与新获得的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) 客户端存储 多因子认证
若干认证器类型名称定义

二次因子平台认证器适合同一客户端设备的再次认证, 并可为新会话启动和恢复既有会话时增加安全层。 二次因子漫游认证器更常用于在某个客户端设备首次认证, 或在多用户共享的客户端设备上认证。

密钥平台认证器密钥漫游认证器支持无密码多因子认证。 除证明持有凭据私钥外, 这些认证器还作为第二个认证因子支持用户验证,例如PIN或生物识别。 因而,认证器可同时充当两类认证因子, 实现多因子认证同时免除与信赖方共享密码的需要。 此类认证器还支持可发现凭据(又称密钥), 即可允许认证流程无需输入用户名。

用户验证平台认证器类别基本已被密钥平台认证器所取代, 但isUserVerifyingPlatformAuthenticatorAvailable方法仍在使用此定义。

上表未命名的其他组合用例价值较低:

下节将更详细定义认证器连接形态凭据存储形式认证因子能力

6.2.1. 认证器连接形态

客户端可通过多种机制与认证器通信。例如,客户端可以调用客户端设备专有API与物理绑定于本机的认证器通信。也可以通过标准化的跨平台传输协议(如蓝牙,见§ 5.8.4认证器传输枚举)发现并与跨平台连接认证器通信。本地集成于客户端设备的认证器称为平台认证器,而由跨平台协议可达的则为漫游认证器

某些平台认证器也可能在某些场景下充当漫游认证器。例如,内置于移动设备的平台认证器可通过蓝牙作为漫游认证器使用。 本机运行的客户端会将其视作平台认证器, 而其他设备上通过蓝牙通信的客户端则会认为它是漫游认证器

平台认证器的主要用途是将特定客户端设备注册为“受信设备”, 这样客户端设备自身可在未来的认证中作为拥有要素。 用户因此可获得无需携带漫游认证器即可完成后续认证流程的便利,比如无需再掏钥匙或手机。

漫游认证器的用例包括:首次在新客户端设备上认证、临时设备或多人共用的客户端设备、无内置平台认证器客户端设备, 或因政策/偏好要求认证器与所用设备分离时。 也可用作备份凭据以防其他认证器遗失。

6.2.2. 凭据存储形式

认证器可通过两种方式储存公钥凭据源

  1. 嵌入于认证器客户端客户端设备的持久性存储,例如安全元件。 这是客户端可发现公钥凭据源的技术要求。

  2. 公钥凭据源加密(即加壳),仅本认证器才能解密(解壳),所得密文即为凭据ID凭据ID信赖方保存,并通过allowCredentials参数传回认证器,使其解密并使用对应的公钥凭据源

    这样可让认证器拥有无限制凭据存储空间,因为加密后的凭据源信赖方保存而非认证器本身——但这种凭据使用前需先向信赖方取回。

认证器支持的存储策略决定其凭据存储形式

请注意,支持可发现凭据认证器可同时支持两种存储策略。此时,可针对不同凭据选择不同存储方式,但需受residentKeyrequireResidentKey参数约束。

6.2.3. 认证因子能力

认证过程中用于证明身份的认证因子,可归为三大类:拥有要素知识要素本体要素。 如物理钥匙、密码、指纹。

所有WebAuthn认证器都属于拥有要素类型,但支持用户验证认证器还可兼作一类或两类其他认证因子。如认证器能校验PIN,则PIN为知识要素生物识别认证器可校验本体要素。因此,支持用户验证认证器多因子认证。反之,不支持的为单因子认证。注意,一个多因子认证器可支持多种用户验证方式,即可同时作为三类认证因子。

虽然用户验证认证器本地完成而非由信赖方执行,但认证器会在签名响应中设置UV标志,告知信赖方已进行用户验证。 信赖方可借UV标志确定注册或认证流程确实用到额外认证因子。UV标志的可信性则可依据认证器证明声明评估。

6.3. 认证器操作

WebAuthn客户端必须先连接认证器才能调用其任何操作。该连接定义了认证器会话。认证器必须保证会话隔离,原则上可只允许单一会话存在,或用更复杂方式区分。

以下操作可在认证器会话中由客户端调用。

6.3.1. 按凭据ID查找凭据源算法

认证器 authenticator查找凭证 ID credentialId的结果,是通过如下算法得到的:

  1. 如果authenticator能将credentialId解密为公钥凭据源credSource

    1. 设置credSource.idcredentialId

    2. 返回credSource

  2. 遍历authenticator凭据映射中每个公钥凭据源credSource

    1. credSource.id等于credentialId,返回credSource

  3. 返回null

6.3.2. authenticatorMakeCredential操作

调用该操作前,客户端必须调用authenticatorCancel操作 ,以终止当前会话中的所有其他操作。

本操作接收如下输入参数:

hash

客户端提供的序列化客户端数据的哈希

rpEntity

信赖方PublicKeyCredentialRpEntity

userEntity

用户账户PublicKeyCredentialUserEntity,含有用户标识(user handle),由信赖方给定。

requireResidentKey

客户端确定的凭据创建流程的resient key有效需求布尔值。

requireUserPresence

恒定布尔值true,或当options.mediationconditional 且用户代理已采集用户同意时为FALSE

requireUserVerification

客户端确定的凭据创建流程的用户验证有效需求布尔值。

credTypesAndPubKeyAlgs

信赖方请求的一组PublicKeyCredentialType与公钥算法(COSEAlgorithmIdentifier)对,按优先级从高到低排序。认证器尽力创建能支持的优先度最高的凭据。

excludeCredentialDescriptorList

选填项,一组PublicKeyCredentialDescriptor对象,由信赖方给定,意在告知认证器如知晓其中任何对象则不应再创建新凭据。 excludeCredentialDescriptorList中即为已知凭据。

enterpriseAttestationPossible

布尔值,指示认证器可以返回唯一标识的attestation。

attestationFormats

一串字符串,表示信赖方对attestation声明格式的偏好,按优先级从高到低排列。如认证器返回attestation,会尽量使用首选格式。

extensions

由客户端基于信赖方请求的扩展(如有)生成的CBOR 映射,键为扩展标识符,值为认证器扩展输入

当调用本操作时,认证器必须按如下流程操作:

  1. 检查所有输入参数语法是否正确且长度合规,否则返回"UnknownError"错误并终止。

  2. 检查credTypesAndPubKeyAlgs中的至少一组PublicKeyCredentialType与加密参数为认证器所支持,否则返回"NotSupportedError"错误并终止。

  3. 遍历excludeCredentialDescriptorList:

    1. 如在本认证器上查找 descriptor.id 返回非null,并且结果项的RP IDtype分别等于rpEntity.idexcludeCredentialDescriptorList.type, 则采集授权手势确认用户同意创建新凭据。授权手势必须含用户在场检测。若用户

      同意新建凭据

      返回"InvalidStateError"错误并终止。

      不同意

      返回"NotAllowedError"错误并终止。

      注意:授权手势只用于隐私目的,授权披露descriptor.id已被本认证器绑定,不是用于继续创建凭据。 若用户同意,客户端信赖方即可知晓,引导用户用其它认证器。如用户不同意, 认证器则不会暴露该id已绑定,仅表现为用户拒绝新建凭据。

  4. requireResidentKeytrue且认证器无法存储客户端可发现凭据源, 返回"ConstraintError"错误并终止。

  5. requireUserVerificationtrue且认证器不能执行用户验证,返回"ConstraintError"错误并终止。

  6. 授权手势完成且用户同意后,生成新凭据对象:

    1. 生成一对publicKeyprivateKey密钥,采用认证器支持的PublicKeyCredentialType及加密参数。

    2. userHandle取自userEntity.id

    3. 新建credentialSource 公钥凭据源,字段包括:

      type

      public-key

      privateKey

      privateKey

      rpId

      rpEntity.id

      userHandle

      userHandle

      otherUI

      认证器选择包含的任意信息。

    4. requireResidentKeytrue或认证器主动创建客户端可发现凭据源

      1. 生成新credentialId

      2. credentialSource.idcredentialId

      3. credentials为本认证器凭据映射

      4. 设定 credentials[(rpEntity.id,userHandle)] = credentialSource

    5. 否则:

      1. credentialSource序列化加密,仅本认证器可解密,所得即credentialId

  7. 如创建凭据目标对象时出错,则返回"UnknownError"错误并终止。

  8. processedExtensions认证器扩展处理结果,遍历所有受支持扩展。

  9. 判断认证器:

    为U2F设备

    新凭据的签名计数器取0。(U2F设备可能有计数器但创建凭据时不返回。详见[FIDO-U2F-Message-Formats]。)

    支持全局签名计数器

    生成认证器数据时用实际计数器值。

    支持每凭据签名计数器

    分配计数器,与新凭据关联,初值为0。

    不支持签名计数器

    新凭据计数器恒为0。

  10. attestedCredentialData为包含credentialIdpublicKey证明凭据数据字节数组。

  11. 选择第一个被支持的attestation声明格式标识作为attestationFormat,若候选中无支持项则选择认证器最偏好的格式。

  12. § 6.1 认证器数据生成authenticatorData字节数组,如有则包含attestedCredentialDataprocessedExtensions

  13. § 6.5.4 证明对象生成流程,以attestationFormatauthenticatorDatahashenterpriseAttestationPossible生成新凭据的证明对象,详情见§ 6.5证明

操作成功时,认证器向客户端返回证明对象

6.3.3. authenticatorGetAssertion 操作

在调用此操作之前,客户端必须调用 authenticatorCancel 操作,以中止身份验证器会话中正在进行的所有其他操作。

此操作接收以下输入参数:

rpId

调用方的 RP ID,由用户代理和客户端确定

hash

由客户端提供的序列化客户端数据的哈希值

allowCredentialDescriptorList

一个可选的 列表,包含 PublicKeyCredentialDescriptor 描述可被 Relying Party(可能已被客户端过滤)接受的凭据。

requireUserPresence

常量布尔值 true。 将其作为伪参数包含在此,以简化将此抽象身份验证器模型应用于可能希望将用户在场测试设为可选项的实现,尽管 WebAuthn 本身不允许其为可选。

requireUserVerification

用于断言的有效用户验证需求,一个由客户端提供的布尔值。

extensions

一个由扩展标识符到其身份验证器扩展输入CBOR 映射,由客户端根据Relying Party所要求的扩展创建。

当调用此方法时,身份验证器必须执行以下步骤:

  1. 检查所有提供的参数是否语法正确且长度合适。如果不是,返回等价于"UnknownError"的错误码并终止操作。

  2. credentialOptions 为新的空集合,用于存储公钥凭据源

  3. 如果传入了 allowCredentialDescriptorList,则针对每个 descriptor 遍历 allowCredentialDescriptorList

    1. credSource 为在此身份验证器中查找 descriptor.id 的结果。

    2. 如果 credSourcenull,则添加credentialOptions 中。

  4. 否则(未传入 allowCredentialDescriptorList),遍历此身份验证器的凭据映射添加credSourcecredentialOptions

  5. 移除 credentialOptionsrpId 不等于 rpId 的项。

  6. 如果 credentialOptions 已为空,则返回等价于"NotAllowedError"的错误码并终止操作。

  7. 提示用户从 credentialOptions 中选择一个公钥凭据源 selectedCredential。 收集授权手势以确认用户同意使用 selectedCredential。 授权手势提示可以由身份验证器自行显示(如果具备输出能力),否则由用户代理显示。

    如果 requireUserVerificationtrue,则授权手势必须包含用户验证

    如果 requireUserPresencetrue,则授权手势必须包含用户在场测试

    如果用户不同意,则返回等价于"NotAllowedError"的错误码并终止操作。

  8. processedExtensions 为对 extensions 中每一对被支持的扩展标识符身份验证器扩展输入执行扩展处理的结果。

  9. 增加与凭据相关的签名计数器或全局签名计数器的值(取决于身份验证器实现的方式),递增为正值。 如果身份验证器没有实现签名计数器,则该计数器值始终为零。

  10. authenticatorData § 6.1 身份验证器数据中规定的字节数组,如有 processedExtensions 作为 extensions 则包含之,不包含 attestedCredentialData

  11. signature 为以 selectedCredentialprivateKeyauthenticatorData || hash 进行签名所得的断言签名,流程如 下图 所示。此处使用简单、无分隔的拼接是安全的,因为身份验证器数据自身描述其长度。序列化客户端数据的哈希值(若干变长)始终在最后。

    生成断言签名
  12. 如果生成断言签名时发生任何错误,则返回等价于"UnknownError"的错误码并终止操作。

  13. 返回给用户代理:
    • selectedCredential.id,如果客户端传入的凭据列表(即 allowCredentialDescriptorList)长度大于等于2或未传入该列表。

      注意:如果 allowCredentialDescriptorList 仅包含一个凭据并已成功使用,则其凭据ID不会返回,因为客户端已经知晓。此举可节省可能受限连接下的数据传输量,且该场景可能较常见。

    • authenticatorData

    • signature

    • selectedCredential.userHandle

      注意:如果客户端传入了 allowCredentialDescriptorList,则返回的 userHandle 可能为 null,详见 userHandleResult

如果身份验证器无法找到与指定Relying Party匹配并满足指定条件的凭据,则终止操作并返回错误。

6.3.4. authenticatorCancel 操作

此操作不接收输入参数,也不返回结果。

当客户端在身份验证器会话中调用此操作时,将终止该会话下正在进行的任何authenticatorMakeCredentialauthenticatorGetAssertion 操作。身份验证器将停止提示或接受任何与已取消操作相关的用户输入。客户端会忽略身份验证器对已取消操作的任何后续响应。

如果此操作在一个未包含authenticatorMakeCredentialauthenticatorGetAssertion 操作的身份验证器会话中被调用,则会被忽略。

6.3.5. silentCredentialDiscovery 操作

这是一项可选操作,身份验证器可以支持该操作以启用 conditional 用户介入

其接收以下输入参数:

rpId

调用方的 RP ID,由客户端 确定

当调用此操作时,身份验证器必须执行以下步骤:

  1. collectedDiscoverableCredentialMetadata 为新的列表,其DiscoverableCredentialMetadata 结构体,包含以下字段

    type

    一个 PublicKeyCredentialType

    id

    一个凭据ID

    rpId

    一个Relying Party 标识符

    userHandle

    一个用户句柄

    otherUI

    用于身份验证器界面的其他信息。

  2. 遍历 公钥凭据源 credSource,取自 authenticator凭据映射

    1. 如果 credSource 不是客户端可发现凭据,则跳过

    2. 如果 credSource.rpId 不等于 rpId,则跳过

    3. discoveredCredentialMetadata 为一个新的DiscoverableCredentialMetadata 结构体,字段拷贝自 credSourcetypeidrpIduserHandleotherUI

    4. 追加 discoveredCredentialMetadatacollectedDiscoverableCredentialMetadata

  3. 返回 collectedDiscoverableCredentialMetadata

6.4. 字符串处理

身份验证器可能需要存储由Relying Party选择的任意字符串,例如 namedisplayName ,它们包含在 PublicKeyCredentialUserEntity 中。本节讨论处理这些可能呈现给人类的任意字符串时需要实际注意的一些后果。

6.4.1. 字符串截断

API 中的每个任意字符串都需考虑身份验证器可能有限的资源。如果采用字符串截断作为处理方式,必须注意不要破坏字符串的值。

例如,仅基于 Unicode 码点的截断可能会导致字形簇(grapheme cluster)被截断。这可能会使该字形簇渲染出不同的字形,从而改变字符串含义,而非只移除整个字形。例如, 展示了一个 UTF-8 编码字符串结尾,编码长度为 65 字节。如果要截断到 64 字节,则最后的 0x88 字节首先被移除以满足大小限制。由于这将导致一个不完整的 UTF-8 码点,剩余的该码点部分也必须一并移除。若还形成了不完整的字形簇,也应将该簇的剩余部分一并移除。

UTF-8 编码字符串结尾,显示不同截断边界的位置。

处理这些问题的主要责任在于客户端,以避免给身份验证器带来理解字符编码或 Unicode 字符属性的负担。下述子章节明确规定了客户端和身份验证器分别如何进行字符串截断的要求。

6.4.1.1. 客户端的字符串截断

WebAuthn 客户端截断字符串时,Relying Party可观察到的截断行为必须满足以下要求:

选择的大小限制不得小于规定的最小支持长度。字符串可以被截断,使其在 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 中的字符串可能要写入定制的身份验证器,然后再读出来显示在其它平台。因此,语言和方向元数据被编码进字符串本身,以确保信息整体传递。

对于允许编码语言和方向元数据的字符串,方法是,在其码点末尾添加两段码点序列:

第一段:用码点 U+E0001 加上语言标签各字母的 ASCII 值,各值均加 U+E0000。例如,语言标签 “en-US” 被编码为 U+E0001, U+E0065, U+E006E, U+E002D, U+E0055, U+E0053。

第二段:只包含一个码点,可为 U+200E(“左至右标记”)、U+200F(“右至左标记”)或 U+E007F(“取消标签”)。前两者用于指示书写方向,但只有在无法自动正确判断方向时才建议用(例如一个包含 LTR 强字符开头的 RTL 字符串)。U+E007F 用于表明语言标签结束、与方向无关。

因此,字符串“حبیب الرحمان”可以有两种不同的 DOMString 值,具体取决于是否编码语言(本例因方向明确,无需方向性标记)。

对可能已编码语言和方向的字符串进行处理时需注意,截断操作可能将语言标签截断为不同但依然有效的语言。最后的方向性标记或“取消标签”码点,可用来无歧义地标识截断。

6.5. 证明(Attestation)

认证器也应尽可能提供某种形式的证明。 如果认证器做到了,基本要求是认证器能够针对每个凭证公钥生成由WebAuthn 依赖方可验证的证明语句。通常,这个证明语句包含由证明私钥对已证明的凭证公钥和挑战生成的签名,以及由证明公钥提供来源信息的证书或类似数据,使依赖方可以做出信任决策。然而,如果没有可用的证明密钥对,则认证器可以使用相应的凭证私钥凭证公钥执行自我证明, 或使用无证明。所有这些信息在每次生成新的公钥凭证时都会由认证器返回,整体以证明对象的形式给出。证明对象与包含被证明凭证数据认证器数据以及证明语句之间的关系在下文中说明。

如果认证器采用自我证明无证明,则不会为依赖方提供进行信任决策所需的来源信息。 在这些情况下,认证器不会向依赖方提供关于自身操作的任何保证。

证明对象布局,展示了包含被证明凭据数据身份验证器数据以及证明语句
注意: 本图仅示例 packed 证明语句格式。第 8 节 还定义了多个其它 证明语句格式

证明对象(attestation object)的重要组成部分是 证明语句。这是一种签名数据对象,包含关于公钥凭据本身及创建它的身份验证器的信息。它包含一个由证明方密钥生成的证明签名(除了自我证明情形外,此时使用凭据私钥)。Relying Party要正确解释证明语句,需搞清楚证明的这两个方面:

  1. 证明语句格式是签名表示方式及各种上下文绑定如何被身份验证器并入证明语句中的方式。即,定义了证明语句的语法。各类平台(如 TPM、Android OS)已有多种证明语句格式,本规范通过 6.5.2 节 详述了可扩展支持多种格式的方法。格式本身用字符串标识,详见 8.1

  2. 证明类型定义了证明语句的语义及其信任模型。具体来说,它规定了Relying Party在验证证明语句的加密有效性后,如何建立信任。此规范支持多种证明类型,详见 § 6.5.3 证明类型

一般来说,证明语句格式证明类型之间没有简单映射。例如,packed 格式既可用于所有 证明类型,而其它格式和类型则适用范围有限。

证明的隐私性、安全性和操作特点由下列因素决定:

证明类型证明语句格式身份验证器选择;Relying Party只能通过设置 attestation 以及 attestationFormats 参数表达偏好。

大多数身份验证器预计只支持少数几种证明类型证明语句格式,而Relying Party会通过策略决定哪些类型可接受。Relying Party还需了解信任身份验证器的特性,可参考 FIDO Metadata Service [FIDOMetadataService]获取这类信息。

6.5.1. 证明的凭据数据

证明的凭据数据是在为凭据生成证明对象时,添加到认证器数据中的变长字节数组。其格式如表格 所示。

名称 长度(字节) 说明
aaguid 16 认证器的AAGUID
credentialIdLength 2 credentialId 的字节长度 L,16 位无符号大端整数。值必须 ≤ 1023。
credentialId L 凭据 ID
credentialPublicKey 可变 以 COSE_Key 格式编码的 凭据公钥,如 [RFC9052] 第 7 节 所定义,使用 CTAP2 标准 CBOR 编码形式。 COSE_Key 编码的 凭据公钥 必须包含 "alg" 参数,并且不得包含其它可选参数。"alg" 参数必须是 COSEAlgorithmIdentifier。 编码后的 凭据公钥 还必须包含该密钥类型规范规定的所有其他必需参数,即对 "kty" 和 "alg" 必须要求的(见 [RFC9053] 第 2 节)。
证明的凭据数据布局。名称列中的名称仅供本文件参考,实际表示 证明的凭据数据时不会出现。
6.5.1.1. credentialPublicKey COSE_Key 格式编码值示例

本节给出 ES256、PS256 和 RS256 签名算法下,COSE_Key 编码的椭圆曲线和 RSA 公钥示例。这些示例符合上面对 credentialPublicKey 值的规则,并以 CDDL [RFC8610] 展示以方便阅读。

[RFC9052] 第 7 节 定义了所有 COSE_Key 编码密钥的一般框架。特定算法下的密钥类型定义见 [RFC9053] 及下文涉及的其它规范。

下例为 EC2 格式(见 [RFC9053] 第 7.1 节)的 COSE_Key 编码椭圆曲线公钥,P-256 曲线、用于 ES256 签名算法(ECDSA w/ SHA-256,见 [RFC9053] 第 2.1 节):

{
  1:   2,  ; kty: EC2 密钥类型
  3:  -7,  ; alg: ES256 签名算法
 -1:   1,  ; crv: P-256 曲线
 -2:   x,  ; x 坐标,32 字节长度字节串
           ; 例如,十六进制: 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d
 -3:   y   ; y 坐标,32 字节长度字节串
           ; 例如,十六进制: 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,见 [RFC8230] 第 2 节):

{
  1:   3,  ; kty: RSA 密钥类型
  3: -37,  ; alg: PS256
 -1:   n,  ; n:   RSA 模数,256 字节长度字节串
           ;      例如,十六进制(中间内容省略):DB5F651550...6DC6548ACC3
 -2:   e   ; e:   公钥指数,3 字节长度字节串
           ;      例如,十六进制: 010001
}

下例为与上述相同公钥,但用于 RS256 签名算法(RSASSA-PKCS1-v1_5 with SHA-256):

{
  1:   3,  ; kty: RSA 密钥类型
  3:-257,  ; alg: RS256
 -1:   n,  ; n:   RSA 模数,256 字节长度字节串
           ;      例如,十六进制(中间内容省略):DB5F651550...6DC6548ACC3
 -2:   e   ; e:   公钥指数,3 字节长度字节串
           ;      例如,十六进制: 010001
}

6.5.2. 证明语句格式

如上所述,证明语句格式是指用于表示认证器对一组上下文绑定内容进行加密签名的数据格式。每种证明语句格式都必须按照如下模板进行定义:

最初指定的证明语句格式列表见§ 8 已定义的证明语句格式

6.5.3. 证明类型

WebAuthn 支持多种证明类型,这些定义了证明语句及其信任模型的语义:

注意:本规范并未专门定义用于表述认证器所用证明类型的数据结构。Relying Party在进行证明语句验证时(即调用 navigator.credentials.create() 时选择的证明传递不是 none,并验证收到的证明语句),会在验证过程中确定所采用的证明类型。参见 § 8 已定义的证明语句格式相关“验证过程”小节,以及 § 14.4.1 证明隐私性。除 SelfNone 之外,本节所有证明类型都要求 Relying Party 校验信任路径,匹配到 §7.1 注册新凭据,第 23 步 所述可接受的根证书。 区分这些证明类型主要用于判断证明是否符合Relying Party的安全策略。

基本证明 (Basic)

基本证明 [UAFProtocol] 情况下,认证器的证明密钥对是面向具体认证器“型号”分配的,即一批认证器共用。因此相同/近似型号认证器通常共享 证明密钥对。详见 § 14.4.1 证明隐私性

基本证明也称为 批量证明

自我证明 (Self)

自我证明(又称代理基本证明 [UAFProtocol])情况下,认证器没有专门的证明密钥对,而是直接用凭据私钥生成证明签名。一般来说,没有有效保护证明私钥措施的认证器采用此类型。

证明 CA (AttCA)

此情形下,认证器基于可信平台模块(TPM),持有认证器专用“背书密钥”(EK),该密钥用于与可信第三方,即证明 CA [TCG-CMCProfile-AIKCertEnroll] 安全通信。认证器可以生成多对证明身份密钥对(AIK),并为每对向证明 CA 申请签发证书。该方案可将 EK(全局唯一标识)暴露范围仅限于证明 CA。每个认证器生成的公钥凭据都可以单独申请 AIK,并通过证明证书传递给 Relying Party

注意:此模式下常见多张证明证书,最后申请的那张为“活跃”证书。

匿名化 CA (AnonCA)

此情形下,认证器使用匿名化 CA 动态为每个凭据生成证明证书,使向 Relying Party 传递的 证明语句不包含可唯一标识信息(如用于追踪等)。

注意:证明语句用以传递 证明AttCAAnonCA 类型与 Basic 类型语句结构完全一致,三者通常仅靠外部已知证书内容区分。

无证明语句 (None)

此时不存在任何证明信息。参见 § 8.7 None 证明语句格式

6.5.4. 生成证明对象

要生成证明对象(见:图 6),给定:

attestationFormat

一种证明语句格式

authData

含有认证器数据的字节数组。

hash

序列化客户端数据的哈希值

认证器必须:

  1. attStmt 为用 authDatahash 调用 attestationFormat签名过程所得结果。

  2. fmtattestationFormat证明语句格式标识符

  3. 以下列 CBOR 映射格式返回证明对象,其中各种变量依本算法初始化:

    attObj = {
        authData: bytes,
    
        ; $$attStmtType 的每个选项定义 fmt 和 attStmt 结构
        $$attStmtType
    } .within attStmtTemplate
    
    attStmtTemplate = {
        authData: bytes,
        fmt: text,
        attStmt: (
          { * tstr => any } ; 每种实际 attStmtType 填充 Map
          //
          [ * any ]         ; attStmt 也可以为数组
        )
    }
    

6.5.5. Packed Attestation、FIDO U2F Attestation 与断言签名的签名格式

建议新定义的证明格式不使用 ASN.1 编码,而是用与 COSE 签名相同的固定长度字节数组无结构方式表示,详见 [RFC9053][RFC8230]

下述签名格式定义满足上述要求,同时可作为其它未明确提及签名算法的实现参考:

7. WebAuthn Relying Party 操作

一个 注册认证流程WebAuthn Relying Party 分别创建一个 PublicKeyCredentialCreationOptionsPublicKeyCredentialRequestOptions 对象开始,这两个对象负责编码 流程 的参数。Relying Party 应确保在此阶段不泄漏敏感信息;详情见 § 14.6.2 用户名枚举

成功执行 create()get() 后,Relying Party 的脚本将从客户端收到一个 PublicKeyCredential ,其中包含 AuthenticatorAttestationResponseAuthenticatorAssertionResponse 结构。 然后必须将该结构的内容传递给 Relying Party 服务器,传递方式超出本规范范围。此节说明 Relying Party 在收到这些结构后需执行的操作。

7.1. 注册新凭据

为执行一次 注册流程Relying Party 必须按如下步骤操作:

  1. options 为新的 CredentialCreationOptions 结构体,根据 Relying Party 对该流程的需求进行设置。 令 pkOptionsoptions.publicKey

  2. 调用 navigator.credentials.create() 并将 options 作为参数传入。 令 credential 为成功解析的 Promise 结果。 如果 Promise 被拒绝,需以用户可见错误中止流程,或根据已知上下文引导用户操作。例如,如果 Promise 拒绝时错误码等价于 "InvalidStateError", 可提示用户换用其他 认证器。 关于不同错误情境及相关原因,详见 § 6.3.2 authenticatorMakeCredential 操作

  3. responsecredential.response。 若 response 不是 AuthenticatorAttestationResponse 实例,则以用户可见错误中止流程。

  4. clientExtensionResults 为调用 credential.getClientExtensionResults() 的结果。

  5. JSONtext 为对 response.clientDataJSON 的值执行 UTF-8 解码 的结果。

    注释: 只要实现的 UTF-8 解码 能得到与标准算法一致的结果,即可采用,尤其要去除任何前导字节顺序标记(BOM)。

  6. C,即 客户端数据,为对 JSONtext 运行特定实现的 JSON 解析器的结果。

    注释: C 可以是任何特定实现的数据结构表示,只要本算法要求的各分量可被引用即可。

  7. 验证 C.type 的值为 webauthn.create

  8. 验证 C.challenge 的值是否等于 pkOptions.challenge 的 base64url 编码值。

  9. 验证 C.origin 的值是否为 Relying Party 期望的 origin。 参考 § 13.4.9 验证凭据来源 获得指导。
  10. C.crossOrigin 存在且为 true, 验证 Relying Party 是否期望该凭据是在一个与其祖先非同源的 iframe 内创建的。

  11. C.topOrigin 存在:

    1. 验证 Relying Party 是否期望该凭据是在一个与其祖先非同源的 iframe 内创建的。

    2. 验证 C.topOrigin 的值是否与 Relying Party 期望嵌入页面的 origin 匹配。 参考 § 13.4.9 验证凭据来源

  12. hash 为使用 SHA-256 算法对 response.clientDataJSON 进行哈希运算得到的结果。

  13. attestationObject 字段进行 CBOR 解码以获得 attestation 声明格式 fmt认证器数据 authData,以及 attestation 声明 attStmt

  14. 验证 authDatarpIdHash 是否为 Relying Party 期望的 RP ID 的 SHA-256 哈希值。

  15. options.mediation 未被设置为 conditional, 则验证 authDataUP 位是否被设置。

  16. Relying Party 要求该注册流程进行 用户验证, 验证 authDataUV 位是否被设置。

  17. authDataBE 位未被设置,则验证 BS 位未被设置。

  18. Relying Party 以凭据的 备份可用性 指导其用户体验或策略,应评估 authDataBE 位。

  19. Relying Party 以凭据的 备份状态 指导其用户体验或策略,应评估 authDataBS 位。

  20. 验证 authData凭据公钥 的 "alg" 参数是否与 pkOptions.pubKeyCredParams 中某条目的 alg 属性一致。

  21. 通过对 fmt 与支持的 WebAuthn Attestation Statement Format Identifier 值集合进行 USASCII 区分大小写匹配,确定 attestation 声明格式。 WebAuthn Attestation Statement Format Identifier 已注册值的最新列表由 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表 [IANA-WebAuthn-Registries] 维护, 该注册表由 [RFC8809] 建立。

  22. 按照 fmtattestation 声明格式验证流程,使用 attStmtauthDatahash 验证 attStmt 是否为正确的 attestation 声明,并传递有效的 attestation 签名

    注释: 每种 attestation 声明格式 都定义了自己的 验证流程。详见 § 8 已定义的 attestation 声明格式,以及 [IANA-WebAuthn-Registries] 最新清单。

  23. 验证成功后,从可信来源或策略中获得该 attestation 类型和 attestation 声明格式 fmt 的可接受信任锚(即 attestation 根证书)列表。例如,通过 FIDO Metadata Service [FIDOMetadataService] ,并利用 authDataaaguid 字段 attestedCredentialData 获得相关信息。
  24. 利用验证流程(见第21步)的输出评估 attestation 的可信度,如下:

    若 attestation 声明不可信,Relying Party 应使 注册流程 失败。

    注释: 但若策略允许,Relying Party 可以登记此 凭据 ID 和凭据公钥, 但将其视为 自签名 attestation(见 § 6.5.3 attestation 类型)。此时,Relying Party 等于声明 对于该 公钥凭据 并无属某认证器型号的密码学证明。 参见 [FIDOSecRef][UAFProtocol] 的详细讨论。

  25. 验证 credentialId 的长度 ≤ 1023 字节。超出此长度的凭据 ID 应使 RP 使 注册流程 失败。

  26. 验证 credentialId 未被任何用户注册。若 credentialId 已存在,则 Relying Party 应使 注册流程 失败。

    注释: Relying Party 拒绝重复 凭据 ID 的理由如下: 凭据 ID 的熵足够高,偶然冲突的可能性极小。 但 非自签名 attestation 并未通过自签名明确证明 凭据私钥注册 时真实可用。 因此攻击者若获得了用户的 凭据 ID凭据公钥(实现方式多样), 可能尝试冒名注册,若被接受且原凭据可发现,则受害者下次登录将进入攻击者账户,数据可能被攻击者获取。

  27. credentialRecord 为一份新 凭据记录,其内容如下:
    type

    credential.type

    id

    credential.idcredential.rawId ,由 Relying Party 选择格式。

    publicKey

    authData 中的 凭据公钥

    signCount

    authData.signCount

    uvInitialized

    authDataUV 标志位 的值。

    transports

    response.getTransports() 的返回值。

    backupEligible

    authDataBE 标志位 的值。

    backupState

    authDataBS 标志位 的值。

    新的 凭据记录 还可以包含以下可选内容:

    attestationObject

    response.attestationObject

    attestationClientDataJSON

    response.clientDataJSON

    Relying Party 还可以根据需要包含任何额外的 信息项。 示例(非规范性):Relying Party 可以让用户为凭据设置“昵称”,以便用户在账户设置时分辨当前 凭据 是绑定到哪个 认证器

  28. 按需处理 clientExtensionResults 里的 客户端扩展输出, 以及 authData扩展 里的 认证器扩展输出, 具体由 Relying Party 决定。 每个 扩展 的处理可能有明确规范,也可能仅由 Relying Party 决定如何处理。 Relying Party 可以选择忽略部分或全部扩展输出。

    客户端 可以设置额外的 认证器扩展客户端扩展 ,这样会导致在 认证器扩展输出客户端扩展输出 中出现 Relying PartypkOptions.extensions 未请求的值。 Relying Party 必须做好处理这类情况的准备, 可选择忽略这些未请求的扩展或直接拒绝 attestation。Relying Party 可结合本地策略和使用的扩展来决定。

    由于所有扩展对于 客户端认证器 均为可选,Relying Party 还必须处理所有或部分请求扩展未生效的情况。

  29. 若上述所有步骤均通过, 将 credentialRecord 存储到 pkOptions.user 所指代的 用户账户中,并按需求继续 注册流程; 否则,使 注册流程 失败。

    Relying Party 未因此失败 注册流程, 则视为接受没有任何凭据是由特定 认证器 生成的密码学证明。 Relying Party 可以将该凭据等价视为 无 attestation(参见 § 6.5.3 attestation 类型)。 参见 [FIDOSecRef][UAFProtocol] 的详细讨论。

    验证 attestation object 要求 Relying Party 能可靠确定 第22步 里的信任锚, 且如涉及证书,Relying Party 必须能获取中间 CA 证书的状态信息。 如果客户端未提供 attestation 证书链,Relying Party 也必须能自行构建 attestation 证书链。

7.2. 验证认证断言

为了执行一次 认证仪式Relying Party 必须按以下步骤进行:

  1. options 为新的 CredentialRequestOptions 结构体,并配置为满足 Relying Party 对此次仪式的需求。令 pkOptionsoptions.publicKey

  2. 调用 navigator.credentials.get() 并将 options 作为参数传入。令 credential 为成功解析的 promise 的结果。如果 promise 被拒绝,则以用户可见的错误中止该过程,或根据被拒绝 promise 的上下文适当引导用户体验。关于不同错误上下文及其成因,详见 § 6.3.3 authenticatorGetAssertion 操作

  3. responsecredential.response。如果 response 不是 AuthenticatorAssertionResponse 的实例,则以用户可见的错误中止该过程。

  4. clientExtensionResults 为调用 credential.getClientExtensionResults() 的结果。

  5. 如果 pkOptions.allowCredentials 不为空,验证 credential.id 标识的是 public key credentials 中列出的其中一个,pkOptions.allowCredentials

  6. 识别当前正在认证的用户,令 credentialRecord 为对应 凭证记录credential

    如果用户在启动 认证仪式 前已被识别,例如通过用户名或 cookie,

    验证被识别的 用户账号 是否包含一个 凭证记录,其 id 等于 credential.rawId。令 credentialRecord 为该 凭证记录。如果 response.userHandle 存在,验证其等于该 用户句柄

    如果用户在启动 认证仪式 前未被识别,

    验证 response.userHandle 存在。验证 response.userHandle 标识的 用户账号 含有一个 凭证记录,其 id 等于 credential.rawId。令 credentialRecord 为该 凭证记录

  7. cDataauthDatasig 分别为 responseclientDataJSONauthenticatorDatasignature 的值。

  8. JSONtext 为对 cData 进行 UTF-8 解码 的结果。

    注意: 只要结果与 UTF-8 解码 算法一致,任何实现的 UTF-8 解码 都是可接受的。尤其要去除任何前导的字节顺序标记(BOM)。

  9. C(声称用于签名的 客户端数据)为执行特定实现的 JSON 解析器解析 JSONtext 的结果。

    注意:C 可以是任意特定实现的数据结构,只要 C 的各组成部分可被引用,满足本算法需求即可。

  10. 验证 C.type 的值为字符串 webauthn.get

  11. 验证 C.challenge 的值等于 pkOptions.challenge 的 base64url 编码。

  12. 验证 C.origin 的值为 Relying Party 期望的 。见 § 13.4.9 证书源验证
  13. 如果 C.crossOrigin 存在且为 true,验证 Relying Party 期望此凭证用于非 同源 的 iframe 内。

  14. 如果 C.topOrigin 存在:

    1. 验证 Relying Party 期望该凭证用于非 同源 的 iframe 内。

    2. 验证 C.topOrigin 的值与 Relying Party 期望被包含在的页面源匹配。见 § 13.4.9 证书源验证

  15. 验证 authData 内的 rpIdHash 是否为 RP ID 的 SHA-256 哈希值,且该 RP ID 为 Relying Party 期望值。

    注意: 如果使用 appid 扩展,本步骤需要特殊逻辑。见 § 10.1.1 FIDO AppID 扩展 (appid)

  16. 验证 authDataflagsUP 位已设置。

  17. 判断本次断言是否需要 用户验证。只有当 pkOptions.userVerification 设为 required 时,才应要求 用户验证

    如果需要 用户验证,则验证 authDataflagsUV 位已设置。否则,忽略 UV 标志

  18. 如果 authDataflagsBE 位未设置,则验证 BS 位未设置。

  19. 如果凭证 备份状态Relying Party 业务逻辑或策略采纳,令 currentBecurrentBsauthDataBEBS 位的值。并将 currentBecurrentBscredentialRecord.backupEligiblecredentialRecord.backupState 比较:

    1. 如果 credentialRecord.backupEligible 已设置,验证 currentBe 已设置。

    2. 如果 credentialRecord.backupEligible 未设置,验证 currentBe 未设置。

    3. 应用 Relying Party 策略(如有)。

    注意: 参见 § 6.1.3 凭证备份状态,了解 Relying Party 如何处理 BS 标志

  20. hashcData 以 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
      这表明认证器可能已被克隆,但并非确切证据。例如,这可能意味着:
      • 可能存在两个或更多 凭证私钥 副本,并被并行使用。

      • 认证器发生了故障。

      • 存在竞争条件,Relying Party 按非认证器生成顺序处理了断言响应。

      Relying Party 应结合自身业务特性,将此信息纳入风险评估。是否在本情况下在下方 credentialRecord.signCount 更新,或直接失败 认证仪式Relying Party 自行决定。

      更多签名计数器说明,参见 § 6.1.1 签名计数器说明

  23. Relying Party 需要,处理 clientExtensionResults客户端扩展输出authDataextensions认证器扩展输出。 不同 扩展 可有具体流程,也可由 Relying Party 自定处理方法。Relying Party 可忽略全部或部分扩展输出。

    客户端 可设置附加 认证器扩展客户端扩展,导致出现 认证器扩展输出客户端扩展输出,这些值并非 Relying PartypkOptions.extensions 请求的。Relying Party 必须能处理这种情况,可以选择忽略或拒绝断言。可以结合本地策略和实际使用扩展自行决定。

    所有扩展对 客户端认证器 都是可选的,Relying Party 也要能应对未命中全部或部分请求扩展的情形。

  24. 用新的状态值更新 credentialRecord
    1. credentialRecord.signCount 更新为 authData.signCount 的值。

    2. credentialRecord.backupState 更新为 currentBs 的值。

    3. 如果 credentialRecord.uvInitializedfalse,则更新为 authDataUV 位的值。此步骤建议需经附加的 认证因子 授权,如 WebAuthn 用户验证;未授权则略过此步骤。

    如果 Relying Party 还有更进一步的安全校验,则应在这些 WebAuthn 认证仪式检查后再执行上述状态更新。

  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 优化的证明声明格式。它采用极其紧凑但可扩展的编码方式,适用于资源有限(如安全元件)的认证器实现。

证明声明格式标识符

packed

支持的证明类型

基本自签AttCA

语法

Packed 证明声明的语法定义如下 CDDL:

$$attStmtType //= (
                      fmt: "packed",
                      attStmt: packedStmtFormat
                  )

packedStmtFormat = {
                       alg: COSEAlgorithmIdentifier,
                       sig: bytes,
                       x5c: [ attestnCert: bytes, * (caCert: bytes) ]
                   } //
                   {
                       alg: COSEAlgorithmIdentifier
                       sig: bytes,
                   }

各字段含义如下:

alg

COSEAlgorithmIdentifier ,即用于生成证明签名的算法标识符。

sig

包含证明签名的字节串。

x5c

此数组元素包含 attestnCert 及其证书链(如有),每项用 X.509 格式编码。attestnCert 认证证书必须是数组第一个元素。

attestnCert

以 X.509 格式编码的认证(证明)证书。

签名过程

此证明声明格式的签名过程类似于 断言签名生成流程

  1. authenticatorData 表示证明用的认证器数据clientDataHash 表示序列化客户端数据的哈希值

  2. 若使用 基本AttCA 证明,则认证器以 authenticatorDataclientDataHash 拼接后,用通过认证器特定机制选定的证明私钥签名,即得 sigx5c 设为 attestnCert 后跟其相关证书链(如有),alg 设为证明私钥的算法。

  3. 若使用 自证明,认证器以 authenticatorDataclientDataHash 拼接,由凭据私钥签名,得 sigalg 设为凭据私钥的算法,其他字段省略。

验证过程

给定验证输入 attStmtauthenticatorDataclientDataHash验证过程如下:

  1. 确认 attStmt 为符合上述语法的有效 CBOR,并对其进行 CBOR 解码提取字段。

  2. x5c 存在:

    • attestnCert 的公钥及 alg 算法,验证 sig 是否为 authenticatorDataclientDataHash 拼接的有效签名。

    • 验证 attestnCert 是否满足 § 8.2.1 Packed 证明证书要求

    • attestnCert 含有 OID 为 1.3.6.1.4.1.45724.1.1.4id-fido-gen-ce-aaguid)的扩展,则验证其值与 authenticatorData 中的 aaguid 相等。

    • 可选,检查 x5c 并结合外部知识以判断 attStmt 属于 基本AttCA 证明。

    • 若验证成功,返回表示证明类型 基本AttCA 或不确定性的实现特定值,以及 证明信任路径 x5c

  3. 若无 x5c,即为自证明

    • 验证 alg 是否与 authenticatorDatacredentialPublicKey 的算法一致。

    • alg 和凭据公钥验证 sig 是否为 authenticatorDataclientDataHash 拼接的有效签名。

    • 若成功,返回表示证明类型自签及空证明信任路径的实现特定值。

8.2.1. Packed 证明声明的证书要求

证明证书必须包含以下字段/扩展:

可选地,还可包含 Authority Information Access (AIA) 扩展(带 id-ad-ocsp 的条目)及 CRL Distribution Point 扩展 [RFC5280]。 由于很多证明证书的状态可由认证器元数据服务查询,例如 FIDO Metadata Service [FIDOMetadataService]

特定认证器型号的固件版本可通过 OID 为 1.3.6.1.4.1.45724.1.1.5id-fido-gen-ce-fw-version)的扩展区分。若存在,该属性值为递增的非负整数,各新固件版本递增。不得标记为 critical。

下例为含所列扩展 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                                 -- 固件版本:42

8.2.2. 企业 Packed 证明声明的证书要求

OID 为 1.3.6.1.4.1.45724.1.1.2id-fido-gen-ce-sernum)的扩展可选地出现在企业用途的 packed 证明里。如存在,该扩展须针对特定 AAGUID,为每台设备指示唯一的 octet string 值。此值须在恢复出厂设置后保持不变,但可与设备其它序列号或硬件标识符不同。本扩展不得标记为 critical,值类型为 OCTET STRING。非企业证明不得含本扩展。

8.3. TPM 证明声明格式

此证明声明格式一般用于以可信平台模块(TPM)为加密引擎的认证器。

证明声明格式标识符

tpm

支持的证明类型

AttCA

语法

TPM 证明声明的语法如下:

$$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 ,即用于生成证明签名的算法标识符。

x5c

aikCert 及其证书链(X.509 编码)。

aikCert

用于证明的 AIK 证书(X.509 编码)。

sig

证明签名,以 [TPMv2-Part2] 11.3.4 节定义的 TPMT_SIGNATURE 结构体形式。

certInfo

用于签名的 TPMS_ATTEST 结构,详见 [TPMv2-Part2] 10.12.8 节。

pubArea

TPM 用于表示凭据公钥的 TPMT_PUBLIC 结构([TPMv2-Part2] 12.2.4 节)。

签名过程

authenticatorData 表示证明用的认证器数据clientDataHash 表示序列化客户端数据的哈希值

拼接 authenticatorDataclientDataHashattToBeSigned

[TPMv2-Part3] 18.2 节,用证明私钥生成签名,其中 extraData 设为 attToBeSigned 的摘要,哈希算法由 “alg” 指定。(如 "RS256" 则为 SHA-256 摘要。)

pubArea 设为凭据公钥的公有域(TPMT_PUBLIC 结构),certInfo 字段(TPMS_ATTEST 结构)即签名输出参数同名字段,sig 字段为上步所得签名。

注意:若通过 TPM2_ReadPublic 命令读取 pubArea,其返回 TPM2B_PUBLIC 结构(2 字节长度加 TPMT_PUBLIC)。须去除头两字节长度再填入 pubArea

验证过程

给定验证输入 attStmtauthenticatorDataclientDataHash验证过程如下:

确认 attStmt 为有效 CBOR,符合上文语法,并对其 CBOR 解码提取字段。

确认 pubAreaparametersunique 字段指定的公钥,与 authenticatorDatacredentialPublicKey 以及 attestedCredentialData 一致。

拼接 authenticatorDataclientDataHashattToBeSigned

验证 certInfo 的完整性

  • 确认 x5c 存在。

  • 验证 aikCert 是否满足 § 8.3.1 TPM 证明声明证书要求

  • aikCert 含有 OID 1.3.6.1.4.1.45724.1.1.4id-fido-gen-ce-aaguid)扩展,则验证其值与 authenticatorDataaaguid 相等。

  • aikCert 的公钥及 alg 算法,验证 sig 是否为 certInfo 的有效签名。

验证 certInfo 的有效性: 注:certInfo 为 TPMS_ATTEST 结构。

  • 确认 magic 设为 TPM_GENERATED_VALUE

  • 确认 type 设为 TPM_ST_ATTEST_CERTIFY

  • 确认 extraData 为用 “alg” 算法对 attToBeSigned 计算哈希所得值。

  • 确认 attested[TPMv2-Part2] 10.12.3 节定义的 TPMS_CERTIFY_INFO 结构,其 name 字段为用 pubArea 的 nameAlg 计算的合法 Name。见 [TPMv2-Part1] 16 节。

    注意:TPM 总以 pubArea 的 nameAlg 生成 name

    注意:“标准证明结构” [TPMv2-Part1] 31.2 节内的其余字段(qualifiedSignerclockInfofirmwareVersion)可忽略。依据使用的 aikCert 密钥特性,这些字段可能被遮蔽或用于风险引擎。

  • 若验证成功,返回表示证明类型 AttCA证明信任路径 x5c的实现特定值。

8.3.1. TPM 证明声明证书要求

TPM 证明证书必须包含如下字段/扩展:

8.4. Android Key 证明声明格式

当相关认证器是 Android "N" 或更高版本上的平台认证器时,证明声明基于 Android 密钥证明。此时,证明声明由安全操作环境中的组件生成,但证明用认证器数据是在该环境外生成的。WebAuthn Relying Party 需检查声明用于证明的认证器数据与证明证书拓展数据的字段一致性。

证明声明格式标识符

android-key

支持的证明类型

基本

语法

Android Key 证明声明即为 Android 证明声明本身,由一系列 DER 编码的 X.509 证书组成。详见Android 官方开发文档。其语法定义如下:

$$attStmtType //= (
                      fmt: "android-key",
                      attStmt: androidStmtFormat
                  )

androidStmtFormat = {
                      alg: COSEAlgorithmIdentifier,
                      sig: bytes,
                      x5c: [ credCert: bytes, * (caCert: bytes) ]
                    }

签名过程

authenticatorData 表示证明用的认证器数据clientDataHash 表示序列化客户端数据的哈希

调用 keyStore.getCertificateChain(myKeyUUID) 请求 Android Key Attestation,并将 clientDataHash 作为挑战值传入(如通过 setAttestationChallenge)。x5c 设为返回值。

认证器通过拼接 authenticatorDataclientDataHash 后用凭据私钥签名得到 sigalg 设为签名格式的算法。

验证过程

给定验证输入 attStmtauthenticatorDataclientDataHash验证过程如下:

  • 确认 attStmt 是符合上述语法的有效 CBOR,并进行 CBOR 解码提取字段。

  • x5c 的首个证书的公钥和 alg 指定算法,验证 sig 是否为 authenticatorDataclientDataHash 拼接的有效签名。

  • 校验 x5c 第一张证书公钥与 authenticatorDatacredentialPublicKey 一致。

  • 校验证明证书拓展数据中的 attestationChallenge 字段等于 clientDataHash

  • 使用证明证书拓展数据的授权列表(authorization list)做如下验证:

    • AuthorizationList.allApplications 字段在 softwareEnforcedteeEnforced 任一授权列表中均不可出现,因为 PublicKeyCredential 必须作用域限定RP ID

    • 如 RP 只接受可信执行环境的密钥,则仅用 teeEnforced 授权列表,否则用 teeEnforcedsoftwareEnforced 的并集:

      • AuthorizationList.origin 字段值等于 KM_ORIGIN_GENERATED

      • AuthorizationList.purpose 字段值等于 KM_PURPOSE_SIGN

  • 若成功,返回表示证明类型 基本以及证明信任路径 x5c 的实现特定值。

8.4.1. Android Key 证明声明证书要求

Android Key Attestation 证明证书Android Key 证明证书拓展数据的 OID 为 1.3.6.1.4.1.11129.2.1.17,其结构定义详见Android 官方文档

8.5. Android SafetyNet 证明声明格式

注意:本格式已弃用,预计将在将来版本中移除。

认证器是某些 Android 平台上的平台认证器时,证明声明可能基于 SafetyNet API。此时认证器数据完全由调用 SafetyNet API 的应用(通常是 Android 平台上的应用)控制,证明声明则提供关于平台健康和调用应用身份的信息(详见 SafetyNet 文档)。

证明声明格式标识符

android-safetynet

支持的证明类型

基本

语法

Android Attestation 声明的语法如下:

$$attStmtType //= (
                      fmt: "android-safetynet",
                      attStmt: safetynetStmtFormat
                  )

safetynetStmtFormat = {
                          ver: text,
                          response: bytes
                      }

各字段含义如下:

ver

提供 SafetyNet API 的 Google Play 服务的版本号。

response

SafetyNet API 的 getJwsResult() 返回的UTF-8 编码结果,此值为 JWS [RFC7515] 对象(详见 SafetyNet 在线文档),采用紧凑序列化格式。

签名过程

authenticatorData 表示证明用的认证器数据clientDataHash 表示序列化客户端数据的哈希

拼接 authenticatorDataclientDataHash,对其执行 SHA-256 哈希,取结果为 attToBeSigned

请求 SafetyNet attestation,将 attToBeSigned 作为 nonce。response 设为结果,ver 设为认证器内的 Google Play 服务版本号。

验证过程

给定验证输入 attStmtauthenticatorDataclientDataHash验证过程如下:

  • 确认 attStmt 是符合上述语法的有效 CBOR,并进行解码提取字段。

  • SafetyNet 在线文档 验证 responsever 版本的有效 SafetyNet 响应。目前仅有一种 SafetyNet 响应格式,ver 为将来扩展预留。

  • 验证 response 的 JWS 载荷中 nonce 属性等于 authenticatorDataclientDataHash 拼接后经 SHA-256 哈希并做 Base64 编码所得值。

  • 参照 SafetyNet 在线文档 验证 SafetyNet 响应实际来自 SafetyNet 服务。

  • 若成功,返回表示证明类型 基本以及证明信任路径 x5c 的实现特定值。

8.6. FIDO U2F 证明声明格式

该证明声明格式用于基于 [FIDO-U2F-Message-Formats] 定义的 FIDO U2F 认证器。

证明声明格式标识符

fido-u2f

支持的证明类型

基本AttCA

语法

FIDO U2F 证明声明的语法如下:

$$attStmtType //= (
                      fmt: "fido-u2f",
                      attStmt: u2fStmtFormat
                  )

u2fStmtFormat = {
                    x5c: [ attestnCert: bytes ],
                    sig: bytes
                }

各字段含义如下:

x5c

仅包含一张 X.509 证明证书的单元素数组。

sig

证明签名。 签名是对 U2F 注册响应消息 [FIDO-U2F-Message-Formats](认证器返回给客户端)的原始数据签发的。

签名过程

如果被证明凭据凭据公钥算法不是 -7("ES256"),则终止并返回错误。否则,设 authenticatorData证明用的认证器数据clientDataHash序列化客户端数据的哈希(采用 SHA-256,长度 32 字节)。

[FIDO-U2F-Message-Formats] 4.3 节要求生成注册响应消息,application parameter 设为该凭据作用域限定到的RP ID 的 SHA-256 哈希,challenge parameter 设为 clientDataHash,key handle parameter 设为凭据的 凭据 ID。将注册响应消息的原始签名字节(不含 user public key、key handle 和证明证书)设为 sig,证明公钥的证书设为 x5c

验证过程

给定验证输入 attStmtauthenticatorDataclientDataHash验证过程如下:

  1. 确认 attStmt 是符合上述语法的有效 CBOR,并解码提取字段。

  2. 检查 x5c 仅有一个元素,将其设为 attCert,再取 certificate public keyattCert 对应的公钥。若该公钥不是 P-256 曲线上的 EC 公钥,终止并返回错误。

  3. authenticatorData 取出 rpIdHash,并从 authenticatorData.attestedCredentialDatacredentialIdcredentialPublicKey

  4. 将 COSE_KEY 格式的 credentialPublicKey(详见 RFC9052 7 节)转换为原始 ANSI X9.62 公钥格式(见 FIDO-Registry 3.6.2 节)。

    • 取得 "-2" 键对应值 x(x 坐标),确认其为 32 字节。若大小不对或未找到,终止并报错。

    • 取得 "-3" 键对应值 y(y 坐标),确认其为 32 字节。若大小不对或未找到,终止并报错。

    • 0x04 || x || y 拼接为 publicKeyU2F

      注意: 这意味着未压缩 ECC 公钥格式。

  5. verificationData0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F(见 4.3 节)。

  6. certificate public keyverificationData,按 [SEC1] 4.1.4 节,使用 SHA-256 验证 sig

  7. 可选,检查 x5c 并结合外部信息判断 attStmt基本 还是 AttCA 证明。

  8. 若成功,返回表示证明类型 基本AttCA 或未确定,以及证明信任路径 x5c的实现特定值。

8.7. None 证明声明格式

None 证明声明格式用于当WebAuthn Relying Party声明不希望接收证明信息时,替换任意认证器返回的证明声明。详见§ 5.4.7 Attestation Conveyance Preference Enumeration (enum AttestationConveyancePreference)

如果认证器不支持证明,其也可直接生成此格式的证明声明。

证明声明格式标识符

none

支持的证明类型

语法

none 证明声明格式语法如下:

$$attStmtType //= (
                      fmt: "none",
                      attStmt: emptyMap
                  )

emptyMap = {}
签名过程

返回上述固定证明声明。

验证过程

返回表示证明类型 以及空证明信任路径的实现特定值。

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, 执行与 声明格式标识符 subStmt.fmt 对应的验证流程,使用 流程输入 subStmtauthenticatorDataclientDataHash

    若任一 subStmt 验证失败,可依Relying Party 策略决定处理结果。

  2. 若足够多(由Relying Party 策略决定)项目attStmt 中通过验证, 则返回由所有通过的验证流程输出组成的组合实现相关值。

9. WebAuthn 扩展

生成公钥凭据及请求、生成认证断言的机制(定义于§ 5 Web Authentication API)可通过扩展进行适应。每种情形通过定义注册扩展 及/或 认证扩展实现。

每个扩展都是客户端扩展,意味着扩展涉及与客户端的通信与处理。客户端扩展定义了以下步骤和数据:

在创建公钥凭据或请求认证断言时, WebAuthn Relying Party 可请求使用一组扩展。若客户端和/或WebAuthn 认证器支持,这些扩展将在请求操作时被调用。Relying Party 通过 get() (用于认证扩展)或 create() (用于注册扩展)调用时,为每个扩展发送 客户端扩展输入客户端客户端 对所支持扩展执行客户端扩展处理,并按每个扩展规范用 扩展标识符客户端扩展输出补充 客户端数据

扩展也可为认证器扩展,即扩展涉及认证器通信及处理。认证器扩展定义了如下流程及数据:

对于认证器扩展,作为客户端扩展处理的一部分,客户端还需为每个扩展创建 CBOR 格式的 认证器扩展输入 值(通常基于对应的 客户端扩展输入),并通过 create() (用于注册扩展)或 get() (用于认证扩展)传递给认证器。这些 认证器扩展输入CBOR 表示,并以 扩展标识符 作为名称、相应的 认证器扩展输入 作为值的键值对形式传递。认证器对其支持的扩展执行进一步处理并返回每个扩展的 CBOR 认证器扩展输出。由于 认证器扩展输出认证器数据 签名返回,认证器扩展可另指定未签名扩展输出,例如当输出本身需依赖 认证器数据时。 作为客户端扩展处理的一部分,要用 认证器扩展输出未签名扩展输出 构造 客户端扩展输出

所有 WebAuthn 扩展 对于客户端和认证器来说都是可选的。因此,Relying Party 请求的扩展可能被浏览器或操作系统忽略而不会传给认证器,也可能被认证器忽略。 扩展被忽略不属于 WebAuthn API 流程失败,因此 Relying Party 使用扩展时,必须能正确处理部分或全部扩展被忽略的情况。

所有 WebAuthn 扩展 必须制定,使客户端与认证器不支持该扩展时不会危及用户安全或隐私。 例如,若扩展需要客户端处理,可设计为仅做格式转发(如简单地把 客户端扩展输入 从 JSON 转为 CBOR),经认证器处理后无语义效果,该扩展即被安全地忽略。由于扩展均为可选,不会导致 API 调用失败。

IANA“WebAuthn 扩展标识符”注册表 [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() 传递),客户端扩展处理规则和 客户端扩展输出值。 如扩展需认证器通信(即为 认证器扩展),还须指定 CBOR 认证器扩展输入参数(通过 authenticatorGetAssertionauthenticatorMakeCredential 调用),认证器扩展处理规则以及 CBOR 认证器扩展输出值。 扩展可指定未签名扩展输出

客户端处理的 客户端扩展 必须返回 客户端扩展输出,以便 WebAuthn Relying Party 可确认扩展已被客户端支持。认证器处理的扩展则必须返回 认证器扩展输出,以便 Relying Party 明确扩展被认证器支持。若扩展无需返回其它结果,推荐定义为返回 JSON 布尔 客户端扩展输出 结果(true 表示扩展已被理解并处理)。类似,未定义返回值的 认证器扩展 应返回 CBOR 布尔 认证器扩展输出(true 表示扩展被处理)。

9.3. 扩展请求参数的拓展

扩展定义一个或两个请求参数。客户端扩展输入 (可编码为 JSON 的值)由 WebAuthn Relying Party 通过 get()create() 方法传递到客户端; 对于认证器扩展CBOR 格式的认证器扩展输入会在流程中由客户端传递给认证器。

Relying Party 请求扩展并设置其 客户端扩展输入,方式是在 extensions 选项中传递对应 扩展标识符 键及值(客户端扩展输入),无论是在 create()get() 调用中。

注意: 其它文档可能指定扩展输入并非严格用扩展标识符作键,但对于新扩展仍然适用上述规范。

var assertionPromise = navigator.credentials.get({
    publicKey: {
        // 省略其它成员
        extensions: {
            // “entry key”为“webauthnExample_foobar”扩展,
            // 其值为含两个输入参数的对象:
            "webauthnExample_foobar": {
              foo: 42,
              bar: "barfoo"
            }
        }
    }
});

扩展定义必须说明其 客户端扩展输入 的合法值。客户端应忽略无效输入的扩展。如扩展无需 Relying Party 参数,建议定义为布尔型客户端参数,true 表示请求使用该扩展。

仅影响客户端处理的扩展无需定义 认证器扩展输入。 涉及认证器处理的扩展,必须说明如何从 客户端扩展输入 生成 认证器扩展输入, 并就CDDL类型 AuthenticationExtensionsAuthenticatorInputsAuthenticationExtensionsAuthenticatorOutputs 定义 $$extensionInput$$extensionOutput 的组套新分支,采用扩展标识符为键。 参数为布尔型的扩展,其 认证器扩展输入 也应为常量布尔 true(CBOR 主类型7,值21)。

以下示例定义了标识符为 webauthnExample_foobar 的扩展,接收无符号整数作为 认证器扩展输入,返回一组字节串作为 认证器扩展输出

$$extensionInput //= (
  webauthnExample_foobar: uint
)
$$extensionOutput //= (
  webauthnExample_foobar: [+ bytes]
)

由于部分认证器通过低带宽链路(如蓝牙低能耗或 NFC)通信,建议定义的认证器参数尽可能小。

9.4. 客户端扩展处理

扩展可定义在凭据创建或断言生成时 客户端 的附加处理流程。客户端扩展输入 用作此客户端处理的输入。 对于所有受支持的 客户端扩展,客户端会将扩展标识符为键、扩展输入为值,加入 clientExtensions 有序字典

同理,客户端扩展输出 作为字典返回,由 getClientExtensionResults() 产出, 以扩展标识符为键、客户端扩展输出为值。与 客户端扩展输入一样,客户端扩展输出 也可被 JSON 编码。 对于被忽略的扩展不得返回任何值。

需认证器处理的扩展必须定义使用 客户端扩展输入 派生出 CBOR 认证器扩展输入 的方法,以及如何利用 CBOR 认证器扩展输出未签名扩展输出 生成 客户端扩展输出

9.5. 认证器扩展处理

各受支持的 认证器扩展CBOR 认证器扩展输入 包含于 authenticatorMakeCredentialauthenticatorGetAssertion 操作的 extensions 参数内。参数为 CBOR 字典,键为 扩展标识符,值为该扩展的 认证器扩展输入

扩展输出表现在 extensions 区域(认证器数据的一部分),其格式为 CBOR 字典,每键为 扩展标识符,值为 认证器扩展输出

未签名扩展输出 独立于 认证器数据 返回,以同一扩展标识符为键的字典单独返回,只包含用到未签名输出的扩展。未签名输出适用于扩展需输出认证器数据签名(因无法对自身签名),或部分扩展输出不应传给 Relying Party 场景。

注意:[FIDO-CTAP] 中,未签名扩展输出 作为顶层 unsignedExtensionOutputs 字段返回,包括 authenticatorMakeCredentialauthenticatorGetAssertion 操作。

每个受支持扩展,均依据其 认证器扩展处理 规则,将 认证器扩展输入(以及其它所需输入)转换为 认证器扩展输出,如需还可产出 未签名扩展输出,被忽略的扩展不得有输出。

10. 已定义扩展

本节及其小节定义了应注册于 IANA“WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)的扩展,可供致力于广泛互操作性的用户代理实现。

10.1. 客户端扩展

本节定义仅为客户端扩展的扩展。

10.1.1. FIDO AppID扩展(appid)

本扩展允许已使用传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 注册凭据的 WebAuthn Relying Parties 请求 断言。FIDO API 使用一种称为 AppID 的 Relying Party 替代标识符 [FIDO-APPID],所有通过该 API 创建的凭据均限定在该标识范围。若无此扩展,须重新注册才能限定到 RP ID

除设置 appid 输入外,使用本扩展还要求 Relying Party 进行一些额外处理,以允许用户使用已注册 U2F 凭据认证

  1. 将所需 U2F 凭据列入 allowCredentials 选项,作为 get() 方法参数:

    • type 成员设为public-key

    • id 成员设为相应 U2F 凭据的 key handle。注意,U2F key handle 常用 base64url 编码,但在 id 处须解码为二进制。

    allowCredentials 可同时含 WebAuthn credential ID 与 U2F key handle; 使用此扩展指定的 appid 并不妨碍用户用限定到 RP ID(参数 rpId)的 WebAuthn 凭据。

  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;
};
客户端扩展处理
  1. facetId 为调用者 origin 交由 FIDO 算法确定应用 FacetID 的结果。

  2. appId 设为扩展输入值。

  3. facetIdappId 交由 FIDO 算法判断 FacetID 是否获授权使用 AppID,如拒绝则抛出 "SecurityError" DOMException

  4. 构建 allowCredentialDescriptorList 时, 若 U2F 认证器反馈凭据不适用(如返回 SW_WRONG_DATA),客户端须用 appId 的 SHA-256 哈希作为 U2F application parameter 重试。若返回适用凭据,必须将该凭据纳入 allowCredentialDescriptorList,并用 appId 替换 authenticatorGetAssertionrpId 参数。

  5. output 为布尔值 false

  6. 创建 assertionCreationData 时, 若断言由 U2F 认证器在 application parameter 为 appId 的 SHA-256 哈希时生成,则将 output 设为 true

注意: 实际上,多实现并未完整实现 “判断 FacetID 是否获授权使用 AppID” 算法的第四步及之后流程,仅在主机名对比时,三步处放宽为接受同一 网站 的主机。

客户端扩展输出

返回 output 的值。若为 true,表示已用 AppID,Relying Party 校验断言时须以 AppID 哈希做 rpIdHash,而不是 RP ID 哈希。

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appid;
};
认证器扩展输入

无。

认证器扩展处理

无。

认证器扩展输出

无。

10.1.2. FIDO AppID 排除扩展(appidExclude)

该注册扩展允许WebAuthn Relying Party 排除包含指定通过传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 创建凭据的认证器。

在从 FIDO U2F JavaScript API 迁移过程中,Relying Party 可能有一部分用户已经注册了传统凭据。appid 扩展可平滑迁移登录流程,但迁移注册流程时,excludeCredentials 字段将无法有效排除含有传统凭据的认证器,因为它的内容被视为 WebAuthn 凭据。此扩展指示客户端平台excludeCredentials内容同时视为 WebAuthn 和传统 FIDO 凭据。注意 U2F key handle 通常使用 base64url 编码,但用作 excludeCredentials 时须解码成二进制。

扩展标识符

appidExclude

适用操作

注册

客户端扩展输入

一个 DOMString,指定 FIDO AppID

partial dictionary AuthenticationExtensionsClientInputs {
  DOMString appidExclude;
};
客户端扩展处理

创建新凭据时:

  1. 确定 RP ID 后,执行如下步骤:

    1. facetId 为调用方 origin 传递给 FIDO 算法的结果,用于确定应用 FacetID

    2. appId 为扩展输入 appidExclude 的值。

    3. facetIdappId 传递给 FIDO 算法判断 FacetID 是否被授权用于该 AppID。若该算法拒绝 appId,则 返回 "SecurityError" DOMException 并终止创建新凭据算法及后续步骤。

      注意: 实际上,多数实现未实现该算法的第四步及其后流程,第三步主机比较实际放宽为接受同一网站的主机。

    4. 否则,继续正常流程。

  2. 调用 authenticatorMakeCredential 之前,执行如下步骤:

    1. authenticator 支持 U2F 协议 [FIDO-U2F-Message-Formats], 则 excludeCredentialDescriptorList 中的每个凭据描述符 C

      1. 通过向 authenticator 发送一个 U2F_AUTHENTICATE 消息,其“五部分”如下,检测 C 是否由该 authenticator 使用 U2F 创建:

        control byte

        0x07(仅检测)

        challenge parameter

        32 字节随机数

        application parameter

        appId 的 SHA-256 哈希

        key handle length

        C.id的字节长度

        key handle

        C.id 的值, 即 credential id

      2. authenticator 响应 message:error:test-of-user-presence-required(即成功),则停止该认证器的正常流程,并以平台相关方式提示该认证器不可用。例如,可通过 UI 呈现,或请求 用户同意,收到后视为认证器返回 InvalidStateError。请求用户同意可通过再次发送 U2F_AUTHENTICATE 消息给 authenticator,但 control byte 设为 0x03(强制用户在场并签名),且忽略响应。

    2. 继续正常处理。

客户端扩展输出

返回 true,用于告知Relying Party 扩展已被执行。

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appidExclude;
};
认证器扩展输入

无。

认证器扩展处理

无。

认证器扩展输出

无。

10.1.3. 凭据属性扩展(credProps

客户端注册扩展,允许在注册典礼创建公钥凭据源时,由客户端向请求的WebAuthn Relying Party报告已知的某些凭据属性

目前仅定义了一种凭据属性客户端可发现凭据属性

扩展标识符

credProps

适用操作

注册

客户端扩展输入

布尔值 true,表示 Relying Party 请求该扩展。

partial dictionary AuthenticationExtensionsClientInputs {
    boolean credProps;
};
客户端扩展处理

rk 设置为 调用authenticatorMakeCredential 操作时使用的 requireResidentKey 参数的值。

客户端扩展输出

设置 clientExtensionResults["credProps"]["rk"] 为在调用authenticatorMakeCredential操作时使用的requireResidentKey参数的值。

dictionary CredentialPropertiesOutput {
    boolean rk;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    CredentialPropertiesOutput credProps;
};
rk, 类型为 布尔值

该可选属性,抽象名称为 客户端可发现凭据属性驻留密钥属性, 是一个布尔值,指示由注册典礼结果返回的 PublicKeyCredential 是否为客户端可发现凭据。 若 rktrue,则该凭据为可发现凭据。 若 rkfalse,则凭据为服务端凭据。 若 rk 缺省,则无法确定凭据是可发现凭据还是服务端凭据

注意:某些认证器即使未被客户端平台请求,也会创建可发现凭据。因此,客户端平台可能无法确信地设置 rk 属性为 false 而被迫省略它。Relying Party 应假定,只要支持 credProps 扩展,客户端平台会尽力填充 rk 属性。因此如果缺少 rk,则该凭据很可能是不可发现凭据

认证器扩展输入

无。

认证器扩展处理

无。

认证器扩展输出

无。

10.1.4. 伪随机函数扩展(prf

客户端 注册扩展认证扩展,允许Relying Party评估与某个凭据相关联的伪随机函数(PRF)输出。该扩展提供的 PRF,将任意长度的 BufferSource 映射为 32 字节 BufferSource

举例来说,PRF 输出可用作对称密钥加密用户数据。离开凭据断言(assertion)的情境,这类加密数据无法访问。按照下方规定,在一次断言操作中对两个输入分别评估 PRF,可实现加密密钥周期轮换,方式为断言时选择新随机输入并用新输出重新加密。若输入不可预测,即使攻击者可以通过用户验证,且在有限时间内获得认证器,也无法获得加密密钥除非其知道正确的 PRF 输入。

此扩展基于 [FIDO-CTAP]hmac-secret 扩展实现。它是一个独立的客户端扩展,因为 hmac-secret 要求输入输出加密并只能由 user agent 进行,并区分 WebAuthn 与底层平台其它用途。实现隔离通过将提供的 PRF 输入与上下文字符串哈希来实现,从而避免对任意输入评估 PRF。

hmac-secret 为每个凭据提供两套 PRF:一个用于请求用户验证的情形,一个用于其它所有情形。本扩展仅公开每个凭据 1 套 PRF,基于 hmac-secret 时,必须选用有用户验证时的 PRF。必要时可覆盖 UserVerificationRequirement

注意:即使不支持 [FIDO-CTAP]认证器,只要在 Relying Party 观察下行为一致也可实现本扩展。

扩展标识符

prf

适用操作

注册认证

客户端扩展输入
dictionary AuthenticationExtensionsPRFValues {
    required BufferSource first;
    BufferSource second;
};

dictionary AuthenticationExtensionsPRFInputs {
    AuthenticationExtensionsPRFValues eval;
    record<DOMString, AuthenticationExtensionsPRFValues> evalByCredential;
};

partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsPRFInputs prf;
};
eval, 类型为 AuthenticationExtensionsPRFValues

要评估 PRF 的一个或两个输入。不是所有认证器都在创建凭据时支持评估 PRF,输出可能会或不会给出,如无则需断言才能获得输出。

evalByCredential, 类型为 record<DOMString, AuthenticationExtensionsPRFValues>

base64url 编码凭据ID映射到该凭据需评估的 PRF 输入。只在 allowCredentials 非空的断言环节适用。

客户端扩展处理(注册场景)
  1. 如存在 evalByCredential,则返回 DOMException,name 为“NotSupportedError”。

  2. 在认证器扩展输入中将 hmac-secret 设为 true

  3. 如有 eval,且未来有 FIDO-CTAP 扩展允许创建时评估 PRF,可按如下配置 hmac-secret 输入:

    • salt1SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || eval.first)

    • eval.second 存在,令 salt2SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || eval.second)

  4. enabled 设为认证器扩展输出中 hmac-secret 的值,如无则设 enabledfalse

  5. results 设为解密出的 PRF 结果(如有)。

客户端扩展处理(认证场景)
  1. evalByCredential 非空但 allowCredentials 为空,返回 DOMException,name 为“NotSupportedError”。

  2. evalByCredential 内有键为空字符串,或不是有效的 base64url 编码,或(解码后)与 id 不匹配任何 allowCredentials 元素,则返回 DOMException,name 为“SyntaxError”。

  3. prf 扩展输出初始化为空字典。

  4. ev 为 null,尝试找到适用的 PRF 输入:

    1. 如存在 evalByCredential 且包含与返回的凭据ID base64url 编码匹配的 entry,则令 ev 为该 entry 的值。

    2. ev 为空,且 eval 存在,则 ev 赋值为其值。

  5. ev 非空:

    1. salt1SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || ev.first)

    2. ev.second 存在,salt2 赋值为 SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || ev.second)

    3. 认证器发送 hmac-secret 扩展,传参为 salt1 与(如有)salt2

    4. 解密扩展结果,并将 results 设为 PRF 结果(如有)。

认证器扩展输入/处理/输出

本扩展与认证器通信时使用 [FIDO-CTAP]hmac-secret 扩展,因此不针对 Relying Party 指定任何直接认证器交互要求。

客户端扩展输出
dictionary AuthenticationExtensionsPRFOutputs {
    boolean enabled;
    AuthenticationExtensionsPRFValues results;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsPRFOutputs prf;
};
enabled, 类型为 布尔值

仅当一或两个 PRF 可供已创建凭据使用时为 true。仅在注册时报告,认证时没有该字段。

results, 类型为 AuthenticationExtensionsPRFValues

evalevalByCredential 里给定输入的 PRF 评估结果。注册时可能没有输出,见 eval 的注释。

某些场景下,例如 PRF 输出仅用于本地派生加密密钥且凭据通过网络传输到远程服务器时,应省略本 results 输出,比如参见 § 7 WebAuthn Relying Party 操作。尤其注意,RegistrationResponseJSONAuthenticationResponseJSONPublicKeyCredential.toJSON() 导出时,如有,本结果也会被包含。

10.1.5. 大对象(Large blob)存储扩展(largeBlob

客户端 注册扩展认证扩展允许Relying Party存储与凭据关联的不透明数据。由于认证器只能存储少量数据,且多数Relying Party为可存储任意用户状态的在线服务,这一扩展只在特定场景有用。例如,Relying Party 可能期望签发证书而非运行集中式认证服务。

注意:Relying Party 可以假定写入受空间限制设备时不透明数据会被自动压缩,因此无需自己再压缩。

由于证书系统需要对凭据的公钥签名,而公钥只有在创建后才可获得,本扩展在注册上下文中不支持写入 blob。不过,若Relying Party打算后续使用认证扩展,则应在创建凭据时使用注册扩展

考虑到证书大小相较于认证器典型存储能力较大,user agent 应根据实际情况提示并确认用户,以帮助用户合理分配有限资源并防止滥用。

注意: 为实现互操作,user agent 在使用 [FIDO-CTAP] 在认证器存储 large blob 时,需遵循该规范内关于存储大对象 per-credential blob的相关规定。

注意: 基于 [FIDO-CTAP] 作为跨平台协议的漫游认证器,仅对可发现凭据支持本 largeBlob 扩展,且如 authenticatorSelection.residentKey 未设为 preferredrequired, 可能返回错误。但不使用 [FIDO-CTAP]认证器不必将该扩展限制于可发现凭据

扩展标识符

largeBlob

适用操作

注册认证

客户端扩展输入
partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsLargeBlobInputs largeBlob;
};

enum LargeBlobSupport {
  "required",
  "preferred",
};

dictionary AuthenticationExtensionsLargeBlobInputs {
    DOMString support;
    boolean read;
    BufferSource write;
};
support, 类型为 DOMString

可取LargeBlobSupport枚举值之一的 DOMString。(见§ 2.1.1 枚举作为 DOMString)。仅在注册阶段有效。

read, 类型为 boolean

布尔值,表示Relying Party希望读取与当前凭据关联的已写入 blob。仅在认证阶段有效。

write, 类型为 BufferSource

Relying Party 希望存储到该凭据上的不透明字节串,仅在认证阶段有效。

客户端扩展处理(注册
  1. readwrite 存在:

    1. 返回名为“NotSupportedError”的DOMException

  2. support 存在且为 required

    1. supported 设为 true

      注意: 这是为了适应将来支持大对象的认证器,流程发生于 第12步的扩展处理阶段,如未选中合适认证器本输出被丢弃。

    2. 如出现候选认证器第22步),则在评估 options 以前,若其不能存储大型 blob,则继续下一个候选。

  3. 否则(support 缺失或值为preferred):

    1. 如选择的认证器支持大对象,则 supportedtrue,否则为 false

客户端扩展处理(认证
  1. support 存在:

    1. 返回名为“NotSupportedError”的DOMException

  2. readwrite 同时存在:

    1. 返回名为“NotSupportedError”的DOMException

  3. read 存在且为 true

    1. 初始化客户端扩展输出 largeBlob

    2. 如果任一认证器返回成功([[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)),尝试读取与当前凭据关联的 largeBlob 数据。

    3. 如成功,将 blob 设为结果。

      注意: 如读取不成功, largeBlob 仍会在 AuthenticationExtensionsClientOutputs 里出现,但 blob 字段不会出现。

  4. write 存在:

    1. allowCredentials 非正好一个元素:

      1. 返回名为“NotSupportedError”的DOMException

    2. 断言操作成功,尝试将 write 内容存储于对应认证器上的指定凭据。

    3. 如写入成功,written 设为 true,否则设为 false

客户端扩展输出
partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsLargeBlobOutputs largeBlob;
};

dictionary AuthenticationExtensionsLargeBlobOutputs {
    boolean supported;
    ArrayBuffer blob;
    boolean written;
};
supported, 类型为 boolean

仅当新建凭据支持存储 large blob 时为 true。仅出现在注册结果中。

blob, 类型为 ArrayBuffer

rawId 指定凭据关联的不透明字节串。仅当 readtrue 时有效。

written, 类型为 boolean

指示 write 内容是否已成功存储于该 认证器指定凭据上。

认证器扩展处理

本扩展指示 user agent 把 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。若 transportinternal,则模拟平台附属,否则为跨平台附属

hasResidentKey

若为 true,则该认证器支持客户端可发现凭据

hasUserVerification

若为 true,认证器支持用户验证

isUserConsenting

决定了所有用户同意 授权手势的结果,并由此决定此虚拟认证器上的用户在场测试的结果。若为 true,总是同意用户同意流程;若为 false,则总是不通过。

isUserVerified

决定在虚拟认证器上执行的用户验证结果。若为 true,总是验证通过;若为 false,总是失败。

注意:hasUserVerificationfalse,该属性无效。

extensions

字符串数组,包含扩展标识符,表示虚拟认证器支持的所有扩展。

一个虚拟认证器必须支持其extensions数组内全部认证器扩展。 不得支持数组外的任何认证器扩展

defaultBackupEligibility

决定任何新建公钥凭据源可备份性凭据属性默认值。 该值在该虚拟认证器执行authenticatorMakeCredential操作时,需反映在BE位(认证器数据标志)。

defaultBackupState

决定任何新建公钥凭据源备份状态凭据属性默认值。 该值在虚拟认证器执行authenticatorMakeCredential操作时,需体现在BS位(认证器数据标志)。

11.3. 添加虚拟认证器

添加虚拟认证器 WebDriver 扩展命令用于创建一个软件虚拟认证器。定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator

认证器配置 是一个 JSON 对象,以 parameters 传入远端步骤。其内容为如下 key - value 对:

关键字 值类型 有效值 默认值
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 错误,错误码为 WebDriver error code invalid argument

    注意: parameters 就是认证器配置对象。

  2. authenticator 为新建的虚拟认证器

  3. parameters 的每个可枚举自身属性

    1. key 为属性名。

    2. value获取 parameters 上名为 key 的属性的结果。

    3. key认证器配置中不存在,返回WebDriver 错误,错误码为 WebDriver error code invalid argument

    4. value 非该 key 的有效值,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

    5. 设置 authenticator 的属性 keyvalue

  4. 认证器配置里定义了默认值的每个属性:

    1. keyauthenticator 的属性,则设置该属性为默认值。

  5. 认证器配置中的每个属性:

    1. keyauthenticator 已定义属性,则返回WebDriver 错误,错误码为 WebDriver error code invalid argument

  6. authenticator.extensions 内的每个 extension

    1. extension 并非端节点 WebAuthn WebDriver 实现支持的扩展标识符,则返回 WebDriver 错误,错误码为 WebDriver error code unsupported operation

  7. 生成一个有效的唯一authenticatorId

  8. 设置 authenticatorauthenticatorId 属性为 authenticatorId

  9. authenticator 存入虚拟认证器数据库

  10. authenticatorId 为数据,返回成功

11.4. 移除虚拟认证器

移除虚拟认证器 WebDriver 扩展命令用于移除之前创建的虚拟认证器。 定义如下:

HTTP 方法 URI 模板
DELETE /session/{session id}/webauthn/authenticator/{authenticatorId}

远端步骤如下:

  1. 如果 authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument

  2. 虚拟认证器数据库中移除由 authenticatorId 标识的虚拟认证器

  3. 返回成功

11.5. 添加凭据

添加凭据 WebDriver 扩展命令公钥凭据源注入到已有的虚拟认证器中,定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator/{authenticatorId}/credential

凭据参数 是一个 JSON 对象,作为 parameters 传递给远端步骤。包含以下 key - value 对:

关键字 描述 值类型
credentialId 凭据 ID,使用Base64url 编码string
isResidentCredential 若为 true,创建客户端可发现凭据;为 false 时创建服务端凭据boolean
rpId 凭据适用的Relying Party IDstring
privateKey 非对称密钥包,包含每个凭据的单一私钥,格式参考 [RFC5958],Base64url 编码。 string
userHandle 关联该凭据的userHandle,Base64url 编码。可选属性。 string
signCount 签名计数器的初始值,关联该公钥凭据源number
largeBlob 关联该大型 blob,Base64url 编码。可选属性。 string
backupEligibility 该凭据的可备份性模拟属性。如果未设置,默认为 虚拟认证器defaultBackupEligibility。 执行authenticatorGetAssertion 时,模拟可备份性必须反映在BE 认证器数据标志上。 boolean
backupState 该凭据的备份状态模拟属性。如果未设置,默认为虚拟认证器defaultBackupState。执行 authenticatorGetAssertion 时,需反映在 BS 认证器数据标志上。 boolean
userName 该凭据对应username。未设置时默认为空字符串。 string
userDisplayName 该凭据对应userdisplayName。未设置时默认为空字符串。 string

远端步骤如下:

  1. 如果 parameters 不是一个 JSON 对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

    注意: parameters凭据参数对象。

  2. parameterscredentialId 属性通过Base64url 解码,设为 credentialId

  3. credentialId 解析失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  4. parametersisResidentCredential 属性赋值给 isResidentCredential

  5. isResidentCredential 未定义,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  6. parametersrpId 属性赋值为 rpId

  7. rpId 非有效 RP ID,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  8. parametersprivateKey 属性通过 Base64url 解码,得到 privateKey

  9. privateKey 解码失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  10. privateKey 非有效编码的仅含单一 P-256 曲线 ECDSA 私钥的密钥包(见 [RFC5958]),返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  11. 如果 parametersuserHandle 存在:

    1. userHandle 设为 parametersuserHandle 属性 Base64url 解码。

    2. userHandle 解码失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  12. 否则:

    1. isResidentCredentialtrue,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

    2. userHandlenull

  13. authenticatorId 未匹配到任何虚拟认证器,返回 WebDriver 错误,错误码 WebDriver error code invalid argument

  14. authenticator 为与 authenticatorId 匹配的虚拟认证器

  15. isResidentCredentialtrueauthenticatorhasResidentKeyfalse,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  16. 如果 authenticator 支持 largeBlob 扩展且 parameterslargeBlob 存在:

    1. largeBlob 设为 parameterslargeBlob 属性 Base64url 解码后结果。

    2. largeBlob 解码失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

  17. 否则:

    1. largeBlobnull

  18. parametersbackupEligibility 属性为 backupEligibility

  19. backupEligibility 未定义,设为 authenticatordefaultBackupEligibility

  20. parametersbackupState 属性为 backupState

  21. backupState 未定义,设为 authenticatordefaultBackupState

  22. parametersuserName 属性。

  23. userName 未定义,则设其值为空字符串。

  24. parametersuserDisplayName 属性。

  25. userDisplayName 未定义,则设其值为空字符串。

  26. isResidentCredentialtrue,新建客户端可发现公钥凭据源;否则,新建服务端公钥凭据源。字段如下:

    type

    public-key

    id

    credentialId

    privateKey

    privateKey

    rpId

    rpId

    userHandle

    userHandle

    otherUI

    userNameuserDisplayName 构造。

  27. 设置 credential可备份性 凭据属性backupEligibility

  28. 设置 credential备份状态 凭据属性backupState

  29. credential 关联 签名计数器 counter,起始值为 parameterssignCount 或为 0(当 signCount 为 null)。

  30. largeBlobnull,将其作为该 credential大型 blob

  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 传递给远端步骤,包含以下 key - value 对:

关键字 描述 值类型
backupEligibility 可备份性凭据属性boolean
backupState 备份状态 凭据属性boolean

远端步骤如下:

  1. parameters 非 JSON 对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument

    注意: parameters 即为设置凭据属性参数对象。

  2. authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument

  3. credential 为由 credentialId 匹配的 authenticator 管理的公钥凭据源

  4. credential 为空,返回WebDriver 错误,错误码为 WebDriver error code invalid argument

  5. parametersbackupEligibility 属性值。

  6. backupEligibility 被定义,则将该 可备份性凭据属性设置为该值。

    注意:通常情况下,backupEligibility 属性对公钥凭据源是永久属性。用 设置凭据属性 命令可用于测试和调试目的变更。

  7. parametersbackupState 属性值。

  8. 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 已定义扩展中新增的扩展标识符注册到由 [RFC8809] 建立的 IANA "WebAuthn Extension Identifiers" 注册表。

13. 安全考虑

本规范定义了一个Web API以及一个密码学对等实体认证协议。 Web Authentication API允许 Web 开发者(即“作者”)在其注册认证流程中使用 Web Authentication 协议。 构成 Web Authentication 协议端点的实体是由用户控制的WebAuthn 认证器以及承载Relying PartyWeb 应用的计算环境。 在该模型中,用户代理连同WebAuthn Client构成了认证器Relying Party之间的中介。 另外,认证器可以向Relying Parties就其来源进行attest

当前,本规范并未包含详尽的安全考量。但[FIDOSecRef] 文档提供了适用于本规范的总体安全分析。此外,[FIDOAuthnrSecReqs] 文档套件就认证器的安全特性提供了有用的信息。

下面的小节包含当前 Web Authentication 特有的安全考虑。它们按受众分组;一般性安全考虑作为本节的直接子节,而专门针对认证器客户端Relying Party实现者的安全考虑被分别归入各自的小节。

13.1. Credential ID 未签名

随同credential ID 一起返回的authentication assertion并未被签名。 这并不构成问题,因为如果某个authenticator返回了错误的credential ID, 或者攻击者截获并篡改了credential ID,则唯一会发生的情况是WebAuthn Relying Party无法查到用于验证返回的签名authenticator data(即assertion)的正确credential public key,从而导致交互以错误结束。

13.2. 客户端与认证器的物理接近性

在 WebAuthn 的认证器模型中,通常假定漫游认证器在物理上与客户端彼此靠近并直接通信。 这种安排具有一些重要优势。

客户端与认证器之间的物理接近性是something you have 认证因子的关键优势之一。 例如,如果一个漫游认证器仅能通过 USB 或 Bluetooth 通信,则这些传输的有限范围保证了任何恶意行为者必须在该范围内才能与认证器交互。 对于可以远程调用的authenticator,情况则不一定如此 —— 即使认证器验证了用户在场, 用户也可能被诱导批准远程发起的恶意请求。

客户端与认证器之间的直接通信使得客户端能够强制执行scope限制来约束凭据的使用。 相反,如果客户端与认证器之间的通信由第三方中介,则客户端必须信任该第三方来强制实施 scope 限制并控制对认证器的访问。 如果未能做到这两点,可能导致恶意的Relying Party接收到针对其它Relying Parties有效的authentication assertions, 或导致恶意用户获得针对其他用户的authentication assertions

如果设计的解决方案不要求authenticatorclient在物理上接近, 或客户端与认证器并不直接通信,设计者应当考虑这如何影响对scope限制的强制执行以及认证器作为something you have 认证因子的强度。

13.3. 针对认证器的安全考虑

13.3.1. Attestation 证书层次

建议采用三层的 attestation 证书层次(即 Attestation Root、Attestation Issuing CA、Attestation Certificate)。同时建议针对每个WebAuthn Authenticator 设备系列(即型号)使用单独的发行 CA,以便于将某个认证器型号特定版本的问题隔离处理。

如果 attestation 根证书并非专用于单一的WebAuthn Authenticator设备系列(即 AAGUID), 则建议在 attestation 证书本身中包含 AAGUID,以便可以将其与authenticator data进行比对验证。

13.3.2. Attestation 证书及其 CA 被攻破

当用于签发 attestation 证书的中间 CA 或根 CA 被攻破时,虽然WebAuthn Authenticatorattestation key pairs本身仍然安全,但它们的证书将不再可信。已记录其attestation public keysWebAuthn Authenticator制造商可以从新的中间 CA 或新的根 CA 为这些密钥签发新的attestation certificates。如果根 CA 发生变化,WebAuthn Relying Parties必须相应地更新其受信任的根证书。

如果某个WebAuthn Authenticatorattestation certificate的私钥被泄露,则该 attestation 证书必须由签发 CA 吊销。若泄露源自固件缺陷,认证器制造商可能需要发布固件更新并向已出厂的WebAuthn Authenticators注入新的attestation private keyscertificates。(该过程超出本规范范围。)如果认证器制造商不具备此能力,则受影响的WebAuthn Authenticators的后续 attestation statements 可能无法被Relying Parties信任。

另见在 § 13.4.5 已吊销的 attestation 证书 中针对 Relying Parties 的相关安全考虑。

13.4. 针对Relying Parties的安全考虑

13.4.1. WebAuthn 对 Relying Parties 的安全收益

本规范为WebAuthn Relying Parties提供的主要好处包括:

  1. 可以使用广泛兼容且易用的多因素认证来保护用户和账户。

  2. Relying Party无需向用户分发认证器硬件。相反,每个用户可以独立获取符合规范的authenticator并将同一认证器用于任意数量的Relying PartiesRelying Party可以通过检查从认证器返回的attestation statements来可选地强制认证器的安全属性要求。

  3. Authentication ceremonies中间人攻击具有抗性。关于registration ceremonies,见下文§ 13.4.4 Attestation Limitations

  4. Relying Party可以自动支持多种类型的用户验证(例如 PIN、生物识别以及未来的方法),几乎无需或只需很少修改代码,并允许每个用户通过其选择的authenticator来决定其偏好使用哪种方式。

  5. Relying Party无需存储额外的秘密即可获得上述好处。

如在合规性节中所述,Relying Party必须按照§ 7 WebAuthn Relying Party Operations中所述的行为来获得所有上述安全收益。然而,一个在此略有偏离的显著用例在下文§ 13.4.4 Attestation Limitations中描述。

13.4.2. 嵌入式使用的可见性考虑

在嵌入式环境中简单使用 WebAuthn,例如在 § 5.10 在 iframe 元素中使用 Web 身份验证中描述的 iframe 内, 可能会让用户容易受到 UI 重绘(也称为 "点击劫持")攻击。这是指攻击者将自己的界面覆盖在依赖方期望显示的界面之上,诱使用户在依赖方界面执行非本意的操作。例如,通过这些技术,攻击者可能诱使用户购买商品、转账等。

即使 WebAuthn 专属界面通常由客户端平台处理,不易受到UI 重绘攻击,但对于在嵌入内容中使用 WebAuthn 的依赖方来说,确保自己的界面真正呈现在用户面前依然非常重要。近期出现的一种做法是监听实验性 Intersection Observer v2isVisible 属性。例如,依赖方在嵌入式环境下运行的脚本可以在检测到 isVisible 等于 false 时,主动以弹窗方式打开自身内容,从而规避其内容被遮挡的问题。

13.4.3. 密码学挑战

作为一种密码学协议,Web Authentication 依赖于随机化的挑战以避免重放攻击。因此,PublicKeyCredentialCreationOptions.challengePublicKeyCredentialRequestOptions.challenge 的值必须由在其信任环境中(例如在服务器端)生成的Relying Parties随机生成,且客户端响应中返回的challenge值必须与生成的值匹配。建议以不依赖客户端行为的方式进行,例如 Relying Party 应将挑战暂时存储直到操作完成。容忍不匹配将破坏协议的安全性。

挑战的有效期应与推荐的 WebAuthn 仪式超时范围和默认值的上限相近。

为防止重放攻击,挑战必须包含足够的熵以使其无法被猜测。因此,挑战建议至少为 16 字节长度。

13.4.4. Attestation 的局限性

本节非规范性。

注册新凭据时,若存在,attestation statement 可能使WebAuthn Relying Party能够推断关于某些authenticator属性的保证,例如认证器模型或其如何存储和保护credential private keys。 然而重要的是要注意,仅凭attestation statement本身并不能让Relying Party验证某个attestation object是否由用户预期的认证器生成,而非由中间人攻击者生成。 例如,攻击者可以利用注入到Relying Party脚本中的恶意代码。 因此,Relying Party必须依赖其他手段,例如 TLS 及相关技术,来保护attestation object不受中间人攻击。

在假设registration ceremony已安全完成且认证器对credential private key保密的前提下,随后使用该public key credential进行的authentication ceremonies对中间人攻击具有抗性。

上述讨论适用于所有attestation types。在任何情况下,中间人攻击者都可能替换PublicKeyCredential对象,包括其attestation statement和要注册的credential public key,并随后篡改为同一攻击者所控制且通过同一攻击者的途径传递的未来authentication assertions

这种攻击可能会被检测到;因为Relying Party在注册时登记了攻击者的credential public key而不是用户的密钥,攻击者必须在后续所有针对该Relying Party的认证流程中持续篡改:未被篡改的流程将失败,从而可能揭露该攻击。

Self AttestationNone以外的attestation types可以增加此类攻击的难度,因为Relying Parties可能向用户显示认证器信息(例如型号标识),攻击者因此可能需要使用与用户相同型号的真实authenticator,否则用户可能注意到 Relying Party 报告的认证器型号与其预期不同。

注意: 上述所有变体的中间人攻击相较于对传统密码认证的中间人攻击更难被攻击者实施。

13.4.5. 被吊销的 Attestation 证书

如果在验证attestation certificate时因中间 attestation CA 证书被吊销而失败,且Relying Party的策略要求在这些情形下拒绝注册/认证请求,则建议该Relying Party同时取消注册(或将信任级别标记为等同于“self attestation”)在 CA 被攻破日期之后使用链上至相同中间 CA 的 attestation 证书注册的public key credentials。因此建议Relying Parties在注册期间记住中间 attestation CA 证书,以便在此类证书被吊销后取消注册相关的public key credentials

另见在 § 13.3.2 Attestation Certificate and Attestation Certificate CA Compromise 中针对authenticators的相关安全考虑。

13.4.6. 凭据丢失与密钥可迁移性

本规范并未定义备份credential private keys或在authenticators之间共享它们的协议。 通常预期credential private key永远不会离开创建它的authenticator。 因此,丢失一个authenticator通常意味着丢失与该认证器绑定的所有credentials,这可能会在用户仅向某个Relying Party注册了单个凭据时将其锁定出账户。 Web Authentication API 提供的替代方案不是备份或共享私钥,而是在同一用户下注册多个credentials。例如,用户可以在常用的客户端设备上注册平台凭据,并为备份或在新设备上使用注册一个或多个漫游凭据

Relying Parties应允许并鼓励用户向同一用户账户注册多个credentialsRelying Parties应使用excludeCredentialsuser.id 选项来确保这些不同的credentials绑定到不同的authenticators

13.4.7. 未受保护账户检测

本节非规范性。

此安全考虑适用于在认证流程的第一步使用非空 allowCredentials 参数的Relying Parties。 例如,当使用基于服务端凭据的认证作为第一认证步骤时。

在这种情况下,allowCredentials 参数可能泄露哪些用户账户已注册 WebAuthn 凭据、哪些未注册的信息,这可能表明账户保护的强度差别。 例如,假设攻击者可以仅提供用户名来发起认证流程,如果某些用户账户返回非空的allowCredentials而其他用户返回失败或需要密码挑战, 攻击者即可推断后者账户很可能未要求 WebAuthn assertion,从而将攻击聚焦于这些可能更弱的账户。

该问题与§ 14.6.2 用户名枚举§ 14.6.3 通过 credential IDs 导致的隐私泄露中描述的问题相似,可用类似方法缓解。

13.4.8. 代码注入攻击

任何在某个来源、属于作用域内的依赖方公钥凭证上的恶意代码,都可能导致 WebAuthn 所能提供的任何安全保障全部失效。WebAuthn 客户端只会在安全上下文中暴露 WebAuthn API, 这虽然能缓解最基础的攻击,但依赖方还应结合其他预防措施。

代码注入可能通过多种方式发生; 本节旨在指出一些可能的场景并提出相应的缓解措施, 但并非详尽列举。

13.4.9. 验证凭据的 origin

注册凭据和在验证断言时, Relying Party必须验证客户端数据(client data)中的origin成员。

Relying Party不得接受意外的origin值, 因为这样可能允许恶意网站获取有效的credentials。 尽管 WebAuthn 凭据的scope防止其在注册时指定的 RP ID 之外的域上被使用,但 Relying Party 对 origin 的验证仍作为对可能出现的认证器未能正确执行凭据 scope 强制的额外防护层。另见§ 13.4.8 代码注入攻击中关于潜在恶意子域的讨论。

验证可以通过精确的字符串匹配或 Relying Party 所需的任何其它方法执行。例如:

在验证客户端数据的topOrigin成员时也适用类似考虑。 当topOrigin存在时,Relying Party 必须验证其值是否符合预期。该验证可以通过精确字符串匹配或 Relying Party 所需的任意方法执行。例如:

14. 隐私考虑

[FIDO-Privacy-Principles] 中的隐私原则同样适用于本规范。

本节按受众划分;一般性隐私考虑作为本节的直接子节,而专门针对 authenticatorclientRelying Party 实现者的隐私考虑被分组到各自的小节中。

14.1. 防止去匿名化的措施

本节非规范性。

Web Authentication API 的许多设计要点是出于隐私考虑。本规范关注的主要问题是保护用户的个人身份,即识别某个人或者将不同身份关联为同一人。尽管 Web Authentication API 不使用也不提供任何形式的全局身份,下列可能被关联的标识符仍会被使用:

上述部分信息必须与 Relying Party 共享。下列小节描述了防止恶意 Relying Parties 利用这些信息识别用户个人身份所采取的措施。

14.2. 匿名、作用域限定、不可关联的 Public Key Credentials

本节非规范性。

虽然 Credential IDscredential public keys 必须与 WebAuthn Relying Party 共享以启用强认证,但它们被设计为最小化可识别性且不在不同 Relying Parties 间共享。

此外,client-side discoverable public key credential source 可选地包含由 Relying Party 指定的 user handle。该 credential 随后可用于同时标识并 authenticate 用户。这意味着一个注重隐私的 Relying Party 可以允许创建用户账户而无需传统用户名,从而进一步改善不同 Relying Parties 间的不可关联性。

14.3. Authenticator 本地的 生物识别

Biometric authenticatorsauthenticator 内部执行 biometric recognition —— 但对于 platform authenticators 来说,生物识别数据也可能(视实现而定)对 client 可见。生物识别数据不会被泄露给 WebAuthn Relying Party;它仅在本地用于执行授权创建或注册,或用于使用 public key credentialuser verification。因此,恶意的 Relying Party 无法通过生物识别数据发现用户的个人身份,且当 Relying Party 出现安全漏洞时,也无法暴露生物识别数据以供攻击者在其他 Relying Parties 上伪造登录。

Relying Party 需要 biometric recognition,该识别由执行 user verificationbiometric authenticator 在本地执行,然后通过在签名的 assertion 响应中设置 UV flag 来表明结果,而不是将生物识别数据本身泄露给 Relying Party

14.4. 针对 authenticators 的隐私考虑

14.4.1. Attestation 隐私

Attestation certificatesattestation key pairs 可能被用来追踪用户或将同一用户的不同在线身份关联起来。可以通过多种方式减缓这种风险,包括:

14.4.2. 存储在认证器中的个人可识别信息的隐私

认证器可以向客户端提供本规范以外的附加信息,例如, 使客户端能够提供丰富的 UI,用户可以选择用于凭证进行认证仪式。如果认证器选择这么做,应避免在未成功执行用户验证时暴露任何个人可识别信息。如果认证器支持多个用户同时注册的用户验证,则应避免暴露当前已验证用户之外的人员信息。因此,不支持用户验证认证器不应存储任何个人可识别信息。

在此讨论中,作为 id 成员传递的用户句柄(user handle)PublicKeyCredentialUserEntity)不被视为个人可识别信息;详见§ 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 能力,可能带来指纹跟踪风险。客户端实现可能需要根据客户端策略和/或用户同意来限制能力信息的披露。

14.6. 依赖方的隐私注意事项

14.6.1. 用户句柄内容

由于用户句柄§ 14.4.2 存储在认证器中的个人可识别信息的隐私中不被视为个人可识别信息, 并且认证器可以在未执行用户验证的情况下暴露用户句柄, 因此依赖方不得在用户句柄中包含任何个人可识别信息,比如邮箱或用户名。如果散列的是个人可识别信息,也不允许使用(除非 hash 函数用仅对依赖方私有的做加盐散列),因为散列并不能防止针对容易猜测的输入值进行探测。建议用户句柄使用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. 通过 credential IDs 导致的隐私泄露

本节非规范性。

本隐私注意事项适用于支持非 allowCredentials 参数作为首次认证步骤的依赖方, 例如使用服务器端凭证作为第一个认证步骤时。

在这种情况下,allowCredentials 参数有泄露个人可识别信息的风险, 因为它会将用户的凭证ID暴露给一个未认证的调用者。凭证ID旨在不能在不同依赖方间被关联, 但凭证ID的长度也许能透露是由哪类认证器所创建。 很可能用户会在多个依赖方使用相同的用户名和一组认证器, 因此allowCredentials凭证ID的数量及其长度 可能成为对用户进行去匿名化的全局相关标识。 知晓用户的凭证ID还使得攻击者即使只有片刻的物理接触用户的某个认证器,也能用来佐证其对用户身份的猜测。

为防止此类信息泄漏,依赖方可以例如:

如果上述防护措施不可用, 即只通过用户名就需要暴露allowCredentials, 那么依赖方可以采用在§ 14.6.2 用户名枚举中讨论的方法,通过返回虚构的凭证ID来缓解隐私泄漏。

通知某个凭证ID无法识别时, WebAuthn 依赖方应使用signalUnknownCredential(options) 方法,而不是signalAllAcceptedCredentials(options) 方法,以避免向未认证的调用者暴露凭证ID

15. 无障碍可及性注意事项

支持用户验证认证器,无论是漫游型还是平台型,都应当为用户提供多种用户验证方式。例如,既支持指纹识别也支持PIN码输入。这可使当选择的验证方式因某些原因不可用时,能够切换到其他用户验证方式。注意,在漫游认证器的情况下,认证器与平台可能协作,例如提供PIN码输入方式 [FIDO-CTAP]

服务方注册时,应给用户提供提示或操作入口,以帮助其将来能正确完成授权动作。比如可以为认证器命名、为设备选择一张关联图片,或填写自由文本的自助说明(如自我提醒)。

依赖定时的认证流程,如注册流程(见 timeout) 或认证流程(见 timeout), 应遵循[WCAG21]2.2条:充裕时间指引。如果客户端平台 判断服务方提供的超时时间未适当地符合上述[WCAG21]指南, 那么客户端平台可以相应地调整这个超时。

WebAuthn认证流程超时的建议范围及默认值如下:

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。 除非特别说明,示例包含无声明情况。

所有随机值均用HKDF-SHA-256 [RFC5869],以CDDL中标记为 'WebAuthn test vectors' 的基础输入密钥材料确定生成, 也可用h'576562417574686e207465737420766563746f7273'表示。 ECDSA签名使用确定性nonce [RFC6979]。 示例中的RSA密钥基于p≥1024的两个最小梅森素数2p - 1。

注意:

注: 实现CTAP2的认证器返回的声明对象使用的密钥与本规范不同。 这些示例反映了WebAuthn服务方所期望的声明对象格式, 所以CTAP2生成的声明对象 需要对key做转换才能与这些示例逐位相同。

16.1. 声明信任根证书

所有包含声明的示例都使用下方X.509 DER格式的声明信任根证书attestation_ca_cert,参见[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.1.1. 无声明的 ES256 凭据

注册:

challenge = h'00c30fb78531c464d2b6771dab8d7b603c01162f2fa486bea70f283ae556e130'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256', L=32)

credential_private_key = h'6e68e7a58484a3264f66b77f5d6dc5bc36a47085b615c9727ab334e8c369c2ee'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256', L=32)
client_data_gen_flags = h'f9'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256', L=1)
; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含
extra_client_data = h'06441e0e375c4c1ad70620302532c4e5'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256', L=16)
aaguid = h'8446ccb9ab1db374750b2367ff6f3a1f'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256', L=16)
credential_id = h'f91f391db4c9b2fde0ea70189cba3fb63f579ba6122b33ad94ff3ec330084be4'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256', L=32)
; auth_data_UV_BE_BS 决定认证器数据标志中的 UV, BE 和 BS 位,但仅当 BE 被设置时才设置 BS
auth_data_UV_BE_BS = h'ba'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256', L=1)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22414d4d507434557878475453746e63647134313759447742466938767049612d7077386f4f755657345441222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20426b5165446a646354427258426941774a544c4535513d3d227d'
attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b559000000008446ccb9ab1db374750b2367ff6f3a1f0020f91f391db4c9b2fde0ea70189cba3fb63f579ba6122b33ad94ff3ec330084be4a5010203262001215820afefa16f97ca9b2d23eb86ccb64098d20db90856062eb249c33a9b672f26df61225820930a56b87a2fca66334b03458abf879717c12cc68ed73290af2e2664796b9220'

认证:

challenge = h'39c0e7521417ba54d43e8dc95174f423dee9bf3cd804ff6d65c857c9abf4d408'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256', L=32)

client_data_gen_flags = h'4a'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256', L=1)
; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含
; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但仅当注册中设置了 BE 时,BS 才会被设置
auth_data_UV_BS = h'38'   ; 由以下方式生成: 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.1.2. 自声明的 ES256 凭据

注册:

challenge = h'7869c2b772d4b58eba9378cf8f29e26cf935aa77df0da89fa99c0bdc0a76f7e5'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed-self.ES256', L=32)

credential_private_key = h'b4bbfa5d68e1693b6ef5a19a0e60ef7ee2cbcac81f7fec7006ac3a21e0c5116a'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed-self.ES256', L=32)
client_data_gen_flags = h'db'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed-self.ES256', L=1)
; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含
extra_client_data = h'53d8535ef284d944643276ffd3160756'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed-self.ES256', L=16)
aaguid = h'df850e09db6afbdfab51697791506cfc'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed-self.ES256', L=16)
credential_id = h'455ef34e2043a87db3d4afeb39bbcb6cc32df9347c789a865ecdca129cbef58c'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed-self.ES256', L=32)
; auth_data_UV_BE_BS 决定认证器数据标志中的 UV, BE 和 BS 位,但仅当 BE 被设置时才设置 BS
auth_data_UV_BE_BS = h'fd'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed-self.ES256', L=1)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2265476e4374334c55745936366b336a506a796e6962506b31716e666644616966715a774c33417032392d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205539685458764b453255526b4d6e625f3078594856673d3d227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a263616c67266373696758483046022100ae045923ded832b844cae4d5fc864277c0dc114ad713e271af0f0d371bd3ac540221009077a088ed51a673951ad3ba2673d5029bab65b64f4ea67b234321f86fcfac5d68617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000df850e09db6afbdfab51697791506cfc0020455ef34e2043a87db3d4afeb39bbcb6cc32df9347c789a865ecdca129cbef58ca5010203262001215820eb151c8176b225cc651559fecf07af450fd85802046656b34c18f6cf193843c5225820927b8aa427a2be1b8834d233a2d34f61f13bfd44119c325d5896e183fee484f2'

认证:

challenge = h'4478a10b1352348dd160c1353b0d469b5db19eb91c27f7dfa6fed39fe26af20b'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed-self.ES256', L=32)

client_data_gen_flags = h'1f'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed-self.ES256', L=1)
; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含
extra_client_data = h'8136f9debcfa121496a265c6ce2982d5'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed-self.ES256', L=16)
; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但仅当注册中设置了 BE 时,BS 才会被设置
auth_data_UV_BS = h'a1'   ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed-self.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a225248696843784e534e493352594d45314f7731476d3132786e726b634a5f6666707637546e2d4a71386773222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206754623533727a36456853576f6d58477a696d4331513d3d227d'
signature = h'3044022076691be76a8618976d9803c4cdc9b97d34a7af37e3bdc894a2bf54f040ffae850220448033a015296ffb09a762efd0d719a55346941e17e91ebf64c60d439d0b9744'

16.1.3. ES256 凭据,clientDataJSON 中 "crossOrigin" 为 true

注册:

challenge = h'3be5aacd03537142472340ab5969f240f1d87716e20b6807ac230655fa4b3b49'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.crossOrigin', L=32) 得出

credential_private_key = h'96c940e769bd9f1237c119f144fa61a4d56af0b3289685ae2bef7fb89620623d'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.crossOrigin', L=32) 得出
client_data_gen_flags = h'71'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.crossOrigin', L=1) 得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
extra_client_data = h'cd9aae12d0d1f435aaa56e6d0564c5ba'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.crossOrigin', L=16) 得出
aaguid = h'883f4f6014f19c09d87aa38123be48d0'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.crossOrigin', L=16) 得出
credential_id = h'6e1050c0d2ca2f07c755cb2c66a74c64fa43065c18f938354d9915db2bd5ce57'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.crossOrigin', L=32) 得出
; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,仅当 BE 为 1 时才设置 BS
auth_data_UV_BE_BS = h'27'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.crossOrigin', L=1) 得出

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a224f2d57717a514e5463554a484930437257576e7951504859647862694332674872434d475666704c4f306b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a207a5a71754574445239445771705735744257544675673d3d227d'
attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54500000000883f4f6014f19c09d87aa38123be48d000206e1050c0d2ca2f07c755cb2c66a74c64fa43065c18f938354d9915db2bd5ce57a501020326200121582022200a473f90b11078851550d03b4e44a2279f8c4eca27b3153dedfe03e4e97d225820cbd0be95e746ad6f5a8191be11756e4c0420e72f65b466d39bc56b8b123a9c6e'

认证:

challenge = h'876aa517ba83fdee65fcffdbca4c84eeae5d54f8041a1fc85c991e5bbb273137'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.crossOrigin', L=32) 得出

client_data_gen_flags = h'57'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.crossOrigin', L=1) 得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
extra_client_data = h'f76a5c4d50f401bcbeab876d9a3e9e7e'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256.crossOrigin', L=16) 得出
; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,仅当注册时 BE 为 1 时才设置 BS
auth_data_UV_BS = h'0c'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='none.ES256.crossOrigin', L=1) 得出

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50500000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a226832716c463771445f65356c5f505f62796b7945377135645650674547685f49584a6b655737736e4d5463222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2039327063545644304162792d713464746d6a366566673d3d227d'
signature = h'304402204396b14b216ed47920dc359e46aa0a1d4a912cf9d50f25a58ec236a11db4cf5e02204fdb59ff01656c4b0868e415436a464b0e30e94b02c719b995afaba9c917146b'

16.1.4. ES256 凭据,clientDataJSON 中含 "topOrigin"

注册:

challenge = h'4e1f4c6198699e33c14f192153f49d7e0e8e3577d5ac416c5f3adc92a41f27e5'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.topOrigin', L=32) 得出

credential_private_key = h'a2d6de40ab974b80d8c1ef78c6d4300097754f7e016afe7f8ea0ad9798b0d420'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.topOrigin', L=32) 得出
client_data_gen_flags = h'54'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.topOrigin', L=1) 得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
aaguid = h'97586fd09799a76401c200455099ef2a'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.topOrigin', L=16) 得出
credential_id = h'b8ad59b996047ab18e2ceb57206c362da57458793481f4a8ebf101c7ca7cc0f1'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.topOrigin', L=32) 得出
; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,仅当 BE 为 1 时才设置 BS
auth_data_UV_BE_BS = h'a0'   ; 由 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'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.topOrigin', L=32) 得出

client_data_gen_flags = h'77'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.topOrigin', L=1) 得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
extra_client_data = h'52216824c5514070c0156162e2fc54a5'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.topOrigin', L=16) 得出
; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,仅当注册时 BE 为 1 时才设置 BS
auth_data_UV_BS = h'9f'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256.topOrigin', L=1) 得出

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50500000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22315570636a4b53324b6f34377379486a7372787a68572d466f51465132796b3572426c584f6573656f4759222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22746f704f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205569466f4a4d565251484441465746693476785570513d3d227d'
signature = h'304402206a19613fa8cfacfc8027272aec5dae3555fea9f983d841581466678d71e6761a02207a9785ba22e48eb18525850357d9dc70795aaad2e6021159c4a4a183146eaa71'

16.1.5. ES256 凭据,超长的 credential ID

注册:

challenge = h'1113c7265ccf5e65124282fa1d7819a7a14cb8539aa4cdbec7487e5f35d8ec6c'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.long-credential-id', L=32) 得出

credential_private_key = h'6fd2149bb5f1597fe549b138794bde61893b2dc32ca316de65f04808dac211dc'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.long-credential-id', L=32) 得出
client_data_gen_flags = h'90'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.long-credential-id', L=1) 得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
aaguid = h'8f3360c2cd1b0ac14ffe0795c5d2638e'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.long-credential-id', L=16) 得出
credential_id = h'3a761a4e1674ad6c4305869435c0eee9c286172c229bb91b48b4ada140c0863417031305cce5b4a27a88d7fe728a5f5a627de771b4b40e77f187980c124f9fe832d7136010436a056cce716680587d23187cf1fc2c62ae86fc3e508ee9617ffc74fbc10488ec16ec5e9096328669a898709b655e549738c666c1ae6281dc3b5f733c251d3eefb76ee70a3805ca91bcc18e49c8dc7f63ebcb486ba8c3d6ab52b88ff72c6a5bb47c32f3ee8683a3ddc8abf60870448ec8a21b5bdcb183c7dead870255575a6df96eb1b6a2a1019780cba9e4887b17ff1164bbbcc10eb0d86ed75984cd3fa3419103024507dfd9ce8f92c56af7914cb0bb50b87ba82a312bb7dcd93028dbdcd6adb266979667158335171e3682d37755701edbf9d872846a291d49e57ef09da1ec637f5052ed2aa7407f7e61827468e94b461844f4c67be5fa9c6055a566f8fdfc29d4bf78a9ff275f552cc68ba543fa3962eea36fd1ea8453764577d021d0a181efc1f6100ab2e4110039e21ee16970bda7432b6134492155afc126295b3a2eccd12c66a68e340969e995e3e8c9c476e395cfc21203414110779474f1c9797406637dbe414f132519d3bf0ce4f01734ef0e1a12c3ad604ff15d766b1624db6a5a7ccbff7bc35c9908df94aba277e0af48f04ff3d16381c47e5a37ed3988a67a3b1ecaa926336b33391fff04128f869991c9fabd905b6fe3ceef5f8b630ec1c5d2636d5b1961ad5ca5004170f6f5e482792aad989b0287fe91e5c479403397152f1fa56aa79b156eb47e6c8ea3eb175c34cfb38ad8e772874639b1023d4d01395c94e55831671cc022aa6fa1e02a02c2e4abc776f6960e51f83b71a8c0f207b6a347573977812c9aa5480b0011aa739bd4b76c18c000cc4757cceccb920f007c40c00e37e5ab21476cd9f6054a8fffb55a108f5c706e2cea2049d81fd321ff47d2a5761b0800955ab1d4f4889f55a84e2601c684f17a4ade7453ea49591d0b59c8d9a765052f62219cf6ef4a5dd9539f0617d6ebbebce7c000455475d18449e25c49ef9a1e3efe18c09082ebe2058d7c347defaa92f0664553b805c7d76bbfce5f330aca220ac90a789380fc479ea0d8793205813cca590a912f699ad52f991a1bc0a503c3ec4b2a696719e3c26591a87127f7305cc7e72f4c8e39355ebb06a5b1042990f38710ee7aa612ee4374bb82e878585a70a96c2a6b47f101a4ff154be4fd76a3167577a5cc54d9167c154c69ac35485e44cc898b719e1be3cc9c0fb5624b8f8a0dae10947a41bf848b6c1bb33d1006ec077d7e286e3f2a7b4843716390119449fe2721e81a5ed2333d331c7120765da58fadae73c19d9a8c4509cf8ac1e9d98b799a5274509069739b5823f3fb496663820033426988eefca53e580e0f9e0dfe0992fc2e53a97e053639f98577058f995bdbd41cefdb'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.long-credential-id', L=1023) 得出
; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,仅当 BE 为 1 时才设置 BS
auth_data_UV_BE_BS = h'69'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.long-credential-id', L=1) 得出

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22455250484a6c7a50586d5553516f4c364858675a7036464d75464f61704d322d7830682d587a5859374777222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d74646e6f6e656761747453746d74a0686175746844617461590483bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b549000000008f3360c2cd1b0ac14ffe0795c5d2638e03ff3a761a4e1674ad6c4305869435c0eee9c286172c229bb91b48b4ada140c0863417031305cce5b4a27a88d7fe728a5f5a627de771b4b40e77f187980c124f9fe832d7136010436a056cce716680587d23187cf1fc2c62ae86fc3e508ee9617ffc74fbc10488ec16ec5e9096328669a898709b655e549738c666c1ae6281dc3b5f733c251d3eefb76ee70a3805ca91bcc18e49c8dc7f63ebcb486ba8c3d6ab52b88ff72c6a5bb47c32f3ee8683a3ddc8abf60870448ec8a21b5bdcb183c7dead870255575a6df96eb1b6a2a1019780cba9e4887b17ff1164bbbcc10eb0d86ed75984cd3fa3419103024507dfd9ce8f92c56af7914cb0bb50b87ba82a312bb7dcd93028dbdcd6adb266979667158335171e3682d37755701edbf9d872846a291d49e57ef09da1ec637f5052ed2aa7407f7e61827468e94b461844f4c67be5fa9c6055a566f8fdfc29d4bf78a9ff275f552cc68ba543fa3962eea36fd1ea8453764577d021d0a181efc1f6100ab2e4110039e21ee16970bda7432b6134492155afc126295b3a2eccd12c66a68e340969e995e3e8c9c476e395cfc21203414110779474f1c9797406637dbe414f132519d3bf0ce4f01734ef0e1a12c3ad604ff15d766b1624db6a5a7ccbff7bc35c9908df94aba277e0af48f04ff3d16381c47e5a37ed3988a67a3b1ecaa926336b33391fff04128f869991c9fabd905b6fe3ceef5f8b630ec1c5d2636d5b1961ad5ca5004170f6f5e482792aad989b0287fe91e5c479403397152f1fa56aa79b156eb47e6c8ea3eb175c34cfb38ad8e772874639b1023d4d01395c94e55831671cc022aa6fa1e02a02c2e4abc776f6960e51f83b71a8c0f207b6a347573977812c9aa5480b0011aa739bd4b76c18c000cc4757cceccb920f007c40c00e37e5ab21476cd9f6054a8fffb55a108f5c706e2cea2049d81fd321ff47d2a5761b0800955ab1d4f4889f55a84e2601c684f17a4ade7453ea49591d0b59c8d9a765052f62219cf6ef4a5dd9539f0617d6ebbebce7c000455475d18449e25c49ef9a1e3efe18c09082ebe2058d7c347defaa92f0664553b805c7d76bbfce5f330aca220ac90a789380fc479ea0d8793205813cca590a912f699ad52f991a1bc0a503c3ec4b2a696719e3c26591a87127f7305cc7e72f4c8e39355ebb06a5b1042990f38710ee7aa612ee4374bb82e878585a70a96c2a6b47f101a4ff154be4fd76a3167577a5cc54d9167c154c69ac35485e44cc898b719e1be3cc9c0fb5624b8f8a0dae10947a41bf848b6c1bb33d1006ec077d7e286e3f2a7b4843716390119449fe2721e81a5ed2333d331c7120765da58fadae73c19d9a8c4509cf8ac1e9d98b799a5274509069739b5823f3fb496663820033426988eefca53e580e0f9e0dfe0992fc2e53a97e053639f98577058f995bdbd41cefdba50102032620012158203b8176b7504489cc593046d7988abb7905a742de6ac2cdc748a873c663e90cb12258201436d5edc9a75f23999eef9d5950a5c2455514ee1014084720f841a06b828a11'

认证:

challenge = h'ef1deba56dce48f674a447ccf63b9599258ce87648e5c396f2ef0ca1da460e3b'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.long-credential-id', L=32) 得出

client_data_gen_flags = h'80'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.long-credential-id', L=1) 得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,仅当注册时 BE 为 1 时才设置 BS
auth_data_UV_BS = h'e5'   ; 由 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.1.6. ES256 凭据的 Packed 类型 Attestation

注册:

challenge = h'c1184a5fddf8045e13dc47f54b61f5a656b666b59018f16d870e9256e9952012'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES256', L=32) 推导得出

credential_private_key = h'36ed7bea2357cefa8c4ec7e134f3312d2e6ca3058519d0bcb4c1424272010432'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES256', L=32) 推导得出
client_data_gen_flags = h'8d'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES256', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
extra_client_data = h'f5af1b3588ca0a05ab05753e7c29756a'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES256', L=16) 推导得出
aaguid = h'876ca4f52071c3e9b25509ef2cdf7ed6'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES256', L=16) 推导得出
credential_id = h'c9a6f5b3462d02873fea0c56862234f99f081728084e511bb7760201a89054a5'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES256', L=32) 推导得出
; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位
auth_data_UV_BE_BS = h'4f'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES256', L=1) 推导得出
attestation_private_key = h'ec2804b222552b4b277d1f58f8c4343c0b0b0db5474eb55365c89d66a2bc96be'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES256', L=32) 推导得出
attestation_cert_serial_number = h'88c220f83c8ef1feafe94deae45faad0'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES256', L=16) 推导得出

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a227752684b58393334424634543345663153324831706c61325a725751475046746877365356756d56494249222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20396138624e596a4b436757724258552d66436c3161673d3d227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022025fcee945801b94e63d7c029e6f761654cf02e7100d5364a3b90e03daa6276fc022100eabcdf4ce19feb0980e829c3b6137079b18e42f43ce5c3c573b83368794f354c637835638159022530820221308201c8a00302010202110088c220f83c8ef1feafe94deae45faad0300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004a91ba4389409dd38a428141940ca8feb1ac0d7b4350558104a3777a49322f3798440f378b3398ab2d3bb7bf91322c92eb23556f59ad0a836fec4c7663b0e4dc3a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414a589ba72d060842ab11f74fb246bdedab16f9b9b301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d040302034700304402201726b9d85ecd8a5ed51163722ca3a20886fd9b242a0aa0453d442116075defd502207ef471e530ac87961a88a7f0d0c17b091ffc6b9238d30f79f635b417be5910e768617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d00000000876ca4f52071c3e9b25509ef2cdf7ed60020c9a6f5b3462d02873fea0c56862234f99f081728084e511bb7760201a89054a5a50102032620012158201cf27f25da591208a4239c2e324f104f585525479a29edeedd830f48e77aeae522582059e4b7da6c0106e206ce390c93ab98a15a5ec3887e57f0cc2bece803b920c423'

认证:

challenge = h'b1106fa46a57bef1781511c0557dc898a03413d5f0f17d244630c194c7e1adb5'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES256', L=32) 推导得出

client_data_gen_flags = h'75'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES256', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
extra_client_data = h'019330c8cc486c3f3eba0b85369eabf1'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.ES256', L=16) 推导得出
; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位
auth_data_UV_BS = h'46'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0c', info='packed.ES256', L=1) 推导得出

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273524276704770587676463446524841565833496d4b4130453958773858306b526a44426c4d6668726255222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20415a4d77794d78496244382d756775464e70367238513d3d227d'
signature = h'30460221009d8d54895393894d37b9fa7bdfbcff05403de3cf0d6443ffb394fa239f101579022100c8871288f19c6c48a3b64c09d39868c12d16ed80ea4c5d8890288975c0272f50'

16.1.7. ES384 凭据的 Packed 类型 Attestation

注册:

challenge = h'567b030b3e186bc1d169dd45b79f9e0d86f1fd63474da3eade5bdb8db379a0c3'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES384', L=32) 推导得出

credential_private_key = h'271e37d309c558c0f35222b37abba7500377d68e179e4c74b0cb558551b2e5276b47b90a317ca8ebbe1a12c93c2d5dd9'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES384', L=48) 推导得出
client_data_gen_flags = h'32'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES384', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
aaguid = h'e950dcda3bdae1d087cda380a897848b'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES384', L=16) 推导得出
credential_id = h'953ae2dd9f28b1a1d5802c83e1f65833bb9769a08de82d812bc27c13fc6f06a9'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES384', L=32) 推导得出
; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位
auth_data_UV_BE_BS = h'db'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES384', L=1) 推导得出
attestation_private_key = h'8d979fbb6e49c4eeb5925a2bca0fcdb023d3fb90bcadce8391da9da4ed2aee9a'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES384', L=32) 推导得出
attestation_cert_serial_number = h'3d0a5588bb87ebb1d4cee4a1807c1b7c'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES384', L=16) 推导得出

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22566e7344437a3459613848526164314674352d65445962785f574e4854615071336c76626a624e356f4d4d222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022100c56ecc970b7843833e0f461fde26233f61eb395161d481558c08b9c6ed61675b022029f5e05033705cd0f9b0a07e149468ec308a4f84906409efdceb1da20a7518d6637835638159022530820221308201c7a00302010202103d0a5588bb87ebb1d4cee4a1807c1b7c300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000417e5cc91d676d370e36aa7de40c25aacb45a3845f13d2932088ece2270b9b431241c219c22d0c256c9438ade00f2c05e62f8ef906b9b997ae9f3c460c2db66f5a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414c7c8dd95382a2230e4c0dd3664338fa908169a9c301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020348003045022054068cc9ae038937b7c468c307edb9c6927ffdeb6a20070c483eb40330f99f10022100cf41953919c3c04693d6b1f42a613753f204e70e85fc6e9b17036170b83596e068617574684461746158c5bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55900000000e950dcda3bdae1d087cda380a897848b0020953ae2dd9f28b1a1d5802c83e1f65833bb9769a08de82d812bc27c13fc6f06a9a5010203382220022158304866bd8b01da789e9eb806e5eab05ae5a638542296ab057a2f1bbce9b58f8a08b9171390b58a37ac7fffc2c5f45857da2258302a0b024c7f4b72072a1f96bd30a7261aae9571dd39870eb29e55c0941c6b08e89629a1ea1216aa64ce57c2807bf3901a'

认证:

challenge = h'ff41c3d25dbd8966fb61e28ef5e47041e137ed268520412d76202ba0ad2d1453'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES384', L=32) 推导得出

client_data_gen_flags = h'0c'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES384', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位
auth_data_UV_BS = h'af'   ; 由 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.1.8. ES512 凭据的 Packed 类型 Attestation

注册:

challenge = h'4ee220cd92b07e11451cb4c201c5755bd879848e492a9b12d79135c62764dc2fd28ead4808cafe5ad1de8fa9e08d4a8eeafea4dfb333877b02bc503f475d3b0c1394a7683baaf4f2477829f7b8cf750948985558748c073068396fcfdcd3f245bf2038e6bb38d7532768aad13be8c118f727722e7426139041e9caca503884c5'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES512', L=128) 推导得出

credential_private_key = h'f11120594f6a4944ac3ba59adbbc5b85016895b649f4cc949a610f4b48be47b318850bacb105f747647bba8852b6b8e52a0b3679f1bbbdfe18c99409bcb644fa45'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES512', L=65) 推导得出
client_data_gen_flags = h'6d'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES512', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
extra_client_data = h'a37a958ce2f6b535a6e06c64cc8fd082'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES512', L=16) 推导得出
aaguid = h'39d8ce6a3cf61025775083a738e5c254'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES512', L=16) 推导得出
credential_id = h'd17d5af7e3f37c56622a67c8462c9e1c6336dfccb8b61d359dc47378dba58ce4'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES512', L=32) 推导得出
; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位
auth_data_UV_BE_BS = h'cf'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES512', L=1) 推导得出
attestation_private_key = h'ffbc89d5f75994f52dc5e7538ee269402d26995d40c16fb713473e34fca98be4'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES512', L=32) 推导得出
attestation_cert_serial_number = h'8a128b7ebe52b993835779e6d9b81355'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES512', L=16) 推导得出

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22547549677a5a4b7766684646484c544341635631573968356849354a4b707353313545317869646b33435f536a713149434d722d577448656a366e676a55714f3676366b33374d7a683373437646415f5231303744424f5570326737717654795233677039376a5064516c496d465659644977484d47673562385f63305f4a46767941343572733431314d6e614b72524f2d6a424750636e636935304a684f5151656e4b796c4134684d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206f3371566a4f4c327454576d3447786b7a495f5167673d3d227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758483046022100c48fcbd826bbc79680802026688d41ab6da8c3a1d22ab6cecf36c8d7695d22500221008767dfe591277e973078d5692c8c35cf9d579792822e7145c96a0ac4515df5b0637835638159022730820223308201c8a0030201020211008a128b7ebe52b993835779e6d9b81355300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004940b68885291536e2f7c60c05acfb252e7eebcf4304425dd93ab7b1962f20492bf18dc0f12862599e81fb764ac92151f9a78fcbb35d7a26c8c52949b18133c06a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604143ffad863abcd3dc5717b8a252189f41af97e7f31301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100832c8b64c4f0188bd32e1bec63e13301cdc03165d3ef840d1f3dabb9a5719f83022100add57a9d5bedec98f29222dfc97ea795d055ee13a02a153d02be9ce00aedeb9168617574684461746158e9bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d0000000039d8ce6a3cf61025775083a738e5c2540020d17d5af7e3f37c56622a67c8462c9e1c6336dfccb8b61d359dc47378dba58ce4a5010203382320032158420083240a2c3ad21a3dc0a6daa3d8bc05a46d7cd9825ba010ae2a22686c2d6d663d7d5f678987fb1e767542e63dc197ae915e25f8ee284651af29066910a2cc083f50225842017337df47ab5cce5d716ef8caffa97a3012689b1f326ea6c43a1ba9596c72f71f0122390143552b42be772b4c35ffb961220c743b486a601ea4cb6d5412f5b078d3'

认证:

challenge = h'08d3190c6dcb3d4f0cb659a0333bf5ea124ddf36a0cd33d5204b0d7a22a8cc26f2e4f169d200285c77b3fb22e0f1c7f49a87d4be2d25e92d797808ddaaa9b5715efd3a6ada9339d3052a687dbc5d2f8c871b0451e0691f57ad138541b7b72e7aa8933729ec1c664bf2e4dedae1616d08ecefa80a2a53b103663ce5a881048829'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES512', L=128) 推导得出

client_data_gen_flags = h'ac'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES512', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位
auth_data_UV_BS = h'52'   ; 由 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.1.9. RS256 凭据的 Packed 类型 Attestation

注册:

challenge = h'bea8f0770009bd57f2c0df6fea9f743a27e4b61bbe923c862c7aad7a9fc8e4a6'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.RS256', L=32) 推导得出

; 两个最小的梅森素数 2^p - 1,p >= 1024
private_key_p = 2^1279 - 1 = h'7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
private_key_q = 2^2203 - 1 = h'07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
client_data_gen_flags = h'1c'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.RS256', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
aaguid = h'428f8878298b9862a36ad8c7527bfef2'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.RS256', L=16) 推导得出
credential_id = h'992a18acc83f67533600c1138a4b4c4bd236de13629cf025ed17cb00b00b74df'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.RS256', L=32) 推导得出
; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位
auth_data_UV_BE_BS = h'7e'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.RS256', L=1) 推导得出
attestation_private_key = h'08a1322d5aa5b5b40cd67c2cc30b038e7921d7888c84c342d50d79f0c5fc3464'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.RS256', L=32) 推导得出
attestation_cert_serial_number = h'1f6fb7a5ece81b45896b983a995da5f3'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.RS256', L=16) 推导得出

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2276716a776477414a76566679774e3976367039304f69666b7468752d6b6a79474c48717465705f49354b59222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c672663736967584730450221008b8c5c6ea8c142c032e0be69e1353d44461c5c9109941cdda951b976eb95b6b302204d52f406c19e254b3ff9589bd18070fb055ac8db12fdd0a6734bea9d7168e900637835638159022630820222308201c7a00302010202101f6fb7a5ece81b45896b983a995da5f3300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004b7b36b7542a11120b443c794d0c99fdc25a06b76586413d81e086163ef6fe147a557afc34e2861d9057d6d465d4705a0310550bdeeb5f35ee35b9425ab859981a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414fb37b647bccfb9e54d989eaaacc1633868703fb3301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100b86bc129d92afca7d9869a39f70f139a305b4073a39eb654d81424bed5757d91022100cf9f7c60cab7c4a7d3e7f0020f281a93d4fd0a9f95121b989f56932a68885fba68617574684461746159021bbfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000428f8878298b9862a36ad8c7527bfef20020992a18acc83f67533600c1138a4b4c4bd236de13629cf025ed17cb00b00b74dfa4010303390100205901b403fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012143010001'

认证:

challenge = h'295f59f5fa8fe62c5aca9e27626c78c8da376ae6d8cd2dd29aebad601e1bc4c5'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.RS256', L=32) 推导得出

client_data_gen_flags = h'0e'   ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.RS256', L=1) 推导得出
; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data
; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位
auth_data_UV_BS = h'ba'   ; 由 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.1.10. 打包声明(使用 Ed25519 凭据)

注册:

challenge = h'560c73a09ce7a1586d61c1d6e41fef149be523e220fc9f385d38ab23702ebf1b'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.Ed25519', L=32)

private_key = h'c87fce9e9cd283d272a2418d9683366f83661e458ad4451f0f1c95cb83b0f0a8'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.Ed25519', L=32)
client_data_gen_flags = h'41'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.Ed25519', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
extra_client_data = h'db7587e24b9187edb77933754331e443'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.Ed25519', L=16)
aaguid = h'164009ea09faae7c397bc3e2ad0e7ec0'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.Ed25519', L=16)
credential_id = h'c6cffa01b7fda368a7e0b29c1384a719820246bca894dd12914708743af0cecd'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.Ed25519', L=32)
; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS
auth_data_UV_BE_BS = h'e8'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.Ed25519', L=1)
attestation_private_key = h'673ee7fd94405de523fd84a088ab082d75b7fceef02a301e2bca0a28537cf243'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.Ed25519', L=32)
attestation_cert_serial_number = h'6e391f23f57150dc7a12dad18f2b43ad'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.Ed25519', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a225667787a6f4a7a6e6f5668745963485735425f76464a766c492d49675f4a38345854697249334175767873222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2032335748346b7552682d323365544e31517a486b51773d3d227d'
attestationObject = h'a363666d74667061636b65646761747453746d74a363616c672663736967584730450220730a54d4f76cb1f2b7dd4a5a6eee3374e3c8a60fb3c4daa527c9277e365b64aa0221008b31a04a28cc4148b14c42a916548ee7f430bc7629295b42ee93e5d1aaba8ee6637835638159022530820221308201c7a00302010202106e391f23f57150dc7a12dad18f2b43ad300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004fb96a581a0b36742a8c45d6ffb5af1ef155524b50339445ec1109874045e0087db77edef91f3dc949927470d84b01627087b72c86b7c9d02e1389cba680ffc36a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414ef2ce1a86caba85121130a16e8ce82a75d5a6653301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020348003045022100ad4fa628cffba5a642a562cbfefe63efecce26d90c80114114d1745383e12f01022028af87ba3b0ff868a34b9458bc6973b27380a328dd87b7436651ffa823280bca6861757468446174615881bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54900000000164009ea09faae7c397bc3e2ad0e7ec00020c6cffa01b7fda368a7e0b29c1384a719820246bca894dd12914708743af0cecda401010327200621582089f81eba4a1f510cb243ff7fb9e9cf899bf627e49ce1ac3c3eae8adb2a8d7d7b'

认证:

challenge = h'3790da8b2b72ee8ce19761787ad38cbfaa697eb3ca013a1342988756b98785ab'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.Ed25519', L=32)

client_data_gen_flags = h'de'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.Ed25519', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但仅当注册时设置了 BE 时,才会设置 BS
auth_data_UV_BS = h'18'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.Ed25519', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224e35446169797479376f7a686c32463465744f4d763670706672504b41546f545170694856726d48686173222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
signature = h'4c873571377ac019f257d6bf07249f63ac2487483c51bc511ce0f0e3266c840cb07a09cdc445a2f963d8603a9f0f6cf9ce709d7fc6a96c7c51ea08d33776010c'

16.1.11. TPM 声明(使用 ES256 凭据)

注册:

challenge = h'cfc82cdf1ceee876120aa88f0364f0910193460cfb97a317b2fe090694f9a299'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='tpm.ES256', L=32)

credential_private_key = h'80c60805e564f6d33e7abdff9d32e3db09a6219fe378a268d23107191b18e39f'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='tpm.ES256', L=32)
client_data_gen_flags = h'84'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='tpm.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
aaguid = h'4b92a377fc5f6107c4c85c190adbfd99'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='tpm.ES256', L=16)
credential_id = h'ec27bec7521c894bbb821105ea3724c90e770cf1fa354157ef18d0f18f78bea9'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='tpm.ES256', L=32)
; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS
auth_data_UV_BE_BS = h'af'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='tpm.ES256', L=1)
attestation_private_key = h'6210f09e0ce7593e851a880a4bdde2d2192afeac46104abce1a890a5a71cf0c6'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='tpm.ES256', L=32)
attestation_cert_serial_number = h'311fc42da0ab10c43a9b1bf3a75e34e2'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='tpm.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a227a38677333787a753648595343716950413254776b51475452677a376c364d587376344a427054356f706b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d'
attestationObject = h'a363666d746374706d6761747453746d74a663616c67266373696758463044022066e5826a652091030fd444e33c3eca2bc6dc548cf3045013addb38aa6457a21002203f3a5c95c9e707d0e555041bcc8698ee4ebc04e26cc8bae459705471789851766376657263322e30637835638159023a30820236308201dca0030201020210311fc42da0ab10c43a9b1bf3a75e34e2300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d03010703420004c54e3f109094f60d7699b7db5d838569ffd1f3e1c9e897cd9eb40063f9402e3e9937e936cf1fcd5eb743ff443c97ab2edcd7c8e0e6cf6cfd413b8ab19fffa769a381d33081d0300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604145f546cb6973d4981e80fcdc7463859f5879680e4301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e30100603551d250409300706056781050803305e0603551d110101ff04543052a450304e314c3014060567810502010c0b69643a30303030303030303014060567810502030c0b69643a3030303030303030301e060567810502020c15576562417574686e207465737420766563746f7273300a06082a8648ce3d0403020348003045022063c9a2797b8066f1db34dd609f1ab6695607e7a98e9ff8090a68853c9a9fc949022100a55831a39f5b8a2aa9a68837829cabf43fea2a5cea4859ae851cac78e6ac3e97677075624172656158560023000b0004000000000010001000030010002041202698c9d9753fb4bb3f27cd09fe6b8afdb76438ee2ae54d7c9dade10d864b0020d8735115cdb330a63ea1d6e43d5000f4bd56f99bce83ee1d73301fc270116d076863657274496e666f5869ff544347801700000020277d0e05579dd013215a62273f7f3a3e7e191ead2654a3036d75a5a3ee37a6b0000000000000000011111111222222223300000000000000000022000b9c42d8aad5939331b9af3711af179f17123178098c9a7d0ca89fcd1fc800f3c7000068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d000000004b92a377fc5f6107c4c85c190adbfd990020ec27bec7521c894bbb821105ea3724c90e770cf1fa354157ef18d0f18f78bea9a501020326200121582041202698c9d9753fb4bb3f27cd09fe6b8afdb76438ee2ae54d7c9dade10d864b225820d8735115cdb330a63ea1d6e43d5000f4bd56f99bce83ee1d73301fc270116d07'

认证:

challenge = h'00093b66c21d5b5e89f7a07082118907ea3e502d343b314b8c5a54d62db202fb'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='tpm.ES256', L=32)

client_data_gen_flags = h'86'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='tpm.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS
auth_data_UV_BS = h'87'   ; 由以下方式导出: 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.1.12. Android Key 声明(使用 ES256 凭据)

注册:

challenge = h'3de1f0b7365dccde3ff0cbf25e26ffa7baff87ef106c80fc865dc402d9960050'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='android-key.ES256', L=32)

credential_private_key = h'd4328d911acb0ebcc42aad29b29ffb55d5bc31d8af7ca9a16703d56c21abc7b4'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='android-key.ES256', L=32)
client_data_gen_flags = h'73'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='android-key.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
extra_client_data = h'555d5c42e476a8b33f6a63dfa07ccbd2'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='android-key.ES256', L=16)
aaguid = h'ade9705e1ce7085b899a540d02199bf8'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='android-key.ES256', L=16)
credential_id = h'0a4729519788b6ed8a2d772b494e186244d8c798c052960dbc8c10c915176795'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='android-key.ES256', L=32)
; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS
auth_data_UV_BE_BS = h'1e'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='android-key.ES256', L=1)
attestation_cert_serial_number = h'1ff91f76b63f44812f998b250b0286bf'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='android-key.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2250654877747a5a647a4e345f384d76795869625f7037725f682d385162494438686c334541746d57414641222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205656316351755232714c4d5f616d50666f487a4c30673d3d227d'
attestationObject = h'a363666d746b616e64726f69642d6b65796761747453746d74a363616c672663736967584630440220592bbc3c4c5f6158b52be1e085c92848986d7844245dfc9512e1a7e9ff7a2cd8022015bdd0852d3bd091e1c22da4211f4ccf0fdf4d912599d1c6630b1f310d3166f5637835638159026d3082026930820210a00302010202101ff91f76b63f44812f998b250b0286bf300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000499169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accfdd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6ba381a83081a5300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604141ac81e50641e8d1339ab9f7eb25f0cd5aac054b0301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e3045060a2b06010401d679020111043730350202012c0201000201000201000420b20e943e3a7544b3a438943b6d5655313a47ef1af34e00ff3261aeb9ed155817040030003000300a06082a8648ce3d040302034700304402206f4609c9ffc946c418cef04c64a0d07bcce78f329b99270b822f2a4d1e3b75330220093c8d18328f36ef157f296393bdc7721dd2bd67438ffeaa42f051a044b7457168617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000ade9705e1ce7085b899a540d02199bf800200a4729519788b6ed8a2d772b494e186244d8c798c052960dbc8c10c915176795a501020326200121582099169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accf225820dd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6b'

认证:

challenge = h'e4ee05ca9dbced74116540f24ed9adc62aae8507560522844ffa7eea14f7af86'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='android-key.ES256', L=32)

client_data_gen_flags = h'43'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='android-key.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
extra_client_data = h'ab127107eff182bc3230beb5f1dad29c'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='android-key.ES256', L=16)
; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS
auth_data_UV_BS = h'4a'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='android-key.ES256', L=1)

authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000'
clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22354f344679703238375851525a55447954746d74786971756851645742534b45545f702d36685433723459222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2071784a78422d5f78677277794d4c3631386472536e413d3d227d'
signature = h'304502202060107d953b286aa1bf35e3e8c78b383fddab5591b2db17ffb23ed83fe7df20022100a99be0297cb0d9d38aa96f30b760a4e0749dab385acd2a51d0560caae570d225'

16.1.13. Apple 匿名声明(使用 ES256 凭据)

注册:

challenge = h'f7f688213852007775009cf8c096fda89d60b9a9fb5a50dd81dd9898af5a0609'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='apple.ES256', L=32)

credential_private_key = h'de987bd9d43eeb44728ce0b14df11209dff931fb56b5b1948de4c0da1144ded0'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='apple.ES256', L=32)
client_data_gen_flags = h'5f'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='apple.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
extra_client_data = h'4e32cf9e939a5d052b14d71b1f6b5364'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='apple.ES256', L=16)
aaguid = h'748210a20076616a733b2114336fc384'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='apple.ES256', L=16)
credential_id = h'9c4a5886af9283d9be3e9ec55978dedfdce2e3b365cab193ae850c16238fafb8'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='apple.ES256', L=32)
; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS
auth_data_UV_BE_BS = h'2a'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='apple.ES256', L=1)
attestation_cert_serial_number = h'394275613d5310b81a29ce90f48b61c1'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='apple.ES256', L=16)

clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22395f61494954685341486431414a7a34774a6239714a316775616e37576c4464676432596d4b396142676b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20546a4c506e704f6158515572464e6362483274545a413d3d227d'
attestationObject = h'a363666d74656170706c656761747453746d74a1637835638159025c30820258308201fea0030201020210394275613d5310b81a29ce90f48b61c1300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d030107034200048a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761af728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136ca38196308193300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e0416041412f1ce6c0ae39b403bfc9200317bc183a4e4d766301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e303306092a864886f76364080204263024a122042097851a1a98b69c0614b26a94b70ec3aa07c061f89dbee23fbee01b6c42d718b0300a06082a8648ce3d040302034800304502207d541a5553f38b93b78b26a9dca58e64a7f8fac15ca206ae3ea32497cda375fb0221009137c6b75e767ec08224b29a7f703db4b745686dcc8a26b66e793688866d064f68617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54900000000748210a20076616a733b2114336fc38400209c4a5886af9283d9be3e9ec55978dedfdce2e3b365cab193ae850c16238fafb8a50102032620012158208a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761a225820f728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136c'

认证:

challenge = h'd3eb2964641e26fed023403a72dde093b19c4ba9008c3f9dd83fcfd347a66d05'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='apple.ES256', L=32)

client_data_gen_flags = h'c2'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='apple.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS
auth_data_UV_BS = h'e2'   ; 由以下方式导出: 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.1.14. FIDO U2F 声明(使用 ES256 凭据)

注册:

challenge = h'e074372990b9caa507a227dfc67b003780c45325380d1a90c20f81ed7d080c06'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='fido-u2f.ES256', L=32)

credential_private_key = h'51bd002938fa10b83683ac2a2032d0a7338c7f65a90228cfd1f61b81ec7288d0'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='fido-u2f.ES256', L=32)
client_data_gen_flags = h'00'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='fido-u2f.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
aaguid = h'afb3c2efc054df425013d5c88e79c3c1'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='fido-u2f.ES256', L=16)
credential_id = h'a4ba6e2d2cfec43648d7d25c5ed5659bc18f2b781538527ebd492de03256bdf4'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='fido-u2f.ES256', L=32)
attestation_private_key = h'66fda477a2a99d14c5edd7c1041a297ba5f3375108b1d032b79429f42349ce33'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='fido-u2f.ES256', L=32)
attestation_cert_serial_number = h'04f66dc6542ea7719dea416d325a2401'   ; 由以下方式导出: 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'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='fido-u2f.ES256', L=32)

client_data_gen_flags = h'2c'   ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='fido-u2f.ES256', L=1)
; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data
; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS
auth_data_UV_BS = h'd1'   ; 由以下方式导出: 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.2. WebAuthn 扩展的测试向量

本节列出 WebAuthn 扩展 的示例值。

16.2.1. 伪随机函数扩展(prf)

本节列出伪随机函数(prf)扩展的示例值。

由于 prf 扩展与 CTAP2 的 hmac-secret 扩展集成([FIDO-CTAP]),因此示例分为两部分:WebAuthn prf 扩展的示例输入和输出(适用于 WebAuthn 客户端和 WebAuthn 依赖方);以及 WebAuthn prf 扩展与 CTAP2 hmac-secret 扩展之间的映射示例(适用于 WebAuthn 客户端和 WebAuthn 认证器)。

16.2.1.1. Web Authentication API

下面的示例可用于测试 WebAuthn 客户端 实现和 WebAuthn 依赖方 使用 prf 扩展。 这些示例并不详尽。

本节中使用的伪随机值生成如下:

16.2.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, 以及 Boris Zbarsky。

感谢 Adam Powers 制作了整体的 注册认证流程图 (图1图2)。

我们感谢 Anthony Nadalin, John Fontana, 以及 Richard Barnes 作为 Web Authentication Working Group 联席主席的贡献。

同时感谢 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 Authentication API 及其操作方式做出了如下更改。

更改:

弃用项:

新增功能:

18.1.2. 编辑性变更

以下更改提升了文档的清晰性、可读性、可导航性等方面。

索引

本规范定义的术语

引用文献定义的术语

参考文献

规范性引用

[CREDENTIAL-MANAGEMENT-1]
Nina Satragno;Marcos Caceres。Credential Management Level 1。2024年8月13日。WD。网址:https://www.w3.org/TR/credential-management-1/
[CSP2]
Mike West;Adam Barth;Daniel Veditz。内容安全策略第2级(Content Security Policy Level 2)。2016年12月15日。REC。网址:https://www.w3.org/TR/CSP2/
[CSS21]
Bert Bos 等。层叠样式表2级修订1(CSS 2.1)规范。2011年6月7日。REC。网址:https://www.w3.org/TR/CSS21/
[DOM4]
Anne van Kesteren。DOM 标准。实时标准。网址:https://dom.spec.whatwg.org/
[ECMAScript]
ECMAScript 语言规范。网址:https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren。编码标准。实时标准。网址:https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren。Fetch 标准。实时标准。网址:https://fetch.spec.whatwg.org/
[FIDO-APPID]
D. Balfanz 等。FIDO AppID 与 Facet 规范。2018年2月27日。FIDO Alliance 实现草案。网址: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-appid-and-facets-v2.0-id-20180227.html
[FIDO-CTAP]
J. Bradley 等。客户端到认证器协议(CTAP)。2022年6月21日。FIDO Alliance 提议标准。网址: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 白皮书。网址: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 提议标准。网址: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 实现草案。网址:https://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-message-formats-v1.1-id-20160915.html
[FIDO-V2.1]
客户端到认证器协议(CTAP)。编辑草案。网址:https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html
[HTML]
Anne van Kesteren 等。HTML 标准。实时标准。网址:https://html.spec.whatwg.org/multipage/
[I18N-GLOSSARY]
Richard Ishida;Addison Phillips。国际化术语表。2024年10月17日。注释。网址:https://www.w3.org/TR/i18n-glossary/
[IANA-COSE-ALGS-REG]
IANA CBOR 对象签名与加密(COSE)算法注册表。网址:https://www.iana.org/assignments/cose/cose.xhtml#algorithms
[IANA-WebAuthn-Registries]
IANA。Web Authentication (WebAuthn) 注册表。网址:https://www.iana.org/assignments/webauthn/
[INFRA]
Anne van Kesteren;Domenic Denicola。Infra 标准。实时标准。网址:https://infra.spec.whatwg.org/
[Permissions-Policy]
Ian Clelland。权限策略。2025年1月13日。WD。网址:https://www.w3.org/TR/permissions-policy-1/
[PRIVATE-AGGREGATION-API]
私有聚合 API。非官方提案草案。网址:https://patcg-individual-drafts.github.io/private-aggregation-api/
[RFC2119]
S. Bradner。RFC 中表示需求等级的关键词。1997年3月。最佳现行实践。网址:https://datatracker.ietf.org/doc/html/rfc2119
[RFC3986]
T. Berners-Lee;R. Fielding;L. Masinter。统一资源标识符(URI):通用语法。2005年1月。互联网标准。网址:https://www.rfc-editor.org/rfc/rfc3986
[RFC4648]
S. Josefsson。Base16、Base32、Base64 数据编码。2006年10月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc4648
[RFC4949]
R. Shirey。互联网安全术语表,第2版。2007年8月。信息性。网址:https://www.rfc-editor.org/rfc/rfc4949
[RFC5234]
D. Crocker, Ed.;P. Overell。语法规范增强BNF:ABNF。2008年1月。互联网标准。网址:https://www.rfc-editor.org/rfc/rfc5234
[RFC5280]
D. Cooper 等。互联网 X.509 公钥基础设施证书与吊销列表(CRL)配置文件。2008年5月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc5280
[RFC5890]
J. Klensin。应用的国际化域名(IDNA):定义和文档框架。2010年8月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc5890
[RFC6454]
A. Barth。Web 起源概念。2011年12月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc6454
[RFC7515]
M. Jones;J. Bradley;N. Sakimura。JSON Web 签名(JWS)。2015年5月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc7515
[RFC8152]
J. Schaad。CBOR 对象签名与加密(COSE)。2017年7月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc8152
[RFC8174]
B. Leiba。RFC2119 关键字大小写歧义。2017年5月。最佳现行实践。网址:https://www.rfc-editor.org/rfc/rfc8174
[RFC8230]
M. Jones。在 CBOR 对象签名与加密(COSE)消息中使用 RSA 算法。2017年9月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc8230
[RFC8264]
P. Saint-Andre;M. Blanchet。PRECIS 框架:应用协议中国际化字符串的准备、执行和比较。2017年10月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc8264
[RFC8265]
P. Saint-Andre;A. Melnikov。表示用户名和密码的国际化字符串的准备、执行和比较。2017年10月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc8265
[RFC8266]
P. Saint-Andre。表示昵称的国际化字符串的准备、执行和比较。2017年10月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc8266
[RFC8610]
H. Birkholz;C. Vigano;C. Bormann。简明数据定义语言(CDDL):用于表达CBOR和JSON数据结构的符号约定。2019年6月。IETF 建议标准。网址:https://tools.ietf.org/html/rfc8610
[RFC8615]
M. Nottingham。知名统一资源标识符(URI)。2019年5月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc8615
[RFC8809]
Jeff Hodges;Giridhar Mandyam;Michael B. Jones。Web 认证(WebAuthn)注册表。2020年8月。IETF 建议标准。网址:https://www.rfc-editor.org/rfc/rfc8809
[RFC8949]
C. Bormann;P. Hoffman。简明二进制对象表示法(CBOR)。2020年12月。互联网标准。网址:https://www.rfc-editor.org/rfc/rfc8949
[RFC9052]
J. Schaad。CBOR 对象签名与加密(COSE):结构与过程。2022年8月。互联网标准。网址:https://www.rfc-editor.org/rfc/rfc9052
[RFC9053]
J. Schaad。CBOR 对象签名与加密(COSE):初始算法。2022年8月。信息性。网址:https://www.rfc-editor.org/rfc/rfc9053
[SEC1]
SEC1:椭圆曲线密码学,第2版。网址:http://www.secg.org/sec1-v2.pdf
[SP800-800-63r3]
Paul A. Grassi;Michael E. Garcia;James L. Fenton。美国国家标准与技术研究院特别出版物800-63:数字身份指南。2017年6月。网址:https://pages.nist.gov/800-63-3/sp800-63-3.html
[TCG-CMCProfile-AIKCertEnroll]
Scott Kelly 等。TCG 基础设施工作组:AIK 证书注册的 CMC 配置文件。2011年3月24日。已发布。网址:https://trustedcomputinggroup.org/wp-content/uploads/IWG_CMC_Profile_Cert_Enrollment_v1_r7.pdf
[TokenBinding]
A. Popov 等。Token Binding 协议1.0版。2018年10月。IETF 建议标准。网址:https://tools.ietf.org/html/rfc8471
[TPMv2-EK-Profile]
TPM 2.0 设备 EK 证书简介。网址:https://trustedcomputinggroup.org/wp-content/uploads/TCG-EK-Credential-Profile-V-2.5-R2_published.pdf
[TPMv2-Part1]
可信平台模块库,第1部分:架构。网址:https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf
[TPMv2-Part2]
可信平台模块库,第2部分:结构。网址:https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
[TPMv2-Part3]
可信平台模块库,第3部分:命令。网址:https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-3-Commands-01.38.pdf
[URL]
Anne van Kesteren。URL 标准。实时标准。网址:https://url.spec.whatwg.org/
[WCAG21]
Michael Cooper 等。网页内容无障碍指南 (WCAG) 2.1。2024年12月12日。REC。网址:https://www.w3.org/TR/WCAG21/
[WEBAUTHN-2-20210408]
Jeff Hodges 等。Web Authentication: An API for accessing Public Key Credentials - Level 2。2021年4月8日。REC。网址:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/
[WEBAUTHN-3]
Michael Jones;Akshay Kumar;Emil Lundberg。Web Authentication:访问公钥凭证的API,第3级。2023年9月27日。WD。网址:https://www.w3.org/TR/webauthn-3/
[WebDriver]
Simon Stewart;David Burns。WebDriver。2018年6月5日。REC。网址:https://www.w3.org/TR/webdriver1/
[WEBDRIVER2]
Simon Stewart;David Burns。WebDriver。2024年12月12日。WD。网址:https://www.w3.org/TR/webdriver2/
[WebIDL]
Edgar Chen;Timothy Gu。Web IDL 标准。实时标准。网址:https://webidl.spec.whatwg.org/

补充性参考

[Ceremony]
Carl Ellison。仪式设计与分析。2007年。网址:https://eprint.iacr.org/2007/399.pdf
[CSS-OVERFLOW-3]
Elika Etemad;Florian Rivoal。CSS 溢出模块3级。2023年3月29日。WD。网址:https://www.w3.org/TR/css-overflow-3/
[EduPersonObjectClassSpec]
EduPerson。持续更新。网址:https://refeds.org/eduperson
[FIDO-Transports-Ext]
FIDO Alliance。FIDO U2F 认证器传输扩展。FIDO Alliance 提议标准。网址: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 实现草案。网址:https://fidoalliance.org/specs/fido-uaf-v1.1-id-20170202/fido-uaf-authnr-cmds-v1.1-id-20170202.html
[FIDOAuthnrSecReqs]
D. Biggs 等。FIDO 认证器安全要求。FIDO Alliance 最终文档。网址:https://fidoalliance.org/specs/fido-security-requirements-v1.0-fd-20170524/
[FIDOMetadataService]
R. Lindemann;B. Hill;D. Baghdasaryan。FIDO 元数据服务。2018年2月27日。FIDO Alliance 实现草案。网址:https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-metadata-service-v2.0-id-20180227.html
[FIDOSecRef]
R. Lindemann 等。FIDO 安全参考。2018年2月27日。FIDO Alliance 实现草案。网址: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 提议标准。网址: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) 第一版。网址:http://standards.iso.org/ittf/PubliclyAvailableStandards/c055194_ISOIEC_2382-37_2012.zip
[RFC3279]
L. Bassham;W. Polk;R. Housley。互联网 X.509 公钥基础设施证书和吊销列表(CRL)配置文件的算法与标识。2002年4月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc3279
[RFC5869]
H. Krawczyk;P. Eronen。基于 HMAC 的密钥提取与扩展函数(HKDF)。2010年5月。信息性。网址:https://www.rfc-editor.org/rfc/rfc5869
[RFC5958]
S. Turner。非对称密钥包。2010年8月。建议标准。网址:https://www.rfc-editor.org/rfc/rfc5958
[RFC6265]
A. Barth。HTTP 状态管理机制。2011年4月。建议标准。网址:https://httpwg.org/specs/rfc6265.html
[RFC6979]
T. Pornin。DSA 与 ECDSA 数字签名算法的确定性用法。2013年8月。信息性。网址:https://www.rfc-editor.org/rfc/rfc6979
[RFC8017]
K. Moriarty, Ed. 等。PKCS #1: RSA 密码学规范第2.2版。2016年11月。信息性。网址:https://www.rfc-editor.org/rfc/rfc8017
[UAFProtocol]
R. Lindemann 等。FIDO UAF 协议规范v1.0。FIDO Alliance 提议标准。网址:https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-protocol-v1.0-ps-20141208.html
[UAX29]
UNICODE 文本分段。网址:http://www.unicode.org/reports/tr29/
[WebAuthn-1]
Dirk Balfanz 等。Web认证:访问公钥凭证API,第1级。2019年3月4日。REC。网址:https://www.w3.org/TR/webauthn-1/
[WebAuthnAPIGuide]
Web Authentication API 指南。实验性。网址: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 AuthenticationExtensionsClientOutputs {
  boolean appid;
};

partial dictionary AuthenticationExtensionsClientInputs {
  DOMString appidExclude;
};

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appidExclude;
};

partial dictionary AuthenticationExtensionsClientInputs {
    boolean credProps;
};

dictionary CredentialPropertiesOutput {
    boolean rk;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    CredentialPropertiesOutput credProps;
};

dictionary AuthenticationExtensionsPRFValues {
    required BufferSource first;
    BufferSource second;
};

dictionary AuthenticationExtensionsPRFInputs {
    AuthenticationExtensionsPRFValues eval;
    record<DOMString, AuthenticationExtensionsPRFValues> evalByCredential;
};

partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsPRFInputs prf;
};

dictionary AuthenticationExtensionsPRFOutputs {
    boolean enabled;
    AuthenticationExtensionsPRFValues results;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsPRFOutputs prf;
};

partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsLargeBlobInputs largeBlob;
};

enum LargeBlobSupport {
  "required",
  "preferred",
};

dictionary AuthenticationExtensionsLargeBlobInputs {
    DOMString support;
    boolean read;
    BufferSource write;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsLargeBlobOutputs largeBlob;
};

dictionary AuthenticationExtensionsLargeBlobOutputs {
    boolean supported;
    ArrayBuffer 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