1. 引言
本节不具有规范性。
本规范定义了一种 API,使限定作用域的、基于公钥的强认证且经过证明的 凭据能够由Web 应用程序创建和使用,以实现对用户的强身份验证。公钥凭据由WebAuthn 认证器应WebAuthn 依赖方的要求创建并存储,但须获得用户同意。此后,公钥凭据只能由属于该依赖方的源访问。 此作用域限定由符合要求的用户代理和认证器共同强制执行。 此外,还会维护不同依赖方之间的隐私;依赖方无法检测限定作用域于其他 依赖方的凭据的任何属性,甚至 无法检测这些凭据是否存在。
依赖方在涉及用户的两个不同但相关的Web
身份验证 API仪式中使用它。第一个
是注册,其中在认证器上创建一个公钥
凭据,并将其限定作用域于具有当前用户帐户的依赖方
(该帐户可能已经存在,也可能在此时创建)。第二个是
身份验证,其中向依赖方提供一个身份验证断言,证明注册该公钥凭据的用户存在并已同意。从功能上讲,Web 身份验证 API由一个扩展
Credential Management API [CREDENTIAL-MANAGEMENT-1] 的 PublicKeyCredential
以及允许这些凭据与 navigator.credentials.create()
和
navigator.credentials.get()
一起使用的基础设施组成。
前者在注册期间使用,而
后者在身份验证期间使用。
总体而言,符合要求的认证器保护公钥凭据,并 与用户代理交互以实现 Web 身份验证 API。 符合要求的认证器可以通过运行在以下位置的软件实现: (a) 通用计算设备上, (b) 设备上的安全执行环境、可信平台模块 (TPM) 或安全元件 (SE) 中,或 (c) 设备之外。 在设备上实现的认证器称为平台认证器。 在设备之外实现的认证器(漫游认证器)可以通过通用串行总线 (USB)、低功耗蓝牙 (BLE) 或近场通信 (NFC) 等传输方式访问。
1.1. 规范路线图
虽然许多 W3C 规范主要面向用户代理开发者,也面向 Web 应用程序 开发者 (即“Web 作者”),但 Web 身份验证的性质要求本规范由多个受众 正确使用, 如下所述。
所有受众都应从§ 1.2 用例、§ 1.3 API 使用示例场景和§ 4 术语开始,并且还应该 参考[WebAuthnAPIGuide]作为整体教程。 除此之外,本文档的预期受众包括以下主要群体:
-
依赖方 Web 应用程序开发者,尤其是负责依赖方Web 应用程序登录流程、帐户 恢复流程、 用户帐户数据库内容等的开发者。
-
Web 框架开发者
-
上述两类受众尤其应该参考§ 7 WebAuthn 依赖方操作。 § 5 Web 身份验证 API的引言可能会有所帮助, 但读者应该意识到,§ 5 Web 身份验证 API 一节专门面向 用户代理开发者,而不是 Web 应用程序开发者。 此外,如果他们打算验证认证器的证明,那么 § 6.5 证明和§ 8 定义的证明语句格式 也与其相关。 如果他们希望使用扩展,则§ 9 WebAuthn 扩展和§ 10 定义的扩展也值得关注。 最后,他们应该阅读§ 13.5 依赖方的安全 注意事项和§ 14.6 依赖方的隐私注意事项, 并考虑哪些挑战适用于他们的应用程序和用户。
-
-
用户代理开发者
-
操作系统平台开发者,负责与特定于平台的 认证器 API、 平台WebAuthn 客户端实例化等相关的操作系统平台 API 设计和实现。
-
上述两类受众应该非常仔细地阅读§ 5 Web 身份验证 API, 如果他们打算支持扩展,还应阅读§ 9 WebAuthn 扩展。 他们还应该仔细阅读 § 14.5 客户端的隐私注意事项。
-
-
认证器 开发者。这些读者需要特别关注§ 6 WebAuthn 认证器模型、 § 8 定义的证明语句格式、§ 9 WebAuthn 扩展和§ 10 定义的扩展。 他们还应该仔细阅读§ 13.3 认证器的安全注意事项和§ 14.4 认证器的隐私注意事项。
对于 Web 身份验证部署的端到端安全性而言,非常重要的一点是,所有受众都应理解 每个 组件——依赖 方服务器、客户端和 认证器—— 的作用,以及§ 13 安全注意事项和§ 14 隐私注意事项,这些内容都应由所有 受众理解。
1.2. 用例
下面的用例场景说明了在两种常见部署类型中使用两种非常不同类型的认证器和凭据, 并概述了其他场景。后面的§ 1.3 API 使用示例场景中给出了包括示例代码在内的其他场景。 这些示例仅用于说明,功能可用性可能因客户端和 认证器实现而异。
1.2.1. 使用多设备凭据的消费者
此用例说明了以消费者为中心的依赖方如何利用内置于用户设备中的认证器, 使用多设备凭据(通常称为已同步的通行密钥)提供抗网络钓鱼的登录。
1.2.1.1. 注册
-
在手机上:
-
用户在浏览器中导航到 example.com,并使用他们一直在使用的任何 方法(可能是密码等传统方法)登录现有帐户,或者创建一个新帐户。
-
手机提示:“是否要为 example.com 创建通行密钥?”
-
用户同意。
-
手机提示用户执行之前配置的授权 手势(PIN、生物特征等);用户 执行该操作。
-
网站显示消息:“注册完成。”
-
1.2.1.2. 身份验证
-
在笔记本电脑或台式机上:
-
接下来,在他们的手机上:
-
用户看到一条单独的提示或通知:“登录 example.com。”
-
用户选择此提示/通知。
-
向用户显示其 example.com 身份列表,例如:“以 Mohamed 身份登录 / 以 张三身份登录”。
-
用户选择一个身份,系统提示其执行授权 手势(PIN、生物特征等),用户随后执行该操作。
-
-
现在,回到笔记本电脑:
-
网页显示所选用户已登录,并导航到已登录页面。
-
1.2.2. 使用单设备凭据的工作人员
此用例说明了以工作人员为中心的依赖方如何结合使用漫游认证器(例如 USB 安全 密钥)和平台认证器(例如内置指纹传感器), 从而使用户具有:
-
一个“主要”漫游认证器,用于在他们此前未使用过的客户端 设备(例如笔记本电脑、 台式机)上进行身份验证,或在缺少平台 认证器的此类客户端设备上进行身份验证,以及
-
一种方式,可在具有不支持单设备 凭据(通常称为设备绑定的通行密钥)的通行密钥 平台认证器的客户端设备上进行强重新身份验证。
1.2.2.1. 注册
在此示例中,用户的雇主邮寄了一枚预配置有设备绑定通行密钥的安全密钥。
临时 PIN 已通过带外方式发送给用户(例如通过 RCS 消息)。
1.2.2.2. 身份验证
-
在笔记本电脑或台式机上:
-
用户在浏览器中导航到 corp.example.com 并开始登录。
-
浏览器或操作系统提示用户使用其安全密钥。
-
用户连接其 USB 安全密钥。
-
USB 安全密钥闪烁,表示用户应按下其上的按钮;用户 按下按钮。
-
浏览器或操作系统要求用户输入其 PIN。
-
用户输入已提供给他们的临时 PIN 并继续。
-
浏览器或操作系统通知用户必须更改其 PIN,并提示 输入新的 PIN。
-
用户输入新的 PIN 并继续。
-
浏览器或操作系统重新启动身份验证流程,并要求用户输入 其 PIN。
-
用户输入新的 PIN 并轻触安全密钥。
-
网页显示所选用户已登录,并导航到已登录页面。
-
1.2.3. 其他用例和配置
还可以有多种其他用例和配置,包括(但不限于):
-
用户在笔记本电脑上导航到 example.com,并在引导流程中于其 手机上创建和注册凭据。
-
用户获得一个独立的漫游认证器,例如具有 USB 和/或 NFC 连接选项的安全密钥,在笔记本电脑或手机的浏览器中加载 example.com,并在引导流程中于 安全密钥上创建和注册凭据。
1.3. API 使用示例场景
本节不具有规范性。
在本节中,我们将介绍公钥凭据生命周期中的一些事件,以及 使用此 API 的相应 示例代码。请注意,这只是一个示例流程,并不限制 API 的使用范围。
与前面各节一样,此流程重点介绍涉及一个具有自己显示屏的通行密钥漫游 认证器 的用例。这种认证器的一个示例是智能手机。此 API 也支持其他类型的认证器,但取决于客户端平台的实现。例如,对于 嵌入在客户端设备中的认证器,此流程无需 修改即可工作。对于没有 自己显示屏的认证器(类似于智能卡),此流程也可以工作,但须考虑特定的实现事项。具体而言, 客户端平台 需要显示原本会由认证器显示的所有提示,并且认证器需要 允许客户端 平台枚举认证器的所有凭据,以便客户端能够获取用于 显示适当提示的信息。
1.3.1. 注册
这是首次使用流程,其中会创建新凭据并将其注册到服务器。 在此流程中,WebAuthn 依赖方并不偏好平台 认证器或漫游认证器。
-
用户访问 example.com,该网站提供一个脚本。此时,用户可能已经使用传统的 用户名和密码、其他认证器或依赖方可接受的其他方式 登录。 或者用户可能正在创建新帐户。
-
依赖方 脚本运行下面的代码片段。
-
客户端平台 搜索并定位认证器。
-
客户端连接到 认证器,并在必要时执行任何配对操作。
-
认证器显示适当的 UI,以便用户提供生物特征或其他授权手势。
-
如果创建了新凭据,
生成并注册新密钥的示例代码如下:
if ( ! window. PublicKeyCredential) { /* 客户端不具备此能力。处理错误。 */ } var publicKey= { // 挑战由服务器生成;请参阅安全注意事项 challenge: new Uint8Array([ 21 , 31 , 105 /* 由服务器生成的另外 29 个随机字节 */ ]), // 依赖方: rp: { name: "ACME 公司" }, // 用户: user: { id: Uint8Array. from ( window. atob( "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=" ), c=> c. charCodeAt( 0 )), name: "alex.mueller@example.com" , displayName: "Alex Müller" , }, // 此依赖方将接受 EdDSA、ES256 或 RS256 凭据,但 // 更倾向于 EdDSA 凭据。 pubKeyCredParams: [ { type: "public-key" , alg: - 8 // 在 IANA COSE Algorithms 注册表中注册的 "EdDSA" }, { type: "public-key" , alg: - 7 // 在 IANA COSE Algorithms 注册表中注册的 "ES256" }, { type: "public-key" , alg: - 257 // 本规范为 "RS256" 注册的值 } ], authenticatorSelection: { // 如果可能,尝试使用 UV。这也是默认值。 userVerification: "preferred" }, timeout: 300000 , // 5 分钟 excludeCredentials: [ // 不要重新注册拥有这些凭据之一的任何认证器 { "id" : Uint8Array. from ( window. atob( "ufJWp8YGlibm1Kd9XQBWN1WAw2jy5In2Xhon9HAqcXE=" ), c=> c. charCodeAt( 0 )), "type" : "public-key" }, { "id" : Uint8Array. from ( window. atob( "E/e1dhZc++mIsz4f9hb6NifAzJpF1V4mEtRlIPBiWdY=" ), c=> c. charCodeAt( 0 )), "type" : "public-key" } ], // 使 excludeCredentials 检查向后兼容使用 U2F 注册的凭据 extensions: { "appidExclude" : "https://acme.example.com" } }; // 注:以下调用将使认证器显示 UI。 navigator. credentials. create({ publicKey}) . then( function ( newCredentialInfo) { // 将新凭据信息发送到服务器以进行验证和注册。 }). catch ( function ( err) { // 没有可接受的认证器,或用户拒绝同意。进行适当处理。 });
1.3.2. 专门使用用户验证平台 认证器进行注册
这是一个示例流程,适用于WebAuthn 依赖方特别希望使用 用户验证平台认证器创建公钥 凭据的情况。
-
用户访问 example.com 并单击登录按钮,该按钮将用户重定向到 login.example.com。
-
用户输入用户名和密码进行登录。登录成功后,用户会被重定向 回 example.com。
-
依赖方 脚本运行下面的代码片段。
-
用户代理检查是否有用户验证平台 认证器可用。如果没有,则终止此流程。
-
依赖 方询问用户是否希望使用它创建凭据。如果不希望,则终止 此流程。
-
用户代理和/或操作系统显示适当的 UI,并引导用户使用 可用的平台认证器之一创建 凭据。
-
成功创建凭据后,依赖方脚本将新凭据传送到 服务器。
-
if ( ! window. PublicKeyCredential) { /* 客户端不支持此 API。处理错误。 */ } PublicKeyCredential. isUserVerifyingPlatformAuthenticatorAvailable() . then( function ( uvpaAvailable) { // 如果存在用户验证平台认证器 if ( uvpaAvailable) { // 渲染某些特定于 RP 的 UI,并获取一个 Boolean 值的 Promise return askIfUserWantsToCreateCredential(); } }). then( function ( userSaidYes) { // 如果存在用户验证平台认证器 // 并且用户希望创建凭据 if ( userSaidYes) { var publicKeyOptions= { /* 公钥凭据创建选项。 */ }; return navigator. credentials. create({ "publicKey" : publicKeyOptions}); } }). then( function ( newCredentialInfo) { if ( newCredentialInfo) { // 将新凭据信息发送到服务器以进行验证和注册。 } }). catch ( function ( err) { // 出现错误。进行适当处理。 });
1.3.3. 身份验证
这是已注册凭据的用户访问网站并希望使用该 凭据进行身份验证时的流程。
-
用户访问 example.com,该网站提供一个脚本。
-
脚本向客户端请求一个 身份验证断言,并提供尽可能多的信息,以缩小 用户可接受凭据的选择范围。这些信息可以从 注册后存储在本地的数据中获得,也可以通过其他方式(例如提示用户输入用户名)获得。
-
依赖方 脚本运行下面的代码片段之一。
-
客户端平台 搜索并定位认证器。
-
客户端连接到 认证器,并在必要时执行任何配对操作。
-
认证器向用户显示一条需要其注意的通知。打开 通知后,会使用创建凭据时提供的 帐户信息向用户显示一个易于理解的可接受凭据选择菜单,同时还显示请求这些密钥的源的部分信息。
-
认证器从用户处获取生物特征或其他授权手势。
-
如果成功生成并返回了断言,
如果依赖方脚本 没有任何可用提示(例如来自本地存储的数据)来帮助缩小 凭据列表,那么执行此类身份验证的示例代码可能如下:
if ( ! window. PublicKeyCredential) { /* 客户端不具备此能力。处理错误。 */ } // credentialId 由认证器生成,是一个不透明的随机字节数组 var credentialId= new Uint8Array([ 183 , 148 , 245 /* 更多之前由认证器生成的随机字节 */ ]); var options= { // 挑战由服务器生成;请参阅安全注意事项 challenge: new Uint8Array([ 4 , 101 , 15 /* 由服务器生成的另外 29 个随机字节 */ ]), timeout: 300000 , // 5 分钟 allowCredentials: [{ type: "public-key" , id: credentialId}] }; navigator. credentials. get({ "publicKey" : options}) . then( function ( assertion) { // 将断言发送到服务器进行验证 }). catch ( function ( err) { // 没有可接受的凭据,或用户拒绝同意。进行适当处理。 });
另一方面,如果依赖 方脚本具有一些可帮助其缩小凭据列表的提示,那么 执行此类身份验证的示例代码可能如下所示。请注意,此示例还演示了如何 使用凭据属性 扩展。
if ( ! window. PublicKeyCredential) { /* 客户端不具备此能力。处理错误。 */ } var encoder= new TextEncoder(); var acceptableCredential1= { type: "public-key" , id: encoder. encode( "BA44712732CE" ) }; var acceptableCredential2= { type: "public-key" , id: encoder. encode( "BG35122345NF" ) }; var options= { // 挑战由服务器生成;请参阅安全注意事项 challenge: new Uint8Array([ 8 , 18 , 33 /* 由服务器生成的另外 29 个随机字节 */ ]), timeout: 300000 , // 5 分钟 allowCredentials: [ acceptableCredential1, acceptableCredential2], extensions: { 'credProps' : true } }; navigator. credentials. get({ "publicKey" : options}) . then( function ( assertion) { // 将断言发送到服务器进行验证 }). catch ( function ( err) { // 没有可接受的凭据,或用户拒绝同意。进行适当处理。 });
1.3.4. 中止身份验证操作
下面的示例展示了开发者如何使用 AbortSignal 参数中止 凭据注册操作。类似的过程也适用于身份验证操作。
const authAbortController= new AbortController(); const authAbortSignal= authAbortController. signal; authAbortSignal. onabort= function () { // 页面一旦得知中止已开始,就通知用户正在尝试中止。 } var options= { // 选项列表。 } navigator. credentials. create({ publicKey: options, signal: authAbortSignal}) . then( function ( attestation) { // 注册用户。 }). catch ( function ( error) { if ( error. name=== "AbortError" ) { // 通知用户凭据尚未创建。 // 通知服务器尚未创建密钥。 } }); // 假定每当发生身份验证时都会显示小组件。 if ( widget== "disappear" ) { authAbortController. abort(); }
1.3.5. 停用
以下是可能希望停用凭据的一些情况。请注意,所有 这些情况均在服务器端处理,不需要此处规定的 API 提供支持。
-
可能情况 #1——用户报告凭据丢失。
-
可能情况 #2——服务器因不活跃而注销凭据。
-
服务器在维护活动期间从数据库中删除凭据。
-
以后,依赖方脚本不会在任何可接受凭据列表中指定此凭据, 并且由此凭据 签名的断言将被拒绝。
-
-
可能情况 #3——用户从认证器中删除凭据。
1.4. 特定于平台的实现指南
本规范定义了在一般情况下如何使用 Web 身份验证。当结合特定 平台支持(例如应用程序)使用 Web 身份验证时,建议查看 特定于平台的文档和指南,以了解其他指导和限制。
2. 一致性
本规范定义了三个一致性类别。每个类别的规定都使该类别中符合要求的 成员能够抵御其他类别中不符合要求或恶意的成员。
2.1. 用户代理
用户代理必须按照§ 5 Web 身份验证 API中的描述行事,才能被视为 符合要求。符合要求的用户代理可以以 任何所需方式实现本规范中给出的算法,只要最终结果与 本规范算法所产生的结果无法区分即可。
符合要求的用户代理还必须是本规范 IDL 片段的符合要求实现, 如“Web IDL”规范中所述。[WebIDL]
2.1.1. 作为 DOMString 类型的枚举
Web IDL 的其他部分并不引用枚举类型,因为这样做
会使得在不更新本规范
及其实现的情况下无法使用其他值。为了向后兼容,
客户端平台和依赖方处理
未知值非常重要。本
规范中的枚举用于文档说明并作为注册表。当这些
枚举在其他地方表示时,它们被指定为 DOMString,
例如 transports。
2.2. 认证器
WebAuthn 认证器必须提供§ 6 WebAuthn 认证器模型定义的操作,并且这些操作必须按照 其中的描述行事。这是一组认证器要能够由符合要求的用户 代理使用所必须满足的功能和安全要求。
如§ 1.2 用例中所述,认证器可以实现于 用户代理底层的操作系统中,或者 外部硬件中,或者两者结合。
2.2.1. 与 FIDO U2F 的向后兼容性
仅支持§ 8.6 FIDO U2F 证明语句格式的认证器没有
存储用户句柄的机制,因此返回的 userHandle
始终为 null。
2.3. WebAuthn 依赖方
WebAuthn 依赖方必须按照§ 7 WebAuthn 依赖方 操作中的描述行事,以获得本规范提供的全部安全优势。有关 此内容的进一步讨论,请参阅§ 13.5.1 WebAuthn 依赖方的安全优势。
2.4. 所有一致性类别
上述一致性类别成员执行的所有CBOR编码都必须使用 CTAP2 规范 CBOR 编码形式。 上述一致性类别的所有解码器都应该拒绝未有效编码为 CTAP2 规范 CBOR 编码形式的 CBOR,并且应该 拒绝包含重复映射键的消息。
3. 依赖项
本规范依赖若干其他底层规范,这些规范列于 下方以及通过引用定义的术语中。
- Base64url 编码
-
术语Base64url 编码是指使用 [RFC4648]第 5 节中定义的 URL 和文件名安全字符集的 base64 编码,其中省略所有末尾的 '=' 字符(第 3.2 节允许如此),并且不 包含任何换行符、空白或其他附加字符。
- CBOR
-
本规范中的许多结构,包括证明语句和扩展,都使用 紧凑二进制对象表示法(CBOR)[RFC8949]的 CTAP2 规范 CBOR 编码形式进行编码, 如[FIDO-CTAP]中所定义。
- CDDL
- COSE
-
CBOR 对象签名和加密 (COSE) [RFC9052] [RFC9053]。 最初由[RFC8152]建立并由这些 规范更新的 IANA COSE Algorithms 注册表[IANA-COSE-ALGS-REG] 也会使用。
- 凭据管理
-
本文档中描述的 API 是[CREDENTIAL-MANAGEMENT-1]中定义的
Credential概念的扩展。 - DOM
-
DOMException以及本规范中使用的 DOMException 值定义于[DOM4]中。 - ECMAScript
- URL
- Web IDL
-
本规范中的许多接口定义和所有 IDL 都依赖[WebIDL]。此 更新版本的 Web IDL 标准增加了对
Promise的支持,它现在是所有新 Web API 中异步 交互的首选机制。 - FIDO AppID
-
确定调用应用程序的 FacetID以及 确定调用者的 FacetID 是否获得 AppID 授权 的算法(仅用于 AppID 扩展)由[FIDO-APPID]定义。
本文档中的关键词“必须”、“不得”、“必需”、“须”、“不得”、“应该”、“不应该”、“推荐”、 “不推荐”、“可以”和“可选”,仅当 它们像此处所示以全大写形式出现时,才应按照 BCP 14 [RFC2119] [RFC8174]中的描述进行解释。
4. 术语
- 证明
-
通常,证明是用于作证、确认或认证的声明。 在 WebAuthn 上下文中,证明用于提供关于认证器 来源及其所产生数据的可验证证据。其中包括凭据 ID、凭据密钥对、签名 计数器等。
在注册仪式期间,会在证明 对象中提供证明语句。另请参阅§ 6.5 证明 和图 6。客户端是否以及如何将证明语句和 aaguid 部分从证明对象传递给依赖方,由证明传送进行描述。
- 证明证书
-
用于认证器证明其制造来源 和能力的证明密钥对的 X.509 证书。在注册时,认证器使用证明 私钥对 它生成并通过 authenticatorMakeCredential 操作返回的、 特定于依赖 方的凭据公钥(以及附加数据)进行签名。依赖方使用 证明证书中传递的证明公钥来验证证明签名。请注意,在自 证明的情况下, 认证器没有 独立的证明密钥对或证明 证书,详情请参阅自证明。
- 身份验证
- 身份验证仪式
-
一种仪式,其中用户及 用户的客户端 平台(包含或连接到至少一个认证器)协同工作, 以密码学方式向依赖方证明用户控制先前已注册的公钥凭据的凭据私钥(请参阅注册)。请注意,这包括用户 存在性测试或 用户 验证。
WebAuthn 身份验证仪式定义于§ 7.2 验证身份验证断言, 并由依赖方调用带有
publicKey参数的操作发起。 有关介绍性概述,请参阅§ 5 Web 身份验证 API;有关实现示例,请参阅§ 1.3.3 身份验证。navigator.credentials.get() - 身份验证断言
- 断言
-
作为 authenticatorGetAssertion 操作结果,由认证器返回的经过密码学签名的
AuthenticatorAssertionResponse对象。这对应于[CREDENTIAL-MANAGEMENT-1]规范中的一次性 凭据。
- 认证器
- WebAuthn 认证器
-
一种存在于硬件或软件中的密码学实体,可以为给定的依赖方注册用户, 随后断言持有已注册的公钥 凭据,并可选择向依赖方验证 用户。认证器可以在注册 和断言期间,通过证明报告有关其类型和安全特性的信息。
WebAuthn 认证器可以是漫游 认证器、集成到客户端设备中的专用硬件子系统, 或客户端或客户端设备的软件组件。WebAuthn 认证器 不一定局限于在 本地上下文中运行,并且可以在客户端硬件之外的服务器中生成或存储凭据密钥对。
通常,假定一个认证器只有一个用户。 如果多个自然人共享对某个认证器的访问, 那么在该认证器的上下文中,他们被视为代表同一个用户。 如果某个认证器 实现支持多个隔离区中的多个用户, 那么每个隔离区都被视为一个单独的认证器, 其中只有一个用户,并且无法访问其他用户的凭据。
- 授权手势
-
授权手势是用户作为仪式的一部分与认证器进行的物理交互, 例如注册或 身份验证。通过 执行这种授权手势,用户提供 同意,使仪式得以继续(即授权)。如果所使用的认证器具备能力,这可以涉及用户验证,也可以涉及简单的用户 存在性测试。
- 已备份
-
公钥凭据源可以通过某种方式进行备份, 以使其能够出现在不同于其生成认证器的其他认证器上。备份可以通过 包括但不限于点对点同步、 云同步、本地网络同步以及手动导入/导出等机制进行。另请参阅§ 6.1.3 凭据备份状态。
- 备份
资格
- 可 备份
-
公钥凭据源的生成认证器在创建时确定 该公钥凭据源 是否允许被备份。 备份资格与当前备份状态一起,通过认证器数据的标志表示。 备份资格是一项凭据属性,并且对于给定的公钥凭据源而言是永久不变的。 可备份的公钥凭据源称为 多设备 凭据,而不可备份的则称为单设备凭据。另请参阅§ 6.1.3 凭据备份状态。
- 备份状态
-
由当前管理认证器确定的多设备凭据的当前备份状态。 备份状态通过认证器数据的标志表示,并且可以随时间变化。另请参阅 备份 资格和§ 6.1.3 凭据备份状态。
- 生物特征认证器
- 生物特征 识别
-
基于个人的生物和行为特征对其进行自动识别[ISOBiometricVocabulary]。
- 绑定
凭据
- "认证器包含一个 凭据"
- "凭据创建于一个 认证器上"
- "认证器包含一个 凭据"
-
如果一个公钥凭据源或公钥 凭据与其管理认证器绑定,即表示只有该管理认证器能够 为与其绑定的公钥凭据源生成断言。
这也可以表述为“管理认证器 包含该绑定 凭据”, 或“该绑定 凭据创建于其管理认证器上”。 但请注意,服务器端凭据可能并未物理存储在认证器内部的 持久内存中, 因此“绑定到” 是主要术语。 请参阅§ 6.2.2 凭据存储模式。
- 仪式
-
仪式这一概念[Ceremony]是网络 协议概念的扩展,其中除了计算机节点之外还有人类节点,通信链路还包括用户界面、人际 通信以及携带数据的 实体对象传递。对于协议而言属于带外的内容,对于仪式而言属于带内。在 本规范中, 注册和身份验证都是 仪式,而授权手势通常是这些仪式的组成部分。
- 客户端
- WebAuthn 客户端
-
本文中也简称为客户端。另请参阅符合要求的用户代理。WebAuthn 客户端是一种通常 完全或部分实现在用户代理中的中介实体。从概念上讲,它位于Web 身份验证 API之下,并实现
[[Create]](origin, options, sameOriginWithAncestors)和[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)内部方法。它负责 为底层认证器 操作封送输入,并将后者操作的结果返回给Web 身份验证 API的调用者。WebAuthn 客户端 运行在WebAuthn 客户端设备上,并且与其相互独立。
- 客户端
设备
- WebAuthn 客户端设备
-
WebAuthn 客户端运行所在的硬件设备,例如智能手机、笔记本 电脑或台式计算机,以及在该硬件上运行的 操作系统。
WebAuthn 客户端设备与客户端之间的区别是:
- 客户端 平台
-
客户端设备和 客户端共同组成客户端平台。 单个硬件设备可以通过运行不同的操作系统和/或客户端,在不同时间成为多个 不同客户端 平台的一部分。
- 客户端侧
- 客户端可发现公钥
凭据源
- 客户端可发现凭据
- 可发现凭据
- 通行密钥
- [已弃用] 驻留凭据
- [已弃用] 驻留密钥
- 客户端可发现凭据
-
注:在历史上,客户端可发现凭据曾被称为驻留凭据或驻留密钥。 由于
ResidentKey和residentKey这两个短语在 WebAuthn API以及认证器模型中都被广泛使用(例如用于字典成员名称、 算法变量名称以及 操作参数),为了向后兼容,它们名称中的resident用法没有改变。此外,术语驻留密钥在此定义为 等同于客户端可发现凭据。客户端可发现 公钥凭据源,简称可发现凭据, 是一种具有可发现性并可用于身份验证 仪式的公钥凭据源, 在这些仪式中,依赖 方不提供任何凭据 ID, 即依赖 方调用
navigator.credentials.get()时传入一个空的allowCredentials参数。这意味着依赖方不一定需要先识别用户。因此,支持可发现凭据的认证器只需给定一个RP ID, 就可以为可发现凭据生成断言签名, 这进而要求公钥凭据源 存储在认证器或客户端平台中。 这与服务器端公钥凭据 源不同, 后者要求同时向认证器提供RP ID和凭据 ID, 但不要求在客户端存储公钥 凭据源。
注:客户端可发现凭据也可用于提供了凭据 ID的身份验证仪式, 即调用
navigator.credentials.get()时传入非空的allowCredentials参数。 - 符合要求的 用户代理
-
一种与底层客户端设备协作实现Web 身份验证 API以及本规范给出的算法,并处理认证器与依赖方之间通信的用户代理。
- 凭据 ID
-
一个概率唯一的字节序列, 用于标识公钥凭据源及其身份验证断言。最长为 1023 字节。
凭据 ID 由认证器以两种形式之一生成:
- 凭据
密钥对
- 凭据私钥
- 凭据 公钥
- 用户公 钥
- 凭据私钥
-
凭据 密钥对是由认证器生成并限定作用域于特定WebAuthn 依赖方的一对非对称密码密钥。它是公钥 凭据的核心部分。
凭据公钥是凭据 密钥对中的公钥部分。 在注册仪式期间,凭据公钥会返回给依赖方。
凭据私钥是凭据密钥 对中的私钥部分。 凭据私钥绑定到特定的认证器——即其 管理认证器—— 并且预期永远不会暴露给任何其他方,甚至不会暴露给该认证器的所有者。
请注意,在自证明的情况下,凭据密钥对也被用作 证明密钥对,详情请参阅自证明。
注:凭据公钥在 FIDO UAF [UAFProtocol]以及 FIDO U2F [FIDO-U2F-Message-Formats]和本规范中与其相关的某些部分中 被称为用户 公钥。
- 凭据 属性
- 凭据 记录
-
为了实现§ 7 WebAuthn 依赖 方操作中定义的算法, 依赖方 必须存储已注册公钥 凭据源的一些属性。 凭据 记录结构是存储在用户帐户中的这些属性的抽象。 凭据记录在注册仪式期间创建,并在后续身份验证仪式中使用。 依赖方可以 根据需要或应用户请求删除凭据记录。
为了完整实现所定义的 § 7.1 注册新凭据和§ 7.2 验证身份验证断言的所有步骤,推荐以下项:
- type
- id
- publicKey
- signCount
- transports
-
当公钥凭据源被注册时,
getTransports()返回的值。注:修改或删除
getTransports()返回值中的项可能会对用户体验产生负面影响,甚至阻止使用对应的 凭据。 - uvInitialized
-
一个 Boolean 值,指示来自此公钥 凭据源的任何凭据 是否曾设置UV标志。
当其为
true时,依赖方可以在身份验证 仪式中将UV标志 视为一个身份验证因素。 例如,当uvInitialized 为true且设置了UV标志时,即使未要求用户验证,依赖方也可以跳过密码提示。当其为
false时,包括在某个会将其更新为true的身份验证 仪式中, 不得将UV 标志 依赖为身份验证因素。 这是因为公钥 凭据源第一次将UV标志设置为 1 时, 依赖方与认证器的用户验证之间 尚未建立任何信任关系。 因此,将uvInitialized从false更新为true应该要求使用一个等同于 WebAuthn 用户 验证的附加身份验证因素进行授权。 - backupEligible
- backupState
以下项是可选的:
- attestationObject
-
当公钥凭据源被注册时,
attestationObject属性的值。 存储此值使依赖方能够在以后引用该凭据的证明语句。 - attestationClientDataJSON
-
当公钥凭据源被注册时,
clientDataJSON属性的值。 将此值与上面的attestationObject项一起存储, 使依赖方能够在以后重新验证证明 签名。 - rpId
-
在凭据注册期间的
create()操作中指定的参数的值。 此值是决定凭据可以在哪里使用的核心属性。 在注册时存储此值可以在将来提供帮助,例如审核其使用情况、 排查使用它进行身份验证时的问题,或以后通过相关源 在不同域之间使用它。rp.id
WebAuthn 扩展可以定义处理扩展所需的附加项。 依赖方也可以 根据需要包含任何附加项, 并且可以省略其实现不需要的任何项。
凭据记录的凭据描述符是一个具有以下内容的
PublicKeyCredentialDescriptor值: - 生成认证器
-
生成认证器是参与authenticatorMakeCredential 操作并由此 创建给定公钥凭据源的认证器。对于单设备凭据,生成认证器与管理认证器相同。 对于多设备凭据,生成认证器 可能与参与给定身份验证操作的当前管理认证器相同,也可能不同。
- 人类友好性
-
一个具有人类友好性的标识符旨在让典型的人类 用户能够记住并复现,与例如随机生成的位序列之类的标识符不同[EduPersonObjectClassSpec]。
- 不可发现凭据
-
这是一种凭据,由于它不是客户端可发现的,因此调用
navigator.credentials.get()时,必须在allowCredentials中提供其凭据 ID。另请参阅服务器端凭据。 - 可注册源标签
-
一个域的可注册域中的第一个域标签, 如果可注册域为 null,则为 null。 例如,如果
co.uk和de都是公共 后缀, 那么example.co.uk和www.example.de的可注册源标签都是example。 - 公钥 凭据
-
一般而言,凭据是一种实体向另一个实体出示的数据,用于向后者 认证前者 [RFC4949]。术语公钥凭据 指以下之一:公钥凭据源、与公钥凭据源对应的可能经过证明的凭据公钥,或者 身份验证断言。具体所指通常由上下文确定。
注: 这是对[RFC4949]的有意违反。在英语中, “credential”既是 a) 为证明某项陈述而出示的东西,也是 b) 预期可多次使用的东西。在公钥系统中,不可能使用单一 数据片段安全地同时满足这两个条件。[RFC4949]选择将 credential 定义为可多次使用的 东西(公钥),而本规范则赋予“credential”英语术语本身的灵活性。本规范 使用更具体的术语来标识与[RFC4949] credential 相关的数据:在注册时, 认证器 创建一个非对称密钥对,并将其私钥部分以及 来自依赖方的信息存储到公钥 凭据源中。公钥部分返回给依赖方,后者 随后将其存储在活动的用户帐户中。 此后,只有由其RP ID标识的该依赖方能够通过
get()方法在身份验证 仪式中使用该公钥凭据。 依赖 方使用其存储的 凭据公钥副本来验证产生的身份验证断言。 - 公钥凭据源
-
一种由认证器用于 生成身份验证断言的凭据源([CREDENTIAL-MANAGEMENT-1])。公钥 凭据源由一个包含以下项的结构组成:
- type
-
其值的类型为
PublicKeyCredentialType, 默认为public-key。 - id
-
一个凭据 ID。
- privateKey
-
凭据私钥。
- rpId
- userHandle
- otherUI
-
认证器用于向其 UI 提供信息的其他可选信息。例如,这可能 包括用户的
displayName。 otherUI是一个可变项,并且 不应该以会阻止otherUI被更新的方式将其绑定到 公钥凭据源。
authenticatorMakeCredential 操作创建一个与管理认证器绑定的公钥凭据源,并 返回与其凭据私钥相关联的凭据公钥。依赖方可以使用此凭据公钥来验证 此公钥凭据源创建的身份验证断言。
- 速率 限制
-
认证器通过限制 给定时间段内连续失败的身份验证尝试次数来实现针对暴力 攻击控制的过程(也称为节流)。如果达到限制, 认证器应该施加随每次连续尝试呈指数增长的延迟,或者 禁用当前 身份验证模式,并在可用时提供不同的身份验证 因素。速率限制通常作为用户 验证的一部分来实现。
- 注册
- 注册仪式
-
一种仪式,其中用户、依赖方以及 用户的客户端 平台(包含或连接到至少一个 认证器)协同 创建公钥凭据并将其与用户帐户关联。 请注意,这包括采用用户存在性测试或用户验证。 成功完成注册仪式后,可以通过身份验证仪式对用户进行身份验证。
WebAuthn 注册仪式定义于§ 7.1 注册新凭据, 并由依赖方调用带有
publicKey参数的操作发起。 有关介绍性概述,请参阅§ 5 Web 身份验证 API;有关实现示例,请参阅§ 1.3.1 注册。navigator.credentials.create() - 依赖
方
- WebAuthn 依赖方
-
其Web 应用程序利用Web 身份验证 API来注册和 验证用户身份的实体。
依赖方 实现通常由两部分组成:一部分是在客户端中调用Web 身份验证 API的客户端脚本, 另一部分是执行依赖方 操作和其他应用程序逻辑的服务器端组件。 两个组件之间的通信必须使用 HTTPS 或等效的传输安全机制, 但除此之外不属于本规范的范围。
注:虽然术语依赖方也经常用于其他 上下文(例如 X.509 和 OAuth),但在某个 上下文中充当依赖方的实体不一定在其他上下文中也是依赖方。在本规范中, 术语WebAuthn 依赖方通常简称为依赖 方,并明确指 WebAuthn 上下文中的依赖方。请注意,在任何具体实例中, WebAuthn 上下文都可能嵌入更广泛的整体上下文中,例如基于 OAuth 的上下文。
- 依赖
方标识符
- RP ID
-
在WebAuthn API的上下文中,依赖方 标识符是一个有效 域字符串,用于标识代表其执行给定注册或身份验证 仪式的WebAuthn 依赖方。公钥凭据只能用于与注册它时相同的实体(由RP ID标识)进行身份验证。
默认情况下,WebAuthn 操作的RP ID设置为调用者源的有效域。调用者可以覆盖此默认值,只要 调用者指定的RP ID值是调用者 源的有效域的可注册域后缀或与其相等。另请参阅 § 5.1.3 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 内部方法和 § 5.1.4 使用现有凭据生成断言。
RP ID基于主机的域名。 它本身不包含方案或端口,而 源包含这些内容。 公钥凭据的RP ID决定其作用域。 即,它决定 可以使用该公钥凭据的源集合,如下所示:
-
以下条件之一必须为真:
例如,对于源为
https://login.example.com:1337的依赖方,以下RP ID有效:login.example.com(默认值)和example.com,但m.login.example.com和com无效。 另一个有效源示例是http://localhost:8000,因为该源为localhost。这样做是为了匹配广泛部署的环境凭据(例如 Cookie、[RFC6265])的行为。 请注意,与 document.domain 的 setter 所提供的相比,这对“同源”限制的放宽程度更大。
这些对源值的限制适用于WebAuthn 客户端。
其他模仿WebAuthn API、用于在非 Web 平台(例如原生移动应用程序)上启用 WebAuthn 公钥凭据的规范, 可以定义将调用者绑定到依赖方标识符的不同规则。但是,RP ID语法必须符合 有效域字符串或 URI [RFC3986] [URL]。
- 服务器端公钥凭据源
- 服务器端凭据
- [已弃用] 非驻留凭据
- 服务器端凭据
-
注:在历史上,服务器端凭据 曾被称为非驻留凭据。 为了向后兼容,名称中包含各种形式
resident的各种WebAuthn API和 认证器 模型组件 均未更改。服务器端公钥凭据 源,简称服务器端凭据, 是一种只有在依赖 方将其凭据 ID提供给
navigator.credentials.get()的allowCredentials参数时,才能在身份验证仪式 中使用的公钥凭据源。这意味着依赖方必须 管理该凭据的存储和发现,并且还必须能够先识别用户,以便 找到要提供给navigator.credentials.get()调用的凭据 ID。服务器端凭据不要求在客户端存储公钥凭据源。 这与客户端可发现凭据不同, 后者不要求先识别用户即可将用户的凭据 ID 提供给
navigator.credentials.get()调用。另请参阅:服务器端凭据存储模式 和不可发现凭据。
- 用户 存在性测试
-
用户 存在性测试是一种简单形式的授权手势和技术过程,其中用户 通过(通常)简单触摸认证器与其交互(也可能存在其他方式),并产生 Boolean 结果。请注意, 这并不构成用户验证,因为根据定义,用户存在性测试 不能进行生物特征识别,也不涉及 提供密码或 PIN 等共享秘密。
- 用户帐户
-
在本规范的上下文中, 用户帐户表示 一组凭据[CREDENTIAL-MANAGEMENT-1] 与由依赖方维护并授权的依赖方资源的一个(子)集之间的映射。 依赖方 通过为凭据的用户句柄分配一个特定于用户 帐户的值,并在用户帐户中为该凭据存储凭据记录,从而将给定公钥凭据映射到用户帐户。 此映射、凭据集合及其授权可能会随时间变化。 根据用户以及依赖方的操作,一个给定的用户帐户 可能由一个或多个自然人(也称为“用户”)访问, 而一个自然人也可能访问一个或多个用户帐户。
- 用户同意
- 用户句柄
-
用户句柄是用户帐户的标识符,由依赖方在注册期间指定为
。 可发现凭据存储此标识符,并且在以空user.id参数开始的身份验证仪式中,必须将其作为allowCredentials返回。response.userHandle用户 句柄的主要用途是在此类身份验证 仪式中标识用户帐户, 但也可以改用凭据 ID。 二者的主要区别是, 凭据 ID由认证器选择,并且对于每个凭据都是唯一的, 而用户句柄由依赖 方选择,并且对于注册到同一用户帐户的所有凭据都应该相同。
认证器将RP ID与用户句柄的组合映射到公钥 凭据源。 因此,一个认证器对于每个依赖方的每个用户 句柄,最多存储一个可发现 凭据。因此, 用户 句柄的第二个用途,是让认证器知道在注册仪式期间何时应该 用新的可发现凭据 替换现有凭据。
用户句柄是一个不透明的字节 序列,最大长度为 64 字节,并且不用于向用户显示。 它不得包含个人身份信息,请参阅§ 14.6.1 用户句柄内容。
- 用户 在场
- 用户 验证
-
一种技术过程,通过该过程,认证器在本地授权调用 authenticatorMakeCredential 和authenticatorGetAssertion 操作。用户 验证可以通过 各种授权手势方式发起;例如,通过 触摸加 PIN 码、输入密码,或者 生物特征 识别(例如出示指纹)[ISOBiometricVocabulary]。其目的是 区分不同的个体用户。 另请参阅§ 6.2.3 身份验证因素 能力。
请注意,用户 验证不会向依赖方提供用户的具体身份, 但是,当使用该凭据执行了 2 次或更多次带有用户验证的仪式时, 它表示执行所有这些仪式的是同一用户。 但如果多个自然人共享对同一认证器的访问, 则同一用户并不总是意味着同一自然人。
注:区分自然人在很大程度上取决于客户端平台 和认证器的 能力。 例如,一些设备设计为供单个人使用, 但它们可能允许多个自然人录入指纹或知道同一个 PIN, 从而使用该设备访问同一个用户帐户。
注:调用authenticatorMakeCredential 和authenticatorGetAssertion 操作 意味着使用由认证器管理的密钥材料。
- 用户 已验证
5. Web 身份验证 API
本节以规范性方式规定了用于创建和使用公钥凭据的 API。其基本 思路是,凭据属于用户,并由管理它们的WebAuthn 认证器管理,WebAuthn 依赖方通过客户端平台与其交互。依赖方脚本可以 (在获得用户同意后) 请求 浏览器创建一个新凭据,供依赖方将来使用。请参阅下面的图 。
脚本还可以请求用户许可,以使用现有凭据执行 身份验证操作。 请参阅下面的图 。
所有这些操作都在认证器中执行,并由 客户端平台代表 用户进行协调。脚本在任何时候都无法访问凭据本身;它只能 以对象形式获取有关凭据的信息。
除上述脚本接口外,认证器还可以实现(或附带实现了)用于管理的用户 界面的客户端软件。例如,可以使用这种界面将认证器重置为干净 状态,或者检查 认证器的当前状态。换言之,这种界面类似于浏览器 提供的用于管理历史记录、已保存密码和 Cookie 等用户状态 的用户界面。凭据 删除等认证器管理操作被视为此类用户界面的职责,因此有意从 暴露给 脚本的 API 中省略。
此 API 的安全属性由客户端和认证器协同提供。认证器 持有并管理凭据,并确保 所有操作都限定作用域于特定源,并且无法针对 不同的源进行重放,这是通过在其响应中纳入源来实现的。具体而言,如§ 6.3 认证器操作中所定义, 请求者的完整源会被包含并纳入签名,无论是在创建新凭据时 生成的证明对象中,还是在 WebAuthn 凭据产生的所有断言中。
此外,为维护用户隐私,并防止恶意依赖方探测属于其他依赖方的公钥 凭据是否存在,每个凭据还会限定作用域于一个依赖方标识符,即 RP ID。客户端会在所有操作中将此RP ID提供给认证器,并且 认证器确保由某个依赖方创建的凭据 只能用于由相同RP ID请求的操作。以这种方式将 源与RP ID分离,使该 API 可以用于 单个依赖方 维护多个源的情况。
客户端通过在每次操作中向认证器提供依赖方的源和RP 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]]内部槽中所含数据的base64url 编码。 rawId-
此属性返回
[[identifier]]内部槽中包含的ArrayBuffer。 response, 类型为AuthenticatorResponse,只读-
此属性包含认证器对客户端创建公钥凭据或生成身份验证断言请求的响应。如果
PublicKeyCredential是响应create()而创建的,则此属性的值将为AuthenticatorAttestationResponse; 否则,PublicKeyCredential是响应get()而创建的,并且此属性的值 将为AuthenticatorAssertionResponse。 authenticatorAttachment, 类型为DOMString,只读,可为 null-
此属性报告在
navigator.credentials.create()或navigator.credentials.get()方法成功完成时有效的认证器附着模式。 此属性的值应该是AuthenticatorAttachment的成员。 依赖方 应该将未知值 视为该值为 null。 getClientExtensionResults()-
此操作返回
[[clientExtensionsResults]]的值,它是一个映射,包含由扩展的 客户端扩展处理产生的 扩展 标识符 → 客户端扩展输出条目。 isConditionalMediationAvailable()-
PublicKeyCredential覆盖此方法,以指示在navigator.credentials.get()期间conditional中介是否可用。 WebAuthn 依赖方在尝试将options.设置为mediationconditional之前,应该验证其可用性。调用后,将返回一个 promise;如果
conditional用户中介可用,则该 promise 以true值兑现,否则以false兑现。此方法没有参数,并返回一个以 Boolean 值兑现的 promise。
conditionalGet能力等同于此 promise 以true兑现。注:如果不存在此方法,则
conditional用户中介不可用于navigator.credentials.get()。注:此方法并不指示
conditional用户中介是否可用于navigator.credentials.create()。 对于后者,请参阅getClientCapabilities()中的conditionalCreate能力。 toJSON()-
此操作返回
RegistrationResponseJSON或AuthenticationResponseJSON, 它们是镜像PublicKeyCredential的JSON 类型表示形式, 适合作为application/json载荷提交给 依赖方服务器。 客户端负责 像通常一样将值序列化为 JSON 类型, 但必须采取额外步骤,先使用base64url 编码将任何ArrayBuffer值编码为DOMString值。RegistrationResponseJSON.clientExtensionResults或AuthenticationResponseJSON.clientExtensionResults成员必须设置为getClientExtensionResults()的输出,其中任何ArrayBuffer值都使用 base64url 编码编码为DOMString值。这可以包括来自在 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]中注册、但未在§ 9 WebAuthn 扩展中定义的扩展的ArrayBuffer值。AuthenticatorAttestationResponseJSON.transports成员必须设置为getTransports()的输出。AuthenticatorAttestationResponseJSON.publicKey成员必须设置为getPublicKey()的输出。AuthenticatorAttestationResponseJSON.publicKeyAlgorithm成员必须设置为getPublicKeyAlgorithm()的输出。
typedef DOMString ; // 此对象的结构将为 // RegistrationResponseJSON 或 AuthenticationResponseJSONBase64URLString 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 >; // 如果 pubKeyCredParams 用于协商用户代理不理解的 // 公钥算法,则 publicKey 字段将缺失。(有关用户代理必须 // 支持哪些算法的列表,请参阅“轻松访问凭据数据” // 一节。)如果使用这种算法,则必须直接从 // attestationObject 或 authenticatorData 中解析公钥。transports Base64URLString ;publicKey required COSEAlgorithmIdentifier ; // 此值包含上面某些字段的副本。请参阅 // “轻松访问凭据数据”一节。publicKeyAlgorithm required Base64URLString ; };attestationObject dictionary {AuthenticationResponseJSON required DOMString ;id required Base64URLString ;rawId required AuthenticatorAssertionResponseJSON ;response DOMString ;authenticatorAttachment required AuthenticationExtensionsClientOutputsJSON ;clientExtensionResults required DOMString ; };type dictionary {AuthenticatorAssertionResponseJSON required Base64URLString ;clientDataJSON required Base64URLString ;authenticatorData required Base64URLString ;signature Base64URLString ; };userHandle dictionary { };AuthenticationExtensionsClientOutputsJSON
[[type]]-
PublicKeyCredential接口对象的[[type]]内部槽的值是字符串 "public-key"。注:这通过继承自
Credential的type属性 getter 体现出来。 [[discovery]][[identifier]]-
此内部槽包含由认证器选择的凭据 ID。 凭据 ID 用于查找要使用的凭据,因此预期在所有认证器上的同类型所有凭据中 具有很高概率的全局唯一性。
此 API 不限制此标识符的格式, 但它不得长于 1023 字节,并且必须足以让认证器 唯一选择一个密钥。 例如,没有板载存储的认证器可以创建包含凭据私钥的标识符, 该私钥使用烧录到认证器中的对称密钥进行封装。
[[clientExtensionsResults]]-
此内部槽包含在依赖方调用
navigator.credentials.create()或navigator.credentials.get()时,对依赖方请求的客户端扩展进行处理的结果。
PublicKeyCredential
的
接口对象继承 Credential
对
[[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors)
的实现,并为以下每个方法定义自己的
实现:[[Create]](origin, options, sameOriginWithAncestors)、
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
和
[[Store]](credential, sameOriginWithAncestors)。
调用 CredentialsContainer
的
preventSilentAccess()
方法
不会对 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.
创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors)
内部方法
PublicKeyCredential
的
接口对象对 [[Create]](origin, options, sameOriginWithAncestors)
内部方法的实现[CREDENTIAL-MANAGEMENT-1]允许
WebAuthn
依赖方脚本调用 navigator.credentials.create()
来请求创建一个新的、与认证器绑定的
公钥凭据源。
通过将
options.
设置为 mediationconditional,
依赖方可以
表示,如果用户已经同意创建凭据,则希望在没有显著模态 UI 的情况下注册凭据。
依赖方应该
首先使用 getClientCapabilities()
检查客户端是否支持
conditionalCreate
能力,
以防止该功能不可用时出现用户可见的错误。
当
options.
设置为 mediationconditional
时,客户端必须将 requireUserPresence 和 requireUserVerification 两者都设置为
FALSE,除非它们可以在仪式期间显式执行。
任何 navigator.credentials.create()
操作都可以利用 AbortController
中止;详细说明请参阅DOM § 3.3
在 API 中使用
AbortController 和 AbortSignal 对象。
此内部方法接受三个 参数:
originoptions-
此参数是一个
CredentialCreationOptions对象,其options.成员包含一个publicKeyPublicKeyCredentialCreationOptions对象,用于指定待创建公钥 凭据的期望属性。 sameOriginWithAncestors-
此参数是一个 Boolean 值,当且仅当调用者的环境设置对象与 其祖先同源时为
true。如果调用者是跨源的,则为false。注:调用此内部方法表示 它已被 权限策略允许,该策略在[CREDENTIAL-MANAGEMENT-1]层级进行评估。 请参阅§ 5.9 权限策略集成。
注:此算法是
同步的:Promise
的兑现/拒绝由
navigator.credentials.create()
处理。
此算法中使用的所有 BufferSource
对象都必须在算法开始时创建快照,以
避免潜在的同步问题。实现应该获取缓冲区源所持字节的副本,并
在算法的相关部分中使用该副本。
调用此方法时,用户代理必须执行以下算法:
-
断言:
options.存在。publicKey -
如果 sameOriginWithAncestors 为
false:-
如果
options.存在且值为mediationconditional:-
抛出一个 "
NotAllowedError"DOMException
-
-
如果由调用
create()的实现所确定的相关全局对象没有 瞬态激活:-
抛出一个 "
NotAllowedError"DOMException。
-
-
如果正在创建凭据的源与相关全局对象的顶层源不同 (即,与用户可在地址栏中看到的源不同), 客户端应该向 用户明确说明这一事实。
-
-
令 pkOptions 为
options.的值。publicKey -
如果
pkOptions.存在,则检查其值是否位于由客户端定义的合理范围内;如果不在,则将其修正为该范围内 最接近的值。将计时器 lifetimeTimer 设置为此调整后的值。如果timeoutpkOptions.不 存在,则将 lifetimeTimer 设置为客户端特定的默认值。timeout有关决定合理范围和默认值的指导,请参阅WebAuthn 仪式超时的推荐范围 和默认值, 以确定
pkOptions.的合理范围和默认值。timeout客户端应该考虑有特殊需要用户的超时相关 认知指南。
-
如果
pkOptions.的长度不在 1 到 64 字节之间(含边界),则抛出一个user.idTypeError。 -
令 callerOrigin 为
origin。 如果 callerOrigin 是不透明源,则抛出一个 "NotAllowedError"DOMException。 -
令 effectiveDomain 为 callerOrigin 的有效域。 如果有效域不是有效域,则抛出一个 "
SecurityError"DOMException。注:有效域可以解析为一个主机,其可以用各种方式表示, 例如域、IPv4 地址、 IPv6 地址、不透明主机或 空主机。 此处只允许主机的域格式。这既是为了简化,也是 考虑到将直接 IP 地址标识与基于 PKI 的安全机制结合使用存在的各种问题。
-
- 存在
-
如果
pkOptions.既不是 effectiveDomain 的可注册域后缀,也不等于 effectiveDomain,并且客户端rp.id- 支持相关源请求
-
-
以 callerOrigin 和 rpIdRequested 为参数运行相关 源验证过程。 如果结果为
false,则抛出一个 "SecurityError"DOMException。
- 不支持相关源请求
-
抛出一个 "
SecurityError"DOMException。
- 不存在
注:
pkOptions.表示 调用者的RP ID。除非调用者在调用rp.idcreate()时显式设置了pkOptions., 否则RP ID默认为调用者源的 有效域。rp.id -
令 credTypesAndPubKeyAlgs 为一个新的列表,其项为
PublicKeyCredentialType与COSEAlgorithmIdentifier的配对。 -
如果
pkOptions.的 大小pubKeyCredParams- 为零
-
将以下
PublicKeyCredentialType和COSEAlgorithmIdentifier值的配对追加到 credTypesAndPubKeyAlgs:-
public-key和-7("ES256")。 -
public-key和-257("RS256")。
-
- 非零
-
对于
pkOptions.中的每个 current:pubKeyCredParams-
如果
current.不包含此实现支持的typePublicKeyCredentialType, 则继续。 -
令 alg 为
current.。alg
如果 credTypesAndPubKeyAlgs为空, 则抛出一个 "
NotSupportedError"DOMException。 -
-
令 clientExtensions 为一个新的映射,并令 authenticatorExtensions 为一个新的映射。
-
如果
pkOptions.存在,则对于extensionspkOptions.中的每个 extensionId → clientExtensionInput:extensions -
令 collectedClientData 为一个新的
CollectedClientData实例,其字段如下:type-
字符串 "webauthn.create"。
challenge-
pkOptions.
challenge的base64url 编码。 origin-
callerOrigin 的序列化。
crossOrigin-
传递给此内部方法的
sameOriginWithAncestors参数值的反值。 topOrigin-
如果传递给此内部方法的
sameOriginWithAncestors参数为false,则为 callerOrigin 的顶层源的序列化,否则为undefined。
- 令 clientDataJSON 为由 collectedClientData 构造的客户端数据的 JSON 兼容 序列化。
-
令 clientDataHash 为由 clientDataJSON 表示的序列化客户端数据的 哈希。
-
令 issuedRequests 为一个新的有序集合。
-
令 authenticators 表示一个值,该值在任意给定时刻都是一个集合,由客户端平台特定的句柄组成,其中每个 项标识当时此客户端 平台上当前可用的一个认证器。
注:什么条件可使认证器 被视为“可用”是有意未规定的;这里旨在表示认证器 可通过各种机制热插拔到 (例如通过 USB) 客户端中,或被其发现 (例如通过 NFC 或 Bluetooth),也可以永久内置于客户端中。
-
如果
options.存在且值为mediationconditional:-
如果用户代理最近没有协调过一次身份验证、该身份验证的源不是 callerOrigin,或者用户 不同意这种类型的凭据创建,则抛出一个 "
NotAllowedError"DOMException。由用户代理自行决定何时认为身份验证仪式已经 完成。该身份验证仪式可以通过 Web 身份验证 API以外的其他方式执行。
-
-
考虑
hints的值,并按用户代理认为合适的方式相应构建用户界面。 -
启动 lifetimeTimer。
-
在 lifetimeTimer 尚未到期时,循环执行以下操作,具体取决于 lifetimeTimer,
以及 authenticators 中每个
authenticator 的状态和响应:
- 如果 lifetimeTimer 到期,
-
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用authenticatorCancel 操作, 并从 issuedRequests 中移除 authenticator。
- 如果用户使用用户代理的用户界面选项取消该过程,
-
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用authenticatorCancel 操作, 并从 issuedRequests 中移除 authenticator。抛出一个 "
NotAllowedError"DOMException。 - 如果
options.存在且已中止,signal -
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用authenticatorCancel 操作,并从 issuedRequests 中移除 authenticator。然后抛出
options.的 中止原因。signal - 如果某个 authenticator 在此客户端设备上变得可用,
-
注:这包括 authenticator 在 lifetimeTimer 启动时已经可用的情况。
-
此 authenticator 现在是候选认证器。
-
如果
pkOptions.存在:authenticatorSelection-
如果
pkOptions.存在, 且其值不等于 authenticator 的认证器 附着模式,则继续。authenticatorSelection.authenticatorAttachment -
如果
pkOptions.authenticatorSelection.residentKey- 存在且设置为
required -
如果 authenticator 无法存储客户端 可发现公钥凭据源,则继续。
- 存在且设置为
preferred或discouraged -
无影响。
- 不存在
-
如果
pkOptions.设置为authenticatorSelection.requireResidentKeytrue,且 authenticator 无法存储客户端 可发现公钥凭据源,则继续。
- 存在且设置为
-
如果
pkOptions.设置为authenticatorSelection.userVerificationrequired, 且 authenticator 无法执行用户验证,则继续。
-
-
令 requireResidentKey 为凭据创建的有效 驻留密钥要求,它是一个 Boolean 值,如下:
如果
pkOptions.authenticatorSelection.residentKey- 存在且设置为
required -
令 requireResidentKey 为
true。 - 存在且设置为
preferred -
如果 authenticator
- 具备客户端 凭据存储模式能力
-
令 requireResidentKey 为
true。 - 不具备客户端 凭据存储模式能力,或者客户端无法确定认证器能力,
-
令 requireResidentKey 为
false。
- 存在且设置为
discouraged -
令 requireResidentKey 为
false。 - 不存在
-
令 requireResidentKey 为
pkOptions.的值。authenticatorSelection.requireResidentKey
- 存在且设置为
-
令 userVerification 为凭据创建的有效 用户验证要求,它是一个 Boolean 值,如下。如果
pkOptions.authenticatorSelection.userVerification- 设置为
required -
-
如果
options.设置为mediationconditional且在仪式期间无法收集用户验证, 则抛出一个ConstraintErrorDOMException。 -
令 userVerification 为
true。
-
- 设置为
preferred -
如果 authenticator
- 设置为
discouraged -
令 userVerification 为
false。
- 设置为
-
令 enterpriseAttestationPossible 为一个 Boolean 值,如下。如果
pkOptions.attestation- 设置为
enterprise -
如果用户代理希望为
pkOptions.支持企业证明(请参阅上面的步骤 8),则令 enterpriseAttestationPossible 为rp.idtrue。 否则为false。 - 否则
-
令 enterpriseAttestationPossible 为
false。
- 设置为
-
令 attestationFormats 为一个字符串列表,初始化为
pkOptions.的值。attestationFormats -
如果
pkOptions.attestation- 设置为
none -
将 attestationFormats 设置为仅包含字符串 “none” 的单元素列表
- 设置为
-
令 excludeCredentialDescriptorList 为一个新的列表。
-
对于
pkOptions.中的每个凭据描述符 C:excludeCredentials-
如果
C.非空,且 authenticator 通过未在transportsC.中提及的传输方式连接,则客户端可以继续。transports注:如果客户端 选择继续,并且
C.中的传输提示不准确,则这可能导致无意中注册多个与同一个认证器绑定的凭据。 例如,由于软件升级增加新的连接选项,已存储的传输提示可能变得不准确。transports -
否则,将 C追加到 excludeCredentialDescriptorList。
-
在 authenticator 上调用authenticatorMakeCredential 操作,并将 clientDataHash、
pkOptions.、rppkOptions.、 requireResidentKey、 userVerification、 credTypesAndPubKeyAlgs、 excludeCredentialDescriptorList、 enterpriseAttestationPossible、 attestationFormats 和 authenticatorExtensions 作为参数。user
-
-
将 authenticator追加到 issuedRequests。
-
- 如果某个 authenticator 在此客户端 设备上变得不可用,
-
从 issuedRequests 中移除 authenticator。
- 如果任何 authenticator 返回表示用户取消操作的状态,
-
-
从 issuedRequests 中移除 authenticator。
-
对于 issuedRequests 中剩余的每个 authenticator, 在 authenticator 上调用authenticatorCancel 操作,并从 issuedRequests 中移除它。
注:认证器可能返回“用户取消了整个操作”的指示。 用户代理如何向用户呈现此状态未作规定。
-
- 如果任何 authenticator 返回等同于 "
InvalidStateError" 的错误状态, -
-
从 issuedRequests 中移除 authenticator。
-
对于 issuedRequests 中剩余的每个 authenticator, 在 authenticator 上调用authenticatorCancel 操作,并从 issuedRequests 中移除它。
-
抛出一个 "
InvalidStateError"DOMException。
注:此错误状态会单独处理, 因为只有当 excludeCredentialDescriptorList 标识了一个与 authenticator绑定的凭据,并且 用户已同意该操作时, authenticator 才会返回它。鉴于存在这种明确同意, 允许依赖方区分这种情况。
-
- 如果任何 authenticator 返回不等同于 "
InvalidStateError" 的错误状态, -
从 issuedRequests 中移除 authenticator。
注:这种情况并不意味着用户对 该操作作出了同意, 因此会向依赖方隐藏错误详情,以防泄露潜在的身份识别信息。 详情请参阅§ 14.5.1 注册仪式隐私。
- 如果任何 authenticator 指示成功,
-
-
从 issuedRequests 中移除 authenticator。此认证器现在是选定认证器。
-
令 credentialCreationData 为一个结构, 其项如下:
-
attestationObjectResult -
其值是成功执行authenticatorMakeCredential 操作返回的字节。
注:此值是
attObj,如§ 6.5.4 生成 证明对象中所定义。 -
clientDataJSONResult -
其值为 clientDataJSON 的字节。
-
attestationConveyancePreferenceOption -
其值为 pkOptions.
attestation的值。 -
clientExtensionResults -
其值为一个
AuthenticationExtensionsClientOutputs对象,包含扩展标识符 → 客户端扩展输出 条目。这些条目通过对pkOptions.中的每个客户端扩展运行各扩展的 客户端扩展 处理算法,以创建客户端扩展输出。extensions
-
-
令 constructCredentialAlg 为一个接受全局对象 global 的算法,其步骤如下:
-
如果
credentialCreationData.attestationConveyancePreferenceOption的值为none-
将潜在可唯一识别身份的信息替换为 相同信息的不可识别身份版本:
-
如果经证明的 凭据数据中的aaguid 为 16 个零字节,
credentialCreationData.attestationObjectResult.fmt为 "packed",且credentialCreationData.attestationObjectResult中不存在 "x5c", 则正在使用自证明, 无需进一步操作。 -
否则:
-
将
credentialCreationData.attestationObjectResult.fmt的值设置为 "none",并将credentialCreationData.attestationObjectResult.attStmt的值设置为空CBOR 映射。(请参阅§ 8.7 无证明语句格式和§ 6.5.4 生成证明对象)。
-
-
indirect-
客户端可以将aaguid 和证明 语句替换为相同数据的、更有利于隐私 和/或更容易验证的版本(例如,通过使用匿名化 CA)。
direct或enterprise
-
令 attestationObject 为一个新的
ArrayBuffer, 使用 global 的%ArrayBuffer% 创建,其中包含credentialCreationData.attestationObjectResult值的字节。 -
令 id 为
attestationObject.authData.attestedCredentialData.credentialId。 -
令 pubKeyCred 为一个与 global 关联的新
PublicKeyCredential对象,其字段如下:[[identifier]]-
id
authenticatorAttachment-
与 authenticator 当前认证器 附着模式相匹配的
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的字节。
-
返回 pubKeyCred。
-
-
对于 issuedRequests 中剩余的每个 authenticator, 在 authenticator 上调用authenticatorCancel 操作,并从 issuedRequests 中移除它。
-
返回 constructCredentialAlg 并终止此算法。
-
-
抛出一个 "
NotAllowedError"DOMException。
在上述过程中,用户代理应该向用户显示一些 UI,以引导他们完成
选择和
授权认证器的过程。当
options.
设置为 mediationconditional
时,除非此前已经通过用户代理确定的方式同意创建凭据,否则不应该显示显著的模态 UI。
5.1.3.1. 创建请求异常
本节不具有规范性。
WebAuthn 依赖
方在调用 navigator.credentials.create()
时可能遇到多种异常。
某些异常可能由多种原因引起,
因此需要WebAuthn
依赖方根据其对 WebAuthn 的使用情况推断实际原因。
注:在处理任何 WebAuthn 扩展期间可能引发的异常, 包括在本规范之外定义的异常, 不在此处列出。
可能引发以下 DOMException
异常:
AbortError-
仪式被
AbortController取消。 请参阅§ 5.6 使用 AbortSignal 中止操作和§ 1.3.4 中止身份验证操作。 ConstraintError-
或者
residentKey被设置为required且没有可用认证器支持驻留密钥, 或者userVerification被设置为required且没有可用认证器能够执行用户验证。 InvalidStateError-
仪式中使用的认证器在用户同意注册凭据后,识别出
excludeCredentials中的一个条目。 NotSupportedError-
pubKeyCredParams中没有任何条目的type属性为public-key, 或者认证器 不支持pubKeyCredParams中指定的任何签名算法。 SecurityError-
有效域不是有效域, 或者
既不等于有效域,也不是其可注册域后缀。 在后一种情况下, 客户端不支持相关源请求, 或者相关源验证 过程失败。rp.id NotAllowedError-
一种涵盖多种可能原因的兜底错误, 包括用户取消仪式等常见原因。 其中一些原因在本规范各处有说明, 另一些则特定于客户端。
可能引发以下简单异常:
TypeError-
options参数不是有效的CredentialCreationOptions值, 或者的值为空或长度超过 64 字节。user.id
5.1.4. 使用现有凭据生成断言
WebAuthn 依赖
方调用
navigator.credentials.get({publicKey:..., ...})
来
发现并使用现有公钥凭据,并获得用户同意。依赖方脚本可以选择指定一些
条件,
用于指示哪些公钥凭据源是可接受的。客户端平台定位
与指定条件匹配的公钥凭据源,
并引导用户选择一个允许脚本使用的凭据源。即使存在公钥凭据源,用户也可以选择
拒绝整个交互,例如为了
保护隐私。如果用户选择一个
公钥凭据源,用户代理随后使用
§ 6.3.3 authenticatorGetAssertion 操作,对依赖方提供的
挑战以及其他收集到的数据进行签名,生成身份验证断言,并将其用作
凭据。
navigator.credentials.get()
的实现[CREDENTIAL-MANAGEMENT-1]调用
PublicKeyCredential.
来收集任何应在无需用户
中介的情况下可用的凭据(大致对应于本规范的授权手势),如果没有恰好找到其中一个,
则调用
[[CollectFromCredentialStore]]()PublicKeyCredential.
让
用户选择一个公钥凭据源。
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
由于本规范要求创建任何断言都必须执行授权手势,
PublicKeyCredential
继承
[[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors)
返回空集合的默认行为。
PublicKeyCredential
对
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
的实现将在下一节中规定。
通常,用户代理应该向用户显示一些 UI,以引导其选择并授权一个
认证器来完成操作。通过将
options.
设置为 mediationconditional,
依赖方可以表示
除非发现了凭据,否则不应该显示显著的模态 UI。
依赖方应该
首先使用 isConditionalMediationAvailable()
或 getClientCapabilities()
检查客户端是否支持 conditionalGet
能力,
以防止该功能不可用时出现用户可见的错误。
任何
navigator.credentials.get()
操作都可以利用 AbortController
中止;
详细说明请参阅DOM § 3.3 在 API
中使用
AbortController 和 AbortSignal 对象。
5.1.4.1. PublicKeyCredential 的
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
内部方法
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)此内部方法接受三个 参数:
origin-
此参数是相关设置对象的源,由调用
get()的实现(即CredentialsContainer的 请求Credential抽象操作)确定。 options-
此参数是一个
CredentialRequestOptions对象,其options.成员包含一个publicKeyPublicKeyCredentialRequestOptions对象,用于指定要发现的公钥凭据的 所需属性。 sameOriginWithAncestors-
此参数是一个 Boolean 值,当且仅当调用者的环境设置对象与 其祖先同源时为
true。如果调用者跨源,则为false。注:调用此内部方法表示 它已被 权限策略允许,该策略在[CREDENTIAL-MANAGEMENT-1]层级进行评估。 请参阅§ 5.9 权限策略集成。
注:此算法是
同步的:Promise
的兑现/拒绝由
navigator.credentials.get()
处理。
此算法中使用的所有 BufferSource
对象都必须在算法开始时创建快照,以
避免潜在的同步问题。实现应该获取缓冲区源所持字节的副本,并
在算法的相关部分中使用该副本。
调用此方法时,用户代理必须执行以下算法:
-
断言:
options.存在。publicKey -
令 pkOptions 为
options.的值。publicKey -
如果
options.存在且值为mediationconditional:-
令 credentialIdFilter 为
pkOptions.的值。allowCredentials -
将
pkOptions.设置为空。allowCredentials注:这可以防止不可发现凭据在
conditional请求期间被使用。 -
将计时器 lifetimeTimer 设置为无穷大。
注:lifetimeTimer 被设置为无穷大,以便用户可以在 Document 的整个生命周期内与任何 带有
"webauthn"自动填充详细信息令牌的input表单控件交互。例如,当 用户点击此类输入字段时,用户代理可以呈现已发现 凭据的列表供用户选择,并且可能还向用户提供 “尝试其他方式”的选项。
-
-
否则:
-
令 callerOrigin 为
origin。 如果 callerOrigin 是 不透明源,则抛出一个 "NotAllowedError"DOMException。 -
令 effectiveDomain 为 callerOrigin 的有效域。 如果有效域不是有效域,则抛出一个 "
SecurityError"DOMException。注:有效域可以解析为主机,它可以用各种方式表示, 例如域、IPv4 地址、IPv6 地址、不透明主机, 或空主机。 此处只允许主机的域格式。这既是为了简化,也是 考虑到将直接 IP 地址标识与 基于 PKI 的安全机制结合使用存在的各种问题。
-
如果
pkOptions.rpId- 存在
-
如果
pkOptions.既不是 effectiveDomain 的可注册域后缀,也不等于 effectiveDomain,并且客户端rpId- 支持相关源请求
-
-
令 rpIdRequested 为
pkOptions.的值。rpId -
以 callerOrigin 和 rpIdRequested 为参数运行相关 源验证过程。 如果结果为
false,则抛出一个 "SecurityError"DOMException。
-
- 不支持相关源请求
-
抛出一个 "
SecurityError"DOMException。
- 不存在
-
将
pkOptions.设置为 effectiveDomain。rpId
注:rpId 表示 调用者的RP ID。除非调用者在调用
get()时显式设置了pkOptions., 否则RP ID默认为 调用者源的有效域。rpId -
令 clientExtensions 为一个新的映射,并令 authenticatorExtensions 为一个新的映射。
-
如果
pkOptions.存在,则对于extensionspkOptions.中的每个 extensionId → clientExtensionInput:extensions -
令 collectedClientData 为一个新的
CollectedClientData实例,其字段如下:type-
字符串 "webauthn.get"。
challenge-
pkOptions.
challenge的base64url 编码。 origin-
callerOrigin 的序列化。
crossOrigin-
传递给此内部方法的
sameOriginWithAncestors参数值的反值。 topOrigin-
如果传递给此内部方法的
sameOriginWithAncestors参数为false,则为 callerOrigin 的顶层源的序列化,否则为undefined。
- 令 clientDataJSON 为由 collectedClientData 构造的客户端数据的 JSON 兼容 序列化。
-
令 clientDataHash 为由 clientDataJSON 表示的序列化 客户端数据的哈希。
-
令 issuedRequests 为一个新的有序集合。
-
令 savedCredentialIds 为一个新的映射。
-
令 authenticators 表示一个值,该值在任意给定时刻都是一个集合,由客户端平台特定的句柄组成,其中每个 项标识当时此客户端 平台上当前可用的一个认证器。
注:什么条件可使认证器 被视为“可用”是有意未规定的;这里旨在表示认证器 可通过各种机制热插拔到 (例如通过 USB) 客户端中,或被其发现 (例如通过 NFC 或 Bluetooth),也可以永久内置于客户端中。
-
令 silentlyDiscoveredCredentials 为一个新的映射,其条目形式为:DiscoverableCredentialMetadata → 认证器。
-
考虑
hints的值,并按用户代理认为合适的方式相应构建用户界面。 -
启动 lifetimeTimer。
-
在 lifetimeTimer 尚未到期时,循环执行 以下操作,具体取决于 lifetimeTimer, 以及 authenticators 中每个 authenticator 的状态和响应:
- 如果 lifetimeTimer 到期,
-
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用authenticatorCancel 操作,并从 issuedRequests 中移除 authenticator。
- 如果用户使用用户代理的用户界面选项取消该过程,
-
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用authenticatorCancel 操作, 并从 issuedRequests 中移除 authenticator。抛出一个 "
NotAllowedError"DOMException。 - 如果
options.存在且已中止,signal -
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用authenticatorCancel 操作, 并从 issuedRequests 中移除 authenticator。然后 抛出
options.的 中止原因。signal -
如果
options.为mediationconditional且用户与一个input或textarea表单控件交互,该控件具有autocomplete属性,且其 非自动填充凭据类型为"webauthn", -
注:
"webauthn"自动填充详细信息令牌必须紧接在最后一个 “Normal”或“Contact”类型的自动填充详细信息令牌 之后。例如:-
"username webauthn" -
"current-password webauthn"
-
如果 silentlyDiscoveredCredentials 不为空:
-
提示用户可以选择性地从 silentlyDiscoveredCredentials 中选择一个DiscoverableCredentialMetadata。 提示应该显示每个DiscoverableCredentialMetadata 的otherUI 中的值,例如
name和displayName。如果用户进行了选择,则令 credentialMetadata 为用户选择的DiscoverableCredentialMetadata。
-
如果用户选择了 credentialMetadata,
-
令 publicKeyOptions 为 pkOptions 的临时副本。
-
令 authenticator 为 silentlyDiscoveredCredentials[credentialMetadata] 的值。
-
将
publicKeyOptions.设置为一个列表,其中包含单个allowCredentialsPublicKeyCredentialDescriptor项;其id的值设置为 credentialMetadata 的id 的值,其type值设置为 credentialMetadata 的type。 -
使用 authenticator、savedCredentialIds、 publicKeyOptions、rpId、 clientDataHash 和 authenticatorExtensions 执行向 认证器发出凭据请求算法。
如果返回
false,则继续。 -
将 authenticator追加到 issuedRequests。
-
-
-
- 如果
options.不是mediationconditional, issuedRequests 为空,pkOptions.非空, 且其中任何公钥 凭据都不会有 authenticator 变得可用,allowCredentials -
向用户指示未找到符合条件的凭据。当用户 确认该对话框时,抛出一个 "
NotAllowedError"DOMException。注:客户端 平台确定不会有 authenticator 变得可用的一种方法,是检查
pkOptions.中现有的allowCredentials项的PublicKeyCredentialDescriptor成员(如果有)。例如,如果所有transports项都只列出PublicKeyCredentialDescriptor, 但所有平台 authenticator 都 已尝试,则不可能满足该请求。或者,所有internal项可能都列出了 客户端平台不支持的PublicKeyCredentialDescriptor。transports - 如果某个 authenticator 在此客户端设备上变得可用,
-
注:这包括 authenticator 在 lifetimeTimer 启动时已经可用的情况。
-
如果
options.为mediationconditional且 authenticator 支持silentCredentialDiscovery 操作:-
令 collectedDiscoveredCredentialMetadata 为在 authenticator 上以 rpId 为参数调用silentCredentialDiscovery 操作的结果。
-
对于 collectedDiscoveredCredentialMetadata 中的每个 credentialMetadata:
-
-
否则:
-
使用 authenticator、savedCredentialIds、 pkOptions、rpId、clientDataHash 和 authenticatorExtensions 执行向 认证器发出凭据请求算法。
如果返回
false,则继续。注:当
options.为mediationconditional且 authenticator 不支持silentCredentialDiscovery 操作时,会进入此分支,以允许在conditional用户中介请求期间使用此类认证器。 -
将 authenticator追加到 issuedRequests。
-
-
- 如果某个 authenticator 在此客户端 设备上变得不可用,
-
从 issuedRequests 中移除 authenticator。
- 如果任何 authenticator 返回表示用户取消操作的状态,
-
-
从 issuedRequests 中移除 authenticator。
-
对于 issuedRequests 中剩余的每个 authenticator, 在 authenticator 上调用authenticatorCancel 操作, 并从 issuedRequests 中移除它。
注:认证器可能返回“用户取消了整个操作”的指示。 用户代理如何向用户呈现此状态未作规定。
-
- 如果任何 authenticator 返回错误状态,
-
从 issuedRequests 中移除 authenticator。
- 如果任何 authenticator 指示成功,
-
-
从 issuedRequests 中移除 authenticator。
-
令 assertionCreationData 为一个结构, 其项如下:
-
credentialIdResult -
如果
savedCredentialIds[authenticator]存在,则将credentialIdResult 的值设置为savedCredentialIds[authenticator]的字节。 否则,将 credentialIdResult 的值设置为成功执行 authenticatorGetAssertion 操作所返回的凭据 ID的字节,如§ 6.3.3 authenticatorGetAssertion 操作中所定义。 -
clientDataJSONResult -
其值为 clientDataJSON 的字节。
-
authenticatorDataResult -
signatureResult -
其值为认证器返回的签名值的字节。
-
userHandleResult -
如果认证器返回了用户句柄,则将userHandleResult 的值设置为 所返回用户句柄的字节。否则,将 userHandleResult 的值设置为 null。
-
clientExtensionResults -
其值为一个
AuthenticationExtensionsClientOutputs对象,包含扩展标识符 → 客户端扩展输出 条目。这些条目通过对pkOptions.中的每个客户端扩展运行各扩展的 客户端扩展 处理算法,以创建客户端扩展输出。extensions
-
-
如果 credentialIdFilter非空,且 credentialIdFilter 不包含任何项,其
id的值设置为credentialIdResult 的值,则继续。 -
如果 credentialIdFilter为空,且userHandleResult 为 null,则继续。
-
令 pubKeyCred 为一个与 global 关联的新
PublicKeyCredential对象,其字段如下:[[identifier]]-
一个新的
ArrayBuffer, 使用 global 的%ArrayBuffer% 创建,其中包含assertionCreationData.credentialIdResult的字节。 authenticatorAttachment-
与 authenticator 当前认证器 附着模式相匹配的
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的字节。
-
对于 issuedRequests 中剩余的每个 authenticator, 在 authenticator 上调用authenticatorCancel 操作, 并从 issuedRequests 中移除它。
-
返回 pubKeyCred 并终止此算法。
-
-
抛出一个 "
NotAllowedError"DOMException。
5.1.4.2. 向认证器发出凭据 请求
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
的此子算法包含使用给定 PublicKeyCredentialRequestOptions
从给定认证器请求凭据时所需的、与具体 UI 上下文无关的
步骤。
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
会根据当前身份验证仪式所受的用户
中介类型(例如 conditional
中介),从不同位置调用此算法。
此算法接受以下参数:
authenticatorsavedCredentialIdspkOptions-
此参数是一个
PublicKeyCredentialRequestOptions对象,用于指定要发现的 公钥 凭据的所需属性。 rpId-
请求的RP ID。
clientDataHash-
由 clientDataJSON 表示的序列化 客户端数据的哈希。
authenticatorExtensions-
一个映射,其中包含扩展标识符到 认证器扩展的客户端扩展处理 输出的base64url 编码。
如果客户端确定 authenticator 无法处理
请求,则此算法返回 false;如果
请求已成功发出,则返回 true。
向认证器发出凭据 请求的步骤如下:
-
如果
pkOptions.设置为userVerificationrequired且 authenticator 无法执行用户验证, 则返回false。 -
令 userVerification 为断言的有效用户验证 要求,它是一个 Boolean 值,如下。如果
pkOptions.userVerification- 设置为
required -
令 userVerification 为
true。 - 设置为
preferred -
如果 authenticator
- 设置为
discouraged -
令 userVerification 为
false。
- 设置为
-
如果
pkOptions.allowCredentials- 非空
-
-
令 allowCredentialDescriptorList 为一个新的列表。
-
执行一个客户端平台特定的过程,通过匹配 rpId、
pkOptions.和allowCredentials.idpkOptions., 确定allowCredentials.typepkOptions.描述的哪些公钥凭据(如果有)与此 authenticator绑定。 将 allowCredentialDescriptorList 设置为该过滤后的列表。allowCredentials -
如果 allowCredentialDescriptorList为空,则返回
false。 -
令 distinctTransports 为一个新的有序集合。
-
如果 allowCredentialDescriptorList 恰好有一个值,则将
savedCredentialIds[authenticator]设置为allowCredentialDescriptorList[0].id的值(有关更多信息,请参阅§ 6.3.3 authenticatorGetAssertion 操作中的此处)。 -
对于 allowCredentialDescriptorList 中的每个凭据描述符 C, 将
C.的每个值(如果有)追加到 distinctTransports。transports注:由于有序集合的性质,这只会在 distinctTransports 中汇总
transports的不同值(对于此认证器)。 -
如果 distinctTransports
- 非空
-
客户端从 distinctTransports 中选择一个 transport 值, 并可能在选择时结合有关应与 authenticator 一起使用的适当传输方式的本地 配置知识。
然后,使用 transport,在 authenticator 上调用authenticatorGetAssertion 操作,并以 rpId、clientDataHash、 allowCredentialDescriptorList、 userVerification 和 authenticatorExtensions 作为参数。
- 为空
-
使用有关应与 authenticator 一起使用的适当传输方式的本地配置知识, 在 authenticator 上调用authenticatorGetAssertion 操作,并以 rpId、 clientDataHash、allowCredentialDescriptorList、 userVerification 和 authenticatorExtensions 作为参数。
-
- 为空
-
使用有关应与 authenticator 一起使用的适当传输方式的本地配置知识,在 authenticator 上调用 authenticatorGetAssertion 操作,并以 rpId、clientDataHash、 userVerification 和 authenticatorExtensions 作为参数。
注:在这种情况下,依赖 方没有提供可接受凭据描述符的列表。因此, 认证器被要求使用它可能持有的、由 rpId 标识的 依赖 方范围内的任何限定作用域凭据。
-
返回
true。
5.1.4.3. 获取请求异常
本节不具有规范性。
WebAuthn 依赖
方在调用 navigator.credentials.get()
时可能遇到多种异常。
某些异常可能由多种原因引起,
因此需要WebAuthn
依赖方根据其对 WebAuthn 的使用情况推断实际原因。
注:在处理任何 WebAuthn 扩展期间可能引发的异常, 包括在本规范之外定义的异常, 不在此处列出。
可能引发以下 DOMException
异常:
AbortError-
仪式被
AbortController取消。 请参阅§ 5.6 使用 AbortSignal 中止操作和§ 1.3.4 中止身份验证操作。 SecurityError-
有效域不是有效域, 或者
既不等于有效域,也不是其可注册域后缀。 在后一种情况下, 客户端不支持相关源请求, 或者相关源验证 过程失败。rp.id NotAllowedError-
一种涵盖多种可能原因的兜底错误, 包括用户取消仪式等常见原因。 其中一些原因在本规范各处有说明, 另一些则特定于客户端。
可能引发以下简单异常:
TypeError-
options参数不是有效的CredentialRequestOptions值。
5.1.5. 存储现有凭据 - PublicKeyCredential 的
[[Store]](credential, sameOriginWithAncestors) 内部方法
[[Store]](credential, sameOriginWithAncestors)
方法不支持
Web 身份验证的 PublicKeyCredential
类型,
因此其对[[Store]](credential, sameOriginWithAncestors)
内部方法的实现始终抛出
错误。
注:此算法是同步的;Promise
的兑现/拒绝由
navigator.credentials.store()
处理。
此内部方法接受两个 参数:
credential-
此参数是一个
PublicKeyCredential对象。 sameOriginWithAncestors
调用此方法时,用户代理必须执行以下算法:
-
抛出一个 "
NotSupportedError"DOMException。
5.1.6. 用户验证平台认证器的可用性 -
PublicKeyCredential 的 isUserVerifyingPlatformAuthenticatorAvailable() 方法
WebAuthn
依赖方使用此方法确定其是否可以使用用户验证平台认证器创建新凭据。
调用后,客户端使用客户端
平台特定的过程来发现可用的用户验证平台认证器。
如果发现任何此类认证器,则 promise 以值 true 兑现。
否则,promise 以值 false 兑现。
根据结果,依赖方可以采取进一步操作,引导用户创建
凭据。
此方法没有参数,并返回一个 Boolean 值。
partial interface PublicKeyCredential {static Promise <boolean >(); };isUserVerifyingPlatformAuthenticatorAvailable
5.1.7.
客户端能力的可用性 -
PublicKeyCredential 的
getClientCapabilities() 方法
WebAuthn
依赖方使用此方法确定一组有限的客户端能力是否可用,
以便向用户提供特定的工作流和体验。例如,在仅有 hybrid
传输可用或 conditional
中介不可用的客户端上,RP 可以提供登录按钮
(而不是显示用户名字段)。
调用后,客户端使用客户端 平台特定的过程来发现这些能力是否可用。
此方法没有参数,并返回从能力键到 Boolean 值的记录。
partial interface PublicKeyCredential {static Promise <PublicKeyCredentialClientCapabilities >(); };getClientCapabilities typedef record <DOMString ,boolean >;PublicKeyCredentialClientCapabilities
PublicKeyCredentialClientCapabilities
中的键必须按字典序升序排列。
键集合应该包含 ClientCapability
的枚举值集合,
但客户端可以按其认为必要的方式省略键;请参阅§ 14.5.4 披露客户端能力。
当给定能力的值为 true 时,表示已知客户端当前支持该功能。
当给定能力的值为 false 时,表示已知客户端当前不支持该功能。
当某项能力没有作为键存在时,客户端功能的可用性未知。
键集合还应该为客户端实现的每个扩展包含一个键,该键通过在扩展标识符前加上字符串
extension: 构成。
每个已实现扩展的关联值应该为 true。如果客户端支持
getClientCapabilities(),但某个扩展没有映射到值 true,则依赖方可以
假定该客户端不会执行该扩展的客户端处理步骤,并且该扩展可能不会被转发给认证器。
请注意,即使某个扩展映射到 true,用于任何给定操作的认证器也可能不支持该扩展,
因此依赖方不得
据此假定该扩展的认证器处理步骤会被执行。
5.1.8.
反序列化注册仪式选项 - PublicKeyCredential 的
parseCreationOptionsFromJSON() 方法
WebAuthn
依赖方使用此方法将
navigator.credentials.create()
的选项的JSON 类型
表示转换为
PublicKeyCredentialCreationOptions。
调用后,客户端必须将
options
参数转换为一个新的、
结构相同的 PublicKeyCredentialCreationOptions
对象,使用base64url
编码
解码 PublicKeyCredentialCreationOptionsJSON
中与 PublicKeyCredentialCreationOptions
中缓冲区源类型属性相对应的任何 DOMString
属性。
此转换还必须
应用于由客户端处理的任何客户端扩展输入。
AuthenticationExtensionsClientInputsJSON
可以包括在 IANA
"WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]中注册但未在
§ 9 WebAuthn 扩展中定义的扩展。
如果客户端在解析任何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 = "none";attestation 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
依赖方使用此方法将
navigator.credentials.get()
的选项的JSON 类型
表示转换为
PublicKeyCredentialRequestOptions。
调用后,客户端必须将
options
参数转换为一个新的、
结构相同的 PublicKeyCredentialRequestOptions
对象,使用base64url
编码
解码 PublicKeyCredentialRequestOptionsJSON
中与 PublicKeyCredentialRequestOptions
中缓冲区源类型属性相对应的任何 DOMString
属性。
此转换还必须
应用于由客户端处理的任何客户端扩展输入。
AuthenticationExtensionsClientInputsJSON
可以包括在 IANA
"WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]中注册但未在
§ 9 WebAuthn 扩展中定义的扩展。
如果客户端在解析任何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 = "preferred";userVerification sequence <DOMString >= [];hints AuthenticationExtensionsClientInputsJSON ; };extensions
5.1.10. 向认证器发出凭据更改信号 - PublicKeyCredential 的信号方法
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 依赖
方可以使用这些信号方法向认证器
通知公钥凭据的状态,以便可以更新、移除或隐藏错误或已撤销的
凭据。客户端以尽力而为的方式提供此
功能,因为认证器可能不支持更新
其凭据映射,或者在发出
请求时可能未连接。此外,为避免在未经用户
同意的情况下泄露有关用户凭据的信息,信号
方法不会指示
操作是否成功。成功兑现的 promise 仅表示
options 对象格式正确。
每个信号方法都包含 认证器 操作。认证器可以选择使其认证器操作偏离本 规范,例如忽略某项其有合理理由认为会违背用户意愿的 更改,或者在进行某些更改前 询问用户。因此,认证器操作 是作为处理信号方法的推荐方式提供的。
如果认证器不具备处理某个
认证器操作的能力,客户端可以选择使用现有
基础设施,例如[FIDO-CTAP]的
authenticatorCredentialManagement
命令来实现等效效果。
注:信号方法有意避免等待认证器 完成执行认证器操作。此措施可保护用户, 防止WebAuthn 依赖方根据请求的时间特征,在未经用户同意的情况下获取有关其凭据可用性的信息。
5.1.10.1. 异步 RP ID 验证 算法
异步 RP ID 验证
算法使信号
方法能够并行验证
RP ID。该算法以一个 DOMString
rpId 作为输入,
并返回一个在验证失败时被拒绝的 promise。步骤如下:
-
令 effectiveDomain 为相关设置对象的源的有效域。如果 effectiveDomain 不是有效域,则返回一个以……拒绝的 promise "
SecurityError"DOMException。 -
如果 rpId 是其可注册域后缀或与其相等 effectiveDomain,则返回一个以……兑现的 promise undefined。
-
如果客户端不支持相关源 请求,则返回一个以……拒绝的 promise,其拒绝原因为 "
SecurityError"DOMException。 -
令 p 为一个新的 promise。
-
并行执行以下步骤:
-
否则,以一个 "
SecurityError"DOMException拒绝 p。
-
返回 p。
5.1.10.2. signalUnknownCredential(options)
signalUnknownCredential
方法发出信号,表示某个凭据
ID未被WebAuthn 依赖方识别,
例如因为它已被用户删除。与 signalAllAcceptedCredentials(options)
不同,此
方法不要求传递完整的已接受凭据 ID
列表和userHandle,从而避免向未经身份验证的调用者
泄露隐私(请参阅§ 14.6.3 通过凭据 ID 泄露隐私)。
调用 signalUnknownCredential(options)
后,客户端执行以下步骤:
-
如果对
options.进行 base64url 解码的结果 是 错误,则返回一个以……拒绝的 promise,拒绝值为一个credentialIdTypeError。 -
令 p 为以
options.执行异步 RP ID 验证算法的结果。rpId -
-
对于当前在此客户端 平台上可用的每个认证器,以 options 作为 输入调用unknownCredentialId 认证器操作。
-
-
返回 p。
unknownCredentialId
认证器操作接受一个 UnknownCredentialOptions
options,其过程如下:
-
对于 认证器的凭据映射中的每个公钥 凭据源 credential:
-
如果 credential 的rpId 等于
options., 且 credential 的id 等于对rpIdoptions.进行 base64url 解码的结果,则从凭据映射中移除 credential,或采用特定于认证器的过程将其从未来的身份验证仪式中隐藏。credentialId
-
用户在WebAuthn
依赖方
提供的 UI 上删除一个凭据。之后,当尝试
使用空的
allowCredentials
向WebAuthn
依赖方进行身份验证时,认证器 UI
向用户提供他们之前删除的凭据。用户选择该
凭据。在拒绝此次登录尝试后,WebAuthn
依赖方运行:
PublicKeyCredential. signalUnknownCredential({ rpId: "example.com" , credentialId: "aabbcc" // 用户刚刚尝试的凭据 ID,base64url });
5.1.10.3. signalAllAcceptedCredentials(options)
发出给定用户完整凭据
ID列表的信号。当用户已经通过身份验证,因此不存在隐私泄露风险时(请参阅
§ 14.6.3 通过凭据 ID 泄露隐私),WebAuthn 依赖方
应该优先使用此方法,而不是 signalUnknownCredential(),因为该列表
提供用户公钥
凭据的完整快照,并可能反映尚未
报告给当前已连接认证器的更改。
调用
signalAllAcceptedCredentials(options)
后,客户端
执行以下步骤:
-
如果对
options.进行 base64url 解码的结果 是 错误,则返回一个以……拒绝的 promise,拒绝值为一个userIdTypeError。 -
对于每一个 credentialId,其位于
options.:allAcceptedCredentialIds-
如果对 credentialId 进行 base64url 解码 的结果是错误,则返回一个以……拒绝的 promise,拒绝值为一个
TypeError。
-
-
令 p 为使用
options.执行异步 RP ID 验证算法所得的结果。rpId -
-
对于此客户端 平台上当前可用的每个认证器,以 options 作为输入调用 allAcceptedCredentialIds 认证器操作。
-
-
返回 p。
allAcceptedCredentialIds 认证器操作接受一个 AllAcceptedCredentialsOptions
options,其过程
如下:
-
令 userId 为对
options.进行 base64url 解码的结果。userId -
断言:userId 不是错误。
-
如果 credential 不存在,则中止这些步骤。
-
如果
options.不包含对 credential 的id进行base64url 编码的结果, 则从凭据映射中移除 credential,或采用特定于认证器的过程,将其从未来的身份验证仪式中隐藏。allAcceptedCredentialIds -
否则,如果 credential 已通过特定于认证器的 过程被隐藏,则撤销该操作,使 credential 出现在未来的 身份验证仪式中。
用户有两个凭据 ID,其base64url
编码分别为
aa 和 bb。用户在WebAuthn
依赖方提供的 UI 上删除凭据 aa。
WebAuthn
依赖方运行:
PublicKeyCredential. signalAllAcceptedCredentials({ rpId: "example.com" , userId: "aabbcc" , // 用户句柄,base64url。 allAcceptedCredentialIds: [ "bb" , ] });
注:执行
signalAllAcceptedCredentials(options)
时,认证器可能尚未连接。
因此,WebAuthn
依赖方可以选择定期运行
signalAllAcceptedCredentials(options),
例如每次登录时。
注:不存在于
allAcceptedCredentialIds
中的凭据将被移除或
隐藏,并且可能无法恢复。依赖方必须谨慎确保
绝不会从列表中遗漏有效凭据 ID。如果意外遗漏了某个有效凭据
ID,则依赖方应该
尽快立即在 signalAllAcceptedCredentials(options)
中包含
它,以便在认证器支持的情况下将其“取消隐藏”。
认证器应该在
可能的情况下,优先将公钥凭据隐藏一段时间,而不是永久
移除,以便在WebAuthn
依赖方
意外从
allAcceptedCredentialIds
中遗漏有效凭据 ID时帮助恢复。
5.1.10.4. signalCurrentUserDetails(options)
signalCurrentUserDetails
方法发出用户当前
name
和 displayName
的信号。
调用 signalCurrentUserDetails(options)
后,
客户端执行以下步骤:
-
如果对 base64url 解码
options.的结果是错误, 则返回一个以……拒绝的 promise,拒绝值为一个userIdTypeError。 -
令 p 为以
options.执行异步 RP ID 验证算法的结果。rpId -
-
对于当前在此客户端 平台上可用的每个认证器,以 options 作为输入调用currentUserDetails 认证器操作。
-
-
返回 p。
currentUserDetails
认证器操作接受一个 CurrentUserDetailsOptions
options,其过程如下:
-
令 userId 为对
options.进行 base64url 解码的结果。userId -
断言:userId 不是错误。
-
如果 credential 不存在,则中止这些步骤。
-
更新 credential 的otherUI,使其与
options.和nameoptions.相匹配。displayName
用户在WebAuthn 依赖方提供的 UI 上更新其名称。WebAuthn 依赖方运行:
PublicKeyCredential. signalCurrentUserDetails({ rpId: "example.com" , userId: "aabbcc" , // 用户句柄,base64url。 name: "新用户名" , displayName: "新显示名称" , });
注:执行
signalCurrentUserDetails(options)
时,认证器可能尚未连接。
因此,WebAuthn
依赖方可以选择定期运行
signalCurrentUserDetails(options),例如
每次登录时。
5.2.
认证器响应(接口 AuthenticatorResponse)
认证器通过
返回一个派生自
AuthenticatorResponse
接口的对象来响应依赖方请求:
[SecureContext ,Exposed =Window ]interface AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer clientDataJSON ; };
clientDataJSON, 类型为 ArrayBuffer,只读-
此属性包含客户端数据的JSON 兼容 序列化,客户端在调用
create()或get()时会将其哈希传递给 认证器(即, 客户端数据本身 不会发送给认证器)。
5.2.1. 有关公钥凭据的信息(接口
AuthenticatorAttestationResponse)
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 证明)。必须保留 完全相同的 JSON 序列化,因为序列化 客户端数据的哈希是基于它计算的。 attestationObject, 类型为ArrayBuffer,只读-
此属性包含一个证明对象,该对象对客户端是不透明的,并受到 密码学保护以防客户端 篡改。证明对象同时包含认证器数据和证明语句。 前者包含 AAGUID、唯一的凭据 ID以及凭据公 钥。证明语句的内容由认证器使用的证明语句格式决定。 它还包含依赖方服务器验证 证明语句所需的任何附加信息,以及用于解码和 验证认证器数据和 客户端数据的 JSON 兼容 序列化所需的信息。有关更多详细信息,请参阅§ 6.5 证明、§ 6.5.4 生成 证明对象 和图 6。
getTransports()-
此操作返回
[[transports]]的值。 getAuthenticatorData()-
此操作返回
attestationObject中包含的认证器数据。 请参阅§ 5.2.1.1 轻松访问凭据数据。 getPublicKey()-
此操作返回新凭据的 DER SubjectPublicKeyInfo,如果不可用则返回 null。 请参阅§ 5.2.1.1 轻松访问凭据 数据。
getPublicKeyAlgorithm()-
此操作返回新凭据的
COSEAlgorithmIdentifier。 请参阅§ 5.2.1.1 轻松访问凭据 数据。 [[transports]]-
此内部槽包含一个 按字典序排列的、由零个或多个唯一
DOMString组成的序列。这些值是认为认证器支持的 传输方式;如果该信息不可用,则为空序列。这些值应该是AuthenticatorTransport的成员,但依赖 方应该接受并存储未知值。
5.2.1.1. 轻松访问凭据数据
[[Create]](origin, options, sameOriginWithAncestors)
方法的每个用户都需要解析并存储返回的凭据公钥,以便验证未来的身份验证断言。但是,凭据
公钥采用 COSE 格式[RFC9052],位于
认证器数据中的
attestedCredentialData 的
credentialPublicKey 成员中,
而认证器数据又位于由 AuthenticatorAttestationResponse.attestationObject
传送的证明
对象中。
希望使用证明的依赖方必须完成解析 attestationObject
并取得凭据公钥的工作,因为该公钥副本是认证器签名的副本。但是,许多有效的 WebAuthn
用例并不需要证明。
对于这些用途,用户代理可以完成解析工作,直接暴露认证器数据,并
将凭据公钥转换为更方便的格式。
因此,getPublicKey()
操作以SubjectPublicKeyInfo形式返回凭据公钥。例如,可以将此 ArrayBuffer
传递给 Java 的 java.security.spec.X509EncodedKeySpec、.NET 的
System.Security.Cryptography.ECDsa.ImportSubjectPublicKeyInfo 或 Go 的
crypto/x509.ParsePKIXPublicKey。
使用 getPublicKey()
确实会带来一些限制:通过使用 pubKeyCredParams,
依赖方可以
与认证器协商使用用户代理可能不理解的公钥算法。
但是,如果依赖方这样做,用户代理将无法把
生成的凭据公钥转换为SubjectPublicKeyInfo格式,并且 getPublicKey()
的返回值将为 null。
当凭据公钥的 COSEAlgorithmIdentifier
值为以下值时,用户代理必须能够为 getPublicKey()
返回非 null 值:
SubjectPublicKeyInfo 不包含 COSE 公钥中所包含的签名
算法信息(例如要使用哪个哈希函数)。为了提供
此信息,getPublicKeyAlgorithm()
返回凭据公钥的 COSEAlgorithmIdentifier。
为了在许多情况下完全无需解析 CBOR,getAuthenticatorData()
返回 attestationObject
中的认证器数据。
认证器
数据包含其他以二进制格式编码的字段。但是,并未提供用于访问这些字段的辅助函数,
因为依赖方在获取断言时已经需要提取这些字段。与凭据创建不同,在凭据创建中签名验证是可选的,而依赖方应该始终验证
断言中的签名,因此必须从已签名的认证器数据中提取字段。在那里使用的相同函数
也可用于凭据创建期间。
依赖方在使用
这些函数之前,应该通过测试
'getPublicKey' in AuthenticatorAttestationResponse.prototype 的值来进行功能检测。
注:getPublicKey()
和 getAuthenticatorData()
直到本规范第 2 级才被添加。
要求这些函数存在的依赖方可能无法与较旧的用户代理互操作。
5.2.2. Web 身份验证断言(接口 AuthenticatorAssertionResponse)
AuthenticatorAssertionResponse
接口表示认证器对客户端请求生成新身份验证断言的响应,该请求给出了WebAuthn 依赖方的
挑战以及它所知凭据的可选列表。此响应包含一个证明持有凭据私钥的密码学签名,并
可以选择包含对特定交易的用户
同意的证据。
[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 WebAuthn 签名中使用的客户端数据(字典 CollectedClientData))。必须保留 完全相同的 JSON 序列化,因为序列化 客户端数据的哈希是基于它计算的。 authenticatorData, 类型为ArrayBuffer,只读-
此属性包含认证器返回的认证器数据。请参阅 § 6.1 认证器数据。
signature, 类型为 ArrayBuffer,只读-
此属性包含从认证器返回的原始签名。请参阅§ 6.3.3 authenticatorGetAssertion 操作。
userHandle, 类型为 ArrayBuffer,只读,可为 null-
此属性包含从认证器返回的用户句柄;如果 认证器未返回 用户句柄,则为 null。 请参阅§ 6.3.3 authenticatorGetAssertion 操作。如果 身份验证仪式中使用的
allowCredentials选项为空, 则认证器必须始终返回用户句柄; 否则可以返回一个。
5.3.
凭据生成参数(字典 PublicKeyCredentialParameters)
dictionary PublicKeyCredentialParameters {required DOMString type ;required COSEAlgorithmIdentifier alg ; };
type, 类型为DOMString-
此成员指定要创建的凭据类型。该值应该是
PublicKeyCredentialType的成员,但客户端 平台必须忽略未知值,并忽略任何具有未知type的PublicKeyCredentialParameters。 alg, 类型为COSEAlgorithmIdentifier-
此成员指定新生成的 凭据将使用的密码学签名算法,因此也指定要生成的非对称密钥对类型,例如 RSA 或椭圆曲线。
注:我们使用 "alg" 作为后一个成员名称,而不是 完整拼写 "algorithm",因为它将被序列化到 发送给认证器的消息中,而该消息可能通过低带宽链路发送。
5.4.
凭据创建选项(字典 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, 类型为PublicKeyCredentialRpEntity-
此成员包含负责该请求的依赖方的名称和标识符。
其值的
name成员是必需的。有关进一步 详细信息,请参阅§ 5.4.1 公钥实体 描述(字典 PublicKeyCredentialEntity)。其值的
id成员指定凭据 应限定作用域到的RP ID。如果省略, 其值将为CredentialsContainer对象的相关设置对象的源的有效域。有关进一步详细信息,请参阅§ 5.4.2 凭据生成的依赖方参数(字典 PublicKeyCredentialRpEntity)。 user, 类型为PublicKeyCredentialUserEntity-
其值的
name、displayName和id成员都是必需的。id可以在某些未来的身份验证仪式中作为userHandle返回,并用于覆盖同一认证器上具有相同和rp.id的现有可发现凭据。user.idname和displayName可以由认证器和客户端在未来的身份验证 仪式中使用, 以帮助用户选择凭据,但不会作为未来身份验证仪式的结果返回给依赖方。有关进一步详细信息,请参阅§ 5.4.1 公钥实体 描述(字典 PublicKeyCredentialEntity)和§ 5.4.3 凭据生成的用户帐户参数(字典 PublicKeyCredentialUserEntity)。
challenge, 类型为 BufferSource-
此成员指定一个挑战,认证器在为新创建的凭据生成证明对象时,会对该挑战以及其他数据进行签名。 请参阅§ 13.5.3 密码学挑战安全 注意事项。
pubKeyCredParams, 类型为 sequence<PublicKeyCredentialParameters>-
此成员列出依赖方支持的密钥类型和签名算法, 按偏好程度从高到低排序。 允许重复,但实际上会被忽略。 客户端和认证器 会尽最大努力创建偏好程度尽可能高的类型的凭据。 如果列出的类型都无法创建,则
create()操作失败。希望支持广泛认证器的依赖方 应该至少包含以下
COSEAlgorithmIdentifier值:-
-8 (EdDSA)
-
-7 (ES256)
-
-257 (RS256)
可以根据需要包含其他签名算法。
由[RFC9864] 引入的以下完全指定
COSEAlgorithmIdentifier值 不推荐 用于pubKeyCredParams:-
-9 (ESP256);改用或同时使用 -7 (ES256)。
-
-51 (ESP384);改用或同时使用 -35 (ES384)。
-
-52 (ESP512);改用或同时使用 -36 (ES512)。
-
-19 (Ed25519);改用或同时使用 -8 (EdDSA)。
注:在 WebAuthn 中,由于§ 5.8.5 密码算法标识符(typedef COSEAlgorithmIdentifier)中规定的附加限制,值 -9 (ESP256)、-51 (ESP384)、-52 (ESP512) 和 -19 (Ed25519) 分别与 -7 (ES256)、-35 (ES384)、-36 (ES512) 和 -8 (EdDSA) 表示相同的含义。 但是,它们在实践中不可互换, 因为许多实现支持后者的标识符而不支持前者。 因此,为了向后兼容,在
pubKeyCredParams中优先使用后者的标识符。 -
timeout, 类型为 unsigned longexcludeCredentials, 类型为 sequence<PublicKeyCredentialDescriptor>, 默认为[]-
依赖方 应该使用此可选成员列出映射到此用户帐户的任何现有凭据 (由
user.id标识)。 这可以确保新凭据不会创建于一个已经包含映射到此用户帐户的凭据的认证器上。 如果会出现这种情况,则要求客户端改为引导用户使用另一个认证器, 如果失败则返回错误。 authenticatorSelection, 类型为AuthenticatorSelectionCriteria-
依赖方 可以使用此可选成员指定 认证器必须或应该满足的能力和设置,以参与
create()操作。 请参阅§ 5.4.4 认证器选择条件 (字典 AuthenticatorSelectionCriteria)。 hints, 类型为 sequence<DOMString>,默认为[]-
此可选成员包含来自
PublicKeyCredentialHint的零个或多个元素,用于指导用户代理与用户交互。请注意,尽管这些元素取自该枚举, 其类型仍为DOMString。请参阅§ 2.1.1 作为 DOMString 类型的枚举。 attestation, 类型为DOMString,默认为"none"-
依赖方 可以使用此可选成员指定有关证明 传送的偏好。 其值应该是
AttestationConveyancePreference的成员。 客户端 平台必须忽略未知值,将未知值视为该成员不存在。默认值为
none。 attestationFormats, 类型为 sequence<DOMString>,默认为[]-
依赖方 可以使用此可选成员指定有关认证器所使用的证明语句格式的偏好。 值应该取自 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表[IANA-WebAuthn-Registries],该注册表由[RFC8809]建立。 值按偏好程度从高到低排序。 允许重复,但实际上会被忽略。 此参数仅供参考,认证器可以使用此参数中未列出的证明语句。
默认值为空列表,表示没有偏好。
extensions, 类型为 AuthenticationExtensionsClientInputs-
依赖方 可以使用此可选成员提供客户端扩展输入, 请求客户端和认证器执行附加处理。 例如,依赖方可以请求客户端返回 有关所创建凭据的附加信息。
扩展框架定义于§ 9 WebAuthn 扩展中。 一些扩展定义于§ 10 定义的扩展中; 有关已注册WebAuthn 扩展的最新列表,请查阅由[RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]。
5.4.1.
公钥实体描述(字典 PublicKeyCredentialEntity)
PublicKeyCredentialEntity
字典描述用户
帐户或WebAuthn 依赖方,公钥凭据分别与其
关联或限定作用域于其。
dictionary PublicKeyCredentialEntity {required DOMString name ; };
name, 类型为 DOMString-
实体的一个对人类友好的名称。其作用 取决于
PublicKeyCredentialEntity所表示的内容:-
[已弃用] 当由
PublicKeyCredentialRpEntity继承时,它是对人类友好的依赖 方标识符,仅用于 显示。例如,"ACME Corporation"、"Wonderful Widgets, Inc." 或 "ОАО Примертех"。此成员已弃用,因为许多客户端不会显示它, 但为了向后兼容,它仍然是必需的字典成员。 依赖 方可以将其设置为等于RP ID,作为安全的默认值。
-
当由
PublicKeyCredentialUserEntity继承时,它是 对人类友好的用户 帐户标识符。此 标识符是客户端向用户显示的主要值,以帮助用户 理解凭据与哪个用户帐户相关联。此标识符的合适值示例包括 "alexm"、"+14255551234"、 "alex.mueller@example.com"、"alex.mueller@example.com (prod-env)", 或 "alex.mueller@example.com (ОАО Примертех)"。
-
依赖方可以让用户选择此 值。依赖方应该按照 [RFC8265] 第 3.4.3 节的规定,对 PRECIS IdentifierClass [RFC8264] 的 UsernameCasePreserved Profile 执行实施, 无论是在设置
name的 值时,还是向用户显示该值 时。 -
客户端应该 按照 [RFC8265] 第 3.4.3 节的规定,对 PRECIS IdentifierClass [RFC8264] 的 UsernameCasePreserved Profile 对
name的 值执行实施,然后再向用户显示该值或 将该值作为authenticatorMakeCredential 操作的参数。
-
当客户端、客户端 平台或认证器显示
name的 值时,它们应该始终使用 UI 元素在所显示的 值周围提供清晰边界,并且不允许其溢出到其他元素中 [css-overflow-3]。存储
name成员的值时, 可以按照§ 6.4.1 字符串 截断中的描述截断该值, 使用大于或等于 64 字节的大小限制。 -
5.4.2.
凭据生成的依赖方参数(字典 PublicKeyCredentialRpEntity)
PublicKeyCredentialRpEntity
字典用于在创建新凭据时提供附加的依赖方属性。
dictionary PublicKeyCredentialRpEntity :PublicKeyCredentialEntity {DOMString id ; };
5.4.3.
凭据生成的用户帐户参数(字典 PublicKeyCredentialUserEntity)
PublicKeyCredentialUserEntity
字典用于在创建新
凭据时提供附加的用户帐户属性。
dictionary PublicKeyCredentialUserEntity :PublicKeyCredentialEntity {required BufferSource id ;required DOMString displayName ; };
id, 类型为BufferSource-
用户帐户的用户句柄。 用户句柄是 最大长度为 64 字节的不透明字节序列, 并非用于向用户显示。
为确保安全运行,身份验证和授权 决策必须基于此
id成员,而不是displayName或name成员。请参阅[RFC8266]第 6.1 节。用户句柄不得 包含关于用户的个人身份信息,例如用户名或电子邮件 地址; 详情请参阅§ 14.6.1 用户句柄内容。用户句柄不得 为空。
用户句柄不应该 在不同用户帐户之间使用恒定值, 即使对于不可发现凭据也是如此,因为某些 认证器始终会创建可发现凭据。 因此,恒定的用户 句柄会使用户无法在依赖方处将此类认证器 用于多个用户 帐户。
displayName, 类型为 DOMString-
用户帐户的一个人类友好的名称,仅用于 显示。依赖 方应该让用户选择此值,并且不应该对该选择施加超过必要程度的限制。 如果没有合适或人类友好的名称 可用,则依赖方应该将此值设置为空字符串。
此标识符的合适值示例包括 "Alex Müller"、"Alex Müller (ACME Co.)" 或 "田中倫"。
-
依赖 方在将
displayName的值设置为非空字符串, 或向用户显示非空值时,应该按照 [RFC8266] 第 2.3 节中针对 PRECIS FreeformClass [RFC8264] 的 Nickname Profile 所规定的方式执行强制处理。 -
客户端应该按照 [RFC8266] 第 2.3 节的规定,对 PRECIS FreeformClass [RFC8264] 的 Nickname Profile, 对
displayName的 值执行实施,然后再向用户显示非空值或 将非空值作为authenticatorMakeCredential 操作的参数。
当客户端、客户端 平台或认证器显示
displayName的值时,它们应该始终使用 UI 元素为所显示的 值提供清晰的边界,并且不允许其溢出到其他元素[css-overflow-3]中。存储
displayName成员的值时, 可以按照§ 6.4.1 字符串 截断中的描述,使用大于或等于 64 字节的大小限制对该值进行截断。 -
5.4.4.
认证器选择条件(字典 AuthenticatorSelectionCriteria)
WebAuthn 依赖
方可以使用 AuthenticatorSelectionCriteria
字典来指定其对认证器
属性的要求。
dictionary AuthenticatorSelectionCriteria {DOMString authenticatorAttachment ;DOMString residentKey ;boolean requireResidentKey =false ;DOMString userVerification = "preferred"; };
authenticatorAttachment, 类型为DOMString-
如果存在此成员,则符合条件的认证器将被筛选为仅包括 以指定认证器附着模式附着的认证器(另请参阅§ 6.2.1 认证器附着 模式)。 如果不存在此成员,则任何附着模式都可接受。 该值应该是
AuthenticatorAttachment的成员,但客户端 平台必须忽略未知值, 将未知值视为该成员不 存在。另请参阅
PublicKeyCredential的authenticatorAttachment成员,它可以指示成功执行create()或get()操作时使用了哪种认证器附着模式。 residentKey, 类型为 DOMString-
指定依赖方希望创建客户端可发现凭据的程度。 出于历史原因,其命名保留了已弃用的“resident”术语。该值 应该是
ResidentKeyRequirement的成员,但客户端 平台必须忽略未知值,将未知值视为该成员不存在。如果未给出值,则当requireResidentKey为true时,有效 值为required;当其为false或不存在时,则为discouraged。有关
residentKey的值及其语义的说明,请参阅ResidentKeyRequirement。 requireResidentKey, 类型为boolean,默认为false-
此成员为了与 WebAuthn 第 1 级向后兼容而保留,并且出于历史 原因,其命名针对可发现 凭据保留了已弃用的“resident”术语。依赖方当且仅当
residentKey被设置为required时,才应该将其设置为true。 userVerification, 类型为DOMString,默认为"preferred"-
此成员指定依赖方对
create()操作的用户 验证要求。 该值应该是UserVerificationRequirement的成员,但客户端 平台必须忽略未知值,将未知值视为该成员不存在。有关
userVerification的值及其语义的说明,请参阅UserVerificationRequirement。
5.4.5. 认证器附着方式枚举(枚举 AuthenticatorAttachment)
此枚举的值描述认证器的附着
模式。
依赖方在调用 navigator.credentials.create()
创建凭据时,使用它来表达首选的认证器附着模式;客户端则使用它报告完成注册或身份验证仪式时所使用的认证器附着模式。
enum AuthenticatorAttachment {"platform" ,"cross-platform" };
注:AuthenticatorAttachment
枚举有意不被引用,请参阅§ 2.1.1
作为 DOMString 类型的枚举。
注:认证器
附着模式选择选项仅在 [[Create]](origin, options, sameOriginWithAncestors)
操作中可用。依赖方
可以使用它,例如确保用户拥有一个漫游凭据,以便
在另一个客户端
设备上进行身份验证;或者专门注册一个平台凭据,以便使用特定客户端设备更轻松地重新进行身份验证。
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作没有认证器附着模式选择选项。
客户端和用户将使用当时可用且方便的任何凭据,
但须受 allowCredentials
选项约束。
5.4.6.
驻留密钥要求枚举(枚举 ResidentKeyRequirement)
enum ResidentKeyRequirement {"discouraged" ,"preferred" ,"required" };
注:ResidentKeyRequirement
枚举有意不被引用,请参阅§ 2.1.1
作为 DOMString 类型的枚举。
此枚举的值描述依赖方对客户端可发现凭据(以前 称为驻留 凭据或驻留 密钥)的要求:
discouraged-
依赖方 倾向于创建服务器端凭据,但也会接受 客户端可发现凭据。 客户端和认证器 应该尽可能创建服务器端凭据。
注:依赖方无法要求所创建的凭据一定是服务器端凭据,并且凭据属性 扩展可能不会为
rk属性返回值。因此,依赖方可能不知道某个凭据是否为服务器端凭据,从而也不知道 创建具有相同用户句柄的第二个凭据是否会逐出第一个。 preferred-
依赖方 强烈倾向于创建客户端可发现凭据, 但也会接受 服务器端凭据。 客户端和认证器 应该尽可能创建可发现凭据。 例如,如果创建可发现凭据需要设置用户验证,则客户端应该 引导用户完成设置。这优先于
userVerification的设置。 required
注:依赖方可以使用凭据
属性扩展的驻留密钥凭据
属性来获取认证器是否创建了客户端可发现凭据的信息。
当
options.
使用 authenticatorSelection.residentKeydiscouraged
或 preferred
值时,这一点很有用,
因为在这些情况下,认证器既可能创建
客户端可发现凭据,也可能创建服务器端
凭据。
5.4.7.
证明传送首选项枚举(枚举 AttestationConveyancePreference)
WebAuthn 依赖
方可以使用 AttestationConveyancePreference
来指定其在凭据生成期间有关证明传送的偏好。
enum AttestationConveyancePreference {"none" ,"indirect" ,"direct" ,"enterprise" };
注:AttestationConveyancePreference
枚举有意不被引用,请参阅§ 2.1.1
作为 DOMString 类型的枚举。
none-
依赖方 对认证器证明不感兴趣。例如,这是为了 可能避免必须获得用户同意才能将身份识别信息转发给依赖方, 或者避免到证明 CA或匿名化 CA的一次 往返。 如果认证器生成的证明语句 不是自证明, 则客户端会将其替换为 无证明语句。
这是默认值,未知值会回退到此值的行为。
indirect-
依赖方 希望接收可验证的证明语句, 但允许客户端决定 如何获得此类证明语句。 客户端可以将认证器生成的证明语句 替换为由匿名化 CA生成的语句, 以保护用户隐私,或帮助依赖方在异构生态系统中进行证明 验证。
注:在这种情况下,无法保证依赖方 会获得可验证的证明语句。 例如,当认证器采用自证明 且客户端未经修改地传递 证明语句时。
directenterprise-
依赖方 希望接收企业证明,它是一种证明语句, 其中可能包含可唯一标识认证器的信息。这适用于 企业内部的受控部署,在这种部署中,组织希望将注册 绑定到特定认证器。除非用户代理或认证器配置允许针对所请求的RP ID提供此类证明,否则用户代理不得提供此类证明。
如果允许,用户代理应该向认证器发出企业证明请求的信号(在调用时),并将生成的AAGUID和证明语句未经修改地传递给依赖方。
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-
此成员指定一个挑战,认证器在生成身份验证断言时,会对该挑战以及其他数据进行签名。请参阅§ 13.5.3 密码学挑战安全 注意事项。
timeout, 类型为unsigned longrpId, 类型为DOMString-
此可选成员指定依赖方声称的RP ID。 客户端必须验证依赖方的源与此RP ID的作用域相匹配。 认证器 必须验证 此RP ID与用于身份验证 仪式的凭据的rpId完全相等。
如果未指定,其值将 为
CredentialsContainer对象的相关设置对象的源的 有效域。 allowCredentials, 类型为 sequence<PublicKeyCredentialDescriptor>, 默认为[]-
此可选成员由客户端用于查找符合此身份验证 仪式条件的认证器。 它可以通过两种方式使用:
-
如果要进行身份验证的用户 帐户已经确定(例如,如果用户已输入 用户名), 则依赖 方应该使用此成员列出 用户帐户中凭据记录的凭据描述符。 这通常应该包括用户帐户中的所有凭据记录。
项应该尽可能指定
transports。 这有助于客户端 针对任何给定情况优化用户体验。 还请注意,当请求用户验证时,依赖方无需筛选列表 — 如果userVerification被设置为required, 客户端将 自动忽略不符合条件的凭据。另请参阅§ 14.6.3 通过凭据 ID 泄露隐私隐私注意事项。
-
如果要进行身份验证的用户 帐户尚未确定, 则依赖 方可以将此成员留空或 不指定。 在这种情况下,此身份验证仪式中将仅使用可发现凭据, 并且可以通过生成的
AuthenticatorAssertionResponse的userHandle来识别用户 帐户。 如果可用的认证器包含多个限定作用域于依赖 方的可发现凭据, 则客户端平台或认证器会显示这些凭据 供用户选择(请参阅步骤 7 和§ 6.3.3 authenticatorGetAssertion 操作)。
如果列表不为空,且所列凭据均无法使用,则客户端必须返回错误。
列表按偏好程度降序排列:列表中的第一项是最优先的凭据,最后一项是最不优先的。
-
userVerification, 类型为DOMString,默认为"preferred"-
此可选成员指定依赖方对于
get()操作的用户验证要求。该值应该是UserVerificationRequirement的成员,但客户端 平台必须忽略未知值,将未知值视为该成员不存在。符合条件的认证器将被筛选为仅包含 能够满足此要求的认证器。有关
userVerification的值及其语义的说明,请参阅UserVerificationRequirement。 hints, 类型为 sequence<DOMString>,默认为[]-
此可选成员包含来自
PublicKeyCredentialHint的零个或多个元素,用于指导用户代理与用户交互。请注意,尽管这些元素取自该枚举,其类型仍为DOMString。请参阅§ 2.1.1 作为 DOMString 类型的枚举。 extensions, 类型为 AuthenticationExtensionsClientInputs-
依赖方可以 使用此可选成员提供客户端扩展输入, 请求客户端和认证器执行附加处理。
扩展框架定义于§ 9 WebAuthn 扩展中。 一些扩展定义于§ 10 定义的扩展中; 有关已注册WebAuthn 扩展的最新列表,请查阅由 [RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]。
5.6. 使用 AbortSignal 中止操作
鼓励开发者利用 AbortController
管理
[[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作。
有关详细说明,请参阅DOM § 3.3 在
API 中使用
AbortController 和 AbortSignal 对象一节。
注:DOM § 3.3 在 API 中使用
AbortController 和 AbortSignal 对象一节规定,与
AbortController
集成的 Web 平台 API 必须在 AbortSignal
被中止后立即拒绝 promise。
鉴于 [[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法复杂的继承和并行化结构,这两个 API 的算法通过在三个位置检查
中止属性来满足此
要求。对于
[[Create]](origin, options, sameOriginWithAncestors),
首先在凭据管理
1 § 2.5.4 创建凭据中调用 [[Create]](origin, options, sameOriginWithAncestors)
之前立即检查中止属性,
然后在§ 5.1.3 创建新凭据 - PublicKeyCredential 的
[[Create]](origin, options, sameOriginWithAncestors) 内部方法中,在认证器
会话开始之前检查,最后在
认证器会话期间检查。对于
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
也是如此。
5.7. WebAuthn 扩展输入和输出
以下各小节定义用于传送WebAuthn 扩展输入和输出的数据类型。
注:认证器 扩展输出作为认证器数据的一部分传送(请参阅表 1)。
注:下面定义的类型 — AuthenticationExtensionsClientInputs
和 AuthenticationExtensionsClientOutputs
— 同时适用于注册扩展和身份验证扩展。
其名称中的 "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-
此成员包含依赖方提供的挑战的 base64url 编码。 请参阅§ 13.5.3 密码学挑战 安全注意事项。
origin, 类型为DOMStringcrossOrigin, 类型为boolean-
此可选成员包含传递给内部方法的
sameOriginWithAncestors参数值的反值。 topOrigin, 类型为DOMString-
此可选成员包含请求者的完全限定顶层源,采用 [RFC6454]定义的语法。仅当调用来自不与其祖先同源的 上下文,即
crossOrigin为true时,才设置它。 - [保留] tokenBinding
-
此可选成员包含与依赖方通信时所使用的令牌 绑定协议[TokenBinding]状态的信息。其缺失表示客户端不支持令牌绑定
注:虽然令牌 绑定存在于 WebAuthn 第 1 级和第 2 级中,但预计不会在第 3 级中使用。tokenBinding 字段被保留,以免 被重新用于其他目的。
status, 类型为DOMString-
此成员应该是
TokenBindingStatus的成员,但客户端平台必须忽略未知值, 将未知值视为 tokenBinding 成员不存在。在已知时,此成员是 以下值之一:注:
TokenBindingStatus枚举有意不被引用,请参阅§ 2.1.1 作为 DOMString 类型的枚举。 id, 类型为DOMString-
如果
status为present, 则此成员必须存在, 并且必须是与依赖方通信时所使用的令牌绑定 ID的base64url 编码。
CollectedClientData
结构由客户端用于计算以下量:
- 客户端数据的 JSON 兼容 序列化
-
这是在
CollectedClientData字典上执行JSON 兼容 序列化算法的结果。 - 序列化 客户端数据的哈希
-
这是客户端构造的客户端数据的 JSON 兼容 序列化的哈希(使用 SHA-256 计算)。
5.8.1.1. 序列化
CollectedClientData
的序列化是将 JSON 序列化为字节算法的一个子集。也就是说,它生成
CollectedClientData
的有效 JSON 编码,
但还提供附加结构,验证方可以利用该结构来避免集成完整的 JSON
解析器。虽然建议验证方执行标准 JSON 解析,但在完整 JSON
解析器过大的上下文中,它们可以使用下面的更有限的算法。此验证算法仅需要base64url 编码、追加
字节字符串(可通过写入固定模板来实现)以及简单的条件检查
(假设已知输入无需转义)。
序列化算法通过将连续的字节字符串追加到最初为空的部分结果中, 直至获得完整结果。
-
令 result 为空字节字符串。
-
将 0x7b2274797065223a (
{"type":) 追加到 result。 -
将 CCDToString(
type) 追加到 result。 -
将 0x2c226368616c6c656e6765223a (
,"challenge":) 追加到 result。 -
将 CCDToString(
challenge) 追加到 result。 -
将 0x2c226f726967696e223a (
,"origin":) 追加到 result。 -
将 CCDToString(
origin) 追加到 result。 -
将 0x2c2263726f73734f726967696e223a (
,"crossOrigin":) 追加到 result。 -
如果
crossOrigin不存在,或为false:-
将 0x66616c7365 (
false) 追加到 result。
-
-
否则:
-
将 0x74727565 (
true) 追加到 result。
-
-
如果
topOrigin存在:-
将 0x2c22746f704f726967696e223a (
,"topOrigin":) 追加到 result。 -
将 CCDToString(
topOrigin) 追加到 result。
-
-
创建
CollectedClientData的临时副本,并移除字段type、challenge、origin、crossOrigin(如果存在)和topOrigin(如果存在)。 -
如果临时副本中没有剩余字段,则:
-
将 0x7d (
}) 追加到 result。
-
-
否则:
-
在临时副本上调用将 JSON 序列化为字节,生成字节字符串 remainder。
-
将 0x2c (
,) 追加到 result。 -
移除 remainder 的前导字节。
-
将 remainder 追加到 result。
-
-
序列化的结果是 result 的值。
函数 CCDToString 在上述算法中使用,并定义如下:
-
令 encoded 为空字节字符串。
-
将 0x22 (
") 追加到 encoded。 -
在给定对象上调用 ToString,将其转换为 字符串。
-
对于所得字符串中的每个码点,如果该码点:
- 位于集合 {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) 追加到 encoded,随后追加四个小写十六进制 数字,将其解释为以 16 为基数的数字时表示该码点。
-
将 0x22 (
") 追加到 encoded。 -
此函数的结果是 encoded 的值。
5.8.1.2. 有限验证算法
如果验证方无法支持完整的 JSON 解析器,则可以使用以下算法验证已编码的 CollectedClientData:
-
算法的输入为:
-
一个字节字符串 clientDataJSON,其中包含
clientDataJSON— 即 待验证的序列化CollectedClientData。 -
一个字符串 type,其中包含预期的
type。 -
一个字节字符串 challenge,其中包含在
PublicKeyCredentialRequestOptions或PublicKeyCredentialCreationOptions中给出的挑战字节字符串。 -
一个字符串 origin,其中包含向用户代理发出请求的预期
origin。 -
一个可选字符串 topOrigin,如果可用,其中包含向用户代理发出请求的预期
topOrigin。 -
一个 Boolean 值 requireTopOrigin,当且仅当在 topOrigin 已定义而 clientDataJSON 中不存在
topOrigin属性时验证应该 失败,该值才为 true。这意味着,当且仅当 requireTopOrigin 为
false时, 此验证算法与 Web 身份验证第 2 级JSON 兼容 序列化算法[webauthn-2-20210408] 向后兼容。
-
-
令 expected 为空字节字符串。
-
将 0x7b2274797065223a (
{"type":) 追加到 expected。 -
将 CCDToString(type) 追加到 expected。
-
将 0x2c226368616c6c656e6765223a (
,"challenge":) 追加到 expected。 -
对 challenge 执行base64url 编码,生成字符串 challengeBase64。
-
将 CCDToString(challengeBase64) 追加到 expected。
-
将 0x2c226f726967696e223a (
,"origin":) 追加到 expected。 -
将 CCDToString(origin) 追加到 expected。
-
将 0x2c2263726f73734f726967696e223a (
,"crossOrigin":) 追加到 expected。 -
如果 topOrigin 已定义:
-
将 0x74727565 (
true) 追加到 expected。 -
如果 requireTopOrigin 为 true, 或者 0x2c22746f704f726967696e223a (
,"topOrigin":) 是 clientDataJSON 中从等于 expected 长度的偏移开始的子字符串的前缀:-
将 0x2c22746f704f726967696e223a (
,"topOrigin":) 追加到 expected。 -
将 CCDToString(topOrigin) 追加到 expected。
-
-
-
否则,即 topOrigin 未定义:
-
将 0x66616c7365 (
false) 追加到 expected。
-
-
如果 expected 不是 clientDataJSON 的前缀,则验证失败。
-
如果 clientDataJSON 的长度未至少比 expected 多一个字节,则 验证失败。
-
如果 clientDataJSON 中位于等于 expected 长度的偏移处的字节:
- 是 0x7d
-
验证成功。
- 是 0x2c
-
验证成功。
- 否则
-
验证失败。
5.8.1.3. 未来发展
为了保持与有限验证
算法的兼容性,本规范的未来版本不得从 CollectedClientData
中移除字段 type、
challenge、
origin、
crossOrigin
或 topOrigin。
它们也不得修改序列化算法以改变
这些字段的序列化顺序,或在它们之间插入新字段。
如果向 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()
中用于确定客户端当前是否以及如何能够访问该凭据。
凭据记录的凭据
描述符是该凭据记录属性的一个子集,
并镜像由
create()
和 get()
返回的 PublicKeyCredential
对象的某些字段。
type, 类型为DOMString-
此成员包含调用者所指公钥凭据的类型。 该值应该是
PublicKeyCredentialType的成员,但客户端 平台必须忽略任何具有未知type的PublicKeyCredentialDescriptor。 但是,如果所有元素都因未知的type而被忽略, 则必须导致错误,因为空的allowCredentials在语义上不同。此值应该设置为表示所标识公钥凭据源的凭据 记录中type 项的值。 这镜像
PublicKeyCredential的type字段。 id, 类型为BufferSource-
此值应该设置为表示所标识公钥凭据源的凭据记录 中id 项的值。 这镜像
PublicKeyCredential的rawId字段。 transports, 类型为 sequence<DOMString>-
此可选成员包含关于客户端可能如何与调用者所指公钥凭据的管理 认证器通信的提示。 这些值应该是
AuthenticatorTransport的成员,但客户端 平台必须忽略未知值。此值应该设置为表示所标识公钥凭据源的凭据 记录中transports 项的值。 这镜像由
create()操作创建的PublicKeyCredential结构的方法。response.getTransports()
5.8.4. 认证器传输枚举(枚举 AuthenticatorTransport)
enum AuthenticatorTransport {"usb" ,"nfc" ,"ble" ,"smart-card" ,"hybrid" ,"internal" };
注:AuthenticatorTransport
枚举有意不被引用,请参阅§ 2.1.1
作为 DOMString 类型的枚举。
getTransports()
获知公钥凭据支持的传输方式。
5.8.5. 密码算法标识符(typedef COSEAlgorithmIdentifier)
typedef long ;COSEAlgorithmIdentifier
COSEAlgorithmIdentifier
的值是标识密码算法的数字。
算法标识符应该使用在 IANA COSE Algorithms 注册表[IANA-COSE-ALGS-REG]中注册的值,
例如,-7 表示 "ES256",-257 表示 "RS256"。
COSE 算法注册表保留了一些自由度,由 COSE 密钥中的其他参数指定。为促进互操作性,本规范 对凭据公钥作出以下附加保证:
-
算法为 -7 (ES256) 的密钥必须将 1 (P-256) 指定为crv 参数,并且不得使用 压缩点形式。
-
算法为 -9 (ESP256) 的密钥不得使用压缩点形式。
-
算法为 -35 (ES384) 的密钥必须将 2 (P-384) 指定为crv 参数,并且不得使用 压缩点形式。
-
算法为 -51 (ESP384) 的密钥不得使用压缩点形式。
-
算法为 -36 (ES512) 的密钥必须将 3 (P-521) 指定为crv 参数,并且不得使用 压缩点形式。
-
算法为 -52 (ESP512) 的密钥不得使用压缩点形式。
-
算法为 -8 (EdDSA) 的密钥必须将 6 (Ed25519) 指定为crv 参数。(这些在 COSE 中始终使用 压缩形式。)
注:使用这些算法正确 实现签名验证需要进行许多检查。其中一项是,在处理未压缩 椭圆曲线点时,实现应该检查该点是否确实位于曲线上。之所以特别 强调此检查,是因为人们认为它尤其容易落入密码学 库与其他代码之间的空白地带。
5.8.6.
用户验证要求枚举(枚举 UserVerificationRequirement)
enum UserVerificationRequirement {"required" ,"preferred" ,"discouraged" };
WebAuthn 依赖方可能要求其某些操作执行用户验证,而其他操作不要求, 并可以使用此类型表达其 需求。
注:UserVerificationRequirement
枚举有意不被引用,请参阅§ 2.1.1
作为 DOMString 类型的枚举。
5.8.7.
客户端能力枚举(枚举 ClientCapability)
enum ClientCapability {"conditionalCreate" ,"conditionalGet" ,"hybridTransport" ,"passkeyPlatformAuthenticator" ,"userVerifyingPlatformAuthenticator" ,"relatedOrigins" ,"signalAllAcceptedCredentials" ,"signalCurrentUserDetails" ,"signalUnknownCredential" };
此枚举定义一组有限的客户端能力,WebAuthn 依赖方可以 对其进行评估,以向用户提供特定的工作流和体验。
依赖方可以使用
PublicKeyCredential
的 getClientCapabilities()
方法获取可用能力的描述。
注: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传输使用通行密钥 平台认证器。 userVerifyingPlatformAuthenticatorrelatedOriginssignalAllAcceptedCredentialssignalCurrentUserDetails,signalUnknownCredential
5.8.8. 用户代理提示枚举(枚举 PublicKeyCredentialHint)
enum PublicKeyCredentialHint {"security-key" ,"client-device" ,"hybrid" , };
注:PublicKeyCredentialHint
枚举有意不被引用,请参阅§ 2.1.1
作为 DOMString 类型的枚举。
提示可以与凭据 transports
和 authenticatorAttachment
中包含的信息相矛盾。
当发生这种情况时,以提示为准。(请注意,使用可发现凭据时不会提供 transports
值,因此提示成为表达此类请求某些方面的唯一
途径。)
security-key-
表示依赖方认为用户会使用物理安全密钥满足此 请求。例如,企业依赖方如果已向 员工发放安全密钥,并且只接受这些认证器 用于注册和身份验证, 则可以设置此提示。
为与较旧的用户代理兼容,当此提示用于
PublicKeyCredentialCreationOptions时,authenticatorAttachment应该设置为cross-platform。 client-device-
表示依赖方认为用户会使用附着到客户端设备的平台认证器满足此 请求。
为与较旧的用户代理兼容,当此提示用于
PublicKeyCredentialCreationOptions时,authenticatorAttachment应该设置为platform。 hybrid-
表示依赖方认为用户会使用智能手机等通用认证器满足此 请求。例如,面向消费者的依赖 方可能认为只有少部分客户拥有专用 安全密钥。此选项还意味着本地平台 认证器不应该在 UI 中被突出显示。
为与较旧的用户代理兼容,当此提示用于
PublicKeyCredentialCreationOptions时,authenticatorAttachment应该设置为cross-platform。
5.9. 权限策略集成
本规范定义三个策略控制的功能[Permissions-Policy]。
其中两个功能由功能标识符令牌
"publickey-credentials-create"
和
"publickey-credentials-get"
标识。
它们的默认允许列表均为
'self'。
第三个功能由功能标识符令牌
"publickey-credentials-remote-client-data-json"
标识。
其默认允许列表为 'none',
这意味着默认情况下对所有源禁用此功能。此功能也是一个强大功能([Permissions]),其名称为
"publickey-credentials-remote-client-data-json",默认权限状态为 "denied"。
Document
的
权限策略决定该文档中的任何内容是否被允许成功调用Web 身份验证 API,即通过
navigator.credentials.create({publicKey:..., ...})
或
navigator.credentials.get({publicKey:..., ...})
调用。如果在任何文档中被禁用,则文档中的任何内容都不会被允许使用
上述方法:尝试这样做将返回错误。
注:[CREDENTIAL-MANAGEMENT-1]中规定的算法执行实际的权限
策略评估。这是因为此类策略评估需要在能够访问当前设置对象时进行。[[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
内部方法没有这种
访问权限,因为它们由 CredentialsContainer
的创建 Credential和请求 Credential抽象
操作[CREDENTIAL-MANAGEMENT-1]并行调用。
5.10. 在 iframe 元素中使用 Web 身份验证
Web
身份验证 API默认在跨源
iframe
中禁用。
要覆盖此默认策略并指示跨源
iframe
被允许调用Web 身份验证
API的
[[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法,
请在
iframe
元素上指定
allow
属性,并分别在
allow
属性值中包含
publickey-credentials-create
或
publickey-credentials-get
功能标识符令牌。
在嵌入上下文中使用 WebAuthn API 的依赖方应该查阅§ 13.5.2 嵌入使用的可见性 注意事项,了解有关UI 重新装饰及其可能缓解措施的内容。
WebAuthn 客户端和客户端平台应该 参考§ 14.5.5 WebAuthn 凭据的跨源使用以了解 其他隐私注意事项。
5.11. 跨相关源使用 Web 身份验证
默认情况下,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 提供。该
JSON 文档必须按如下方式返回:
-
内容类型必须为
application/json。 -
顶层 JSON 对象必须包含名为
origins的键,其值必须是 包含一个或多个 Web 源字符串的数组。
例如,对于 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 客户端 必须支持至少五个可注册源标签。客户端策略应该定义 上限以防止滥用。
WebAuthn 客户端向此 well-known
端点发出的请求必须不带凭据、不带引用来源,
并使用 https: 方案。在
跟随重定向时,WebAuthn
客户端必须显式要求所有重定向也使用 https: 方案。
支持此功能的WebAuthn 客户端
应该在其对 getClientCapabilities() 的响应中包含 relatedOrigins。
WebAuthn 客户端和客户端平台应该 参考§ 14.5.5 WebAuthn 凭据的跨源使用以了解 其他隐私注意事项。
5.11.1. 验证相关源
给定参数 callerOrigin 和 rpIdRequested,相关源验证过程 如下:
-
令 maxLabels 为客户端策略允许的可注册源 标签的最大数量。
-
获取 RP ID rpIdRequested 的
webauthnwell-known URL[RFC8615](即https://rpIdRequested/.well-known/webauthn), 不带凭据,不带引用来源,并使用https:方案。-
如果获取失败、响应的内容类型不是
application/json,或者(跟随重定向后)状态码不是 200,则抛出一个 "SecurityError"DOMException。 -
如果资源正文不是有效的 JSON 对象,则抛出一个 "
SecurityError"DOMException。 -
如果 JSON 对象的 origins 属性值缺失,或不是 字符串数组,则抛出一个 "
SecurityError"DOMException。
-
-
令 labelsSeen 为新的空集合。
-
对于 origins 中的每个 originItem:
-
返回
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 API底层算法会整理这些选项并 将其传递给下面定义的相应 认证器操作。
在此抽象模型中,认证器提供密钥管理和密码学签名。它可以嵌入 WebAuthn 客户端中,也可以完全位于独立设备中。认证器本身可以包含一个 密码学模块,该模块以比认证器其余部分更高的安全级别 运行。这对于嵌入 WebAuthn 客户端中的认证器尤其重要,因为在这些情况下,此密码学模块(例如可能是 TPM)可以被 认为比认证器的其余部分更可信。
每个认证器存储一个凭据映射,这是一个从(rpId、userHandle)到 公钥凭据源的映射。
此外,每个认证器都有一个认证器证明全局唯一标识符,即 AAGUID,它是一个 128 位 标识符, 用于指示认证器的类型(例如制造商和型号)。制造商必须选择 AAGUID,使该制造商制造的所有实质上相同的 认证器都具有相同的 AAGUID,并且与所有其他类型 认证器的 AAGUID 不同(具有高概率)。给定类型 认证器的 AAGUID 应该随机生成以确保这一点。依赖方可以使用 AAGUID 结合其他来源的信息推断 认证器的某些属性,例如 认证级别和密钥保护强度。依赖方可以使用 AAGUID 尝试在不请求和验证证明的情况下识别 认证器的制造商,但如果没有证明,则无法证明 AAGUID 的真实性。
认证器的主要功能是提供WebAuthn 签名,这些签名绑定到各种上下文数据。 当签名请求从服务器传递到 认证器时,这些 数据在栈的不同层次被观察并添加。在验证签名时,服务器会将这些绑定与预期值进行检查。这些 上下文绑定 分为两类:由依赖方或客户端添加的,称为客户端数据;以及由认证器添加的, 称为认证器数据。认证器对客户端数据进行签名,但除此之外并不关心 其内容。为了节省认证器的带宽和处理需求,客户端会对客户端数据进行哈希,并且 只将结果发送给认证器。认证器会对 序列化客户端 数据的哈希与其自身的认证器数据的组合进行签名。
此设计的目标可以概括如下。
-
生成签名的方案应该适应客户端设备与 认证器之间链路 在带宽和/或延迟方面非常受限的情况。例如 Bluetooth Low Energy 和近场 通信。
-
认证器处理的数据应该较小,并且易于在底层代码中解释。尤其是,认证器 不应该必须解析 JSON 等高级编码。
-
客户端和 认证器都应该能够根据需要灵活添加上下文绑定。
-
该设计旨在尽可能重用现有编码格式,以帮助采用 和实现。
认证器为两个不同目的生成密码学签名:
-
当通过 authenticatorMakeCredential 操作创建新公钥凭据时,会生成证明 签名。证明签名提供认证器和凭据某些属性的密码学 证明。例如,证明签名 断言认证器类型(由其 AAGUID 表示)和凭据公钥。证明签名由证明私钥签名,该密钥根据 所需的证明类型选择。 有关证明的更多详细信息,请参阅§ 6.5 证明。
-
当调用authenticatorGetAssertion 方法时,会生成断言 签名。它表示 认证器断言用户已同意特定交易,例如登录 或完成购买。因此,断言签名断言持有特定 凭据私钥的认证器 已尽其能力确认,请求此交易的用户 与同意 创建该特定公钥凭据的用户相同。它还断言称为客户端 数据的其他信息,这些信息可能对调用者有用,例如提供用户同意的方式, 以及认证器向用户显示的提示。断言签名格式如 下面的图 4所示。
术语 WebAuthn 签名同时指证明签名和断言签名。 这些签名的格式以及生成它们的过程将在下面规定。
6.1. 认证器数据
认证器 数据结构编码由认证器作出的上下文绑定。这些绑定由 认证器自身控制,并从WebAuthn 依赖方对 认证器安全属性的评估中获得其可信度。在一种极端情况下,认证器可能嵌入客户端中,其绑定的可信度 可能不高于客户端数据。在另一个 极端情况下,认证器可能是具有高安全性硬件和 软件的独立实体,并通过安全通道连接到客户端。在这两种情况下,依赖方都以相同 格式接收认证器数据, 并利用其对认证器的了解作出信任决策。
认证器 数据采用紧凑但可扩展的编码。这是所期望的,因为认证器可能是能力 有限且功耗要求较低的设备,其软件栈比客户端平台简单得多。
认证器 数据结构是一个 37 字节或更多字节的数组, 其布局如表 所示。
| 名称 | 长度(字节) | 描述 |
|---|---|---|
| rpIdHash | 32 | 凭据所限定作用域到的RP ID的 SHA-256 哈希。 |
| flags | 1 | 标志(位 0 是最低有效位): |
| signCount | 4 | 签名 计数器,32 位无符号大端整数。 |
| attestedCredentialData | 可变(如果存在) | 经证明的凭据数据(如果存在)。有关详细信息,请参阅§ 6.5.1 经证明的凭据数据。 其长度取决于 被证明的凭据 ID和凭据公 钥的长度。 |
| extensions | 可变(如果存在) | 扩展定义的认证器数据。这是一个 CBOR [RFC8949] 映射,以扩展标识符作为键, 以认证器扩展输出作为 值。有关详细信息,请参阅§ 9 WebAuthn 扩展。 |
RP ID最初在创建凭据时从客户端接收,并在生成断言时 再次接收。 但是,它在一些重要方面不同于其他客户端 数据。首先,与客户端数据不同,凭据的RP ID不会 在操作之间发生变化,而是在该凭据的整个生命周期内保持不变。其次,在authenticatorGetAssertion 操作期间,认证器会验证它, 方法是验证所请求凭据所限定作用域到的RP ID与客户端提供的RP ID完全匹配。
-
当且仅当认证器执行了用户在场测试时,才必须设置UP标志。 当且仅当认证器执行了用户验证时,才必须设置UV标志。
RFU位必须设置为零。注:如果认证器同时执行了用户在场 测试和用户验证, 可能组合在单个授权手势中, 那么认证器将同时设置UP标志和UV标志。
-
当且仅当凭据是多设备凭据时,才必须设置BE标志。 此值在注册仪式后不得更改,如§ 6.1.3 凭据备份状态中所定义。
-
对于证明签名,认证器必须设置 AT标志并包含
attestedCredentialData。 对于断言 签名,不得设置AT标志,并且不得包含attestedCredentialData。
确定经证明的凭据数据的可变长度,需要根据前面的
credentialId的
长度确定
credentialPublicKey的
起始位置,然后确定
credentialPublicKey的
长度(另请参阅第 7 节,出自[RFC9052])。
6.1.1. 签名计数器注意事项
认证器应该实现签名计数器功能。从概念上讲,这些计数器由认证器按每个凭据
存储,或者作为整个认证器的全局计数器存储。凭据的签名计数器初始值由
authenticatorMakeCredential 返回的认证器数据中的
signCount
值指定。每次成功执行
authenticatorGetAssertion 操作时,签名计数器都会增加某个正值,
后续值会再次在认证器数据中返回给WebAuthn
依赖方。签名
计数器的用途是帮助依赖方检测克隆的认证器。对于保护措施有限的认证器,
克隆检测更加重要。
未实现签名计数器的认证器
会使认证器
数据中的
signCount
恒定为零。
依赖方存储最近一次authenticatorGetAssertion 操作的签名计数器。(如果从未对某个凭据执行过authenticatorGetAssertion,则使用
authenticatorMakeCredential 操作中的计数器。)在后续
authenticatorGetAssertion 操作中,依赖方会将存储的签名
计数器值与断言的认证器数据中返回的新
signCount
值进行比较。如果其中任一非零,并且新的
signCount
值小于或等于存储值,则可能存在克隆的认证器,或认证器可能
出现故障,
或者可能存在竞态条件,使依赖方接收和处理断言的顺序
与认证器生成断言的顺序不同。
检测到签名 计数器不匹配,并不能指示当前操作是由克隆认证器还是原始认证器执行的。依赖方应该根据各自情况适当地处理此情形, 即考虑其风险容忍度或可能导致计数器值不递增具有可接受理由的操作因素。
认证器:
-
应该实现按凭据的签名计数器。这可以防止 签名 计数器值在依赖方之间共享,并可能被用作 用户的关联句柄。认证器可以实现全局签名计数器, 即按认证器设置,但这对用户隐私较不友好。
-
应该确保签名计数器值不会 意外减小(例如,由于硬件故障)。
6.1.2. FIDO U2F 签名格式兼容性
断言签名的格式对认证器数据 结构与序列化客户端 数据的哈希的连接进行签名,它与 FIDO U2F 身份验证签名格式兼容(请参阅 第 5.4 节,出自 [FIDO-U2F-Message-Formats])。
这是因为 FIDO U2F 身份验证响应消息中已签名数据的前 37 个字节
构成有效的
认证器数据
结构,其余 32 个字节是序列化客户端
数据的哈希。在此
认证器数据
结构中,
rpIdHash
是 FIDO U2F 应用参数,除
UP 外的所有
标志
始终为零,并且
attestedCredentialData
和
extensions
永远不会存在。因此,可以使用与authenticatorGetAssertion 操作生成的其他断言签名相同的过程验证 FIDO U2F 身份验证签名。
6.1.3. 凭据备份状态
凭据备份 资格和当前备份状态通过认证器数据中的BE和BS标志传送,如表 中所定义。
BE标志的值在authenticatorMakeCredential 操作期间设置,并且不得 更改。
BS标志的值可以随着 公钥凭据源的当前状态随时间变化。下面的表 定义 有效组合及其含义。
建议依赖 方将这些标志的最新值与用户帐户一起存储,以便将来评估。
-
要求额外的认证器:
当BE标志设置为
0时,该凭据是单设备凭据,并且生成认证器永远不会 允许备份该凭据。单设备凭据无法抵御单个 设备丢失。依赖 方应该确保每个用户帐户 已注册额外的认证器,和/或已有 帐户恢复流程。 例如,可以提示用户设置额外的认证器,例如漫游 认证器,或能够使用多设备凭据的 认证器。
-
将用户升级为无密码帐户:
当BS标志从
0变为1时,认证器正在发出信号,表明凭据已备份,并受到保护而不受单个 设备丢失影响。依赖方可以 选择提示用户升级其帐户安全性并移除密码。
-
状态更改后添加额外因素:
当BS标志从
1变为0时,认证器正在发出信号,表明凭据不再备份, 并且不再受到保护而不受单个设备丢失影响。这可能由用户操作导致,例如 禁用备份服务, 或由错误导致,例如备份服务出现问题。当发生此转换时,依赖方应该引导用户完成 验证其其他身份验证因素的过程。 如果用户的帐户没有其他凭据,则应该引导他们添加 一个额外凭据, 以确保他们不会失去对帐户的访问。例如,可以提示用户 设置一个额外的认证器, 例如漫游认证器或能够使用多设备凭据的认证器。
6.2. 认证器分类
许多用例取决于所使用认证器的能力。 本节定义这些能力的一些术语、其最重要的组合, 以及这些组合支持哪些用例。
例如:
-
以后在同一客户端设备上重新进行身份验证时,平台 认证器可能最方便, 因为它直接内置在客户端设备中,而不是用户可能需要寻找的独立设备。
-
笔记本电脑可能支持通过 USB 和 Bluetooth 连接到漫游认证器, 而手机可能只支持 NFC。
以上示例说明了主要的认证器类型特征:
这些特征相互独立,理论上可以以任意方式组合, 但表 列出并命名了一些特别重要的认证器类型。
| 认证器类型 | 认证器附着模式 | 凭据存储模式 | 身份验证因素能力 |
|---|---|---|---|
| 第二因素平台认证器 | 平台 | 任一 | 具备单因素能力 |
| 用户验证平台认证器 | 平台 | 任一 | 具备多因素能力 |
| 第二因素漫游认证器 | 跨平台 | 服务器端存储 | 具备单因素能力 |
| 通行密钥漫游认证器 | 跨平台 | 客户端存储 | 具备多因素能力 |
| 通行密钥平台认证器 | 平台(transport
= internal)
或跨平台(transport
= hybrid)
| 客户端存储 | 具备多因素能力 |
第二因素平台认证器便于 在同一客户端设备上重新进行身份验证, 并可用于在启动新会话和恢复 现有会话时增加额外的安全层。 第二因素漫游认证器更可能 用于首次在特定客户端设备上进行身份验证, 或在多个用户共享的客户端设备上进行身份验证。
通行密钥平台认证器和通行密钥漫游认证器 支持无密码多因素 身份验证。 除了证明持有凭据私钥之外, 这些认证器还支持用户验证作为第二个身份验证因素, 通常是 PIN 或生物特征识别。 因此,认证器可以 充当两种身份验证因素, 从而支持多因素 身份验证,同时无需与依赖方共享密码。 这些认证器还支持可发现凭据,也称为通行密钥, 这意味着它们还支持无需输入用户名的身份验证流程。
用户验证平台认证器类别
在很大程度上已被通行密钥平台认证器类别取代,
但该定义仍由 isUserVerifyingPlatformAuthenticatorAvailable
方法使用。
表 中未命名的组合 具有较不突出的用例:
-
漫游认证器如果具备可发现凭据能力但不具备多因素能力, 则可以用于无需用户名的单因素身份验证, 其中用户由用户句柄自动识别, 并仅将持有凭据私钥作为唯一的身份验证因素。 这在某些情况下可能有用,但会使用户特别容易受到认证器被盗的影响。
-
漫游认证器如果具备多因素能力但不 具备可发现凭据能力, 则可用于多因素 身份验证,但要求先识别用户, 这存在泄露个人身份信息的风险;请参阅§ 14.6.3 通过凭据 ID 泄露隐私。
以下小节更深入地定义认证器 附着模式、 凭据存储模式和身份验证 因素能力这些方面。
6.2.1. 认证器附着 模式
客户端可以使用多种机制与认证器通信。 例如,客户端可以使用特定于客户端设备的 API, 与物理绑定到客户端设备的认证器通信。另一方面, 客户端可以使用多种标准化的 跨平台传输协议,例如 Bluetooth(请参阅§ 5.8.4 认证器 传输枚举(枚举 AuthenticatorTransport)),来发现 并与跨平台附着的认证器通信。我们将属于客户端设备一部分的认证器 称为平台 认证器,而可通过跨平台 传输协议访问的则称为漫游认证器。
-
平台认证器使用特定于客户端 设备的传输方式附着,称为平台附着,并且通常无法从客户端设备移除。公 钥凭据如果绑定到平台 认证器,则称为平台凭据。
-
漫游认证器使用跨平台 传输方式附着,称为跨平台附着。此类认证器可以 从客户端设备移除,并可以在其之间“漫游”。公钥凭据如果绑定到漫游认证器,则称为漫游 凭据。
某些平台 认证器根据上下文也可能充当漫游认证器。例如, 集成到移动设备中的平台 认证器可以通过 Bluetooth 使自身作为漫游 认证器可用。 在这种情况下,运行在移动 设备上的客户端会将认证器识别为平台认证器, 而运行在不同客户端设备上并通过 Bluetooth 与同一认证器通信的客户端则会将其识别为漫游认证器。
平台认证器的主要用例是将特定客户端设备注册为“受信任 设备”, 从而使客户端设备本身充当未来你所拥有的事物身份验证因素,用于未来的身份验证。 这为用户带来便利, 使其在未来的身份验证仪式中无需漫游认证器, 例如,用户无需在 口袋里翻找钥匙扣或手机。
漫游认证器的用例包括: 首次在新客户端设备上进行身份验证, 在很少使用的客户端 设备上、在多个用户共享的客户端 设备上, 或在不包含平台认证器的客户端设备上; 以及当策略或偏好规定认证器应与其配合使用的客户端设备保持分离时。 漫游 认证器还可用于保存 备份凭据,以防另一个认证器丢失。
6.2.2. 凭据存储模式
-
存储在嵌入认证器、客户端或客户端设备中的持久存储中,例如安全元件中。 这是客户端可发现 公钥凭据源的一项技术要求。
-
通过加密(即封装)公钥凭据源, 使得只有此认证器能够解密(即解封装)它,并让生成的 密文成为公钥 凭据源的凭据 ID。凭据 ID由依赖方存储, 并通过
get()的allowCredentials选项返回给认证器, 这允许认证器解密并使用公钥 凭据源。这使认证器能够拥有无限的凭据存储容量, 因为加密的 公钥凭据源由 依赖方 而不是认证器存储 — 但这意味着以这种方式存储的 凭据必须先从 依赖方检索,之后 认证器 才能使用它。
认证器支持这些存储策略中的哪一种,定义了该认证器的凭据存储 模式,如下:
-
如果认证器 支持客户端可发现 公钥凭据源,则它具有客户端凭据存储模式。具有客户端凭据存储 模式的认证器也称为具备可发现 凭据能力。
-
如果认证器 不具有客户端凭据存储 模式,即它仅支持将公钥 凭据源以密文形式存储在凭据 ID中,则它具有服务器端凭据存储模式。
请注意,具备可发现凭据能力的认证器可以同时支持
两种存储策略。在这种情况下,认证器可以
自行决定为不同的凭据使用不同的存储策略,但须受
residentKey
和 requireResidentKey
选项的约束,这些选项属于
create()。
6.2.3. 身份验证因素能力
在身份验证仪式期间,可以用来证明身份的身份验证因素 大致分为三类:你所拥有的事物、你所知道的事物和 你自身的特征。 示例分别包括物理密钥、密码 和指纹。
所有WebAuthn 认证器都属于你所拥有的事物 类别,但支持用户 验证的认证器 还可以充当另外一种或两种身份验证因素。 例如,如果认证器能够 验证 PIN,则 PIN 是你所知道的事物,而 生物特征 认证器可以验证你自身的特征。 因此, 支持用户验证的认证器是具备多因素 能力的。相反,不具备多因素 能力的认证器是具备单因素能力的。请注意,一个具备多因素能力的认证器 可以支持多种用户验证模式,这意味着它可以充当全部三类身份验证因素。
尽管用户 验证是在认证器本地执行,而不是由依赖方执行,但认证器 会通过在返回给依赖方的已签名响应中设置UV标志来指示是否执行了用户 验证。 因此,依赖方可以 使用UV标志来验证 在注册或身份验证仪式中使用了额外的身份验证因素。反过来,可以通过检查 认证器的证明 语句来评估UV标志的真实性。
6.3. 认证器操作
WebAuthn 客户端必须 连接到认证器,才能调用该认证器的任何操作。此连接 定义一个认证器会话。认证器必须在 会话之间保持隔离。它可以通过在任何特定时间只允许存在一个 会话,或者通过提供更复杂的会话管理来实现这一点。
客户端可以在认证器会话中调用以下操作。
6.3.1. 按凭据 ID 查找凭据源 算法
在认证器 authenticator 中查找凭据 ID credentialId 的结果是以下算法的结果:
-
如果 authenticator 可以将 credentialId 解密为公钥 凭据源 credSource:
-
将 credSource.id 设置为 credentialId。
-
返回 credSource。
-
-
对于 authenticator 的凭据映射中的每个公钥 凭据源 credSource:
-
如果 credSource.id 是 credentialId,则返回 credSource。
-
-
返回
null。
6.3.2. authenticatorMakeCredential 操作
在调用此操作之前,客户端必须调用authenticatorCancel 操作, 以中止认证器会话中正在进行的所有其他操作。
此操作接受以下输入参数:
- hash
-
由客户端提供的序列化 客户端数据的哈希。
- rpEntity
- userEntity
-
用户帐户的
PublicKeyCredentialUserEntity, 其中包含依赖方给出的用户 句柄。 - requireResidentKey
-
凭据创建的有效驻留密钥 要求,这是一个由客户端确定的 Boolean 值。
- requireUserPresence
-
常量 Boolean 值
true;或者当options.设置为mediationconditional且用户代理此前已从用户收集同意时,为 FALSE。 - requireUserVerification
-
凭据创建的有效用户 验证要求,这是一个由客户端确定的 Boolean 值。
- credTypesAndPubKeyAlgs
-
由依赖方请求的
PublicKeyCredentialType与公钥算法(COSEAlgorithmIdentifier) 配对的序列。此 序列按偏好程度从高到低排序。认证器会尽最大努力创建其能够创建的 最优先凭据。 - excludeCredentialDescriptorList
-
由依赖方提供的
PublicKeyCredentialDescriptor对象的可选列表,其意图是,如果认证器已知其中任意对象,则不应该创建新凭据。 excludeCredentialDescriptorList 包含 已知凭据列表。 - enterpriseAttestationPossible
-
一个 Boolean 值,表示认证器可以返回可单独识别身份的证明。
- attestationFormats
-
一个字符串序列,用于表达依赖方对证明语句格式的偏好, 从最优先到最不优先。如果认证器返回证明,则它会尽最大努力 使用其支持的最优先格式。
- extensions
调用此操作时,认证器必须执行以下过程:
-
检查所有提供的参数在语法上是否格式良好且长度正确。如果不是, 则返回等同于 "
UnknownError" 的错误码并终止操作。 -
检查 credTypesAndPubKeyAlgs 中指定的
PublicKeyCredentialType与密码学参数的组合中 是否至少支持一种。 如果不支持,则返回等同于 "NotSupportedError" 的错误码并终止操作。 -
对于 excludeCredentialDescriptorList 中的每个 descriptor:
-
如果在此认证器中查找
descriptor.返回非 null,并且返回项的RP ID和type分别匹配idrpEntity.和idexcludeCredentialDescriptorList., 则收集一个确认创建新凭据之用户同意的授权手势。该授权手势必须包括用户在场测试。如果用户type- 确认同意创建新凭据
-
返回等同于 "
InvalidStateError" 的错误码并终止操作。 - 不同意创建新凭据
-
返回等同于 "
NotAllowedError" 的错误码并终止操作。
注:此授权手势的目的不是继续创建凭据, 而是出于隐私原因,授权披露
descriptor.已绑定到此认证器这一事实。 如果用户同意,客户端和依赖方就可以检测到这一点,并引导用户 使用不同的认证器。 如果用户不同意, 认证器不会透露iddescriptor.已绑定到它, 并会像用户只是拒绝同意创建凭据一样作出响应。id
-
-
如果 requireResidentKey 为
true,且认证器无法存储客户端可发现 公钥凭据源, 则返回等同于 "ConstraintError" 的错误码并终止操作。 -
如果 requireUserVerification 为
true,且认证器无法执行用户 验证,则返回 等同于 "ConstraintError" 的错误码并终止操作。 -
收集一个确认创建新凭据之用户同意的授权手势。
如果认证器具有自己的输出能力,则由
认证器显示授权手势的提示,否则由用户代理显示。该提示应该
尽可能显示
rpEntity.、idrpEntity.、nameuserEntity.和nameuserEntity.。displayName如果 requireUserVerification 为
true,则授权手势 必须包括用户 验证。如果 requireUserPresence 为
true,则授权手势 必须包括用户在场测试。如果用户未同意,或者用户验证失败,则返回等同于 "
NotAllowedError" 的错误码并终止操作。 -
-
令(publicKey、privateKey)为一对新的密码学密钥,使用 credTypesAndPubKeyAlgs 中此认证器支持的第一个项 所表示的
PublicKeyCredentialType与密码学参数的组合。 -
令 userHandle 为
userEntity.。id -
令 credentialSource 为一个新的公钥 凭据源,其字段为:
- type
- privateKey
-
privateKey
- rpId
-
rpEntity.id - userHandle
-
userHandle
- otherUI
-
认证器选择包含的任何其他信息。
-
如果 requireResidentKey 为
true,或者认证器选择创建 客户端 可发现公钥凭据源: -
否则:
-
令 credentialId 为序列化并加密 credentialSource 的结果,使得只有此认证器可以 解密它。
-
-
-
如果创建新凭据对象时发生任何错误,则返回等同于 "
UnknownError" 的错误码并 终止操作。 -
令 processedExtensions 为针对 extensions 中每个受支持的扩展标识符 → 认证器扩展输入执行认证器扩展处理的结果。
-
如果认证器:
-
令 attestedCredentialData 为包含 credentialId 和 publicKey 的经证明的凭据数据字节数组。
-
令 attestationFormat 为 attestationFormats 中第一个受支持的证明语句格式标识符,同时考虑 enterpriseAttestationPossible。 如果 attestationFormats 不包含任何受支持的值,则令 attestationFormat 为此认证器最偏好的证明语句格式 标识符。
-
令 authenticatorData 为该字节数组,如§ 6.1 认证器数据中所规定, 其中包含 attestedCredentialData 作为
attestedCredentialData, 并包含 processedExtensions(如果有)作为extensions。 -
使用§ 6.5.4 生成证明对象中规定的 过程、证明语句格式 attestationFormat,以及 authenticatorData 和 hash 的值,为新凭据创建证明对象,同时
考虑enterpriseAttestationPossible 的值。有关证明的更多详细信息,请参阅§ 6.5 证明。
此操作成功完成后,认证器将证明对象返回给客户端。
6.3.3. authenticatorGetAssertion 操作
在调用此操作之前,客户端必须调用authenticatorCancel 操作, 以中止认证器会话中正在进行的所有其他操作。
此操作接受以下输入参数:
- rpId
- hash
-
由客户端提供的序列化 客户端数据的哈希。
- allowCredentialDescriptorList
-
一个可选的
PublicKeyCredentialDescriptor列表, 描述依赖方可接受的凭据(可能已由客户端筛选),如果有。 - requireUserPresence
-
常量 Boolean 值
true。 它在此处作为伪参数包含,以简化将此抽象认证器模型应用于 可能希望使用户在场测试可选的实现,尽管 WebAuthn 并不 允许这样做。 - requireUserVerification
-
断言的有效用户验证 要求,这是一个由客户端提供的 Boolean 值。
- extensions
调用此方法时,认证器必须执行以下过程:
-
检查所有提供的参数在语法上是否格式良好且长度正确。如果不是, 则返回等同于 "
UnknownError" 的错误码并终止操作。 -
如果提供了 allowCredentialDescriptorList,则对于 allowCredentialDescriptorList 中的每个 descriptor:
-
否则(未提供 allowCredentialDescriptorList),对于此 认证器的凭据映射中的每个 key → credSource,将 credSource追加 到 credentialOptions。
-
如果 credentialOptions 现在为空,则返回等同于 "
NotAllowedError" 的错误码并终止操作。 -
提示用户从 credentialOptions 中选择一个公钥凭据源
selectedCredential。
收集一个确认使用
selectedCredential 之用户同意的授权手势。
如果认证器具有自己的输出能力,则可以由它显示
授权手势的提示,否则由用户代理显示。
如果 requireUserVerification 为
true,则授权手势 必须包括用户 验证。如果 requireUserPresence 为
true,则授权手势 必须包括 用户 在场测试。如果用户未同意,则返回等同于 "
NotAllowedError" 的错误码并终止操作。 -
令 processedExtensions 为针对 extensions 中每个受支持的扩展标识符 → 认证器扩展输入执行认证器扩展处理的结果。
-
根据认证器实现的方式,将凭据关联的 签名 计数器或全局签名计数器值增加某个正值。 如果认证器 未实现签名计数器,则令签名计数器值 恒定为 零。
-
令 authenticatorData 为该 字节数组, 如§ 6.1 认证器数据中所规定,其中包含 processedExtensions(如果有)作为
extensions, 并排除attestedCredentialData。 -
令 signature 为使用 selectedCredential 的privateKey对连接
authenticatorData || hash生成的断言签名,如下方图 所示。这里使用简单的、 无分隔符的 连接是安全的,因为认证器数据描述自身长度。序列化 客户端数据的哈希(其长度可能可变)始终是最后一个元素。生成断言签名。 -
如果生成断言签名时发生任何错误,则返回等同于 "
UnknownError" 的错误码并 终止操作。 -
向用户代理返回:
-
selectedCredential.id,如果客户端提供了长度为 2 或更大的凭据 列表(即 allowCredentialDescriptorList),或者未提供此类列表。
注:如果客户端在 allowCredentialDescriptorList 中恰好提供了一个凭据,并且该凭据 已成功使用,则不会返回其 凭据 ID, 因为客户端已经知道它。这可以避免通过 可能受限的连接传输这些字节,而这种情况很可能很常见。
-
authenticatorData
-
signature
-
selectedCredential.userHandle
注:在提供了 allowCredentialDescriptorList 的情况下,返回的 userHandle 值可能为
null,请参阅:userHandleResult。
-
如果认证器无法 找到与指定依赖方对应且 满足指定条件的任何凭据,则它终止操作并返回错误。
6.3.4. authenticatorCancel 操作
此操作不接受输入参数,也不返回结果。
当客户端在认证器会话中调用此操作时,它会终止 该认证器 会话中当前正在进行的任何authenticatorMakeCredential 或authenticatorGetAssertion 操作。认证器停止提示或接受与授权 已取消操作相关的任何用户输入。 客户端会忽略认证器针对已取消操作的任何后续响应。
如果在认证器会话中调用此操作,而该会话当前没有正在进行的authenticatorMakeCredential 或authenticatorGetAssertion 操作,则忽略此操作。
6.3.5. silentCredentialDiscovery 操作
这是认证器可以支持的一个可选操作,用于支持 conditional
用户中介。
它接受以下输入参数:
调用此操作时,认证器必须执行以下过程:
-
令 collectedDiscoverableCredentialMetadata 为一个新的列表,其项是具有以下 项的 DiscoverableCredentialMetadata 结构:
-
返回 collectedDiscoverableCredentialMetadata。
6.4. 字符串处理
认证器可能需要存储由依赖方选择的任意字符串,例如
name
和 displayName,
它们位于 PublicKeyCredentialUserEntity
中。
本节讨论处理可能呈现给
人类的任意字符串的一些实际后果。
6.4.1. 字符串截断
API 中的每个任意字符串都会对认证器可能有限的可用资源作出某种适配。 当所选适配方式是字符串截断时,需要注意不要损坏字符串值。
例如,仅基于 Unicode 码点进行截断可能导致字素簇被截断。 这可能导致该字素簇呈现为不同的字形, 从而可能改变字符串的含义,而不是完全移除该字形。 例如,图 显示一个 UTF-8 编码字符串的末尾,其编码长度为 65 字节。 如果截断到 64 字节,则首先移除最后的 0x88 字节以满足大小限制。 由于这会留下部分 UTF-8 码点,因此该码点的其余部分也必须被移除。 由于这会留下部分字素簇,该字素簇的其余部分也应该被 移除。
处理这些问题的责任主要落在客户端上, 以避免让认证器承担理解字符编码和 Unicode 字符属性的负担。 以下小节分别定义客户端和认证器 可以如何执行字符串截断的要求。
6.4.1.1. 客户端进行的字符串截断
当WebAuthn 客户端 截断字符串时, 依赖方可观察到的截断行为必须满足以下要求:
选择一个大于或等于规定的最小支持长度的大小限制。 可以截断字符串,使其在 UTF-8 字符编码中的字节长度满足该 限制。 此截断必须尊重 UTF-8 码点边界,并且应该尊重字素簇边界[UAX29]。 得到的截断值可以短于所选大小限制, 但不得短于满足大小限制且结束于字素簇边界的最长前缀子字符串。
如果认证器能够满足这些 要求,则客户端可以让认证器执行截断; 否则,客户端必须在将字符串值转发给认证器之前执行截断。
除上述内容外,仅按字节边界截断会导致一个已知问题,用户代理应该 注意:如果认证器使用[FIDO-CTAP],则来自 认证器的后续消息可能包含无效 CBOR,因为该值被类型化为 CBOR 字符串,因此要求 是有效的 UTF-8。因此,在处理认证器时,用户代理应该:
-
确保发送给认证器的任何字符串均有效编码。
-
处理字符串被截断从而导致无效编码的情况。例如,末尾的任何 部分码点都可以被丢弃或替换为 U+FFFD。
6.4.1.2. 认证器进行的字符串截断
由于WebAuthn 认证器可能实现在受限 环境中, 因此对认证器的要求比对客户端的要求更宽松。
当WebAuthn 认证器截断字符串时, 截断行为必须满足以下要求:
选择一个大于或等于规定的最小支持长度的大小限制。 可以截断字符串,使其在 UTF-8 字符编码中的字节长度满足该 限制。 此截断应该尊重 UTF-8 码点边界,并且可以尊重字素簇边界[UAX29]。 得到的截断值可以短于所选大小限制, 但不得短于满足大小限制且结束于字素簇边界的最长前缀子字符串。
6.4.2. 语言和方向编码
为了在上下文中正确显示,字符串的语言和基本方向可能是必需的。此 API 中的字符串 可能必须写入固定功能的认证器,然后稍后读取并显示在不同的 平台上。
为了与不支持专用语言和方向 元数据字段的现有固定功能认证器兼容, Web 身份验证第 2 级包含了将此类元数据嵌入字符串本身的规定,以确保 原子地传输它。 不推荐使用此编码;客户端 和认证器可以 忽略新值中的此类编码。 客户端和认证器可以按照Web 身份验证第 2 级 §6.4.2. 语言和方向编码中的描述检测并处理现有字符串中编码的语言 和方向元数据。
相反,Web 身份验证 API的未来版本可能提供专用的语言和 方向元数据字段。
6.5. 证明
认证器如果可能,还应该 提供某种形式的证明。 如果认证器这样做,基本要求是认证器能够 针对每个凭据公钥生成可由WebAuthn 依赖方验证的证明语句。通常,此 证明 语句包含由证明私钥对经证明的凭据 公钥和 挑战所作的签名,以及为证明 公钥提供来源信息的证书或类似数据, 从而使依赖方 能够作出信任决策。但是,如果没有可用的证明密钥对,则认证器 可以使用相应的凭据 私钥对凭据公钥执行自 证明, 或者执行无证明。每当生成新的 公钥 凭据时,所有这些 信息都会由认证器以一个证明对象的整体形式返回。证明对象 与认证器 数据(其中包含经证明的凭据数据)以及证明语句之间的关系 如下面的图 所示。
如果认证器采用 自证明或无证明,则不会提供任何来源信息 供依赖方 据此作出信任决策。 在这些情况下,认证器不会向依赖方保证其操作。
证明对象的一个重要组成部分是证明语句。这是一种特定类型的已签名 数据对象,其中包含关于公钥凭据本身以及创建它的认证器的陈述。它 包含使用证明机构密钥创建的证明签名(自证明情况除外,此时使用凭据 私钥创建)。为了正确解释证明语句,依赖方需要 理解证明的以下两个方面:
-
证明语句格式是 认证器表示签名以及将各种上下文 绑定纳入证明语句的方式。换言之,它定义 语句的语法。各种现有组件和操作系统平台(例如 TPM 和 Android 操作系统)此前已经定义 证明语句格式。本规范 以可扩展方式支持多种此类格式,如§ 6.5.2 证明语句格式中所定义。格式 本身由字符串标识,如§ 8.1 证明语句格式标识符中所述。
-
证明 类型定义证明语句及其底层信任 模型的语义。 具体而言,它定义依赖方在验证某个证明语句在密码学上有效之后,如何建立对其的信任。 本规范支持多种证明类型,如 § 6.5.3 证明类型中所述。
一般而言,证明语句格式与证明类型之间没有简单的映射。例如, § 8.2 打包证明语句格式中定义的 "packed" 证明语句格式可以与所有证明 类型结合使用,而其他格式和类型的适用性则更有限。
证明的隐私、安全和操作特征取决于:
证明类型和
证明语句格式由认证器选择;
依赖方只能通过设置 attestation
和 attestationFormats
参数来表示其偏好。
预计大多数认证器只会支持少量证明类型和证明语句格式,而依赖方会根据 策略决定哪些证明类型可以接受。依赖方还需要 根据其掌握的关于这些 认证器的信息,了解其信任的认证器的特征。例如, FIDO 元数据服务[FIDOMetadataService]提供了一种访问此类信息的方式。
6.5.1. 经证明的凭据数据
经证明的凭据 数据是在为凭据生成证明对象时添加到认证器数据中的可变长度字节数组。 其格式如表 所示。
| 名称 | 长度(字节) | 描述 |
|---|---|---|
| aaguid | 16 | 认证器的 AAGUID。 |
| credentialIdLength | 2 | credentialId 的字节长度 L,16 位 无符号大端整数。值必须 ≤ 1023。 |
| credentialId | L | 凭据 ID |
| credentialPublicKey | 可变 |
以 COSE_Key 格式编码的凭据公钥,
如第 7 节中所定义,出自[RFC9052],
使用CTAP2 规范 CBOR 编码形式。
COSE_Key 编码的凭据公钥必须包含 "alg"
参数,并且不得
包含任何其他可选参数。"alg" 参数必须包含一个 COSEAlgorithmIdentifier
值。
编码后的凭据公钥还必须包含
相关密钥类型规范所规定的任何其他必需参数,即密钥类型 "kty" 和算法 "alg"
所必需的参数(请参阅第 2 节,出自[RFC9053])。
|
6.5.1.1. 以 COSE_Key 格式编码的 credentialPublicKey 值
示例
本节提供用于 ES256、PS256 和 RS256 签名算法的 COSE_Key 编码椭圆曲线和 RSA 公钥示例。这些示例遵循上面对credentialPublicKey 值定义的规则,并 使用 CDDL [RFC8610] 表示以便清晰说明。
第 7 节,出自[RFC9052],定义了 所有 COSE_Key 编码密钥的一般框架。 特定算法的特定密钥类型定义于[RFC9053]以及其他 规范中, 如下所述。
下面是一个以 EC2 格式进行 COSE_Key 编码的椭圆曲线公钥示例(请参阅第 7.1 节,出自[RFC9053]), 使用 P-256 曲线,用于 ES256 签名 算法(使用 SHA-256 的 ECDSA,请参阅第 2.1 节,出自[RFC9053]):
{ 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 [RFC8610] 表示相匹配:
A5 01 02 03 26 20 01 21 58 20 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d 22 58 20 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c
下面是一个 COSE_Key 编码的 2048 位 RSA 公钥示例(请参阅[RFC8230] 第 4 节), 用于 PS256 签名算法 (使用 SHA-256 的 RSASSA-PSS,请参阅第 2 节,出自[RFC8230]:
{ 1 : 3 , ; kty:RSA 密钥类型 3 : -37 , ; alg:PS256 -1 : n , ; n:RSA 模数 n,长度为 256 字节的字节字符串 ; 例如,以十六进制表示(为简洁起见省略中间字节):DB5F651550...6DC6548ACC3 -2 : e ; e:RSA 公共指数 e,长度为 3 字节的字节字符串 ; 例如,以十六进制表示:010001 }
下面是与上述相同的 COSE_Key 编码 RSA 公钥示例, 用于 RS256 签名算法(使用 SHA-256 的 RSASSA-PKCS1-v1_5):
{ 1 : 3 , ; kty:RSA 密钥类型 3 : -257 , ; alg:RS256 -1 : n , ; n:RSA 模数 n,长度为 256 字节的字节字符串 ; 例如,以十六进制表示(为简洁起见省略中间字节):DB5F651550...6DC6548ACC3 -2 : e ; e:RSA 公共指数 e,长度为 3 字节的字节字符串 ; 例如,以十六进制表示:010001 }
6.5.2. 证明语句格式
如上所述,证明语句格式是一种数据格式,用于 表示认证器针对一组 上下文绑定生成的密码学签名。每种证明语句格式必须使用以下 模板定义:
-
支持的证明类型:
-
语法: 以此格式生成的证明语句的语法,使用 CDDL [RFC8610] 为§ 6.5.4 生成证明对象中定义的扩展点
$$attStmtType进行定义。 -
签名 过程: 给定待证明的公钥凭据、包含用于证明的认证器 数据的认证器 数据结构,以及序列化 客户端数据的哈希时,在此格式中计算证明语句的签名 过程。
-
验证 过程: 验证证明语句的过程,它接受以下验证过程输入:
-
attStmt:证明语句结构
-
authenticatorData:声称已用于证明的认证器数据
-
clientDataHash:序列化 客户端数据的哈希
该过程返回以下任一结果:
-
最初规定的证明语句格式列表位于§ 8 定义的证明语句格式中。
6.5.3. 证明类型
WebAuthn 支持多种证明类型,用于定义证明语句及其底层信任 模型的语义:
注:本规范未定义任何显式表示证明类型的数据
结构。进行证明
语句验证的依赖方 — 即在
调用 navigator.credentials.create()
时选择除
none
之外的证明传送并验证收到的证明语句 — 将在验证过程中确定所采用的
证明类型。请参阅
§ 8 定义的证明语句格式中的“验证过程”小节。另请参阅§ 14.4.1 证明隐私。对于本
节定义的除自证明
和无证明之外的所有证明类型,依赖方验证之后,还要根据§ 7.1 注册新凭据的
步骤 24
将信任路径与可接受的根证书进行匹配。
区分这些证明类型主要用于
判断证明是否符合
依赖方策略。
- 基本 证明(基本)
-
在基本证明[UAFProtocol]的情况下,认证器的证明 密钥对特定于某个 认证器“型号”,即一“批”认证器。因此,相同或 类似型号的认证器通常共享同一个证明密钥对。有关更多信息,请参阅 § 14.4.1 证明隐私。
基本 证明也称为批量证明。
- 自 证明(自证明)
-
在自 证明(也称为替代基本证明[UAFProtocol])的情况下, 认证器没有 任何特定的证明密钥对。相反,它使用凭据私钥创建证明签名。 对证明私钥没有有效保护措施的认证器 通常使用此证明类型。
- 证明 CA(AttCA)
-
在这种情况下,认证器基于可信平台模块 (TPM),并 持有特定于认证器的 “背书密钥”(EK)。此密钥用于与可信第三方,即证明 CA [TCG-CMCProfile-AIKCertEnroll] (以前称为“隐私 CA”)安全通信。认证器可以生成多个 证明身份密钥对 (AIK),并请求证明 CA为每个 AIK 签发 AIK 证书。 使用此方法,此类认证器可以将 EK(它是一个全局关联 句柄)的暴露限制在证明 CA。可以针对每个由认证器生成的公 钥凭据 分别请求 AIK,并作为证明 证书传送给依赖方。
注:此概念通常会产生多个 证明证书。最近请求的证明证书 称为“活动”证书。
- 匿名化 CA(AnonCA)
-
在这种情况下,认证器使用匿名化 CA,它动态 为每个凭据生成证明 证书,使呈现给依赖方的证明语句不 提供可唯一识别的信息,例如可能用于跟踪的信息。
注:传送证明的证明语句如果其类型为AttCA 或AnonCA,则使用与类型为基本的证明相同的数据结构,因此三种证明类型 通常只能根据外部提供的、有关证明语句中传送的证明证书内容的知识加以区分。
- 无证明语句(无)
-
在这种情况下,没有可用的证明信息。另请参阅§ 8.7 无证明语句格式。
6.5.4. 生成证明对象
认证器必须:
-
令 attStmt 为在给定 authData 和 hash 的情况下运行 attestationFormat 的签名 过程的结果。
-
令 fmt 为 attestationFormat 的证明语句格式 标识符
-
以具有以下 语法的 CBOR 映射形式返回证明对象,其中填入此 算法初始化的变量:
attObj = { authData: bytes, ; $$attStmtType 中的每个选择定义 fmt 值和 attStmt 结构 $$attStmtType } .within attStmtTemplate attStmtTemplate = { authData: bytes, fmt: text, attStmt: ( { * tstr => any } ; 映射由每个具体的 attStmtType 填充 // [ * any ] ; attStmt 也可以是数组 ) }
6.5.5. 打包证明、FIDO U2F 证明和断言 签名的签名格式
-
对于 COSEAlgorithmIdentifier -7 (ES256) 以及其他基于 ECDSA 的算法,
sig值必须编码为 ASN.1 DER Ecdsa-Sig-Value,如[RFC3279] 第 2.2.3 节中所定义。示例: 注:编码长度会随 INTEGER 大小和曲线大小而变化。 30 43 ; SEQUENCE(67 字节) 02 21 ; INTEGER(33 字节) | 00 89 90 95 04 e1 4f 1e 29 db a8 15 8f a7 c3 87 | e8 88 ff be 07 d8 24 bb 21 43 20 55 06 ab 15 9c | 3e 02 1e ; INTEGER(30 字节) | 56 55 4f b5 81 9b 12 84 5e 85 be 2f 78 37 1c f3 | cb 95 e3 87 f4 51 cb 36 2b 94 78 d1 83 d2注:由于 CTAP1/U2F 认证器已经以此格式生成 签名值,因此出于一致性原因,CTAP2 认证器也将 以相同格式生成签名值。
建议任何新定义的证明格式不要使用 ASN.1 编码, 而应将签名表示为没有内部结构的等效固定长度字节数组, 使用与 COSE 签名相同的表示方式,如[RFC9053]和[RFC8230]中所定义。
下面的签名格式定义满足此要求,并可作为为此处未明确提及的其他 签名算法推导相同格式的示例:
-
对于 COSEAlgorithmIdentifier -257 (RS256),
sig必须包含使用 [RFC8017]第 8.2.1 节定义的 RSASSA-PKCS1-v1_5 签名方案生成的签名,并使用 SHA-256 作为 哈希函数。 该签名不使用 ASN.1 封装。 -
对于 COSEAlgorithmIdentifier -37 (PS256),
sig必须包含使用 [RFC8017]第 8.1.1 节定义的 RSASSA-PSS 签名方案生成的签名,并使用 SHA-256 作为 哈希函数。 该签名不使用 ASN.1 封装。
7. WebAuthn 依赖方操作
注册
或身份验证仪式始于WebAuthn
依赖方分别创建 PublicKeyCredentialCreationOptions
或 PublicKeyCredentialRequestOptions
对象,该对象编码仪式的参数。依赖方
应该注意不要在此阶段泄露敏感信息;有关详细信息,请参阅§ 14.6.2 用户名枚举。
成功执行 create()
或 get()
后,
依赖方的脚本
会从客户端接收一个 PublicKeyCredential,
其中分别包含
AuthenticatorAttestationResponse
或 AuthenticatorAssertionResponse
结构。
然后,它必须使用本规范范围之外的方法,将此结构的内容传送给依赖方服务器。
本节描述依赖方在收到这些
结构后必须执行的操作。
7.1. 注册新凭据
-
令 options 为一个新的
CredentialCreationOptions结构,根据依赖方对该仪式的需求进行配置。 令 pkOptions 为options.。publicKey -
调用
navigator.credentials.create()并将 options 作为参数传递。 令 credential 为成功兑现的 promise 的结果。 如果 promise 被拒绝,则以用户可见的错误中止仪式,或者根据 被拒绝 promise 中可用的上下文可能确定的信息来引导 用户体验。例如,如果 promise 以 等同于 "InvalidStateError" 的错误码被拒绝, 则可以指示用户使用不同的认证器。 有关不同错误上下文及导致这些上下文的情况,请参阅§ 6.3.2 authenticatorMakeCredential 操作。 -
令 response 为
credential.。 如果 response 不是responseAuthenticatorAttestationResponse的实例, 则以用户可见的错误中止仪式。 -
令 clientExtensionResults 为调用
credential.的结果。getClientExtensionResults() -
令 JSONtext 为对
response.的值运行UTF-8 解码的结果。clientDataJSON注:可以使用UTF-8 解码的任何实现,只要其产生的结果与 UTF-8 解码算法产生的结果相同。特别是,必须移除任何前导字节顺序 标记 (BOM)。
-
令 C,即声称在创建凭据期间收集的客户端 数据,为在 JSONtext 上运行实现特定 JSON 解析器的结果。
注:C 可以是任何 实现特定的数据结构表示,只要按照此算法要求, C 的各组成部分可以被引用。
-
验证
C.的值是typewebauthn.create。 -
验证
C.的值是依赖方预期的源。 有关指导,请参阅§ 13.5.9 验证凭据的源。origin -
如果
C.存在且设置为crossOrigintrue, 则验证依赖 方预期此凭据是在一个 不与其祖先同源的 iframe 中创建的。 -
如果
C.存在:topOrigin -
令 hash 为使用 SHA-256 对
response.计算哈希的结果。clientDataJSON -
对
AuthenticatorAttestationResponse结构的attestationObject字段执行 CBOR 解码,以获得证明语句格式 fmt、认证器数据 authData 和证明语句 attStmt。 -
如果
options.未设置为mediationconditional, 则验证 authData 中flags的UP 位已设置。 -
验证 authData 中凭据公钥的 "alg" 参数 与
pkOptions.中某个项的pubKeyCredParamsalg属性相匹配。 -
通过对 fmt 与受支持的 WebAuthn 证明语句格式标识符值集合执行 区分大小写的 USASCII 匹配,确定证明语句格式。 已注册 WebAuthn 证明语句格式标识符值的最新列表 维护在由 [RFC8809]建立的 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表[IANA-WebAuthn-Registries]中。
-
使用证明语句格式 fmt 的验证过程,给定 attStmt、
authData 和 hash,验证 attStmt 是正确的证明语句,传送有效的证明
签名。
注:每种证明 语句格式都规定其自己的验证过程。有关 最初定义的格式,请参阅§ 8 定义的证明语句格式;有关 最新列表,请参阅[IANA-WebAuthn-Registries]。
-
如果验证成功,则从可信来源或
策略中获取该证明类型和证明语句格式 fmt 的可接受信任锚(即证明根
证书)列表。例如,
FIDO 元数据服务[FIDOMetadataService]提供了一种获取此类信息的方式,
使用 authData 中
attestedCredentialData里的aaguid。 -
使用步骤 22中的验证过程输出,
按如下方式评估证明的可信度:
注:但是,如果策略允许,依赖方可以 注册凭据 ID和凭据公钥,但将该 凭据视为具有自证明(请参阅§ 6.5.3 证明类型)。如果这样做,依赖方就是在 断言没有密码学证据证明该公钥凭据由特定认证器型号生成。 有关更详细的讨论,请参阅[FIDOSecRef]和[UAFProtocol]。
-
验证
credentialId≤ 1023 字节。大于该字节数的凭据 ID 应该导致 RP 使此次注册仪式失败。 -
验证
credentialId尚未为任何用户注册。如果credentialId已知,则依赖方应该使此次注册仪式失败。注:依赖方拒绝重复凭据 ID的理由如下: 凭据 ID 包含足够的熵,因此意外重复的可能性非常低。但是,除自证明之外的证明 类型不包含自签名,无法在注册时显式证明持有凭据私钥。因此,成功 获得用户针对某站点的凭据 ID和凭据公钥的攻击者 (这可能通过多种方式实现),可能尝试在该站点将 受害者的凭据注册为自己的凭据。如果依赖方接受此新注册并替换 受害者现有的凭据注册,而且这些凭据是 可发现的,那么受害者在下一次尝试时可能被迫登录攻击者的帐户。 受害者在该状态下保存到站点的数据随后将可被 攻击者访问。
-
令 credentialRecord 为一个新的凭据记录,包含以下内容:
- type
-
credential.。type - id
- publicKey
-
authData 中的凭据公钥。
- signCount
-
authData.signCount。 - uvInitialized
- transports
-
从
response.返回的值。getTransports() - backupEligible
- backupState
新的凭据 记录还可以包含以下可选内容:
- attestationObject
-
response.。attestationObject - attestationClientDataJSON
-
response.。clientDataJSON - rpId
依赖方还可以 根据需要包含任何其他项。 作为非规范性示例,依赖方可以允许用户为凭据设置“昵称”, 以帮助用户在与帐户设置交互时记住哪个凭据绑定到哪个认证器。
-
根据依赖
方的要求,处理
clientExtensionResults 中的客户端扩展输出
以及 authData 中
extensions中的认证器扩展输出。 根据每个扩展, 处理步骤可能已被具体规定,也可能由依赖方决定如何处理扩展 输出。 依赖方可以 忽略任意或全部扩展输出。客户端可以设置额外的认证器扩展或 客户端 扩展,从而使认证器扩展输出或 客户端 扩展输出中出现 依赖 方未在
pkOptions.中请求的值。 依赖方 必须准备好处理这种情况, 无论是忽略未经请求的扩展还是拒绝证明。依赖方可以 根据本地策略和正在使用的扩展作出此 决定。extensions -
如果上述所有步骤都成功, 则将 credentialRecord 存储在
pkOptions.所表示的用户帐户中,并适当地继续注册仪式。 否则,使注册仪式失败。user如果依赖方 在这种情况下没有使注册仪式失败, 那么依赖 方就是在接受不存在密码学证据 证明公钥凭据由任何特定认证器型号生成。 依赖方 可以将该凭据视为等同于无证明的凭据(请参阅§ 6.5.3 证明 类型)。 有关更详细的讨论,请参阅[FIDOSecRef]和[UAFProtocol]。
验证证明对象要求依赖方拥有 一种可信的方法来确定上述步骤 23中的可接受信任锚。 此外,如果使用证书,依赖方必须能够访问 中间 CA 证书的证书状态信息。如果客户端没有 在证明信息中提供此链,则依赖方还必须能够构建证明 证书链。
7.2. 验证身份验证断言
-
令 options 为一个新的
CredentialRequestOptions结构,根据依赖方对该仪式的需求进行配置。 令 pkOptions 为options.。publicKey -
调用
navigator.credentials.get()并将 options 作为参数传递。 令 credential 为成功兑现的 promise 的结果。 如果 promise 被拒绝,则以用户可见的错误中止仪式,或者根据 被拒绝 promise 中可用的上下文可能 确定的信息来引导用户体验。有关不同 错误上下文及导致这些错误上下文的 情况,请参阅§ 6.3.3 authenticatorGetAssertion 操作。 -
令 response 为
credential.。 如果 response 不是responseAuthenticatorAssertionResponse的实例, 则以用户可见的错误中止仪式。 -
令 clientExtensionResults 为调用
credential.的结果。getClientExtensionResults() -
如果
pkOptions.不为空, 则验证allowCredentialscredential.标识了idpkOptions.中列出的某个公钥凭据。allowCredentials -
令 cData、authData 和 sig 分别表示 response 的
clientDataJSON、authenticatorData和signature的值。 -
令 JSONtext 为对 cData 的值运行UTF-8 解码的结果。
注:可以使用UTF-8 解码的任何实现,只要其产生的结果与 UTF-8 解码算法产生的结果相同。特别是,必须移除任何前导字节顺序 标记 (BOM)。
-
令 C,即声称用于签名的客户端 数据,为在 JSONtext 上运行实现特定 JSON 解析器的结果。
注:C 可以是任何 实现特定的数据结构表示,只要按照此算法要求, C 的各组成部分可以被引用。
-
验证
C.的值是字符串typewebauthn.get。 -
验证
C.的值是依赖方预期的源。 有关指导,请参阅§ 13.5.9 验证凭据的源。origin -
如果
C.存在且设置为crossOrigintrue, 则验证依赖 方预期此凭据将在一个不与其祖先同源的 iframe 中使用。 -
如果
C.存在:topOrigin -
验证
authData 中的
rpIdHash是依赖方预期的RP ID的 SHA-256 哈希。注:如果使用appid 扩展,此步骤需要一些特殊逻辑。有关 详细信息,请参阅§ 10.1.1 FIDO AppID 扩展 (appid)。
-
确定此次断言是否需要用户验证。 当且仅当
pkOptions.设置为userVerificationrequired时,才应该要求用户 验证。 -
如果凭据备份 状态被用作依赖方业务逻辑或策略的一部分, 则令 currentBe 和 currentBs 分别为 authData 中
flags的BE 和BS 位的值。 将 currentBe 和 currentBs 与credentialRecord.backupEligible和credentialRecord.backupState比较:-
如果
credentialRecord.backupEligible已设置,则验证 currentBe 已设置。 -
如果
credentialRecord.backupEligible未设置,则验证 currentBe 未设置。 -
应用依赖 方策略(如果有)。
注:有关依赖方可能 如何处理BS标志值的示例,请参阅§ 6.1.3 凭据备份状态。
-
-
令 hash 为使用 SHA-256 对 cData 计算哈希的结果。
-
使用
credentialRecord.publicKey, 验证 sig 是对 authData 和 hash 二进制连接的有效签名。注:此验证步骤与 FIDO U2F 认证器生成的签名兼容。请参阅 § 6.1.2 FIDO U2F 签名格式兼容性。
-
如果 authData.
signCount非零,或者credentialRecord.signCount非零, 则运行以下子步骤: -
根据依赖
方的要求,处理
clientExtensionResults 中的客户端扩展输出
以及 authData 中
extensions中的认证器扩展输出。 根据每个扩展, 处理步骤可能已被具体规定,也可能由依赖方决定如何处理扩展 输出。 依赖方可以 忽略任意或全部扩展输出。客户端可以设置额外的认证器扩展或 客户端 扩展,从而使认证器扩展输出或 客户端 扩展输出中出现 依赖 方未在
pkOptions.中请求的值。 依赖方 必须准备好处理这种情况, 无论是忽略未经请求的扩展还是拒绝断言。依赖方可以 根据本地策略和正在使用的扩展作出此 决定。extensions -
使用新的状态值更新 credentialRecord:
-
将
credentialRecord.backupState更新为 currentBs 的值。 -
如果
credentialRecord.uvInitialized为false, 则将其更新为 authData 中flags里的UV 位的值。 此更改应该要求使用等同于 WebAuthn用户 验证的额外身份验证因素进行授权; 如果未授权,则跳过此步骤。
如果依赖方 执行这些 WebAuthn身份验证 仪式步骤之外的额外安全检查, 则上述状态更新应该推迟到这些额外检查成功完成 之后。
8. 定义的证明语句格式
WebAuthn 支持可插拔的证明语句格式。本节定义一组初始 格式。
8.1. 证明语句格式标识符
证明语句格式由一个字符串标识,该字符串称为证明语句 格式标识符,由 证明语句格式的作者选择。
证明语句格式标识符应该注册到 由[RFC8809]建立的 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表[IANA-WebAuthn-Registries]中。 所有已注册的证明语句格式标识符自然都彼此唯一。
未注册的证明语句格式标识符应该使用小写反向域名命名方式,并使用 开发者注册的域名,以确保标识符的唯一性。所有证明语句 格式标识符的长度必须 最多为 32 个八位字节,并且必须仅由可打印的 USASCII 字符组成,不包括 反斜杠和双引号, 即[RFC5234]中定义的 VCHAR,但不包括 %x22 和 %x5c。
注:这意味着基于域名的证明语句格式 标识符只能包含 LDH 标签[RFC5890]。
实现必须以区分大小写的方式匹配 WebAuthn 证明语句格式标识符。
可能存在多个版本的证明语句格式应该在其
标识符中包含版本。这样,
不同版本实际上会被视为不同格式,例如将 packed2 作为
§ 8.2 打包证明语句格式的新版本。
以下各节介绍一组当前已定义并已注册的证明语句格式及 其标识符。 已注册证明语句格式标识符的最新列表 维护在 由[RFC8809]建立的 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表[IANA-WebAuthn-Registries]中。
8.2. 打包证明语句格式
这是一种针对 WebAuthn 优化的证明语句格式。它使用非常紧凑但仍可扩展的 编码方法。资源有限(例如安全元件)的认证器也可以实现它。
- 证明语句格式标识符
-
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 格式编码的证明证书。
- 签名过程
-
此证明语句格式的签名过程 类似于生成断言签名的过程。
-
令 authenticatorData 表示用于证明的认证器 数据, 并令 clientDataHash 表示序列化 客户端数据的哈希。
-
如果使用基本或AttCA证明, 则认证器将 authenticatorData 与 clientDataHash 连接,并使用通过认证器特定 机制选择的证明 私钥对结果签名,从而生成 sig。它将 x5c 设置为 attestnCert,后接相关证书链(如果有)。它将 alg 设置为 证明私钥的算法。
-
如果使用自 证明,则认证器将 authenticatorData 与 clientDataHash 连接, 并使用凭据私钥对结果签名,从而生成 sig。它将 alg 设置为 凭据私钥的算法,并 省略其他字段。
-
- 验证过程
-
给定验证过程输入 attStmt、 authenticatorData 和 clientDataHash,验证过程 如下:
-
验证 attStmt 是符合上述语法的有效 CBOR,并 对其执行 CBOR 解码以提取 所包含的字段。
-
如果存在 x5c:
-
使用 attestnCert 中的 证明公钥和 alg 中指定的算法,验证 sig 是 authenticatorData 与 clientDataHash 连接结果的有效签名。
-
验证 attestnCert 满足§ 8.2.1 打包证明语句的证书 要求。
-
如果 attestnCert 包含 OID 为
1.3.6.1.4.1.45724.1.1.4(id-fido-gen-ce-aaguid)的扩展, 则验证 此扩展的值与 authenticatorData 中的aaguid相匹配。
-
-
如果不存在 x5c,则使用的是自证明。
-
验证 alg 与 authenticatorData 中
credentialPublicKey的算法相匹配。 -
使用凭据公钥和 alg,验证 sig 是 authenticatorData 与 clientDataHash 连接结果的有效签名。
-
-
8.2.1. 打包证明 语句的证书要求
证明证书必须具有以下字段/扩展:
-
版本必须设置为 3(由值为 2 的 ASN.1 INTEGER 表示)。
-
Subject 字段必须设置为:
- Subject-C
-
指定认证器供应商注册所在国家/地区的 ISO 3166 代码 (PrintableString)
- Subject-O
-
认证器供应商的法定名称 (UTF8String)
- Subject-OU
-
字面字符串 “Authenticator Attestation” (UTF8String)
- Subject-CN
-
由供应商自行选择的 UTF8String
-
如果相关证明根证书用于多个认证器型号,则必须存在扩展 OID
1.3.6.1.4.1.45724.1.1.4(id-fido-gen-ce-aaguid), 其中包含作为 16 字节 OCTET STRING 的 AAGUID。 该扩展不得标记为关键。由于依赖方 可能不知道证明根 证书是否用于多个认证器型号,因此建议依赖方检查该扩展 是否存在;如果存在,则验证其中包含的 AAGUID 与证明 对象中呈现的 AAGUID 相同。
请注意,X.509 扩展会在 OCTET STRING 中编码该值的 DER 编码。 因此,为了有效,AAGUID 必须封装在两个 OCTET STRING 中。
-
基本约束扩展必须将 CA 组件设置为
false。
此外,带有 id-ad-ocsp 项的机构信息访问 (AIA) 扩展和 CRL
分发点扩展
[RFC5280]
均为可选,因为许多证明证书的状态可通过认证器元数据
服务获得。例如,请参阅 FIDO 元数据服务[FIDOMetadataService]。
可以使用扩展 OID
1.3.6.1.4.1.45724.1.1.5
(id-fido-gen-ce-fw-version)区分特定认证器型号的固件。
如果存在,此属性包含一个非负值的 INTEGER,该值会随着新的
固件发行版本递增。该扩展不得标记为关键。
例如,以下是一个包含上述扩展 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. 企业打包 证明语句的证书要求
扩展 OID 1.3.6.1.4.1.45724.1.1.2(id-fido-gen-ce-sernum)还可以
存在于企业用途的打包证明中。如果存在,则此扩展必须针对特定 AAGUID
为每台设备指示唯一的八位字节字符串值。此值在
恢复出厂设置后必须保持不变,但可以不同于与
设备关联的任何其他序列号或其他硬件标识符。此扩展不得标记为关键,对应值编码为
OCTET STRING。此扩展不得存在于非企业证明中。
8.3. TPM 证明语句格式
此证明语句格式通常由使用可信平台模块作为 密码学 引擎的认证器使用。
- 证明语句格式标识符
-
tpm
- 支持的证明类型
- 语法
-
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 表示 序列化 客户端数据的哈希。
连接 authenticatorData 和 clientDataHash 以形成 attToBeSigned。
使用[TPMv2-Part3]第 18.2 节规定的过程生成签名,使用 证明私钥,并 将
extraData参数设置为使用与 "alg" 签名算法对应的 哈希算法对 attToBeSigned 计算的摘要。 (对于 "RS256" 算法,这将是 SHA-256 摘要。)将 pubArea 字段设置为凭据公钥的公共区域(TPMT_PUBLIC 结构),将 certInfo 字段(TPMS_ATTEST 结构) 设置为同名输出参数,并将 sig 字段设置为从 上述过程中获得的签名。
注:如果使用 TPM2_ReadPublic 命令从 TPM 读取 pubArea,该命令会返回一个 TPM2B_PUBLIC 结构。TPM2B_PUBLIC 是两个长度字节,后接 TPMT_PUBLIC 结构。在将其放入 pubArea 之前, 必须移除这两个长度字节。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程 如下:
验证 attStmt 是符合上述语法的有效 CBOR,并执行 CBOR 解码以提取 所包含的字段。
验证由 pubArea 的
parameters和unique字段指定的公钥 与 authenticatorData 中attestedCredentialData中的credentialPublicKey完全相同。连接 authenticatorData 和 clientDataHash 以形成 attToBeSigned。
验证 certInfo 的完整性
-
验证 x5c 存在。
-
验证 aikCert 满足§ 8.3.1 TPM 证明语句证书 要求。
-
如果 aikCert 包含 OID 为
1.3.6.1.4.1.45724.1.1.4(id-fido-gen-ce-aaguid)的扩展,则验证该 扩展的值与 authenticatorData 中的aaguid相匹配。 -
使用 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 的有效 Name,该 Name 使用[TPMv2-Part1]第 16 节规定的过程并使用 pubArea 中的 nameAlg 计算。注:TPM 始终会返回 TPMS_CERTIFY_INFO 结构,其中
name中的 nameAlg 与 pubArea 中的 nameAlg 相同。注: “标准证明结构”[TPMv2-Part1] 第 31.2 节中的其余字段,即
qualifiedSigner、clockInfo和firmwareVersion会被忽略。 根据所使用 aikCert 密钥的属性,这些字段可能被 混淆。 如果有效,则可以将这些字段用作风险引擎的输入。
-
8.3.1. TPM 证明语句证书要求
TPM 证明 证书必须具有以下字段/扩展:
-
版本必须设置为 3。
-
Subject 字段必须设置为空。
-
Subject Alternative Name 扩展必须按照[TPMv2-EK-Profile]第 3.2.9 节中的定义设置。
注:[TPMv2-EK-Profile]的早期版本允许 包含一个名为 HardwareModuleName 的可选属性,该属性在 EK 证书中包含 TPM 序列号。 HardwareModuleName 不应该放入证明 证书的 Subject Alternative Name 中。
-
Extended Key Usage 扩展必须包含 OID
2.23.133.8.3("joint-iso-itu-t(2) internationalorganizations(23) 133 tcg-kp(8) tcg-kp-AIKCertificate(3)")。 -
Basic Constraints 扩展必须将 CA 组件设置为
false。 -
带有
id-ad-ocsp项的 Authority Information Access (AIA) 扩展和 CRL Distribution Point 扩展[RFC5280] 均为 可选,因为许多证明证书的状态可通过元数据服务获得。 例如,请参阅 FIDO 元数据服务[FIDOMetadataService]。
8.4. Android 密钥证明语句格式
当相关认证器是 Android "N" 或更高版本平台上的平台认证器时, 证明语句基于Android 密钥 证明。在这些情况下,证明语句 由运行在安全操作环境中的组件生成,但用于证明的认证器数据 在该环境之外生成。预期WebAuthn 依赖方检查声称已用于证明的认证器数据 与证明证书扩展数据的字段一致。
- 证明语句格式标识符
-
android-key
- 支持的证明类型
- 语法
-
Android 密钥证明语句仅由 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 密钥证明, 并将 clientDataHash 作为 挑战值提供(例如,通过使用 setAttestationChallenge)。将 x5c 设置为返回值。认证器通过连接 authenticatorData 和 clientDataHash, 并使用凭据私钥对结果签名来生成 sig。它将 alg 设置为 签名格式的算法。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程 如下:
-
验证 attStmt 是符合上述语法的有效 CBOR,并 对其执行 CBOR 解码以提取 所包含的字段。
-
使用 x5c 中第一个证书里的 公钥和 alg 中指定的算法,验证 sig 是 authenticatorData 与 clientDataHash 连接结果的有效签名。
-
验证 x5c 中第一个证书里的公钥与 authenticatorData 中
attestedCredentialData中的credentialPublicKey相匹配。 -
验证证明 证书 扩展数据中的
attestationChallenge字段与 clientDataHash 完全相同。 -
使用证明证书 扩展数据中的适当授权列表验证以下内容:
-
AuthorizationList.allApplications字段在任一 授权列表 (softwareEnforced或teeEnforced)中均不存在,因为 PublicKeyCredential 必须限定作用域于RP ID。 -
对于以下内容,如果 RP 仅希望接受来自可信执行环境的密钥,则仅使用
teeEnforced授权列表; 否则使用teeEnforced和softwareEnforced的并集。-
AuthorizationList.origin字段中的值等于KM_ORIGIN_GENERATED。 -
AuthorizationList.purpose字段中的值等于KM_PURPOSE_SIGN。
-
-
-
8.4.1. Android 密钥证明语句证书要求
Android 密钥证明证明证书的Android 密钥证明证书扩展
数据由 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 证明语句的语法定义如下:
$$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 表示 序列化 客户端数据的哈希。
连接 authenticatorData 和 clientDataHash,对连接后的字符串执行 SHA-256 哈希,并 令该哈希的结果构成 attToBeSigned。
请求 SafetyNet 证明,并将 attToBeSigned 作为 nonce 值提供。将 response 设置为结果,并将 ver 设置为 认证器中运行的 Google Play 服务版本。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程 如下:
-
验证 attStmt 是符合上述语法的有效 CBOR,并 对其执行 CBOR 解码以提取 所包含的字段。
-
按照SafetyNet 在线文档指示的步骤,验证 response 是版本 ver 的有效 SafetyNet 响应。 截至本文撰写时,SafetyNet 响应只有一种格式,ver 保留供将来使用。
-
验证 response 负载中的
nonce属性 与 authenticatorData 和 clientDataHash 连接结果的 SHA-256 哈希的 Base64 编码完全相同。 -
按照 SafetyNet 在线文档中的步骤, 验证 SafetyNet 响应确实来自 SafetyNet 服务。
-
8.6. FIDO U2F 证明语句格式
此证明语句格式与使用[FIDO-U2F-Message-Formats]中定义格式的 FIDO U2F 认证器一起使用。
- 证明语句格式标识符
-
fido-u2f
- 支持的证明类型
- 语法
-
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 对序列化的客户端数据进行哈希, clientDataHash 的长度将为 32 字节。)
按照[FIDO-U2F-Message-Formats]的第 4.3 节中的规定生成注册响应消息,其中 application 参数设置为给定凭据所限定作用域到的RP ID的 SHA-256 哈希,challenge 参数设置为 clientDataHash, key handle 参数设置为给定凭据的凭据 ID。将此注册响应消息的原始签名 部分(即不含用户公钥、 key handle 和证明证书)设置为 sig,并将 证明公钥的证明证书设置为 x5c。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程 如下:
-
验证 attStmt 是符合上述语法的有效 CBOR,并 对其执行 CBOR 解码以提取 所包含的字段。
-
检查 x5c 恰好有一个元素,并令 attCert 为该元素。 令 certificate public key 为 attCert 所传送的公钥。如果 certificate public key 不是 P-256 曲线上的椭圆 曲线 (EC) 公钥,则终止此算法并返回适当的错误。
-
从 authenticatorData 中提取声称的 rpIdHash,并从 authenticatorData.
attestedCredentialData中提取声称的 credentialId 和 credentialPublicKey。 -
将 COSE_KEY 格式的 credentialPublicKey(请参阅第 7 节,出自[RFC9052]) 转换为原始 ANSI X9.62 公钥 格式(请参阅[FIDO-Registry]的第 3.6.2 节 公钥表示 格式中的 ALG_KEY_ECC_X962_RAW)。
-
令 x 为 credentialPublicKey 中对应于 "-2" 键(表示 x 坐标)的值,并确认其 大小为 32 字节。 如果大小不同或未找到 "-2" 键,则终止此算法并返回 适当的错误。
-
令 y 为 credentialPublicKey 中对应于 "-3" 键(表示 y 坐标)的值,并确认其 大小为 32 字节。 如果大小不同或未找到 "-3" 键,则终止此算法并返回 适当的错误。
-
令 publicKeyU2F 为连接结果
0x04 || x || y。注:这表示 未压缩 ECC 密钥格式。
-
-
令 verificationData 为(0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F)的连接(请参阅第 4.3 节,出自[FIDO-U2F-Message-Formats])。
-
按照[SEC1]第 4.1.4 节,使用 verificationData 和 certificate public key 验证 sig,并使用 SHA-256 作为 第二步中使用的哈希函数。
-
8.7. 无证明语句格式
当WebAuthn 依赖方表示其不希望接收证明信息时,无证明语句格式用于替换任何由认证器提供的证明语句,请参阅§ 5.4.7 证明传送首选项枚举(枚举 AttestationConveyancePreference)。
如果认证器不 支持证明,则认证器也可以 直接生成此格式的证明语句。
- 证明语句格式标识符
-
none
- 支持的证明类型
- 语法
-
无证明语句的语法定义如下:
$$attStmtType //= ( fmt: "none", attStmt: emptyMap ) emptyMap = {} - 签名过程
-
返回上面定义的固定证明语句。
- 验证过程
8.8. Apple 匿名证明语句格式
此证明语句格式仅由 Apple 用于支持 WebAuthn 的某些类型 Apple 设备。
- 证明语句格式标识符
-
apple
- 支持的证明类型
- 语法
-
Apple 证明语句的语法定义如下:
$$attStmtType //= ( fmt: "apple", attStmt: appleStmtFormat ) appleStmtFormat = { x5c: [ credCert: bytes, * (caCert: bytes) ] }上述字段的语义如下:
- x5c
-
credCert 后接其证书链,每个均以 X.509 格式编码。
- credCert
-
用于证明的凭据公钥证书,以 X.509 格式编码。
- 签名过程
-
-
令 authenticatorData 表示用于证明的认证器数据,并令 clientDataHash 表示序列化 客户端数据的哈希。
-
连接 authenticatorData 和 clientDataHash 以形成 nonceToHash。
-
对 nonceToHash 执行 SHA-256 哈希以生成 nonce。
-
让 Apple 匿名证明 CA 为凭据公钥生成 X.509 证书,并将 nonce 作为 OID 为
1.2.840.113635.100.8.2的证书扩展包含其中。 credCert 表示此证书。因此,credCert 充当 证明的证据,而其中包含的 nonce 证明该证明是实时的。此外, nonce 还保护 authenticatorData 和客户端数据的完整性。 -
将 x5c 设置为 credCert,后接其证书链。
-
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
8.9. 复合证明语句格式
"compound" 证明语句格式用于在单个仪式中传递多个自包含证明语句。
- 证明语句格式标识符
-
compound
- 支持的证明类型
-
任意。请参阅§ 6.5.3 证明类型。
- 语法
-
复合证明语句的语法定义如下:
$$attStmtType //= ( fmt: "compound", attStmt: [2* nonCompoundAttStmt] ) nonCompoundAttStmt = { $$attStmtType } .within { fmt: text .ne "compound", * any => any } - 签名过程
-
不适用
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程 如下:
9. WebAuthn 扩展
生成公钥凭据以及请求和生成 身份验证断言的机制,如 § 5 Web 身份验证 API中所定义,可以扩展以适应特定用例。 每种情况都通过定义一个注册 扩展和/或一个身份验证扩展来处理。
每个扩展都是一个客户端 扩展,这意味着该扩展涉及与 客户端的通信和由客户端执行的处理。 客户端扩展定义 以下步骤和数据:
-
navigator.credentials.create()针对注册扩展的扩展请求参数和响应值。 -
navigator.credentials.get()针对身份验证 扩展的扩展请求参数和响应值。
创建公钥凭据或请求身份验证断言时,
WebAuthn
依赖方可以请求使用一组
扩展。如果客户端和/或
WebAuthn
认证器支持这些扩展,则会在所请求的操作期间调用它们。依赖方在 get()
调用
(用于身份验证扩展)或 create()
调用(用于注册扩展)中,将每个扩展的客户端扩展输入发送给客户端。
客户端针对客户端平台
支持的每个扩展执行客户端扩展处理,并按照每个
扩展的规定,通过包含扩展标识符和客户端扩展输出
值来扩充客户端数据。
扩展也可以是一个认证器扩展,这意味着该扩展涉及 与认证器的通信和由认证器执行的 处理。认证器扩展定义以下步骤和数据:
-
authenticatorMakeCredential 针对注册扩展的扩展请求 参数和响应值。
-
authenticatorGetAssertion 针对身份验证扩展的扩展请求 参数和响应值。
对于认证器扩展,作为客户端扩展处理的一部分,客户端还会为
每个扩展创建 CBOR
认证器扩展输入值
(通常基于相应的客户端扩展输入值),
并在 create()
调用(用于注册扩展)或
get()
调用(用于身份验证扩展)中将它们传递给认证器。这些认证器
扩展输入值
以 CBOR 表示,并作为名称-值
对传递,其中以扩展标识符作为名称,以相应的
认证器扩展输入作为值。认证器
随后针对其支持的扩展执行附加处理,并按照扩展的规定为每个扩展返回
CBOR 认证器扩展输出。
由于认证器扩展输出作为已签名认证器数据的一部分返回,因此认证器扩展
还可以指定一个未签名扩展输出,例如用于输出
本身依赖于认证器数据的情况。
针对认证器扩展的客户端扩展处理的一部分,是使用认证器扩展输出
和未签名扩展输出作为创建客户端
扩展输出的输入。
所有WebAuthn 扩展对于客户端和认证器都是可选的。因此,依赖方请求的任何扩展都可以 被客户端浏览器或操作系统忽略而完全不传递给认证器,也可以被 认证器忽略。 忽略扩展绝不会被视为 WebAuthn API 处理失败,因此当依赖方在任何 API 调用中包含扩展时,它们必须准备好处理其中部分或全部扩展被忽略的情况。
所有WebAuthn 扩展都必须以这样的方式定义:即客户端或认证器不支持它们 时,不会危及用户的安全或隐私。 例如,如果某个扩展需要客户端处理,则可以将其定义为确保 一个仅将客户端扩展输入从 JSON 转码为 CBOR 的简单直通实现 会产生语义上无效的认证器扩展输入值,从而导致 认证器忽略该扩展。由于所有扩展都是可选的,这不会导致 API 操作发生功能性失败。
可以查阅由[RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries], 以获取已注册WebAuthn 扩展的最新列表。
9.1. 扩展标识符
扩展由一个字符串标识,该字符串称为扩展标识符,由扩展作者选择。
扩展标识符应该注册到 由[RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]中。 所有已注册扩展标识符自然都彼此唯一。
未注册的扩展标识符应该力求全局唯一,例如通过包含定义实体,
如
myCompany_extension。
所有扩展标识符的长度必须最多为 32 个八位字节,并且必须仅由可打印的 USASCII 字符组成, 不包括反斜杠和双引号,即[RFC5234]中定义的 VCHAR,但不包括 %x22 和 %x5c。实现必须 以区分大小写的方式匹配 WebAuthn 扩展标识符。
可能存在多个版本的扩展应该注意在其标识符中包含版本。这样,不同
版本实际上会被视为不同扩展,例如 myCompany_extension_01
§ 10 定义的扩展定义了一组附加扩展及其标识符。 有关已注册 WebAuthn 扩展标识符的最新列表,请参阅由[RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]。
9.2. 定义扩展
扩展的定义必须指定一个扩展标识符、一个通过 get()
或 create()
调用发送的客户端扩展输入参数、
客户端扩展处理规则,以及一个客户端
扩展输出值。
如果扩展与认证器通信(意味着它是一个认证器扩展),
它还必须指定通过authenticatorGetAssertion 或authenticatorMakeCredential 调用发送的
CBOR 认证器扩展输入参数、
认证器扩展处理规则,以及
CBOR 认证器
扩展输出值。
扩展可以指定未签名扩展输出。
客户端处理的任何客户端扩展
都必须返回一个客户端扩展输出值,以便WebAuthn
依赖方
知道该扩展已由客户端执行。类似地,任何需要认证器
处理的扩展都必须返回一个
认证器扩展输出,以使依赖方知道
该扩展已由认证器执行。如果
某扩展在其他方面不需要任何结果值,则应该将其定义为返回 JSON Boolean 客户端
扩展输出结果,并设置为 true,以表示该扩展已被理解和
处理。同样,任何在其他方面不需要任何
结果值的认证器扩展都必须返回一个值,并且应该返回一个 CBOR Boolean
认证器扩展输出结果,并设置为
true,以表示该扩展已被理解和处理。
9.3. 扩展请求参数
扩展定义一个或两个请求参数。客户端扩展输入
是一个可编码为 JSON 的值,它在 get()
或 create()
调用中从WebAuthn
依赖方传递给
客户端,
而 CBOR 认证器扩展输入
则在处理这些
调用期间,针对认证器扩展从客户端传递给认证器。
依赖方
通过在 extensions
选项中包含一个条目,在 create()
或 get()
调用中同时请求使用某个扩展并设置其客户端扩展输入。
条目键是扩展标识符,值是客户端
扩展输入。
注:其他文档已经规定过这样的扩展,其中 扩展输入并不总是使用扩展标识符 作为条目键。 上述约定仍适用于新扩展。
var assertionPromise= navigator. credentials. get({ publicKey: { // 为简洁起见省略其他成员 extensions: { // 一个标识 "webauthnExample_foobar" 扩展的“条目键”, // 其值是一个包含两个输入参数的映射: "webauthnExample_foobar" : { foo: 42 , bar: "barfoo" } } } });
扩展定义必须规定其客户端扩展输入的有效值。客户端
应该忽略具有
无效客户端扩展输入的扩展。如果某扩展不需要来自依赖
方的任何参数,则应该将其定义
为接受一个 Boolean 客户端参数,并将其设置为 true,以表示依赖方请求该扩展。
仅影响客户端处理的扩展不需要指定认证器
扩展输入。具有
认证器处理的扩展必须指定根据客户端扩展输入计算认证器
扩展输入的方法,
并且必须通过为 $$extensionInput 和 $$extensionOutput 组套接字
使用扩展
标识符作为条目键定义一个附加选择,从而为 CDDL 类型
AuthenticationExtensionsAuthenticatorInputs
和
AuthenticationExtensionsAuthenticatorOutputs
定义扩展。
不需要输入参数、因此定义为接受设置为 true 的 Boolean客户端
扩展输入
值的扩展,
也应该将认证器扩展输入定义为常量
Boolean 值 true(CBOR 主类型
7,值 21)。
以下示例定义了一个标识符为
webauthnExample_foobar 的扩展,
它接受一个无符号整数作为认证器扩展输入,
并返回一个至少包含一个字节字符串的数组作为认证器
扩展输出:
$$extensionInput //= ( webauthnExample_foobar : uint) $$extensionOutput //= ( webauthnExample_foobar : [ + bytes] )
由于某些认证器通过 Bluetooth Low-Energy 或 NFC 等低带宽链路通信, 扩展应该力求定义尽可能小的认证器参数。
9.4. 客户端扩展处理
扩展可以在创建凭据或 生成断言期间对客户端定义附加处理要求。扩展的客户端扩展输入用作此客户端处理的输入。 对于每个受支持的客户端 扩展,客户端向 clientExtensions 映射添加一个条目,其中 以扩展 标识符作为键,以扩展的客户端扩展输入作为值。
同样,客户端扩展输出在 getClientExtensionResults()
的结果中表示为一个字典,其中以扩展
标识符作为键,以每个扩展的客户端扩展输出值作为值。
与客户端
扩展输入一样,客户端扩展输出是一个可编码为
JSON 的值。
对于被忽略的扩展,不得返回任何值。
需要认证器处理的扩展必须定义 如何使用客户端扩展输入来确定 CBOR 认证器 扩展输入的过程,以及 如何使用 CBOR 认证器扩展输出,以及在使用时的未签名扩展输出, 来确定客户端扩展输出的过程。
9.5. 认证器扩展 处理
每个已处理认证器扩展的 CBOR 认证器 扩展输入值包含在 authenticatorMakeCredential 和authenticatorGetAssertion 操作的 extensions 参数中。extensions 参数是一个 CBOR 映射,其中每个键都是一个扩展 标识符,对应的值则是该扩展的认证器 扩展输入。
同样,扩展输出表示在认证器数据的extensions部分中。认证器 数据的 extensions 部分 是一个 CBOR 映射,其中每个键都是一个扩展标识符, 对应的值则是该扩展的认证器扩展输出。
未签名扩展 输出独立于认证器数据表示,并由认证器 作为单独的映射返回,使用相同的扩展标识符作为键。此映射仅包含 使用未签名输出的认证器 扩展的条目。当扩展输出一个针对 认证器 数据的签名时,未签名输出很有用(因为否则签名将不得不对自身签名,这是不可能的),或者当 某些扩展输出不应该发送给依赖方时。
注:在[FIDO-CTAP] 中,未签名扩展输出会作为 CBOR 映射从
authenticatorMakeCredential 和authenticatorGetAssertion
的一个名为
unsignedExtensionOutputs 的顶层字段中返回。
对于每个受支持的扩展,使用该扩展的认证器扩展处理规则,从认证器扩展输入 以及可能的其他输入中创建 认证器扩展输出,以及在使用时的未签名扩展输出。 对于被忽略的扩展,不得返回任何值。
10. 定义的扩展
本节及其小节定义一组附加扩展,以注册到 由[RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]中。 面向广泛互操作性的用户代理可以实现这些扩展。
10.1. 客户端扩展
本节定义仅为客户端扩展的扩展。
10.1.1. FIDO AppID 扩展 (appid)
此扩展允许先前使用旧版 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 注册凭据的WebAuthn 依赖方 请求一个断言。FIDO API 使用一个称为 AppID 的依赖方替代标识符 [FIDO-APPID],而使用这些 API 创建的任何凭据都将限定作用域于 该标识符。没有此扩展时,它们需要重新注册,才能限定作用域于RP ID。
除了设置 appid
扩展输入之外,
使用此扩展还需要依赖方执行一些额外处理,
以允许用户使用其已注册的 U2F 凭据进行身份验证:
-
在
get()方法的allowCredentials选项 中列出所需的 U2F 凭据:-
将
type成员设置为public-key。 -
将
id成员设置为所需凭据各自的 U2F key handle。请注意,U2F key handle 通常使用base64url 编码,但在id中使用时必须解码为其二进制形式。
allowCredentials可以同时混合包含 WebAuthn凭据 ID和 U2F key handle; 通过此扩展指定appid并不会阻止用户使用 已通过 WebAuthn 注册且限定作用域于rpId中所述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 - 操作适用性
- 客户端扩展输入
-
一个指定 FIDO AppID 的单个 DOMString。
partial dictionary AuthenticationExtensionsClientInputs {DOMString ; };appid partial dictionary AuthenticationExtensionsClientInputsJSON {DOMString ; };appid - 客户端扩展处理
-
-
令 facetId 为将调用者的源传递给 FIDO 确定调用应用程序的 FacetID 算法所得的结果。
-
令 appId 为扩展输入。
-
将 facetId 和 appId 传递给 FIDO 的确定 调用者的 FacetID 是否获准用于某个 AppID算法。如果该算法拒绝 appId,则返回一个 "
SecurityError"DOMException。 -
在构建 allowCredentialDescriptorList时, 如果 U2F 认证器指示某个凭据不适用(即 返回
SW_WRONG_DATA),则客户端必须使用设置为 appId 的 SHA-256 哈希的 U2F application 参数重试。如果这产生适用的 凭据,则客户端必须将该凭据包含在 allowCredentialDescriptorList 中。随后,appId 的值会替换 authenticatorGetAssertion 的rpId参数。 -
令 output 为 Boolean 值
false。 -
在创建 assertionCreationData时, 如果断言由 U2F 认证器创建,且 U2F application 参数设置为 appId 的 SHA-256 哈希 而不是RP ID的 SHA-256 哈希,则将 output 设置为
true。
-
注:实际上,有若干实现并未 实现确定调用者的 FacetID 是否获准用于某个 AppID算法的第四步及后续步骤。 相反,在第三步中,对主机的比较被放宽,以接受位于同一站点上的主机。
- 客户端扩展输出
-
返回 output 的值。如果为 true,则使用了 AppID,因此在验证断言时,依赖方必须 预期
rpIdHash是 AppID 的哈希,而不是RP ID的哈希。partial dictionary AuthenticationExtensionsClientOutputs {boolean ; };appid partial dictionary AuthenticationExtensionsClientOutputsJSON {boolean ; };appid - 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.1.2. FIDO AppID 排除扩展 (appidExclude)
此注册扩展允许WebAuthn 依赖方排除包含 使用旧版 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI]创建的指定凭据的认证器。
在从 FIDO U2F JavaScript API 迁移期间,依赖方可能拥有一批已经注册了旧版凭据的用户。 appid 扩展允许登录流程平滑迁移,但在迁移注册流程时,excludeCredentials 字段 无法有效排除拥有旧版凭据的认证器,因为其内容会被视为 WebAuthn 凭据。此扩展指示客户端平台将excludeCredentials 的内容同时视为 WebAuthn 和旧版 FIDO 凭据。请注意,U2F key handle 通常使用base64url 编码,但在excludeCredentials中使用时,必须解码 为其二进制形式。
- 扩展标识符
-
appidExclude - 操作适用性
- 客户端扩展输入
-
一个指定 FIDO AppID 的单个 DOMString。
partial dictionary AuthenticationExtensionsClientInputs {DOMString ; };appidExclude partial dictionary AuthenticationExtensionsClientInputsJSON {DOMString ; };appidExclude - 客户端扩展处理
-
在创建新凭据时:
-
紧接在建立 RP ID之后执行以下 步骤:
-
令 facetId 为将调用者的源传递给 FIDO 确定 调用应用程序的 FacetID算法所得的结果。
-
令 appId 为扩展输入
appidExclude的值。 -
将 facetId 和 appId 传递给 FIDO 的确定 调用者的 FacetID 是否获准用于某个 AppID算法。如果后一个算法 拒绝 appId,则 返回一个 "
SecurityError"DOMException并同时终止 创建新凭据算法和 这些步骤。注:实际上,有若干 实现并未实现确定 调用者的 FacetID 是否获准用于某个 AppID算法的第四步及后续步骤。相反,在第三步中, 对主机的比较被放宽,以接受位于同一站点上的主机。
-
否则,继续正常处理。
-
-
紧接在调用 authenticatorMakeCredential之前执行以下步骤:
-
如果 authenticator 支持 U2F 协议[FIDO-U2F-Message-Formats],则对于 excludeCredentialDescriptorList 中的每个 凭据描述符 C:
-
通过向 authenticator 发送一个
U2F_AUTHENTICATE消息来检查 C 是否是使用 U2F 在 authenticator 上创建的, 其“五个部分”设置为以下值: -
如果 authenticator 以
message:error:test-of-user-presence-required(即成功)响应: 停止对该 authenticator 的正常处理,并以 平台特定方式指示该认证器不适用。例如,这可以通过 UI 表示,或者 可以涉及向 authenticator 请求用户同意,并在收到后将 其视为认证器返回了InvalidStateError。 可以通过如上向 authenticator 再发送一个U2F_AUTHENTICATE消息来请求用户同意, 不同之处在于将 control byte 设置为0x03("enforce-user-presence-and-sign"), 并忽略响应。
-
-
继续正常处理。
-
-
- 客户端扩展输出
-
返回值
true,以向依赖方指示该扩展已被执行。partial dictionary AuthenticationExtensionsClientOutputs {boolean ; };appidExclude partial dictionary AuthenticationExtensionsClientOutputsJSON {boolean ; };appidExclude - 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.1.3. 凭据属性扩展(credProps)
此客户端注册 扩展便于在注册 仪式导致创建公钥凭据源时,将客户端已知的某些凭据属性报告给发出请求的WebAuthn 依赖方。
目前定义了一个凭据属性:客户端 可发现凭据属性。
- 扩展标识符
-
credProps - 操作适用性
- 客户端扩展输入
-
Boolean 值
true,用于指示依赖方请求此扩展。partial dictionary AuthenticationExtensionsClientInputs {boolean ; };credProps partial dictionary AuthenticationExtensionsClientInputsJSON {boolean ; };credProps - 客户端扩展处理
-
将
rk设置为在调用authenticatorMakeCredential 操作时所使用的 requireResidentKey 参数值。 - 客户端扩展输出
-
将
clientExtensionResults["设置为在调用authenticatorMakeCredential 操作时所使用的 requireResidentKey 参数值。credProps"]["rk"]dictionary {CredentialPropertiesOutput boolean rk ; };partial dictionary AuthenticationExtensionsClientOutputs {CredentialPropertiesOutput ; };credProps partial dictionary AuthenticationExtensionsClientOutputsJSON {CredentialPropertiesOutput ; };credProps rk, 类型为boolean-
此可选属性,抽象地称为客户端 可发现凭据属性 或驻留密钥 凭据属性, 是一个 Boolean 值,指示作为注册仪式结果返回的
PublicKeyCredential是否为客户端可发现 凭据。 如果rk为true,则该凭据是可发现 凭据。 如果rk为false,则该凭据是服务器端 凭据。 如果rk不存在,则不知道该凭据是可发现 凭据还是服务器端凭据。注:某些认证器即使在客户端平台未请求时也会创建可发现凭据。因此,客户端 平台可能被迫省略
rk属性,因为它们没有足够保证将其设置为false。依赖 方应该假定,如果支持credProps扩展,那么客户端平台将尽力填充rk属性。因此,缺失的rk表示创建的凭据最有可能是不可发现凭据。
- 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.1.4. 伪随机函数扩展(prf)
此客户端注册
扩展和身份验证扩展允许依赖方计算与凭据关联的
伪随机函数 (PRF) 的输出。此扩展提供的 PRF 将任意长度的 BufferSource
映射到 32 字节的 BufferSource。
作为一个动机示例,PRF 输出可以用作对称密钥来加密用户数据。若无法从关联的凭据获取断言,则无法访问此类加密 数据。通过使用下面的规定在单次断言 操作中计算 PRF 的两个输入,可以在断言期间定期轮换加密密钥,方法是选择新的随机输入并使用新 输出重新加密。如果计算输入不可预测,那么即使攻击者能够满足用户验证, 并且在有限时间内可以访问认证器,如果不知道正确的 PRF 输入,也无法获知加密密钥。
此扩展以[FIDO-CTAP]
hmac-secret 扩展为基础建模,但
也可以通过其他方式实现。
它是一个独立的客户端
扩展,因为 hmac-secret 要求以只有用户代理才能执行的方式对输入和输出进行加密,
并且要在 WebAuthn 的使用与底层平台的任何使用之间提供隔离。
这种隔离通过使用上下文字符串对提供的 PRF 输入进行哈希来实现,
以防止对任意输入计算 PRF。
hmac-secret 扩展为每个凭据提供两个 PRF:一个用于执行了
用户验证的请求,
另一个用于所有其他请求。此扩展仅为每个凭据暴露一个 PRF,
并且在基于 hmac-secret 实现时,该 PRF 必须是执行用户验证时使用的那个。
如有必要,这会覆盖 UserVerificationRequirement。
此扩展可以为不使用[FIDO-CTAP] 的认证器实现。 客户端与认证器之间的此接口, 以及由认证器构造 PRF 的方式,仅作抽象规定。
注:基于 hmac-secret
实现会产生其他情况下不存在的认证器扩展输出。
这些输出已加密,依赖方无法使用,
但客户端也无法删除它们,因为认证器数据已签名。
- 扩展标识符
-
prf - 操作适用性
- 客户端扩展输入
-
dictionary {AuthenticationExtensionsPRFValues required BufferSource ;first BufferSource ; };second dictionary {AuthenticationExtensionsPRFValuesJSON required Base64URLString ;first Base64URLString ; };second dictionary {AuthenticationExtensionsPRFInputs AuthenticationExtensionsPRFValues eval ;record <DOMString ,AuthenticationExtensionsPRFValues >evalByCredential ; };dictionary {AuthenticationExtensionsPRFInputsJSON AuthenticationExtensionsPRFValuesJSON ;eval record <DOMString ,AuthenticationExtensionsPRFValuesJSON >; };evalByCredential partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsPRFInputs ; };prf partial dictionary AuthenticationExtensionsClientInputsJSON {AuthenticationExtensionsPRFInputsJSON ; };prf eval, 类型为 AuthenticationExtensionsPRFValues-
用于计算 PRF 的一个或两个输入。并非所有认证器都支持 在创建凭据期间计算 PRF,因此可能会也可能不会提供输出。 如果未提供,则需要一个断言才能获得输出。
evalByCredential, 类型为 record<DOMString, AuthenticationExtensionsPRFValues>-
一个将base64url 编码的凭据 ID映射到 要为该凭据计算的 PRF 输入的记录。仅适用于
allowCredentials不为空的断言期间。
- 客户端扩展处理(注册)
-
-
如果
evalByCredential存在,则返回一个名称为“NotSupportedError”的DOMException。 -
如果
eval存在: -
如果认证器支持 CTAP2
hmac-secret扩展[FIDO-CTAP]:-
在认证器扩展输入中将
hmac-secret设置为true。 -
如果定义了 salt1,并且[FIDO-CTAP]的未来扩展允许 在创建时计算 PRF, 则使用 salt1 以及在已定义时的 salt2 值相应配置
hmac-secret输入。 -
将
enabled设置为认证器扩展输出中hmac-secret的值。如果 不存在,则将enabled设置为false。 -
将
results设置为解密后的 PRF 结果(如果有)。
-
-
如果认证器不支持 CTAP2
hmac-secret扩展[FIDO-CTAP], 但支持与下面定义的抽象认证器 处理兼容的其他实现:
-
- 客户端扩展处理(身份验证)
-
-
如果
evalByCredential不为空,但allowCredentials为空,则返回一个名称为“NotSupportedError”的DOMException。 -
如果
evalByCredential中的任何键为空字符串,或不是有效的base64url 编码,或者执行base64url 解码后不等于allowCredentials中某个元素的id,则返回一个名称为“SyntaxError”的DOMException。 -
将
prf扩展输出初始化为空字典。 -
令 ev 为 null,并尝试查找任何适用的 PRF 输入:
-
如果
evalByCredential存在,并包含一个条目,其键是 将要返回的凭据 ID的base64url 编码,则令 ev 为该条目的值。
-
-
如果 ev 不为 null:
-
令 salt1 为
SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || ev.的值。first) -
如果
ev.存在,则令 salt2 为secondSHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || ev.的值。second) -
如果认证器支持 CTAP2
hmac-secret扩展[FIDO-CTAP]: -
如果认证器不支持 CTAP2
hmac-secret扩展[FIDO-CTAP], 但支持与下面定义的抽象 认证器处理兼容的其他实现:-
使用某种未规定的机制将 salt1 以及在已定义时的 salt2 按此顺序作为 PRF 输入传送给认证器。
-
使用某种未规定的机制从 认证器接收 PRF 输出,作为一个
AuthenticationExtensionsPRFValues值 results。 将设置为 results。results
-
-
-
- 认证器扩展输入 / 输出
-
此扩展对 认证器实现进行了抽象, 使用[FIDO-CTAP]
hmac-secret扩展或未规定的客户端与认证器通信接口。 因此,除以下要求外,它不规定输入和输出的 CBOR 接口:-
认证器扩展输出不得 包含明文 PRF 输出。
注:这是因为认证器数据已签名, 因此如果
PublicKeyCredential需要发送到依赖方服务器, 认证器扩展输出就无法被省略。 这对于 PRF 输出应该仅在客户端保持私密的用例很重要, 例如使用 PRF 输出来派生加密密钥。
-
- 认证器扩展处理
-
支持[FIDO-CTAP]
hmac-secret扩展的认证器按照该扩展中的定义实现认证器处理。不支持[FIDO-CTAP]
hmac-secret扩展的认证器 可以改为实现以下抽象过程:-
令 PRF 为与当前凭据关联的伪随机函数, 如果尚未初始化,则初始化该关联:
令 PRF 为一个伪随机函数,其输出恰好为 32 字节长, 从至少包含 2256 个此类函数的集合中均匀随机选择。 PRF 的选择必须独立于用户验证的状态。 所选 PRF 不应该用于实现此扩展之外的其他目的。 在凭据的生命周期内,将 PRF 与当前凭据关联。
-
使用某种未规定的机制从客户端按此顺序接收 PRF 输入 salt1,以及可选的 salt2。 如果没有收到,则令 salt1 和 salt2 为 undefined。
-
如果定义了 salt1:
-
令 results 为一个
AuthenticationExtensionsPRFValues结构,其中包含 PRF 对给定输入的计算结果: -
使用某种未规定的机制将 results 作为 PRF 输出传送给客户端。
-
-
- 客户端扩展输出
-
dictionary {AuthenticationExtensionsPRFOutputs boolean enabled ;AuthenticationExtensionsPRFValues results ; };dictionary {AuthenticationExtensionsPRFOutputsJSON boolean ;enabled AuthenticationExtensionsPRFValuesJSON ; };results partial dictionary AuthenticationExtensionsClientOutputs {AuthenticationExtensionsPRFOutputs ; };prf partial dictionary AuthenticationExtensionsClientOutputsJSON {AuthenticationExtensionsPRFOutputsJSON ; };prf enabled, 类型为booleanresults, 类型为AuthenticationExtensionsPRFValues-
针对
eval或evalByCredential中给定输入计算 PRF 的结果。 在注册期间可能无法获得输出;请参阅eval中的说明。对于某些用例,例如 PRF 输出用于派生仅在客户端使用的加密密钥时, 如果
PublicKeyCredential被发送到远程服务器, 例如执行§ 7 WebAuthn 依赖方操作中的过程时,可能需要省略此results输出。 特别要注意,RegistrationResponseJSON和AuthenticationResponseJSON由返回时,如果存在此PublicKeyCredential.toJSON()results输出,则会将其包含在内。
10.1.5. 大 blob 存储扩展(largeBlob)
此客户端注册 扩展和身份验证扩展允许依赖方存储与凭据关联的不透明数据。 由于认证器只能存储少量数据,而大多数依赖方都是可以为用户存储 任意数量状态的在线服务,因此它只在特定情况下有用。例如,依赖方 可能希望颁发证书,而不是运行集中式身份验证服务。
注:依赖方可以假定,不透明数据在写入 空间受限设备时会被压缩,因此无需自行压缩。
由于证书系统需要对凭据的公钥进行签名,而该公钥仅在 创建之后才可用,因此此扩展不会在注册上下文中添加写入 blob 的能力。但是,如果依赖方希望以后使用身份验证扩展, 则在创建凭据时应该使用注册 扩展。
由于证书相对于典型认证器的存储能力而言体积较大,因此用户代理 应该考虑哪些指示和确认最适合引导用户分配这一 有限资源并防止滥用。
注:为了实现互操作性,使用[FIDO-CTAP]在认证器上存储 大 blob 的用户代理预期使用该规范中针对存储大型、按凭据 blob所详述的规定。
注:将[FIDO-CTAP]用作其跨平台传输
协议的漫游认证器仅对可发现凭据支持此大 Blob
扩展,
并且除非
设置为 authenticatorSelection.residentKeypreferred
或 required,
否则可能返回错误。
但是,不使用[FIDO-CTAP]的认证器不一定将此
扩展限制为可发现凭据。
- 扩展标识符
-
largeBlob - 操作适用性
- 客户端扩展输入
-
partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsLargeBlobInputs ; };largeBlob partial dictionary AuthenticationExtensionsClientInputsJSON {AuthenticationExtensionsLargeBlobInputsJSON ; };largeBlob enum {LargeBlobSupport ,"required" , };"preferred" dictionary {AuthenticationExtensionsLargeBlobInputs DOMString support ;boolean read ;BufferSource write ; };dictionary {AuthenticationExtensionsLargeBlobInputsJSON DOMString ;support boolean ;read Base64URLString ; };write support, 类型为DOMString-
一个取
LargeBlobSupport值之一的 DOMString。 (请参阅§ 2.1.1 作为 DOMString 类型的枚举。)仅在注册期间有效。 read, 类型为 booleanwrite, 类型为BufferSource
- 客户端扩展处理(注册)
-
-
-
返回一个名称为“
NotSupportedError”的DOMException。
-
-
-
将
supported设置为true。注:这是为了预期 能够存储大 blob 的认证器变得可用。 它发生在
[[Create]](origin, options, sameOriginWithAncestors)的步骤 12中的扩展处理期间。 如果没有令人满意的认证器可用,AuthenticationExtensionsLargeBlobOutputs将被放弃。 -
如果候选认证器变得 可用(
[[Create]](origin, options, sameOriginWithAncestors)的步骤 22), 那么,在计算任何options之前,如果候选认证器不能 存储大 blob,则继续(即忽略该候选认证器)。
-
-
- 客户端扩展处理(身份验证)
-
-
如果
support存在:-
返回一个名称为“
NotSupportedError”的DOMException。
-
-
-
返回一个名称为“
NotSupportedError”的DOMException。
-
-
如果
read存在且值为true:-
如果任何认证器指示成功(在
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)中), 则尝试读取与所断言凭据关联的任何 largeBlob 数据。 -
如果成功,则将
blob设置为结果。注:如果读取不 成功,则
largeBlob将存在于AuthenticationExtensionsClientOutputs中,但blob成员不会存在。
-
如果
write存在:-
如果
allowCredentials不恰好包含一个元素:-
返回一个名称为“
NotSupportedError”的DOMException。
-
-
如果成功,则将
written设置为true,否则设置为false。
-
-
- 客户端扩展输出
-
partial dictionary AuthenticationExtensionsClientOutputs {AuthenticationExtensionsLargeBlobOutputs ; };largeBlob partial dictionary AuthenticationExtensionsClientOutputsJSON {AuthenticationExtensionsLargeBlobOutputsJSON ; };largeBlob dictionary {AuthenticationExtensionsLargeBlobOutputs boolean supported ;ArrayBuffer blob ;boolean written ; };dictionary {AuthenticationExtensionsLargeBlobOutputsJSON boolean ;supported Base64URLString ;blob boolean ; };written - 认证器扩展处理
10.1.6. 远程客户端数据 JSON 扩展(remoteClientDataJSON)
远程桌面 Web 客户端允许用户从本地 客户端(Web)应用程序与远程主机的(原生)桌面环境交互。
此注册 扩展和身份验证扩展允许用户使用连接到本地客户端平台的 WebAuthn 认证器,以登录浏览器中的网站,或登录运行在远程主机上的应用程序, 该远程主机处于远程 桌面 Web 客户端中。
这允许基于 Web 的远程桌面 Web 客户端在本地执行远程 WebAuthn 请求。这里,远程 桌面 Web 客户端代表 远程计算机上的 RP 调用 WebAuthn 请求,而其源与远程计算机中的调用 RP 不同。
此扩展是一个强大功能,使用前需要显式的按源权限。 用户 代理不应该在请求时提示用户授予此权限; 相反,该授权通过设备管理策略(例如,枚举特定远程桌面 Web 客户端源的受管浏览器配置文件、受管 浏览器实例或受管设备)进行管理,或者 通过WebAuthn 客户端设置中的显式按源用户选择加入来管理。 此权限必须按源配置,并且不得提供允许所有源的能力。
- 权限
-
此扩展定义一个强大功能([Permissions])和一个策略控制的功能([Permissions-Policy]), 两者均由名称
"publickey-credentials-remote-client-data-json"标识。 此策略控制的功能的默认允许列表为'none'。 此功能的默认权限状态为"denied", 这意味着该扩展默认不可用,必须显式启用。 由于没有定义其他方面,权限描述符类型默认为PermissionDescriptor。远程桌面 Web 客户端可以通过PermissionsAPI 检查用户代理是否已配置为 允许当前源使用此扩展:const status= await navigator. permissions. query({ name: "publickey-credentials-remote-client-data-json" }); if ( status. state=== "granted" ) { // 客户端已配置为允许 remoteClientDataJSON 扩展;继续远程桌面流程。 } - 扩展标识符
-
remoteClientDataJSON - 操作适用性
- 客户端扩展输入
-
partial dictionary AuthenticationExtensionsClientInputs {DOMString ; };remoteClientDataJSON partial dictionary AuthenticationExtensionsClientInputsJSON {DOMString ; };remoteClientDataJSON - 客户端扩展处理(注册)
-
在创建新凭据时,此扩展会在该算法的标记点插入 以下 步骤:
-
用以下 过程替换建立 RP ID
-
如果针对
"publickey-credentials-remote-client-data-json"和当前设置对象获取当前 权限状态的结果 不是"granted"。-
抛出一个 "
NotAllowedError"DOMException。
-
-
-
抛出一个 "
NotAllowedError"DOMException。
-
-
令 collectedClientData 为给定 remoteClientDataJSON 时将 JSON 字符串解析为 Infra 值的结果。
-
如果上述解析步骤失败,则抛出一个 "
EncodingError"DOMException。
-
-
令 remoteOrigin 为 collectedClientData 的
"origin"键的值。 -
跳过检查
pkOptions.是否是 remoteOrigin 的可注册域后缀或与其相等。rp.id注:这意味着本地 客户端将所有与RP ID相关的源检查委托给远程客户端。
-
-
跳过构造 collectedClientData 步骤。
-
在序列化客户端数据步骤中, 改为将 clientDataJSON 设置为 remoteClientDataJSON。
-
- 客户端扩展处理(身份验证)
-
在生成身份验证断言时,此扩展会在该 算法的标记点插入 以下步骤:
-
用以下过程替换建立 RP ID:
-
如果针对
"publickey-credentials-remote-client-data-json"和当前设置对象获取当前 权限状态的结果 不是"granted"。-
抛出一个 "
NotAllowedError"DOMException。
-
-
-
抛出一个 "
NotAllowedError"DOMException。
-
-
令 collectedClientData 为给定 remoteClientDataJSON 时将 JSON 字符串解析为 Infra 值的结果。
-
如果上述解析步骤失败,则抛出一个 "
EncodingError"DOMException。
-
-
令 remoteOrigin 为 collectedClientData 的
"origin"键的值。 -
跳过检查
pkOptions.是否是 remoteOrigin 的可注册域后缀或与其相等。rp.id注:这意味着本地 客户端将所有与RP ID相关的源检查委托给远程客户端。
-
-
跳过构造 collectedClientData 步骤。
-
在序列化客户端数据步骤中, 改为将 clientDataJSON 设置为 remoteClientDataJSON。
-
- 认证器扩展输入
-
无
- 认证器扩展处理
-
无
- 认证器扩展输出
-
无
- 客户端扩展输出
-
返回值
true,以向依赖方指示该扩展已被执行。partial dictionary AuthenticationExtensionsClientOutputs {boolean ; };remoteClientDataJSON partial dictionary AuthenticationExtensionsClientOutputsJSON {boolean ; };remoteClientDataJSON
10.2. 认证器扩展
本节目前为空。
11. 用户代理自动化
出于用户代理自动化和Web 应用程序测试的目的,本文档定义了若干 [WebDriver] 扩展命令。
11.1. WebAuthn WebDriver 扩展能力
为了宣告下面定义的扩展命令的可用性,定义了一个新的扩展能力。
在验证能力时,使用 value 验证
"webauthn:virtualAuthenticators" 的扩展特定子步骤如下:
-
如果
value不是boolean,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。 -
否则,将
deserialized设置为value。
在匹配能力时,使用 value 匹配
"webauthn:virtualAuthenticators" 的扩展特定步骤如下:
11.1.1. 认证器扩展 能力
此外,还为本规范中定义的每个认证器扩展 (即定义认证器扩展处理的扩展)定义了扩展能力:
| 能力 | 键 | 值类型 | 描述 |
|---|---|---|---|
| 伪随机函数扩展支持 | "webauthn:extension:prf"
| boolean | 指示端点节点的 WebAuthn WebDriver 实现 是否支持prf 扩展。 |
| 大 Blob 存储扩展支持 | "webauthn:extension:largeBlob"
| boolean | 指示端点节点的 WebAuthn WebDriver 实现 是否支持largeBlob 扩展。 |
| credBlob 扩展支持 | "webauthn:extension:credBlob"
| boolean | 指示端点节点的 WebAuthn WebDriver 实现
是否支持[FIDO-CTAP]中定义的 credBlob 扩展。
|
在验证能力时,使用 value 验证认证器扩展能力
key 的扩展特定子步骤如下:
-
如果
value不是boolean,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。 -
否则,将
deserialized设置为value。
在匹配能力时,使用 value 匹配
认证器扩展能力
key 的扩展特定步骤如下:
实现已定义认证器扩展的用户代理应该实现相应的 认证器扩展能力。
11.2. 虚拟认证器
这些 WebDriver扩展命令创建虚拟 认证器并与之交互:即 认证器 模型的软件实现。虚拟认证器存储在虚拟认证器 数据库中。 每个已存储的虚拟认证器具有以下属性:
- authenticatorId
-
一个非 null 字符串,由[RFC3986]附录 A 中定义的
unreserved产生式中的最多 48 个字符组成, 用于唯一标识虚拟认证器。 - protocol
-
虚拟认证器使用的协议:
"ctap1/u2f"、"ctap2"或"ctap2_1"之一[FIDO-CTAP]。 - transport
-
模拟的
AuthenticatorTransport。 如果 transport 设置为internal, 则 认证器模拟平台附着。否则,它模拟跨平台附着。 - hasResidentKey
-
如果设置为
true,认证器将支持客户端可发现凭据。 - hasUserVerification
-
如果设置为
true,认证器支持用户验证。 - isUserConsenting
-
确定所有用户同意授权手势的结果, 并由此确定在虚拟认证器上执行的任何用户在场测试的结果。如果设置为
true, 则用户同意将 始终被授予。如果设置为false,则不会被授予。 - isUserVerified
-
确定在虚拟认证器上执行的用户验证结果。 如果设置为
true, 用户 验证将始终成功。如果设置为false,则会失败。注:如果 hasUserVerification 设置为
false,则此属性不起作用。 - extensions
-
虚拟认证器必须支持其 extensions 数组中存在的所有认证器扩展。 它不得支持任何不在其 extensions 数组中的认证器扩展。
- defaultBackupEligibility
-
确定任何新创建公钥凭据源的备份资格凭据属性的默认状态。 使用此虚拟认证器执行authenticatorMakeCredential 操作时,此值必须反映在认证器数据的BE标志中。
- defaultBackupState
-
确定任何新创建公钥凭据源的备份状态凭据属性的默认状态。 使用此虚拟认证器执行authenticatorMakeCredential 操作时,此值必须反映在认证器数据的BS标志中。
11.3. 添加虚拟认证器
添加 虚拟认证器 WebDriver扩展命令创建一个软件虚拟认证器。其 定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator
|
认证器 配置是作为 parameters 传递给远程 端步骤的 JSON 对象。它包含以下 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 数组 | 包含扩展标识符的数组 | 空数组 |
| defaultBackupEligibility | boolean | true, false
| false
|
| defaultBackupState | boolean | true, false
| false
|
远程端步骤如下:
-
如果 parameters 不是 JSON 对象,则返回一个 WebDriver 错误,其WebDriver 错误码为 无效参数。
注:parameters 是一个认证器配置对象。
-
令 authenticator 为一个新的虚拟认证器。
-
对于 parameters 中的每个可枚举自有属性:
-
令 key 为该属性的名称。
-
令 value 为从 parameters 中获取名为 key 的属性的结果。
-
如果认证器配置中没有与 key 匹配的
key,则返回一个WebDriver 错误,其 WebDriver 错误码为无效参数。 -
如果 value 不是该 key 的
valid values之一, 则返回一个WebDriver 错误,其WebDriver 错误码为 无效参数。 -
在 authenticator 上将属性 key设置为 value。
-
-
对于认证器配置中定义了默认值的每个属性:
-
如果
key不是 authenticator 已定义的属性,则在 authenticator 上将属性key设置为default。
-
-
对于认证器配置中的每个属性:
-
如果
key不是 authenticator 已定义的属性,则返回一个WebDriver 错误,其WebDriver 错误码为 无效参数。
-
-
对于 authenticator.extensions 中的每个 extension:
-
如果 extension 不是端点节点 WebAuthn WebDriver 实现支持的扩展标识符,则 返回一个WebDriver 错误,其WebDriver 错误码为不支持的操作。
-
-
生成一个有效且唯一的authenticatorId。
-
在 authenticator 上将属性
authenticatorId设置为 authenticatorId。 -
将 authenticator 存储在虚拟认证器数据库中。
-
返回成功,数据为 authenticatorId。
11.4. 移除虚拟认证器
移除虚拟认证器 WebDriver扩展命令移除先前创建的虚拟 认证器。 其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}
|
远程端步骤如下:
-
如果 authenticatorId 与虚拟认证器数据库中存储的任何虚拟认证器都不匹配,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
返回成功。
11.5. 添加凭据
添加凭据 WebDriver 扩展命令将一个公钥凭据 源注入现有的 虚拟 认证器。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/credential
|
凭据 参数是一个 JSON 对象,作为 parameters 传递给远程 端步骤。它包含以下 key 和 value 对:
| 键 | 描述 | 值类型 |
|---|---|---|
| credentialId | 使用Base64url 编码编码的凭据 ID。 | string |
| isResidentCredential |
如果设置为 true,则创建客户端可发现
凭据。如果设置为 false,则改为创建服务器端
凭据。
| boolean |
| rpId | 凭据所限定作用域到的依赖方 ID。 | string |
| privateKey | 一个非对称密钥包,其中包含一个私钥, 符合[RFC5958],并使用Base64url 编码进行编码。 | string |
| userHandle | 与凭据关联的userHandle,使用 Base64url 编码进行编码。可以不定义此属性。 | string |
| signCount |
此属性是必需的。它必须是范围为 0 到 4294967295(含)的
32 位无符号整数值,或者为 null。
当 signCount 是无符号整数值时,会将一个
签名
计数器与该凭据关联,并在authenticatorGetAssertion 操作期间递增。当
signCount 为 null 时,
不会有签名计数器与该
凭据关联。
| number 或 null |
| largeBlob | 与公钥凭据源关联的大型、按凭据 blob,使用Base64url 编码进行编码。 可以不定义此属性。 | string |
| backupEligibility | 公钥凭据源的模拟备份资格。如果未设置,该值将默认为 虚拟认证器的 defaultBackupEligibility 属性。 在使用此公钥凭据源执行 authenticatorGetAssertion 操作时, 模拟的备份资格必须反映在认证器数据的BE标志中。 | boolean |
| backupState | 公钥凭据源的模拟备份 状态。如果未设置,该值将默认为 虚拟认证器的 defaultBackupState 属性。 在使用此公钥凭据源执行 authenticatorGetAssertion 操作时, 模拟的备份状态必须反映在认证器数据的BS标志中。 | boolean |
| userName |
与凭据关联的 user
的
name。
如果未设置,该值将默认为空字符串。
| string |
| userDisplayName |
与凭据关联的 user
的
displayName。
如果未设置,该值将默认为空字符串。
| string |
远程端步骤如下:
-
如果 parameters 不是 JSON 对象,则返回一个 WebDriver 错误,其WebDriver 错误码为 无效参数。
注:parameters 是一个凭据 参数对象。
-
令 credentialId 为对 parameters 的 credentialId 属性执行Base64url 编码解码的结果。
-
如果 credentialId 为失败,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。
-
令 isResidentCredential 为 parameters 的 isResidentCredential 属性。
-
如果 isResidentCredential 未定义,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。
-
令 rpId 为 parameters 的 rpId 属性。
-
如果 rpId 不是有效的RP ID,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
令 privateKey 为对 parameters 的 privateKey 属性执行Base64url 编码解码的结果。
-
如果 privateKey 为失败,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。
-
如果 privateKey 不是符合[RFC5958]、包含单个 P-256 曲线 ECDSA 私钥且有效编码的非对称密钥包,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。
-
如果 parameters 的 userHandle 属性已定义:
-
令 userHandle 为对 parameters 的 userHandle 属性执行Base64url 编码解码的结果。
-
如果 userHandle 为失败,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
-
否则:
-
如果 isResidentCredential 为
true,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。 -
令 userHandle 为
null。
-
-
如果 authenticatorId 与虚拟认证器数据库中存储的任何虚拟认证器都不匹配,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
令 authenticator 为由 authenticatorId 匹配的虚拟认证器。
-
如果 isResidentCredential 为
true,并且 authenticator 的 hasResidentKey 属性为false,则返回一个 WebDriver 错误,其WebDriver 错误码为无效参数。 -
如果 authenticator 支持largeBlob 扩展,并且 parameters 的 largeBlob 功能已定义:
-
令 largeBlob 为对 parameters 的 largeBlob 属性执行Base64url 编码解码的结果。
-
如果 largeBlob 为失败,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
-
否则:
-
令 largeBlob 为
null。
-
-
令 backupEligibility 为 parameters 的 backupEligibility 属性。
-
如果 backupEligibility 未定义,则将 backupEligibility 设置为 authenticator 的 defaultBackupEligibility 的值。
-
令 backupState 为 parameters 的 backupState 属性。
-
如果 backupState 未定义,则将 backupState 设置为 authenticator 的 defaultBackupState 的值。
-
令 userName 为 parameters 的 userName 属性。
-
如果 userName 未定义,则将 userName 设置为空字符串。
-
令 userDisplayName 为 parameters 的 userDisplayName 属性。
-
如果 userDisplayName 未定义,则将 userDisplayName 设置为空字符串。
-
如果 isResidentCredential 为
true,则令 credential 为一个新的客户端可发现 公钥凭据源;否则为一个服务器端公钥凭据 源,其项如下:- type
- id
-
credentialId
- privateKey
-
privateKey
- rpId
-
rpId
- userHandle
-
userHandle
- otherUI
-
从 userName 和 userDisplayName 构造。
-
令 signCount 为 parameters 的 signCount 属性。
-
如果 signCount 未定义,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。
-
如果 signCount 设置为范围为
0到4294967295(含)的 32 位无符号整数值,则将一个签名 计数器 counter 与 credential 关联,其初始值等于 signCount。 -
否则,如果 signCount 为
null,则不将签名计数器与 credential 关联。 -
否则,返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
如果 largeBlob 不为
null,则将与 credential 关联的大型、按凭据 blob设置为 largeBlob。 -
将 credential 和 counter 存储在 authenticator 的数据库中。
-
返回成功。
11.6. 获取凭据
获取凭据
WebDriver 扩展命令会针对
虚拟
认证器中存储的每个
公钥凭据源返回一个凭据参数对象,
无论它们是使用添加凭据
还是 navigator.credentials.create()
存储的。
其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| GET | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远程端步骤如下:
-
如果 authenticatorId 与虚拟认证器数据库中存储的任何虚拟认证器都不匹配,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
令 credentialsArray 为空数组。
-
对于由 authenticatorId 标识的认证器管理的每个公钥凭据源 credential,构造一个对应的凭据参数对象,并将 其添加到 credentialsArray。
-
返回成功,数据中包含 credentialsArray。
11.7. 移除凭据
移除凭据 WebDriver 扩展命令移除存储在 虚拟 认证器上的一个公钥凭据 源。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}
|
远程端步骤如下:
-
如果 authenticatorId 与虚拟认证器数据库中存储的任何虚拟认证器都不匹配,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
令 authenticator 为由 authenticatorId 标识的虚拟认证器。
-
如果 credentialId 与 authenticator 管理的任何公钥 凭据源都不匹配,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。
-
移除由 credentialId 标识并由 authenticator 管理的公钥凭据源。
-
返回成功。
11.8. 移除所有凭据
移除所有 凭据 WebDriver 扩展命令移除存储在 虚拟 认证器上的所有公钥凭据 源。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远程端步骤如下:
-
如果 authenticatorId 与虚拟认证器数据库中存储的任何虚拟认证器都不匹配,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
返回成功。
11.9. 设置用户已验证
设置用户已验证扩展命令设置虚拟 认证器上的 isUserVerified 属性。其 定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/uv
|
设置用户 已验证参数是一个 JSON 对象,作为 parameters 传递给远程端步骤。 它包含以下 key 和 value 对:
远程端步骤如下:
-
如果 parameters 不是 JSON 对象,则返回一个 WebDriver 错误,其WebDriver 错误码为 无效参数。
注:parameters 是一个设置用户已验证参数对象。
-
如果 authenticatorId 与虚拟认证器数据库中存储的任何虚拟认证器都不匹配,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
如果 isUserVerified 不是 parameters 的已定义属性,则返回一个WebDriver 错误,其WebDriver 错误码为 无效参数。
-
令 authenticator 为由 authenticatorId 标识的虚拟认证器。
-
将 authenticator 的 isUserVerified 属性设置为 parameters 的 isUserVerified 属性。
-
返回成功。
11.10. 设置凭据属性
设置 凭据属性扩展命令允许设置 虚拟 认证器的公钥凭据源的若干凭据 属性。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}/props
|
设置 凭据属性参数是一个 JSON 对象,作为 parameters 传递给远程端步骤。 它包含以下 key 和 value 对:
| 键 | 描述 | 值类型 |
|---|---|---|
| backupEligibility | 备份资格凭据 属性。 | boolean |
| backupState | 备份状态 凭据属性。 | boolean |
| signCount |
此属性是可选的。定义时,它应该是范围为 0 到
4294967295(含)的 32 位无符号整数值,
或 null。当 signCount 是无符号整数值时,凭据
将更新为具有一个设置为 signCount 的签名计数器。
当 signCount 为 null 时,将移除与
凭据关联的任何现有签名计数器。
| number 或 null |
远程端步骤如下:
-
如果 parameters 不是 JSON 对象,则返回一个 WebDriver 错误,其WebDriver 错误码为 无效参数。
注:parameters 是一个设置凭据属性参数 对象。
-
如果 authenticatorId 与虚拟认证器数据库中存储的任何虚拟认证器都不匹配,则返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
令 credential 为由 authenticator 管理并由 credentialId 匹配的公钥凭据源。
-
如果 credential 为空,则返回一个WebDriver 错误, 其WebDriver 错误码为无效参数。
-
令 backupEligibility 为 parameters 的 backupEligibility 属性。
-
如果 backupEligibility 已定义,则将 credential 的备份资格凭据属性设置为 backupEligibility 的值。
注:通常,backupEligibility 属性对于公钥凭据源是永久的。 设置凭据属性允许出于 测试和调试目的更改它。
-
令 backupState 为 parameters 的 backupState 属性。
-
如果 backupState 已定义,则将 credential 的备份状态凭据属性设置为 backupState 的值。
-
令 signCount 为 parameters 的 signCount 属性。
-
如果 signCount 已定义:
-
如果 signCount 设置为范围为
0到4294967295(含)的 32 位无符号整数值,则将 credential 的现有签名计数器 设置为 signCount 的值。如果 credential 没有签名计数器, 则将一个签名计数器与 credential 关联并设置为 signCount 的值。 -
否则,如果 signCount 为
null,则移除为 credential 设置的任何签名计数器。 -
否则,返回一个WebDriver 错误,其WebDriver 错误码为无效参数。
-
-
返回成功。
12. IANA 注意事项
12.1. WebAuthn 证明语句格式标识符注册更新
本节更新 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表[IANA-WebAuthn-Registries]中下面列出的、在 § 8 定义的证明语句格式中定义的证明语句格式;该注册表由[RFC8809]建立,这些格式最初注册于[WebAuthn-1],现将其 指向本规范。
-
WebAuthn 证明语句格式标识符:packed
-
描述:"packed" 证明语句格式是一种针对 WebAuthn 优化的证明格式。它使用一种 非常 紧凑但仍可扩展的编码方法。此格式可由资源有限的认证器(例如, 安全元件)实现。
-
规范文档:本规范的§ 8.2 打包证明语句 格式
-
WebAuthn 证明语句格式标识符:tpm
-
描述:TPM 证明语句格式返回与打包 证明语句格式相同格式的证明语句,尽管 rawData 和 signature 字段的计算方式不同。
-
规范文档:本规范的§ 8.3 TPM 证明语句 格式
-
WebAuthn 证明语句格式标识符:android-key
-
描述:"N" 及更高版本上的平台认证器可以提供这种专有的“硬件 证明”语句。
-
规范文档:本规范的§ 8.4 Android 密钥证明 语句格式
-
WebAuthn 证明语句格式标识符:android-safetynet
-
描述:基于 Android 的平台认证器可以生成基于 Android SafetyNet API 的证明语句。
-
规范文档:本规范的§ 8.5 Android SafetyNet 证明语句格式
-
WebAuthn 证明语句格式标识符:fido-u2f
-
描述:与 FIDO U2F 认证器一起使用
-
规范文档:本规范的§ 8.6 FIDO U2F 证明 语句格式
12.2. WebAuthn 证明语句格式标识符注册
本节将在§ 8 定义的证明语句格式中新定义的下列证明语句格式注册到由[RFC8809]建立的 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表[IANA-WebAuthn-Registries]中。
-
WebAuthn 证明语句格式标识符:apple
-
描述:与 Apple 设备的平台认证器一起使用
-
规范文档:本规范的§ 8.8 Apple 匿名 证明语句格式
-
WebAuthn 证明语句格式标识符:none
-
描述:当WebAuthn 依赖方表示其不希望 接收证明信息时,用于替换认证器提供的任何证明语句。
-
规范文档:本规范的§ 8.7 无证明语句 格式
12.3. WebAuthn 扩展标识符注册更新
本节更新由[RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]中下面列出的、在§ 10 定义的扩展中定义的扩展标识符值;这些值最初注册于[WebAuthn-1],现将其 指向本规范。
-
WebAuthn 扩展标识符:appid
-
描述:此身份验证扩展允许先前使用旧版 FIDO JavaScript API 注册过凭据的WebAuthn 依赖方请求断言。
-
规范文档:本规范的§ 10.1.1 FIDO AppID 扩展 (appid)
12.4. WebAuthn 扩展标识符注册
本节将在§ 10 定义的扩展中新定义的下列扩展标识符值注册到由[RFC8809]建立的 IANA "WebAuthn Extension Identifiers" 注册表[IANA-WebAuthn-Registries]中。
-
WebAuthn 扩展标识符:appidExclude
-
描述:此注册扩展允许WebAuthn 依赖 方排除包含使用旧版 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI]创建的指定凭据的认证器。
-
WebAuthn 扩展标识符:credProps
-
规范文档:本规范的§ 10.1.3 凭据属性 扩展 (credProps)
-
WebAuthn 扩展标识符:largeBlob
-
规范文档:本规范的§ 10.1.5 大 blob 存储 扩展 (largeBlob)
12.5. Well-Known URI 注册
本节在 IANA "Well-Known URIs" 注册表[IANA-Well-Known-URIs]中注册以下 well-known URI。
-
URI 后缀:
webauthn -
参考:本规范的§ 5.11.1 验证相关源
-
状态:永久
-
变更控制者:W3C Web 身份验证工作组 (public-webauthn@w3.org)
-
相关信息:(无)
13. 安全注意事项
本规范定义一个Web API和一个密码学对等实体身份验证 协议。 Web 身份验证 API允许 Web 开发人员(即“作者”)在其 注册和身份验证仪式中使用 Web 身份验证 协议。 构成 Web 身份验证协议端点的实体是用户控制的WebAuthn 认证器和WebAuthn 依赖方的计算环境, 该环境托管依赖方的Web 应用程序。 在此模型中,用户代理与WebAuthn 客户端一起构成认证器与依赖方之间的中介。 此外,认证器 可以向依赖方证明其来源。
目前,本规范未提供详细的安全注意事项。不过,[FIDOSecRef] 文档提供了一份总体上适用于本规范的安全分析。 此外,[FIDOAuthnrSecReqs]文档套件提供了有关认证器安全特征的有用信息。
下面的小节构成当前特定于 Web 身份验证的安全注意事项。 它们按受众划分; 一般安全注意事项是本节的直接子节, 而专门面向认证器、客户端和依赖方实现者的安全注意事项 则分组到各自的小节中。
13.1. 未签名的凭据 ID
随身份验证断言一起提供的凭据 ID未签名。 这并不是问题,因为如果认证器返回 错误的凭据 ID,或者 攻击者拦截并操纵凭据 ID,唯一会发生的情况是WebAuthn 依赖方无法查找到正确的 凭据公 钥来验证返回的已签名认证器数据 (又称断言),因此该 交互将以错误结束。
13.2. 客户端与认证器之间的物理接近性
在 WebAuthn认证器模型中,通常假设漫游 认证器 在物理上接近客户端并直接与其通信。 这种安排具有一些重要优势。
客户端与认证器之间物理接近性的保证 是你所拥有的事物身份验证因素的关键优势。 例如,如果漫游认证器只能通过 USB 或 Bluetooth 通信, 这些传输方式有限的范围确保任何恶意行为者 必须实际处于该范围内才能与认证器交互。 对于可以远程调用的认证器而言,这不一定成立 — 即使认证器 验证用户 在场, 用户也可能被骗去授权远程发起的恶意请求。
客户端与认证器之间直接通信 意味着客户端可以强制执行凭据的作用域限制。 相比之下,如果客户端与认证器之间的通信由某个第三方中介, 则客户端必须信任第三 方来 强制执行作用域限制并控制 对认证器的访问。 任一方面未能做到都可能导致 恶意依赖方 收到对其他依赖方有效的身份验证断言, 或恶意用户获得其他用户的身份验证断言。
如果设计一种认证器无需在物理上接近客户端, 或客户端与认证器不 直接通信的解决方案, 设计者应该考虑这会如何影响作用域限制的执行 以及认证器作为你所拥有的事物 身份验证因素的强度。
13.3. 认证器的安全注意事项
13.3.1. 证明证书层次结构
推荐对证明证书使用三级层次结构(即证明根、证明签发 CA、证明 证书)。还推荐为每个WebAuthn 认证器设备系列(即型号)使用单独的 签发 CA,以 帮助隔离特定版本认证器型号的问题。
如果证明根证书并非专用于单个WebAuthn 认证器设备 系列(即 AAGUID),则应该在证明证书本身中指定 AAGUID,以便可以针对认证器 数据验证它。
13.3.2. 证明证书和证明证书 CA 泄露
当用于签发证明证书的中间 CA 或根 CA 泄露时,WebAuthn 认证器的 证明密钥 对仍然安全,尽管其证书已不能再被信任。记录了其认证器型号的证明公钥的WebAuthn 认证器 制造商可以从新的 中间 CA 或新的根 CA 为这些密钥签发新的证明 证书。如果根 CA 发生变化,WebAuthn 依赖方必须 相应更新其受信任根证书。
如果WebAuthn 认证器的证明证书的私 钥已泄露,则签发 CA 必须吊销该证书。WebAuthn 认证器制造商可能需要发布固件更新,并向已经 制造的WebAuthn 认证器注入新的证明私钥 和证书,如果泄露是由固件 缺陷导致。(发生这种情况的过程超出 本规范范围。)如果WebAuthn 认证器制造商没有此 能力,则依赖方可能无法再信任来自受影响WebAuthn 认证器的任何后续证明语句。
另请参阅依赖方的相关安全注意事项§ 13.5.5 被吊销的证明证书。
13.4. 客户端的安全注意事项
13.4.1. remoteClientDataJSON 扩展
remoteClientDataJSON 扩展使远程桌面 Web 客户端 能够代表远程依赖方代理 Web 身份验证 API请求。这从根本上 以下列方式改变了Web 身份验证 API的信任模型:
-
源替换:用户代理接受 由调用方远程桌面 Web 客户端提供的
origin, 而不是从当前执行上下文中推导它。 因此,授予此权限的任何用户代理都必须信任调用方 准确且诚实地提供远程依赖方的源。 -
RP ID 验证:RP ID 验证被委托给远程客户端,因为远程客户端 拥有验证源所需的全部上下文,可以考虑相关源和平台特定的应用部署模型。 因此,授予此权限的任何用户代理都必须信任远程客户端已经 针对所有源检查准确且诚实地验证了RP ID。
-
需要按源配置机制:由于此扩展的权限按 源设置, 用户代理必须只提供基于按源方式的配置机制, 通过用户代理策略(例如 UA 设置或企业策略)。
授予此扩展的用户 代理应该在远程桌面代理的 WebAuthn 操作正在进行时明确告知用户, 使用户理解 其认证器正在代表远程托管的应用程序使用。
13.5. 依赖方的安全注意事项
13.5.1. WebAuthn 依赖方的安全优势
本规范为WebAuthn 依赖方提供的主要优势包括:
-
可以使用广泛兼容、易于使用的多因素身份验证来保护用户和帐户。
-
依赖方 无需向其用户提供认证器硬件。相反,每个用户都可以 独立获取任何符合要求的认证器,并将同一个认证器用于任意数量的依赖方。 依赖方 可以选择性地 通过检查认证器返回的证明语句,对认证器的安全属性施加要求。
-
身份验证仪式可抵抗中间人攻击。 关于注册仪式,请参阅下面的§ 13.5.4 证明的局限性。
-
依赖方可以 自动支持多种用户验证方式——例如 PIN、生物特征和/或未来 方法——而只需很少或无需更改代码,并且可以让每个用户通过选择 认证器 来决定其偏好的方式。
-
依赖方 无需存储额外秘密即可获得上述优势。
如一致性一节所述,依赖方必须按照 § 7 WebAuthn 依赖方操作中的描述行事, 才能获得上述所有安全优势。但是,下面的§ 13.5.4 证明的局限性描述了一个明显稍有偏离的用例。
13.5.2. 嵌入式使用的可见性注意事项
在嵌入上下文中简单使用 WebAuthn,例如在
iframe
中,
如§ 5.10 在 iframe 元素中使用 Web 身份验证所述,
可能使用户容易受到UI 重绘攻击,也称为“点击劫持”。在这种攻击中,攻击者会在依赖
方预期的 UI 上覆盖自己的 UI,并试图欺骗用户对依赖方执行非预期操作。例如,
使用这些技术,攻击者可能能够欺骗用户购买商品、转账等。
尽管 WebAuthn 特定的 UI 通常由客户端平台处理,因此不易受到UI 重绘攻击,但对于
包含嵌入式 WebAuthn 内容的依赖方而言,确保其内容的 UI 对用户可见可能非常重要。一种新兴
做法是观察实验性Intersection Observer v2 的
isVisible 属性状态。例如,运行在嵌入上下文中的依赖方脚本,如果检测到 isVisble 被设置为
false,可以预先在弹出窗口中加载自身,从而绕过其内容被遮挡的情况。
13.5.3. 密码学挑战
作为密码学协议,Web 身份验证依赖随机化挑战
来避免重放攻击。因此,PublicKeyCredentialCreationOptions.challenge
和 PublicKeyCredentialRequestOptions.challenge
的值都必须由依赖方在其信任的环境中(例如服务器端)随机生成,并且
客户端响应中返回的 challenge
值必须与所生成的值相匹配。这应该以不依赖
客户端行为的方式完成,例如,依赖方应该临时存储挑战
直到操作完成。容忍不匹配将损害协议的安全性。
挑战的有效期应该类似于 WebAuthn 仪式超时的建议范围和 默认值的上限。
为了防止重放攻击,挑战必须包含足够的熵,使猜测它们不可行。因此挑战应该 至少为 16 字节长。
13.5.4. 证明的局限性
本节不具有规范性。
在注册新凭据时,如果存在证明 语句, 它可能允许WebAuthn 依赖方推导出有关各种认证器特性的保证。 例如,认证器型号,或其如何存储和保护凭据 私钥。 但是,需要注意的是,仅凭证明语句本身, 无法使依赖 方验证证明对象是由 用户意图使用的认证器生成,而不是由中间人攻击者生成。 例如,此类攻击者可以使用注入依赖方脚本的恶意代码。 因此,依赖方必须依赖其他方式,例如 TLS 和相关技术, 来保护证明对象免受中间人攻击。
假设注册仪式已安全完成,并且认证器保持 凭据私钥的机密性,则随后使用该公钥 凭据进行的身份验证仪式 可抵抗中间人攻击的篡改。
上述讨论适用于所有证明类型。在所有情况下,中间人攻击者都有可能替换 PublicKeyCredential
对象,包括证明语句和待注册的
凭据公
钥,随后还可篡改未来
限定作用域于同一依赖方且经过同一攻击者的身份验证断言。
这种攻击有可能被检测到;由于依赖方注册的是攻击者的凭据公钥而 不是用户的,因此攻击者必须篡改随后与该依赖方进行的所有身份验证仪式: 未受篡改的 仪式将失败,从而可能暴露该攻击。
除自证明和无证明以外的证明类型可以增加此类 攻击的难度,因为依赖方 可能能够向用户显示认证器信息,例如型号名称。因此, 攻击者可能需要使用 与用户认证器型号相同的真实认证器,否则用户可能会注意到依赖方报告的 认证器型号与用户预期不同。
注:上述所有中间人攻击变体 对攻击者而言,都比针对传统密码身份验证的中间人攻击更难实施。
13.5.5. 被吊销的证明证书
如果证明 证书验证由于中间证明 CA 证书被吊销而失败,并且依赖方的策略 要求在这些情况下拒绝注册/身份验证请求,则推荐依赖方还 注销(或标记为与“自证明”等效的信任级别)那些 在 CA 泄露日期之后,使用链到同一中间 CA 的证明证书注册的公钥凭据。因此推荐 依赖方 在注册期间记住中间证明 CA 证书,以便在 相关证书被吊销后执行注册时,注销相关公 钥凭据。
另请参阅认证器的相关安全注意事项§ 13.3.2 证明证书和证明证书 CA 泄露。
13.5.6. 凭据丢失和密钥可移动性
本规范未定义用于备份凭据私钥或在认证器之间共享它们的协议。 通常,预期凭据私钥永远不会离开创建它的认证器。因此,丢失 认证器通常意味着丢失 所有绑定到丢失认证器的凭据,如果用户仅向依赖 方注册了一个凭据, 这可能导致用户被锁定在帐户之外。Web 身份验证 API 并不备份或共享私钥,而是允许 为同一用户注册多个凭据。例如,用户可以 在经常使用的客户端 设备上注册平台 凭据,并注册一个或多个漫游凭据,以用作备份并与新的或很少使用的 客户端设备一起使用。
依赖方应该允许
并鼓励用户向同一用户帐户注册多个凭据。
依赖方应该利用
和
excludeCredentials
选项,以确保这些
不同的凭据绑定到不同的认证器。
user.id
13.5.7. 未受保护帐户检测
本节不具有规范性。
此安全注意事项适用于这样的依赖方:其支持将非空
allowCredentials
参数作为第一个身份验证步骤的身份验证仪式。
例如,使用服务器端凭据进行身份验证作为第一个身份验证步骤。
在这种情况下,allowCredentials
参数存在泄露以下信息的风险:
哪些用户帐户注册了
WebAuthn 凭据,哪些没有,
这可能成为帐户保护强度的信号。
例如,假设攻击者仅通过提供用户名就可以发起身份验证仪式,
并且依赖方
对某些用户帐户响应非空的 allowCredentials,
而对其他用户帐户响应失败或密码挑战。
攻击者随后可以推断,后一类用户帐户
很可能不需要 WebAuthn断言即可成功身份验证,
从而将攻击集中到这些可能更弱的帐户上。
此问题类似于§ 14.6.2 用户名 枚举 和§ 14.6.3 通过凭据 ID 泄露隐私中描述的问题,并可通过 类似方式缓解。
13.5.8. 代码注入攻击
任何在源上执行的恶意代码, 如果该源位于依赖方的公钥凭据的作用域内, 都有可能使 WebAuthn 可能提供的任何和所有安全保证失效。 WebAuthn 客户端仅 在安全上下文中暴露 WebAuthn API, 这缓解了最基本的攻击,但依赖方应该结合额外预防措施。
代码注入可能通过多种方式发生; 本节试图指出一些可能的情形并建议适当的缓解措施, 但并非详尽列表。
-
恶意代码可能由依赖方包含的第三方脚本注入, 无论是有意的,还是由于第三方中的安全漏洞。
-
根据凭据作用域规则,恶意代码可能托管在RP ID的子域上。 例如,托管在
usercontent.example.org上的用户提交代码 可以使用任何限定作用域于RP IDexample.org的凭据。 如果依赖方 在验证断言时允许子域origin, 恶意用户可能利用这一点发动中间人攻击, 以获取有效的身份验证断言并冒充攻击 受害者。因此,依赖 方默认不应该在验证断言时允许子域
origin。 如果依赖方 需要允许子域origin, 则依赖 方不得在其 源的任何允许子域上提供不受信任的代码, 这些源位于其公钥凭据的作用域内。
13.5.9. 验证凭据的源
在注册凭据时以及
验证断言时,
依赖方必须
验证客户端数据的 origin
成员。
依赖方不得
接受意外的 origin
值,
因为这样做可能允许恶意网站获取有效的凭据。
尽管 WebAuthn 凭据的作用域会阻止它们在
其注册时RP ID以外的域上使用,
但依赖方的源
验证提供了额外一层保护,
以防有缺陷的认证器未能强制执行凭据作用域。
另请参阅§ 13.5.8 代码注入攻击中有关潜在
恶意子域的讨论。
验证可以通过精确字符串匹配或依赖方所需的任何其他方法执行。 例如:
-
仅在
https://example.org提供服务的 Web 应用程序应该要求origin与https://example.org完全相等。 -
在少量域上提供服务的 Web 应用程序可以要求
origin与允许源列表中的某个元素完全相等, 例如列表["https://example.org", "https://login.example.org"]。 -
利用相关源请求的 Web 应用程序还可以 要求
origin与允许源列表中的某个元素完全相等, 例如列表["https://example.co.uk", "https://example.de", "https://myexamplerewards.com"]。 此列表通常会与RP ID的 well-known URI 中列出的源相匹配。请参阅§ 5.11 跨相关源使用 Web 身份验证。 -
在经常变化的大量域上提供服务的 Web 应用程序可以从结构上解析
origin, 并要求 URL scheme 为https, 且 authority 等于RP ID或其任意子域——例如example.org或example.org的任意子域)。注:有关允许RP ID任意子域的风险讨论,请参阅§ 13.5.8 代码注入攻击。
-
具有配套原生应用程序的 Web 应用程序可以允许
origin是原生应用程序的操作系统相关 标识符。例如,这样的依赖方可以要求origin与以下列表中的某个元素完全相等:["https://example.org", "example-os:appid:204ffa1a5af110ac483f131a1bef8a841a7adb0d8d135908bbd964ed05d2653b"]。
验证客户端数据的 topOrigin
成员时也适用类似注意事项。
当 topOrigin
存在时,依赖
方必须验证其值符合预期。
此验证可以通过精确字符串匹配或依赖方所需的任何其他方法执行。
例如:
-
希望在少量域上的跨源
iframe中嵌入的 Web 应用程序 可以要求topOrigin与允许源列表中的某个元素完全相等, 例如列表["https://example-partner1.org", "https://login.partner2-example.org"]。 -
希望在大量域上的跨源
iframe中嵌入的 Web 应用程序 可以允许topOrigin的任意值, 或使用动态过程 来确定给定的topOrigin值是否允许用于特定仪式。
14. 隐私注意事项
[FIDO-Privacy-Principles]中的隐私原则也适用于本规范。
本节按受众划分; 一般隐私注意事项是本节的直接子节, 而专门面向认证器、客户端和依赖方实现者的隐私注意事项 则分组到各自的小节中。
14.1. 防止去匿名化措施
本节不具有规范性。
Web 身份验证 API设计的许多方面都是出于隐私考虑。本 规范中考虑的主要问题是 保护用户的个人身份,即识别人类个体,或将 不同身份关联为属于同一个人。尽管Web 身份验证 API不 使用或提供任何 形式的全局身份,但会使用以下类型的潜在可关联标识符:
-
这些由WebAuthn 依赖方注册,随后由 用户用于证明持有相应的凭据私钥。在客户端与 认证器通信时,这些也对客户端可见。
-
用户的生物特征,例如指纹或面部识别数据[ISOBiometricVocabulary]。
-
用户认证器的型号,例如产品名称。
-
用户认证器的身份,例如序列号。
上述某些信息必然会与依赖方共享。以下各节描述为 防止恶意依赖 方利用这些信息发现用户个人身份而采取的措施。
14.2. 匿名、限定作用域且不可关联的公钥 凭据
本节不具有规范性。
尽管凭据 ID和凭据 公钥必然需要与WebAuthn 依赖方共享以实现强 身份验证,但它们被设计为尽可能少地具有识别性,并且不会在依赖方之间共享。
-
每个公钥凭据都严格限定作用域于特定依赖方,并且 客户端确保其存在不会 泄露给其他依赖方。因此,恶意依赖方不能要求客户端披露用户的其他 身份。
-
客户端还确保 在没有用户同意的情况下,不会向依赖方披露公钥凭据的存在。 这在§ 14.5.1 注册仪式 隐私和§ 14.5.2 身份验证仪式隐私中有进一步详述。 因此,恶意依赖方 不能在用户不知情的情况下识别用户,即使用户已经注册了公钥凭据且该凭据可用。
-
认证器确保 不同公钥凭据的凭据 ID和凭据公钥 无法被关联为属于同一用户。因此,一对恶意依赖方不能在它们的 系统之间关联用户,除非有附加信息,例如故意重复使用的用户名或电子邮件地址。
-
认证器确保 其证明证书不会独特到足以 识别单个认证器 或一小组认证器。这在§ 14.4.1 证明隐私中有进一步详述。因此,一对恶意 依赖方不能 通过跟踪单个认证器来关联其系统之间的用户。
此外,客户端可发现公钥 凭据源可以选择性地包含由依赖方指定的用户句柄。随后该凭据可用于 同时识别和 验证用户身份。 这意味着注重隐私的依赖方可以允许创建不使用传统用户名的用户帐户, 从而进一步提高依赖方之间的不可关联性。
14.3. 认证器本地生物特征识别
生物特征 认证器在认证器内部执行生物特征识别——不过对于平台 认证器,根据实现,生物特征数据也可能对客户端可见。生物特征数据不会 暴露给WebAuthn 依赖方;它仅在本地用于执行用户验证, 以授权创建和 注册公钥凭据,或使用它进行身份验证。因此,恶意依赖方无法通过 生物特征数据发现用户的个人身份,并且依赖方处的安全漏洞也无法暴露生物特征数据供 攻击者用于伪造对其他依赖方的登录。
当依赖 方要求生物特征识别时,这会由生物特征 认证器在本地执行, 通过执行用户 验证,然后通过在已签名断言响应中设置UV标志来表示结果, 而不是向依赖方披露生物特征数据本身。
14.4. 认证器的隐私注意事项
14.4.1. 证明隐私
证明证书和证明密钥对可用于跟踪用户 或将同一用户的各种在线身份关联在一起。 这可以通过多种方式缓解,包括:
-
WebAuthn 认证器制造商可以选择分批出货 认证器, 其中一批中的认证器 共享相同的证明证书(称为基本 证明或批量证明)。 这会使用户匿名化,但代价是如果其私钥泄露, 就无法吊销特定证明证书。 此时认证器 制造商应该确保此类批次足够大,以提供有意义的 匿名化, 同时也应尽量减小批次大小,以在证明私钥泄露时 限制受影响用户的数量。
[UAFProtocol]要求至少 100,000 个认证器 设备共享相同的证明证书,以形成 足够大的组。这可以作为适当批次大小的指导。
-
WebAuthn 认证器可以具有动态 为每个凭据生成不同证明密钥对(并请求相关 证书)的能力,如匿名化 CA方法中所述。例如, 一个认证器可以随附一个 主证明私钥(及证书), 并与云端运行的匿名化 CA结合, 动态生成每个凭据的证明密钥对和证明证书。
注:在本 规范之外的多个地方,术语“Privacy CA”用于指代这里所称的 匿名化 CA。由于可信计算组织 (TCG) 也曾使用术语“Privacy CA”来指代 TCG 现在称为证明 CA (ACA) 的概念[TCG-CMCProfile-AIKCertEnroll], 因此我们在此使用术语匿名化 CA,以尝试减少 本规范特定上下文中的混淆。
14.4.2. 存储在认证器中的个人身份信息的隐私
认证器可以向客户端提供本规范定义之外的附加信息,例如, 使客户端能够提供丰富的 UI, 供用户选择在身份验证仪式中使用哪个凭据。如果 认证器选择这样做, 除非已成功执行用户验证,否则它不应该暴露个人身份信息。 如果认证器支持同时注册多个用户的用户验证,则 认证器不应该 暴露除当前已验证用户之外其他用户的个人身份信息。因此, 不具备用户 验证能力的认证器不应该存储个人身份信息。
就本讨论而言,作为
PublicKeyCredentialUserEntity
的 id
成员传送的用户句柄
不被视为个人身份信息;请参阅§ 14.6.1 用户
句柄内容。
这些建议旨在防止物理访问认证器的对手提取有关 认证器已注册 用户的个人身份信息。
14.5. 客户端的隐私注意事项
14.5.1. 注册仪式隐私
为了保护用户免于在没有同意的情况下被识别,
[[Create]](origin, options, sameOriginWithAncestors)
方法的实现需要注意不要泄露可能使恶意WebAuthn 依赖方能够区分以下情况的信息,
其中“被排除”意味着依赖方在 excludeCredentials
中列出的凭据中至少有一个绑定到
认证器:
如果上述情况可区分,就会泄露信息,使恶意依赖方能够通过探测
哪些凭据可用来识别用户。例如,如果客户端在被排除的认证器一变得可用时就返回
失败响应,这就是一种信息泄露。在这种情况下——尤其是当被排除的
认证器是平台
认证器时——依赖方可以检测到仪式在
用户实际上有可能手动取消之前就已被取消,从而推断
excludeCredentials
参数中列出的凭据至少有一个
对用户可用。
不过,如果用户在返回可区分错误之前已经同意创建新凭据,则上述情况并不是问题,因为在这种情况下 用户已经确认愿意共享将被 泄露的信息。
14.5.2. 身份验证仪式隐私
为了保护用户免于在没有同意的情况下被识别,
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法的实现需要注意不要
泄露可能使恶意WebAuthn
依赖方能够区分以下情况的信息,
其中“已命名”意味着该凭据由依赖方列在 allowCredentials
中:
如果上述情况可区分,就会泄露信息,使恶意依赖方能够通过探测
哪些凭据可用来识别用户。
例如,如果客户端仅在发现认证器包含已命名凭据之后,
才显示用于取消或继续身份验证仪式的说明和控件,
就可能发生一种此类信息泄露。
在这种情况下,如果依赖方知道这种客户端行为,
依赖方就可以
检测到仪式是由用户取消而非超时取消,从而推断
allowCredentials
参数中列出的凭据至少有
一个对用户可用。
可以通过显示允许用户随时取消身份验证仪式的控件来解决此问题, 无论是否有任何已命名凭据可用。
14.5.3. 操作系统帐户之间的隐私
如果多用户操作系统的客户端设备中包含平台 认证器,则平台 认证器和客户端 设备应该协同工作,以确保任何平台凭据的存在 仅向创建该平台凭据的操作系统用户披露。
14.5.4. 披露客户端能力
getClientCapabilities
方法帮助WebAuthn
依赖方构建很可能在客户端和/或用户处成功的注册和
身份验证体验。
WebAuthn 客户端 是否支持某项能力可能带来指纹识别风险。为降低此风险,客户端 应该优先从返回的记录中省略某个键,而不是返回 false 值。省略 该键(如§ 5.1.7 客户端能力的可用性 - PublicKeyCredential 的 getClientCapabilities() 方法中所述)比 显式确认某个功能不受支持提供更小的指纹识别面。客户端实现也可以根据客户端策略和/或用户同意限制能力 披露。
14.5.5. WebAuthn 凭据的跨源使用
当 WebAuthn注册或身份验证仪式 在跨源上下文中执行时, 例如使用相关源请求 或在跨源 iframe中调用时, 用户可能会对是谁正在访问或请求创建公钥 凭据产生混淆。
对于调用源与RP ID不同的场景, 例如相关源请求, WebAuthn 客户端和客户端平台应该 确保 凭据和认证器选择界面 通过同时显示以下内容为用户提供清晰上下文:
例如,给定RP ID
exampleA.com,调用源为 https://otherExampleB.com,
WebAuthn 客户端和/或
客户端平台可以
向用户显示:
“使用你为 exampleA.com 准备的通行密钥登录 otherExampleB.com?”
对于在iframe中调用 WebAuthn 的场景, WebAuthn 客户端 和/或客户端平台 还应该确保 凭据和认证器选择界面向用户提供警告 以及有关嵌入 iframe 的页面的顶级源的附加上下文, 因为这可能与调用者的源不同。成功的仪式会允许 顶级源和调用源在各自站点之间关联用户身份。
例如,给定RP ID
examplepay.com,调用源为 https://examplepay.com
且顶级源为
https://example.com,
WebAuthn 客户端和/或
客户端平台可以
向用户显示:
“使用你的通行密钥登录 examplepay.com?Example.com 将知道你正在登录 examplepay.com。”
14.6. 依赖方的隐私注意事项
14.6.1. 用户句柄内容
由于用户句柄在§ 14.4.2 存储在认证器中的个人 身份信息的隐私中不被视为个人身份信息, 并且由于认证器可以 在不先执行用户 验证的情况下披露用户句柄, 依赖方不得 在用户 句柄中包含个人身份信息,例如电子邮件 地址或用户名。这也包括个人身份信息的哈希值,除非哈希 函数使用加盐方式,并采用仅依赖方私有的盐值, 因为哈希并不能阻止对可猜测输入 值的探测。推荐让用户句柄为 64 个随机字节,并将此值存储在用户帐户中。
14.6.2. 用户名枚举
在发起注册或身份验证仪式时, WebAuthn 依赖方可能存在泄露其已注册用户敏感 信息的风险。例如,如果依赖方使用电子邮件地址作为用户名,而攻击者尝试 为 "alex.mueller@example.com" 发起身份验证 仪式, 并且依赖方 返回失败,但随后 为 "j.doe@example.com" 成功发起身份验证仪式,则攻击者可以推断 "j.doe@example.com" 已注册,而 "alex.mueller@example.com" 未注册。因此,依赖方泄露了可能敏感的信息: "j.doe@example.com" 在此依赖 方拥有用户帐户。
以下是依赖方可以实施以缓解或 防止此类攻击造成信息 泄露的非规范性、非详尽措施列表:
-
对于注册仪式:
-
对于身份验证仪式:
-
如果在发起身份验证仪式时,不存在与所提供用户名匹配的用户帐户, 则使用填充了看似合理的虚构值的语法有效
PublicKeyCredentialRequestOptions对象调用navigator.credentials.get(), 从而继续 仪式。这种方法也可用于缓解通过
allowCredentials发生的信息泄露; 请参阅§ 13.5.7 未受保护帐户检测 和§ 14.6.3 通过凭据 ID 泄露隐私。注:用户名可以通过 各种特定于依赖 方的方式“提供”:登录表单、会话 cookie 等。
注:如果返回的虚构值 与实际值明显不同,聪明的攻击者可能能够辨别它们, 从而能够测试实际帐户是否存在。明显不同 值的示例包括:对于所有用户名输入这些值 始终相同,或者对相同用户名输入重复尝试时这些值不同。例如,
allowCredentials成员因此可以填充由用户名 确定性派生的伪随机值。 -
验证来自认证器的
AuthenticatorAssertionResponse响应时,使 验证因签名无效而失败与因为没有注册此用户或凭据而失败无法区分。 -
执行多步骤身份验证仪式,例如先 提供用户名和密码或会话 cookie, 然后再发起 WebAuthn仪式作为后续步骤。 这会将用户名枚举问题从 WebAuthn 步骤 移到前面的身份验证步骤,在那里可能更容易解决。
-
14.6.3. 通过凭据 ID 泄露隐私
本节不具有规范性。
此隐私注意事项适用于这样的依赖方:其支持将非空
allowCredentials
参数作为第一个身份验证步骤的身份验证仪式。
例如,将使用服务器端凭据进行的身份验证作为第一个身份验证步骤。
在这种情况下,allowCredentials
参数存在泄露个人身份信息的风险,
因为它会向未经身份验证的调用者暴露用户的凭据 ID。
凭据 ID被设计为
不能在依赖方之间关联,
但凭据
ID的长度可能暗示创建它的认证器类型。
用户很可能会在多个依赖方使用相同的用户名和同一组认证器,
因此 allowCredentials
中凭据
ID的数量及其长度
可能充当用于去匿名化用户的全局关联句柄。
知道用户的凭据
ID还使得仅在短暂物理接触用户的某个认证器的情况下
就能确认对用户身份的猜测。
为了防止此类信息泄露,依赖方例如可以:
-
先执行单独的身份验证步骤, 例如用户名和密码身份验证或会话 cookie 身份验证, 然后再发起 WebAuthn身份验证仪式并暴露用户的凭据 ID。
-
使用客户端可发现凭据, 从而不需要
allowCredentials参数。
如果上述预防措施不可用,
即仅给定用户名就需要暴露 allowCredentials,
依赖方可以
使用与§ 14.6.2 用户名枚举中讨论的相同方法,
返回虚构凭据 ID来缓解隐私泄露。
当发出信号表示某个凭据 id无法识别时,
WebAuthn
依赖方应该使用
signalUnknownCredential(options)
方法,而不是
signalAllAcceptedCredentials(options)
方法,以避免
向未经身份验证的调用者暴露凭据 ID。
15. 无障碍注意事项
具备用户 验证能力的认证器,无论是漫游认证器还是平台认证器,都应该为用户提供多于一种用户验证 方法。例如,同时提供指纹感应和 PIN 输入。如果所选用户 验证方式因某种原因无法工作,这允许回退到其他用户 验证方式。请注意,对于漫游 认证器,认证器和平台可以协同提供 PIN 输入等用户验证 方法[FIDO-CTAP]。
依赖方在注册时应该 为用户提供正确完成未来授权手势的辅助方式。这可以包括为 认证器命名、选择与设备关联的图片,或输入自由文本说明 (例如作为给自己的提醒)。
15.1. 仪式超时的建议范围
依赖计时的仪式,例如注册
仪式(参见 timeout)
或身份验证仪式(参见 timeout),
应遵循[WCAG21]的指南 2.2 足够的时间。如果客户端平台
确定依赖
方提供的超时值未适当遵循后者[WCAG21]指南,
则客户端平台
可以相应调整超时值。
WebAuthn 仪式超时的建议范围和 默认值如下:
-
建议范围:300000 毫秒到 600000 毫秒。
-
建议默认值:300000 毫秒(5 分钟)。
16. 测试向量
本节不具有规范性。
本节列出可用于验证实现的示例值。
示例以伪代码形式成对给出,其中注册 和身份验证仪式使用相同凭据完成, 字节字符串字面量和注释采用 CDDL [RFC8610] 表示法。 示例并不详尽,也不包括WebAuthn 扩展。
示例按从输入到输出的流程组织,其中包括一些中间值。
在注册示例中,依赖方定义 challenge
输入,
客户端生成 clientDataJSON
输出,
认证器
生成 attestationObject
输出。
在身份验证示例中,依赖方定义 challenge
输入,
客户端生成 clientDataJSON
输出,
认证器
生成
authenticatorData
和 signature
输出。
不包括其他在密码学上无关的输入和输出。
认证器实现者
可以检查其是否生成结构类似的
attestationObject、
authenticatorData
和 signature
输出。
客户端实现者可以检查其是否
生成结构类似的 clientDataJSON
输出。
依赖方实现者
可以检查在给定相同 challenge
输入时,是否能成功验证注册输出,
并检查在给定相同 challenge
输入
以及关联注册示例中的凭据公钥和凭据 ID时,是否能成功验证身份验证输出。
所有示例都使用RP ID
example.org、origin
https://example.org
以及在适用时的 topOrigin
https://example.com。
除非另有说明,示例包括无证明。
请注意,clientDataJSON、attestationObject 和
证明证书等复合对象
可能包含伪代码中未明确提及的附加、通常为常量的数据。
所有随机值均使用 HKDF-SHA-256 [RFC5869]
从 CDDL 中表示为 'WebAuthn test vectors' 的基础输入密钥材料确定性生成,
或等价地表示为 h'576562417574686e207465737420766563746f7273'。
ECDSA 签名使用确定性 nonce [RFC6979]。
示例中的 RSA 密钥由最小的两个 Mersenne 素数 2p - 1 构造,其中
p ≥ 1024。
请注意:
注:实现 CTAP2 [FIDO-CTAP] 的认证器返回证明 对象时 使用的键与本规范定义的键不同。 这些示例反映WebAuthn 依赖方所预期的证明对象格式, 因此从 CTAP2 发出的证明 对象需要转换其键, 才能在位级上与这些示例完全相同。
16.1. 证明信任根证书
所有包含证明的示例都使用下面以
attestation_ca_cert 给出的证明信任根证书,
采用 X.509 DER 编码[RFC5280]:
attestation_ca_key = h'7809337f05740a96a78eedf9e9280499dcc8f2aa129616049ec1dccfe103eb2a' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='Attestation CA', L=32) attestation_ca_serial_number = h'ed7f905d8bd0b414d1784913170a90b6' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='Attestation CA', L=16) attestation_ca_cert = h'30820207308201ada003020102021100ed7f905d8bd0b414d1784913170a90b6300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a3062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d030107034200043269300e5ff7b699015f70cf80a8763bf705bc2e2af0c1b39cff718b7c35880ca30f319078d91b03389a006fdfc8a1dcd84edfa07d30aa13474a248a0dab5baaa3423040300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e0416041445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d04030203480030450220483063b6bb08dcc83da33a02c11d2f42203176893554d138c614a36908724cc8022100f5ef2c912d4500b3e2f5b591d0622491e9f220dfd1f9734ec484bb7e90887663'
16.2. 无证明的 ES256 凭据
注册:
challenge = h'00c30fb78531c464d2b6771dab8d7b603c01162f2fa486bea70f283ae556e130' ; 派生方式: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) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON extraData_random = h'06441e0e375c4c1ad70620302532c4e5' = b64'BkQeDjdcTBrXBiAwJTLE5Q' ; 派生方式: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'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22414d4d507434557878475453746e63647134313759447742466938767049612d7077386f4f755657345441222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20426b5165446a646354427258426941774a544c453551227d' 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) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON ; 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.3. 带自证明的 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) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON extraData_random = h'53d8535ef284d944643276ffd3160756' = b64'U9hTXvKE2URkMnb_0xYHVg' ; 派生方式: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'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2265476e4374334c55745936366b336a506a796e6962506b31716e666644616966715a774c33417032392d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205539685458764b453255526b4d6e625f307859485667227d' attestationObject = h'a363666d74667061636b65646761747453746d74a263616c672663736967584630440220067a20754ab925005dbf378097c92120031581c73228d1fb4f5b881bcd7da98302207fc7b147558c7c0eba3af18bd9d121fa3d3a26d17fe3f220272178f473b6006d68617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000df850e09db6afbdfab51697791506cfc0020455ef34e2043a87db3d4afeb39bbcb6cc32df9347c789a865ecdca129cbef58ca5010203262001215820eb151c8176b225cc651559fecf07af450fd85802046656b34c18f6cf193843c5225820927b8aa427a2be1b8834d233a2d34f61f13bfd44119c325d5896e183fee484f2'
身份验证:
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) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON extraData_random = h'8136f9debcfa121496a265c6ce2982d5' = b64'gTb53rz6EhSWomXGzimC1Q' ; 派生方式: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'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a225248696843784e534e493352594d45314f7731476d3132786e726b634a5f6666707637546e2d4a71386773222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206754623533727a36456853576f6d58477a696d433151227d' signature = h'304402203310b9431903c401f1be2bdc8d23a4007682dbbddcf846994947b7f465daf84002204e94dd00047b316061b3b99772b7efd95994a83ef584b3b6b825ea3550251b66'
16.4. clientDataJSON 中 "crossOrigin": true 的 ES256 凭据
注册:
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 时,extraData 才会添加到 clientDataJSON extraData_random = h'cd9aae12d0d1f435aaa56e6d0564c5ba' = b64'zZquEtDR9DWqpW5tBWTFug' ; 派生方式: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 时才设置 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'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a224f2d57717a514e5463554a484930437257576e7951504859647862694332674872434d475666704c4f306b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a207a5a7175457444523944577170573574425754467567227d' 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 时,extraData 才会添加到 clientDataJSON extraData_random = h'f76a5c4d50f401bcbeab876d9a3e9e7e' = b64'92pcTVD0Aby-q4dtmj6efg' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256.crossOrigin', L=16) ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但只有在注册期间设置了 BE 时才设置 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'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a226832716c463771445f65356c5f505f62796b7945377135645650674547685f49584a6b655737736e4d5463222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2039327063545644304162792d713464746d6a36656667227d' signature = h'3046022100eb12fcf23b12764c0f122e22371fab92e283879fd798f38ee1841c951b6e40e7022100c76237ff9db77b3c56f30837cda6a09acfa2e915544e609c0733b1184036d1cf'
16.5. clientDataJSON 中包含 "topOrigin" 的 ES256 凭据
注册:
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 时,extraData 才会添加到 clientDataJSON 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 时才设置 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 时,extraData 才会添加到 clientDataJSON extraData_random = h'52216824c5514070c0156162e2fc54a5' = b64'UiFoJMVRQHDAFWFi4vxUpQ' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.topOrigin', L=16) ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但只有在注册期间设置了 BE 时才设置 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'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22315570636a4b53324b6f34377379486a7372787a68572d466f51465132796b3572426c584f6573656f4759222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22746f704f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205569466f4a4d56525148444146574669347678557051227d' signature = h'3045022100b5a70c81780d5fcc9a4f2ae9caae99058f8accaf58b91fb59329646c28ac6ffc022012e101c165db3c8e9957f0c54dd6ca9b56bc3bd2f280bd2faa6c1d02c6e5c171'
16.6. 具有超长凭据 ID 的 ES256 凭据
注册:
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 时,extraData 才会添加到 clientDataJSON 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 时才设置 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 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但只有在注册期间设置了 BE 时才设置 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.7. 带 ES256 凭据的打包证明
注册:
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 时,extraData 才会添加到 clientDataJSON extraData_random = h'f5af1b3588ca0a05ab05753e7c29756a' = b64'9a8bNYjKCgWrBXU-fCl1ag' ; 派生方式: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 决定认证器数据标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS 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'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a227752684b58393334424634543345663153324831706c61325a725751475046746877365356756d56494249222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20396138624e596a4b436757724258552d66436c316167227d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c6726637369675847304502203f19ec4b229f46ab8c45eff29b904ff10c0390dc40bf1216f04a78f4ceba3425022100fe7041a32759aff05a0f9f26c70a999c7a284451ba89234a1d3483c25e21925b637835638159022530820221308201c8a00302010202110088c220f83c8ef1feafe94deae45faad0300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004a91ba4389409dd38a428141940ca8feb1ac0d7b4350558104a3777a49322f3798440f378b3398ab2d3bb7bf91322c92eb23556f59ad0a836fec4c7663b0e4dc3a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414a589ba72d060842ab11f74fb246bdedab16f9b9b301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d040302034700304402201726b9d85ecd8a5ed51163722ca3a20886fd9b242a0aa0453d442116075defd502207ef471e530ac87961a88a7f0d0c17b091ffc6b9238d30f79f635b417be5910e768617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d00000000876ca4f52071c3e9b25509ef2cdf7ed60020c9a6f5b3462d02873fea0c56862234f99f081728084e511bb7760201a89054a5a50102032620012158201cf27f25da591208a4239c2e324f104f585525479a29edeedd830f48e77aeae522582059e4b7da6c0106e206ce390c93ab98a15a5ec3887e57f0cc2bece803b920c423'
身份验证:
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 时,extraData 才会添加到 clientDataJSON extraData_random = h'019330c8cc486c3f3eba0b85369eabf1' = b64'AZMwyMxIbD8-uguFNp6r8Q' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.ES256', L=16) ; auth_data_UV_BS 设置认证器数据标志中的 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'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273524276704770587676463446524841565833496d4b4130453958773858306b526a44426c4d6668726255222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20415a4d77794d78496244382d756775464e7036723851227d' signature = h'30450220694969d3ee928de6f02ef23a9c644d7d779916451734a94b432542f498a1ebe90221008b0819c824218a97152cd099c55bfb1477b29d900a49a64018314f9bfccda163'
16.8. 带 ES384 凭据的打包证明
注册:
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 时,extraData 才会添加到 clientDataJSON 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 决定认证器数据标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS 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 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 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.9. 带 ES512 凭据的打包证明
注册:
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 时,extraData 才会添加到 clientDataJSON extraData_random = h'a37a958ce2f6b535a6e06c64cc8fd082' = b64'o3qVjOL2tTWm4GxkzI_Qgg' ; 派生方式: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 决定认证器数据标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS 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'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22547549677a5a4b7766684646484c544341635631573968356849354a4b707353313545317869646b33435f536a713149434d722d577448656a366e676a55714f3676366b33374d7a683373437646415f5231303744424f5570326737717654795233677039376a5064516c496d465659644977484d47673562385f63305f4a46767941343572733431314d6e614b72524f2d6a424750636e636935304a684f5151656e4b796c4134684d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206f3371566a4f4c327454576d3447786b7a495f516767227d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022100ce158f6c04aa5c14c0dd3e1103cf93664896fb5c337a66dbd7dba31546ff0d41022071cbcd0d3b8e218a6d05374e0ef8031329d25059002ac1603d02d5fd8a0a29cb637835638159022730820223308201c8a0030201020211008a128b7ebe52b993835779e6d9b81355300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004940b68885291536e2f7c60c05acfb252e7eebcf4304425dd93ab7b1962f20492bf18dc0f12862599e81fb764ac92151f9a78fcbb35d7a26c8c52949b18133c06a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604143ffad863abcd3dc5717b8a252189f41af97e7f31301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100832c8b64c4f0188bd32e1bec63e13301cdc03165d3ef840d1f3dabb9a5719f83022100add57a9d5bedec98f29222dfc97ea795d055ee13a02a153d02be9ce00aedeb9168617574684461746158e9bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d0000000039d8ce6a3cf61025775083a738e5c2540020d17d5af7e3f37c56622a67c8462c9e1c6336dfccb8b61d359dc47378dba58ce4a5010203382320032158420083240a2c3ad21a3dc0a6daa3d8bc05a46d7cd9825ba010ae2a22686c2d6d663d7d5f678987fb1e767542e63dc197ae915e25f8ee284651af29066910a2cc083f50225842017337df47ab5cce5d716ef8caffa97a3012689b1f326ea6c43a1ba9596c72f71f0122390143552b42be772b4c35ffb961220c743b486a601ea4cb6d5412f5b078d3'
身份验证:
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 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 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.10. 带 RS256 凭据的打包证明
注册:
challenge = h'bea8f0770009bd57f2c0df6fea9f743a27e4b61bbe923c862c7aad7a9fc8e4a6' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.RS256', L=32) ; 最小的两个 Mersenne 素数 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 时,extraData 才会添加到 clientDataJSON 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 决定认证器数据标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS 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 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 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.11. 带 Ed25519 凭据的打包证明
注册:
challenge = h'a8abf9dabdc6b0df63466b39bda9e8a34a34e185337a59f1c579990676d3b3bd' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.EdDSA', L=32) private_key = h'971f38c0f73aaf0c5a614eb5e26430ae1ea0ed13e4f425d96e9662349340b0b3' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.EdDSA', L=32) client_data_gen_flags = h'bd' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.EdDSA', L=1) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON extraData_random = h'07f0d3e60ed90fffbd3932d85f922f11' = b64'B_DT5g7ZD_-9OTLYX5IvEQ' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.EdDSA', L=16) aaguid = h'd5aa33581e8ca478e20fe713f5d32ff2' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.EdDSA', L=16) credential_id = h'ce9f840ed96599580cd140fbc7bb3230633f50f61041aff73308ae71caa8a2bd' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.EdDSA', L=32) ; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS auth_data_UV_BE_BS = h'32' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.EdDSA', L=1) attestation_private_key = h'fbe7f950684f23afd045072a8b287ad29528707c662672850ac69733ffe0db85' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.EdDSA', L=32) attestation_cert_serial_number = h'b2cfc9ea33c8643b0e1a760463eaf164' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.EdDSA', L=16) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22714b763532723347734e396a526d733576616e6f6f306f303459557a656c6e7878586d5a426e6254733730222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20425f44543567375a445f2d394f544c59583549764551227d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758483046022100d83f60bd80269537583218858aefb03ac57d45fa06e42feaae332d187f62da9f022100a02bd3cb6f7e1d283c93bad1f3f4b5a4c0494463da7fdbf256949116754d1f17637835638159022730820223308201c8a003020102021100b2cfc9ea33c8643b0e1a760463eaf164300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004dd2b7a564b73b8c0b81c4c62e521925c4d1198ec9f583dbf1eebe364b65cd9c29a9bdf346aaa81fb6b9507e5249a52fdaf8e39e26b0b7dc45992a7e233b70f70a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604140ae27546bc7eccb1b4b597bd354f0c0b1f1f8f8e301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100a0d434ecb5fc3bfd7da5f41904517ad2836249f561bd834ba7a438a8ab7a4ce8022100fac845bb7a02513b58e9f319654dbe49b0f02b95835bac568c71f8a18cdde9ab6861757468446174615881bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54100000000d5aa33581e8ca478e20fe713f5d32ff20020ce9f840ed96599580cd140fbc7bb3230633f50f61041aff73308ae71caa8a2bda401010327200621582044e06ddd331c36a8dc667bab52bcae63486c916aa5e339e6acebaa84934bf832'
身份验证:
challenge = h'895957e01c633a698348a2d8a31a54b7db27e8c1c43b2080d79ae2190267bfd2' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.EdDSA', L=32) client_data_gen_flags = h'8c' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.EdDSA', L=1) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但只有在注册期间设置了 BE 时才设置 BS auth_data_UV_BS = h'ab' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.EdDSA', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50100000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2269566c583442786a4f6d6d44534b4c596f7870557439736e364d48454f7943413135726947514a6e763949222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'f5c59c7e46c34f6f8cc197101ddf9934fa2595f68eb1913a637e8419eb9ba4cfdfc48f85393bc0d40b011f0d6fecb097d6607525713223a0dc0d453993dae00b'
16.12. 带 Ed448 凭据的打包证明
注册:
challenge = h'2578d0801b5a005b5451e540121788cb01949e187b91db13f58755403efbf337' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.Ed448', L=32) private_key = h'ed479eecf63bd89e3898434798bb3c417bfc8284f6f011958bc0e78edbf6a2a640c0e358b1b1452a1f3782c400dabb4134192dee3031869a45' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.Ed448', L=57) client_data_gen_flags = h'e3' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.Ed448', L=1) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON extraData_random = h'050a80de27875521cc4c3316c06da42b' = b64'BQqA3ieHVSHMTDMWwG2kKw' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.Ed448', L=16) aaguid = h'41c913aeda925fe02273322e34c2ae67' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.Ed448', L=16) credential_id = h'224fcde324e6b075ede55098a24b9ddce5f5a7c71d23703efd528a38f8a5f33c' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.Ed448', L=32) ; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS auth_data_UV_BE_BS = h'3b' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.Ed448', L=1) attestation_private_key = h'd90faf5cc3f7853456b09124dd870250347f9c9ff66dba363aecd9194c665715' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.Ed448', L=32) attestation_cert_serial_number = h'cff4228697d6e5ac47480b2390677f05' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.Ed448', L=16) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a224a586a5167427461414674555565564145686549797747556e6868376b6473543959645651443737387a63222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2042517141336965485653484d54444d577747326b4b77227d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022100c5430b6b53f6b8fd1e5fa46ae7ebb8f9e9ae0d10ebc748e876e2d979b39b1382022008c5cda8af174f2d3c050d5d14eec0721031364cb12924a06633d4924c6bcad3637835638159022730820223308201c8a003020102021100cff4228697d6e5ac47480b2390677f05300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004b85aaf790c824037cfe9fc56ab8d7ce6fbfaff2e3fe7c8d745734c3c6e3c6ce880d505ccdb1e2c3738680e6f49f475e4d8d0b6c29060e6e0d7a6392fb69094cea360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414fa8f81c2dcc0e194ae5034c7e79dcf6d9d8593e2301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100e761f54215ad92f27c2c14b9eea3e39e8c22429e833ecba5be918987aa72e0e6022100d5a714df479c238586b7d9e6684ea84991087038b0fef6a29b57b66b74df05fd686175746844617461589bbfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b5590000000041c913aeda925fe02273322e34c2ae670020224fcde324e6b075ede55098a24b9ddce5f5a7c71d23703efd528a38f8a5f33ca4010103383420072158398051ef4f94670b5abf17da2e9558ba6eba94eb8704363915b4d666de287ad329de9f1f075211aba602dc6e7a5e52b15a8ee1c984a9f8887380'
身份验证:
challenge = h'1a942f401d8d8e36fe888c35c22b718217802fc6685bf139c47b311408128693' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.Ed448', L=32) client_data_gen_flags = h'2d' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.Ed448', L=1) ; 当且仅当 client_data_gen_flags 的 0x01 位为 1 时,extraData 才会添加到 clientDataJSON extraData_random = h'5ca1e381b5e009e01760db2eb632316f' = b64'XKHjgbXgCeAXYNsutjIxbw' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.Ed448', L=16) ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但只有在注册期间设置了 BE 时才设置 BS auth_data_UV_BS = h'fc' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0c', info='packed.Ed448', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51d00000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22477051765142324e6a6a622d6949773177697478676865414c385a6f575f4535784873784641675368704d222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20584b486a6762586743654158594e7375746a49786277227d' signature = h'071db921430e13ca1a607eedb96cbd30fd63946a06e731217cad6fd82ba3b930d482308a2c101752a2518cff70918d4a20f29bd2eda4f45a80bba6c4ad85b10fb721b1849725b7dbef315d5fb101c6dab890b06d94a8b52a74b5848f68e6152af24867b7555d2b22b8955cbff5c87de73b00'
16.13. 带 ES256 凭据的 TPM 证明
注册:
challenge = h'cfc82cdf1ceee876120aa88f0364f0910193460cfb97a317b2fe090694f9a299' ; 派生方式: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 时,extraData 才会添加到 clientDataJSON 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 决定认证器数据标志中的 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 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 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.14. 带 ES256 凭据的 Android 密钥证明
注册:
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 时,extraData 才会添加到 clientDataJSON extraData_random = h'555d5c42e476a8b33f6a63dfa07ccbd2' = b64'VV1cQuR2qLM_amPfoHzL0g' ; 派生方式: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 决定认证器数据标志中的 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'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2250654877747a5a647a4e345f384d76795869625f7037725f682d385162494438686c334541746d57414641222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205656316351755232714c4d5f616d50666f487a4c3067227d' attestationObject = h'a363666d746b616e64726f69642d6b65796761747453746d74a363616c67266373696758483046022100e95512982aa3f216cff2e87c8ec57057b8529f674eaabeccaa27fd03d8779f19022100afb6bf459da4a826f00d01fc6b60712ff31dc4eb331619c8f874bb17e4314e94637835638159027c308202783082021ea00302010202101ff91f76b63f44812f998b250b0286bf300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000499169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accfdd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6ba381b63081b3300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604141ac81e50641e8d1339ab9f7eb25f0cd5aac054b0301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e3053060a2b06010401d679020111044530430202012c0a01000201000a01000420b435028d7b6a8f83bb461d41c19b053a9d3cdb30351a4f374cd4cde8dbefb60604003000300ea1053103020102bf853e03020100300a06082a8648ce3d040302034800304502201354f9149996f6e1830852da629b86d37c10da0ffe17471c67d48765ed83f63b02210086db5746944cecdfce071d9e041072ceac3d1c504382f205676e9a1f02d7632568617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000ade9705e1ce7085b899a540d02199bf800200a4729519788b6ed8a2d772b494e186244d8c798c052960dbc8c10c915176795a501020326200121582099169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accf225820dd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6b'
身份验证:
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 时,extraData 才会添加到 clientDataJSON extraData_random = h'ab127107eff182bc3230beb5f1dad29c' = b64'qxJxB-_xgrwyML618drSnA' ; 派生方式:HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='android-key.ES256', L=16) ; auth_data_UV_BS 设置认证器数据标志中的 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'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22354f344679703238375851525a55447954746d74786971756851645742534b45545f702d36685433723459222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2071784a78422d5f78677277794d4c3631386472536e41227d' signature = h'3045022100a2b5e37da43ceb63566f6e2817c6cbef261073d0cadfd213ff6229bd33ddea6c02203d77eb3202fc92b9b5bb843ef082c7766f8c7f23194c92708ff2f3d1de765a8f'
16.15. 带 ES256 凭据的 Apple 匿名证明
注册:
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 时,extraData 才会添加到 clientDataJSON extraData_random = h'4e32cf9e939a5d052b14d71b1f6b5364' = b64'TjLPnpOaXQUrFNcbH2tTZA' ; 派生方式: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 决定认证器数据标志中的 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'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22395f61494954685341486431414a7a34774a6239714a316775616e37576c4464676432596d4b396142676b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20546a4c506e704f6158515572464e6362483274545a41227d' attestationObject = h'a363666d74656170706c656761747453746d74a1637835638159025c30820258308201fea0030201020210394275613d5310b81a29ce90f48b61c1300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d030107034200048a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761af728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136ca38196308193300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e0416041412f1ce6c0ae39b403bfc9200317bc183a4e4d766301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e303306092a864886f76364080204263024a1220420d7a86e7233fb843eb0eeb407d8b76ff7e4f82d218cf5dbb461d752073f5cb29a300a06082a8648ce3d0403020348003045022070f5c2ede3000e9dae358d412b26a4acbf18f4cdeb80f5b13fcd564d090c39ec022100f672e2c3dbe117c9b1490b3c660abf5dcd74398187082dacb58b6744de4aca6068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54900000000748210a20076616a733b2114336fc38400209c4a5886af9283d9be3e9ec55978dedfdce2e3b365cab193ae850c16238fafb8a50102032620012158208a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761a225820f728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136c'
身份验证:
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 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 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.16. 带 ES256 凭据的 FIDO U2F 证明
注册:
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 时,extraData 才会添加到 clientDataJSON 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 时,extraData 才会添加到 clientDataJSON ; auth_data_UV_BS 设置认证器数据标志中的 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.17. WebAuthn 扩展的测试向量
本节列出WebAuthn 扩展的示例值。
16.17.1. 伪随机函数扩展 (prf)
本节列出伪随机函数(prf)扩展的示例值。
由于prf 扩展与 CTAP2
hmac-secret 扩展[FIDO-CTAP]集成,
示例分为两节:
与WebAuthn 客户端和WebAuthn
依赖方相关的 WebAuthn
prf 扩展示例输入和输出;
以及与WebAuthn
客户端和WebAuthn 认证器相关的 WebAuthnprf
扩展与 CTAP2 hmac-secret 扩展之间的示例映射。
16.17.1.1. Web 身份验证 API
以下示例可用于测试WebAuthn 客户端对prf 扩展的实现,以及WebAuthn 依赖方对 该扩展的使用。 示例并不详尽。
-
enabled输出在注册仪式期间始终存在, 而在身份验证仪式期间从不出现:// 示例扩展输入: { prf: {} } // navigator.credentials.create() 的示例客户端扩展输出: { prf: { enabled: true } } { prf: { enabled: false } } // navigator.credentials.get() 的示例客户端扩展输出: { prf: {} } -
如果存在
eval或evalByCredential输入,则results输出可以在 注册仪式或身份验证 仪式 期间出现:// 示例扩展输入: { prf: { eval: { first: new Uint8Array([ 1 , 2 , 3 , 4 ]) } } } // navigator.credentials.create() 的示例客户端扩展输出: { prf: { enabled: true } } { prf: { enabled: false } } { prf: { enabled: true , results: { first: ArrayBuffer} } } // navigator.credentials.get() 的示例客户端扩展输出: { prf: {} } { prf: { results: { first: ArrayBuffer} } } -
输出 当且仅当results.secondresults输出存在 且所选择 PRF 输入中存在输入时存在:second// 示例扩展输入: { prf: { eval: { first: new Uint8Array([ 1 , 2 , 3 , 4 ]), second: new Uint8Array([ 5 , 6 , 7 , 8 ]), }, evalByCredential: { "e02eZ9lPp0UdkF4vGRO4-NxlhWBkL1FCmsmb1tTfRyE" : { first: new Uint8Array([ 9 , 10 , 11 , 12 ]), } } } } // 如果使用凭据 "e02eZ9lP...",navigator.credentials.get() 的示例客户端扩展输出: { prf: { results: { first: ArrayBuffer} } } // 如果使用其他凭据,navigator.credentials.get() 的示例客户端扩展输出: { prf: {} } { prf: { results: { first: ArrayBuffer, second: ArrayBuffer} } } -
first和second输出 可以是任何BufferSource类型。 相等的first和second输入 会产生相等的first和second输出:// 示例扩展输入: { prf: { evalByCredential: { "e02eZ9lPp0UdkF4vGRO4-NxlhWBkL1FCmsmb1tTfRyE" : { first: new Uint8Array([ 9 , 10 , 11 , 12 ]), second: new Uint8Array([ 9 , 10 , 11 , 12 ]) } } } } // navigator.credentials.get() 的示例客户端扩展输出: { prf: { results: { first: new Uint8Array([ 0xc4 , 0x17 , 0x2e , 0x98 , 0x2e , 0x90 , 0x97 , 0xc3 , 0x9a , 0x6c , 0x0c , 0xb7 , 0x20 , 0xcb , 0x37 , 0x5b , 0x92 , 0xe3 , 0xfc , 0xad , 0x15 , 0x4a , 0x63 , 0xe4 , 0x3a , 0x93 , 0xf1 , 0x09 , 0x6b , 0x1e , 0x19 , 0x73 ]), second: new Uint32Array([ 0x982e17c4 , 0xc397902e , 0xb70c6c9a , 0x5b37cb20 , 0xadfce392 , 0xe4634a15 , 0x09f1933a , 0x73191e6b ]), } } }
本节使用的伪随机值生成方式如下:
-
"e02eZ9lPp0UdkF4vGRO4-NxlhWBkL1FCmsmb1tTfRyE" = Base64Url(SHA-256(UTF-8("WebAuthn PRF test vectors") || 0x00)) -
h'c4172e982e9097c39a6c0cb720cb375b92e3fcad154a63e43a93f1096b1e1973' = SHA-256(UTF-8("WebAuthn PRF test vectors") || 0x01)
16.17.1.2. CTAP2 hmac-secret 扩展
以下示例可用于测试WebAuthn 客户端实现
中prf 扩展如何使用[FIDO-CTAP] hmac-secret 扩展。
示例使用 CDDL [RFC8610]
表示法给出。
示例并不详尽。
-
以下共享定义用于之后的所有示例:
; 给定输入参数: platform_key_agreement_private_key = 0x0971bc7fb1be48270adcd3d9a5fc15d5fb0f335b3071ff36a54c007fa6c76514 authenticator_key_agreement_public_key = { 1 : 2 , 3 : -25 , -1 : 1 , -2 : h'a30522c2de402b561965c3cf949a1cab020c6f6ea36fcf7e911ac1a0f1515300' , -3 : h'9961a929abdb2f42e6566771887d41484d889e735e3248518a53112d2b915f00' , } authenticator_cred_random = h'437e065e723a98b2f08f39d8baf7c53ecb3c363c5e5104bdaaf5d5ca2e028154' first和second输入 在示例中分别映射为prf_eval_first和prf_eval_second。 示例中的prf_results_first和prf_results_second值 分别映射到和results.first输出。results.second -
使用 PIN 协议 2 的单输入情况:
; 来自依赖方的输入: prf_eval_first = h'576562417574686e20505246207465737420766563746f727302' ; 客户端计算: shared_secret = h'0c63083de8170101d38bcf8bd72309568ddb4550867e23404b35d85712f7c20d8bc911ee23c06034cbc14290b9669bec07739053c5a416e313ef905c79955876' salt1 = h'527413ebb48293772df30f031c5ac4650c7de14bf9498671ae163447b6a772b3' salt_enc = h'23dde5e3462daf36559b85c4ac5f9656aa9bfd81c1dc2bf8533c8b9f3882854786b4f500e25b4e3d81f7fc7c74236229' ; 认证器计算: output1 = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' output_enc = h'3bfaa48f7952330d63e35ff8cd5bca48d2a12823828915749287256ab146272f9fb437bf65691243c3f504bd7ea6d5e6' ; 客户端解密: prf_results_first = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' -
使用 PIN 协议 2 的双输入情况:
; 来自依赖方的输入: prf_eval_first = h'576562417574686e20505246207465737420766563746f727302' prf_eval_second = h'576562417574686e20505246207465737420766563746f727303' ; 客户端计算: shared_secret = h'0c63083de8170101d38bcf8bd72309568ddb4550867e23404b35d85712f7c20d8bc911ee23c06034cbc14290b9669bec07739053c5a416e313ef905c79955876' salt1 = h'527413ebb48293772df30f031c5ac4650c7de14bf9498671ae163447b6a772b3' salt2 = h'd68ac03329a10ee5e0ec834492bb9a96a0e547baf563bf78ccbe8789b22e776b' salt_enc = h'd9f4236403e0fe843a8e4e5be764d120904c198ad6e77b089876a3391961f183b0008b4ca66b91cd72aa35b6151ff981f6e5649f3c040e6615ad7dd8ae96ef23b229a5c97c3f0dcd8605eee166ce163a' ; 认证器计算: output1 = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' output2 = h'a62a8773b19cda90d7ed4ef72a80a804320dbd3997e2f663805ad1fd3293d50b' output_enc = h'90ee52f739043bc17b3488a74306d7801debb5b61f18662c648a25b5b5678ede482cdaff99a537a44f064fcb10ce6e04dfd27619dc96a0daff8507e499296b1eecf0981f7c8518b277a7a3018f5ec6fb' ; 客户端解密: prf_results_first = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' prf_results_second = h'a62a8773b19cda90d7ed4ef72a80a804320dbd3997e2f663805ad1fd3293d50b' -
使用 PIN 协议 1 的单输入情况:
; 来自依赖方的输入: prf_eval_first = h'576562417574686e20505246207465737420766563746f727302' ; 客户端计算: shared_secret = h'23e5ed7157c25892b77732fb9c8a107e3518800db2af4142f9f4adfacb771d39' salt1 = h'527413ebb48293772df30f031c5ac4650c7de14bf9498671ae163447b6a772b3' salt_enc = h'ab8c878bb05d04700f077ed91845ec9c503c925cb12b327ddbeb4243c397f913' ; 认证器计算: output1 = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' output_enc = h'15d4e4f3f04109b492b575c1b38c28585b6719cf8d61304215108d939f37ccfb' ; 客户端解密: prf_results_first = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae'
本节使用的输入和伪随机值生成方式如下:
-
seed = UTF-8("WebAuthn PRF test vectors") -
prf_eval_first = seed || 0x02 -
prf_eval_second = seed || 0x03 -
platform_key_agreement_private_key = SHA-256(seed || 0x04) -
authenticator_key_agreement_public_key = P256-Public-Key(sk)其中sk = SHA-256(seed || 0x05) -
authenticator_cred_random = SHA-256(seed || 0x06) -
使用 PIN 协议 2 的单输入
salt_enc中的iv:截断的SHA-256(seed || 0x07) -
使用 PIN 协议 2 的双输入
salt_enc中的iv:截断的SHA-256(seed || 0x08) -
使用 PIN 协议 2 的单输入
output_enc中的iv:截断的SHA-256(seed || 0x09) -
使用 PIN 协议 2 的双输入
output_enc中的iv:截断的SHA-256(seed || 0x0a)
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 身份验证 工作组联合主席所作的贡献。
我们还感谢 Simone Onofri、 Philippe Le Hégaret、 Wendy Seltzer、 Samuel Weiler 和 Harry Halpin 作为我们的 W3C 团队联系人所作的贡献。
18. 修订历史
本节不具有规范性。
本节总结随着时间推移对本规范所作的重大更改。
18.1. 自 Web 身份验证第 3 级[webauthn-3-20260825]以来的更改
18.1.1. 实质性更改
对Web 身份验证 API及其运行方式作了以下更改。
更改:
新功能:
-
添加了用于远程桌面 WebAuthn 操作的remoteClientDataJSON 注册和身份验证 扩展,包括默认拒绝的强大功能、一个策略控制的功能,其默认允许列表为
'none',以及客户端安全注意事项:§ 10.1.6 远程客户端数据 JSON 扩展 (remoteClientDataJSON)、§ 5.9 权限策略 集成、§ 13.4.1 remoteClientDataJSON 扩展。
18.1.2. 编辑性更改
作出以下更改以改善文档的清晰度、可读性、可导航性及类似方面。
-
为凭据创建和身份验证算法中remoteClientDataJSON 扩展使用的客户端数据构造和序列化步骤添加了显式锚点。
18.2. 自 Web 身份验证第 2 级[webauthn-2-20210408]以来的更改
18.2.1. 实质性更改
对Web 身份验证 API及其运行方式作了以下更改。
更改:
-
更新超时指南:§ 15.1 仪式超时的建议 范围
-
不再包含
uvm扩展;请改为参阅 L2 [webauthn-2-20210408]。 -
当
attestation首选项为none时,经证明的凭据 数据中的aaguid 不再置零: § 5.1.3 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 内部方法 -
增加要求 ESP256 (-9)、ESP384 (-51) 和 ESP512 (-52) 公钥使用未压缩 形式:§ 5.8.5 密码算法标识符(typedef COSEAlgorithmIdentifier)
-
移除了§ 5.6 使用 AbortSignal 中止操作中 关于文档失去焦点时中止的建议。
弃用:
-
注册参数
: § 5.4.1 公钥实体描述(dictionary PublicKeyCredentialEntity)publicKey.rp.name -
tokenBinding 已更改为 [保留]。
-
不再推荐字段内的语言和方向元数据:
-
增加了不建议在
pubKeyCredParams中使用COSEAlgorithmIdentifier值 -9、-51、-52 和 -19 的建议。
新功能:
-
新的 JSON(反)序列化方法:
-
跨源 iframe 中的创建操作:
-
create 的条件中介:§ 5.1.3 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 内部方法
-
get 的条件中介:§ 5.1.4 使用现有凭据 生成断言
-
§ 5.1.7 客户端能力的可用性 - PublicKeyCredential 的 getClientCapabilities() 方法
-
§ 5.8.4 认证器传输方式枚举(enum AuthenticatorTransport)中新增枚举值
hybrid。 -
新的客户端数据属性
topOrigin: § 5.8.1 WebAuthn 签名中使用的客户端数据(dictionary CollectedClientData) -
注册参数
: § 5.4 凭据创建选项(dictionary PublicKeyCredentialCreationOptions)publicKey.attestationFormats
18.2.2. 编辑性更改
作出以下更改以改善文档的清晰度、可读性、可导航性及类似方面。
-
更新了§ 1.2 用例,以反映部署 环境的发展。
-
澄清错误条件:
-
§ 6.4 字符串处理拆分为§ 6.4.1.1 客户端进行的字符串截断和§ 6.4.1.2 认证器进行的字符串截断子节, 以澄清职责划分。
-
添加了§ 16 测试向量。
-
将规范性语言移出“注”块。
-
移除了Web 身份验证:用于访问公钥凭据的 API - 第 3 级 § sctn-isUserVerifyingPlatformAuthenticatorAvailable 和Web 身份验证:用于访问公钥凭据的 API - 第 3 级 § sctn-getClientCapabilities中关于权限策略的过时注释。
-
在Web 身份验证:用于访问公钥凭据的 API - 第 3 级 § sctn-sample-registration的示例代码中添加了算法 -8 (EdDSA)。